blob: fbdb3a706020bbe22bf74ad10711dadcb32f3b4e [file] [log] [blame]
Jeff Sharkeye22d02e2013-04-26 16:54:55 -07001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.documentsui;
18
Jeff Sharkey8a8fb672013-05-07 12:41:33 -070019import static com.android.documentsui.DocumentsActivity.TAG;
20
Jeff Sharkey09c10bf2013-06-30 20:02:59 -070021import android.app.Fragment;
Jeff Sharkeye22d02e2013-04-26 16:54:55 -070022import android.app.FragmentManager;
23import android.app.FragmentTransaction;
Jeff Sharkeye22d02e2013-04-26 16:54:55 -070024import android.app.LoaderManager.LoaderCallbacks;
25import android.content.Context;
Jeff Sharkeye22d02e2013-04-26 16:54:55 -070026import android.content.Loader;
Jeff Sharkey8a8fb672013-05-07 12:41:33 -070027import android.graphics.Bitmap;
28import android.graphics.Point;
Jeff Sharkeye22d02e2013-04-26 16:54:55 -070029import android.net.Uri;
Jeff Sharkey8a8fb672013-05-07 12:41:33 -070030import android.os.AsyncTask;
Jeff Sharkeye22d02e2013-04-26 16:54:55 -070031import android.os.Bundle;
32import android.provider.DocumentsContract;
Jeff Sharkey09c10bf2013-06-30 20:02:59 -070033import android.text.format.DateUtils;
Jeff Sharkey2e694f82013-08-06 16:26:14 -070034import android.text.format.Formatter;
Jeff Sharkey8a8fb672013-05-07 12:41:33 -070035import android.text.format.Time;
36import android.util.Log;
Jeff Sharkeyc317af82013-07-01 16:56:54 -070037import android.util.SparseBooleanArray;
38import android.view.ActionMode;
Jeff Sharkeye22d02e2013-04-26 16:54:55 -070039import android.view.LayoutInflater;
Jeff Sharkey09c10bf2013-06-30 20:02:59 -070040import android.view.Menu;
Jeff Sharkey09c10bf2013-06-30 20:02:59 -070041import android.view.MenuItem;
Jeff Sharkeye22d02e2013-04-26 16:54:55 -070042import android.view.View;
43import android.view.ViewGroup;
Jeff Sharkeyc317af82013-07-01 16:56:54 -070044import android.widget.AbsListView;
45import android.widget.AbsListView.MultiChoiceModeListener;
Jeff Sharkey09c10bf2013-06-30 20:02:59 -070046import android.widget.AdapterView;
47import android.widget.AdapterView.OnItemClickListener;
Jeff Sharkeya5defe32013-08-05 17:56:48 -070048import android.widget.BaseAdapter;
Jeff Sharkey09c10bf2013-06-30 20:02:59 -070049import android.widget.GridView;
Jeff Sharkeye22d02e2013-04-26 16:54:55 -070050import android.widget.ImageView;
51import android.widget.ListView;
52import android.widget.TextView;
53
Jeff Sharkey3c28b792013-07-01 17:22:02 -070054import com.android.documentsui.DocumentsActivity.DisplayState;
Jeff Sharkeya5defe32013-08-05 17:56:48 -070055import com.android.documentsui.model.Document;
Jeff Sharkey2e694f82013-08-06 16:26:14 -070056import com.android.documentsui.model.Root;
Jeff Sharkeya5defe32013-08-05 17:56:48 -070057import com.android.internal.util.Predicate;
Jeff Sharkeyc317af82013-07-01 16:56:54 -070058import com.google.android.collect.Lists;
59
Jeff Sharkey2e694f82013-08-06 16:26:14 -070060import java.text.DateFormat;
Jeff Sharkeyc317af82013-07-01 16:56:54 -070061import java.util.ArrayList;
Jeff Sharkeya5defe32013-08-05 17:56:48 -070062import java.util.Comparator;
63import java.util.List;
Jeff Sharkey2e694f82013-08-06 16:26:14 -070064import java.util.concurrent.atomic.AtomicInteger;
Jeff Sharkey09c10bf2013-06-30 20:02:59 -070065
66/**
67 * Display the documents inside a single directory.
68 */
69public class DirectoryFragment extends Fragment {
70
Jeff Sharkeyc6cbdf12013-08-07 16:22:02 -070071 private View mEmptyView;
Jeff Sharkey09c10bf2013-06-30 20:02:59 -070072 private ListView mListView;
73 private GridView mGridView;
74
Jeff Sharkeyc317af82013-07-01 16:56:54 -070075 private AbsListView mCurrentView;
76
Jeff Sharkeyc6cbdf12013-08-07 16:22:02 -070077 private Predicate<Document> mFilter;
78
Jeff Sharkeya5defe32013-08-05 17:56:48 -070079 public static final int TYPE_NORMAL = 1;
80 public static final int TYPE_SEARCH = 2;
81 public static final int TYPE_RECENT_OPEN = 3;
Jeff Sharkey5b535922013-08-02 15:55:26 -070082
83 private int mType = TYPE_NORMAL;
84
Jeff Sharkey8a8fb672013-05-07 12:41:33 -070085 private Point mThumbSize;
86
Jeff Sharkeye22d02e2013-04-26 16:54:55 -070087 private DocumentsAdapter mAdapter;
Jeff Sharkeya5defe32013-08-05 17:56:48 -070088 private LoaderCallbacks<List<Document>> mCallbacks;
Jeff Sharkeye22d02e2013-04-26 16:54:55 -070089
Jeff Sharkey2e694f82013-08-06 16:26:14 -070090 private static final String EXTRA_TYPE = "type";
Jeff Sharkey5b535922013-08-02 15:55:26 -070091 private static final String EXTRA_URI = "uri";
Jeff Sharkeye22d02e2013-04-26 16:54:55 -070092
Jeff Sharkey2e694f82013-08-06 16:26:14 -070093 private static AtomicInteger sLoaderId = new AtomicInteger(4000);
Jeff Sharkeye22d02e2013-04-26 16:54:55 -070094
Jeff Sharkey2e694f82013-08-06 16:26:14 -070095 private final int mLoaderId = sLoaderId.incrementAndGet();
96
97 public static void showNormal(FragmentManager fm, Uri uri) {
98 show(fm, TYPE_NORMAL, uri);
99 }
100
101 public static void showSearch(FragmentManager fm, Uri uri, String query) {
102 final Uri searchUri = DocumentsContract.buildSearchUri(uri, query);
103 show(fm, TYPE_SEARCH, searchUri);
104 }
105
106 public static void showRecentsOpen(FragmentManager fm) {
107 show(fm, TYPE_RECENT_OPEN, null);
108 }
109
110 private static void show(FragmentManager fm, int type, Uri uri) {
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700111 final Bundle args = new Bundle();
Jeff Sharkey2e694f82013-08-06 16:26:14 -0700112 args.putInt(EXTRA_TYPE, type);
Jeff Sharkey5b535922013-08-02 15:55:26 -0700113 args.putParcelable(EXTRA_URI, uri);
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700114
115 final DirectoryFragment fragment = new DirectoryFragment();
116 fragment.setArguments(args);
117
118 final FragmentTransaction ft = fm.beginTransaction();
Jeff Sharkey76112212013-08-06 11:26:10 -0700119 ft.replace(R.id.container_directory, fragment);
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700120 ft.commitAllowingStateLoss();
121 }
122
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700123 public static DirectoryFragment get(FragmentManager fm) {
124 // TODO: deal with multiple directories shown at once
Jeff Sharkey76112212013-08-06 11:26:10 -0700125 return (DirectoryFragment) fm.findFragmentById(R.id.container_directory);
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700126 }
127
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700128 @Override
129 public View onCreateView(
130 LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
131 final Context context = inflater.getContext();
132
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700133 final View view = inflater.inflate(R.layout.fragment_directory, container, false);
134
Jeff Sharkeyc6cbdf12013-08-07 16:22:02 -0700135 mEmptyView = view.findViewById(android.R.id.empty);
136
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700137 mListView = (ListView) view.findViewById(R.id.list);
138 mListView.setOnItemClickListener(mItemListener);
Jeff Sharkeyc317af82013-07-01 16:56:54 -0700139 mListView.setMultiChoiceModeListener(mMultiListener);
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700140
141 mGridView = (GridView) view.findViewById(R.id.grid);
142 mGridView.setOnItemClickListener(mItemListener);
Jeff Sharkeyc317af82013-07-01 16:56:54 -0700143 mGridView.setMultiChoiceModeListener(mMultiListener);
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700144
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700145 mAdapter = new DocumentsAdapter();
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700146
Jeff Sharkey5b535922013-08-02 15:55:26 -0700147 final Uri uri = getArguments().getParcelable(EXTRA_URI);
Jeff Sharkey2e694f82013-08-06 16:26:14 -0700148 mType = getArguments().getInt(EXTRA_TYPE);
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700149
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700150 mCallbacks = new LoaderCallbacks<List<Document>>() {
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700151 @Override
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700152 public Loader<List<Document>> onCreateLoader(int id, Bundle args) {
Jeff Sharkey3c28b792013-07-01 17:22:02 -0700153 final DisplayState state = getDisplayState(DirectoryFragment.this);
Jeff Sharkeyc6cbdf12013-08-07 16:22:02 -0700154 mFilter = new MimePredicate(state.acceptMimes);
Jeff Sharkey3c28b792013-07-01 17:22:02 -0700155
Jeff Sharkey1d890e02013-08-15 11:24:03 -0700156 Uri contentsUri;
Jeff Sharkey5b535922013-08-02 15:55:26 -0700157 if (mType == TYPE_NORMAL) {
158 contentsUri = DocumentsContract.buildContentsUri(uri);
Jeff Sharkey2e694f82013-08-06 16:26:14 -0700159 } else if (mType == TYPE_RECENT_OPEN) {
160 contentsUri = RecentsProvider.buildRecentOpen();
Jeff Sharkey46165b52013-07-31 20:53:22 -0700161 } else {
Jeff Sharkey5b535922013-08-02 15:55:26 -0700162 contentsUri = uri;
Jeff Sharkey46165b52013-07-31 20:53:22 -0700163 }
164
Jeff Sharkey1d890e02013-08-15 11:24:03 -0700165 if (state.localOnly) {
166 contentsUri = DocumentsContract.setLocalOnly(contentsUri);
167 }
168
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700169 final Comparator<Document> sortOrder;
Jeff Sharkey2e694f82013-08-06 16:26:14 -0700170 if (state.sortOrder == DisplayState.SORT_ORDER_DATE || mType == TYPE_RECENT_OPEN) {
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700171 sortOrder = new Document.DateComparator();
172 } else if (state.sortOrder == DisplayState.SORT_ORDER_NAME) {
173 sortOrder = new Document.NameComparator();
Jeff Sharkeyc6cbdf12013-08-07 16:22:02 -0700174 } else if (state.sortOrder == DisplayState.SORT_ORDER_SIZE) {
175 sortOrder = new Document.SizeComparator();
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700176 } else {
177 throw new IllegalArgumentException("Unknown sort order " + state.sortOrder);
178 }
179
Jeff Sharkeyc6cbdf12013-08-07 16:22:02 -0700180 return new DirectoryLoader(context, contentsUri, mType, null, sortOrder);
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700181 }
182
183 @Override
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700184 public void onLoadFinished(Loader<List<Document>> loader, List<Document> data) {
185 mAdapter.swapDocuments(data);
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700186 }
187
188 @Override
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700189 public void onLoaderReset(Loader<List<Document>> loader) {
190 mAdapter.swapDocuments(null);
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700191 }
192 };
193
Jeff Sharkey2e694f82013-08-06 16:26:14 -0700194 updateDisplayState();
195
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700196 return view;
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700197 }
198
199 @Override
200 public void onStart() {
201 super.onStart();
Jeff Sharkey2e694f82013-08-06 16:26:14 -0700202 getLoaderManager().restartLoader(mLoaderId, getArguments(), mCallbacks);
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700203 }
204
205 @Override
206 public void onStop() {
207 super.onStop();
Jeff Sharkey2e694f82013-08-06 16:26:14 -0700208 getLoaderManager().destroyLoader(mLoaderId);
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700209 }
210
Jeff Sharkey2e694f82013-08-06 16:26:14 -0700211 public void updateDisplayState() {
Jeff Sharkey3c28b792013-07-01 17:22:02 -0700212 final DisplayState state = getDisplayState(this);
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700213
Jeff Sharkeyc6cbdf12013-08-07 16:22:02 -0700214 // TODO: avoid kicking loader when nothing changed
Jeff Sharkey2e694f82013-08-06 16:26:14 -0700215 getLoaderManager().restartLoader(mLoaderId, getArguments(), mCallbacks);
216 mListView.smoothScrollToPosition(0);
217 mGridView.smoothScrollToPosition(0);
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700218
Jeff Sharkey3c28b792013-07-01 17:22:02 -0700219 mListView.setVisibility(state.mode == DisplayState.MODE_LIST ? View.VISIBLE : View.GONE);
220 mGridView.setVisibility(state.mode == DisplayState.MODE_GRID ? View.VISIBLE : View.GONE);
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700221
Jeff Sharkeyc317af82013-07-01 16:56:54 -0700222 final int choiceMode;
Jeff Sharkey3c28b792013-07-01 17:22:02 -0700223 if (state.allowMultiple) {
Jeff Sharkeyc317af82013-07-01 16:56:54 -0700224 choiceMode = ListView.CHOICE_MODE_MULTIPLE_MODAL;
225 } else {
226 choiceMode = ListView.CHOICE_MODE_NONE;
227 }
228
Jeff Sharkey8a8fb672013-05-07 12:41:33 -0700229 final int thumbSize;
Jeff Sharkey3c28b792013-07-01 17:22:02 -0700230 if (state.mode == DisplayState.MODE_GRID) {
Jeff Sharkey8a8fb672013-05-07 12:41:33 -0700231 thumbSize = getResources().getDimensionPixelSize(R.dimen.grid_width);
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700232 mListView.setAdapter(null);
Jeff Sharkeyc317af82013-07-01 16:56:54 -0700233 mListView.setChoiceMode(ListView.CHOICE_MODE_NONE);
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700234 mGridView.setAdapter(mAdapter);
Jeff Sharkeyc317af82013-07-01 16:56:54 -0700235 mGridView.setColumnWidth(getResources().getDimensionPixelSize(R.dimen.grid_width));
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700236 mGridView.setNumColumns(GridView.AUTO_FIT);
Jeff Sharkeyc317af82013-07-01 16:56:54 -0700237 mGridView.setChoiceMode(choiceMode);
238 mCurrentView = mGridView;
Jeff Sharkey3c28b792013-07-01 17:22:02 -0700239 } else if (state.mode == DisplayState.MODE_LIST) {
Jeff Sharkey8a8fb672013-05-07 12:41:33 -0700240 thumbSize = getResources().getDimensionPixelSize(android.R.dimen.app_icon_size);
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700241 mGridView.setAdapter(null);
Jeff Sharkeyc317af82013-07-01 16:56:54 -0700242 mGridView.setChoiceMode(ListView.CHOICE_MODE_NONE);
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700243 mListView.setAdapter(mAdapter);
Jeff Sharkeyc317af82013-07-01 16:56:54 -0700244 mListView.setChoiceMode(choiceMode);
245 mCurrentView = mListView;
Jeff Sharkey3c28b792013-07-01 17:22:02 -0700246 } else {
247 throw new IllegalStateException();
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700248 }
Jeff Sharkey8a8fb672013-05-07 12:41:33 -0700249
250 mThumbSize = new Point(thumbSize, thumbSize);
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700251 }
252
253 private OnItemClickListener mItemListener = new OnItemClickListener() {
254 @Override
255 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700256 final Document doc = mAdapter.getItem(position);
Jeff Sharkeyf339f252013-08-15 16:17:41 -0700257 if (mFilter.apply(doc)) {
258 ((DocumentsActivity) getActivity()).onDocumentPicked(doc);
259 }
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700260 }
261 };
262
Jeff Sharkeyc317af82013-07-01 16:56:54 -0700263 private MultiChoiceModeListener mMultiListener = new MultiChoiceModeListener() {
264 @Override
265 public boolean onCreateActionMode(ActionMode mode, Menu menu) {
266 mode.getMenuInflater().inflate(R.menu.mode_directory, menu);
267 return true;
268 }
269
270 @Override
271 public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
272 return true;
273 }
274
275 @Override
276 public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
277 if (item.getItemId() == R.id.menu_open) {
Jeff Sharkey5b535922013-08-02 15:55:26 -0700278 final Uri uri = getArguments().getParcelable(EXTRA_URI);
Jeff Sharkeyc317af82013-07-01 16:56:54 -0700279 final SparseBooleanArray checked = mCurrentView.getCheckedItemPositions();
280 final ArrayList<Document> docs = Lists.newArrayList();
281
282 final int size = checked.size();
283 for (int i = 0; i < size; i++) {
284 if (checked.valueAt(i)) {
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700285 final Document doc = mAdapter.getItem(checked.keyAt(i));
286 docs.add(doc);
Jeff Sharkeyc317af82013-07-01 16:56:54 -0700287 }
288 }
289
290 ((DocumentsActivity) getActivity()).onDocumentsPicked(docs);
291 return true;
292 } else {
293 return false;
294 }
295 }
296
297 @Override
298 public void onDestroyActionMode(ActionMode mode) {
299 // ignored
300 }
301
302 @Override
303 public void onItemCheckedStateChanged(
304 ActionMode mode, int position, long id, boolean checked) {
305 if (checked) {
Jeff Sharkeyc317af82013-07-01 16:56:54 -0700306 // Directories cannot be checked
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700307 final Document doc = mAdapter.getItem(position);
Jeff Sharkey2e694f82013-08-06 16:26:14 -0700308 if (doc.isDirectory()) {
Jeff Sharkeyc317af82013-07-01 16:56:54 -0700309 mCurrentView.setItemChecked(position, false);
310 }
311 }
312
313 mode.setTitle(getResources()
314 .getString(R.string.mode_selected_count, mCurrentView.getCheckedItemCount()));
315 }
316 };
317
Jeff Sharkey3c28b792013-07-01 17:22:02 -0700318 private static DisplayState getDisplayState(Fragment fragment) {
319 return ((DocumentsActivity) fragment.getActivity()).getDisplayState();
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700320 }
321
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700322 private class DocumentsAdapter extends BaseAdapter {
323 private List<Document> mDocuments;
324
325 public DocumentsAdapter() {
326 }
327
328 public void swapDocuments(List<Document> documents) {
329 mDocuments = documents;
Jeff Sharkeyc6cbdf12013-08-07 16:22:02 -0700330
331 if (documents != null && documents.isEmpty()) {
332 mEmptyView.setVisibility(View.VISIBLE);
333 } else {
334 mEmptyView.setVisibility(View.GONE);
335 }
336
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700337 notifyDataSetChanged();
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700338 }
339
340 @Override
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700341 public View getView(int position, View convertView, ViewGroup parent) {
342 final Context context = parent.getContext();
Jeff Sharkey2e694f82013-08-06 16:26:14 -0700343 final DisplayState state = getDisplayState(DirectoryFragment.this);
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700344
345 if (convertView == null) {
346 final LayoutInflater inflater = LayoutInflater.from(context);
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700347 if (state.mode == DisplayState.MODE_LIST) {
348 convertView = inflater.inflate(R.layout.item_doc_list, parent, false);
349 } else if (state.mode == DisplayState.MODE_GRID) {
350 convertView = inflater.inflate(R.layout.item_doc_grid, parent, false);
351 } else {
352 throw new IllegalStateException();
353 }
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700354 }
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700355
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700356 final Document doc = getItem(position);
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700357
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700358 final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
Jeff Sharkey2e694f82013-08-06 16:26:14 -0700359 final TextView title = (TextView) convertView.findViewById(android.R.id.title);
Jeff Sharkeyc6cbdf12013-08-07 16:22:02 -0700360 final View summaryGrid = convertView.findViewById(R.id.summary_grid);
Jeff Sharkey2e694f82013-08-06 16:26:14 -0700361 final ImageView icon1 = (ImageView) convertView.findViewById(android.R.id.icon1);
362 final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
363 final TextView date = (TextView) convertView.findViewById(R.id.date);
364 final TextView size = (TextView) convertView.findViewById(R.id.size);
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700365
Jeff Sharkey8a8fb672013-05-07 12:41:33 -0700366 final ThumbnailAsyncTask oldTask = (ThumbnailAsyncTask) icon.getTag();
367 if (oldTask != null) {
368 oldTask.cancel(false);
369 }
370
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700371 if (doc.isThumbnailSupported()) {
Jeff Sharkey8a8fb672013-05-07 12:41:33 -0700372 final Bitmap cachedResult = ThumbnailCache.get(context).get(doc.uri);
373 if (cachedResult != null) {
374 icon.setImageBitmap(cachedResult);
375 } else {
376 final ThumbnailAsyncTask task = new ThumbnailAsyncTask(icon, mThumbSize);
377 icon.setImageBitmap(null);
378 icon.setTag(task);
379 task.execute(doc.uri);
380 }
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700381 } else {
Jeff Sharkey76112212013-08-06 11:26:10 -0700382 icon.setImageDrawable(RootsCache.resolveDocumentIcon(
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700383 context, doc.uri.getAuthority(), doc.mimeType));
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700384 }
385
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700386 title.setText(doc.displayName);
Jeff Sharkey2e694f82013-08-06 16:26:14 -0700387
388 if (mType == TYPE_NORMAL || mType == TYPE_SEARCH) {
389 icon1.setVisibility(View.GONE);
390 if (doc.summary != null) {
391 summary.setText(doc.summary);
392 summary.setVisibility(View.VISIBLE);
393 } else {
394 summary.setVisibility(View.INVISIBLE);
395 }
396 } else if (mType == TYPE_RECENT_OPEN) {
397 final Root root = RootsCache.findRoot(context, doc);
398 icon1.setVisibility(View.VISIBLE);
399 icon1.setImageDrawable(root.icon);
400 summary.setText(root.getDirectoryString());
401 summary.setVisibility(View.VISIBLE);
402 }
403
Jeff Sharkeyc6cbdf12013-08-07 16:22:02 -0700404 if (summaryGrid != null) {
405 summaryGrid.setVisibility(
406 (summary.getVisibility() == View.VISIBLE) ? View.VISIBLE : View.GONE);
407 }
408
Jeff Sharkey8a8fb672013-05-07 12:41:33 -0700409 if (doc.lastModified == -1) {
410 date.setText(null);
411 } else {
412 date.setText(formatTime(context, doc.lastModified));
413 }
Jeff Sharkey2e694f82013-08-06 16:26:14 -0700414
415 if (state.showSize) {
416 size.setVisibility(View.VISIBLE);
Jeff Sharkeyf339f252013-08-15 16:17:41 -0700417 if (doc.isDirectory() || doc.size == -1) {
Jeff Sharkey2e694f82013-08-06 16:26:14 -0700418 size.setText(null);
419 } else {
420 size.setText(Formatter.formatFileSize(context, doc.size));
421 }
422 } else {
423 size.setVisibility(View.GONE);
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700424 }
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700425
426 return convertView;
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700427 }
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700428
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700429 @Override
430 public int getCount() {
431 return mDocuments != null ? mDocuments.size() : 0;
432 }
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700433
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700434 @Override
435 public Document getItem(int position) {
436 return mDocuments.get(position);
437 }
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700438
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700439 @Override
440 public long getItemId(int position) {
441 return getItem(position).uri.hashCode();
442 }
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700443 }
Jeff Sharkey8a8fb672013-05-07 12:41:33 -0700444
445 private static class ThumbnailAsyncTask extends AsyncTask<Uri, Void, Bitmap> {
446 private final ImageView mTarget;
447 private final Point mSize;
448
449 public ThumbnailAsyncTask(ImageView target, Point size) {
450 mTarget = target;
451 mSize = size;
452 }
453
454 @Override
455 protected void onPreExecute() {
456 mTarget.setTag(this);
457 }
458
459 @Override
460 protected Bitmap doInBackground(Uri... params) {
461 final Context context = mTarget.getContext();
462 final Uri uri = params[0];
463
464 Bitmap result = null;
465 try {
466 result = DocumentsContract.getThumbnail(
467 context.getContentResolver(), uri, mSize);
468 if (result != null) {
469 ThumbnailCache.get(context).put(uri, result);
470 }
471 } catch (Exception e) {
472 Log.w(TAG, "Failed to load thumbnail: " + e);
473 }
474 return result;
475 }
476
477 @Override
478 protected void onPostExecute(Bitmap result) {
479 if (mTarget.getTag() == this) {
480 mTarget.setImageBitmap(result);
481 mTarget.setTag(null);
482 }
483 }
484 }
485
486 private static String formatTime(Context context, long when) {
487 // TODO: DateUtils should make this easier
488 Time then = new Time();
489 then.set(when);
490 Time now = new Time();
491 now.setToNow();
492
493 int flags = DateUtils.FORMAT_NO_NOON | DateUtils.FORMAT_NO_MIDNIGHT
494 | DateUtils.FORMAT_ABBREV_ALL;
495
496 if (then.year != now.year) {
497 flags |= DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_DATE;
498 } else if (then.yearDay != now.yearDay) {
499 flags |= DateUtils.FORMAT_SHOW_DATE;
500 } else {
501 flags |= DateUtils.FORMAT_SHOW_TIME;
502 }
503
504 return DateUtils.formatDateTime(context, when, flags);
505 }
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700506}