Home | History | Annotate | Download | only in widget
      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.graphics.Bitmap;
     21 import android.os.CancellationSignal;
     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.ViewGroup;
     28 import android.view.ViewPropertyAnimator;
     29 import android.widget.LinearLayout;
     30 import android.widget.TextView;
     31 
     32 import com.android.launcher3.BaseActivity;
     33 import com.android.launcher3.DeviceProfile;
     34 import com.android.launcher3.R;
     35 import com.android.launcher3.SimpleOnStylusPressListener;
     36 import com.android.launcher3.StylusEventHelper;
     37 import com.android.launcher3.WidgetPreviewLoader;
     38 import com.android.launcher3.graphics.DrawableFactory;
     39 import com.android.launcher3.model.WidgetItem;
     40 
     41 /**
     42  * Represents the individual cell of the widget inside the widget tray. The preview is drawn
     43  * horizontally centered, and scaled down if needed.
     44  *
     45  * This view does not support padding. Since the image is scaled down to fit the view, padding will
     46  * further decrease the scaling factor. Drag-n-drop uses the view bounds for showing a smooth
     47  * transition from the view to drag view, so when adding padding support, DnD would need to
     48  * consider the appropriate scaling factor.
     49  */
     50 public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
     51 
     52     private static final String TAG = "WidgetCell";
     53     private static final boolean DEBUG = false;
     54 
     55     private static final int FADE_IN_DURATION_MS = 90;
     56 
     57     /** Widget cell width is calculated by multiplying this factor to grid cell width. */
     58     private static final float WIDTH_SCALE = 2.6f;
     59 
     60     /** Widget preview width is calculated by multiplying this factor to the widget cell width. */
     61     private static final float PREVIEW_SCALE = 0.8f;
     62 
     63     protected int mPresetPreviewSize;
     64     private int mCellSize;
     65 
     66     private WidgetImageView mWidgetImage;
     67     private TextView mWidgetName;
     68     private TextView mWidgetDims;
     69 
     70     protected WidgetItem mItem;
     71 
     72     private WidgetPreviewLoader mWidgetPreviewLoader;
     73     private StylusEventHelper mStylusEventHelper;
     74 
     75     protected CancellationSignal mActiveRequest;
     76     private boolean mAnimatePreview = true;
     77 
     78     protected final BaseActivity mActivity;
     79 
     80     public WidgetCell(Context context) {
     81         this(context, null);
     82     }
     83 
     84     public WidgetCell(Context context, AttributeSet attrs) {
     85         this(context, attrs, 0);
     86     }
     87 
     88     public WidgetCell(Context context, AttributeSet attrs, int defStyle) {
     89         super(context, attrs, defStyle);
     90 
     91         mActivity = BaseActivity.fromContext(context);
     92         mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
     93 
     94         setContainerWidth();
     95         setWillNotDraw(false);
     96         setClipToPadding(false);
     97         setAccessibilityDelegate(mActivity.getAccessibilityDelegate());
     98     }
     99 
    100     private void setContainerWidth() {
    101         DeviceProfile profile = mActivity.getDeviceProfile();
    102         mCellSize = (int) (profile.cellWidthPx * WIDTH_SCALE);
    103         mPresetPreviewSize = (int) (mCellSize * PREVIEW_SCALE);
    104     }
    105 
    106     @Override
    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      */
    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, null);
    124         mWidgetName.setText(null);
    125         mWidgetDims.setText(null);
    126 
    127         if (mActiveRequest != null) {
    128             mActiveRequest.cancel();
    129             mActiveRequest = null;
    130         }
    131     }
    132 
    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(item.widgetInfo));
    146         }
    147     }
    148 
    149     public WidgetImageView getWidgetView() {
    150         return mWidgetImage;
    151     }
    152 
    153     public void setAnimatePreview(boolean shouldAnimate) {
    154         mAnimatePreview = shouldAnimate;
    155     }
    156 
    157     public void applyPreview(Bitmap bitmap) {
    158         applyPreview(bitmap, true);
    159     }
    160 
    161     public void applyPreview(Bitmap bitmap, boolean animate) {
    162         if (bitmap != null) {
    163             mWidgetImage.setBitmap(bitmap,
    164                     DrawableFactory.get(getContext()).getBadgeForUser(mItem.user, getContext()));
    165             if (mAnimatePreview) {
    166                 mWidgetImage.setAlpha(0f);
    167                 ViewPropertyAnimator anim = mWidgetImage.animate();
    168                 anim.alpha(1.0f).setDuration(FADE_IN_DURATION_MS);
    169             } else {
    170                 mWidgetImage.setAlpha(1f);
    171             }
    172         }
    173     }
    174 
    175     public void ensurePreview() {
    176         ensurePreview(true);
    177     }
    178 
    179     public void ensurePreview(boolean animate) {
    180         if (mActiveRequest != null) {
    181             return;
    182         }
    183         mActiveRequest = mWidgetPreviewLoader.getPreview(
    184                 mItem, mPresetPreviewSize, mPresetPreviewSize, this, animate);
    185     }
    186 
    187     @Override
    188     public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
    189             int oldTop, int oldRight, int oldBottom) {
    190         removeOnLayoutChangeListener(this);
    191         ensurePreview();
    192     }
    193 
    194     @Override
    195     public boolean onTouchEvent(MotionEvent ev) {
    196         boolean handled = super.onTouchEvent(ev);
    197         if (mStylusEventHelper.onMotionEvent(ev)) {
    198             return true;
    199         }
    200         return handled;
    201     }
    202 
    203     /**
    204      * Helper method to get the string info of the tag.
    205      */
    206     private String getTagToString() {
    207         if (getTag() instanceof PendingAddWidgetInfo ||
    208                 getTag() instanceof PendingAddShortcutInfo) {
    209             return getTag().toString();
    210         }
    211         return "";
    212     }
    213 
    214     @Override
    215     public void setLayoutParams(ViewGroup.LayoutParams params) {
    216         params.width = params.height = mCellSize;
    217         super.setLayoutParams(params);
    218     }
    219 
    220     @Override
    221     public CharSequence getAccessibilityClassName() {
    222         return WidgetCell.class.getName();
    223     }
    224 }
    225