• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.launcher3.widget;
18 
19 import android.content.Context;
20 import android.content.res.Resources;
21 import android.graphics.Bitmap;
22 import android.util.AttributeSet;
23 import android.util.Log;
24 import android.view.MotionEvent;
25 import android.view.View;
26 import android.view.View.OnLayoutChangeListener;
27 import android.view.ViewPropertyAnimator;
28 import android.widget.LinearLayout;
29 import android.widget.TextView;
30 
31 import com.android.launcher3.DeviceProfile;
32 import com.android.launcher3.ItemInfo;
33 import com.android.launcher3.Launcher;
34 import com.android.launcher3.LauncherAppState;
35 import com.android.launcher3.SimpleOnStylusPressListener;
36 import com.android.launcher3.R;
37 import com.android.launcher3.StylusEventHelper;
38 import com.android.launcher3.WidgetPreviewLoader;
39 import com.android.launcher3.WidgetPreviewLoader.PreviewLoadRequest;
40 import com.android.launcher3.model.WidgetItem;
41 
42 /**
43  * Represents the individual cell of the widget inside the widget tray. The preview is drawn
44  * horizontally centered, and scaled down if needed.
45  *
46  * This view does not support padding. Since the image is scaled down to fit the view, padding will
47  * further decrease the scaling factor. Drag-n-drop uses the view bounds for showing a smooth
48  * transition from the view to drag view, so when adding padding support, DnD would need to
49  * consider the appropriate scaling factor.
50  */
51 public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
52 
53     private static final String TAG = "WidgetCell";
54     private static final boolean DEBUG = false;
55 
56     private static final int FADE_IN_DURATION_MS = 90;
57 
58     /** Widget cell width is calculated by multiplying this factor to grid cell width. */
59     private static final float WIDTH_SCALE = 2.6f;
60 
61     /** Widget preview width is calculated by multiplying this factor to the widget cell width. */
62     private static final float PREVIEW_SCALE = 0.8f;
63 
64     private int mPresetPreviewSize;
65     int cellSize;
66 
67     private WidgetImageView mWidgetImage;
68     private TextView mWidgetName;
69     private TextView mWidgetDims;
70 
71     private WidgetItem mItem;
72 
73     private WidgetPreviewLoader mWidgetPreviewLoader;
74     private PreviewLoadRequest mActiveRequest;
75     private StylusEventHelper mStylusEventHelper;
76 
77     private final Launcher mLauncher;
78 
WidgetCell(Context context)79     public WidgetCell(Context context) {
80         this(context, null);
81     }
82 
WidgetCell(Context context, AttributeSet attrs)83     public WidgetCell(Context context, AttributeSet attrs) {
84         this(context, attrs, 0);
85     }
86 
WidgetCell(Context context, AttributeSet attrs, int defStyle)87     public WidgetCell(Context context, AttributeSet attrs, int defStyle) {
88         super(context, attrs, defStyle);
89 
90         final Resources r = context.getResources();
91         mLauncher = Launcher.getLauncher(context);
92         mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
93 
94         setContainerWidth();
95         setWillNotDraw(false);
96         setClipToPadding(false);
97         setAccessibilityDelegate(mLauncher.getAccessibilityDelegate());
98     }
99 
setContainerWidth()100     private void setContainerWidth() {
101         DeviceProfile profile = mLauncher.getDeviceProfile();
102         cellSize = (int) (profile.cellWidthPx * WIDTH_SCALE);
103         mPresetPreviewSize = (int) (cellSize * PREVIEW_SCALE);
104     }
105 
106     @Override
onFinishInflate()107     protected void onFinishInflate() {
108         super.onFinishInflate();
109 
110         mWidgetImage = (WidgetImageView) findViewById(R.id.widget_preview);
111         mWidgetName = ((TextView) findViewById(R.id.widget_name));
112         mWidgetDims = ((TextView) findViewById(R.id.widget_dims));
113     }
114 
115     /**
116      * Called to clear the view and free attached resources. (e.g., {@link Bitmap}
117      */
clear()118     public void clear() {
119         if (DEBUG) {
120             Log.d(TAG, "reset called on:" + mWidgetName.getText());
121         }
122         mWidgetImage.animate().cancel();
123         mWidgetImage.setBitmap(null);
124         mWidgetName.setText(null);
125         mWidgetDims.setText(null);
126 
127         if (mActiveRequest != null) {
128             mActiveRequest.cleanup();
129             mActiveRequest = null;
130         }
131     }
132 
applyFromCellItem(WidgetItem item, WidgetPreviewLoader loader)133     public void applyFromCellItem(WidgetItem item, WidgetPreviewLoader loader) {
134         mItem = item;
135         mWidgetName.setText(mItem.label);
136         mWidgetDims.setText(getContext().getString(R.string.widget_dims_format,
137                 mItem.spanX, mItem.spanY));
138         mWidgetDims.setContentDescription(getContext().getString(
139                 R.string.widget_accessible_dims_format, mItem.spanX, mItem.spanY));
140         mWidgetPreviewLoader = loader;
141 
142         if (item.activityInfo != null) {
143             setTag(new PendingAddShortcutInfo(item.activityInfo));
144         } else {
145             setTag(new PendingAddWidgetInfo(mLauncher, item.widgetInfo));
146         }
147     }
148 
getPreviewSize()149     public int[] getPreviewSize() {
150         int[] maxSize = new int[2];
151 
152         maxSize[0] = mPresetPreviewSize;
153         maxSize[1] = mPresetPreviewSize;
154         return maxSize;
155     }
156 
applyPreview(Bitmap bitmap)157     public void applyPreview(Bitmap bitmap) {
158         if (bitmap != null) {
159             mWidgetImage.setBitmap(bitmap);
160             mWidgetImage.setAlpha(0f);
161             ViewPropertyAnimator anim = mWidgetImage.animate();
162             anim.alpha(1.0f).setDuration(FADE_IN_DURATION_MS);
163         }
164     }
165 
ensurePreview()166     public void ensurePreview() {
167         if (mActiveRequest != null) {
168             return;
169         }
170         int[] size = getPreviewSize();
171         if (DEBUG) {
172             Log.d(TAG, String.format("[tag=%s] ensurePreview (%d, %d):",
173                     getTagToString(), size[0], size[1]));
174         }
175         mActiveRequest = mWidgetPreviewLoader.getPreview(mItem, size[0], size[1], this);
176     }
177 
178     @Override
onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom)179     public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
180             int oldTop, int oldRight, int oldBottom) {
181         removeOnLayoutChangeListener(this);
182         ensurePreview();
183     }
184 
getActualItemWidth()185     public int getActualItemWidth() {
186         ItemInfo info = (ItemInfo) getTag();
187         int[] size = getPreviewSize();
188         int cellWidth = mLauncher.getDeviceProfile().cellWidthPx;
189 
190         return Math.min(size[0], info.spanX * cellWidth);
191     }
192 
193     @Override
onTouchEvent(MotionEvent ev)194     public boolean onTouchEvent(MotionEvent ev) {
195         boolean handled = super.onTouchEvent(ev);
196         if (mStylusEventHelper.onMotionEvent(ev)) {
197             return true;
198         }
199         return handled;
200     }
201 
202     /**
203      * Helper method to get the string info of the tag.
204      */
getTagToString()205     private String getTagToString() {
206         if (getTag() instanceof PendingAddWidgetInfo ||
207                 getTag() instanceof PendingAddShortcutInfo) {
208             return getTag().toString();
209         }
210         return "";
211     }
212 
213     @Override
getAccessibilityClassName()214     public CharSequence getAccessibilityClassName() {
215         return WidgetCell.class.getName();
216     }
217 }
218