DirectoryFragment.java revision ae9b51bfa313c51a31af30875a71255d7b6d2e61
19e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey/* 29e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey * Copyright (C) 2013 The Android Open Source Project 39e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey * 49e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License"); 59e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey * you may not use this file except in compliance with the License. 69e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey * You may obtain a copy of the License at 79e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey * 89e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey * http://www.apache.org/licenses/LICENSE-2.0 99e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey * 109e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey * Unless required by applicable law or agreed to in writing, software 119e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS, 129e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey * See the License for the specific language governing permissions and 149e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey * limitations under the License. 159e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey */ 169e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey 179e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeypackage com.android.documentsui; 189e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey 199d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkeyimport static com.android.documentsui.DocumentsActivity.TAG; 204eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkeyimport static com.android.documentsui.DocumentsActivity.DisplayState.ACTION_MANAGE; 214eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkeyimport static com.android.documentsui.DocumentsActivity.DisplayState.MODE_GRID; 224eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkeyimport static com.android.documentsui.DocumentsActivity.DisplayState.MODE_LIST; 23aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_DISPLAY_NAME; 24aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_LAST_MODIFIED; 254eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkeyimport static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_SIZE; 269d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey 2754e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkeyimport android.app.Fragment; 289e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.app.FragmentManager; 299e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.app.FragmentTransaction; 309e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.app.LoaderManager.LoaderCallbacks; 314eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkeyimport android.content.ContentResolver; 329e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.content.Context; 334eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkeyimport android.content.Intent; 349e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.content.Loader; 359d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkeyimport android.graphics.Bitmap; 369d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkeyimport android.graphics.Point; 379e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.net.Uri; 389d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkeyimport android.os.AsyncTask; 399e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.os.Bundle; 409e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.provider.DocumentsContract; 4154e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkeyimport android.text.format.DateUtils; 42b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport android.text.format.Formatter; 439d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkeyimport android.text.format.Time; 449d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkeyimport android.util.Log; 45be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkeyimport android.util.SparseBooleanArray; 46be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkeyimport android.view.ActionMode; 479e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.view.LayoutInflater; 4854e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkeyimport android.view.Menu; 4954e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkeyimport android.view.MenuItem; 509e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.view.View; 519e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.view.ViewGroup; 52be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkeyimport android.widget.AbsListView; 53be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkeyimport android.widget.AbsListView.MultiChoiceModeListener; 5454e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkeyimport android.widget.AdapterView; 5554e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkeyimport android.widget.AdapterView.OnItemClickListener; 56ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkeyimport android.widget.BaseAdapter; 5754e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkeyimport android.widget.GridView; 589e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.widget.ImageView; 599e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.widget.ListView; 609e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.widget.TextView; 614eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkeyimport android.widget.Toast; 629e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey 631482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkeyimport com.android.documentsui.DocumentsActivity.DisplayState; 64ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkeyimport com.android.documentsui.model.DocumentInfo; 65ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkeyimport com.android.internal.util.Predicate; 66be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkeyimport com.google.android.collect.Lists; 67be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey 68be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkeyimport java.util.ArrayList; 69ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkeyimport java.util.Comparator; 70ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkeyimport java.util.List; 71b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport java.util.concurrent.atomic.AtomicInteger; 7254e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey 7354e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey/** 7454e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey * Display the documents inside a single directory. 7554e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey */ 7654e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkeypublic class DirectoryFragment extends Fragment { 7754e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey 789fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey private View mEmptyView; 7954e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey private ListView mListView; 8054e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey private GridView mGridView; 8154e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey 82be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey private AbsListView mCurrentView; 83be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey 84ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey private Predicate<DocumentInfo> mFilter; 859fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey 86ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey public static final int TYPE_NORMAL = 1; 87ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey public static final int TYPE_SEARCH = 2; 88ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey public static final int TYPE_RECENT_OPEN = 3; 89dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey 90dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey private int mType = TYPE_NORMAL; 91dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey 929d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey private Point mThumbSize; 939d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey 949e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey private DocumentsAdapter mAdapter; 95b448660a227f93d7bd5c5d019a21745e67c2f54dJeff Sharkey private LoaderCallbacks<DirectoryResult> mCallbacks; 969e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey 97b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey private static final String EXTRA_TYPE = "type"; 98dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey private static final String EXTRA_URI = "uri"; 999e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey 100b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey private static AtomicInteger sLoaderId = new AtomicInteger(4000); 101b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey 102b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey private final int mLoaderId = sLoaderId.incrementAndGet(); 103b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey 104b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey public static void showNormal(FragmentManager fm, Uri uri) { 105b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey show(fm, TYPE_NORMAL, uri); 106b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey } 107b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey 108b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey public static void showSearch(FragmentManager fm, Uri uri, String query) { 109ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey final Uri searchUri = DocumentsContract.buildSearchDocumentsUri( 110ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey uri.getAuthority(), DocumentsContract.getDocumentId(uri), query); 111b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey show(fm, TYPE_SEARCH, searchUri); 112b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey } 113b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey 114b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey public static void showRecentsOpen(FragmentManager fm) { 115b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey show(fm, TYPE_RECENT_OPEN, null); 116b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey } 1179e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey 118b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey private static void show(FragmentManager fm, int type, Uri uri) { 1199e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey final Bundle args = new Bundle(); 120b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey args.putInt(EXTRA_TYPE, type); 121dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey args.putParcelable(EXTRA_URI, uri); 1229e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey 1239e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey final DirectoryFragment fragment = new DirectoryFragment(); 1249e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey fragment.setArguments(args); 1259e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey 1269e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey final FragmentTransaction ft = fm.beginTransaction(); 12766516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey ft.replace(R.id.container_directory, fragment); 1289e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey ft.commitAllowingStateLoss(); 1299e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey } 1309e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey 131ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey public static DirectoryFragment get(FragmentManager fm) { 132ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey // TODO: deal with multiple directories shown at once 13366516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey return (DirectoryFragment) fm.findFragmentById(R.id.container_directory); 134ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey } 135ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey 1369e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey @Override 1379e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey public View onCreateView( 1389e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 1399e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey final Context context = inflater.getContext(); 1409e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey 14154e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey final View view = inflater.inflate(R.layout.fragment_directory, container, false); 14254e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey 1439fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey mEmptyView = view.findViewById(android.R.id.empty); 1449fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey 14554e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey mListView = (ListView) view.findViewById(R.id.list); 14654e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey mListView.setOnItemClickListener(mItemListener); 147be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey mListView.setMultiChoiceModeListener(mMultiListener); 14854e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey 14954e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey mGridView = (GridView) view.findViewById(R.id.grid); 15054e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey mGridView.setOnItemClickListener(mItemListener); 151be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey mGridView.setMultiChoiceModeListener(mMultiListener); 15254e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey 153ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey mAdapter = new DocumentsAdapter(); 15454e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey 155dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey final Uri uri = getArguments().getParcelable(EXTRA_URI); 156b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey mType = getArguments().getInt(EXTRA_TYPE); 1579e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey 158b448660a227f93d7bd5c5d019a21745e67c2f54dJeff Sharkey mCallbacks = new LoaderCallbacks<DirectoryResult>() { 1599e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey @Override 160b448660a227f93d7bd5c5d019a21745e67c2f54dJeff Sharkey public Loader<DirectoryResult> onCreateLoader(int id, Bundle args) { 1611482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey final DisplayState state = getDisplayState(DirectoryFragment.this); 1629fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey mFilter = new MimePredicate(state.acceptMimes); 1631482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey 16454ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey Uri contentsUri; 165dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey if (mType == TYPE_NORMAL) { 166ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey contentsUri = DocumentsContract.buildChildDocumentsUri( 167ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey uri.getAuthority(), DocumentsContract.getDocumentId(uri)); 168b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey } else if (mType == TYPE_RECENT_OPEN) { 169b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey contentsUri = RecentsProvider.buildRecentOpen(); 170bc2971d2499f5bf5534ced7296ece630ca902738Jeff Sharkey } else { 171dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey contentsUri = uri; 172bc2971d2499f5bf5534ced7296ece630ca902738Jeff Sharkey } 173bc2971d2499f5bf5534ced7296ece630ca902738Jeff Sharkey 174ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey final Comparator<DocumentInfo> sortOrder; 175aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey if (state.sortOrder == SORT_ORDER_LAST_MODIFIED || mType == TYPE_RECENT_OPEN) { 176ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey sortOrder = new DocumentInfo.LastModifiedComparator(); 177aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } else if (state.sortOrder == SORT_ORDER_DISPLAY_NAME) { 178ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey sortOrder = new DocumentInfo.DisplayNameComparator(); 1794eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey } else if (state.sortOrder == SORT_ORDER_SIZE) { 180ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey sortOrder = new DocumentInfo.SizeComparator(); 181ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey } else { 182ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey throw new IllegalArgumentException("Unknown sort order " + state.sortOrder); 183ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey } 184ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey 1859fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey return new DirectoryLoader(context, contentsUri, mType, null, sortOrder); 1869e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey } 1879e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey 1889e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey @Override 189b448660a227f93d7bd5c5d019a21745e67c2f54dJeff Sharkey public void onLoadFinished(Loader<DirectoryResult> loader, DirectoryResult result) { 190b448660a227f93d7bd5c5d019a21745e67c2f54dJeff Sharkey mAdapter.swapDocuments(result.contents); 1919e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey } 1929e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey 1939e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey @Override 194b448660a227f93d7bd5c5d019a21745e67c2f54dJeff Sharkey public void onLoaderReset(Loader<DirectoryResult> loader) { 195ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey mAdapter.swapDocuments(null); 1969e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey } 1979e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey }; 1989e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey 199b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey updateDisplayState(); 200b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey 20154e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey return view; 2029e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey } 2039e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey 2049e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey @Override 2059e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey public void onStart() { 2069e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey super.onStart(); 207b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey getLoaderManager().restartLoader(mLoaderId, getArguments(), mCallbacks); 2089e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey } 2099e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey 2109e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey @Override 2119e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey public void onStop() { 2129e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey super.onStop(); 213b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey getLoaderManager().destroyLoader(mLoaderId); 21454e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey } 2159e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey 216b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey public void updateDisplayState() { 2171482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey final DisplayState state = getDisplayState(this); 21854e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey 2199fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey // TODO: avoid kicking loader when nothing changed 220b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey getLoaderManager().restartLoader(mLoaderId, getArguments(), mCallbacks); 221b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey mListView.smoothScrollToPosition(0); 222b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey mGridView.smoothScrollToPosition(0); 22354e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey 2244eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey mListView.setVisibility(state.mode == MODE_LIST ? View.VISIBLE : View.GONE); 2254eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey mGridView.setVisibility(state.mode == MODE_GRID ? View.VISIBLE : View.GONE); 22654e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey 227be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey final int choiceMode; 2281482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey if (state.allowMultiple) { 229be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey choiceMode = ListView.CHOICE_MODE_MULTIPLE_MODAL; 230be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey } else { 231be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey choiceMode = ListView.CHOICE_MODE_NONE; 232be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey } 233be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey 2349d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey final int thumbSize; 2354eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey if (state.mode == MODE_GRID) { 2369d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey thumbSize = getResources().getDimensionPixelSize(R.dimen.grid_width); 23754e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey mListView.setAdapter(null); 238be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey mListView.setChoiceMode(ListView.CHOICE_MODE_NONE); 23954e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey mGridView.setAdapter(mAdapter); 240be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey mGridView.setColumnWidth(getResources().getDimensionPixelSize(R.dimen.grid_width)); 24154e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey mGridView.setNumColumns(GridView.AUTO_FIT); 242be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey mGridView.setChoiceMode(choiceMode); 243be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey mCurrentView = mGridView; 2444eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey } else if (state.mode == MODE_LIST) { 2459d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey thumbSize = getResources().getDimensionPixelSize(android.R.dimen.app_icon_size); 24654e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey mGridView.setAdapter(null); 247be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey mGridView.setChoiceMode(ListView.CHOICE_MODE_NONE); 24854e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey mListView.setAdapter(mAdapter); 249be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey mListView.setChoiceMode(choiceMode); 250be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey mCurrentView = mListView; 2511482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey } else { 2521482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey throw new IllegalStateException(); 25354e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey } 2549d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey 2559d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey mThumbSize = new Point(thumbSize, thumbSize); 25654e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey } 25754e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey 25854e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey private OnItemClickListener mItemListener = new OnItemClickListener() { 25954e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey @Override 26054e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 261ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey final DocumentInfo doc = mAdapter.getItem(position); 262a5599ef636e37cb0b6474349936999be1afe6987Jeff Sharkey if (mFilter.apply(doc)) { 263a5599ef636e37cb0b6474349936999be1afe6987Jeff Sharkey ((DocumentsActivity) getActivity()).onDocumentPicked(doc); 264a5599ef636e37cb0b6474349936999be1afe6987Jeff Sharkey } 26554e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey } 26654e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey }; 26754e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey 268be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey private MultiChoiceModeListener mMultiListener = new MultiChoiceModeListener() { 269be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey @Override 270be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey public boolean onCreateActionMode(ActionMode mode, Menu menu) { 271be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey mode.getMenuInflater().inflate(R.menu.mode_directory, menu); 272be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey return true; 273be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey } 274be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey 275be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey @Override 276be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey public boolean onPrepareActionMode(ActionMode mode, Menu menu) { 2774eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey final DisplayState state = getDisplayState(DirectoryFragment.this); 2784eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey 2794eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey final MenuItem open = menu.findItem(R.id.menu_open); 2804eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey final MenuItem share = menu.findItem(R.id.menu_share); 2814eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey final MenuItem delete = menu.findItem(R.id.menu_delete); 2824eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey 2834eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey final boolean manageMode = state.action == ACTION_MANAGE; 2844eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey open.setVisible(!manageMode); 2854eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey share.setVisible(manageMode); 2864eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey delete.setVisible(manageMode); 2874eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey 288be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey return true; 289be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey } 290be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey 291be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey @Override 292be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey public boolean onActionItemClicked(ActionMode mode, MenuItem item) { 2934eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey final SparseBooleanArray checked = mCurrentView.getCheckedItemPositions(); 294ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey final ArrayList<DocumentInfo> docs = Lists.newArrayList(); 2954eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey final int size = checked.size(); 2964eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey for (int i = 0; i < size; i++) { 2974eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey if (checked.valueAt(i)) { 298ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey final DocumentInfo doc = mAdapter.getItem(checked.keyAt(i)); 2994eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey docs.add(doc); 300be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey } 3014eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey } 3024eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey 3034eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey final int id = item.getItemId(); 3044eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey if (id == R.id.menu_open) { 3054eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey DocumentsActivity.get(DirectoryFragment.this).onDocumentsPicked(docs); 3064eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey return true; 307be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey 3084eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey } else if (id == R.id.menu_share) { 3094eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey onShareDocuments(docs); 310be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey return true; 3114eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey 3124eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey } else if (id == R.id.menu_delete) { 3134eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey onDeleteDocuments(docs); 3144eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey return true; 3154eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey 316be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey } else { 317be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey return false; 318be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey } 319be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey } 320be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey 321be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey @Override 322be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey public void onDestroyActionMode(ActionMode mode) { 323be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey // ignored 324be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey } 325be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey 326be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey @Override 327be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey public void onItemCheckedStateChanged( 328be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey ActionMode mode, int position, long id, boolean checked) { 329be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey if (checked) { 330be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey // Directories cannot be checked 331ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey final DocumentInfo doc = mAdapter.getItem(position); 332b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey if (doc.isDirectory()) { 333be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey mCurrentView.setItemChecked(position, false); 334be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey } 335be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey } 336be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey 337be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey mode.setTitle(getResources() 338be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey .getString(R.string.mode_selected_count, mCurrentView.getCheckedItemCount())); 339be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey } 340be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey }; 341be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey 342ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey private void onShareDocuments(List<DocumentInfo> docs) { 3434eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey final ArrayList<Uri> uris = Lists.newArrayList(); 344ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey for (DocumentInfo doc : docs) { 3454eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey uris.add(doc.uri); 3464eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey } 3474eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey 3484eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey final Intent intent; 3494eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey if (uris.size() > 1) { 3504eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey intent = new Intent(Intent.ACTION_SEND_MULTIPLE); 3514eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 3524eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey intent.addCategory(Intent.CATEGORY_DEFAULT); 3534eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey // TODO: find common mimetype 3544eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey intent.setType("*/*"); 3554eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris); 3564eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey } else { 3574eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey intent = new Intent(Intent.ACTION_SEND); 3584eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 3594eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey intent.addCategory(Intent.CATEGORY_DEFAULT); 3604eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey intent.setData(uris.get(0)); 3614eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey } 3624eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey 3634eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey startActivity(intent); 3644eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey } 3654eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey 366ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey private void onDeleteDocuments(List<DocumentInfo> docs) { 3674eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey final Context context = getActivity(); 3684eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey final ContentResolver resolver = context.getContentResolver(); 3694eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey 3704eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey boolean hadTrouble = false; 371ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey for (DocumentInfo doc : docs) { 3724eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey if (!doc.isDeleteSupported()) { 3734eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey Log.w(TAG, "Skipping " + doc); 3744eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey hadTrouble = true; 3754eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey continue; 3764eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey } 3774eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey 3784eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey try { 3794eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey if (resolver.delete(doc.uri, null, null) != 1) { 3804eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey Log.w(TAG, "Failed to delete " + doc); 3814eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey hadTrouble = true; 3824eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey } 3834eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey } catch (Exception e) { 3844eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey Log.w(TAG, "Failed to delete " + doc + ": " + e); 3854eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey hadTrouble = true; 3864eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey } 3874eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey } 3884eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey 3894eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey if (hadTrouble) { 3904eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey Toast.makeText(context, R.string.toast_failed_delete, Toast.LENGTH_SHORT).show(); 3914eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey } 3924eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey } 3934eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey 3941482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey private static DisplayState getDisplayState(Fragment fragment) { 3951482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey return ((DocumentsActivity) fragment.getActivity()).getDisplayState(); 39654e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey } 39754e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey 398ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey private class DocumentsAdapter extends BaseAdapter { 399ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey private List<DocumentInfo> mDocuments; 400ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey 401ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey public DocumentsAdapter() { 4029e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey } 4039e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey 404ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey public void swapDocuments(List<DocumentInfo> documents) { 405ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey mDocuments = documents; 4069fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey 407b448660a227f93d7bd5c5d019a21745e67c2f54dJeff Sharkey if (mDocuments != null && mDocuments.isEmpty()) { 4089fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey mEmptyView.setVisibility(View.VISIBLE); 4099fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey } else { 4109fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey mEmptyView.setVisibility(View.GONE); 4119fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey } 4129fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey 413ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey notifyDataSetChanged(); 4149e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey } 4159e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey 4169e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey @Override 417ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey public View getView(int position, View convertView, ViewGroup parent) { 418ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey final Context context = parent.getContext(); 419b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey final DisplayState state = getDisplayState(DirectoryFragment.this); 420ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey 4214eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey final RootsCache roots = DocumentsApplication.getRootsCache(context); 4224eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache( 4234eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey context, mThumbSize); 4244eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey 425ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey if (convertView == null) { 426ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey final LayoutInflater inflater = LayoutInflater.from(context); 4274eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey if (state.mode == MODE_LIST) { 428ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey convertView = inflater.inflate(R.layout.item_doc_list, parent, false); 4294eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey } else if (state.mode == MODE_GRID) { 430ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey convertView = inflater.inflate(R.layout.item_doc_grid, parent, false); 431ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey } else { 432ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey throw new IllegalStateException(); 433ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey } 434ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey } 435ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey 436ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey final DocumentInfo doc = getItem(position); 437ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey 438b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon); 439ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey final TextView title = (TextView) convertView.findViewById(android.R.id.title); 4409fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey final View summaryGrid = convertView.findViewById(R.id.summary_grid); 441b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey final ImageView icon1 = (ImageView) convertView.findViewById(android.R.id.icon1); 442ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey final TextView summary = (TextView) convertView.findViewById(android.R.id.summary); 443b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey final TextView date = (TextView) convertView.findViewById(R.id.date); 444b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey final TextView size = (TextView) convertView.findViewById(R.id.size); 445ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey 4469d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey final ThumbnailAsyncTask oldTask = (ThumbnailAsyncTask) icon.getTag(); 4479d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey if (oldTask != null) { 4489d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey oldTask.cancel(false); 4499d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey } 4509d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey 451ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey if (doc.isThumbnailSupported()) { 4524eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey final Bitmap cachedResult = thumbs.get(doc.uri); 4539d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey if (cachedResult != null) { 4549d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey icon.setImageBitmap(cachedResult); 4559d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey } else { 4569d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey final ThumbnailAsyncTask task = new ThumbnailAsyncTask(icon, mThumbSize); 4579d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey icon.setImageBitmap(null); 4589d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey icon.setTag(task); 4599d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey task.execute(doc.uri); 4609d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey } 4619e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey } else { 462aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey icon.setImageDrawable(RootsCache.resolveDocumentIcon(context, doc.mimeType)); 4639e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey } 4649e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey 465ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey title.setText(doc.displayName); 466b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey 467b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey if (mType == TYPE_NORMAL || mType == TYPE_SEARCH) { 468b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey icon1.setVisibility(View.GONE); 469b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey if (doc.summary != null) { 470b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey summary.setText(doc.summary); 471b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey summary.setVisibility(View.VISIBLE); 472b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey } else { 473b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey summary.setVisibility(View.INVISIBLE); 474b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey } 475b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey } else if (mType == TYPE_RECENT_OPEN) { 476aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey // TODO: resolve storage root 477b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey } 478b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey 4799fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey if (summaryGrid != null) { 4809fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey summaryGrid.setVisibility( 4819fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey (summary.getVisibility() == View.VISIBLE) ? View.VISIBLE : View.GONE); 4829fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey } 4839fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey 4849d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey if (doc.lastModified == -1) { 4859d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey date.setText(null); 4869d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey } else { 4879d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey date.setText(formatTime(context, doc.lastModified)); 4889d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey } 489b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey 490b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey if (state.showSize) { 491b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey size.setVisibility(View.VISIBLE); 492a5599ef636e37cb0b6474349936999be1afe6987Jeff Sharkey if (doc.isDirectory() || doc.size == -1) { 493b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey size.setText(null); 494b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey } else { 495b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey size.setText(Formatter.formatFileSize(context, doc.size)); 496b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey } 497b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey } else { 498b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey size.setVisibility(View.GONE); 49954e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey } 500ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey 501ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey return convertView; 50254e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey } 50354e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey 504ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey @Override 505ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey public int getCount() { 506ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey return mDocuments != null ? mDocuments.size() : 0; 507ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey } 5089e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey 509ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey @Override 510ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey public DocumentInfo getItem(int position) { 511ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey return mDocuments.get(position); 512ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey } 51354e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey 514ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey @Override 515ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey public long getItemId(int position) { 516ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey return getItem(position).uri.hashCode(); 517ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey } 5189e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey } 5199d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey 5209d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey private static class ThumbnailAsyncTask extends AsyncTask<Uri, Void, Bitmap> { 5219d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey private final ImageView mTarget; 5224eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey private final Point mThumbSize; 5239d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey 5244eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey public ThumbnailAsyncTask(ImageView target, Point thumbSize) { 5259d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey mTarget = target; 5264eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey mThumbSize = thumbSize; 5279d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey } 5289d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey 5299d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey @Override 5309d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey protected void onPreExecute() { 5319d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey mTarget.setTag(this); 5329d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey } 5339d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey 5349d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey @Override 5359d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey protected Bitmap doInBackground(Uri... params) { 5369d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey final Context context = mTarget.getContext(); 5379d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey final Uri uri = params[0]; 5389d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey 5399d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey Bitmap result = null; 5409d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey try { 541ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey result = DocumentsContract.getDocumentThumbnail( 542ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey context.getContentResolver(), uri, mThumbSize, null); 5439d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey if (result != null) { 5444eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache( 5454eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey context, mThumbSize); 5464eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey thumbs.put(uri, result); 5479d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey } 5489d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey } catch (Exception e) { 5499d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey Log.w(TAG, "Failed to load thumbnail: " + e); 5509d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey } 5519d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey return result; 5529d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey } 5539d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey 5549d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey @Override 5559d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey protected void onPostExecute(Bitmap result) { 5569d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey if (mTarget.getTag() == this) { 5579d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey mTarget.setImageBitmap(result); 5589d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey mTarget.setTag(null); 5599d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey } 5609d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey } 5619d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey } 5629d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey 5639d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey private static String formatTime(Context context, long when) { 5649d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey // TODO: DateUtils should make this easier 5659d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey Time then = new Time(); 5669d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey then.set(when); 5679d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey Time now = new Time(); 5689d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey now.setToNow(); 5699d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey 5709d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey int flags = DateUtils.FORMAT_NO_NOON | DateUtils.FORMAT_NO_MIDNIGHT 5719d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey | DateUtils.FORMAT_ABBREV_ALL; 5729d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey 5739d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey if (then.year != now.year) { 5749d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey flags |= DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_DATE; 5759d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey } else if (then.yearDay != now.yearDay) { 5769d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey flags |= DateUtils.FORMAT_SHOW_DATE; 5779d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey } else { 5789d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey flags |= DateUtils.FORMAT_SHOW_TIME; 5799d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey } 5809d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey 5819d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey return DateUtils.formatDateTime(context, when, flags); 5829d0843df7e3984293dc4ab6ee2f9502e898b63aaJeff Sharkey } 5839e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey} 584