diff options
Diffstat (limited to 'src/com/android/launcher3')
10 files changed, 310 insertions, 229 deletions
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java index 52a83dcdf..bd1268651 100644 --- a/src/com/android/launcher3/AbstractFloatingView.java +++ b/src/com/android/launcher3/AbstractFloatingView.java @@ -95,7 +95,7 @@ public abstract class AbstractFloatingView extends LinearLayout { return null; } - protected static void closeOpenContainer(Launcher launcher, @FloatingViewType int type) { + public static void closeOpenContainer(Launcher launcher, @FloatingViewType int type) { AbstractFloatingView view = getOpenView(launcher, type); if (view != null) { view.close(true); diff --git a/src/com/android/launcher3/badge/BadgeRenderer.java b/src/com/android/launcher3/badge/BadgeRenderer.java index 864a65d8a..1f3e22de2 100644 --- a/src/com/android/launcher3/badge/BadgeRenderer.java +++ b/src/com/android/launcher3/badge/BadgeRenderer.java @@ -22,7 +22,6 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; -import android.graphics.RectF; import android.graphics.Shader; import android.support.annotation.Nullable; diff --git a/src/com/android/launcher3/notification/NotificationItemView.java b/src/com/android/launcher3/notification/NotificationItemView.java index 742c90a5a..efd9a3b06 100644 --- a/src/com/android/launcher3/notification/NotificationItemView.java +++ b/src/com/android/launcher3/notification/NotificationItemView.java @@ -20,14 +20,7 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.content.Context; import android.content.res.ColorStateList; -import android.graphics.Bitmap; -import android.graphics.BitmapShader; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffXfermode; import android.graphics.Rect; -import android.graphics.Shader; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; @@ -36,11 +29,11 @@ import android.widget.FrameLayout; import com.android.launcher3.ItemInfo; import com.android.launcher3.R; +import com.android.launcher3.anim.PillHeightRevealOutlineProvider; import com.android.launcher3.graphics.IconPalette; import com.android.launcher3.logging.UserEventDispatcher.LogContainerProvider; import com.android.launcher3.popup.PopupItemView; import com.android.launcher3.userevent.nano.LauncherLogProto; -import com.android.launcher3.anim.PillHeightRevealOutlineProvider; import java.util.List; @@ -54,9 +47,6 @@ public class NotificationItemView extends PopupItemView implements LogContainerP private static final Rect sTempRect = new Rect(); - private final Paint mBackgroundClipPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG | - Paint.FILTER_BITMAP_FLAG); - private View mDivider; private NotificationMainView mMainView; private NotificationFooterLayout mFooter; @@ -85,35 +75,6 @@ public class NotificationItemView extends PopupItemView implements LogContainerP mSwipeHelper.setDisableHardwareLayers(true); } - private void initializeBackgroundClipping(boolean force) { - if (force || mBackgroundClipPaint.getShader() == null) { - mBackgroundClipPaint.setXfermode(null); - mBackgroundClipPaint.setShader(null); - Bitmap backgroundBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), - Bitmap.Config.ALPHA_8); - Canvas canvas = new Canvas(); - canvas.setBitmap(backgroundBitmap); - float roundRectRadius = getResources().getDimensionPixelSize( - R.dimen.bg_round_rect_radius); - canvas.drawRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), - roundRectRadius, roundRectRadius, mBackgroundClipPaint); - Shader backgroundClipShader = new BitmapShader(backgroundBitmap, - Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); - mBackgroundClipPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); - mBackgroundClipPaint.setShader(backgroundClipShader); - } - } - - @Override - protected void dispatchDraw(Canvas canvas) { - initializeBackgroundClipping(false /* force */); - int saveCount = canvas.saveLayer(0, 0, getWidth(), getHeight(), null, - Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG); - super.dispatchDraw(canvas); - canvas.drawPaint(mBackgroundClipPaint); - canvas.restoreToCount(saveCount); - } - public Animator animateHeightRemoval(int heightToRemove) { final int newHeight = getHeight() - heightToRemove; Animator heightAnimator = new PillHeightRevealOutlineProvider(mPillRect, @@ -135,11 +96,6 @@ public class NotificationItemView extends PopupItemView implements LogContainerP } @Override - protected float getBackgroundRadius() { - return getResources().getDimensionPixelSize(R.dimen.bg_round_rect_radius); - } - - @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (mMainView.getNotificationInfo() == null) { // The notification hasn't been populated yet. diff --git a/src/com/android/launcher3/notification/NotificationMainView.java b/src/com/android/launcher3/notification/NotificationMainView.java index b3425259b..824dbf279 100644 --- a/src/com/android/launcher3/notification/NotificationMainView.java +++ b/src/com/android/launcher3/notification/NotificationMainView.java @@ -22,7 +22,9 @@ import android.animation.ArgbEvaluator; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.content.Context; +import android.content.res.ColorStateList; import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.RippleDrawable; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; @@ -71,7 +73,9 @@ public class NotificationMainView extends LinearLayout implements SwipeHelper.Ca public void applyColors(IconPalette iconPalette) { mColorBackground = new ColorDrawable(iconPalette.backgroundColor); - setBackground(mColorBackground); + RippleDrawable rippleDrawable = new RippleDrawable(ColorStateList.valueOf( + iconPalette.secondaryColor), mColorBackground, null); + setBackground(rippleDrawable); mIconPalette = iconPalette; } diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java index 7811b960e..15dde4330 100644 --- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java +++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java @@ -27,7 +27,6 @@ import android.annotation.TargetApi; import android.content.Context; import android.content.res.Resources; import android.graphics.Color; -import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.drawable.ShapeDrawable; @@ -64,15 +63,13 @@ import com.android.launcher3.badge.BadgeInfo; import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.dragndrop.DragOptions; -import com.android.launcher3.dragndrop.DragView; import com.android.launcher3.graphics.IconPalette; import com.android.launcher3.graphics.TriangleShape; import com.android.launcher3.notification.NotificationItemView; import com.android.launcher3.shortcuts.DeepShortcutView; -import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider; +import com.android.launcher3.shortcuts.ShortcutsItemView; import com.android.launcher3.util.PackageUserKey; -import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -84,18 +81,17 @@ import static com.android.launcher3.userevent.nano.LauncherLogProto.Target; * A container for shortcuts to deep links within apps. */ @TargetApi(Build.VERSION_CODES.N) -public class PopupContainerWithArrow extends AbstractFloatingView - implements View.OnLongClickListener, View.OnTouchListener, DragSource, +public class PopupContainerWithArrow extends AbstractFloatingView implements DragSource, DragController.DragListener { - private final Point mIconShift = new Point(); - private final Point mIconLastTouchPos = new Point(); - protected final Launcher mLauncher; private final int mStartDragThreshold; private LauncherAccessibilityDelegate mAccessibilityDelegate; private final boolean mIsRtl; + public ShortcutsItemView mShortcutsItemView; + private NotificationItemView mNotificationItemView; + protected BubbleTextView mOriginalIcon; private final Rect mTempRect = new Rect(); private PointF mInterceptTouchDown = new PointF(); @@ -177,6 +173,8 @@ public class PopupContainerWithArrow extends AbstractFloatingView boolean reverseOrder = mIsAboveIcon; if (reverseOrder) { removeAllViews(); + mNotificationItemView = null; + mShortcutsItemView = null; itemsToPopulate = PopupPopulator.reverseItems(itemsToPopulate); addDummyViews(originalIcon, itemsToPopulate, notificationKeys.length > 1); @@ -184,22 +182,12 @@ public class PopupContainerWithArrow extends AbstractFloatingView orientAboutIcon(originalIcon, arrowHeight + arrowVerticalOffset); } - List<DeepShortcutView> shortcutViews = new ArrayList<>(); - NotificationItemView notificationView = null; - for (int i = 0; i < getChildCount(); i++) { - View item = getChildAt(i); + List<DeepShortcutView> shortcutViews = mShortcutsItemView.getDeepShortcutViews(reverseOrder); + for (int i = 0; i < itemsToPopulate.length; i++) { switch (itemsToPopulate[i]) { - case SHORTCUT: - if (reverseOrder) { - shortcutViews.add(0, (DeepShortcutView) item); - } else { - shortcutViews.add((DeepShortcutView) item); - } - break; case NOTIFICATION: - notificationView = (NotificationItemView) item; IconPalette iconPalette = originalIcon.getIconPalette(); - notificationView.applyColors(iconPalette); + mNotificationItemView.applyColors(iconPalette); break; } } @@ -221,28 +209,46 @@ public class PopupContainerWithArrow extends AbstractFloatingView final Looper workerLooper = LauncherModel.getWorkerLooper(); new Handler(workerLooper).postAtFrontOfQueue(PopupPopulator.createUpdateRunnable( mLauncher, (ItemInfo) originalIcon.getTag(), new Handler(Looper.getMainLooper()), - this, shortcutIds, shortcutViews, notificationKeys, notificationView)); + this, shortcutIds, shortcutViews, notificationKeys, mNotificationItemView)); } private void addDummyViews(BubbleTextView originalIcon, - PopupPopulator.Item[] itemsToPopulate, boolean notificationFooterHasIcons) { + PopupPopulator.Item[] itemTypesToPopulate, boolean notificationFooterHasIcons) { final Resources res = getResources(); - final int spacing = res.getDimensionPixelSize(R.dimen.deep_shortcuts_spacing); + final int spacing = res.getDimensionPixelSize(R.dimen.popup_items_spacing); final LayoutInflater inflater = mLauncher.getLayoutInflater(); - int numItems = itemsToPopulate.length; + int numItems = itemTypesToPopulate.length; for (int i = 0; i < numItems; i++) { - final PopupItemView item = (PopupItemView) inflater.inflate( - itemsToPopulate[i].layoutId, this, false); - if (itemsToPopulate[i] == PopupPopulator.Item.NOTIFICATION) { + PopupPopulator.Item itemTypeToPopulate = itemTypesToPopulate[i]; + final View item = inflater.inflate(itemTypeToPopulate.layoutId, this, false); + + if (itemTypeToPopulate == PopupPopulator.Item.NOTIFICATION) { + mNotificationItemView = (NotificationItemView) item; int footerHeight = notificationFooterHasIcons ? res.getDimensionPixelSize(R.dimen.notification_footer_height) : 0; item.findViewById(R.id.footer).getLayoutParams().height = footerHeight; } - if (i < numItems - 1) { - ((LayoutParams) item.getLayoutParams()).bottomMargin = spacing; - } + + boolean itemIsFollowedByDifferentType = i < numItems - 1 + && itemTypesToPopulate[i + 1] != itemTypeToPopulate; + item.setAccessibilityDelegate(mAccessibilityDelegate); - addView(item); + if (itemTypeToPopulate == PopupPopulator.Item.SHORTCUT) { + if (mShortcutsItemView == null) { + mShortcutsItemView = (ShortcutsItemView) inflater.inflate( + R.layout.shortcuts_item, this, false); + addView(mShortcutsItemView); + } + mShortcutsItemView.addDeepShortcutView((DeepShortcutView) item); + if (itemIsFollowedByDifferentType) { + ((LayoutParams) mShortcutsItemView.getLayoutParams()).bottomMargin = spacing; + } + } else { + addView(item); + if (itemIsFollowedByDifferentType) { + ((LayoutParams) item.getLayoutParams()).bottomMargin = spacing; + } + } } // TODO: update this, since not all items are shortcuts setContentDescription(getContext().getString(R.string.shortcuts_menu_description, @@ -534,49 +540,8 @@ public class PopupContainerWithArrow extends AbstractFloatingView return true; } - @Override - public boolean onTouch(View v, MotionEvent ev) { - // Touched a shortcut, update where it was touched so we can drag from there on long click. - switch (ev.getAction()) { - case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_MOVE: - mIconLastTouchPos.set((int) ev.getX(), (int) ev.getY()); - break; - } - return false; - } - - public boolean onLongClick(View v) { - // Return early if this is not initiated from a touch or not the correct view - if (!v.isInTouchMode() || !(v.getParent() instanceof DeepShortcutView)) return false; - // Return early if global dragging is not enabled - if (!mLauncher.isDraggingEnabled()) return false; - // Return early if an item is already being dragged (e.g. when long-pressing two shortcuts) - if (mLauncher.getDragController().isDragging()) return false; - - // Long clicked on a shortcut. - mDeferContainerRemoval = true; - DeepShortcutView sv = (DeepShortcutView) v.getParent(); - sv.setWillDrawIcon(false); - - // Move the icon to align with the center-top of the touch point - mIconShift.x = mIconLastTouchPos.x - sv.getIconCenter().x; - mIconShift.y = mIconLastTouchPos.y - mLauncher.getDeviceProfile().iconSizePx; - - DragView dv = mLauncher.getWorkspace().beginDragShared( - sv.getBubbleText(), this, sv.getFinalInfo(), - new ShortcutDragPreviewProvider(sv.getIconView(), mIconShift), new DragOptions()); - dv.animateShift(-mIconShift.x, -mIconShift.y); - - // TODO: support dragging from within folder without having to close it - AbstractFloatingView.closeOpenContainer(mLauncher, AbstractFloatingView.TYPE_FOLDER); - return false; - } - public void trimNotifications(Map<PackageUserKey, BadgeInfo> updatedBadges) { - final NotificationItemView notificationView = - (NotificationItemView) findViewById(R.id.notification_view); - if (notificationView == null) { + if (mNotificationItemView == null) { return; } ItemInfo originalInfo = (ItemInfo) mOriginalIcon.getTag(); @@ -585,11 +550,11 @@ public class PopupContainerWithArrow extends AbstractFloatingView AnimatorSet removeNotification = LauncherAnimUtils.createAnimatorSet(); final int duration = getResources().getInteger( R.integer.config_removeNotificationViewDuration); - final int spacing = getResources().getDimensionPixelSize(R.dimen.deep_shortcuts_spacing); + final int spacing = getResources().getDimensionPixelSize(R.dimen.popup_items_spacing); removeNotification.play(reduceNotificationViewHeight( - notificationView.getHeight() + spacing, duration, notificationView)); + mNotificationItemView.getHeight() + spacing, duration, mNotificationItemView)); final View removeMarginView = mIsAboveIcon ? getItemViewAt(getItemCount() - 2) - : notificationView; + : mNotificationItemView; if (removeMarginView != null) { ValueAnimator removeMargin = ValueAnimator.ofFloat(1, 0).setDuration(duration); removeMargin.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @@ -601,12 +566,12 @@ public class PopupContainerWithArrow extends AbstractFloatingView }); removeNotification.play(removeMargin); } - Animator fade = ObjectAnimator.ofFloat(notificationView, ALPHA, 0) + Animator fade = ObjectAnimator.ofFloat(mNotificationItemView, ALPHA, 0) .setDuration(duration); fade.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - removeView(notificationView); + removeView(mNotificationItemView); if (getItemCount() == 0) { close(false); return; @@ -626,7 +591,7 @@ public class PopupContainerWithArrow extends AbstractFloatingView removeNotification.start(); return; } - notificationView.trimNotifications(badgeInfo.getNotificationKeys()); + mNotificationItemView.trimNotifications(badgeInfo.getNotificationKeys()); } private ObjectAnimator createArrowScaleAnim(float scale) { @@ -669,8 +634,7 @@ public class PopupContainerWithArrow extends AbstractFloatingView } public Animator reduceNotificationViewHeight(int heightToRemove, int duration) { - return reduceNotificationViewHeight(heightToRemove, duration, - (NotificationItemView) findViewById(R.id.notification_view)); + return reduceNotificationViewHeight(heightToRemove, duration, mNotificationItemView); } @Override @@ -702,6 +666,7 @@ public class PopupContainerWithArrow extends AbstractFloatingView public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) { // Either the original icon or one of the shortcuts was dragged. // Hide the container, but don't remove it yet because that interferes with touch events. + mDeferContainerRemoval = true; animateClose(); } @@ -723,7 +688,6 @@ public class PopupContainerWithArrow extends AbstractFloatingView @Override public void fillInLogContainerData(View v, ItemInfo info, Target target, Target targetParent) { target.itemType = ItemType.DEEPSHORTCUT; - target.rank = info.rank; targetParent.containerType = ContainerType.DEEPSHORTCUTS; } @@ -765,38 +729,17 @@ public class PopupContainerWithArrow extends AbstractFloatingView for (int i = firstOpenItemIndex; i < firstOpenItemIndex + numOpenShortcuts; i++) { final PopupItemView view = getItemViewAt(i); Animator anim; - if (view.willDrawIcon()) { - anim = view.createCloseAnimation(mIsAboveIcon, mIsLeftAligned, duration); - int animationIndex = mIsAboveIcon ? i - firstOpenItemIndex - : numOpenShortcuts - i - 1; - anim.setStartDelay(stagger * animationIndex); - - Animator fadeAnim = ObjectAnimator.ofFloat(view, View.ALPHA, 0); - // Don't start fading until the arrow is gone. - fadeAnim.setStartDelay(stagger * animationIndex + arrowScaleDuration); - fadeAnim.setDuration(duration - arrowScaleDuration); - fadeAnim.setInterpolator(fadeInterpolator); - shortcutAnims.play(fadeAnim); - } else { - // The view is being dragged. Animate it such that it collapses with the drag view - anim = view.collapseToIcon(); - anim.setDuration(DragView.VIEW_ZOOM_DURATION); - - // Scale and translate the view to follow the drag view. - Point iconCenter = view.getIconCenter(); - view.setPivotX(iconCenter.x); - view.setPivotY(iconCenter.y); - - float scale = ((float) mLauncher.getDeviceProfile().iconSizePx) / view.getHeight(); - Animator anim2 = LauncherAnimUtils.ofPropertyValuesHolder(view, - new PropertyListBuilder() - .scale(scale) - .translationX(mIconShift.x) - .translationY(mIconShift.y) - .build()) - .setDuration(DragView.VIEW_ZOOM_DURATION); - shortcutAnims.play(anim2); - } + anim = view.createCloseAnimation(mIsAboveIcon, mIsLeftAligned, duration); + int animationIndex = mIsAboveIcon ? i - firstOpenItemIndex + : numOpenShortcuts - i - 1; + anim.setStartDelay(stagger * animationIndex); + + Animator fadeAnim = ObjectAnimator.ofFloat(view, View.ALPHA, 0); + // Don't start fading until the arrow is gone. + fadeAnim.setStartDelay(stagger * animationIndex + arrowScaleDuration); + fadeAnim.setDuration(duration - arrowScaleDuration); + fadeAnim.setInterpolator(fadeInterpolator); + shortcutAnims.play(fadeAnim); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { diff --git a/src/com/android/launcher3/popup/PopupItemView.java b/src/com/android/launcher3/popup/PopupItemView.java index b3d7155aa..dc4f415d5 100644 --- a/src/com/android/launcher3/popup/PopupItemView.java +++ b/src/com/android/launcher3/popup/PopupItemView.java @@ -21,8 +21,15 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.content.Context; import android.content.res.ColorStateList; +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Paint; import android.graphics.Point; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; import android.graphics.Rect; +import android.graphics.Shader; import android.util.AttributeSet; import android.view.View; import android.widget.FrameLayout; @@ -31,7 +38,6 @@ import com.android.launcher3.LogAccelerateInterpolator; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.util.PillRevealOutlineProvider; -import com.android.launcher3.util.PillWidthRevealOutlineProvider; /** * An abstract {@link FrameLayout} that supports animating an item's content @@ -47,6 +53,9 @@ public abstract class PopupItemView extends FrameLayout protected View mIconView; + private final Paint mBackgroundClipPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG | + Paint.FILTER_BITMAP_FLAG); + public PopupItemView(Context context) { this(context, null, 0); } @@ -73,12 +82,35 @@ public abstract class PopupItemView extends FrameLayout mPillRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); } - protected ColorStateList getAttachedArrowColor() { - return getBackgroundTintList(); + protected void initializeBackgroundClipping(boolean force) { + if (force || mBackgroundClipPaint.getShader() == null) { + mBackgroundClipPaint.setXfermode(null); + mBackgroundClipPaint.setShader(null); + Bitmap backgroundBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), + Bitmap.Config.ALPHA_8); + Canvas canvas = new Canvas(); + canvas.setBitmap(backgroundBitmap); + canvas.drawRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), + getBackgroundRadius(), getBackgroundRadius(), mBackgroundClipPaint); + Shader backgroundClipShader = new BitmapShader(backgroundBitmap, + Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + mBackgroundClipPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); + mBackgroundClipPaint.setShader(backgroundClipShader); + } } - public boolean willDrawIcon() { - return true; + @Override + protected void dispatchDraw(Canvas canvas) { + initializeBackgroundClipping(false /* force */); + int saveCount = canvas.saveLayer(0, 0, getWidth(), getHeight(), null, + Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG); + super.dispatchDraw(canvas); + canvas.drawPaint(mBackgroundClipPaint); + canvas.restoreToCount(saveCount); + } + + protected ColorStateList getAttachedArrowColor() { + return getBackgroundTintList(); } /** @@ -126,17 +158,6 @@ public abstract class PopupItemView extends FrameLayout } /** - * Creates an animator which clips the container to form a circle around the icon. - */ - public Animator collapseToIcon() { - int halfHeight = getMeasuredHeight() / 2; - int iconCenterX = getIconCenter().x; - return new PillWidthRevealOutlineProvider(mPillRect, - iconCenterX - halfHeight, iconCenterX + halfHeight) - .createRevealAnimator(this, true); - } - - /** * Returns the position of the center of the icon relative to the container. */ public Point getIconCenter() { @@ -148,7 +169,7 @@ public abstract class PopupItemView extends FrameLayout } protected float getBackgroundRadius() { - return getResources().getDimensionPixelSize(R.dimen.bg_pill_radius); + return getResources().getDimensionPixelSize(R.dimen.bg_round_rect_radius); } /** @@ -182,8 +203,10 @@ public abstract class PopupItemView extends FrameLayout public void setProgress(float progress) { super.setProgress(progress); - mZoomView.setScaleX(progress); - mZoomView.setScaleY(progress); + if (mZoomView != null) { + mZoomView.setScaleX(progress); + mZoomView.setScaleY(progress); + } float height = mOutline.height(); mTranslateView.setTranslationY(mTranslateYMultiplier * (mFullHeight - height)); diff --git a/src/com/android/launcher3/popup/PopupPopulator.java b/src/com/android/launcher3/popup/PopupPopulator.java index d2814ee7b..39c2db2d5 100644 --- a/src/com/android/launcher3/popup/PopupPopulator.java +++ b/src/com/android/launcher3/popup/PopupPopulator.java @@ -196,7 +196,8 @@ public class PopupPopulator { @Override public void run() { - mShortcutChild.applyShortcutInfo(mShortcutChildInfo, mDetail, mContainer); + mShortcutChild.applyShortcutInfo(mShortcutChildInfo, mDetail, + mContainer.mShortcutsItemView); } } diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutView.java b/src/com/android/launcher3/shortcuts/DeepShortcutView.java index 2f07c9ac9..47a023e25 100644 --- a/src/com/android/launcher3/shortcuts/DeepShortcutView.java +++ b/src/com/android/launcher3/shortcuts/DeepShortcutView.java @@ -17,26 +17,30 @@ package com.android.launcher3.shortcuts; import android.content.Context; +import android.graphics.Point; import android.graphics.Rect; import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; +import android.widget.FrameLayout; import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.ShortcutInfo; -import com.android.launcher3.popup.PopupContainerWithArrow; -import com.android.launcher3.popup.PopupItemView; +import com.android.launcher3.Utilities; /** * A {@link android.widget.FrameLayout} that contains a {@link DeepShortcutView}. * This lets us animate the DeepShortcutView (icon and text) separately from the background. */ -public class DeepShortcutView extends PopupItemView { +public class DeepShortcutView extends FrameLayout { + + private static final Point sTempPoint = new Point(); private final Rect mPillRect; private DeepShortcutTextView mBubbleText; + private View mIconView; private ShortcutInfo mInfo; private ShortcutInfoCompat mDetail; @@ -59,6 +63,7 @@ public class DeepShortcutView extends PopupItemView { protected void onFinishInflate() { super.onFinishInflate(); mBubbleText = (DeepShortcutTextView) findViewById(R.id.deep_shortcut); + mIconView = findViewById(R.id.icon); } public DeepShortcutTextView getBubbleText() { @@ -73,6 +78,17 @@ public class DeepShortcutView extends PopupItemView { return mIconView.getVisibility() == View.VISIBLE; } + /** + * Returns the position of the center of the icon relative to the container. + */ + public Point getIconCenter() { + sTempPoint.y = sTempPoint.x = getMeasuredHeight() / 2; + if (Utilities.isRtl(getResources())) { + sTempPoint.x = getMeasuredWidth() - sTempPoint.x; + } + return sTempPoint; + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); @@ -81,7 +97,7 @@ public class DeepShortcutView extends PopupItemView { /** package private **/ public void applyShortcutInfo(ShortcutInfo info, ShortcutInfoCompat detail, - PopupContainerWithArrow container) { + ShortcutsItemView container) { mInfo = info; mDetail = detail; mBubbleText.applyFromShortcutInfo(info); diff --git a/src/com/android/launcher3/shortcuts/ShortcutsItemView.java b/src/com/android/launcher3/shortcuts/ShortcutsItemView.java new file mode 100644 index 000000000..349c4c946 --- /dev/null +++ b/src/com/android/launcher3/shortcuts/ShortcutsItemView.java @@ -0,0 +1,180 @@ +/* + * 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.shortcuts; + +import android.animation.Animator; +import android.animation.AnimatorSet; +import android.content.Context; +import android.graphics.Point; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.widget.LinearLayout; + +import com.android.launcher3.AbstractFloatingView; +import com.android.launcher3.ItemInfo; +import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherAnimUtils; +import com.android.launcher3.R; +import com.android.launcher3.anim.PropertyListBuilder; +import com.android.launcher3.dragndrop.DragOptions; +import com.android.launcher3.dragndrop.DragView; +import com.android.launcher3.logging.UserEventDispatcher.LogContainerProvider; +import com.android.launcher3.popup.PopupContainerWithArrow; +import com.android.launcher3.popup.PopupItemView; +import com.android.launcher3.userevent.nano.LauncherLogProto; + +import java.util.ArrayList; +import java.util.List; + +/** + * A {@link PopupItemView} that contains all of the {@link DeepShortcutView}s for an app. + */ +public class ShortcutsItemView extends PopupItemView implements View.OnLongClickListener, + View.OnTouchListener, LogContainerProvider { + + private Launcher mLauncher; + private LinearLayout mDeepShortcutsLayout; + private final Point mIconShift = new Point(); + private final Point mIconLastTouchPos = new Point(); + + public ShortcutsItemView(Context context) { + this(context, null, 0); + } + + public ShortcutsItemView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ShortcutsItemView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + mLauncher = Launcher.getLauncher(context); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mDeepShortcutsLayout = (LinearLayout) findViewById(R.id.deep_shortcuts); + } + + @Override + public boolean onTouch(View v, MotionEvent ev) { + // Touched a shortcut, update where it was touched so we can drag from there on long click. + switch (ev.getAction()) { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_MOVE: + mIconLastTouchPos.set((int) ev.getX(), (int) ev.getY()); + break; + } + return false; + } + + @Override + public boolean onLongClick(View v) { + // Return early if this is not initiated from a touch or not the correct view + if (!v.isInTouchMode() || !(v.getParent() instanceof DeepShortcutView)) return false; + // Return early if global dragging is not enabled + if (!mLauncher.isDraggingEnabled()) return false; + // Return early if an item is already being dragged (e.g. when long-pressing two shortcuts) + if (mLauncher.getDragController().isDragging()) return false; + + // Long clicked on a shortcut. + DeepShortcutView sv = (DeepShortcutView) v.getParent(); + sv.setWillDrawIcon(false); + + // Move the icon to align with the center-top of the touch point + mIconShift.x = mIconLastTouchPos.x - sv.getIconCenter().x; + mIconShift.y = mIconLastTouchPos.y - mLauncher.getDeviceProfile().iconSizePx; + + DragView dv = mLauncher.getWorkspace().beginDragShared(sv.getBubbleText(), + (PopupContainerWithArrow) getParent(), sv.getFinalInfo(), + new ShortcutDragPreviewProvider(sv.getIconView(), mIconShift), new DragOptions()); + dv.animateShift(-mIconShift.x, -mIconShift.y); + + // TODO: support dragging from within folder without having to close it + AbstractFloatingView.closeOpenContainer(mLauncher, AbstractFloatingView.TYPE_FOLDER); + return false; + } + + public void addDeepShortcutView(DeepShortcutView deepShortcutView) { + if (getNumDeepShortcuts() > 0) { + getDeepShortcutAt(getNumDeepShortcuts() - 1).findViewById(R.id.divider) + .setVisibility(VISIBLE); + } + mDeepShortcutsLayout.addView(deepShortcutView); + } + + private DeepShortcutView getDeepShortcutAt(int index) { + return (DeepShortcutView) mDeepShortcutsLayout.getChildAt(index); + } + + private int getNumDeepShortcuts() { + return mDeepShortcutsLayout.getChildCount(); + } + + public List<DeepShortcutView> getDeepShortcutViews(boolean reverseOrder) { + int numDeepShortcuts = getNumDeepShortcuts(); + List<DeepShortcutView> deepShortcutViews = new ArrayList<>(numDeepShortcuts); + for (int i = 0; i < numDeepShortcuts; i++) { + DeepShortcutView deepShortcut = getDeepShortcutAt(i); + if (reverseOrder) { + deepShortcutViews.add(0, deepShortcut); + } else { + deepShortcutViews.add(deepShortcut); + } + } + return deepShortcutViews; + } + + @Override + public Animator createOpenAnimation(boolean isContainerAboveIcon, boolean pivotLeft) { + AnimatorSet openAnimation = LauncherAnimUtils.createAnimatorSet(); + openAnimation.play(super.createOpenAnimation(isContainerAboveIcon, pivotLeft)); + for (int i = 0; i < getNumDeepShortcuts(); i++) { + View deepShortcutIcon = getDeepShortcutAt(i).getIconView(); + deepShortcutIcon.setScaleX(0); + deepShortcutIcon.setScaleY(0); + openAnimation.play(LauncherAnimUtils.ofPropertyValuesHolder( + deepShortcutIcon, new PropertyListBuilder().scale(1).build())); + } + return openAnimation; + } + + @Override + public Animator createCloseAnimation(boolean isContainerAboveIcon, boolean pivotLeft, + long duration) { + AnimatorSet closeAnimation = LauncherAnimUtils.createAnimatorSet(); + closeAnimation.play(super.createCloseAnimation(isContainerAboveIcon, pivotLeft, duration)); + for (int i = 0; i < getNumDeepShortcuts(); i++) { + View deepShortcutIcon = getDeepShortcutAt(i).getIconView(); + deepShortcutIcon.setScaleX(1); + deepShortcutIcon.setScaleY(1); + closeAnimation.play(LauncherAnimUtils.ofPropertyValuesHolder( + deepShortcutIcon, new PropertyListBuilder().scale(0).build())); + } + return closeAnimation; + } + + @Override + public void fillInLogContainerData(View v, ItemInfo info, LauncherLogProto.Target target, + LauncherLogProto.Target targetParent) { + target.itemType = LauncherLogProto.ItemType.DEEPSHORTCUT; + target.rank = info.rank; + targetParent.containerType = LauncherLogProto.ContainerType.DEEPSHORTCUTS; + } +} diff --git a/src/com/android/launcher3/util/PillWidthRevealOutlineProvider.java b/src/com/android/launcher3/util/PillWidthRevealOutlineProvider.java deleted file mode 100644 index 89dda3b26..000000000 --- a/src/com/android/launcher3/util/PillWidthRevealOutlineProvider.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.util; - -import android.graphics.Rect; - -/** - * Extension of {@link PillRevealOutlineProvider} which only changes the width of the pill. - */ -public class PillWidthRevealOutlineProvider extends PillRevealOutlineProvider { - - private final int mStartLeft; - private final int mStartRight; - - public PillWidthRevealOutlineProvider(Rect pillRect, int left, int right) { - super(0, 0, pillRect); - mOutline.set(pillRect); - mStartLeft = left; - mStartRight = right; - } - - @Override - public void setProgress(float progress) { - mOutline.left = (int) (progress * mPillRect.left + (1 - progress) * mStartLeft); - mOutline.right = (int) (progress * mPillRect.right + (1 - progress) * mStartRight); - } -} |