131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/* 231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * you may not use this file except in compliance with the License. 631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * You may obtain a copy of the License at 731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 1031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 1131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 1231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * See the License for the specific language governing permissions and 1431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * limitations under the License. 1531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 1631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 17a5902524d4403885eb4c50360bf3465c6be796efJoe Onoratopackage com.android.launcher2; 1831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 1931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.Context; 20656d11c882296d732e6bdab30ec26f84b99eba19Winson Chungimport android.content.res.Resources; 2167b2f6cba5aa7b5d0fac5e66ba8f3d5f887baee6Michael Jurkaimport android.graphics.Bitmap; 2231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Canvas; 23656d11c882296d732e6bdab30ec26f84b99eba19Winson Chungimport android.graphics.Color; 2431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Paint; 2538b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurkaimport android.graphics.Rect; 26137142e39bd65429b0ad3e502aa9851ba81ca6ffMichael Jurkaimport android.graphics.Region; 2738b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurkaimport android.graphics.Region.Op; 2831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.drawable.Drawable; 29656d11c882296d732e6bdab30ec26f84b99eba19Winson Chungimport android.util.AttributeSet; 3038b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurkaimport android.view.MotionEvent; 31bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurkaimport android.widget.TextView; 32edcce099c98a6c40d10109ac092ab50f9d2668f3Romain Guy 3392f3d46cf35e78891f73226e81f8ca7e9a7f4d92Michael Jurkaimport com.android.launcher.R; 3492f3d46cf35e78891f73226e81f8ca7e9a7f4d92Michael Jurka 3531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/** 3631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * TextView that draws a bubble behind the text. We cannot use a LineBackgroundSpan 3731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * because we want to make the bubble taller than the text and TextView's clip is 3831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * too aggressive. 3931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 4008ee77090f1fef565142e9341914369b1aa342d1Michael Jurkapublic class BubbleTextView extends TextView { 41656d11c882296d732e6bdab30ec26f84b99eba19Winson Chung static final float CORNER_RADIUS = 4.0f; 4288127038178b3bbf0eb91103a31e682cc0615074Winson Chung static final float SHADOW_LARGE_RADIUS = 4.0f; 4388127038178b3bbf0eb91103a31e682cc0615074Winson Chung static final float SHADOW_SMALL_RADIUS = 1.75f; 4488127038178b3bbf0eb91103a31e682cc0615074Winson Chung static final float SHADOW_Y_OFFSET = 2.0f; 45c7aef8ca7593eaa37ac7dde514e139f113399ce7Winson Chung static final int SHADOW_LARGE_COLOUR = 0xDD000000; 46c7aef8ca7593eaa37ac7dde514e139f113399ce7Winson Chung static final int SHADOW_SMALL_COLOUR = 0xCC000000; 47656d11c882296d732e6bdab30ec26f84b99eba19Winson Chung static final float PADDING_H = 8.0f; 48656d11c882296d732e6bdab30ec26f84b99eba19Winson Chung static final float PADDING_V = 3.0f; 49656d11c882296d732e6bdab30ec26f84b99eba19Winson Chung 5031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private Paint mPaint; 51656d11c882296d732e6bdab30ec26f84b99eba19Winson Chung private float mBubbleColorAlpha; 52e22a8e9d3eafe569fe0f4d284c77af08c6e2fe28Winson Chung private int mPrevAlpha = -1; 5331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 5438b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka private final HolographicOutlineHelper mOutlineHelper = new HolographicOutlineHelper(); 5538b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka private final Canvas mTempCanvas = new Canvas(); 5638b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka private final Rect mTempRect = new Rect(); 5738b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka private boolean mDidInvalidateForPressedState; 5838b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka private Bitmap mPressedOrFocusedBackground; 5938b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka private int mFocusedOutlineColor; 6038b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka private int mFocusedGlowColor; 6138b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka private int mPressedOutlineColor; 6238b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka private int mPressedGlowColor; 6338b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka 6431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private boolean mBackgroundSizeChanged; 6531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private Drawable mBackground; 6631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 67ddd62e9f3dd21c52dffceef9b168629ebb7f4c03Michael Jurka private boolean mStayPressed; 68ddd62e9f3dd21c52dffceef9b168629ebb7f4c03Michael Jurka 6931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public BubbleTextView(Context context) { 7031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(context); 7131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project init(); 7231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 7331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 7431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public BubbleTextView(Context context, AttributeSet attrs) { 7531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(context, attrs); 7631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project init(); 7731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 7831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 7931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public BubbleTextView(Context context, AttributeSet attrs, int defStyle) { 8031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(context, attrs, defStyle); 8131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project init(); 8231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 8331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 8431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private void init() { 8531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mBackground = getBackground(); 8631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 87656d11c882296d732e6bdab30ec26f84b99eba19Winson Chung final Resources res = getContext().getResources(); 88656d11c882296d732e6bdab30ec26f84b99eba19Winson Chung int bubbleColor = res.getColor(R.color.bubble_dark_background); 8931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 90656d11c882296d732e6bdab30ec26f84b99eba19Winson Chung mPaint.setColor(bubbleColor); 91656d11c882296d732e6bdab30ec26f84b99eba19Winson Chung mBubbleColorAlpha = Color.alpha(bubbleColor) / 255.0f; 927d3810d8337e4f030796b566a2d562fcf79b0a22Winson Chung mFocusedOutlineColor = mFocusedGlowColor = mPressedOutlineColor = mPressedGlowColor = 937d3810d8337e4f030796b566a2d562fcf79b0a22Winson Chung res.getColor(android.R.color.holo_blue_light); 94e7e3f6c438a9de1d4a0557962f868d9a01f56286Michael Jurka 95e7e3f6c438a9de1d4a0557962f868d9a01f56286Michael Jurka setShadowLayer(SHADOW_LARGE_RADIUS, 0.0f, SHADOW_Y_OFFSET, SHADOW_LARGE_COLOUR); 9631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 9731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 9867b2f6cba5aa7b5d0fac5e66ba8f3d5f887baee6Michael Jurka public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache) { 9967b2f6cba5aa7b5d0fac5e66ba8f3d5f887baee6Michael Jurka Bitmap b = info.getIcon(iconCache); 10067b2f6cba5aa7b5d0fac5e66ba8f3d5f887baee6Michael Jurka 10167b2f6cba5aa7b5d0fac5e66ba8f3d5f887baee6Michael Jurka setCompoundDrawablesWithIntrinsicBounds(null, 10267b2f6cba5aa7b5d0fac5e66ba8f3d5f887baee6Michael Jurka new FastBitmapDrawable(b), 10367b2f6cba5aa7b5d0fac5e66ba8f3d5f887baee6Michael Jurka null, null); 10467b2f6cba5aa7b5d0fac5e66ba8f3d5f887baee6Michael Jurka setText(info.title); 10567b2f6cba5aa7b5d0fac5e66ba8f3d5f887baee6Michael Jurka setTag(info); 10667b2f6cba5aa7b5d0fac5e66ba8f3d5f887baee6Michael Jurka } 10767b2f6cba5aa7b5d0fac5e66ba8f3d5f887baee6Michael Jurka 10831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 10931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected boolean setFrame(int left, int top, int right, int bottom) { 11031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { 11131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mBackgroundSizeChanged = true; 11231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 11331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return super.setFrame(left, top, right, bottom); 11431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 11531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 11631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 11731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected boolean verifyDrawable(Drawable who) { 11831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return who == mBackground || super.verifyDrawable(who); 11931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 12031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 12131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 12231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void drawableStateChanged() { 12338b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka if (isPressed()) { 12438b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka // In this case, we have already created the pressed outline on ACTION_DOWN, 12538b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka // so we just need to do an invalidate to trigger draw 12638b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka if (!mDidInvalidateForPressedState) { 1273499d8c89d6b5989579880bf80df31df46483304Patrick Dubroy setCellLayoutPressedOrFocusedIcon(); 12838b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka } 12938b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka } else { 13038b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka // Otherwise, either clear the pressed/focused background, or create a background 13138b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka // for the focused state 13238b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka final boolean backgroundEmptyBefore = mPressedOrFocusedBackground == null; 133ddd62e9f3dd21c52dffceef9b168629ebb7f4c03Michael Jurka if (!mStayPressed) { 134ddd62e9f3dd21c52dffceef9b168629ebb7f4c03Michael Jurka mPressedOrFocusedBackground = null; 135ddd62e9f3dd21c52dffceef9b168629ebb7f4c03Michael Jurka } 13638b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka if (isFocused()) { 137a017c0379c30e0272a88a93d05b6a30e28955b88Patrick Dubroy if (mLayout == null) { 138a017c0379c30e0272a88a93d05b6a30e28955b88Patrick Dubroy // In some cases, we get focus before we have been layed out. Set the 139a017c0379c30e0272a88a93d05b6a30e28955b88Patrick Dubroy // background to null so that it will get created when the view is drawn. 140a017c0379c30e0272a88a93d05b6a30e28955b88Patrick Dubroy mPressedOrFocusedBackground = null; 141a017c0379c30e0272a88a93d05b6a30e28955b88Patrick Dubroy } else { 142a017c0379c30e0272a88a93d05b6a30e28955b88Patrick Dubroy mPressedOrFocusedBackground = createGlowingOutline( 143a017c0379c30e0272a88a93d05b6a30e28955b88Patrick Dubroy mTempCanvas, mFocusedGlowColor, mFocusedOutlineColor); 144a017c0379c30e0272a88a93d05b6a30e28955b88Patrick Dubroy } 145ddd62e9f3dd21c52dffceef9b168629ebb7f4c03Michael Jurka mStayPressed = false; 1463499d8c89d6b5989579880bf80df31df46483304Patrick Dubroy setCellLayoutPressedOrFocusedIcon(); 14738b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka } 14838b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka final boolean backgroundEmptyNow = mPressedOrFocusedBackground == null; 14938b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka if (!backgroundEmptyBefore && backgroundEmptyNow) { 1503499d8c89d6b5989579880bf80df31df46483304Patrick Dubroy setCellLayoutPressedOrFocusedIcon(); 15138b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka } 15238b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka } 15338b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka 15431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project Drawable d = mBackground; 15531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (d != null && d.isStateful()) { 15631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project d.setState(getDrawableState()); 15731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 15831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super.drawableStateChanged(); 15931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 16031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 16138b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka /** 162cd953711fcbb6c8c6579fb7127e3c86103c0d409Patrick Dubroy * Draw this BubbleTextView into the given Canvas. 16338b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka * 16438b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka * @param destCanvas the canvas to draw on 16538b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka * @param padding the horizontal and vertical padding to use when drawing 16638b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka */ 16738b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka private void drawWithPadding(Canvas destCanvas, int padding) { 16838b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka final Rect clipRect = mTempRect; 16938b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka getDrawingRect(clipRect); 17038b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka 17138b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka // adjust the clip rect so that we don't include the text label 17238b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka clipRect.bottom = 17338b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka getExtendedPaddingTop() - (int) BubbleTextView.PADDING_V + getLayout().getLineTop(0); 17438b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka 17538b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka // Draw the View into the bitmap. 17638b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka // The translate of scrollX and scrollY is necessary when drawing TextViews, because 17738b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka // they set scrollX and scrollY to large values to achieve centered text 17838b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka destCanvas.save(); 17938b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka destCanvas.translate(-getScrollX() + padding / 2, -getScrollY() + padding / 2); 18038b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka destCanvas.clipRect(clipRect, Op.REPLACE); 1813499d8c89d6b5989579880bf80df31df46483304Patrick Dubroy draw(destCanvas); 18238b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka destCanvas.restore(); 18338b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka } 18438b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka 18538b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka /** 18638b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location. 18738b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka * Responsibility for the bitmap is transferred to the caller. 18838b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka */ 18938b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka private Bitmap createGlowingOutline(Canvas canvas, int outlineColor, int glowColor) { 19038b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka final int padding = HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS; 19138b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka final Bitmap b = Bitmap.createBitmap( 19238b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka getWidth() + padding, getHeight() + padding, Bitmap.Config.ARGB_8888); 19338b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka 19438b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka canvas.setBitmap(b); 19538b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka drawWithPadding(canvas, padding); 19638b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka mOutlineHelper.applyExtraThickExpensiveOutlineWithBlur(b, canvas, glowColor, outlineColor); 197aaf473c2bb6329b3b09ed2e19de6aae26077050cAdam Cohen canvas.setBitmap(null); 19838b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka 19938b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka return b; 20038b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka } 20138b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka 20238b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka @Override 20338b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka public boolean onTouchEvent(MotionEvent event) { 20438b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka // Call the superclass onTouchEvent first, because sometimes it changes the state to 20538b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka // isPressed() on an ACTION_UP 20638b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka boolean result = super.onTouchEvent(event); 20738b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka 20838b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka switch (event.getAction()) { 20938b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka case MotionEvent.ACTION_DOWN: 21038b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka // So that the pressed outline is visible immediately when isPressed() is true, 21138b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka // we pre-create it on ACTION_DOWN (it takes a small but perceptible amount of time 21238b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka // to create it) 21338b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka if (mPressedOrFocusedBackground == null) { 21438b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka mPressedOrFocusedBackground = createGlowingOutline( 21538b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka mTempCanvas, mPressedGlowColor, mPressedOutlineColor); 21638b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka } 21738b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka // Invalidate so the pressed state is visible, or set a flag so we know that we 21838b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka // have to call invalidate as soon as the state is "pressed" 21938b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka if (isPressed()) { 22038b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka mDidInvalidateForPressedState = true; 221e6235dd225404239b55c459245543f3302326112Michael Jurka setCellLayoutPressedOrFocusedIcon(); 22238b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka } else { 22338b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka mDidInvalidateForPressedState = false; 22438b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka } 22538b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka break; 22638b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka case MotionEvent.ACTION_CANCEL: 22738b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka case MotionEvent.ACTION_UP: 22838b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka // If we've touched down and up on an item, and it's still not "pressed", then 22938b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka // destroy the pressed outline 23038b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka if (!isPressed()) { 23138b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka mPressedOrFocusedBackground = null; 23238b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka } 23338b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka break; 23438b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka } 23538b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka return result; 23638b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka } 23738b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka 238ddd62e9f3dd21c52dffceef9b168629ebb7f4c03Michael Jurka void setStayPressed(boolean stayPressed) { 239ddd62e9f3dd21c52dffceef9b168629ebb7f4c03Michael Jurka mStayPressed = stayPressed; 240ddd62e9f3dd21c52dffceef9b168629ebb7f4c03Michael Jurka if (!stayPressed) { 241ddd62e9f3dd21c52dffceef9b168629ebb7f4c03Michael Jurka mPressedOrFocusedBackground = null; 242ddd62e9f3dd21c52dffceef9b168629ebb7f4c03Michael Jurka } 2433499d8c89d6b5989579880bf80df31df46483304Patrick Dubroy setCellLayoutPressedOrFocusedIcon(); 244ddd62e9f3dd21c52dffceef9b168629ebb7f4c03Michael Jurka } 245a017c0379c30e0272a88a93d05b6a30e28955b88Patrick Dubroy 2463499d8c89d6b5989579880bf80df31df46483304Patrick Dubroy void setCellLayoutPressedOrFocusedIcon() { 24776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen if (getParent() instanceof CellLayoutChildren) { 24876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen CellLayoutChildren parent = (CellLayoutChildren) getParent(); 24976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen if (parent != null) { 25076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen CellLayout layout = (CellLayout) parent.getParent(); 25176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen layout.setPressedOrFocusedIcon((mPressedOrFocusedBackground != null) ? this : null); 25276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen } 253d69e11384c9eefe49039b198edcece5d59c8868fPatrick Dubroy } 254a017c0379c30e0272a88a93d05b6a30e28955b88Patrick Dubroy } 255a017c0379c30e0272a88a93d05b6a30e28955b88Patrick Dubroy 2561e9cbfef04366a206d59922c14fe4356b7cca426Winson Chung void clearPressedOrFocusedBackground() { 2571e9cbfef04366a206d59922c14fe4356b7cca426Winson Chung mPressedOrFocusedBackground = null; 2581e9cbfef04366a206d59922c14fe4356b7cca426Winson Chung setCellLayoutPressedOrFocusedIcon(); 2591e9cbfef04366a206d59922c14fe4356b7cca426Winson Chung } 2601e9cbfef04366a206d59922c14fe4356b7cca426Winson Chung 2613499d8c89d6b5989579880bf80df31df46483304Patrick Dubroy Bitmap getPressedOrFocusedBackground() { 2623499d8c89d6b5989579880bf80df31df46483304Patrick Dubroy return mPressedOrFocusedBackground; 2633499d8c89d6b5989579880bf80df31df46483304Patrick Dubroy } 264a017c0379c30e0272a88a93d05b6a30e28955b88Patrick Dubroy 2653499d8c89d6b5989579880bf80df31df46483304Patrick Dubroy int getPressedOrFocusedBackgroundPadding() { 2663499d8c89d6b5989579880bf80df31df46483304Patrick Dubroy return HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS / 2; 2673499d8c89d6b5989579880bf80df31df46483304Patrick Dubroy } 26888127038178b3bbf0eb91103a31e682cc0615074Winson Chung 2693499d8c89d6b5989579880bf80df31df46483304Patrick Dubroy @Override 2703499d8c89d6b5989579880bf80df31df46483304Patrick Dubroy public void draw(Canvas canvas) { 271bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurka final Drawable background = mBackground; 272bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurka if (background != null) { 273bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurka final int scrollX = mScrollX; 274bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurka final int scrollY = mScrollY; 275bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurka 276bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurka if (mBackgroundSizeChanged) { 277bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurka background.setBounds(0, 0, mRight - mLeft, mBottom - mTop); 278bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurka mBackgroundSizeChanged = false; 279bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurka } 280bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurka 281bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurka if ((scrollX | scrollY) == 0) { 282bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurka background.draw(canvas); 283bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurka } else { 284bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurka canvas.translate(scrollX, scrollY); 285bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurka background.draw(canvas); 286bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurka canvas.translate(-scrollX, -scrollY); 28731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 28807f2e81d77b5f788e1d812011ea3d5b74acde4e4Winson Chung } 289bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurka // We enhance the shadow by drawing the shadow twice 290e7e3f6c438a9de1d4a0557962f868d9a01f56286Michael Jurka getPaint().setShadowLayer(SHADOW_LARGE_RADIUS, 0.0f, SHADOW_Y_OFFSET, SHADOW_LARGE_COLOUR); 291bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurka super.draw(canvas); 292bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurka canvas.save(Canvas.CLIP_SAVE_FLAG); 293bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurka canvas.clipRect(mScrollX, mScrollY + getExtendedPaddingTop(), mScrollX + getWidth(), 2940969300eb23ae2051441d5c72ffbabaab03a93d5Winson Chung mScrollY + getHeight(), Region.Op.INTERSECT); 295e7e3f6c438a9de1d4a0557962f868d9a01f56286Michael Jurka getPaint().setShadowLayer(SHADOW_SMALL_RADIUS, 0.0f, 0.0f, SHADOW_SMALL_COLOUR); 296bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurka super.draw(canvas); 297bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurka canvas.restore(); 29831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 2999c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato 3009c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato @Override 3019c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato protected void onAttachedToWindow() { 3029c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato super.onAttachedToWindow(); 303656d11c882296d732e6bdab30ec26f84b99eba19Winson Chung if (mBackground != null) mBackground.setCallback(this); 3049c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 3059c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato 3069c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato @Override 3079c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato protected void onDetachedFromWindow() { 3089c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato super.onDetachedFromWindow(); 309656d11c882296d732e6bdab30ec26f84b99eba19Winson Chung if (mBackground != null) mBackground.setCallback(null); 3109c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 311affd7b4d23cecb4ed74133dd8bd9a5ede099c562Winson Chung 312affd7b4d23cecb4ed74133dd8bd9a5ede099c562Winson Chung @Override 313affd7b4d23cecb4ed74133dd8bd9a5ede099c562Winson Chung protected boolean onSetAlpha(int alpha) { 314e22a8e9d3eafe569fe0f4d284c77af08c6e2fe28Winson Chung if (mPrevAlpha != alpha) { 315e22a8e9d3eafe569fe0f4d284c77af08c6e2fe28Winson Chung mPrevAlpha = alpha; 316656d11c882296d732e6bdab30ec26f84b99eba19Winson Chung mPaint.setAlpha((int) (alpha * mBubbleColorAlpha)); 317e22a8e9d3eafe569fe0f4d284c77af08c6e2fe28Winson Chung super.onSetAlpha(alpha); 318e22a8e9d3eafe569fe0f4d284c77af08c6e2fe28Winson Chung } 319e22a8e9d3eafe569fe0f4d284c77af08c6e2fe28Winson Chung return true; 320affd7b4d23cecb4ed74133dd8bd9a5ede099c562Winson Chung } 32131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project} 322