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.View; 27 import android.view.ViewGroup; 28 import android.widget.ImageView; 29 import android.widget.LinearLayout; 30 import android.widget.TextView; 31 32 import com.android.documentsui.R; 33 import com.android.documentsui.base.DocumentInfo; 34 import com.android.documentsui.base.Events.InputEvent; 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 isInDragHotspot(InputEvent 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 isOverDocIcon(InputEvent 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 if (mDoc.summary != null) { 181 hasDetails = true; 182 mSummary.setText(mDoc.summary); 183 mSummary.setVisibility(View.VISIBLE); 184 } else { 185 mSummary.setVisibility(View.INVISIBLE); 186 } 187 188 if (mDoc.lastModified > 0) { 189 hasDetails = true; 190 mDate.setText(Shared.formatTime(mContext, mDoc.lastModified)); 191 } else { 192 mDate.setText(null); 193 } 194 195 if (mDoc.size > -1) { 196 hasDetails = true; 197 mSize.setVisibility(View.VISIBLE); 198 mSize.setText(Formatter.formatFileSize(mContext, mDoc.size)); 199 } else { 200 mSize.setVisibility(View.INVISIBLE); 201 } 202 203 mType.setText(mFileTypeLookup.lookup(mDoc.mimeType)); 204 } 205 206 // mDetails view doesn't exists in layout-sw720dp-land layout 207 if (mDetails != null) { 208 mDetails.setVisibility(hasDetails ? View.VISIBLE : View.GONE); 209 } 210 211 // TODO: Add document debug info 212 // Call includeDebugInfo 213 } 214 } 215