diff options
author | Tony <twickham@google.com> | 2016-07-22 12:46:51 -0700 |
---|---|---|
committer | Tony <twickham@google.com> | 2016-07-26 17:10:05 -0700 |
commit | eec1f9a839e8c58a96f16f61e998891433e0eb6b (patch) | |
tree | 4ade448d4e5eeec4bb130d583acceffcb32f0945 /src | |
parent | e9381d60cc18bac394c1e59196cf764bb3a49527 (diff) | |
download | android_packages_apps_Trebuchet-eec1f9a839e8c58a96f16f61e998891433e0eb6b.tar.gz android_packages_apps_Trebuchet-eec1f9a839e8c58a96f16f61e998891433e0eb6b.tar.bz2 android_packages_apps_Trebuchet-eec1f9a839e8c58a96f16f61e998891433e0eb6b.zip |
Add arrow view to deep shortcuts container.
- We create a trangular path, which we use as the view's
outline (for the shadow) and as its PathShape background.
- We scale up the arrow as the container opens.
Bug: 28980830
Change-Id: I71e566552f063dfdb69067bb7e3cee659988f934
Diffstat (limited to 'src')
3 files changed, 135 insertions, 15 deletions
diff --git a/src/com/android/launcher3/graphics/TriangleShape.java b/src/com/android/launcher3/graphics/TriangleShape.java new file mode 100644 index 000000000..cce4e3cd9 --- /dev/null +++ b/src/com/android/launcher3/graphics/TriangleShape.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 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.graphics; + +import android.graphics.Outline; +import android.graphics.Path; +import android.graphics.drawable.shapes.PathShape; +import android.support.annotation.NonNull; + +/** + * Wrapper around {@link android.graphics.drawable.shapes.PathShape} + * that creates a shape with a triangular path (pointing up or down). + */ +public class TriangleShape extends PathShape { + private Path mTriangularPath; + + public TriangleShape(Path path, float stdWidth, float stdHeight) { + super(path, stdWidth, stdHeight); + mTriangularPath = path; + } + + public static TriangleShape create(float width, float height, boolean isPointingUp) { + Path triangularPath = new Path(); + if (isPointingUp) { + triangularPath.moveTo(0, height); + triangularPath.lineTo(width, height); + triangularPath.lineTo(width / 2, 0); + triangularPath.close(); + } else { + triangularPath.moveTo(0, 0); + triangularPath.lineTo(width / 2, height); + triangularPath.lineTo(width, 0); + triangularPath.close(); + } + return new TriangleShape(triangularPath, width, height); + } + + @Override + public void getOutline(@NonNull Outline outline) { + outline.setConvexPath(mTriangularPath); + } +} diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutView.java b/src/com/android/launcher3/shortcuts/DeepShortcutView.java index f6fcdde2e..7cb2d43d7 100644 --- a/src/com/android/launcher3/shortcuts/DeepShortcutView.java +++ b/src/com/android/launcher3/shortcuts/DeepShortcutView.java @@ -89,11 +89,8 @@ public class DeepShortcutView extends FrameLayout { /** * Creates an animator to play when the shortcut container is being opened. - * - * @param animationIndex The index at which this animation will be started - * relative to other DeepShortcutView open animations. */ - public Animator createOpenAnimation(int animationIndex, boolean isContainerAboveIcon) { + public Animator createOpenAnimation(long animationDelay, boolean isContainerAboveIcon) { final Resources res = getResources(); setVisibility(INVISIBLE); @@ -119,8 +116,7 @@ public class DeepShortcutView extends FrameLayout { .scaleX(1).scaleY(1); openAnimation.playTogether(reveal, translationY, scale); - openAnimation.setStartDelay(animationIndex * res.getInteger( - R.integer.config_deepShortcutOpenStagger)); + openAnimation.setStartDelay(animationDelay); openAnimation.setDuration(res.getInteger(R.integer.config_deepShortcutOpenDuration)); openAnimation.setInterpolator(new DecelerateInterpolator()); return openAnimation; diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java b/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java index 4cbbe97cf..c881c8c4b 100644 --- a/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java +++ b/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java @@ -16,19 +16,24 @@ package com.android.launcher3.shortcuts; +import android.animation.Animator; import android.animation.AnimatorSet; import android.annotation.TargetApi; import android.content.ComponentName; import android.content.Context; +import android.content.res.Resources; import android.graphics.Bitmap; +import android.graphics.Color; import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.graphics.drawable.ShapeDrawable; import android.os.Build; import android.os.Handler; import android.os.Looper; import android.text.TextUtils; import android.util.AttributeSet; +import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.LayoutInflater; import android.view.MotionEvent; @@ -44,6 +49,7 @@ import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAnimUtils; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherModel; +import com.android.launcher3.LauncherViewPropertyAnimator; import com.android.launcher3.R; import com.android.launcher3.ShortcutInfo; import com.android.launcher3.Utilities; @@ -54,6 +60,7 @@ import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.dragndrop.DragView; import com.android.launcher3.graphics.ScaledPreviewProvider; +import com.android.launcher3.graphics.TriangleShape; import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto.Target; @@ -88,6 +95,7 @@ public class DeepShortcutsContainer extends LinearLayout implements View.OnLongC private Point mIconLastTouchPos = new Point(); private boolean mIsLeftAligned; private boolean mIsAboveIcon; + private View mArrow; private boolean mSrcIconDragStarted; @@ -210,27 +218,56 @@ public class DeepShortcutsContainer extends LinearLayout implements View.OnLongC } private DeepShortcutView getShortcutAt(int index) { + if (!mIsAboveIcon) { + // Opening down, so arrow is the first view. + index++; + } return (DeepShortcutView) getChildAt(index); } + private int getShortcutCount() { + // All children except the arrow are shortcuts. + return getChildCount() - 1; + } + private void animateOpen(BubbleTextView originalIcon) { orientAboutIcon(originalIcon); + final Resources resources = getResources(); + final int arrowWidth = resources.getDimensionPixelSize(R.dimen.deep_shortcuts_arrow_width); + final int arrowHeight = resources.getDimensionPixelSize(R.dimen.deep_shortcuts_arrow_height); + int iconWidth = originalIcon.getWidth() - originalIcon.getTotalPaddingLeft() + - originalIcon.getTotalPaddingRight(); + iconWidth *= originalIcon.getScaleX(); + final int arrowHorizontalOffset = iconWidth / 2 - arrowWidth / 2; + final int arrowVerticalOffset = resources.getDimensionPixelSize( + R.dimen.deep_shortcuts_arrow_vertical_offset); + mArrow = addArrowView(arrowHorizontalOffset, arrowVerticalOffset, arrowWidth, arrowHeight); setVisibility(View.VISIBLE); final AnimatorSet shortcutAnims = LauncherAnimUtils.createAnimatorSet(); - final int numShortcuts = getChildCount(); - final int arrowOffset = getResources().getDimensionPixelSize( - R.dimen.deep_shortcuts_arrow_horizontal_offset); - final int pivotX = mIsLeftAligned ? arrowOffset : getMeasuredWidth() - arrowOffset; + final int shortcutCount = getShortcutCount(); + final int pivotX = mIsLeftAligned ? arrowHorizontalOffset + : getMeasuredWidth() - arrowHorizontalOffset; final int pivotY = getShortcutAt(0).getMeasuredHeight() / 2; - for (int i = 0; i < numShortcuts; i++) { + for (int i = 0; i < shortcutCount; i++) { DeepShortcutView deepShortcutView = getShortcutAt(i); deepShortcutView.setPivotX(pivotX); deepShortcutView.setPivotY(pivotY); - int animationIndex = mIsAboveIcon ? numShortcuts - i - 1 : i; - shortcutAnims.play(deepShortcutView.createOpenAnimation(animationIndex, mIsAboveIcon)); + int animationIndex = mIsAboveIcon ? shortcutCount - i - 1 : i; + long animationDelay = animationIndex * getResources().getInteger( + R.integer.config_deepShortcutOpenStagger); + shortcutAnims.play(deepShortcutView.createOpenAnimation(animationDelay, mIsAboveIcon)); } + mArrow.setScaleX(0); + mArrow.setScaleY(0); + final long shortcutAnimDuration = shortcutAnims.getChildAnimations().get(0).getDuration(); + final long arrowScaleDelay = shortcutAnimDuration / 6; + final long arrowScaleDuration = shortcutAnimDuration - arrowScaleDelay; + Animator arrowScale = new LauncherViewPropertyAnimator(mArrow).scaleX(1).scaleY(1); + arrowScale.setStartDelay(arrowScaleDelay); + arrowScale.setDuration(arrowScaleDuration); + shortcutAnims.play(arrowScale); shortcutAnims.start(); } @@ -245,8 +282,6 @@ public class DeepShortcutsContainer extends LinearLayout implements View.OnLongC * * So we always align left if there is enough horizontal space * and align above if there is enough vertical space. - * - * TODO: draw arrow based on orientation. */ private void orientAboutIcon(BubbleTextView icon) { int width = getMeasuredWidth(); @@ -285,6 +320,36 @@ public class DeepShortcutsContainer extends LinearLayout implements View.OnLongC setY(y); } + /** + * Adds an arrow view pointing at the original icon. + * @param horizontalOffset the horizontal offset of the arrow, so that it + * points at the center of the original icon + */ + private View addArrowView(int horizontalOffset, int verticalOffset, int width, int height) { + LinearLayout.LayoutParams layoutParams = new LayoutParams(width, height); + if (mIsLeftAligned) { + layoutParams.gravity = Gravity.LEFT; + layoutParams.leftMargin = horizontalOffset; + } else { + layoutParams.gravity = Gravity.RIGHT; + layoutParams.rightMargin = horizontalOffset; + } + if (mIsAboveIcon) { + layoutParams.topMargin = verticalOffset; + } else { + layoutParams.bottomMargin = verticalOffset; + } + + View arrowView = new View(getContext()); + ShapeDrawable arrowDrawable = new ShapeDrawable(TriangleShape.create( + width, height, !mIsAboveIcon)); + arrowDrawable.getPaint().setColor(Color.WHITE); + arrowView.setBackground(arrowDrawable); + arrowView.setElevation(getElevation()); + addView(arrowView, mIsAboveIcon ? getChildCount() : 0, layoutParams); + return arrowView; + } + private void deferDrag(BubbleTextView originalIcon) { mDeferredDragIcon = originalIcon; showDragView(originalIcon); @@ -339,6 +404,7 @@ public class DeepShortcutsContainer extends LinearLayout implements View.OnLongC Utilities.translateEventCoordinates(this, mLauncher.getDragLayer(), ev); final int dragLayerX = (int) ev.getX(); final int dragLayerY = (int) ev.getY(); + int shortcutCount = getShortcutCount(); if (action == MotionEvent.ACTION_MOVE) { if (mLastX != 0 || mLastY != 0) { mDistanceDragged += Math.hypot(mLastX - x, mLastY - y); @@ -347,6 +413,8 @@ public class DeepShortcutsContainer extends LinearLayout implements View.OnLongC mLastY = y; if (shouldStartDeferredDrag((int) x, (int) y)) { + DeepShortcutView topShortcut = getShortcutAt(0); + DeepShortcutView bottomShortcut = getShortcutAt(shortcutCount - 1); mSrcIconDragStarted = true; cleanupDeferredDrag(true); mDeferredDragIcon.getParent().requestDisallowInterceptTouchEvent(false); |