Home | History | Annotate | Download | only in dirlist
      1 /*
      2  * Copyright (C) 2015 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 
     17 package com.android.documentsui.dirlist;
     18 
     19 import static com.android.documentsui.base.DocumentInfo.getCursorString;
     20 
     21 import android.annotation.Nullable;
     22 import android.content.Context;
     23 import android.database.Cursor;
     24 import android.graphics.Rect;
     25 import android.text.format.Formatter;
     26 import android.view.MotionEvent;
     27 import android.view.View;
     28 import android.view.ViewGroup;
     29 import android.widget.ImageView;
     30 import android.widget.LinearLayout;
     31 import android.widget.TextView;
     32 
     33 import com.android.documentsui.R;
     34 import com.android.documentsui.base.DocumentInfo;
     35 import com.android.documentsui.base.Lookup;
     36 import com.android.documentsui.base.Shared;
     37 import com.android.documentsui.roots.RootCursorWrapper;
     38 
     39 final class ListDocumentHolder extends DocumentHolder {
     40 
     41     private final TextView mTitle;
     42     private final @Nullable LinearLayout mDetails;  // Container of date/size/summary
     43     private final TextView mDate;
     44     private final TextView mSize;
     45     private final TextView mType;
     46     private final TextView mSummary;
     47     private final ImageView mIconMime;
     48     private final ImageView mIconThumb;
     49     private final ImageView mIconCheck;
     50     private final View mIconLayout;
     51 
     52     private final IconHelper mIconHelper;
     53     private final Lookup<String, String> mFileTypeLookup;
     54     // This is used in as a convenience in our bind method.
     55     private final DocumentInfo mDoc;
     56 
     57     public ListDocumentHolder(Context context, ViewGroup parent, IconHelper iconHelper,
     58             Lookup<String, String> fileTypeLookup) {
     59         super(context, parent, R.layout.item_doc_list);
     60 
     61         mIconLayout = itemView.findViewById(android.R.id.icon);
     62         mIconMime = (ImageView) itemView.findViewById(R.id.icon_mime);
     63         mIconThumb = (ImageView) itemView.findViewById(R.id.icon_thumb);
     64         mIconCheck = (ImageView) itemView.findViewById(R.id.icon_check);
     65         mTitle = (TextView) itemView.findViewById(android.R.id.title);
     66         mSummary = (TextView) itemView.findViewById(android.R.id.summary);
     67         mSize = (TextView) itemView.findViewById(R.id.size);
     68         mDate = (TextView) itemView.findViewById(R.id.date);
     69         mType = (TextView) itemView.findViewById(R.id.file_type);
     70         // Warning: mDetails view doesn't exists in layout-sw720dp-land layout
     71         mDetails = (LinearLayout) itemView.findViewById(R.id.line2);
     72 
     73         mIconHelper = iconHelper;
     74         mFileTypeLookup = fileTypeLookup;
     75         mDoc = new DocumentInfo();
     76     }
     77 
     78     @Override
     79     public void setSelected(boolean selected, boolean animate) {
     80         // We always want to make sure our check box disappears if we're not selected,
     81         // even if the item is disabled. But it should be an error (see assert below)
     82         // to be set to selected && be disabled.
     83         float checkAlpha = selected ? 1f : 0f;
     84         if (animate) {
     85             fade(mIconCheck, checkAlpha).start();
     86         } else {
     87             mIconCheck.setAlpha(checkAlpha);
     88         }
     89 
     90         if (!itemView.isEnabled()) {
     91             assert(!selected);
     92             return;
     93         }
     94 
     95         super.setSelected(selected, animate);
     96 
     97         if (animate) {
     98             fade(mIconMime, 1f - checkAlpha).start();
     99             fade(mIconThumb, 1f - checkAlpha).start();
    100         } else {
    101             mIconMime.setAlpha(1f - checkAlpha);
    102             mIconThumb.setAlpha(1f - checkAlpha);
    103         }
    104     }
    105 
    106     @Override
    107     public void setEnabled(boolean enabled) {
    108         super.setEnabled(enabled);
    109 
    110         // Text colors enabled/disabled is handle via a color set.
    111         final float imgAlpha = enabled ? 1f : DISABLED_ALPHA;
    112         mIconMime.setAlpha(imgAlpha);
    113         mIconThumb.setAlpha(imgAlpha);
    114     }
    115 
    116     @Override
    117     public boolean inDragRegion(MotionEvent event) {
    118         // If itemView is activated = selected, then whole region is interactive
    119         if (itemView.isActivated()) {
    120             return true;
    121         }
    122 
    123         // Do everything in global coordinates - it makes things simpler.
    124         int[] coords = new int[2];
    125         mIconLayout.getLocationOnScreen(coords);
    126 
    127         Rect textBounds = new Rect();
    128         mTitle.getPaint().getTextBounds(
    129                 mTitle.getText().toString(), 0, mTitle.getText().length(), textBounds);
    130 
    131         Rect rect = new Rect(
    132                 coords[0],
    133                 coords[1],
    134                 coords[0] + mIconLayout.getWidth() + textBounds.width(),
    135                 coords[1] + Math.max(mIconLayout.getHeight(), textBounds.height()));
    136 
    137         // If the tap occurred inside icon or the text, these are interactive spots.
    138         return rect.contains((int) event.getRawX(), (int) event.getRawY());
    139     }
    140 
    141     @Override
    142     public boolean inSelectRegion(MotionEvent event) {
    143         Rect iconRect = new Rect();
    144         mIconLayout.getGlobalVisibleRect(iconRect);
    145 
    146         return iconRect.contains((int) event.getRawX(), (int) event.getRawY());
    147     }
    148 
    149     /**
    150      * Bind this view to the given document for display.
    151      * @param cursor Pointing to the item to be bound.
    152      * @param modelId The model ID of the item.
    153      */
    154     @Override
    155     public void bind(Cursor cursor, String modelId) {
    156         assert(cursor != null);
    157 
    158         mModelId = modelId;
    159 
    160         mDoc.updateFromCursor(cursor, getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY));
    161 
    162         mIconHelper.stopLoading(mIconThumb);
    163 
    164         mIconMime.animate().cancel();
    165         mIconMime.setAlpha(1f);
    166         mIconThumb.animate().cancel();
    167         mIconThumb.setAlpha(0f);
    168 
    169         mIconHelper.load(mDoc, mIconThumb, mIconMime, null);
    170 
    171         mTitle.setText(mDoc.displayName, TextView.BufferType.SPANNABLE);
    172         mTitle.setVisibility(View.VISIBLE);
    173 
    174 
    175         boolean hasDetails = false;
    176         if (mDoc.isDirectory()) {
    177             // Note, we don't show any details for any directory...ever.
    178             hasDetails = false;
    179         } else {
    180             // Show summary if the file is partial. Otherwise, there tends
    181             // to be a bunch of confusing junk in the summary field
    182             // as populated by Downlaods (and others). So to make things
    183             // simpler and clearer for the user in list view, we only
    184             // show the summary if the file is partial >
    185             // which we believe to mean actively downloading.
    186             if (mDoc.isPartial() && mDoc.summary != null) {
    187                 hasDetails = true;
    188                 mSummary.setText(mDoc.summary);
    189                 mSummary.setVisibility(View.VISIBLE);
    190             } else {
    191                 mSummary.setVisibility(View.INVISIBLE);
    192             }
    193 
    194             if (mDoc.lastModified > 0) {
    195                 hasDetails = true;
    196                 mDate.setText(Shared.formatTime(mContext, mDoc.lastModified));
    197             } else {
    198                 mDate.setText(null);
    199             }
    200 
    201             if (mDoc.size > -1) {
    202                 hasDetails = true;
    203                 mSize.setVisibility(View.VISIBLE);
    204                 mSize.setText(Formatter.formatFileSize(mContext, mDoc.size));
    205             } else {
    206                 mSize.setVisibility(View.INVISIBLE);
    207             }
    208 
    209             mType.setText(mFileTypeLookup.lookup(mDoc.mimeType));
    210         }
    211 
    212         // mDetails view doesn't exists in layout-sw720dp-land layout
    213         if (mDetails != null) {
    214             mDetails.setVisibility(hasDetails ? View.VISIBLE : View.GONE);
    215         }
    216 
    217         // TODO: Add document debug info
    218         // Call includeDebugInfo
    219     }
    220 }
    221