7f3526a1a4
- Use smaller radius for notifications round rect background - Remove "Notifications" header, and clip children to round rect path - Flip main notification so that icon shows on the right instead of left; footer is also flipped so animation makes sense - Clean up animations to animate view outline instead of height Bug: 32410600 Change-Id: I6bd1e1f8395b3703f28c3b0056a89e67672368ab
218 lines
7.5 KiB
Java
218 lines
7.5 KiB
Java
/*
|
|
* 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.popup;
|
|
|
|
import android.animation.Animator;
|
|
import android.animation.AnimatorListenerAdapter;
|
|
import android.animation.ValueAnimator;
|
|
import android.content.Context;
|
|
import android.content.res.ColorStateList;
|
|
import android.graphics.Point;
|
|
import android.graphics.Rect;
|
|
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.util.PillRevealOutlineProvider;
|
|
import com.android.launcher3.util.PillWidthRevealOutlineProvider;
|
|
|
|
/**
|
|
* An abstract {@link FrameLayout} that supports animating an item's content
|
|
* (e.g. icon and text) separate from the item's background.
|
|
*/
|
|
public abstract class PopupItemView extends FrameLayout
|
|
implements ValueAnimator.AnimatorUpdateListener {
|
|
|
|
protected static final Point sTempPoint = new Point();
|
|
|
|
protected final Rect mPillRect;
|
|
private float mOpenAnimationProgress;
|
|
|
|
protected View mIconView;
|
|
|
|
public PopupItemView(Context context) {
|
|
this(context, null, 0);
|
|
}
|
|
|
|
public PopupItemView(Context context, AttributeSet attrs) {
|
|
this(context, attrs, 0);
|
|
}
|
|
|
|
public PopupItemView(Context context, AttributeSet attrs, int defStyle) {
|
|
super(context, attrs, defStyle);
|
|
|
|
mPillRect = new Rect();
|
|
}
|
|
|
|
@Override
|
|
protected void onFinishInflate() {
|
|
super.onFinishInflate();
|
|
mIconView = findViewById(R.id.popup_item_icon);
|
|
}
|
|
|
|
@Override
|
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
|
mPillRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight());
|
|
}
|
|
|
|
protected ColorStateList getAttachedArrowColor() {
|
|
return getBackgroundTintList();
|
|
}
|
|
|
|
public boolean willDrawIcon() {
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Creates an animator to play when the shortcut container is being opened.
|
|
*/
|
|
public Animator createOpenAnimation(boolean isContainerAboveIcon, boolean pivotLeft) {
|
|
Point center = getIconCenter();
|
|
ValueAnimator openAnimator = new ZoomRevealOutlineProvider(center.x, center.y,
|
|
mPillRect, this, mIconView, isContainerAboveIcon, pivotLeft)
|
|
.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();
|
|
ValueAnimator closeAnimator = new ZoomRevealOutlineProvider(center.x, center.y,
|
|
mPillRect, this, mIconView, isContainerAboveIcon, pivotLeft)
|
|
.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;
|
|
}
|
|
|
|
/**
|
|
* 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() {
|
|
sTempPoint.y = sTempPoint.x = getMeasuredHeight() / 2;
|
|
if (Utilities.isRtl(getResources())) {
|
|
sTempPoint.x = getMeasuredWidth() - sTempPoint.x;
|
|
}
|
|
return sTempPoint;
|
|
}
|
|
|
|
protected float getBackgroundRadius() {
|
|
return getResources().getDimensionPixelSize(R.dimen.bg_pill_radius);
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
|
|
public ZoomRevealOutlineProvider(int x, int y, Rect pillRect, PopupItemView translateView,
|
|
View zoomView, boolean isContainerAboveIcon, boolean pivotLeft) {
|
|
super(x, y, pillRect, translateView.getBackgroundRadius());
|
|
mTranslateView = translateView;
|
|
mZoomView = zoomView;
|
|
mFullHeight = pillRect.height();
|
|
|
|
mTranslateYMultiplier = isContainerAboveIcon ? 0.5f : -0.5f;
|
|
|
|
mPivotLeft = pivotLeft;
|
|
mTranslateX = pivotLeft ? pillRect.height() / 2 : pillRect.right - pillRect.height() / 2;
|
|
}
|
|
|
|
@Override
|
|
public void setProgress(float progress) {
|
|
super.setProgress(progress);
|
|
|
|
mZoomView.setScaleX(progress);
|
|
mZoomView.setScaleY(progress);
|
|
|
|
float height = mOutline.height();
|
|
mTranslateView.setTranslationY(mTranslateYMultiplier * (mFullHeight - height));
|
|
|
|
float pivotX = mPivotLeft ? (mOutline.left + height / 2) : (mOutline.right - height / 2);
|
|
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;
|
|
}
|
|
}
|
|
}
|