• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.DevicePolicyResources.Drawables.Style.SOLID_NOT_COLORED;
20 import static com.android.documentsui.DevicePolicyResources.Drawables.WORK_PROFILE_ICON;
21 import static com.android.documentsui.base.DocumentInfo.getCursorInt;
22 import static com.android.documentsui.base.DocumentInfo.getCursorLong;
23 import static com.android.documentsui.base.DocumentInfo.getCursorString;
24 
25 import android.app.admin.DevicePolicyManager;
26 import android.content.Context;
27 import android.database.Cursor;
28 import android.graphics.drawable.Drawable;
29 import android.os.Build;
30 import android.provider.DocumentsContract.Document;
31 import android.text.format.Formatter;
32 import android.view.MotionEvent;
33 import android.view.View;
34 import android.view.ViewGroup;
35 import android.widget.ImageView;
36 
37 import androidx.annotation.RequiresApi;
38 
39 import com.android.documentsui.R;
40 import com.android.documentsui.base.DocumentInfo;
41 import com.android.documentsui.base.Shared;
42 import com.android.documentsui.base.UserId;
43 import com.android.documentsui.roots.RootCursorWrapper;
44 import com.android.documentsui.ui.Views;
45 import com.android.modules.utils.build.SdkLevel;
46 
47 import java.util.function.Function;
48 
49 final class GridPhotoHolder extends DocumentHolder {
50 
51     private final ImageView mIconMimeLg;
52     private final ImageView mIconThumb;
53     private final ImageView mIconCheck;
54     private final IconHelper mIconHelper;
55     private final View mPreviewIcon;
56     private final View mIconBriefcase;
57 
58     // This is used in as a convenience in our bind method.
59     private final DocumentInfo mDoc = new DocumentInfo();
60 
GridPhotoHolder(Context context, ViewGroup parent, IconHelper iconHelper)61     public GridPhotoHolder(Context context, ViewGroup parent, IconHelper iconHelper) {
62         super(context, parent, R.layout.item_photo_grid);
63 
64         mIconMimeLg = (ImageView) itemView.findViewById(R.id.icon_mime_lg);
65         mIconThumb = (ImageView) itemView.findViewById(R.id.icon_thumb);
66         mIconCheck = (ImageView) itemView.findViewById(R.id.icon_check);
67         mIconBriefcase = itemView.findViewById(R.id.icon_briefcase);
68         mPreviewIcon = itemView.findViewById(R.id.preview_icon);
69 
70         mIconHelper = iconHelper;
71 
72         if (SdkLevel.isAtLeastT()) {
73             setUpdatableWorkProfileIcon(context);
74         }
75     }
76 
77     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
setUpdatableWorkProfileIcon(Context context)78     private void setUpdatableWorkProfileIcon(Context context) {
79         DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
80         Drawable drawable = dpm.getResources().getDrawable(
81                 WORK_PROFILE_ICON, SOLID_NOT_COLORED, () ->
82                         context.getDrawable(R.drawable.ic_briefcase));
83         ImageView icon = (ImageView) mIconBriefcase.findViewById(R.id.icon_id);
84 
85         icon.setImageDrawable(drawable);
86     }
87 
88     @Override
setSelected(boolean selected, boolean animate)89     public void setSelected(boolean selected, boolean animate) {
90         // We always want to make sure our check box disappears if we're not selected,
91         // even if the item is disabled. This is because this object can be reused
92         // and this method will be called to setup initial state.
93         float checkAlpha = selected ? 1f : 0f;
94         if (animate) {
95             fade(mIconCheck, checkAlpha).start();
96         } else {
97             mIconCheck.setAlpha(checkAlpha);
98         }
99 
100         // But it should be an error to be set to selected && be disabled.
101         if (!itemView.isEnabled()) {
102             assert (!selected);
103             return;
104         }
105 
106         super.setSelected(selected, animate);
107     }
108 
109     @Override
setEnabled(boolean enabled)110     public void setEnabled(boolean enabled) {
111         super.setEnabled(enabled);
112 
113         float imgAlpha = enabled ? 1f : DISABLED_ALPHA;
114 
115         mIconMimeLg.setAlpha(imgAlpha);
116         mIconThumb.setAlpha(imgAlpha);
117     }
118 
119     @Override
bindPreviewIcon(boolean show, Function<View, Boolean> clickCallback)120     public void bindPreviewIcon(boolean show, Function<View, Boolean> clickCallback) {
121         mPreviewIcon.setVisibility(show ? View.VISIBLE : View.GONE);
122         if (show) {
123             mPreviewIcon.setContentDescription(
124                     getPreviewIconContentDescription(
125                             mIconHelper.shouldShowBadge(mDoc.userId.getIdentifier()),
126                             mDoc.displayName));
127             mPreviewIcon.setAccessibilityDelegate(new PreviewAccessibilityDelegate(clickCallback));
128         }
129     }
130 
131     @Override
bindBriefcaseIcon(boolean show)132     public void bindBriefcaseIcon(boolean show) {
133         mIconBriefcase.setVisibility(show ? View.VISIBLE : View.GONE);
134     }
135 
136     @Override
inDragRegion(MotionEvent event)137     public boolean inDragRegion(MotionEvent event) {
138         // Entire grid box should be draggable
139         return true;
140     }
141 
142     @Override
inSelectRegion(MotionEvent event)143     public boolean inSelectRegion(MotionEvent event) {
144         // Photo gird should not have any select region.
145         return false;
146     }
147 
148     @Override
inPreviewIconRegion(MotionEvent event)149     public boolean inPreviewIconRegion(MotionEvent event) {
150         return Views.isEventOver(event, itemView.getParent(), mPreviewIcon);
151     }
152 
153     /**
154      * Bind this view to the given document for display.
155      * @param cursor Pointing to the item to be bound.
156      * @param modelId The model ID of the item.
157      */
158     @Override
bind(Cursor cursor, String modelId)159     public void bind(Cursor cursor, String modelId) {
160         assert (cursor != null);
161 
162         mModelId = modelId;
163 
164         mDoc.updateFromCursor(cursor,
165                 UserId.of(getCursorInt(cursor, RootCursorWrapper.COLUMN_USER_ID)),
166                 getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY));
167 
168         mIconHelper.stopLoading(mIconThumb);
169 
170         mIconMimeLg.animate().cancel();
171         mIconMimeLg.setAlpha(1f);
172         mIconThumb.animate().cancel();
173         mIconThumb.setAlpha(0f);
174 
175         mIconHelper.load(mDoc, mIconThumb, mIconMimeLg, null);
176 
177         final String docSize =
178                 Formatter.formatFileSize(mContext, getCursorLong(cursor, Document.COLUMN_SIZE));
179         final String docDate = Shared.formatTime(mContext, mDoc.lastModified);
180         if (mIconHelper.shouldShowBadge(mDoc.userId.getIdentifier())) {
181             itemView.setContentDescription((mContext.getText(R.string.a11y_work) + ", ")
182                     + mDoc.displayName + ", " + docSize + ", " + docDate);
183         } else {
184             itemView.setContentDescription(mDoc.displayName + ", " + docSize + ", " + docDate);
185         }
186     }
187 }
188