Merge "Refactor DocumentHolder."
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Shared.java b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
index 570c9bf..c3366c3 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Shared.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
@@ -17,6 +17,8 @@
package com.android.documentsui;
import android.content.Context;
+import android.text.format.DateUtils;
+import android.text.format.Time;
/** @hide */
public final class Shared {
@@ -40,4 +42,26 @@
public static final String getQuantityString(Context context, int resourceId, int quantity) {
return context.getResources().getQuantityString(resourceId, quantity, quantity);
}
+
+ public static String formatTime(Context context, long when) {
+ // TODO: DateUtils should make this easier
+ Time then = new Time();
+ then.set(when);
+ Time now = new Time();
+ now.setToNow();
+
+ int flags = DateUtils.FORMAT_NO_NOON | DateUtils.FORMAT_NO_MIDNIGHT
+ | DateUtils.FORMAT_ABBREV_ALL;
+
+ if (then.year != now.year) {
+ flags |= DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_DATE;
+ } else if (then.yearDay != now.yearDay) {
+ flags |= DateUtils.FORMAT_SHOW_DATE;
+ } else {
+ flags |= DateUtils.FORMAT_SHOW_TIME;
+ }
+
+ return DateUtils.formatDateTime(context, when, flags);
+ }
+
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index b340cd0..035ae77 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -23,7 +23,6 @@
import static com.android.documentsui.State.MODE_UNKNOWN;
import static com.android.documentsui.State.SORT_ORDER_UNKNOWN;
import static com.android.documentsui.model.DocumentInfo.getCursorInt;
-import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.internal.util.Preconditions.checkState;
@@ -36,22 +35,18 @@
import android.app.FragmentTransaction;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.ClipData;
-import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.Loader;
import android.database.Cursor;
-import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.os.CancellationSignal;
-import android.os.OperationCanceledException;
import android.os.Parcelable;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
@@ -65,16 +60,12 @@
import android.support.v7.widget.RecyclerView.RecyclerListener;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.text.TextUtils;
-import android.text.format.DateUtils;
-import android.text.format.Formatter;
-import android.text.format.Time;
import android.util.Log;
import android.util.SparseArray;
import android.util.TypedValue;
import android.view.ActionMode;
import android.view.DragEvent;
import android.view.GestureDetector;
-import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
@@ -93,22 +84,17 @@
import com.android.documentsui.DocumentsActivity;
import com.android.documentsui.DocumentsApplication;
import com.android.documentsui.Events;
-import com.android.documentsui.IconUtils;
import com.android.documentsui.Menus;
import com.android.documentsui.MessageBar;
import com.android.documentsui.MimePredicate;
-import com.android.documentsui.ProviderExecutor;
-import com.android.documentsui.ProviderExecutor.Preemptable;
import com.android.documentsui.R;
import com.android.documentsui.RecentLoader;
import com.android.documentsui.RecentsProvider;
import com.android.documentsui.RecentsProvider.StateColumns;
-import com.android.documentsui.RootCursorWrapper;
import com.android.documentsui.RootsCache;
import com.android.documentsui.Shared;
import com.android.documentsui.Snackbars;
import com.android.documentsui.State;
-import com.android.documentsui.ThumbnailCache;
import com.android.documentsui.dirlist.MultiSelectManager.Selection;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
@@ -153,6 +139,8 @@
private Model.UpdateListener mModelUpdateListener = new ModelUpdateListener();
private ItemClickListener mItemClickListener = new ItemClickListener();
+ private IconHelper mIconHelper;
+
private View mEmptyView;
private RecyclerView mRecView;
@@ -162,9 +150,6 @@
private int mLastMode = MODE_UNKNOWN;
private int mLastSortOrder = SORT_ORDER_UNKNOWN;
private boolean mLastShowSize;
- private boolean mHideGridTitles;
- private boolean mSvelteRecents;
- private Point mThumbSize;
private DocumentsAdapter mAdapter;
private LoaderCallbacks<DirectoryResult> mCallbacks;
private FragmentTuner mTuner;
@@ -177,9 +162,6 @@
private MessageBar mMessageBar;
private View mProgressBar;
- private int mSelectedItemColor;
- private int mDefaultItemColor;
-
public static void showNormal(FragmentManager fm, RootInfo root, DocumentInfo doc, int anim) {
show(fm, TYPE_NORMAL, root, doc, null, anim);
}
@@ -307,12 +289,9 @@
final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
- mAdapter = new DocumentsAdapter(context);
+ mAdapter = new DocumentsAdapter();
mRecView.setAdapter(mAdapter);
- mDefaultItemColor = context.getResources().getColor(R.color.item_doc_background);
- mSelectedItemColor = context.getResources().getColor(R.color.item_doc_background_selected);
-
GestureDetector.SimpleOnGestureListener listener =
new GestureDetector.SimpleOnGestureListener() {
@Override
@@ -364,17 +343,22 @@
mTuner = FragmentTuner.pick(state);
mClipper = new DocumentClipper(context);
+ mIconHelper = new IconHelper(context, state.derivedMode);
+
+ boolean hideGridTitles;
if (mType == TYPE_RECENT_OPEN) {
// Hide titles when showing recents for picking images/videos
- mHideGridTitles = MimePredicate.mimeMatches(
+ hideGridTitles = MimePredicate.mimeMatches(
MimePredicate.VISUAL_MIMES, state.acceptMimes);
} else {
- mHideGridTitles = (doc != null) && doc.isGridTitlesHidden();
+ hideGridTitles = (doc != null) && doc.isGridTitlesHidden();
}
+ GridDocumentHolder.setHideTitles(hideGridTitles);
final ActivityManager am = (ActivityManager) context.getSystemService(
Context.ACTIVITY_SERVICE);
- mSvelteRecents = am.isLowRamDevice() && (mType == TYPE_RECENT_OPEN);
+ boolean svelte = am.isLowRamDevice() && (mType == TYPE_RECENT_OPEN);
+ mIconHelper.setThumbnailsEnabled(!svelte);
mCallbacks = new LoaderCallbacks<DirectoryResult>() {
@Override
@@ -585,12 +569,9 @@
* classes as needed.
*/
private void updateLayout(int mode) {
- final int thumbSize;
-
final LayoutManager layout;
switch (mode) {
case MODE_GRID:
- thumbSize = getResources().getDimensionPixelSize(R.dimen.grid_width);
if (mGridLayout == null) {
mGridLayout = new GridLayoutManager(getContext(), mColumnCount);
mGridLayout.setSpanSizeLookup(mAdapter.createSpanSizeLookup());
@@ -598,7 +579,6 @@
layout = mGridLayout;
break;
case MODE_LIST:
- thumbSize = getResources().getDimensionPixelSize(R.dimen.icon_size);
if (mListLayout == null) {
mListLayout = new LinearLayoutManager(getContext());
}
@@ -614,7 +594,7 @@
// imperatively calling this function.
mSelectionManager.handleLayoutChanged();
// setting layout manager automatically invalidates existing ViewHolders.
- mThumbSize = new Point(thumbSize, thumbSize);
+ mIconHelper.setMode(mode);
}
private int calculateColumnCount() {
@@ -775,14 +755,10 @@
}
}
- private static void cancelThumbnailTask(View view) {
+ private void cancelThumbnailTask(View view) {
final ImageView iconThumb = (ImageView) view.findViewById(R.id.icon_thumb);
if (iconThumb != null) {
- final ThumbnailAsyncTask oldTask = (ThumbnailAsyncTask) iconThumb.getTag();
- if (oldTask != null) {
- oldTask.preempt();
- iconThumb.setTag(null);
- }
+ mIconHelper.stopLoading(iconThumb);
}
}
@@ -921,59 +897,6 @@
return ((BaseActivity) getActivity()).getDisplayState();
}
- // Provide a reference to the views for each data item
- // Complex data items may need more than one view per item, and
- // you provide access to all the views for a data item in a view holder
- final class DocumentHolder
- extends RecyclerView.ViewHolder
- implements View.OnKeyListener
- {
- public String modelId;
- private ClickListener mClickListener;
- private View.OnKeyListener mKeyListener;
-
- public DocumentHolder(View view) {
- super(view);
- view.setOnKeyListener(this);
- }
-
- public void setSelected(boolean selected) {
- itemView.setActivated(selected);
- itemView.setBackgroundColor(selected ? mSelectedItemColor : mDefaultItemColor);
- }
-
- @Override
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- // Intercept enter key-up events, and treat them as clicks. Forward other events.
- if (event.getAction() == KeyEvent.ACTION_UP &&
- keyCode == KeyEvent.KEYCODE_ENTER) {
- if (mClickListener != null) {
- mClickListener.onClick(this);
- }
- return true;
- } else if (mKeyListener != null) {
- return mKeyListener.onKey(v, keyCode, event);
- }
- return false;
- }
-
- public void addClickListener(ClickListener listener) {
- // Just handle one for now; switch to a list if necessary.
- checkState(mClickListener == null);
- mClickListener = listener;
- }
-
- public void addOnKeyListener(View.OnKeyListener listener) {
- // Just handle one for now; switch to a list if necessary.
- checkState(mKeyListener == null);
- mKeyListener = listener;
- }
- }
-
- interface ClickListener {
- public void onClick(DocumentHolder doc);
- }
-
void showEmptyView() {
mEmptyView.setVisibility(View.VISIBLE);
mRecView.setVisibility(View.GONE);
@@ -1002,11 +925,9 @@
implements Model.UpdateListener {
private static final String TAG = "DocumentsAdapter";
- private static final int ITEM_TYPE_LAYOUT_DIVIDER = 0;
- private static final int ITEM_TYPE_DOCUMENT = 1;
- private static final int ITEM_TYPE_DIRECTORY = 2;
-
- private final Context mContext;
+ public static final int ITEM_TYPE_LAYOUT_DIVIDER = 0;
+ public static final int ITEM_TYPE_DOCUMENT = 1;
+ public static final int ITEM_TYPE_DIRECTORY = 2;
/**
* An ordered list of model IDs. This is the data structure that determines what shows up in
@@ -1018,10 +939,6 @@
// position where the transition happens.
private int mDividerPosition;
- public DocumentsAdapter(Context context) {
- mContext = context;
- }
-
public GridLayoutManager.SpanSizeLookup createSpanSizeLookup() {
return new GridLayoutManager.SpanSizeLookup() {
@Override
@@ -1039,43 +956,27 @@
@Override
public DocumentHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- View item = null;
+ if (viewType == ITEM_TYPE_LAYOUT_DIVIDER) {
+ return new EmptyDocumentHolder(getContext());
+ };
- switch (viewType) {
- case ITEM_TYPE_DIRECTORY:
- case ITEM_TYPE_DOCUMENT:
- item = createItemView(parent);
- break;
- case ITEM_TYPE_LAYOUT_DIVIDER:
- item = createLayoutWhitespace();
- break;
- }
-
- DocumentHolder holder = new DocumentHolder(item);
- holder.addClickListener(mItemClickListener);
- holder.addOnKeyListener(mSelectionManager);
- return holder;
- }
-
- private View createItemView(ViewGroup parent) {
+ DocumentHolder holder = null;
final State state = getDisplayState();
- final LayoutInflater inflater = LayoutInflater.from(getContext());
-
switch (state.derivedMode) {
case MODE_GRID:
- return inflater.inflate(R.layout.item_doc_grid, parent, false);
+ holder = new GridDocumentHolder(getContext(), parent, mIconHelper, viewType);
+ break;
case MODE_LIST:
- return inflater.inflate(R.layout.item_doc_list, parent, false);
+ holder = new ListDocumentHolder(getContext(), parent, mIconHelper);
+ break;
case MODE_UNKNOWN:
default:
throw new IllegalStateException("Unsupported layout mode.");
}
- }
- private View createLayoutWhitespace() {
- View whitespace = new View(getContext());
- whitespace.setVisibility(View.GONE);
- return whitespace;
+ holder.addClickListener(mItemClickListener);
+ holder.addOnKeyListener(mSelectionManager);
+ return holder;
}
/**
@@ -1108,165 +1009,17 @@
return;
}
- final Context context = getContext();
- final State state = getDisplayState();
- final RootsCache roots = DocumentsApplication.getRootsCache(context);
- final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache(
- context, mThumbSize);
+ String modelId = mModelIds.get(position);
+ Cursor cursor = mModel.getItem(modelId);
+ holder.bind(cursor, modelId, getDisplayState());
- holder.modelId = mModelIds.get(position);
- final Cursor cursor = mModel.getItem(holder.modelId);
- checkNotNull(cursor, "Cursor cannot be null.");
-
- final String docAuthority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
- final String docRootId = getCursorString(cursor, RootCursorWrapper.COLUMN_ROOT_ID);
- final String docId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
- final String docDisplayName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME);
- final long docLastModified = getCursorLong(cursor, Document.COLUMN_LAST_MODIFIED);
- final int docIcon = getCursorInt(cursor, Document.COLUMN_ICON);
final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
- final String docSummary = getCursorString(cursor, Document.COLUMN_SUMMARY);
- final long docSize = getCursorLong(cursor, Document.COLUMN_SIZE);
- final View itemView = holder.itemView;
-
- holder.setSelected(isSelected(holder.modelId));
-
- final ImageView iconMime = (ImageView) itemView.findViewById(R.id.icon_mime);
- final ImageView iconThumb = (ImageView) itemView.findViewById(R.id.icon_thumb);
- final TextView title = (TextView) itemView.findViewById(android.R.id.title);
- final ImageView icon1 = (ImageView) itemView.findViewById(android.R.id.icon1);
- final TextView summary = (TextView) itemView.findViewById(android.R.id.summary);
- final TextView date = (TextView) itemView.findViewById(R.id.date);
- final TextView size = (TextView) itemView.findViewById(R.id.size);
-
- final ThumbnailAsyncTask oldTask = (ThumbnailAsyncTask) iconThumb.getTag();
- if (oldTask != null) {
- oldTask.preempt();
- iconThumb.setTag(null);
- }
-
- iconMime.animate().cancel();
- iconThumb.animate().cancel();
-
- final boolean supportsThumbnail = (docFlags & Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
- final boolean allowThumbnail = (state.derivedMode == MODE_GRID)
- || MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, docMimeType);
- final boolean showThumbnail = supportsThumbnail && allowThumbnail && !mSvelteRecents;
-
- final boolean enabled = mTuner.isDocumentEnabled(docMimeType, docFlags);
- final float iconAlpha = (state.derivedMode == MODE_LIST && !enabled) ? 0.5f : 1f;
-
- boolean cacheHit = false;
- if (showThumbnail) {
- final Uri uri = DocumentsContract.buildDocumentUri(docAuthority, docId);
- final Bitmap cachedResult = thumbs.get(uri);
- if (cachedResult != null) {
- iconThumb.setImageBitmap(cachedResult);
- cacheHit = true;
- } else {
- iconThumb.setImageDrawable(null);
- // TODO: Hang this off DocumentHolder?
- final ThumbnailAsyncTask task = new ThumbnailAsyncTask(
- uri, iconMime, iconThumb, mThumbSize, iconAlpha);
- iconThumb.setTag(task);
- ProviderExecutor.forAuthority(docAuthority).execute(task);
- }
- }
-
- // Always throw MIME icon into place, even when a thumbnail is being
- // loaded in background.
- if (cacheHit) {
- iconMime.setAlpha(0f);
- iconMime.setImageDrawable(null);
- iconThumb.setAlpha(1f);
- } else {
- iconMime.setAlpha(1f);
- iconThumb.setAlpha(0f);
- iconThumb.setImageDrawable(null);
- iconMime.setImageDrawable(
- getDocumentIcon(mContext, docAuthority, docId, docMimeType, docIcon, state));
- }
-
- if ((state.derivedMode == MODE_GRID) && mHideGridTitles) {
- title.setVisibility(View.GONE);
- } else {
- title.setText(docDisplayName);
- title.setVisibility(View.VISIBLE);
- }
-
- Drawable iconDrawable = null;
- if (mType == TYPE_RECENT_OPEN) {
- // We've already had to enumerate roots before any results can
- // be shown, so this will never block.
- final RootInfo root = roots.getRootBlocking(docAuthority, docRootId);
- iconDrawable = root.loadIcon(mContext);
-
- if (summary != null) {
- final boolean alwaysShowSummary = getResources()
- .getBoolean(R.bool.always_show_summary);
- if (alwaysShowSummary) {
- summary.setText(root.getDirectoryString());
- summary.setVisibility(View.VISIBLE);
- } else {
- if (iconDrawable != null && roots.isIconUniqueBlocking(root)) {
- // No summary needed if icon speaks for itself
- summary.setVisibility(View.INVISIBLE);
- } else {
- summary.setText(root.getDirectoryString());
- summary.setVisibility(View.VISIBLE);
- summary.setTextAlignment(TextView.TEXT_ALIGNMENT_TEXT_END);
- }
- }
- }
- } else {
- // Directories showing thumbnails in grid mode get a little icon
- // hint to remind user they're a directory.
- if (Document.MIME_TYPE_DIR.equals(docMimeType) && state.derivedMode == MODE_GRID
- && showThumbnail) {
- iconDrawable = IconUtils.applyTintAttr(mContext, R.drawable.ic_doc_folder,
- android.R.attr.textColorPrimaryInverse);
- }
-
- if (summary != null) {
- if (docSummary != null) {
- summary.setText(docSummary);
- summary.setVisibility(View.VISIBLE);
- } else {
- summary.setVisibility(View.INVISIBLE);
- }
- }
- }
-
- if (iconDrawable != null) {
- icon1.setVisibility(View.VISIBLE);
- icon1.setImageDrawable(iconDrawable);
- } else {
- icon1.setVisibility(View.GONE);
- }
-
- if (docLastModified == -1) {
- date.setText(null);
- } else {
- date.setText(formatTime(mContext, docLastModified));
- }
-
- if (!state.showSize || Document.MIME_TYPE_DIR.equals(docMimeType) || docSize == -1) {
- size.setVisibility(View.GONE);
- } else {
- size.setVisibility(View.VISIBLE);
- size.setText(Formatter.formatFileSize(mContext, docSize));
- }
-
- setEnabledRecursive(itemView, enabled);
-
- iconMime.setAlpha(iconAlpha);
- iconThumb.setAlpha(iconAlpha);
- icon1.setAlpha(iconAlpha);
-
+ holder.setSelected(isSelected(modelId));
+ holder.setEnabled(mTuner.isDocumentEnabled(docMimeType, docFlags));
if (DEBUG_ENABLE_DND) {
- setupDragAndDropOnDocumentView(itemView, cursor);
+ setupDragAndDropOnDocumentView(holder.itemView, cursor);
}
}
@@ -1389,27 +1142,6 @@
}
}
- private static String formatTime(Context context, long when) {
- // TODO: DateUtils should make this easier
- Time then = new Time();
- then.set(when);
- Time now = new Time();
- now.setToNow();
-
- int flags = DateUtils.FORMAT_NO_NOON | DateUtils.FORMAT_NO_MIDNIGHT
- | DateUtils.FORMAT_ABBREV_ALL;
-
- if (then.year != now.year) {
- flags |= DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_DATE;
- } else if (then.yearDay != now.yearDay) {
- flags |= DateUtils.FORMAT_SHOW_DATE;
- } else {
- flags |= DateUtils.FORMAT_SHOW_TIME;
- }
-
- return DateUtils.formatDateTime(context, when, flags);
- }
-
private String findCommonMimeType(List<String> mimeTypes) {
String[] commonType = mimeTypes.get(0).split("/");
if (commonType.length != 2) {
@@ -1434,19 +1166,6 @@
return commonType[0] + "/" + commonType[1];
}
- private void setEnabledRecursive(View v, boolean enabled) {
- if (v == null) return;
- if (v.isEnabled() == enabled) return;
- v.setEnabled(enabled);
-
- if (v instanceof ViewGroup) {
- final ViewGroup vg = (ViewGroup) v;
- for (int i = vg.getChildCount() - 1; i >= 0; i--) {
- setEnabledRecursive(vg.getChildAt(i), enabled);
- }
- }
- }
-
private void copyFromClipboard() {
new AsyncTask<Void, Void, List<DocumentInfo>>() {
@@ -1721,89 +1440,12 @@
private Drawable getDragShadowIcon(List<DocumentInfo> docs) {
if (docs.size() == 1) {
final DocumentInfo doc = docs.get(0);
- return getDocumentIcon(getActivity(), doc.authority, doc.documentId,
- doc.mimeType, doc.icon, getDisplayState());
+ return mIconHelper.getDocumentIcon(getActivity(), doc.authority, doc.documentId,
+ doc.mimeType, doc.icon);
}
return getActivity().getDrawable(R.drawable.ic_doc_generic);
}
- public static Drawable getDocumentIcon(Context context, String docAuthority, String docId,
- String docMimeType, int docIcon, State state) {
- if (docIcon != 0) {
- return IconUtils.loadPackageIcon(context, docAuthority, docIcon);
- } else {
- return IconUtils.loadMimeIcon(context, docMimeType, docAuthority, docId,
- state.derivedMode);
- }
- }
-
- private static class ThumbnailAsyncTask extends AsyncTask<Uri, Void, Bitmap>
- implements Preemptable {
- private final Uri mUri;
- private final ImageView mIconMime;
- private final ImageView mIconThumb;
- private final Point mThumbSize;
- private final float mTargetAlpha;
- private final CancellationSignal mSignal;
-
- public ThumbnailAsyncTask(Uri uri, ImageView iconMime, ImageView iconThumb, Point thumbSize,
- float targetAlpha) {
- mUri = uri;
- mIconMime = iconMime;
- mIconThumb = iconThumb;
- mThumbSize = thumbSize;
- mTargetAlpha = targetAlpha;
- mSignal = new CancellationSignal();
- }
-
- @Override
- public void preempt() {
- cancel(false);
- mSignal.cancel();
- }
-
- @Override
- protected Bitmap doInBackground(Uri... params) {
- if (isCancelled()) return null;
-
- final Context context = mIconThumb.getContext();
- final ContentResolver resolver = context.getContentResolver();
-
- ContentProviderClient client = null;
- Bitmap result = null;
- try {
- client = DocumentsApplication.acquireUnstableProviderOrThrow(
- resolver, mUri.getAuthority());
- result = DocumentsContract.getDocumentThumbnail(client, mUri, mThumbSize, mSignal);
- if (result != null) {
- final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache(
- context, mThumbSize);
- thumbs.put(mUri, result);
- }
- } catch (Exception e) {
- if (!(e instanceof OperationCanceledException)) {
- Log.w(TAG, "Failed to load thumbnail for " + mUri + ": " + e);
- }
- } finally {
- ContentProviderClient.releaseQuietly(client);
- }
- return result;
- }
-
- @Override
- protected void onPostExecute(Bitmap result) {
- if (mIconThumb.getTag() == this && result != null) {
- mIconThumb.setTag(null);
- mIconThumb.setImageBitmap(result);
-
- mIconMime.setAlpha(mTargetAlpha);
- mIconMime.animate().alpha(0f).start();
- mIconThumb.setAlpha(0f);
- mIconThumb.animate().alpha(mTargetAlpha).start();
- }
- }
- }
-
private class DrawableShadowBuilder extends View.DragShadowBuilder {
private final Drawable mShadow;
@@ -1854,7 +1496,7 @@
return mSelectionManager.getSelection().contains(modelId);
}
- private class ItemClickListener implements ClickListener {
+ private class ItemClickListener implements DocumentHolder.ClickListener {
@Override
public void onClick(DocumentHolder doc) {
if (mSelectionManager.hasSelection()) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java
new file mode 100644
index 0000000..a01021f
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.dirlist;
+
+import static com.android.internal.util.Preconditions.checkState;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.RecyclerView;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.documentsui.R;
+import com.android.documentsui.State;
+
+public abstract class DocumentHolder
+ extends RecyclerView.ViewHolder
+ implements View.OnKeyListener {
+
+ public @Nullable String modelId;
+
+ final int mSelectedItemColor;
+ final int mDefaultItemColor;
+ final boolean mAlwaysShowSummary;
+ final Context mContext;
+ final IconHelper mIconHelper;
+
+ private ListDocumentHolder.ClickListener mClickListener;
+ private View.OnKeyListener mKeyListener;
+
+ public DocumentHolder(Context context, ViewGroup parent, int layout, IconHelper iconHelper) {
+ this(context, inflateLayout(context, parent, layout), iconHelper);
+ }
+
+ public DocumentHolder(Context context, View item, IconHelper iconHelper) {
+ super(item);
+
+ itemView.setOnKeyListener(this);
+
+ mContext = context;
+
+ mDefaultItemColor = context.getColor(R.color.item_doc_background);
+ mSelectedItemColor = context.getColor(R.color.item_doc_background_selected);
+ mAlwaysShowSummary = context.getResources().getBoolean(R.bool.always_show_summary);
+
+ mIconHelper = iconHelper;
+ }
+
+ /**
+ * Binds the view to the given item data.
+ * @param cursor
+ * @param modelId
+ * @param state
+ */
+ public abstract void bind(Cursor cursor, String modelId, State state);
+
+ public void setSelected(boolean selected) {
+ itemView.setActivated(selected);
+ itemView.setBackgroundColor(selected ? mSelectedItemColor : mDefaultItemColor);
+ }
+
+ @Override
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+ // Intercept enter key-up events, and treat them as clicks. Forward other events.
+ if (event.getAction() == KeyEvent.ACTION_UP &&
+ keyCode == KeyEvent.KEYCODE_ENTER) {
+ if (mClickListener != null) {
+ mClickListener.onClick(this);
+ }
+ return true;
+ } else if (mKeyListener != null) {
+ return mKeyListener.onKey(v, keyCode, event);
+ }
+ return false;
+ }
+
+ public void addClickListener(ListDocumentHolder.ClickListener listener) {
+ // Just handle one for now; switch to a list if necessary.
+ checkState(mClickListener == null);
+ mClickListener = listener;
+ }
+
+ public void addOnKeyListener(View.OnKeyListener listener) {
+ // Just handle one for now; switch to a list if necessary.
+ checkState(mKeyListener == null);
+ mKeyListener = listener;
+ }
+
+ public void setEnabled(boolean enabled) {
+ setEnabledRecursive(itemView, enabled);
+ }
+
+ static void setEnabledRecursive(View itemView, boolean enabled) {
+ if (itemView == null) return;
+ if (itemView.isEnabled() == enabled) return;
+ itemView.setEnabled(enabled);
+
+ if (itemView instanceof ViewGroup) {
+ final ViewGroup vg = (ViewGroup) itemView;
+ for (int i = vg.getChildCount() - 1; i >= 0; i--) {
+ setEnabledRecursive(vg.getChildAt(i), enabled);
+ }
+ }
+ }
+
+ private static View inflateLayout(Context context, ViewGroup parent, int layout) {
+ final LayoutInflater inflater = LayoutInflater.from(context);
+ return inflater.inflate(layout, parent, false);
+ }
+
+ interface ClickListener {
+ public void onClick(DocumentHolder doc);
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/EmptyDocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/EmptyDocumentHolder.java
new file mode 100644
index 0000000..0bdf530
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/EmptyDocumentHolder.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.dirlist;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.view.View;
+
+import com.android.documentsui.State;
+
+final class EmptyDocumentHolder extends DocumentHolder {
+ public EmptyDocumentHolder(Context context) {
+ super(context, new View(context), null);
+ itemView.setVisibility(View.GONE);
+ }
+
+ public void bind(Cursor cursor, String modelId, State state) {
+ // Nothing to bind.
+ return;
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java
new file mode 100644
index 0000000..43256c3
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.dirlist;
+
+import static com.android.documentsui.model.DocumentInfo.getCursorInt;
+import static com.android.documentsui.model.DocumentInfo.getCursorLong;
+import static com.android.documentsui.model.DocumentInfo.getCursorString;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+import android.text.format.Formatter;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.documentsui.R;
+import com.android.documentsui.RootCursorWrapper;
+import com.android.documentsui.Shared;
+import com.android.documentsui.State;
+
+final class GridDocumentHolder extends DocumentHolder {
+ private static boolean mHideTitles;
+
+ public GridDocumentHolder(
+ Context context, ViewGroup parent, IconHelper thumbnailLoader, int viewType) {
+ super(context, parent, R.layout.item_doc_grid, thumbnailLoader);
+ }
+
+ /**
+ * Bind this view to the given document for display.
+ * @param cursor Pointing to the item to be bound.
+ * @param modelId The model ID of the item.
+ * @param state Current display state.
+ */
+ public void bind(Cursor cursor, String modelId, State state) {
+ this.modelId = modelId;
+
+ checkNotNull(cursor, "Cursor cannot be null.");
+
+ final String docAuthority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
+ final String docId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
+ final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+ final String docDisplayName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME);
+ final long docLastModified = getCursorLong(cursor, Document.COLUMN_LAST_MODIFIED);
+ final int docIcon = getCursorInt(cursor, Document.COLUMN_ICON);
+ final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
+ final long docSize = getCursorLong(cursor, Document.COLUMN_SIZE);
+
+ final TextView title = (TextView) itemView.findViewById(android.R.id.title);
+ final TextView date = (TextView) itemView.findViewById(R.id.date);
+ final TextView size = (TextView) itemView.findViewById(R.id.size);
+ final ImageView iconMime = (ImageView) itemView.findViewById(R.id.icon_mime);
+ final ImageView iconThumb = (ImageView) itemView.findViewById(R.id.icon_thumb);
+
+ mIconHelper.stopLoading(iconThumb);
+
+ iconMime.animate().cancel();
+ iconMime.setAlpha(1f);
+ iconThumb.animate().cancel();
+ iconThumb.setAlpha(0f);
+
+ final Uri uri = DocumentsContract.buildDocumentUri(docAuthority, docId);
+ mIconHelper.loadThumbnail(uri, docMimeType, docFlags, docIcon, iconThumb, iconMime);
+
+ if (mHideTitles) {
+ title.setVisibility(View.GONE);
+ } else {
+ title.setText(docDisplayName);
+ title.setVisibility(View.VISIBLE);
+ }
+
+ if (docLastModified == -1) {
+ date.setText(null);
+ } else {
+ date.setText(Shared.formatTime(mContext, docLastModified));
+ }
+
+ if (!state.showSize || Document.MIME_TYPE_DIR.equals(docMimeType) || docSize == -1) {
+ size.setVisibility(View.GONE);
+ } else {
+ size.setVisibility(View.VISIBLE);
+ size.setText(Formatter.formatFileSize(mContext, docSize));
+ }
+ }
+
+ /**
+ * Sets whether to hide titles on subsequently created GridDocumentHolder items.
+ * @param hideTitles
+ */
+ public static void setHideTitles(boolean hideTitles) {
+ mHideTitles = hideTitles;
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/IconHelper.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/IconHelper.java
new file mode 100644
index 0000000..ff70eaf
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/IconHelper.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.dirlist;
+
+import static com.android.documentsui.Shared.DEBUG;
+import static com.android.documentsui.State.MODE_GRID;
+import static com.android.documentsui.State.MODE_LIST;
+import static com.android.documentsui.State.MODE_UNKNOWN;
+
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Point;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.CancellationSignal;
+import android.os.OperationCanceledException;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+import android.util.Log;
+import android.widget.ImageView;
+
+import com.android.documentsui.DocumentsApplication;
+import com.android.documentsui.IconUtils;
+import com.android.documentsui.MimePredicate;
+import com.android.documentsui.ProviderExecutor;
+import com.android.documentsui.ProviderExecutor.Preemptable;
+import com.android.documentsui.R;
+import com.android.documentsui.ThumbnailCache;
+
+/**
+ * A class to assist with loading and managing the Images (i.e. thumbnails and icons) associated
+ * with items in the directory listing.
+ */
+public class IconHelper {
+ private static String TAG = "IconHelper";
+
+ private Context mContext;
+ private ThumbnailCache mCache;
+ private Point mThumbSize;
+ // The display mode (MODE_GRID, MODE_LIST, etc).
+ private int mMode;
+ private boolean mThumbnailsEnabled = true;
+
+ /**
+ * @param context
+ * @param mode MODE_GRID or MODE_LIST
+ */
+ public IconHelper(Context context, int mode) {
+ mContext = context;
+ setMode(mode);
+ mCache = DocumentsApplication.getThumbnailsCache(context, mThumbSize);
+ }
+
+ /**
+ * Enables or disables thumbnails. When thumbnails are disabled, mime icons (or custom icons, if
+ * specified by the document) are used instead.
+ *
+ * @param enabled
+ */
+ public void setThumbnailsEnabled(boolean enabled) {
+ mThumbnailsEnabled = enabled;
+ }
+
+ /**
+ * Sets the current display mode. This affects the thumbnail sizes that are loaded.
+ * @param mode See {@link State.MODE_LIST} and {@link State.MODE_GRID}.
+ */
+ public void setMode(int mode) {
+ // TODO: Instead of exposing setMode, make the mode final, and make separate instances for
+ // grid/list.
+ int thumbSize;
+ switch (mode) {
+ case MODE_GRID:
+ thumbSize = mContext.getResources().getDimensionPixelSize(R.dimen.grid_width);
+ break;
+ case MODE_LIST:
+ thumbSize = mContext.getResources().getDimensionPixelSize(R.dimen.icon_size);
+ break;
+ case MODE_UNKNOWN:
+ default:
+ throw new IllegalArgumentException("Unsupported layout mode: " + mode);
+ }
+ mMode = mode;
+ mThumbSize = new Point(thumbSize, thumbSize);
+ }
+
+ /**
+ * Cancels any ongoing load operations associated with the given ImageView.
+ * @param icon
+ */
+ public void stopLoading(ImageView icon) {
+ final LoaderTask oldTask = (LoaderTask) icon.getTag();
+ if (oldTask != null) {
+ oldTask.preempt();
+ icon.setTag(null);
+ }
+ }
+
+ /** Internal task for loading thumbnails asynchronously. */
+ private static class LoaderTask
+ extends AsyncTask<Uri, Void, Bitmap>
+ implements Preemptable {
+ private final Uri mUri;
+ private final ImageView mIconMime;
+ private final ImageView mIconThumb;
+ private final Point mThumbSize;
+ private final CancellationSignal mSignal;
+
+ public LoaderTask(Uri uri, ImageView iconMime, ImageView iconThumb,
+ Point thumbSize) {
+ mUri = uri;
+ mIconMime = iconMime;
+ mIconThumb = iconThumb;
+ mThumbSize = thumbSize;
+ mSignal = new CancellationSignal();
+ if (DEBUG) Log.d(TAG, "Starting icon loader task for " + mUri);
+ }
+
+ @Override
+ public void preempt() {
+ if (DEBUG) Log.d(TAG, "Icon loader task for " + mUri + " was cancelled.");
+ cancel(false);
+ mSignal.cancel();
+ }
+
+ @Override
+ protected Bitmap doInBackground(Uri... params) {
+ if (isCancelled())
+ return null;
+
+ final Context context = mIconThumb.getContext();
+ final ContentResolver resolver = context.getContentResolver();
+
+ ContentProviderClient client = null;
+ Bitmap result = null;
+ try {
+ client = DocumentsApplication.acquireUnstableProviderOrThrow(
+ resolver, mUri.getAuthority());
+ result = DocumentsContract.getDocumentThumbnail(client, mUri, mThumbSize, mSignal);
+ if (result != null) {
+ final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache(
+ context, mThumbSize);
+ thumbs.put(mUri, result);
+ }
+ } catch (Exception e) {
+ if (!(e instanceof OperationCanceledException)) {
+ Log.w(TAG, "Failed to load thumbnail for " + mUri + ": " + e);
+ }
+ } finally {
+ ContentProviderClient.releaseQuietly(client);
+ }
+ return result;
+ }
+
+ @Override
+ protected void onPostExecute(Bitmap result) {
+ if (DEBUG) Log.d(TAG, "Loader task for " + mUri + " completed");
+
+ if (mIconThumb.getTag() == this && result != null) {
+ mIconThumb.setTag(null);
+ mIconThumb.setImageBitmap(result);
+
+ float alpha = mIconMime.getAlpha();
+ mIconMime.animate().alpha(0f).start();
+ mIconThumb.setAlpha(0f);
+ mIconThumb.animate().alpha(alpha).start();
+ }
+ }
+ }
+
+ /**
+ * Load thumbnails for a directory list item.
+ * @param uri The URI for the file being represented.
+ * @param mimeType The mime type of the file being represented.
+ * @param docFlags Flags for the file being represented.
+ * @param docIcon Custom icon (if any) for the file being requested.
+ * @param iconThumb The itemview's thumbnail icon.
+ * @param iconMime The itemview's mime icon.
+ * @return
+ */
+ public void loadThumbnail(Uri uri, String mimeType, int docFlags, int docIcon,
+ ImageView iconThumb, ImageView iconMime) {
+ boolean cacheHit = false;
+
+ final String docAuthority = uri.getAuthority();
+
+ final boolean supportsThumbnail = (docFlags & Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
+ final boolean allowThumbnail = (mMode == MODE_GRID)
+ || MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, mimeType);
+ final boolean showThumbnail = supportsThumbnail && allowThumbnail && mThumbnailsEnabled;
+ if (showThumbnail) {
+ final Bitmap cachedResult = mCache.get(uri);
+ if (cachedResult != null) {
+ iconThumb.setImageBitmap(cachedResult);
+ cacheHit = true;
+ } else {
+ iconThumb.setImageDrawable(null);
+ final LoaderTask task = new LoaderTask(uri, iconMime, iconThumb, mThumbSize);
+ iconThumb.setTag(task);
+ ProviderExecutor.forAuthority(docAuthority).execute(task);
+ }
+ }
+
+ if (cacheHit) {
+ iconMime.setImageDrawable(null);
+ iconMime.setAlpha(0f);
+ iconThumb.setAlpha(1f);
+ } else {
+ // Add a mime icon if the thumbnail is being loaded in the background.
+ iconThumb.setImageDrawable(null);
+ iconMime.setImageDrawable(getDocumentIcon(
+ mContext, docAuthority, DocumentsContract.getDocumentId(uri), mimeType, docIcon));
+ iconMime.setAlpha(1f);
+ iconThumb.setAlpha(0f);
+ }
+ }
+
+ /**
+ * Gets a mime icon or package icon for a file.
+ * @param context
+ * @param authority The authority string of the file.
+ * @param id The document ID of the file.
+ * @param mimeType The mime type of the file.
+ * @param icon The custom icon (if any) of the file.
+ * @return
+ */
+ public Drawable getDocumentIcon(Context context, String authority, String id,
+ String mimeType, int icon) {
+ if (icon != 0) {
+ return IconUtils.loadPackageIcon(context, authority, icon);
+ } else {
+ return IconUtils.loadMimeIcon(context, mimeType, authority, id, mMode);
+ }
+ }
+
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
new file mode 100644
index 0000000..b46a0e5a
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.dirlist;
+
+import static com.android.documentsui.model.DocumentInfo.getCursorInt;
+import static com.android.documentsui.model.DocumentInfo.getCursorLong;
+import static com.android.documentsui.model.DocumentInfo.getCursorString;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+import android.text.format.Formatter;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.documentsui.R;
+import com.android.documentsui.RootCursorWrapper;
+import com.android.documentsui.Shared;
+import com.android.documentsui.State;
+
+final class ListDocumentHolder extends DocumentHolder {
+ final ImageView mIconMime;
+ final ImageView mIconThumb;
+ final ImageView mIcon1;
+
+ public ListDocumentHolder(Context context, ViewGroup parent, IconHelper thumbnailLoader) {
+ super(context, parent, R.layout.item_doc_list, thumbnailLoader);
+
+ mIconMime = (ImageView) itemView.findViewById(R.id.icon_mime);
+ mIconThumb = (ImageView) itemView.findViewById(R.id.icon_thumb);
+ mIcon1 = (ImageView) itemView.findViewById(android.R.id.icon1);
+ }
+
+ /**
+ * Bind this view to the given document for display.
+ * @param cursor Pointing to the item to be bound.
+ * @param modelId The model ID of the item.
+ * @param state Current display state.
+ */
+ @Override
+ public void bind(Cursor cursor, String modelId, State state) {
+ this.modelId = modelId;
+
+ checkNotNull(cursor, "Cursor cannot be null.");
+
+ final String docAuthority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
+ final String docId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
+ final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+ final String docDisplayName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME);
+ final long docLastModified = getCursorLong(cursor, Document.COLUMN_LAST_MODIFIED);
+ final int docIcon = getCursorInt(cursor, Document.COLUMN_ICON);
+ final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
+ final String docSummary = getCursorString(cursor, Document.COLUMN_SUMMARY);
+ final long docSize = getCursorLong(cursor, Document.COLUMN_SIZE);
+
+ final TextView title = (TextView) itemView.findViewById(android.R.id.title);
+ final TextView summary = (TextView) itemView.findViewById(android.R.id.summary);
+ final TextView date = (TextView) itemView.findViewById(R.id.date);
+ final TextView size = (TextView) itemView.findViewById(R.id.size);
+
+ mIconHelper.stopLoading(mIconThumb);
+
+ mIconMime.animate().cancel();
+ mIconThumb.animate().cancel();
+
+ final Uri uri = DocumentsContract.buildDocumentUri(docAuthority, docId);
+ mIconHelper.loadThumbnail(uri, docMimeType, docFlags, docIcon, mIconThumb, mIconMime);
+
+ title.setText(docDisplayName);
+ title.setVisibility(View.VISIBLE);
+
+ if (docSummary != null) {
+ summary.setText(docSummary);
+ summary.setVisibility(View.VISIBLE);
+ } else {
+ summary.setVisibility(View.INVISIBLE);
+ }
+
+ if (docLastModified == -1) {
+ date.setText(null);
+ } else {
+ date.setText(Shared.formatTime(mContext, docLastModified));
+ }
+
+ if (!state.showSize || Document.MIME_TYPE_DIR.equals(docMimeType) || docSize == -1) {
+ size.setVisibility(View.GONE);
+ } else {
+ size.setVisibility(View.VISIBLE);
+ size.setText(Formatter.formatFileSize(mContext, docSize));
+ }
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ super.setEnabled(enabled);
+ final float iconAlpha = enabled ? 1f : 0.5f;
+ mIconMime.setAlpha(iconAlpha);
+ mIconThumb.setAlpha(iconAlpha);
+ mIcon1.setAlpha(iconAlpha);
+ }
+}