Remove gap between popup items
- Unround interior corners - Update colors (shortcuts are gray when next to notifications, notifications always white) - Clean up animation to animate entire popup with simple reveal instead of individual items animating with reveal and icon scale Bug: 35766387 Bug: 36110804 Change-Id: I33685d53e2db3904731676123dc230be4dabb5d4
This commit is contained in:
parent
d5645d406b
commit
acaf5b3a37
|
@ -1,21 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="#FFFFFF" />
|
||||
<corners android:radius="@dimen/bg_round_rect_radius" />
|
||||
</shape>
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<View xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/popup_item_divider_height"
|
||||
android:background="?android:attr/listDivider"/>
|
|
@ -19,9 +19,7 @@
|
|||
android:id="@+id/notification_view"
|
||||
android:layout_width="@dimen/bg_popup_item_width"
|
||||
android:layout_height="wrap_content"
|
||||
android:elevation="@dimen/deep_shortcuts_elevation"
|
||||
android:background="@drawable/bg_white_round_rect"
|
||||
android:backgroundTint="@color/notification_color_beneath">
|
||||
android:elevation="@dimen/deep_shortcuts_elevation">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
|
@ -35,7 +33,7 @@
|
|||
android:layout_height="@dimen/notification_header_height"
|
||||
android:paddingStart="@dimen/notification_padding_start"
|
||||
android:paddingEnd="@dimen/notification_padding_end"
|
||||
android:background="@color/popup_header_background_color"
|
||||
android:background="@color/popup_background_color"
|
||||
android:elevation="@dimen/notification_elevation">
|
||||
<TextView
|
||||
android:id="@+id/notification_text"
|
||||
|
|
|
@ -19,8 +19,7 @@
|
|||
android:id="@+id/shortcuts_view"
|
||||
android:layout_width="@dimen/bg_popup_item_width"
|
||||
android:layout_height="wrap_content"
|
||||
android:elevation="@dimen/deep_shortcuts_elevation"
|
||||
android:background="@drawable/bg_white_round_rect">
|
||||
android:elevation="@dimen/deep_shortcuts_elevation">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/deep_shortcuts"
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
<color name="spring_loaded_highlighted_panel_border_color">#FFF</color>
|
||||
|
||||
<!-- Popup container -->
|
||||
<color name="popup_header_background_color">#EEEEEE</color> <!-- Gray 200 -->
|
||||
<color name="popup_header_background_color">#F5F5F5</color> <!-- Gray 100 -->
|
||||
<color name="popup_background_color">#FFF</color>
|
||||
<color name="notification_icon_default_color">#757575</color> <!-- Gray 600 -->
|
||||
<color name="notification_color_beneath">#E0E0E0</color> <!-- Gray 300 -->
|
||||
|
|
|
@ -124,11 +124,8 @@
|
|||
<item type="id" name="preview_image_id" />
|
||||
|
||||
<!-- Popup items -->
|
||||
<integer name="config_deepShortcutOpenDuration">220</integer>
|
||||
<integer name="config_deepShortcutArrowOpenDuration">80</integer>
|
||||
<integer name="config_deepShortcutOpenStagger">40</integer>
|
||||
<integer name="config_deepShortcutCloseDuration">150</integer>
|
||||
<integer name="config_deepShortcutCloseStagger">20</integer>
|
||||
<integer name="config_popupOpenCloseDuration">220</integer>
|
||||
<integer name="config_popupArrowOpenDuration">80</integer>
|
||||
<integer name="config_removeNotificationViewDuration">300</integer>
|
||||
|
||||
<!-- Accessibility actions -->
|
||||
|
|
|
@ -148,7 +148,6 @@
|
|||
<dimen name="deep_shortcuts_elevation">9dp</dimen>
|
||||
<dimen name="bg_popup_item_width">220dp</dimen>
|
||||
<dimen name="bg_popup_item_height">56dp</dimen>
|
||||
<dimen name="popup_items_spacing">4dp</dimen>
|
||||
<dimen name="pre_drag_view_scale">6dp</dimen>
|
||||
<!-- an icon with shortcuts must be dragged this far before the container is removed. -->
|
||||
<dimen name="deep_shortcuts_start_drag_threshold">16dp</dimen>
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* 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.anim;
|
||||
|
||||
import android.graphics.Rect;
|
||||
|
||||
/**
|
||||
* Extension of {@link PillRevealOutlineProvider} which only changes the height of the pill.
|
||||
* For now, we assume the height is added/removed from the bottom.
|
||||
*/
|
||||
public class PillHeightRevealOutlineProvider extends PillRevealOutlineProvider {
|
||||
|
||||
private final int mNewHeight;
|
||||
|
||||
public PillHeightRevealOutlineProvider(Rect pillRect, float radius, int newHeight) {
|
||||
super(0, 0, pillRect, radius);
|
||||
mOutline.set(pillRect);
|
||||
mNewHeight = newHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProgress(float progress) {
|
||||
mOutline.top = 0;
|
||||
int heightDifference = mPillRect.height() - mNewHeight;
|
||||
mOutline.bottom = (int) (mPillRect.bottom - heightDifference * (1 - progress));
|
||||
}
|
||||
}
|
|
@ -1,68 +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.anim;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.view.ViewOutlineProvider;
|
||||
|
||||
/**
|
||||
* A {@link ViewOutlineProvider} that animates a reveal in a "pill" shape.
|
||||
* A pill is simply a round rect, but we assume the width is greater than
|
||||
* the height and that the radius is equal to half the height.
|
||||
*/
|
||||
public class PillRevealOutlineProvider extends RevealOutlineAnimation {
|
||||
|
||||
private int mCenterX;
|
||||
private int mCenterY;
|
||||
private float mFinalRadius;
|
||||
protected Rect mPillRect;
|
||||
|
||||
/**
|
||||
* @param x reveal center x
|
||||
* @param y reveal center y
|
||||
* @param pillRect round rect that represents the final pill shape
|
||||
*/
|
||||
public PillRevealOutlineProvider(int x, int y, Rect pillRect) {
|
||||
this(x, y, pillRect, pillRect.height() / 2f);
|
||||
}
|
||||
|
||||
public PillRevealOutlineProvider(int x, int y, Rect pillRect, float radius) {
|
||||
mCenterX = x;
|
||||
mCenterY = y;
|
||||
mPillRect = pillRect;
|
||||
mOutlineRadius = mFinalRadius = radius;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRemoveElevationDuringAnimation() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProgress(float progress) {
|
||||
// Assumes width is greater than height.
|
||||
int centerToEdge = Math.max(mCenterX, mPillRect.width() - mCenterX);
|
||||
int currentSize = (int) (progress * centerToEdge);
|
||||
|
||||
// Bound the outline to the final pill shape defined by mPillRect.
|
||||
mOutline.left = Math.max(mPillRect.left, mCenterX - currentSize);
|
||||
mOutline.top = Math.max(mPillRect.top, mCenterY - currentSize);
|
||||
mOutline.right = Math.min(mPillRect.right, mCenterX + currentSize);
|
||||
mOutline.bottom = Math.min(mPillRect.bottom, mCenterY + currentSize);
|
||||
mOutlineRadius = Math.min(mFinalRadius, mOutline.height() / 2);
|
||||
}
|
||||
}
|
|
@ -18,6 +18,11 @@ package com.android.launcher3.anim;
|
|||
|
||||
import android.graphics.Rect;
|
||||
|
||||
import com.android.launcher3.popup.PopupContainerWithArrow;
|
||||
|
||||
import static com.android.launcher3.popup.PopupContainerWithArrow.ROUNDED_BOTTOM_CORNERS;
|
||||
import static com.android.launcher3.popup.PopupContainerWithArrow.ROUNDED_TOP_CORNERS;
|
||||
|
||||
/**
|
||||
* A {@link RevealOutlineAnimation} that provides an outline that interpolates between two radii
|
||||
* and two {@link Rect}s.
|
||||
|
@ -32,12 +37,21 @@ public class RoundedRectRevealOutlineProvider extends RevealOutlineAnimation {
|
|||
private final Rect mStartRect;
|
||||
private final Rect mEndRect;
|
||||
|
||||
private final @PopupContainerWithArrow.RoundedCornerFlags int mRoundedCorners;
|
||||
|
||||
public RoundedRectRevealOutlineProvider(float startRadius, float endRadius, Rect startRect,
|
||||
Rect endRect) {
|
||||
this(startRadius, endRadius, startRect, endRect,
|
||||
ROUNDED_TOP_CORNERS | ROUNDED_BOTTOM_CORNERS);
|
||||
}
|
||||
|
||||
public RoundedRectRevealOutlineProvider(float startRadius, float endRadius, Rect startRect,
|
||||
Rect endRect, int roundedCorners) {
|
||||
mStartRadius = startRadius;
|
||||
mEndRadius = endRadius;
|
||||
mStartRect = startRect;
|
||||
mEndRect = endRect;
|
||||
mRoundedCorners = roundedCorners;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -51,7 +65,13 @@ public class RoundedRectRevealOutlineProvider extends RevealOutlineAnimation {
|
|||
|
||||
mOutline.left = (int) ((1 - progress) * mStartRect.left + progress * mEndRect.left);
|
||||
mOutline.top = (int) ((1 - progress) * mStartRect.top + progress * mEndRect.top);
|
||||
if ((mRoundedCorners & ROUNDED_TOP_CORNERS) == 0) {
|
||||
mOutline.top -= mOutlineRadius;
|
||||
}
|
||||
mOutline.right = (int) ((1 - progress) * mStartRect.right + progress * mEndRect.right);
|
||||
mOutline.bottom = (int) ((1 - progress) * mStartRect.bottom + progress * mEndRect.bottom);
|
||||
if ((mRoundedCorners & ROUNDED_BOTTOM_CORNERS) == 0) {
|
||||
mOutline.bottom += mOutlineRadius;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ import android.app.Notification;
|
|||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
@ -30,7 +29,7 @@ import android.widget.TextView;
|
|||
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.anim.PillHeightRevealOutlineProvider;
|
||||
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
|
||||
import com.android.launcher3.graphics.IconPalette;
|
||||
import com.android.launcher3.logging.UserEventDispatcher.LogContainerProvider;
|
||||
import com.android.launcher3.popup.PopupItemView;
|
||||
|
@ -87,9 +86,10 @@ public class NotificationItemView extends PopupItemView implements LogContainerP
|
|||
}
|
||||
|
||||
public Animator animateHeightRemoval(int heightToRemove) {
|
||||
final int newHeight = getHeight() - heightToRemove;
|
||||
return new PillHeightRevealOutlineProvider(mPillRect,
|
||||
getBackgroundRadius(), newHeight).createRevealAnimator(this, true /* isReversed */);
|
||||
Rect endRect = new Rect(mPillRect);
|
||||
endRect.bottom -= heightToRemove;
|
||||
return new RoundedRectRevealOutlineProvider(getBackgroundRadius(), getBackgroundRadius(),
|
||||
mPillRect, endRect, mRoundedCorners).createRevealAnimator(this, false);
|
||||
}
|
||||
|
||||
public void updateHeader(int notificationCount, @Nullable IconPalette palette) {
|
||||
|
@ -162,13 +162,6 @@ public class NotificationItemView extends PopupItemView implements LogContainerP
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getArrowColor(boolean isArrowAttachedToBottom) {
|
||||
return ContextCompat.getColor(getContext(), isArrowAttachedToBottom
|
||||
? R.color.popup_background_color
|
||||
: R.color.popup_header_background_color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillInLogContainerData(View v, ItemInfo info, LauncherLogProto.Target target,
|
||||
LauncherLogProto.Target targetParent) {
|
||||
|
|
|
@ -20,19 +20,22 @@ import android.animation.Animator;
|
|||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.TimeInterpolator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.CornerPathEffect;
|
||||
import android.graphics.Outline;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.ShapeDrawable;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.support.annotation.IntDef;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -40,7 +43,7 @@ import android.view.MotionEvent;
|
|||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.view.animation.AccelerateDecelerateInterpolator;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
|
@ -53,13 +56,13 @@ import com.android.launcher3.Launcher;
|
|||
import com.android.launcher3.LauncherAnimUtils;
|
||||
import com.android.launcher3.LauncherModel;
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.LogAccelerateInterpolator;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
|
||||
import com.android.launcher3.accessibility.ShortcutMenuAccessibilityDelegate;
|
||||
import com.android.launcher3.anim.PropertyListBuilder;
|
||||
import com.android.launcher3.anim.PropertyResetListener;
|
||||
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
|
||||
import com.android.launcher3.badge.BadgeInfo;
|
||||
import com.android.launcher3.dragndrop.DragController;
|
||||
import com.android.launcher3.dragndrop.DragLayer;
|
||||
|
@ -73,6 +76,8 @@ import com.android.launcher3.shortcuts.DeepShortcutView;
|
|||
import com.android.launcher3.shortcuts.ShortcutsItemView;
|
||||
import com.android.launcher3.util.PackageUserKey;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -89,6 +94,16 @@ import static com.android.launcher3.userevent.nano.LauncherLogProto.Target;
|
|||
public class PopupContainerWithArrow extends AbstractFloatingView implements DragSource,
|
||||
DragController.DragListener {
|
||||
|
||||
public static final int ROUNDED_TOP_CORNERS = 1 << 0;
|
||||
public static final int ROUNDED_BOTTOM_CORNERS = 1 << 1;
|
||||
|
||||
@IntDef(flag = true, value = {
|
||||
ROUNDED_TOP_CORNERS,
|
||||
ROUNDED_BOTTOM_CORNERS
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface RoundedCornerFlags {}
|
||||
|
||||
protected final Launcher mLauncher;
|
||||
private final int mStartDragThreshold;
|
||||
private LauncherAccessibilityDelegate mAccessibilityDelegate;
|
||||
|
@ -107,6 +122,8 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
|
|||
protected Animator mOpenCloseAnimator;
|
||||
private boolean mDeferContainerRemoval;
|
||||
private AnimatorSet mReduceHeightAnimatorSet;
|
||||
private final Rect mStartRect = new Rect();
|
||||
private final Rect mEndRect = new Rect();
|
||||
|
||||
public PopupContainerWithArrow(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
|
@ -222,6 +239,7 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
|
|||
mArrow.setPivotX(arrowWidth / 2);
|
||||
mArrow.setPivotY(mIsAboveIcon ? 0 : arrowHeight);
|
||||
|
||||
measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
|
||||
animateOpen();
|
||||
|
||||
mLauncher.getDragController().addDragListener(this);
|
||||
|
@ -238,46 +256,66 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
|
|||
private void addDummyViews(PopupPopulator.Item[] itemTypesToPopulate,
|
||||
boolean notificationFooterHasIcons) {
|
||||
final Resources res = getResources();
|
||||
final int spacing = res.getDimensionPixelSize(R.dimen.popup_items_spacing);
|
||||
final LayoutInflater inflater = mLauncher.getLayoutInflater();
|
||||
|
||||
int shortcutsItemRoundedCorners = ROUNDED_TOP_CORNERS | ROUNDED_BOTTOM_CORNERS;
|
||||
int numItems = itemTypesToPopulate.length;
|
||||
for (int i = 0; i < numItems; i++) {
|
||||
PopupPopulator.Item itemTypeToPopulate = itemTypesToPopulate[i];
|
||||
PopupPopulator.Item prevItemTypeToPopulate =
|
||||
i > 0 ? itemTypesToPopulate[i - 1] : null;
|
||||
PopupPopulator.Item nextItemTypeToPopulate =
|
||||
i < numItems - 1 ? itemTypesToPopulate[i + 1] : null;
|
||||
final View item = inflater.inflate(itemTypeToPopulate.layoutId, this, false);
|
||||
|
||||
boolean shouldUnroundTopCorners = prevItemTypeToPopulate != null
|
||||
&& itemTypeToPopulate.isShortcut ^ prevItemTypeToPopulate.isShortcut;
|
||||
boolean shouldUnroundBottomCorners = nextItemTypeToPopulate != null
|
||||
&& itemTypeToPopulate.isShortcut ^ nextItemTypeToPopulate.isShortcut;
|
||||
|
||||
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;
|
||||
|
||||
int roundedCorners = ROUNDED_TOP_CORNERS | ROUNDED_BOTTOM_CORNERS;
|
||||
if (shouldUnroundTopCorners) {
|
||||
roundedCorners &= ~ROUNDED_TOP_CORNERS;
|
||||
}
|
||||
if (shouldUnroundBottomCorners) {
|
||||
roundedCorners &= ~ROUNDED_BOTTOM_CORNERS;
|
||||
}
|
||||
int backgroundColor = ContextCompat.getColor(getContext(),
|
||||
R.color.notification_color_beneath);
|
||||
mNotificationItemView.setBackgroundWithCorners(backgroundColor, roundedCorners);
|
||||
|
||||
mNotificationItemView.getMainView().setAccessibilityDelegate(mAccessibilityDelegate);
|
||||
} else if (itemTypeToPopulate == PopupPopulator.Item.SHORTCUT) {
|
||||
item.setAccessibilityDelegate(mAccessibilityDelegate);
|
||||
}
|
||||
|
||||
boolean shouldAddBottomMargin = nextItemTypeToPopulate != null
|
||||
&& itemTypeToPopulate.isShortcut ^ nextItemTypeToPopulate.isShortcut;
|
||||
|
||||
if (itemTypeToPopulate.isShortcut) {
|
||||
if (mShortcutsItemView == null) {
|
||||
mShortcutsItemView = (ShortcutsItemView) inflater.inflate(
|
||||
R.layout.shortcuts_item, this, false);
|
||||
addView(mShortcutsItemView);
|
||||
if (shouldUnroundTopCorners) {
|
||||
shortcutsItemRoundedCorners &= ~ROUNDED_TOP_CORNERS;
|
||||
}
|
||||
}
|
||||
mShortcutsItemView.addShortcutView(item, itemTypeToPopulate);
|
||||
if (shouldAddBottomMargin) {
|
||||
((LayoutParams) mShortcutsItemView.getLayoutParams()).bottomMargin = spacing;
|
||||
if (shouldUnroundBottomCorners) {
|
||||
shortcutsItemRoundedCorners &= ~ROUNDED_BOTTOM_CORNERS;
|
||||
}
|
||||
} else {
|
||||
addView(item);
|
||||
if (shouldAddBottomMargin) {
|
||||
((LayoutParams) item.getLayoutParams()).bottomMargin = spacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
int backgroundColor = ContextCompat.getColor(getContext(), mNotificationItemView == null
|
||||
? R.color.popup_background_color
|
||||
: R.color.popup_header_background_color);
|
||||
mShortcutsItemView.setBackgroundWithCorners(backgroundColor, shortcutsItemRoundedCorners);
|
||||
}
|
||||
|
||||
protected PopupItemView getItemViewAt(int index) {
|
||||
|
@ -297,45 +335,31 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
|
|||
setVisibility(View.VISIBLE);
|
||||
mIsOpen = true;
|
||||
|
||||
final AnimatorSet shortcutAnims = LauncherAnimUtils.createAnimatorSet();
|
||||
final int itemCount = getItemCount();
|
||||
final AnimatorSet openAnim = LauncherAnimUtils.createAnimatorSet();
|
||||
final Resources res = getResources();
|
||||
|
||||
final long duration = getResources().getInteger(
|
||||
R.integer.config_deepShortcutOpenDuration);
|
||||
final long arrowScaleDuration = getResources().getInteger(
|
||||
R.integer.config_deepShortcutArrowOpenDuration);
|
||||
final long arrowScaleDelay = duration - arrowScaleDuration;
|
||||
final long stagger = getResources().getInteger(
|
||||
R.integer.config_deepShortcutOpenStagger);
|
||||
final TimeInterpolator fadeInterpolator = new LogAccelerateInterpolator(100, 0);
|
||||
|
||||
// Animate shortcuts
|
||||
DecelerateInterpolator interpolator = new DecelerateInterpolator();
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
final PopupItemView popupItemView = getItemViewAt(i);
|
||||
popupItemView.setVisibility(INVISIBLE);
|
||||
popupItemView.setAlpha(0);
|
||||
|
||||
Animator anim = popupItemView.createOpenAnimation(mIsAboveIcon, mIsLeftAligned);
|
||||
anim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
popupItemView.setVisibility(VISIBLE);
|
||||
}
|
||||
});
|
||||
anim.setDuration(duration);
|
||||
int animationIndex = mIsAboveIcon ? itemCount - i - 1 : i;
|
||||
anim.setStartDelay(stagger * animationIndex);
|
||||
anim.setInterpolator(interpolator);
|
||||
shortcutAnims.play(anim);
|
||||
|
||||
Animator fadeAnim = ObjectAnimator.ofFloat(popupItemView, View.ALPHA, 1);
|
||||
fadeAnim.setInterpolator(fadeInterpolator);
|
||||
// We want the shortcut to be fully opaque before the arrow starts animating.
|
||||
fadeAnim.setDuration(arrowScaleDelay);
|
||||
shortcutAnims.play(fadeAnim);
|
||||
// Rectangular reveal.
|
||||
int itemsTotalHeight = 0;
|
||||
for (int i = 0; i < getItemCount(); i++) {
|
||||
itemsTotalHeight += getItemViewAt(i).getMeasuredHeight();
|
||||
}
|
||||
shortcutAnims.addListener(new AnimatorListenerAdapter() {
|
||||
Point startPoint = computeAnimStartPoint(itemsTotalHeight);
|
||||
int top = mIsAboveIcon ? getPaddingTop() : startPoint.y;
|
||||
float radius = getItemViewAt(0).getBackgroundRadius();
|
||||
mStartRect.set(startPoint.x, startPoint.y, startPoint.x, startPoint.y);
|
||||
mEndRect.set(0, top, getMeasuredWidth(), top + itemsTotalHeight);
|
||||
final ValueAnimator revealAnim = new RoundedRectRevealOutlineProvider
|
||||
(radius, radius, mStartRect, mEndRect).createRevealAnimator(this, false);
|
||||
revealAnim.setDuration((long) res.getInteger(R.integer.config_popupOpenCloseDuration));
|
||||
revealAnim.setInterpolator(new AccelerateDecelerateInterpolator());
|
||||
|
||||
// Animate the arrow.
|
||||
mArrow.setScaleX(0);
|
||||
mArrow.setScaleY(0);
|
||||
Animator arrowScale = createArrowScaleAnim(1).setDuration(res.getInteger(
|
||||
R.integer.config_popupArrowOpenDuration));
|
||||
|
||||
openAnim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mOpenCloseAnimator = null;
|
||||
|
@ -346,15 +370,26 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
|
|||
}
|
||||
});
|
||||
|
||||
// Animate the arrow
|
||||
mArrow.setScaleX(0);
|
||||
mArrow.setScaleY(0);
|
||||
Animator arrowScale = createArrowScaleAnim(1).setDuration(arrowScaleDuration);
|
||||
arrowScale.setStartDelay(arrowScaleDelay);
|
||||
shortcutAnims.play(arrowScale);
|
||||
mOpenCloseAnimator = openAnim;
|
||||
openAnim.playSequentially(revealAnim, arrowScale);
|
||||
openAnim.start();
|
||||
}
|
||||
|
||||
mOpenCloseAnimator = shortcutAnims;
|
||||
shortcutAnims.start();
|
||||
/**
|
||||
* Returns the point at which the center of the arrow merges with the first popup item.
|
||||
*/
|
||||
private Point computeAnimStartPoint(int itemsTotalHeight) {
|
||||
int arrowCenterX = getResources().getDimensionPixelSize(mIsLeftAligned ^ mIsRtl ?
|
||||
R.dimen.popup_arrow_horizontal_center_start:
|
||||
R.dimen.popup_arrow_horizontal_center_end);
|
||||
if (!mIsLeftAligned) {
|
||||
arrowCenterX = getMeasuredWidth() - arrowCenterX;
|
||||
}
|
||||
int arrowHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom()
|
||||
- itemsTotalHeight;
|
||||
// The y-coordinate of edge between the arrow and the first popup item.
|
||||
int arrowEdge = getPaddingTop() + (mIsAboveIcon ? itemsTotalHeight : arrowHeight);
|
||||
return new Point(arrowCenterX, arrowEdge);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -506,7 +541,7 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
|
|||
// since the latter expects the arrow which hasn't been added yet.
|
||||
PopupItemView itemAttachedToArrow = (PopupItemView)
|
||||
(getChildAt(mIsAboveIcon ? getChildCount() - 1 : 0));
|
||||
arrowPaint.setColor(itemAttachedToArrow.getArrowColor(mIsAboveIcon));
|
||||
arrowPaint.setColor(ContextCompat.getColor(mLauncher, R.color.popup_background_color));
|
||||
// The corner path effect won't be reflected in the shadow, but shouldn't be noticeable.
|
||||
int radius = getResources().getDimensionPixelSize(R.dimen.popup_arrow_corner_radius);
|
||||
arrowPaint.setPathEffect(new CornerPathEffect(radius));
|
||||
|
@ -609,22 +644,8 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
|
|||
AnimatorSet removeNotification = LauncherAnimUtils.createAnimatorSet();
|
||||
final int duration = getResources().getInteger(
|
||||
R.integer.config_removeNotificationViewDuration);
|
||||
final int spacing = getResources().getDimensionPixelSize(R.dimen.popup_items_spacing);
|
||||
removeNotification.play(reduceNotificationViewHeight(
|
||||
mNotificationItemView.getHeightMinusFooter() + spacing, duration));
|
||||
final View removeMarginView = mIsAboveIcon ? getItemViewAt(getItemCount() - 2)
|
||||
: mNotificationItemView;
|
||||
if (removeMarginView != null) {
|
||||
ValueAnimator removeMargin = ValueAnimator.ofFloat(1, 0).setDuration(duration);
|
||||
removeMargin.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator valueAnimator) {
|
||||
((MarginLayoutParams) removeMarginView.getLayoutParams()).bottomMargin
|
||||
= (int) (spacing * (float) valueAnimator.getAnimatedValue());
|
||||
}
|
||||
});
|
||||
removeNotification.play(removeMargin);
|
||||
}
|
||||
mNotificationItemView.getHeightMinusFooter(), duration));
|
||||
Animator fade = ObjectAnimator.ofFloat(mNotificationItemView, ALPHA, 0)
|
||||
.setDuration(duration);
|
||||
fade.addListener(new AnimatorListenerAdapter() {
|
||||
|
@ -634,19 +655,25 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
|
|||
mNotificationItemView = null;
|
||||
if (getItemCount() == 0) {
|
||||
close(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
removeNotification.play(fade);
|
||||
final long arrowScaleDuration = getResources().getInteger(
|
||||
R.integer.config_deepShortcutArrowOpenDuration);
|
||||
R.integer.config_popupArrowOpenDuration);
|
||||
Animator hideArrow = createArrowScaleAnim(0).setDuration(arrowScaleDuration);
|
||||
hideArrow.setStartDelay(0);
|
||||
Animator showArrow = createArrowScaleAnim(1).setDuration(arrowScaleDuration);
|
||||
showArrow.setStartDelay((long) (duration - arrowScaleDuration * 1.5));
|
||||
removeNotification.playSequentially(hideArrow, showArrow);
|
||||
removeNotification.start();
|
||||
if (mShortcutsItemView != null) {
|
||||
int backgroundColor = ContextCompat.getColor(getContext(),
|
||||
R.color.popup_background_color);
|
||||
// With notifications gone, all corners of shortcuts item should be rounded.
|
||||
mShortcutsItemView.setBackgroundWithCorners(backgroundColor,
|
||||
ROUNDED_TOP_CORNERS | ROUNDED_BOTTOM_CORNERS);
|
||||
}
|
||||
return;
|
||||
}
|
||||
mNotificationItemView.trimNotifications(NotificationKeyData.extractKeysOnly(
|
||||
|
@ -770,55 +797,40 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
|
|||
if (!mIsOpen) {
|
||||
return;
|
||||
}
|
||||
mEndRect.setEmpty();
|
||||
if (mOpenCloseAnimator != null) {
|
||||
Outline outline = new Outline();
|
||||
getOutlineProvider().getOutline(this, outline);
|
||||
outline.getRect(mEndRect);
|
||||
mOpenCloseAnimator.cancel();
|
||||
}
|
||||
mIsOpen = false;
|
||||
|
||||
final AnimatorSet shortcutAnims = LauncherAnimUtils.createAnimatorSet();
|
||||
final int itemCount = getItemCount();
|
||||
int numOpenShortcuts = 0;
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
if (getItemViewAt(i).isOpenOrOpening()) {
|
||||
numOpenShortcuts++;
|
||||
}
|
||||
final AnimatorSet closeAnim = LauncherAnimUtils.createAnimatorSet();
|
||||
final Resources res = getResources();
|
||||
|
||||
// Animate the arrow.
|
||||
Animator arrowScale = createArrowScaleAnim(0).setDuration(res.getInteger(
|
||||
R.integer.config_popupArrowOpenDuration));
|
||||
|
||||
// Rectangular reveal (reversed).
|
||||
int itemsTotalHeight = 0;
|
||||
for (int i = 0; i < getItemCount(); i++) {
|
||||
itemsTotalHeight += getItemViewAt(i).getMeasuredHeight();
|
||||
}
|
||||
final long duration = getResources().getInteger(
|
||||
R.integer.config_deepShortcutCloseDuration);
|
||||
final long arrowScaleDuration = getResources().getInteger(
|
||||
R.integer.config_deepShortcutArrowOpenDuration);
|
||||
final long stagger = getResources().getInteger(
|
||||
R.integer.config_deepShortcutCloseStagger);
|
||||
final TimeInterpolator fadeInterpolator = new LogAccelerateInterpolator(100, 0);
|
||||
|
||||
int firstOpenItemIndex = mIsAboveIcon ? itemCount - numOpenShortcuts : 0;
|
||||
for (int i = firstOpenItemIndex; i < firstOpenItemIndex + numOpenShortcuts; i++) {
|
||||
final PopupItemView view = getItemViewAt(i);
|
||||
Animator anim;
|
||||
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) {
|
||||
view.setVisibility(INVISIBLE);
|
||||
}
|
||||
});
|
||||
shortcutAnims.play(anim);
|
||||
Point startPoint = computeAnimStartPoint(itemsTotalHeight);
|
||||
int top = mIsAboveIcon ? getPaddingTop() : startPoint.y;
|
||||
float radius = getItemViewAt(0).getBackgroundRadius();
|
||||
mStartRect.set(startPoint.x, startPoint.y, startPoint.x, startPoint.y);
|
||||
if (mEndRect.isEmpty()) {
|
||||
mEndRect.set(0, top, getMeasuredWidth(), top + itemsTotalHeight);
|
||||
}
|
||||
Animator arrowAnim = createArrowScaleAnim(0).setDuration(arrowScaleDuration);
|
||||
arrowAnim.setStartDelay(0);
|
||||
shortcutAnims.play(arrowAnim);
|
||||
final ValueAnimator revealAnim = new RoundedRectRevealOutlineProvider(
|
||||
radius, radius, mStartRect, mEndRect).createRevealAnimator(this, true);
|
||||
revealAnim.setDuration((long) res.getInteger(R.integer.config_popupOpenCloseDuration));
|
||||
revealAnim.setInterpolator(new AccelerateDecelerateInterpolator());
|
||||
|
||||
shortcutAnims.addListener(new AnimatorListenerAdapter() {
|
||||
closeAnim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mOpenCloseAnimator = null;
|
||||
|
@ -829,8 +841,9 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
|
|||
}
|
||||
}
|
||||
});
|
||||
mOpenCloseAnimator = shortcutAnims;
|
||||
shortcutAnims.start();
|
||||
mOpenCloseAnimator = closeAnim;
|
||||
closeAnim.playSequentially(arrowScale, revealAnim);
|
||||
closeAnim.start();
|
||||
mOriginalIcon.forceHideBadge(false);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,38 +16,34 @@
|
|||
|
||||
package com.android.launcher3.popup;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.ShapeDrawable;
|
||||
import android.graphics.drawable.shapes.RoundRectShape;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.android.launcher3.LogAccelerateInterpolator;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.PillRevealOutlineProvider;
|
||||
import com.android.launcher3.popup.PopupContainerWithArrow.RoundedCornerFlags;
|
||||
|
||||
import static com.android.launcher3.popup.PopupContainerWithArrow.ROUNDED_BOTTOM_CORNERS;
|
||||
import static com.android.launcher3.popup.PopupContainerWithArrow.ROUNDED_TOP_CORNERS;
|
||||
|
||||
/**
|
||||
* An abstract {@link FrameLayout} that supports animating an item's content
|
||||
* (e.g. icon and text) separate from the item's background.
|
||||
* An abstract {@link FrameLayout} that contains content for {@link PopupContainerWithArrow}.
|
||||
*/
|
||||
public abstract class PopupItemView extends FrameLayout
|
||||
implements ValueAnimator.AnimatorUpdateListener {
|
||||
|
||||
protected static final Point sTempPoint = new Point();
|
||||
public abstract class PopupItemView extends FrameLayout {
|
||||
|
||||
protected final Rect mPillRect;
|
||||
private float mOpenAnimationProgress;
|
||||
protected @RoundedCornerFlags int mRoundedCorners;
|
||||
protected final boolean mIsRtl;
|
||||
protected View mIconView;
|
||||
|
||||
|
@ -93,164 +89,55 @@ public abstract class PopupItemView extends FrameLayout
|
|||
|
||||
@Override
|
||||
protected void dispatchDraw(Canvas canvas) {
|
||||
if (mRoundedCorners == 0) {
|
||||
super.dispatchDraw(canvas);
|
||||
return;
|
||||
}
|
||||
|
||||
int saveCount = canvas.saveLayer(0, 0, getWidth(), getHeight(), null);
|
||||
super.dispatchDraw(canvas);
|
||||
|
||||
// Clip children to this item's rounded corners.
|
||||
int cornerWidth = mRoundedCornerBitmap.getWidth();
|
||||
int cornerHeight = mRoundedCornerBitmap.getHeight();
|
||||
// Clip top left corner.
|
||||
mMatrix.reset();
|
||||
canvas.drawBitmap(mRoundedCornerBitmap, mMatrix, mBackgroundClipPaint);
|
||||
// Clip top right corner.
|
||||
mMatrix.setRotate(90, cornerWidth / 2, cornerHeight / 2);
|
||||
mMatrix.postTranslate(canvas.getWidth() - cornerWidth, 0);
|
||||
canvas.drawBitmap(mRoundedCornerBitmap, mMatrix, mBackgroundClipPaint);
|
||||
// Clip bottom right corner.
|
||||
mMatrix.setRotate(180, cornerWidth / 2, cornerHeight / 2);
|
||||
mMatrix.postTranslate(canvas.getWidth() - cornerWidth, canvas.getHeight() - cornerHeight);
|
||||
canvas.drawBitmap(mRoundedCornerBitmap, mMatrix, mBackgroundClipPaint);
|
||||
// Clip bottom left corner.
|
||||
mMatrix.setRotate(270, cornerWidth / 2, cornerHeight / 2);
|
||||
mMatrix.postTranslate(0, canvas.getHeight() - cornerHeight);
|
||||
canvas.drawBitmap(mRoundedCornerBitmap, mMatrix, mBackgroundClipPaint);
|
||||
if ((mRoundedCorners & ROUNDED_TOP_CORNERS) != 0) {
|
||||
// Clip top left corner.
|
||||
mMatrix.reset();
|
||||
canvas.drawBitmap(mRoundedCornerBitmap, mMatrix, mBackgroundClipPaint);
|
||||
// Clip top right corner.
|
||||
mMatrix.setRotate(90, cornerWidth / 2, cornerHeight / 2);
|
||||
mMatrix.postTranslate(canvas.getWidth() - cornerWidth, 0);
|
||||
canvas.drawBitmap(mRoundedCornerBitmap, mMatrix, mBackgroundClipPaint);
|
||||
}
|
||||
if ((mRoundedCorners & ROUNDED_BOTTOM_CORNERS) != 0) {
|
||||
// Clip bottom right corner.
|
||||
mMatrix.setRotate(180, cornerWidth / 2, cornerHeight / 2);
|
||||
mMatrix.postTranslate(canvas.getWidth() - cornerWidth, canvas.getHeight() - cornerHeight);
|
||||
canvas.drawBitmap(mRoundedCornerBitmap, mMatrix, mBackgroundClipPaint);
|
||||
// Clip bottom left corner.
|
||||
mMatrix.setRotate(270, cornerWidth / 2, cornerHeight / 2);
|
||||
mMatrix.postTranslate(0, canvas.getHeight() - cornerHeight);
|
||||
canvas.drawBitmap(mRoundedCornerBitmap, mMatrix, mBackgroundClipPaint);
|
||||
}
|
||||
|
||||
canvas.restoreToCount(saveCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an animator to play when the shortcut container is being opened.
|
||||
* Creates a round rect drawable (with the specified corners unrounded)
|
||||
* and sets it as this View's background.
|
||||
*/
|
||||
public Animator createOpenAnimation(boolean isContainerAboveIcon, boolean pivotLeft) {
|
||||
Point center = getIconCenter();
|
||||
int arrowCenter = getResources().getDimensionPixelSize(pivotLeft ^ mIsRtl ?
|
||||
R.dimen.popup_arrow_horizontal_center_start:
|
||||
R.dimen.popup_arrow_horizontal_center_end);
|
||||
ValueAnimator openAnimator = new ZoomRevealOutlineProvider(center.x, center.y,
|
||||
mPillRect, this, mIconView, isContainerAboveIcon, pivotLeft, arrowCenter)
|
||||
.createRevealAnimator(this, false);
|
||||
mOpenAnimationProgress = 0f;
|
||||
openAnimator.addUpdateListener(this);
|
||||
return openAnimator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator valueAnimator) {
|
||||
mOpenAnimationProgress = valueAnimator.getAnimatedFraction();
|
||||
}
|
||||
|
||||
public boolean isOpenOrOpening() {
|
||||
return mOpenAnimationProgress > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an animator to play when the shortcut container is being closed.
|
||||
*/
|
||||
public Animator createCloseAnimation(boolean isContainerAboveIcon, boolean pivotLeft,
|
||||
long duration) {
|
||||
Point center = getIconCenter();
|
||||
int arrowCenter = getResources().getDimensionPixelSize(pivotLeft ^ mIsRtl ?
|
||||
R.dimen.popup_arrow_horizontal_center_start :
|
||||
R.dimen.popup_arrow_horizontal_center_end);
|
||||
ValueAnimator closeAnimator = new ZoomRevealOutlineProvider(center.x, center.y,
|
||||
mPillRect, this, mIconView, isContainerAboveIcon, pivotLeft, arrowCenter)
|
||||
.createRevealAnimator(this, true);
|
||||
// Scale down the duration and interpolator according to the progress
|
||||
// that the open animation was at when the close started.
|
||||
closeAnimator.setDuration((long) (duration * mOpenAnimationProgress));
|
||||
closeAnimator.setInterpolator(new CloseInterpolator(mOpenAnimationProgress));
|
||||
closeAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mOpenAnimationProgress = 0;
|
||||
}
|
||||
});
|
||||
return closeAnimator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the position of the center of the icon relative to the container.
|
||||
*/
|
||||
public Point getIconCenter() {
|
||||
sTempPoint.y = getMeasuredHeight() / 2;
|
||||
sTempPoint.x = getResources().getDimensionPixelSize(R.dimen.bg_popup_item_height) / 2;
|
||||
if (Utilities.isRtl(getResources())) {
|
||||
sTempPoint.x = getMeasuredWidth() - sTempPoint.x;
|
||||
}
|
||||
return sTempPoint;
|
||||
public void setBackgroundWithCorners(int color, @RoundedCornerFlags int roundedCorners) {
|
||||
mRoundedCorners = roundedCorners;
|
||||
float rTop = (roundedCorners & ROUNDED_TOP_CORNERS) == 0 ? 0 : getBackgroundRadius();
|
||||
float rBot = (roundedCorners & ROUNDED_BOTTOM_CORNERS) == 0 ? 0 : getBackgroundRadius();
|
||||
float[] radii = new float[] {rTop, rTop, rTop, rTop, rBot, rBot, rBot, rBot};
|
||||
ShapeDrawable roundRectBackground = new ShapeDrawable(new RoundRectShape(radii, null, null));
|
||||
roundRectBackground.getPaint().setColor(color);
|
||||
setBackground(roundRectBackground);
|
||||
}
|
||||
|
||||
protected float getBackgroundRadius() {
|
||||
return getResources().getDimensionPixelSize(R.dimen.bg_round_rect_radius);
|
||||
}
|
||||
|
||||
public abstract int getArrowColor(boolean isArrowAttachedToBottom);
|
||||
|
||||
/**
|
||||
* Extension of {@link PillRevealOutlineProvider} which scales the icon based on the height.
|
||||
*/
|
||||
private static class ZoomRevealOutlineProvider extends PillRevealOutlineProvider {
|
||||
|
||||
private final View mTranslateView;
|
||||
private final View mZoomView;
|
||||
|
||||
private final float mFullHeight;
|
||||
private final float mTranslateYMultiplier;
|
||||
|
||||
private final boolean mPivotLeft;
|
||||
private final float mTranslateX;
|
||||
private final float mArrowCenter;
|
||||
|
||||
public ZoomRevealOutlineProvider(int x, int y, Rect pillRect, PopupItemView translateView,
|
||||
View zoomView, boolean isContainerAboveIcon, boolean pivotLeft, float arrowCenter) {
|
||||
super(x, y, pillRect, translateView.getBackgroundRadius());
|
||||
mTranslateView = translateView;
|
||||
mZoomView = zoomView;
|
||||
mFullHeight = pillRect.height();
|
||||
|
||||
mTranslateYMultiplier = isContainerAboveIcon ? 0.5f : -0.5f;
|
||||
|
||||
mPivotLeft = pivotLeft;
|
||||
mTranslateX = pivotLeft ? arrowCenter : pillRect.right - arrowCenter;
|
||||
mArrowCenter = arrowCenter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProgress(float progress) {
|
||||
super.setProgress(progress);
|
||||
|
||||
if (mZoomView != null) {
|
||||
mZoomView.setScaleX(progress);
|
||||
mZoomView.setScaleY(progress);
|
||||
}
|
||||
|
||||
float height = mOutline.height();
|
||||
mTranslateView.setTranslationY(mTranslateYMultiplier * (mFullHeight - height));
|
||||
|
||||
float offsetX = Math.min(mOutline.width(), mArrowCenter);
|
||||
float pivotX = mPivotLeft ? (mOutline.left + offsetX) : (mOutline.right - offsetX);
|
||||
mTranslateView.setTranslationX(mTranslateX - pivotX);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An interpolator that reverses the current open animation progress.
|
||||
*/
|
||||
private static class CloseInterpolator extends LogAccelerateInterpolator {
|
||||
private float mStartProgress;
|
||||
private float mRemainingProgress;
|
||||
|
||||
/**
|
||||
* @param openAnimationProgress The progress that the open interpolator ended at.
|
||||
*/
|
||||
public CloseInterpolator(float openAnimationProgress) {
|
||||
super(100, 0);
|
||||
mStartProgress = 1f - openAnimationProgress;
|
||||
mRemainingProgress = openAnimationProgress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getInterpolation(float v) {
|
||||
return mStartProgress + super.getInterpolation(v) * mRemainingProgress;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,12 +16,10 @@
|
|||
|
||||
package com.android.launcher3.shortcuts;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.content.Context;
|
||||
import android.graphics.Point;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
|
@ -30,9 +28,7 @@ import com.android.launcher3.AbstractFloatingView;
|
|||
import com.android.launcher3.BubbleTextView;
|
||||
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;
|
||||
|
@ -135,7 +131,17 @@ public class ShortcutsItemView extends PopupItemView implements View.OnLongClick
|
|||
if (mSystemShortcutIcons == null) {
|
||||
mSystemShortcutIcons = (LinearLayout) mLauncher.getLayoutInflater().inflate(
|
||||
R.layout.system_shortcut_icons, mShortcutsLayout, false);
|
||||
mShortcutsLayout.addView(mSystemShortcutIcons, 0);
|
||||
|
||||
View divider = LayoutInflater.from(getContext()).inflate(
|
||||
R.layout.horizontal_divider, this, false);
|
||||
|
||||
if (mShortcutsLayout.getChildCount() > 0) {
|
||||
mShortcutsLayout.addView(divider);
|
||||
}
|
||||
mShortcutsLayout.addView(mSystemShortcutIcons);
|
||||
if (mShortcutsLayout.getChildCount() == 1) {
|
||||
mShortcutsLayout.addView(divider);
|
||||
}
|
||||
}
|
||||
mSystemShortcutIcons.addView(shortcutView, index);
|
||||
} else {
|
||||
|
@ -209,51 +215,6 @@ public class ShortcutsItemView extends PopupItemView implements View.OnLongClick
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Animator createOpenAnimation(boolean isContainerAboveIcon, boolean pivotLeft) {
|
||||
AnimatorSet openAnimation = LauncherAnimUtils.createAnimatorSet();
|
||||
openAnimation.play(super.createOpenAnimation(isContainerAboveIcon, pivotLeft));
|
||||
for (int i = 0; i < mShortcutsLayout.getChildCount(); i++) {
|
||||
if (!(mShortcutsLayout.getChildAt(i) instanceof DeepShortcutView)) {
|
||||
continue;
|
||||
}
|
||||
DeepShortcutView shortcutView = ((DeepShortcutView) mShortcutsLayout.getChildAt(i));
|
||||
View deepShortcutIcon = shortcutView.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 < mShortcutsLayout.getChildCount(); i++) {
|
||||
if (!(mShortcutsLayout.getChildAt(i) instanceof DeepShortcutView)) {
|
||||
continue;
|
||||
}
|
||||
DeepShortcutView shortcutView = ((DeepShortcutView) mShortcutsLayout.getChildAt(i));
|
||||
View deepShortcutIcon = shortcutView.getIconView();
|
||||
deepShortcutIcon.setScaleX(1);
|
||||
deepShortcutIcon.setScaleY(1);
|
||||
closeAnimation.play(LauncherAnimUtils.ofPropertyValuesHolder(
|
||||
deepShortcutIcon, new PropertyListBuilder().scale(0).build()));
|
||||
}
|
||||
return closeAnimation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getArrowColor(boolean isArrowAttachedToBottom) {
|
||||
return ContextCompat.getColor(getContext(),
|
||||
isArrowAttachedToBottom || mSystemShortcutIcons == null
|
||||
? R.color.popup_background_color
|
||||
: R.color.popup_header_background_color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillInLogContainerData(View v, ItemInfo info, LauncherLogProto.Target target,
|
||||
LauncherLogProto.Target targetParent) {
|
||||
|
|
Loading…
Reference in New Issue