Separating double shadow logic for BubbleTextView in a separate subclass

This allows better customization and reuse of the double shadow logic and simplified
various attribute management

Change-Id: I5e277d8399756385452d8bb8c0a0107234a76d34
This commit is contained in:
Sunny Goyal 2017-06-23 10:36:27 -07:00
parent a9d721df78
commit 9314b7c01d
7 changed files with 120 additions and 111 deletions

View File

@ -14,4 +14,4 @@
limitations under the License.
-->
<com.android.launcher3.BubbleTextView style="@style/BaseIcon.Workspace" />
<com.android.launcher3.views.DoubleShadowBubbleTextView style="@style/BaseIcon.Workspace" />

View File

@ -20,7 +20,7 @@
android:layout_height="match_parent"
android:orientation="vertical"
android:focusable="true" >
<com.android.launcher3.BubbleTextView
<com.android.launcher3.views.DoubleShadowBubbleTextView
style="@style/BaseIcon.Workspace"
android:id="@+id/folder_icon_name"
android:focusable="false"

View File

@ -42,7 +42,6 @@
android:textColor="?android:attr/textColorPrimary"
android:textSize="16sp"
android:textAlignment="viewStart"
launcher:customShadows="false"
launcher:deferShadowGeneration="true"
launcher:iconDisplay="widget_section"
launcher:iconSizeOverride="@dimen/widget_section_icon_size"

View File

@ -43,10 +43,15 @@
<enum name="shortcut_popup" value="4" />
</attr>
<attr name="deferShadowGeneration" format="boolean" />
<attr name="customShadows" format="boolean" />
<attr name="centerVertically" format="boolean" />
</declare-styleable>
<declare-styleable name="ShadowInfo">
<attr name="ambientShadowColor" format="color" />
<attr name="ambientShadowBlur" format="dimension" />
<attr name="keyShadowColor" format="color" />
<attr name="keyShadowBlur" format="dimension" />
<attr name="keyShadowOffset" format="dimension" />
</declare-styleable>
<!-- PagedView specific attributes. These attributes are used to customize

View File

@ -119,16 +119,17 @@
<!-- No shadows in the base theme -->
<item name="android:shadowRadius">0</item>
<item name="customShadows">false</item>
</style>
<!-- Icon displayed on the worksapce -->
<style name="BaseIcon.Workspace">
<item name="customShadows">true</item>
<item name="android:shadowRadius">2.0</item>
<item name="android:shadowColor">?attr/workspaceShadowColor</item>
<item name="keyShadowColor">?attr/workspaceKeyShadowColor</item>
<item name="ambientShadowColor">?attr/workspaceAmbientShadowColor</item>
<item name="ambientShadowBlur">2.5dp</item>
<item name="keyShadowColor">?attr/workspaceKeyShadowColor</item>
<item name="keyShadowBlur">1dp</item>
<item name="keyShadowOffset">.5dp</item>
</style>
<!-- Theme for the popup container -->

View File

@ -27,7 +27,6 @@ import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.support.v4.graphics.ColorUtils;
@ -62,11 +61,6 @@ import java.text.NumberFormat;
*/
public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver {
// Dimensions in DP
private static final float AMBIENT_SHADOW_RADIUS = 2.5f;
private static final float KEY_SHADOW_RADIUS = 1f;
private static final float KEY_SHADOW_OFFSET = 0.5f;
private static final int DISPLAY_WORKSPACE = 0;
private static final int DISPLAY_ALL_APPS = 1;
private static final int DISPLAY_FOLDER = 2;
@ -76,22 +70,15 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver {
private final Launcher mLauncher;
private Drawable mIcon;
private final boolean mCenterVertically;
private final Drawable mBackground;
private OnLongClickListener mOnLongClickListener;
private final CheckLongPressHelper mLongPressHelper;
private final HolographicOutlineHelper mOutlineHelper;
private final StylusEventHelper mStylusEventHelper;
private final int mAmbientShadowColor;
private final int mKeyShadowColor;
private boolean mBackgroundSizeChanged;
private final float mSlop;
private Bitmap mPressedBackground;
private float mSlop;
private final boolean mDeferShadowGenerationOnTouch;
private final boolean mCustomShadowsEnabled;
private final boolean mLayoutHorizontal;
private final int mIconSize;
@ViewDebug.ExportedProperty(category = "launcher")
@ -154,15 +141,13 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver {
super(context, attrs, defStyle);
mLauncher = Launcher.getLauncher(context);
DeviceProfile grid = mLauncher.getDeviceProfile();
mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.BubbleTextView, defStyle, 0);
mCustomShadowsEnabled = a.getBoolean(R.styleable.BubbleTextView_customShadows, false);
mLayoutHorizontal = a.getBoolean(R.styleable.BubbleTextView_layoutHorizontal, false);
mDeferShadowGenerationOnTouch =
a.getBoolean(R.styleable.BubbleTextView_deferShadowGeneration, false);
mAmbientShadowColor = a.getColor(R.styleable.BubbleTextView_ambientShadowColor, 0x33000000);
mKeyShadowColor = a.getColor(R.styleable.BubbleTextView_keyShadowColor, 0x66000000);
int display = a.getInteger(R.styleable.BubbleTextView_iconDisplay, DISPLAY_WORKSPACE);
int defaultIconSize = grid.iconSizePx;
@ -184,23 +169,12 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver {
defaultIconSize);
a.recycle();
if (mCustomShadowsEnabled) {
// Draw the background itself as the parent is drawn twice.
mBackground = getBackground();
setBackground(null);
// Set shadow layer as the larger shadow to that the textView does not clip the shadow.
float density = getResources().getDisplayMetrics().density;
setShadowLayer(density * AMBIENT_SHADOW_RADIUS, 0, 0, mAmbientShadowColor);
} else {
mBackground = null;
}
mLongPressHelper = new CheckLongPressHelper(this);
mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
mOutlineHelper = HolographicOutlineHelper.getInstance(getContext());
setAccessibilityDelegate(mLauncher.getAccessibilityDelegate());
}
public void applyFromShortcutInfo(ShortcutInfo info) {
@ -261,19 +235,6 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver {
mLongPressHelper.setLongPressTimeout(longPressTimeout);
}
@Override
protected boolean setFrame(int left, int top, int right, int bottom) {
if (getLeft() != left || getRight() != right || getTop() != top || getBottom() != bottom) {
mBackgroundSizeChanged = true;
}
return super.setFrame(left, top, right, bottom);
}
@Override
protected boolean verifyDrawable(Drawable who) {
return who == mBackground || super.verifyDrawable(who);
}
@Override
public void setTag(Object tag) {
if (tag != null) {
@ -415,54 +376,14 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver {
return result;
}
@SuppressWarnings("wrongcall")
protected void drawWithoutBadge(Canvas canvas) {
super.onDraw(canvas);
}
@Override
public void draw(Canvas canvas) {
if (!mCustomShadowsEnabled) {
super.draw(canvas);
drawBadgeIfNecessary(canvas);
return;
}
final Drawable background = mBackground;
if (background != null) {
final int scrollX = getScrollX();
final int scrollY = getScrollY();
if (mBackgroundSizeChanged) {
background.setBounds(0, 0, getRight() - getLeft(), getBottom() - getTop());
mBackgroundSizeChanged = false;
}
if ((scrollX | scrollY) == 0) {
background.draw(canvas);
} else {
canvas.translate(scrollX, scrollY);
background.draw(canvas);
canvas.translate(-scrollX, -scrollY);
}
}
// If text is transparent, don't draw any shadow
if ((getCurrentTextColor() >> 24) == 0) {
getPaint().clearShadowLayer();
super.draw(canvas);
drawBadgeIfNecessary(canvas);
return;
}
// We enhance the shadow by drawing the shadow twice
float density = getResources().getDisplayMetrics().density;
getPaint().setShadowLayer(density * AMBIENT_SHADOW_RADIUS, 0, 0, mAmbientShadowColor);
super.draw(canvas);
canvas.save(Canvas.CLIP_SAVE_FLAG);
canvas.clipRect(getScrollX(), getScrollY() + getExtendedPaddingTop(),
getScrollX() + getWidth(),
getScrollY() + getHeight(), Region.Op.INTERSECT);
getPaint().setShadowLayer(
density * KEY_SHADOW_RADIUS, 0.0f, density * KEY_SHADOW_OFFSET, mKeyShadowColor);
super.draw(canvas);
canvas.restore();
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawBadgeIfNecessary(canvas);
}
@ -470,7 +391,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver {
* Draws the icon badge in the top right corner of the icon bounds.
* @param canvas The canvas to draw to.
*/
private void drawBadgeIfNecessary(Canvas canvas) {
protected void drawBadgeIfNecessary(Canvas canvas) {
if (!mForceHideBadge && (hasBadge() || mBadgeScale > 0)) {
getIconBounds(mTempIconBounds);
mTempSpaceForBadgeOffset.set((getWidth() - mIconSize) / 2, getPaddingTop());
@ -508,14 +429,6 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver {
outBounds.set(left, top, right, bottom);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (mBackground != null) mBackground.setCallback(this);
mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mCenterVertically) {
@ -529,12 +442,6 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mBackground != null) mBackground.setCallback(null);
}
@Override
public void setTextColor(int color) {
mTextColor = color;

View File

@ -0,0 +1,97 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.views;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Region;
import android.util.AttributeSet;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.R;
/**
* Extension of {@link BubbleTextView} which draws two shadows on the text (ambient and key shadows}
*/
public class DoubleShadowBubbleTextView extends BubbleTextView {
private final ShadowInfo mShadowInfo;
public DoubleShadowBubbleTextView(Context context) {
this(context, null);
}
public DoubleShadowBubbleTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DoubleShadowBubbleTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mShadowInfo = new ShadowInfo(context, attrs, defStyle);
setShadowLayer(mShadowInfo.ambientShadowBlur, 0, 0, mShadowInfo.ambientShadowColor);
}
@Override
public void onDraw(Canvas canvas) {
// If text is transparent, don't draw any shadow
if ((getCurrentTextColor() >> 24) == 0) {
getPaint().clearShadowLayer();
super.onDraw(canvas);
return;
}
// We enhance the shadow by drawing the shadow twice
getPaint().setShadowLayer(
mShadowInfo.ambientShadowBlur, 0, 0, mShadowInfo.ambientShadowColor);
drawWithoutBadge(canvas);
canvas.save(Canvas.CLIP_SAVE_FLAG);
canvas.clipRect(getScrollX(), getScrollY() + getExtendedPaddingTop(),
getScrollX() + getWidth(),
getScrollY() + getHeight(), Region.Op.INTERSECT);
getPaint().setShadowLayer(mShadowInfo.keyShadowBlur, 0.0f,
mShadowInfo.keyShadowOffset, mShadowInfo.keyShadowColor);
drawWithoutBadge(canvas);
canvas.restore();
drawBadgeIfNecessary(canvas);
}
public static class ShadowInfo {
public final float ambientShadowBlur;
public final int ambientShadowColor;
public final float keyShadowBlur;
public final float keyShadowOffset;
public final int keyShadowColor;
public ShadowInfo(Context c, AttributeSet attrs, int defStyle) {
TypedArray a = c.obtainStyledAttributes(
attrs, R.styleable.ShadowInfo, defStyle, 0);
ambientShadowBlur = a.getDimension(R.styleable.ShadowInfo_ambientShadowBlur, 0);
ambientShadowColor = a.getColor(R.styleable.ShadowInfo_ambientShadowColor, 0);
keyShadowBlur = a.getDimension(R.styleable.ShadowInfo_keyShadowBlur, 0);
keyShadowOffset = a.getDimension(R.styleable.ShadowInfo_keyShadowOffset, 0);
keyShadowColor = a.getColor(R.styleable.ShadowInfo_keyShadowColor, 0);
a.recycle();
}
}
}