diff options
author | Sunny Goyal <sunnygoyal@google.com> | 2014-08-20 20:36:59 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2014-08-20 20:15:45 +0000 |
commit | 22308ce1b858aa9a4e9068ea4fb1d47e62fc6e67 (patch) | |
tree | b4d16b837ff1c55a64053e692a6082cd28affdf6 | |
parent | 2111606845bec8b40e8eb164c73c60f59c028014 (diff) | |
parent | 508da15509224b46fcccabbe78f3e92fe69a67d8 (diff) | |
download | android_packages_apps_Trebuchet-22308ce1b858aa9a4e9068ea4fb1d47e62fc6e67.tar.gz android_packages_apps_Trebuchet-22308ce1b858aa9a4e9068ea4fb1d47e62fc6e67.tar.bz2 android_packages_apps_Trebuchet-22308ce1b858aa9a4e9068ea4fb1d47e62fc6e67.zip |
Merge "Updating the icon click feedback" into ub-now-porkchop
-rw-r--r-- | res/layout/apps_customize_application.xml | 4 | ||||
-rw-r--r-- | res/values/attrs.xml | 1 | ||||
-rw-r--r-- | res/values/colors.xml | 1 | ||||
-rw-r--r-- | res/values/styles.xml | 4 | ||||
-rw-r--r-- | src/com/android/launcher3/AppsCustomizePagedView.java | 86 | ||||
-rw-r--r-- | src/com/android/launcher3/BubbleTextView.java | 210 | ||||
-rw-r--r-- | src/com/android/launcher3/CellLayout.java | 57 | ||||
-rw-r--r-- | src/com/android/launcher3/FastBitmapDrawable.java | 65 | ||||
-rw-r--r-- | src/com/android/launcher3/FastBitmapView.java | 58 | ||||
-rw-r--r-- | src/com/android/launcher3/FocusHelper.java | 21 | ||||
-rw-r--r-- | src/com/android/launcher3/Folder.java | 9 | ||||
-rw-r--r-- | src/com/android/launcher3/FolderIcon.java | 5 | ||||
-rw-r--r-- | src/com/android/launcher3/HolographicOutlineHelper.java | 188 | ||||
-rw-r--r-- | src/com/android/launcher3/Launcher.java | 53 | ||||
-rw-r--r-- | src/com/android/launcher3/PagedViewIcon.java | 114 | ||||
-rw-r--r-- | src/com/android/launcher3/Workspace.java | 96 |
16 files changed, 393 insertions, 579 deletions
diff --git a/res/layout/apps_customize_application.xml b/res/layout/apps_customize_application.xml index 17f4a8e15..c56cdf3d2 100644 --- a/res/layout/apps_customize_application.xml +++ b/res/layout/apps_customize_application.xml @@ -14,10 +14,8 @@ limitations under the License. --> -<com.android.launcher3.PagedViewIcon +<com.android.launcher3.BubbleTextView xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" - style="@style/WorkspaceIcon.AppsCustomize" android:id="@+id/application_icon" android:focusable="true" /> diff --git a/res/values/attrs.xml b/res/values/attrs.xml index 552e84ca2..0db60c95c 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -106,7 +106,6 @@ <declare-styleable name="BubbleTextView"> <!-- A spacing override for the icons within a page --> <attr name="customShadows" format="boolean" /> - <attr name="glowColor" format="color" /> </declare-styleable> <!-- AppsCustomizePagedView specific attributes. These attributes are used to diff --git a/res/values/colors.xml b/res/values/colors.xml index 5e9c6ecec..8aa2184e5 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -34,7 +34,6 @@ <color name="quantum_panel_text_color">#FF666666</color> <color name="quantum_panel_text_shadow_color">#FFC4C4C4</color> - <color name="folder_items_glow_color">#FFCCCCCC</color> <color name="outline_color">#FFFFFFFF</color> <color name="widget_text_panel">#FF374248</color> diff --git a/res/values/styles.xml b/res/values/styles.xml index 6079eee3b..056930604 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -91,7 +91,8 @@ <item name="android:shadowRadius">2.0</item> <item name="android:shadowDx">0</item> <item name="android:shadowDy">2</item> - <item name="android:shadowColor">#FFC4C4C4</item> + <item name="android:shadowColor">@color/quantum_panel_text_shadow_color</item> + <item name="customShadows">false</item> </style> <style name="WorkspaceIcon.Folder"> @@ -103,7 +104,6 @@ <item name="android:shadowDy">2</item> <item name="customShadows">false</item> - <item name="glowColor">@color/folder_items_glow_color</item> </style> <style name="SearchDropTargetBar"> diff --git a/src/com/android/launcher3/AppsCustomizePagedView.java b/src/com/android/launcher3/AppsCustomizePagedView.java index b2228f7af..1ab11ee8a 100644 --- a/src/com/android/launcher3/AppsCustomizePagedView.java +++ b/src/com/android/launcher3/AppsCustomizePagedView.java @@ -44,7 +44,6 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.animation.AccelerateInterpolator; -import android.view.animation.DecelerateInterpolator; import android.widget.GridLayout; import android.widget.ImageView; import android.widget.Toast; @@ -144,8 +143,7 @@ class AppsCustomizeAsyncTask extends AsyncTask<AsyncTaskPageData, Void, AsyncTas */ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implements View.OnClickListener, View.OnKeyListener, DragSource, - PagedViewIcon.PressedCallback, PagedViewWidget.ShortPressListener, - LauncherTransitionable { + PagedViewWidget.ShortPressListener, LauncherTransitionable { static final String TAG = "AppsCustomizePagedView"; private static Rect sTmpRect = new Rect(); @@ -167,7 +165,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen // Save and Restore private int mSaveInstanceStateItemIndex = -1; - private PagedViewIcon mPressedIcon; // Content private ArrayList<AppInfo> mApps; @@ -444,39 +441,29 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen @Override public void onClick(View v) { // When we have exited all apps or are in transition, disregard clicks - if (!mLauncher.isAllAppsVisible() || - mLauncher.getWorkspace().isSwitchingState()) return; + if (!mLauncher.isAllAppsVisible() + || mLauncher.getWorkspace().isSwitchingState() + || !(v instanceof PagedViewWidget)) return; - if (v instanceof PagedViewIcon) { - // Animate some feedback to the click - final AppInfo appInfo = (AppInfo) v.getTag(); - - // Lock the drawable state to pressed until we return to Launcher - if (mPressedIcon != null) { - mPressedIcon.lockDrawableState(); - } - mLauncher.onClickPagedViewIcon(v, appInfo); - } else if (v instanceof PagedViewWidget) { - // Let the user know that they have to long press to add a widget - if (mWidgetInstructionToast != null) { - mWidgetInstructionToast.cancel(); - } - mWidgetInstructionToast = Toast.makeText(getContext(),R.string.long_press_widget_to_add, - Toast.LENGTH_SHORT); - mWidgetInstructionToast.show(); - - // Create a little animation to show that the widget can move - float offsetY = getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY); - final ImageView p = (ImageView) v.findViewById(R.id.widget_preview); - AnimatorSet bounce = LauncherAnimUtils.createAnimatorSet(); - ValueAnimator tyuAnim = LauncherAnimUtils.ofFloat(p, "translationY", offsetY); - tyuAnim.setDuration(125); - ValueAnimator tydAnim = LauncherAnimUtils.ofFloat(p, "translationY", 0f); - tydAnim.setDuration(100); - bounce.play(tyuAnim).before(tydAnim); - bounce.setInterpolator(new AccelerateInterpolator()); - bounce.start(); + // Let the user know that they have to long press to add a widget + if (mWidgetInstructionToast != null) { + mWidgetInstructionToast.cancel(); } + mWidgetInstructionToast = Toast.makeText(getContext(),R.string.long_press_widget_to_add, + Toast.LENGTH_SHORT); + mWidgetInstructionToast.show(); + + // Create a little animation to show that the widget can move + float offsetY = getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY); + final ImageView p = (ImageView) v.findViewById(R.id.widget_preview); + AnimatorSet bounce = LauncherAnimUtils.createAnimatorSet(); + ValueAnimator tyuAnim = LauncherAnimUtils.ofFloat(p, "translationY", offsetY); + tyuAnim.setDuration(125); + ValueAnimator tydAnim = LauncherAnimUtils.ofFloat(p, "translationY", 0f); + tydAnim.setDuration(100); + bounce.play(tyuAnim).before(tydAnim); + bounce.setInterpolator(new AccelerateInterpolator()); + bounce.start(); } public boolean onKey(View v, int keyCode, KeyEvent event) { @@ -492,7 +479,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } private void beginDraggingApplication(View v) { - mLauncher.getWorkspace().onDragStartedWithItem(v); mLauncher.getWorkspace().beginDragShared(v, this); } @@ -726,7 +712,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen protected boolean beginDragging(final View v) { if (!super.beginDragging(v)) return false; - if (v instanceof PagedViewIcon) { + if (v instanceof BubbleTextView) { beginDraggingApplication(v); } else if (v instanceof PagedViewWidget) { if (!beginDraggingWidget(v)) { @@ -741,9 +727,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen public void run() { // We don't enter spring-loaded mode if the drag has been cancelled if (mLauncher.getDragController().isDragging()) { - // Reset the alpha on the dragged icon before we drag - resetDrawableState(); - // Go into spring loaded mode (must happen before we startDrag()) mLauncher.enterSpringLoadedDragMode(); } @@ -992,10 +975,10 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen ArrayList<Bitmap> images = new ArrayList<Bitmap>(); for (int i = startIndex; i < endIndex; ++i) { AppInfo info = mApps.get(i); - PagedViewIcon icon = (PagedViewIcon) mLayoutInflater.inflate( + BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate( R.layout.apps_customize_application, layout, false); - icon.applyFromApplicationInfo(info, true, this); - icon.setOnClickListener(this); + icon.applyFromApplicationInfo(info); + icon.setOnClickListener(mLauncher); icon.setOnLongClickListener(this); icon.setOnTouchListener(this); icon.setOnKeyListener(this); @@ -1559,23 +1542,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen cancelAllTasks(); } - @Override - public void iconPressed(PagedViewIcon icon) { - // Reset the previously pressed icon and store a reference to the pressed icon so that - // we can reset it on return to Launcher (in Launcher.onResume()) - if (mPressedIcon != null) { - mPressedIcon.resetDrawableState(); - } - mPressedIcon = icon; - } - - public void resetDrawableState() { - if (mPressedIcon != null) { - mPressedIcon.resetDrawableState(); - mPressedIcon = null; - } - } - /* * We load an extra page on each side to prevent flashes from scrolling and loading of the * widget previews in the background with the AsyncTasks. diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index 5c2bb9946..869b0ac88 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -23,14 +23,13 @@ import android.content.res.Resources.Theme; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; -import android.graphics.Rect; import android.graphics.Region; -import android.graphics.Region.Op; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.util.Log; import android.util.SparseArray; import android.util.TypedValue; +import android.view.KeyEvent; import android.view.MotionEvent; import android.view.ViewConfiguration; import android.widget.TextView; @@ -44,12 +43,11 @@ public class BubbleTextView extends TextView { private static SparseArray<Theme> sPreloaderThemes = new SparseArray<>(2); - static final float SHADOW_LARGE_RADIUS = 4.0f; - static final float SHADOW_SMALL_RADIUS = 1.75f; - static final float SHADOW_Y_OFFSET = 2.0f; - static final int SHADOW_LARGE_COLOUR = 0xDD000000; - static final int SHADOW_SMALL_COLOUR = 0xCC000000; - static final float PADDING_H = 8.0f; + private static final float SHADOW_LARGE_RADIUS = 4.0f; + private static final float SHADOW_SMALL_RADIUS = 1.75f; + private static final float SHADOW_Y_OFFSET = 2.0f; + private static final int SHADOW_LARGE_COLOUR = 0xDD000000; + private static final int SHADOW_SMALL_COLOUR = 0xCC000000; static final float PADDING_V = 3.0f; private static final String TAG = "BubbleTextView"; @@ -57,14 +55,7 @@ public class BubbleTextView extends TextView { private static final boolean DEBUG = false; private HolographicOutlineHelper mOutlineHelper; - private final Canvas mTempCanvas = new Canvas(); - private final Rect mTempRect = new Rect(); - private boolean mDidInvalidateForPressedState; - private Bitmap mPressedOrFocusedBackground; - private int mFocusedOutlineColor; - private int mFocusedGlowColor; - private int mPressedOutlineColor; - private int mPressedGlowColor; + private Bitmap mPressedBackground; private float mSlop; @@ -72,14 +63,15 @@ public class BubbleTextView extends TextView { private final boolean mCustomShadowsEnabled; private boolean mIsTextVisible; + // TODO: Remove custom background handling code, as no instance of BubbleTextView use any + // background. private boolean mBackgroundSizeChanged; private final Drawable mBackground; private boolean mStayPressed; + private boolean mIgnorePressedStateChange; private CheckLongPressHelper mLongPressHelper; - private CharSequence mDefaultText = ""; - public BubbleTextView(Context context) { this(context, null, 0); } @@ -91,11 +83,8 @@ public class BubbleTextView extends TextView { public BubbleTextView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - Resources res = context.getResources(); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BubbleTextView, defStyle, 0); - setGlowColor(a.getColor(R.styleable.BubbleTextView_glowColor, - res.getColor(R.color.outline_color))); mCustomShadowsEnabled = a.getBoolean(R.styleable.BubbleTextView_customShadows, true); a.recycle(); @@ -143,6 +132,7 @@ public class BubbleTextView extends TextView { if (info.contentDescription != null) { setContentDescription(info.contentDescription); } + setText(info.title); setTag(info); if (info.wasPromise) { @@ -150,6 +140,22 @@ public class BubbleTextView extends TextView { } } + public void applyFromApplicationInfo(AppInfo info) { + LauncherAppState app = LauncherAppState.getInstance(); + DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + + Drawable topDrawable = Utilities.createIconDrawable(info.iconBitmap); + topDrawable.setBounds(0, 0, grid.allAppsIconSizePx, grid.allAppsIconSizePx); + setCompoundDrawables(null, topDrawable, null, null); + setCompoundDrawablePadding(grid.iconDrawablePaddingPx); + setText(info.title); + if (info.contentDescription != null) { + setContentDescription(info.contentDescription); + } + setTag(info); + } + + @Override protected boolean setFrame(int left, int top, int right, int bottom) { if (getLeft() != left || getRight() != right || getTop() != top || getBottom() != bottom) { @@ -169,98 +175,22 @@ public class BubbleTextView extends TextView { LauncherModel.checkItemInfo((ItemInfo) tag); } super.setTag(tag); - if (tag instanceof ShortcutInfo) { - final ShortcutInfo info = (ShortcutInfo) tag; - mDefaultText = info.title; - setText(mDefaultText); - } } @Override - protected void drawableStateChanged() { - if (isPressed()) { - // In this case, we have already created the pressed outline on ACTION_DOWN, - // so we just need to do an invalidate to trigger draw - if (!mDidInvalidateForPressedState) { - setCellLayoutPressedOrFocusedIcon(); - } - } else { - // Otherwise, either clear the pressed/focused background, or create a background - // for the focused state - final boolean backgroundEmptyBefore = mPressedOrFocusedBackground == null; - if (!mStayPressed) { - mPressedOrFocusedBackground = null; - } - if (isFocused()) { - if (getLayout() == null) { - // In some cases, we get focus before we have been layed out. Set the - // background to null so that it will get created when the view is drawn. - mPressedOrFocusedBackground = null; - } else { - mPressedOrFocusedBackground = createGlowingOutline( - mTempCanvas, mFocusedGlowColor, mFocusedOutlineColor); - } - mStayPressed = false; - setCellLayoutPressedOrFocusedIcon(); - } - final boolean backgroundEmptyNow = mPressedOrFocusedBackground == null; - if (!backgroundEmptyBefore && backgroundEmptyNow) { - setCellLayoutPressedOrFocusedIcon(); - } - } + public void setPressed(boolean pressed) { + super.setPressed(pressed); - Drawable d = mBackground; - if (d != null && d.isStateful()) { - d.setState(getDrawableState()); + if (!mIgnorePressedStateChange) { + updateIconState(); } - super.drawableStateChanged(); } - /** - * Draw this BubbleTextView into the given Canvas. - * - * @param destCanvas the canvas to draw on - * @param padding the horizontal and vertical padding to use when drawing - */ - private void drawWithPadding(Canvas destCanvas, int padding) { - final Rect clipRect = mTempRect; - getDrawingRect(clipRect); - - // adjust the clip rect so that we don't include the text label - clipRect.bottom = - getExtendedPaddingTop() - (int) BubbleTextView.PADDING_V + getLayout().getLineTop(0); - - // Draw the View into the bitmap. - // The translate of scrollX and scrollY is necessary when drawing TextViews, because - // they set scrollX and scrollY to large values to achieve centered text - destCanvas.save(); - destCanvas.scale(getScaleX(), getScaleY(), - (getWidth() + padding) / 2, (getHeight() + padding) / 2); - destCanvas.translate(-getScrollX() + padding / 2, -getScrollY() + padding / 2); - destCanvas.clipRect(clipRect, Op.REPLACE); - draw(destCanvas); - destCanvas.restore(); - } - - public void setGlowColor(int color) { - mFocusedOutlineColor = mFocusedGlowColor = mPressedOutlineColor = mPressedGlowColor = color; - } - - /** - * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location. - * Responsibility for the bitmap is transferred to the caller. - */ - private Bitmap createGlowingOutline(Canvas canvas, int outlineColor, int glowColor) { - final int padding = mOutlineHelper.mMaxOuterBlurRadius; - final Bitmap b = Bitmap.createBitmap( - getWidth() + padding, getHeight() + padding, Bitmap.Config.ARGB_8888); - - canvas.setBitmap(b); - drawWithPadding(canvas, padding); - mOutlineHelper.applyExtraThickExpensiveOutlineWithBlur(b, canvas, glowColor, outlineColor); - canvas.setBitmap(null); - - return b; + private void updateIconState() { + Drawable top = getCompoundDrawables()[1]; + if (top instanceof FastBitmapDrawable) { + ((FastBitmapDrawable) top).setPressed(isPressed() || mStayPressed); + } } @Override @@ -271,20 +201,11 @@ public class BubbleTextView extends TextView { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: - // So that the pressed outline is visible immediately when isPressed() is true, + // So that the pressed outline is visible immediately on setStayPressed(), // we pre-create it on ACTION_DOWN (it takes a small but perceptible amount of time // to create it) - if (mPressedOrFocusedBackground == null) { - mPressedOrFocusedBackground = createGlowingOutline( - mTempCanvas, mPressedGlowColor, mPressedOutlineColor); - } - // Invalidate so the pressed state is visible, or set a flag so we know that we - // have to call invalidate as soon as the state is "pressed" - if (isPressed()) { - mDidInvalidateForPressedState = true; - setCellLayoutPressedOrFocusedIcon(); - } else { - mDidInvalidateForPressedState = false; + if (mPressedBackground == null) { + mPressedBackground = mOutlineHelper.createMediumDropShadow(this); } mLongPressHelper.postCheckForLongPress(); @@ -294,7 +215,7 @@ public class BubbleTextView extends TextView { // If we've touched down and up on an item, and it's still not "pressed", then // destroy the pressed outline if (!isPressed()) { - mPressedOrFocusedBackground = null; + mPressedBackground = null; } mLongPressHelper.cancelLongPress(); @@ -311,34 +232,47 @@ public class BubbleTextView extends TextView { void setStayPressed(boolean stayPressed) { mStayPressed = stayPressed; if (!stayPressed) { - mPressedOrFocusedBackground = null; + mPressedBackground = null; } - setCellLayoutPressedOrFocusedIcon(); - } - void setCellLayoutPressedOrFocusedIcon() { - // Disable pressed state when the icon is in preloader state. - if ((getParent() instanceof ShortcutAndWidgetContainer) && - !(getCompoundDrawables()[1] instanceof PreloadIconDrawable)){ - ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) getParent(); - if (parent != null) { - CellLayout layout = (CellLayout) parent.getParent(); - layout.setPressedOrFocusedIcon((mPressedOrFocusedBackground != null) ? this : null); - } + // Only show the shadow effect when persistent pressed state is set. + if (getParent() instanceof ShortcutAndWidgetContainer) { + CellLayout layout = (CellLayout) getParent().getParent(); + layout.setPressedIcon(this, mPressedBackground, mOutlineHelper.shadowBitmapPadding); } + + updateIconState(); } - void clearPressedOrFocusedBackground() { - mPressedOrFocusedBackground = null; - setCellLayoutPressedOrFocusedIcon(); + void clearPressedBackground() { + setPressed(false); + setStayPressed(false); } - Bitmap getPressedOrFocusedBackground() { - return mPressedOrFocusedBackground; + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (super.onKeyDown(keyCode, event)) { + // Pre-create shadow so show immediately on click. + if (mPressedBackground == null) { + mPressedBackground = mOutlineHelper.createMediumDropShadow(this); + } + return true; + } + return false; } - int getPressedOrFocusedBackgroundPadding() { - return mOutlineHelper.mMaxOuterBlurRadius / 2; + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + // Unlike touch events, keypress event propagate pressed state change immediately, + // without waiting for onClickHandler to execute. Disable pressed state changes here + // to avoid flickering. + mIgnorePressedStateChange = true; + boolean result = super.onKeyUp(keyCode, event); + + mPressedBackground = null; + mIgnorePressedStateChange = false; + updateIconState(); + return result; } @Override diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index 89473c8b1..d0b3f4376 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -123,7 +123,7 @@ public class CellLayout extends ViewGroup { private int mDragOutlineCurrent = 0; private final Paint mDragOutlinePaint = new Paint(); - private BubbleTextView mPressedOrFocusedIcon; + private final FastBitmapView mTouchFeedbackView; private HashMap<CellLayout.LayoutParams, Animator> mReorderAnimators = new HashMap<CellLayout.LayoutParams, Animator>(); @@ -288,6 +288,9 @@ public class CellLayout extends ViewGroup { mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap, mCountX, mCountY); + mTouchFeedbackView = new FastBitmapView(context); + // Make the feedback view large enough to hold the blur bitmap. + addView(mTouchFeedbackView, (int) (grid.cellWidthPx * 1.5), (int) (grid.cellHeightPx * 1.5)); addView(mShortcutsAndWidgets); } @@ -334,14 +337,6 @@ public class CellLayout extends ViewGroup { return mDropPending; } - private void invalidateBubbleTextView(BubbleTextView icon) { - final int padding = icon.getPressedOrFocusedBackgroundPadding(); - invalidate(icon.getLeft() + getPaddingLeft() - padding, - icon.getTop() + getPaddingTop() - padding, - icon.getRight() + getPaddingLeft() + padding, - icon.getBottom() + getPaddingTop() + padding); - } - void setOverScrollAmount(float r, boolean left) { if (left && mOverScrollForegroundDrawable != mOverScrollLeft) { mOverScrollForegroundDrawable = mOverScrollLeft; @@ -355,16 +350,23 @@ public class CellLayout extends ViewGroup { invalidate(); } - void setPressedOrFocusedIcon(BubbleTextView icon) { - // We draw the pressed or focused BubbleTextView's background in CellLayout because it - // requires an expanded clip rect (due to the glow's blur radius) - BubbleTextView oldIcon = mPressedOrFocusedIcon; - mPressedOrFocusedIcon = icon; - if (oldIcon != null) { - invalidateBubbleTextView(oldIcon); - } - if (mPressedOrFocusedIcon != null) { - invalidateBubbleTextView(mPressedOrFocusedIcon); + void setPressedIcon(BubbleTextView icon, Bitmap background, int padding) { + if (icon == null || background == null) { + mTouchFeedbackView.setBitmap(null); + mTouchFeedbackView.animate().cancel(); + } else { + int offset = getMeasuredWidth() - getPaddingLeft() - getPaddingRight() + - (mCountX * mCellWidth); + mTouchFeedbackView.setTranslationX(icon.getLeft() + (int) Math.ceil(offset / 2f) + - padding); + mTouchFeedbackView.setTranslationY(icon.getTop() - padding); + if (mTouchFeedbackView.setBitmap(background)) { + mTouchFeedbackView.setAlpha(0); + mTouchFeedbackView.animate().alpha(1) + .setDuration(FastBitmapDrawable.CLICK_FEEDBACK_DURATION) + .setInterpolator(FastBitmapDrawable.CLICK_FEEDBACK_INTERPOLATOR) + .start(); + } } } @@ -431,23 +433,6 @@ public class CellLayout extends ViewGroup { } } - // We draw the pressed or focused BubbleTextView's background in CellLayout because it - // requires an expanded clip rect (due to the glow's blur radius) - if (mPressedOrFocusedIcon != null) { - final int padding = mPressedOrFocusedIcon.getPressedOrFocusedBackgroundPadding(); - final Bitmap b = mPressedOrFocusedIcon.getPressedOrFocusedBackground(); - if (b != null) { - int offset = getMeasuredWidth() - getPaddingLeft() - getPaddingRight() - - (mCountX * mCellWidth); - int left = getPaddingLeft() + (int) Math.ceil(offset / 2f); - int top = getPaddingTop(); - canvas.drawBitmap(b, - mPressedOrFocusedIcon.getLeft() + left - padding, - mPressedOrFocusedIcon.getTop() + top - padding, - null); - } - } - if (DEBUG_VISUALIZE_OCCUPIED) { int[] pt = new int[2]; ColorDrawable cd = new ColorDrawable(Color.RED); diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java index cf7c22eef..7c9e77eef 100644 --- a/src/com/android/launcher3/FastBitmapDrawable.java +++ b/src/com/android/launcher3/FastBitmapDrawable.java @@ -16,30 +16,62 @@ package com.android.launcher3; +import android.animation.ObjectAnimator; +import android.animation.TimeInterpolator; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; import android.graphics.Paint; import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.util.SparseArray; class FastBitmapDrawable extends Drawable { + static final TimeInterpolator CLICK_FEEDBACK_INTERPOLATOR = new TimeInterpolator() { + + @Override + public float getInterpolation(float input) { + if (input < 0.05f) { + return input / 0.05f; + } else if (input < 0.3f){ + return 1; + } else { + return (1 - input) / 0.7f; + } + } + }; + static final long CLICK_FEEDBACK_DURATION = 2000; + + private static final int PRESSED_BRIGHTNESS = 100; private static ColorMatrix sGhostModeMatrix; private static final ColorMatrix sTempMatrix = new ColorMatrix(); + /** + * Store the brightness colors filters to optimize animations during icon press. This + * only works for non-ghost-mode icons. + */ + private static final SparseArray<ColorFilter> sCachedBrightnessFilter = + new SparseArray<ColorFilter>(); + private static final int GHOST_MODE_MIN_COLOR_RANGE = 130; private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG); - private Bitmap mBitmap; + private final Bitmap mBitmap; private int mAlpha; private int mBrightness = 0; private boolean mGhostModeEnabled = false; + private boolean mPressed = false; + private ObjectAnimator mPressedAnimator; + FastBitmapDrawable(Bitmap b) { mAlpha = 255; mBitmap = b; @@ -114,6 +146,23 @@ class FastBitmapDrawable extends Drawable { } } + public void setPressed(boolean pressed) { + if (mPressed != pressed) { + mPressed = pressed; + if (mPressed) { + mPressedAnimator = ObjectAnimator + .ofInt(this, "brightness", PRESSED_BRIGHTNESS) + .setDuration(CLICK_FEEDBACK_DURATION); + mPressedAnimator.setInterpolator(CLICK_FEEDBACK_INTERPOLATOR); + mPressedAnimator.start(); + } else if (mPressedAnimator != null) { + mPressedAnimator.cancel(); + setBrightness(0); + } + } + invalidateSelf(); + } + public boolean isGhostModeEnabled() { return mGhostModeEnabled; } @@ -122,14 +171,11 @@ class FastBitmapDrawable extends Drawable { return mBrightness; } - public void addBrightness(int amount) { - setBrightness(mBrightness + amount); - } - public void setBrightness(int brightness) { if (mBrightness != brightness) { mBrightness = brightness; updateFilter(); + invalidateSelf(); } } @@ -157,8 +203,13 @@ class FastBitmapDrawable extends Drawable { mPaint.setColorFilter(new ColorMatrixColorFilter(sTempMatrix)); } } else if (mBrightness != 0) { - setBrightnessMatrix(sTempMatrix, mBrightness); - mPaint.setColorFilter(new ColorMatrixColorFilter(sTempMatrix)); + ColorFilter filter = sCachedBrightnessFilter.get(mBrightness); + if (filter == null) { + filter = new PorterDuffColorFilter(Color.argb(mBrightness, 255, 255, 255), + PorterDuff.Mode.SRC_ATOP); + sCachedBrightnessFilter.put(mBrightness, filter); + } + mPaint.setColorFilter(filter); } else { mPaint.setColorFilter(null); } diff --git a/src/com/android/launcher3/FastBitmapView.java b/src/com/android/launcher3/FastBitmapView.java new file mode 100644 index 000000000..0937eb75e --- /dev/null +++ b/src/com/android/launcher3/FastBitmapView.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2014 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; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.view.View; + +public class FastBitmapView extends View { + + private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG); + private Bitmap mBitmap; + + public FastBitmapView(Context context) { + super(context); + } + + /** + * Applies the new bitmap. + * @return true if the view was invalidated. + */ + public boolean setBitmap(Bitmap b) { + if (b != mBitmap){ + if (mBitmap != null) { + invalidate(0, 0, mBitmap.getWidth(), mBitmap.getHeight()); + } + mBitmap = b; + if (mBitmap != null) { + invalidate(0, 0, mBitmap.getWidth(), mBitmap.getHeight()); + } + return true; + } + return false; + } + + @Override + protected void onDraw(Canvas canvas) { + if (mBitmap != null) { + canvas.drawBitmap(mBitmap, 0, 0, mPaint); + } + } +} diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java index df5e0fc33..34e752b85 100644 --- a/src/com/android/launcher3/FocusHelper.java +++ b/src/com/android/launcher3/FocusHelper.java @@ -22,8 +22,6 @@ import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; import android.widget.ScrollView; -import android.widget.TabHost; -import android.widget.TabWidget; import java.util.ArrayList; import java.util.Collections; @@ -89,7 +87,6 @@ public class FocusHelper { final PagedViewGridLayout parent = (PagedViewGridLayout) w.getParent(); final PagedView container = (PagedView) parent.getParent(); - final AppsCustomizeTabHost tabHost = findTabHostParent(container); final int widgetIndex = parent.indexOfChild(w); final int widgetCount = parent.getChildCount(); final int pageIndex = ((PagedView) container).indexToPage(container.indexOfChild(parent)); @@ -228,6 +225,13 @@ public class FocusHelper { * Handles key events in a PageViewCellLayout containing PagedViewIcons. */ static boolean handleAppsCustomizeKeyEvent(View v, int keyCode, KeyEvent e) { + final int action = e.getAction(); + if (((action == KeyEvent.ACTION_DOWN) && v.onKeyDown(keyCode, e)) + || ((action == KeyEvent.ACTION_UP) && v.onKeyUp(keyCode, e))) { + // Let the view handle the confirmation key. + return true; + } + ViewGroup parentLayout; ViewGroup itemContainer; int countX; @@ -246,7 +250,6 @@ public class FocusHelper { // Note we have an extra parent because of the // PagedViewCellLayout/PagedViewCellLayoutChildren relationship final PagedView container = (PagedView) parentLayout.getParent(); - final AppsCustomizeTabHost tabHost = findTabHostParent(container); final int iconIndex = itemContainer.indexOfChild(v); final int itemCount = itemContainer.getChildCount(); final int pageIndex = ((PagedView) container).indexToPage(container.indexOfChild(parentLayout)); @@ -255,7 +258,6 @@ public class FocusHelper { final int x = iconIndex % countX; final int y = iconIndex / countX; - final int action = e.getAction(); final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP); ViewGroup newParent = null; // Side pages do not always load synchronously, so check before focusing child siblings @@ -319,15 +321,6 @@ public class FocusHelper { } wasHandled = true; break; - case KeyEvent.KEYCODE_ENTER: - case KeyEvent.KEYCODE_DPAD_CENTER: - if (handleKeyEvent) { - // Simulate a click on the icon - View.OnClickListener clickListener = (View.OnClickListener) container; - clickListener.onClick(v); - } - wasHandled = true; - break; case KeyEvent.KEYCODE_PAGE_UP: if (handleKeyEvent) { // Select the first icon on the previous page, or the first icon on this page diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java index c548a6f39..f26f87c39 100644 --- a/src/com/android/launcher3/Folder.java +++ b/src/com/android/launcher3/Folder.java @@ -118,10 +118,6 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList private FocusIndicatorView mFocusIndicatorHandler; - private int DRAG_MODE_NONE = 0; - private int DRAG_MODE_REORDER = 1; - private int mDragMode = DRAG_MODE_NONE; - // We avoid measuring the scroll view with a 0 width or height, as this // results in CellLayout being measured as UNSPECIFIED, which it does // not support. @@ -254,7 +250,6 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList mLauncher.getLauncherClings().dismissFolderCling(null); - mLauncher.getWorkspace().onDragStartedWithItem(v); mLauncher.getWorkspace().beginDragShared(v, this); mCurrentDragInfo = item; @@ -783,9 +778,6 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList mReorderAlarm.setAlarm(REORDER_DELAY); mPreviousTargetCell[0] = mTargetCell[0]; mPreviousTargetCell[1] = mTargetCell[1]; - mDragMode = DRAG_MODE_REORDER; - } else { - mDragMode = DRAG_MODE_NONE; } } } @@ -841,7 +833,6 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList mOnExitAlarm.setAlarm(ON_EXIT_CLOSE_DELAY); } mReorderAlarm.cancelAlarm(); - mDragMode = DRAG_MODE_NONE; } public void onDropCompleted(final View target, final DragObject d, diff --git a/src/com/android/launcher3/FolderIcon.java b/src/com/android/launcher3/FolderIcon.java index 21efd7113..a359f1180 100644 --- a/src/com/android/launcher3/FolderIcon.java +++ b/src/com/android/launcher3/FolderIcon.java @@ -583,9 +583,10 @@ public class FolderIcon extends FrameLayout implements FolderListener { d.setBounds(0, 0, mIntrinsicIconSize, mIntrinsicIconSize); if (d instanceof FastBitmapDrawable) { FastBitmapDrawable fd = (FastBitmapDrawable) d; - fd.addBrightness(params.overlayAlpha); + int oldBrightness = fd.getBrightness(); + fd.setBrightness(params.overlayAlpha); d.draw(canvas); - fd.addBrightness(-params.overlayAlpha); + fd.setBrightness(oldBrightness); } else { d.setColorFilter(Color.argb(params.overlayAlpha, 255, 255, 255), PorterDuff.Mode.SRC_ATOP); diff --git a/src/com/android/launcher3/HolographicOutlineHelper.java b/src/com/android/launcher3/HolographicOutlineHelper.java index d7b960aba..b1e0e68a4 100644 --- a/src/com/android/launcher3/HolographicOutlineHelper.java +++ b/src/com/android/launcher3/HolographicOutlineHelper.java @@ -20,48 +20,49 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.BlurMaskFilter; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; +import android.graphics.Region.Op; public class HolographicOutlineHelper { - private final Paint mHolographicPaint = new Paint(); + + private static final Rect sTempRect = new Rect(); + + private final Canvas mCanvas = new Canvas(); + private final Paint mDrawPaint = new Paint(); private final Paint mBlurPaint = new Paint(); private final Paint mErasePaint = new Paint(); - public int mMaxOuterBlurRadius; - public int mMinOuterBlurRadius; + private final BlurMaskFilter mMediumOuterBlurMaskFilter; + private final BlurMaskFilter mThinOuterBlurMaskFilter; + private final BlurMaskFilter mMediumInnerBlurMaskFilter; - private BlurMaskFilter mExtraThickOuterBlurMaskFilter; - private BlurMaskFilter mThickOuterBlurMaskFilter; - private BlurMaskFilter mMediumOuterBlurMaskFilter; - private BlurMaskFilter mThinOuterBlurMaskFilter; - private BlurMaskFilter mThickInnerBlurMaskFilter; - private BlurMaskFilter mExtraThickInnerBlurMaskFilter; - private BlurMaskFilter mMediumInnerBlurMaskFilter; + private final BlurMaskFilter mShaowBlurMaskFilter; + private final int mShadowOffset; - private static final int THICK = 0; - private static final int MEDIUM = 1; - private static final int EXTRA_THICK = 2; + /** + * Padding used when creating shadow bitmap; + */ + final int shadowBitmapPadding; static HolographicOutlineHelper INSTANCE; private HolographicOutlineHelper(Context context) { final float scale = LauncherAppState.getInstance().getScreenDensity(); - mMinOuterBlurRadius = (int) (scale * 1.0f); - mMaxOuterBlurRadius = (int) (scale * 12.0f); - - mExtraThickOuterBlurMaskFilter = new BlurMaskFilter(scale * 12.0f, BlurMaskFilter.Blur.OUTER); - mThickOuterBlurMaskFilter = new BlurMaskFilter(scale * 6.0f, BlurMaskFilter.Blur.OUTER); mMediumOuterBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.OUTER); mThinOuterBlurMaskFilter = new BlurMaskFilter(scale * 1.0f, BlurMaskFilter.Blur.OUTER); - mExtraThickInnerBlurMaskFilter = new BlurMaskFilter(scale * 6.0f, BlurMaskFilter.Blur.NORMAL); - mThickInnerBlurMaskFilter = new BlurMaskFilter(scale * 4.0f, BlurMaskFilter.Blur.NORMAL); mMediumInnerBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.NORMAL); - mHolographicPaint.setFilterBitmap(true); - mHolographicPaint.setAntiAlias(true); + mShaowBlurMaskFilter = new BlurMaskFilter(scale * 4.0f, BlurMaskFilter.Blur.NORMAL); + mShadowOffset = (int) (scale * 2.0f); + shadowBitmapPadding = (int) (scale * 4.0f); + + mDrawPaint.setFilterBitmap(true); + mDrawPaint.setAntiAlias(true); mBlurPaint.setFilterBitmap(true); mBlurPaint.setAntiAlias(true); mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); @@ -77,37 +78,15 @@ public class HolographicOutlineHelper { } /** - * Returns the interpolated holographic highlight alpha for the effect we want when scrolling - * pages. - */ - public static float highlightAlphaInterpolator(float r) { - float maxAlpha = 0.6f; - return (float) Math.pow(maxAlpha * (1.0f - r), 1.5f); - } - - /** - * Returns the interpolated view alpha for the effect we want when scrolling pages. - */ - public static float viewAlphaInterpolator(float r) { - final float pivot = 0.95f; - if (r < pivot) { - return (float) Math.pow(r / pivot, 1.5f); - } else { - return 1.0f; - } - } - - /** * Applies a more expensive and accurate outline to whatever is currently drawn in a specified * bitmap. */ void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color, - int outlineColor, int thickness) { - applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, true, - thickness); + int outlineColor) { + applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, true); } void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color, - int outlineColor, boolean clipAlpha, int thickness) { + int outlineColor, boolean clipAlpha) { // We start by removing most of the alpha channel so as to ignore shadows, and // other types of partial transparency when defining the shape of the object @@ -127,50 +106,18 @@ public class HolographicOutlineHelper { Bitmap glowShape = srcDst.extractAlpha(); // calculate the outer blur first - BlurMaskFilter outerBlurMaskFilter; - switch (thickness) { - case EXTRA_THICK: - outerBlurMaskFilter = mExtraThickOuterBlurMaskFilter; - break; - case THICK: - outerBlurMaskFilter = mThickOuterBlurMaskFilter; - break; - case MEDIUM: - outerBlurMaskFilter = mMediumOuterBlurMaskFilter; - break; - default: - throw new RuntimeException("Invalid blur thickness"); - } - mBlurPaint.setMaskFilter(outerBlurMaskFilter); + mBlurPaint.setMaskFilter(mMediumOuterBlurMaskFilter); int[] outerBlurOffset = new int[2]; Bitmap thickOuterBlur = glowShape.extractAlpha(mBlurPaint, outerBlurOffset); - if (thickness == EXTRA_THICK) { - mBlurPaint.setMaskFilter(mMediumOuterBlurMaskFilter); - } else { - mBlurPaint.setMaskFilter(mThinOuterBlurMaskFilter); - } + mBlurPaint.setMaskFilter(mThinOuterBlurMaskFilter); int[] brightOutlineOffset = new int[2]; Bitmap brightOutline = glowShape.extractAlpha(mBlurPaint, brightOutlineOffset); // calculate the inner blur srcDstCanvas.setBitmap(glowShape); srcDstCanvas.drawColor(0xFF000000, PorterDuff.Mode.SRC_OUT); - BlurMaskFilter innerBlurMaskFilter; - switch (thickness) { - case EXTRA_THICK: - innerBlurMaskFilter = mExtraThickInnerBlurMaskFilter; - break; - case THICK: - innerBlurMaskFilter = mThickInnerBlurMaskFilter; - break; - case MEDIUM: - innerBlurMaskFilter = mMediumInnerBlurMaskFilter; - break; - default: - throw new RuntimeException("Invalid blur thickness"); - } - mBlurPaint.setMaskFilter(innerBlurMaskFilter); + mBlurPaint.setMaskFilter(mMediumInnerBlurMaskFilter); int[] thickInnerBlurOffset = new int[2]; Bitmap thickInnerBlur = glowShape.extractAlpha(mBlurPaint, thickInnerBlurOffset); @@ -186,16 +133,16 @@ public class HolographicOutlineHelper { // draw the inner and outer blur srcDstCanvas.setBitmap(srcDst); srcDstCanvas.drawColor(0, PorterDuff.Mode.CLEAR); - mHolographicPaint.setColor(color); + mDrawPaint.setColor(color); srcDstCanvas.drawBitmap(thickInnerBlur, thickInnerBlurOffset[0], thickInnerBlurOffset[1], - mHolographicPaint); + mDrawPaint); srcDstCanvas.drawBitmap(thickOuterBlur, outerBlurOffset[0], outerBlurOffset[1], - mHolographicPaint); + mDrawPaint); // draw the bright outline - mHolographicPaint.setColor(outlineColor); + mDrawPaint.setColor(outlineColor); srcDstCanvas.drawBitmap(brightOutline, brightOutlineOffset[0], brightOutlineOffset[1], - mHolographicPaint); + mDrawPaint); // cleanup srcDstCanvas.setBitmap(null); @@ -205,25 +152,52 @@ public class HolographicOutlineHelper { glowShape.recycle(); } - void applyExtraThickExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color, - int outlineColor) { - applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, EXTRA_THICK); - } - - void applyThickExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color, - int outlineColor) { - applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, THICK); + Bitmap createMediumDropShadow(BubbleTextView view) { + final Bitmap result = Bitmap.createBitmap( + view.getWidth() + shadowBitmapPadding + shadowBitmapPadding, + view.getHeight() + shadowBitmapPadding + shadowBitmapPadding + mShadowOffset, + Bitmap.Config.ARGB_8888); + + mCanvas.setBitmap(result); + + final Rect clipRect = sTempRect; + view.getDrawingRect(sTempRect); + // adjust the clip rect so that we don't include the text label + clipRect.bottom = view.getExtendedPaddingTop() - (int) BubbleTextView.PADDING_V + + view.getLayout().getLineTop(0); + + // Draw the View into the bitmap. + // The translate of scrollX and scrollY is necessary when drawing TextViews, because + // they set scrollX and scrollY to large values to achieve centered text + mCanvas.save(); + mCanvas.scale(view.getScaleX(), view.getScaleY(), + view.getWidth() / 2 + shadowBitmapPadding, + view.getHeight() / 2 + shadowBitmapPadding); + mCanvas.translate(-view.getScrollX() + shadowBitmapPadding, + -view.getScrollY() + shadowBitmapPadding); + mCanvas.clipRect(clipRect, Op.REPLACE); + view.draw(mCanvas); + mCanvas.restore(); + + int[] blurOffst = new int[2]; + mBlurPaint.setMaskFilter(mShaowBlurMaskFilter); + Bitmap blurBitmap = result.extractAlpha(mBlurPaint, blurOffst); + + mCanvas.save(); + mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + mCanvas.translate(blurOffst[0], blurOffst[1]); + + mDrawPaint.setColor(Color.BLACK); + mDrawPaint.setAlpha(30); + mCanvas.drawBitmap(blurBitmap, 0, 0, mDrawPaint); + + mDrawPaint.setAlpha(60); + mCanvas.drawBitmap(blurBitmap, 0, mShadowOffset, mDrawPaint); + mCanvas.restore(); + + mCanvas.setBitmap(null); + blurBitmap.recycle(); + + return result; } - - void applyMediumExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color, - int outlineColor, boolean clipAlpha) { - applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, clipAlpha, - MEDIUM); - } - - void applyMediumExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color, - int outlineColor) { - applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, MEDIUM); - } - } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 88a60d08c..b8571008b 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -82,7 +82,6 @@ import android.view.Surface; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; -import android.view.ViewAnimationUtils; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.ViewTreeObserver.OnGlobalLayoutListener; @@ -1026,10 +1025,6 @@ public class Launcher extends Activity // Resets the previous workspace icon press state mWaitingForResume.setStayPressed(false); } - if (mAppsCustomizeContent != null) { - // Resets the previous all apps icon press state - mAppsCustomizeContent.resetDrawableState(); - } // It is possible that widgets can receive updates while launcher is not in the foreground. // Consequently, the widgets will be inflated in the orientation of the foreground activity @@ -2451,6 +2446,8 @@ public class Launcher extends Activity } } else if (v == mAllAppsButton) { onClickAllAppsButton(v); + } else if (tag instanceof AppInfo) { + startAppShortcutOrInfoActivity(v); } else if (tag instanceof LauncherAppWidgetInfo) { if (v instanceof PendingAppWidgetHostView) { onClickPendingWidget((PendingAppWidgetHostView) v); @@ -2458,6 +2455,10 @@ public class Launcher extends Activity } } + public void onClickPagedViewIcon(View v) { + startAppShortcutOrInfoActivity(v); + } + public boolean onTouch(View v, MotionEvent event) { return false; } @@ -2539,17 +2540,6 @@ public class Launcher extends Activity } /** - * Event handler for a paged view icon click. - * @param v The view that was clicked. - * @param appInfo The {link AppInfo} of the view. - */ - public void onClickPagedViewIcon(View v, AppInfo appInfo) { - if (LOGD) Log.d(TAG, "onClickPagedViewIcon"); - startActivitySafely(v, appInfo.intent, appInfo); - getStats().recordLaunch(appInfo.intent); - } - - /** * Event handler for an app shortcut click. * * @param v The view that was clicked. Must be a tagged with a {@link ShortcutInfo}. @@ -2586,7 +2576,7 @@ public class Launcher extends Activity builder.setPositiveButton(R.string.abandoned_search, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { - startAppShortcutActivity(v); + startAppShortcutOrInfoActivity(v); } } ); @@ -2603,24 +2593,29 @@ public class Launcher extends Activity } // Start activities - startAppShortcutActivity(v); + startAppShortcutOrInfoActivity(v); } - private void startAppShortcutActivity(View v) { + private void startAppShortcutOrInfoActivity(View v) { Object tag = v.getTag(); - if (!(tag instanceof ShortcutInfo)) { - throw new IllegalArgumentException("Input must be a Shortcut"); + final ShortcutInfo shortcut; + final Intent intent; + if (tag instanceof ShortcutInfo) { + shortcut = (ShortcutInfo) tag; + intent = shortcut.intent; + int[] pos = new int[2]; + v.getLocationOnScreen(pos); + intent.setSourceBounds(new Rect(pos[0], pos[1], + pos[0] + v.getWidth(), pos[1] + v.getHeight())); + + } else if (tag instanceof AppInfo) { + shortcut = null; + intent = ((AppInfo) tag).intent; + } else { + throw new IllegalArgumentException("Input must be a Shortcut or AppInfo"); } - final ShortcutInfo shortcut = (ShortcutInfo) tag; - final Intent intent = shortcut.intent; - - int[] pos = new int[2]; - v.getLocationOnScreen(pos); - intent.setSourceBounds(new Rect(pos[0], pos[1], - pos[0] + v.getWidth(), pos[1] + v.getHeight())); boolean success = startActivitySafely(v, intent, tag); - mStats.recordLaunch(intent, shortcut); if (success && v instanceof BubbleTextView) { diff --git a/src/com/android/launcher3/PagedViewIcon.java b/src/com/android/launcher3/PagedViewIcon.java deleted file mode 100644 index e819d5edf..000000000 --- a/src/com/android/launcher3/PagedViewIcon.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2010 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; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Region; -import android.graphics.drawable.Drawable; -import android.util.AttributeSet; -import android.util.TypedValue; -import android.widget.TextView; - -/** - * An icon on a PagedView, specifically for items in the launcher's paged view (with compound - * drawables on the top). - */ -public class PagedViewIcon extends TextView { - /** A simple callback interface to allow a PagedViewIcon to notify when it has been pressed */ - public static interface PressedCallback { - void iconPressed(PagedViewIcon icon); - } - - @SuppressWarnings("unused") - private static final String TAG = "PagedViewIcon"; - private static final float PRESS_ALPHA = 0.4f; - - private PagedViewIcon.PressedCallback mPressedCallback; - private boolean mLockDrawableState = false; - - private Bitmap mIcon; - - public PagedViewIcon(Context context) { - this(context, null); - } - - public PagedViewIcon(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public PagedViewIcon(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - public void onFinishInflate() { - super.onFinishInflate(); - - // Ensure we are using the right text size - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); - setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.allAppsIconTextSizePx); - } - - public void applyFromApplicationInfo(AppInfo info, boolean scaleUp, - PagedViewIcon.PressedCallback cb) { - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); - - mIcon = info.iconBitmap; - mPressedCallback = cb; - Drawable icon = Utilities.createIconDrawable(mIcon); - icon.setBounds(0, 0, grid.allAppsIconSizePx, grid.allAppsIconSizePx); - setCompoundDrawables(null, icon, null, null); - setCompoundDrawablePadding(grid.iconDrawablePaddingPx); - setText(info.title); - if (info.contentDescription != null) { - setContentDescription(info.contentDescription); - } - setTag(info); - } - - public void lockDrawableState() { - mLockDrawableState = true; - } - - public void resetDrawableState() { - mLockDrawableState = false; - post(new Runnable() { - @Override - public void run() { - refreshDrawableState(); - } - }); - } - - protected void drawableStateChanged() { - super.drawableStateChanged(); - - // We keep in the pressed state until resetDrawableState() is called to reset the press - // feedback - if (isPressed()) { - setAlpha(PRESS_ALPHA); - if (mPressedCallback != null) { - mPressedCallback.iconPressed(this); - } - } else if (!mLockDrawableState) { - setAlpha(1f); - } - } -} diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 3ec5ddc60..ace5e84ed 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -27,7 +27,6 @@ import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; import android.app.WallpaperManager; -import android.appwidget.AppWidgetHost; import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetProviderInfo; import android.content.ComponentName; @@ -47,9 +46,7 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.AsyncTask; import android.os.Handler; -import android.os.Handler.Callback; import android.os.IBinder; -import android.os.Message; import android.os.Parcelable; import android.support.v4.view.ViewCompat; import android.util.AttributeSet; @@ -76,9 +73,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; /** * The workspace is a wide area with a wallpaper and a finite number of pages. @@ -212,7 +207,7 @@ public class Workspace extends SmoothPagedView private HolographicOutlineHelper mOutlineHelper; private Bitmap mDragOutline = null; - private final Rect mTempRect = new Rect(); + private static final Rect sTempRect = new Rect(); private final int[] mTempXY = new int[2]; private int[] mTempVisiblePagesRange = new int[2]; private boolean mOverscrollEffectSet; @@ -241,6 +236,8 @@ public class Workspace extends SmoothPagedView private DropTarget.DragEnforcer mDragEnforcer; private float mMaxDistanceForFolderCreation; + private final Canvas mCanvas = new Canvas(); + // Variables relating to touch disambiguation (scrolling workspace vs. scrolling a widget) private float mXDown; private float mYDown; @@ -1994,14 +1991,7 @@ public class Workspace extends SmoothPagedView * appearance). * */ - public void onDragStartedWithItem(View v) { - final Canvas canvas = new Canvas(); - - // The outline is used to visualize where the item will land if dropped - mDragOutline = createDragOutline(v, canvas, DRAG_BITMAP_PADDING); - } - - private Rect getDrawableBounds(Drawable d) { + private static Rect getDrawableBounds(Drawable d) { Rect bounds = new Rect(); d.copyBounds(bounds); if (bounds.width() == 0 || bounds.height() == 0) { @@ -2017,8 +2007,6 @@ public class Workspace extends SmoothPagedView } public void onExternalDragStartedWithItem(View v) { - final Canvas canvas = new Canvas(); - // Compose a drag bitmap with the view scaled to the icon size LauncherAppState app = LauncherAppState.getInstance(); DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); @@ -2038,22 +2026,19 @@ public class Workspace extends SmoothPagedView // Compose the bitmap to create the icon from Bitmap b = Bitmap.createBitmap(bmpWidth, bmpHeight, Bitmap.Config.ARGB_8888); - Canvas c = new Canvas(b); - drawDragView(v, c, 0); - c.setBitmap(null); + mCanvas.setBitmap(b); + drawDragView(v, mCanvas, 0); + mCanvas.setBitmap(null); // The outline is used to visualize where the item will land if dropped - mDragOutline = createDragOutline(b, canvas, DRAG_BITMAP_PADDING, iconSize, iconSize, true); + mDragOutline = createDragOutline(b, DRAG_BITMAP_PADDING, iconSize, iconSize, true); } public void onDragStartedWithItem(PendingAddItemInfo info, Bitmap b, boolean clipAlpha) { - final Canvas canvas = new Canvas(); - int[] size = estimateItemSize(info.spanX, info.spanY, info, false); // The outline is used to visualize where the item will land if dropped - mDragOutline = createDragOutline(b, canvas, DRAG_BITMAP_PADDING, size[0], - size[1], clipAlpha); + mDragOutline = createDragOutline(b, DRAG_BITMAP_PADDING, size[0], size[1], clipAlpha); } public void exitWidgetResizeMode() { @@ -2551,8 +2536,8 @@ public class Workspace extends SmoothPagedView * @param destCanvas the canvas to draw on * @param padding the horizontal and vertical padding to use when drawing */ - private void drawDragView(View v, Canvas destCanvas, int padding) { - final Rect clipRect = mTempRect; + private static void drawDragView(View v, Canvas destCanvas, int padding) { + final Rect clipRect = sTempRect; v.getDrawingRect(clipRect); boolean textVisible = false; @@ -2591,7 +2576,7 @@ public class Workspace extends SmoothPagedView * @param expectedPadding padding to add to the drag view. If a different padding was used * its value will be changed */ - public Bitmap createDragBitmap(View v, Canvas canvas, AtomicInteger expectedPadding) { + public Bitmap createDragBitmap(View v, AtomicInteger expectedPadding) { Bitmap b; int padding = expectedPadding.get(); @@ -2606,9 +2591,9 @@ public class Workspace extends SmoothPagedView v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888); } - canvas.setBitmap(b); - drawDragView(v, canvas, padding); - canvas.setBitmap(null); + mCanvas.setBitmap(b); + drawDragView(v, mCanvas, padding); + mCanvas.setBitmap(null); return b; } @@ -2617,15 +2602,15 @@ public class Workspace extends SmoothPagedView * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location. * Responsibility for the bitmap is transferred to the caller. */ - private Bitmap createDragOutline(View v, Canvas canvas, int padding) { + private Bitmap createDragOutline(View v, int padding) { final int outlineColor = getResources().getColor(R.color.outline_color); final Bitmap b = Bitmap.createBitmap( v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888); - canvas.setBitmap(b); - drawDragView(v, canvas, padding); - mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor); - canvas.setBitmap(null); + mCanvas.setBitmap(b); + drawDragView(v, mCanvas, padding); + mOutlineHelper.applyExpensiveOutlineWithBlur(b, mCanvas, outlineColor, outlineColor); + mCanvas.setBitmap(null); return b; } @@ -2633,11 +2618,11 @@ public class Workspace extends SmoothPagedView * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location. * Responsibility for the bitmap is transferred to the caller. */ - private Bitmap createDragOutline(Bitmap orig, Canvas canvas, int padding, int w, int h, + private Bitmap createDragOutline(Bitmap orig, int padding, int w, int h, boolean clipAlpha) { final int outlineColor = getResources().getColor(R.color.outline_color); final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); - canvas.setBitmap(b); + mCanvas.setBitmap(b); Rect src = new Rect(0, 0, orig.getWidth(), orig.getHeight()); float scaleFactor = Math.min((w - padding) / (float) orig.getWidth(), @@ -2649,10 +2634,10 @@ public class Workspace extends SmoothPagedView // center the image dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2); - canvas.drawBitmap(orig, src, dst, null); - mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor, + mCanvas.drawBitmap(orig, src, dst, null); + mOutlineHelper.applyExpensiveOutlineWithBlur(b, mCanvas, outlineColor, outlineColor, clipAlpha); - canvas.setBitmap(null); + mCanvas.setBitmap(null); return b; } @@ -2670,21 +2655,20 @@ public class Workspace extends SmoothPagedView CellLayout layout = (CellLayout) child.getParent().getParent(); layout.prepareChildForDrag(child); + beginDragShared(child, this); + } + + public void beginDragShared(View child, DragSource source) { child.clearFocus(); child.setPressed(false); - final Canvas canvas = new Canvas(); - // The outline is used to visualize where the item will land if dropped - mDragOutline = createDragOutline(child, canvas, DRAG_BITMAP_PADDING); - beginDragShared(child, this); - } + mDragOutline = createDragOutline(child, DRAG_BITMAP_PADDING); - public void beginDragShared(View child, DragSource source) { mLauncher.onDragStarted(child); // The drag bitmap follows the touch point around on the screen AtomicInteger padding = new AtomicInteger(DRAG_BITMAP_PADDING); - final Bitmap b = createDragBitmap(child, new Canvas(), padding); + final Bitmap b = createDragBitmap(child, padding); final int bmpWidth = b.getWidth(); final int bmpHeight = b.getHeight(); @@ -2698,7 +2682,7 @@ public class Workspace extends SmoothPagedView DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); Point dragVisualizeOffset = null; Rect dragRect = null; - if (child instanceof BubbleTextView || child instanceof PagedViewIcon) { + if (child instanceof BubbleTextView) { int iconSize = grid.iconSizePx; int top = child.getPaddingTop(); int left = (bmpWidth - iconSize) / 2; @@ -2717,7 +2701,7 @@ public class Workspace extends SmoothPagedView // Clear the pressed state if necessary if (child instanceof BubbleTextView) { BubbleTextView icon = (BubbleTextView) child; - icon.clearPressedOrFocusedBackground(); + icon.clearPressedBackground(); } else if (child instanceof FolderIcon) { // The folder cling isn't flexible enough to be shown in non-default workspace positions // Also if they are dragging it a folder, we assume they don't need to see the cling. @@ -2752,14 +2736,14 @@ public class Workspace extends SmoothPagedView // Compose a new drag bitmap that is of the icon size AtomicInteger padding = new AtomicInteger(DRAG_BITMAP_PADDING); - final Bitmap tmpB = createDragBitmap(child, new Canvas(), padding); + final Bitmap tmpB = createDragBitmap(child, padding); Bitmap b = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888); Paint p = new Paint(); p.setFilterBitmap(true); - Canvas c = new Canvas(b); - c.drawBitmap(tmpB, new Rect(0, 0, tmpB.getWidth(), tmpB.getHeight()), + mCanvas.setBitmap(b); + mCanvas.drawBitmap(tmpB, new Rect(0, 0, tmpB.getWidth(), tmpB.getHeight()), new Rect(0, 0, iconSize, iconSize), p); - c.setBitmap(null); + mCanvas.setBitmap(null); // Find the child's location on the screen int bmpWidth = tmpB.getWidth(); @@ -4033,12 +4017,12 @@ public class Workspace extends SmoothPagedView int height = MeasureSpec.makeMeasureSpec(unScaledSize[1], MeasureSpec.EXACTLY); Bitmap b = Bitmap.createBitmap(unScaledSize[0], unScaledSize[1], Bitmap.Config.ARGB_8888); - Canvas c = new Canvas(b); + mCanvas.setBitmap(b); layout.measure(width, height); layout.layout(0, 0, unScaledSize[0], unScaledSize[1]); - layout.draw(c); - c.setBitmap(null); + layout.draw(mCanvas); + mCanvas.setBitmap(null); layout.setVisibility(visibility); return b; } |