PagedViewIcon.java revision b3347bb9f4ccf41fb7043bca66c3a565bde1083b
1/* 2 * Copyright (C) 2010 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 17package com.android.launcher2; 18 19import android.content.Context; 20import android.content.res.Resources; 21import android.graphics.Bitmap; 22import android.graphics.BlurMaskFilter; 23import android.graphics.Canvas; 24import android.graphics.Color; 25import android.graphics.Matrix; 26import android.graphics.Paint; 27import android.graphics.PointF; 28import android.graphics.PorterDuff; 29import android.graphics.PorterDuffXfermode; 30import android.graphics.Rect; 31import android.graphics.Region.Op; 32import android.util.AttributeSet; 33import android.util.DisplayMetrics; 34import android.view.View; 35import android.widget.TextView; 36 37class HolographicOutlineHelper { 38 private final Paint mHolographicPaint = new Paint(); 39 private final Paint mBlurPaint = new Paint(); 40 private final Paint mErasePaint = new Paint(); 41 private static final Matrix mIdentity = new Matrix(); 42 private static final float STROKE_WIDTH = 6.0f; 43 private static final float BLUR_FACTOR = 3.5f; 44 45 HolographicOutlineHelper(float density) { 46 mHolographicPaint.setColor(0xFF6699ff); 47 mHolographicPaint.setFilterBitmap(true); 48 mHolographicPaint.setAntiAlias(true); 49 mBlurPaint.setMaskFilter(new BlurMaskFilter(BLUR_FACTOR * density, 50 BlurMaskFilter.Blur.OUTER)); 51 mBlurPaint.setFilterBitmap(true); 52 mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 53 mErasePaint.setFilterBitmap(true); 54 mErasePaint.setAntiAlias(true); 55 } 56 57 private float cubic(float r) { 58 return (float) (Math.pow(r-1, 3) + 1); 59 } 60 61 /** 62 * Returns the interpolated holographic highlight alpha for the effect we want when scrolling 63 * pages. 64 */ 65 public float highlightAlphaInterpolator(float r) { 66 final float pivot = 0.3f; 67 if (r < pivot) { 68 return Math.max(0.5f, 0.65f*cubic(r/pivot)); 69 } else { 70 return Math.min(1.0f, 0.65f*cubic(1 - (r-pivot)/(1-pivot))); 71 } 72 } 73 74 /** 75 * Returns the interpolated view alpha for the effect we want when scrolling pages. 76 */ 77 public float viewAlphaInterpolator(float r) { 78 final float pivot = 0.6f; 79 if (r < pivot) { 80 return r/pivot; 81 } else { 82 return 1.0f; 83 } 84 } 85 86 /** 87 * Applies an outline to whatever is currently drawn in the specified bitmap. 88 */ 89 void applyOutline(Bitmap srcDst, Canvas srcDstCanvas, PointF offset) { 90 Bitmap mask = srcDst.extractAlpha(); 91 Matrix m = new Matrix(); 92 final int width = srcDst.getWidth(); 93 final int height = srcDst.getHeight(); 94 float xScale = STROKE_WIDTH*2.0f/width; 95 float yScale = STROKE_WIDTH*2.0f/height; 96 m.preScale(1+xScale, 1+yScale, (width / 2.0f) + offset.x, 97 (height / 2.0f) + offset.y); 98 99 srcDstCanvas.drawColor(0, PorterDuff.Mode.CLEAR); 100 srcDstCanvas.drawBitmap(mask, m, mHolographicPaint); 101 srcDstCanvas.drawBitmap(mask, mIdentity, mErasePaint); 102 mask.recycle(); 103 } 104 105 /** 106 * Applies an blur to whatever is currently drawn in the specified bitmap. 107 */ 108 void applyBlur(Bitmap srcDst, Canvas srcDstCanvas) { 109 int[] xy = new int[2]; 110 Bitmap mask = srcDst.extractAlpha(mBlurPaint, xy); 111 srcDstCanvas.drawBitmap(mask, xy[0], xy[1], mHolographicPaint); 112 mask.recycle(); 113 } 114} 115 116/** 117 * An icon on a PagedView, specifically for items in the launcher's paged view (with compound 118 * drawables on the top). 119 */ 120public class PagedViewIcon extends TextView { 121 private static final String TAG = "PagedViewIcon"; 122 123 // holographic outline 124 private final Paint mPaint = new Paint(); 125 private static HolographicOutlineHelper sHolographicOutlineHelper; 126 private Bitmap mHolographicOutline; 127 private Canvas mHolographicOutlineCanvas; 128 private boolean mIsHolographicUpdatePass; 129 private Rect mDrawableClipRect; 130 131 private int mAlpha; 132 private int mHolographicAlpha; 133 134 public PagedViewIcon(Context context) { 135 this(context, null); 136 } 137 138 public PagedViewIcon(Context context, AttributeSet attrs) { 139 this(context, attrs, 0); 140 } 141 142 public PagedViewIcon(Context context, AttributeSet attrs, int defStyle) { 143 super(context, attrs, defStyle); 144 145 if (sHolographicOutlineHelper == null) { 146 final Resources resources = context.getResources(); 147 final DisplayMetrics metrics = resources.getDisplayMetrics(); 148 final float density = metrics.density; 149 sHolographicOutlineHelper = new HolographicOutlineHelper(density); 150 } 151 mDrawableClipRect = new Rect(); 152 153 setFocusable(true); 154 setBackgroundDrawable(null); 155 } 156 157 @Override 158 public void setAlpha(float alpha) { 159 final float viewAlpha = sHolographicOutlineHelper.viewAlphaInterpolator(alpha); 160 mAlpha = (int) (viewAlpha * 255); 161 final float holographicAlpha = sHolographicOutlineHelper.highlightAlphaInterpolator(alpha); 162 mHolographicAlpha = (int) (holographicAlpha * 255); 163 164 // WORKAROUND: until TextView handles canvas shadow layer alpha itself 165 int sRed = Color.red(mShadowColor); 166 int sGreen = Color.green(mShadowColor); 167 int sBlue = Color.blue(mShadowColor); 168 super.setShadowLayer(mShadowRadius, mShadowDx, mShadowDy, Color.argb(mAlpha, sRed, sGreen, 169 sBlue)); 170 171 super.setAlpha(viewAlpha); 172 } 173 174 @Override 175 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 176 super.onLayout(changed, left, top, right, bottom); 177 178 if (mHolographicOutline == null) { 179 final PointF offset = new PointF(0, 180 -(getCompoundPaddingBottom() + getCompoundPaddingTop())/2.0f); 181 182 // update the clipping rect to be used in the holographic pass below 183 getDrawingRect(mDrawableClipRect); 184 mDrawableClipRect.bottom = getPaddingTop() + getCompoundPaddingTop(); 185 186 // set a flag to indicate that we are going to draw the view at full alpha with the text 187 // clipped for the generation of the holographic icon 188 mIsHolographicUpdatePass = true; 189 mHolographicOutline = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), 190 Bitmap.Config.ARGB_8888); 191 mHolographicOutlineCanvas = new Canvas(mHolographicOutline); 192 mHolographicOutlineCanvas.concat(getMatrix()); 193 draw(mHolographicOutlineCanvas); 194 sHolographicOutlineHelper.applyOutline(mHolographicOutline, mHolographicOutlineCanvas, 195 offset); 196 sHolographicOutlineHelper.applyBlur(mHolographicOutline, mHolographicOutlineCanvas); 197 mIsHolographicUpdatePass = false; 198 } 199 } 200 201 // WORKAROUND: until TextView handles canvas shadow layer alpha itself 202 float mShadowRadius, mShadowDx, mShadowDy; 203 int mShadowColor; 204 @Override 205 public void setShadowLayer(float radius, float dx, float dy, int color) { 206 mShadowRadius = radius; 207 mShadowDx = dx; 208 mShadowDy = dy; 209 mShadowColor = color; 210 super.setShadowLayer(radius, dx, dy, color); 211 } 212 213 @Override 214 protected void onDraw(Canvas canvas) { 215 if (mIsHolographicUpdatePass) { 216 // only clip to the text view (restore its alpha so that we get a proper outline) 217 canvas.save(); 218 canvas.clipRect(mDrawableClipRect, Op.REPLACE); 219 super.onSetAlpha(255); 220 super.onDraw(canvas); 221 super.onSetAlpha(mAlpha); 222 canvas.restore(); 223 } else { 224 if (mAlpha > 0) { 225 super.onDraw(canvas); 226 } 227 } 228 229 if (!mIsHolographicUpdatePass && mHolographicOutline != null && mHolographicAlpha > 0) { 230 mPaint.setAlpha(mHolographicAlpha); 231 canvas.drawBitmap(mHolographicOutline, 0, 0, mPaint); 232 } 233 } 234} 235