Home | History | Annotate | Download | only in launcher3
      1 /*
      2  * Copyright (C) 2014 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;
     18 
     19 import android.content.Context;
     20 import android.graphics.Bitmap;
     21 import android.graphics.Canvas;
     22 import android.graphics.Color;
     23 import android.graphics.Paint;
     24 import android.graphics.Rect;
     25 import android.view.View;
     26 import android.view.ViewDebug;
     27 import android.view.ViewGroup;
     28 
     29 public class ClickShadowView extends View {
     30 
     31     private static final int SHADOW_SIZE_FACTOR = 3;
     32     private static final int SHADOW_LOW_ALPHA = 30;
     33     private static final int SHADOW_HIGH_ALPHA = 60;
     34 
     35     private final Paint mPaint;
     36 
     37     @ViewDebug.ExportedProperty(category = "launcher")
     38     private final float mShadowOffset;
     39     @ViewDebug.ExportedProperty(category = "launcher")
     40     private final float mShadowPadding;
     41 
     42     private Bitmap mBitmap;
     43 
     44     public ClickShadowView(Context context) {
     45         super(context);
     46         mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
     47         mPaint.setColor(Color.BLACK);
     48 
     49         mShadowPadding = getResources().getDimension(R.dimen.blur_size_click_shadow);
     50         mShadowOffset = getResources().getDimension(R.dimen.click_shadow_high_shift);
     51     }
     52 
     53     /**
     54      * @return extra space required by the view to show the shadow.
     55      */
     56     public int getExtraSize() {
     57         return (int) (SHADOW_SIZE_FACTOR * mShadowPadding);
     58     }
     59 
     60     /**
     61      * Applies the new bitmap.
     62      * @return true if the view was invalidated.
     63      */
     64     public boolean setBitmap(Bitmap b) {
     65         if (b != mBitmap){
     66             mBitmap = b;
     67             invalidate();
     68             return true;
     69         }
     70         return false;
     71     }
     72 
     73     @Override
     74     protected void onDraw(Canvas canvas) {
     75         if (mBitmap != null) {
     76             mPaint.setAlpha(SHADOW_LOW_ALPHA);
     77             canvas.drawBitmap(mBitmap, 0, 0, mPaint);
     78             mPaint.setAlpha(SHADOW_HIGH_ALPHA);
     79             canvas.drawBitmap(mBitmap, 0, mShadowOffset, mPaint);
     80         }
     81     }
     82 
     83     public void animateShadow() {
     84         setAlpha(0);
     85         animate().alpha(1)
     86             .setDuration(FastBitmapDrawable.CLICK_FEEDBACK_DURATION)
     87             .setInterpolator(FastBitmapDrawable.CLICK_FEEDBACK_INTERPOLATOR)
     88             .start();
     89     }
     90 
     91     /**
     92      * Aligns the shadow with {@param view}
     93      * @param viewParent immediate parent of {@param view}. It must be a sibling of this view.
     94      */
     95     public void alignWithIconView(BubbleTextView view, ViewGroup viewParent, View clipAgainstView) {
     96         float leftShift = view.getLeft() + viewParent.getLeft() - getLeft();
     97         float topShift = view.getTop() + viewParent.getTop() - getTop();
     98         int iconWidth = view.getRight() - view.getLeft();
     99         int iconHeight = view.getBottom() - view.getTop();
    100         int iconHSpace = iconWidth - view.getCompoundPaddingRight() - view.getCompoundPaddingLeft();
    101         float drawableWidth = view.getIcon().getBounds().width();
    102 
    103         if (clipAgainstView != null) {
    104             // Set the bounds to clip against
    105             int[] coords = new int[] {0, 0};
    106             Utilities.getDescendantCoordRelativeToAncestor(clipAgainstView, (View) getParent(),
    107                     coords, false);
    108             int clipLeft = (int) Math.max(0, coords[0] - leftShift - mShadowPadding);
    109             int clipTop = (int) Math.max(0, coords[1] - topShift - mShadowPadding) ;
    110             setClipBounds(new Rect(clipLeft, clipTop, clipLeft + iconWidth, clipTop + iconHeight));
    111         } else {
    112             // Reset the clip bounds
    113             setClipBounds(null);
    114         }
    115 
    116         setTranslationX(leftShift
    117                 + viewParent.getTranslationX()
    118                 + view.getCompoundPaddingLeft() * view.getScaleX()
    119                 + (iconHSpace - drawableWidth) * view.getScaleX() / 2  /* drawable gap */
    120                 + iconWidth * (1 - view.getScaleX()) / 2  /* gap due to scale */
    121                 - mShadowPadding  /* extra shadow size */
    122                 );
    123         setTranslationY(topShift
    124                 + viewParent.getTranslationY()
    125                 + view.getPaddingTop() * view.getScaleY()  /* drawable gap */
    126                 + view.getHeight() * (1 - view.getScaleY()) / 2  /* gap due to scale */
    127                 - mShadowPadding  /* extra shadow size */
    128                 );
    129     }
    130 }
    131