summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJon Miranda <jonmiranda@google.com>2019-04-16 20:53:24 -0700
committerJon Miranda <jonmiranda@google.com>2019-04-19 15:13:10 -0700
commitde0093dfa5e5ffe128a64ad7b767b6b3e650473b (patch)
treec696ad8c300a0fded0c6d1cd888b4d6c9ca3f304 /src
parent0f8c7c0e91c7d5edb4193e436ad1d2a5671bb96c (diff)
downloadandroid_packages_apps_Trebuchet-de0093dfa5e5ffe128a64ad7b767b6b3e650473b.tar.gz
android_packages_apps_Trebuchet-de0093dfa5e5ffe128a64ad7b767b6b3e650473b.tar.bz2
android_packages_apps_Trebuchet-de0093dfa5e5ffe128a64ad7b767b6b3e650473b.zip
Add ListenerView so that we can fast finish the FloatingIconView fade anim.
This change allows us to quickly end the animation if the user begins interacting with launcher before the animation is over. This can currently happen when the user swipes up to go home, and then quickly swipes up again to enter overview. Bug: 129421279 Change-Id: I88c7d55ef8ac09f999c082317de3bb3693c11466
Diffstat (limited to 'src')
-rw-r--r--src/com/android/launcher3/AbstractFloatingView.java11
-rw-r--r--src/com/android/launcher3/views/FloatingIconView.java131
-rw-r--r--src/com/android/launcher3/views/ListenerView.java86
3 files changed, 181 insertions, 47 deletions
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 0e082760a..3cb6ba67f 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -30,6 +30,7 @@ import android.util.AttributeSet;
import android.util.Pair;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.LinearLayout;
import androidx.annotation.IntDef;
@@ -58,6 +59,7 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
TYPE_ON_BOARD_POPUP,
TYPE_DISCOVERY_BOUNCE,
TYPE_SNACKBAR,
+ TYPE_LISTENER,
TYPE_TASK_MENU,
TYPE_OPTIONS_POPUP
@@ -72,15 +74,16 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
public static final int TYPE_ON_BOARD_POPUP = 1 << 5;
public static final int TYPE_DISCOVERY_BOUNCE = 1 << 6;
public static final int TYPE_SNACKBAR = 1 << 7;
+ public static final int TYPE_LISTENER = 1 << 8;
// Popups related to quickstep UI
- public static final int TYPE_TASK_MENU = 1 << 8;
- public static final int TYPE_OPTIONS_POPUP = 1 << 9;
+ public static final int TYPE_TASK_MENU = 1 << 9;
+ public static final int TYPE_OPTIONS_POPUP = 1 << 10;
public static final int TYPE_ALL = TYPE_FOLDER | TYPE_ACTION_POPUP
| TYPE_WIDGETS_BOTTOM_SHEET | TYPE_WIDGET_RESIZE_FRAME | TYPE_WIDGETS_FULL_SHEET
| TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE | TYPE_TASK_MENU
- | TYPE_OPTIONS_POPUP | TYPE_SNACKBAR;
+ | TYPE_OPTIONS_POPUP | TYPE_SNACKBAR | TYPE_LISTENER;
// Type of popups which should be kept open during launcher rebind
public static final int TYPE_REBIND_SAFE = TYPE_WIDGETS_FULL_SHEET
@@ -90,7 +93,7 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
public static final int TYPE_HIDE_BACK_BUTTON = TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE
| TYPE_SNACKBAR;
- public static final int TYPE_ACCESSIBLE = TYPE_ALL & ~TYPE_DISCOVERY_BOUNCE;
+ public static final int TYPE_ACCESSIBLE = TYPE_ALL & ~TYPE_DISCOVERY_BOUNCE & ~TYPE_LISTENER;
// These view all have particular operation associated with swipe down interaction.
public static final int TYPE_STATUS_BAR_SWIPE_DOWN_DISALLOW = TYPE_WIDGETS_BOTTOM_SHEET |
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index f96652eba..f2fc7182a 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -70,7 +70,7 @@ import static com.android.launcher3.Utilities.mapToRange;
public class FloatingIconView extends View implements Animator.AnimatorListener, ClipPathView {
public static final float SHAPE_PROGRESS_DURATION = 0.15f;
-
+ private static final int FADE_DURATION_MS = 200;
private static final Rect sTmpRect = new Rect();
private Runnable mEndRunnable;
@@ -93,10 +93,15 @@ public class FloatingIconView extends View implements Animator.AnimatorListener,
private float mBgDrawableStartScale = 1f;
private float mBgDrawableEndScale = 1f;
+ private AnimatorSet mFadeAnimatorSet;
+ private ListenerView mListenerView;
+
private FloatingIconView(Context context) {
super(context);
+
mBlurSizeOutline = context.getResources().getDimensionPixelSize(
R.dimen.blur_size_medium_outline);
+ mListenerView = new ListenerView(context, null);
}
/**
@@ -138,6 +143,12 @@ public class FloatingIconView extends View implements Animator.AnimatorListener,
if (mRevealAnimator == null) {
mRevealAnimator = (ValueAnimator) FolderShape.getShape().createRevealAnimator(this,
mStartRevealRect, mEndRevealRect, mTaskCornerRadius / scale, !isOpening);
+ mRevealAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mRevealAnimator = null;
+ }
+ });
mRevealAnimator.start();
// We pause here so we can set the current fraction ourselves.
mRevealAnimator.pause();
@@ -314,7 +325,7 @@ public class FloatingIconView extends View implements Animator.AnimatorListener,
@WorkerThread
private int getOffsetForIconBounds(Drawable drawable) {
- if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O ||
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O ||
!(drawable instanceof AdaptiveIconDrawable)) {
return 0;
}
@@ -364,6 +375,18 @@ public class FloatingIconView extends View implements Animator.AnimatorListener,
}
}
+ public void onListenerViewClosed() {
+ // Fast finish here.
+ if (mEndRunnable != null) {
+ mEndRunnable.run();
+ mEndRunnable = null;
+ }
+ if (mFadeAnimatorSet != null) {
+ mFadeAnimatorSet.end();
+ mFadeAnimatorSet = null;
+ }
+ }
+
@Override
public void onAnimationStart(Animator animator) {}
@@ -410,52 +433,69 @@ public class FloatingIconView extends View implements Animator.AnimatorListener,
// We need to add it to the overlay, but keep it invisible until animation starts..
final DragLayer dragLayer = launcher.getDragLayer();
view.setVisibility(INVISIBLE);
- ((ViewGroup) dragLayer.getParent()).getOverlay().add(view);
+ ((ViewGroup) dragLayer.getParent()).addView(view);
+ dragLayer.addView(view.mListenerView);
+ view.mListenerView.setListener(view::onListenerViewClosed);
- if (hideOriginal) {
- view.mEndRunnable = () -> {
- AnimatorSet fade = new AnimatorSet();
- fade.setDuration(200);
- fade.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- originalView.setVisibility(VISIBLE);
- }
+ view.mEndRunnable = () -> {
+ view.mEndRunnable = null;
- @Override
- public void onAnimationEnd(Animator animation) {
- ((ViewGroup) dragLayer.getParent()).getOverlay().remove(view);
+ if (hideOriginal) {
+ if (isOpening) {
+ originalView.setVisibility(VISIBLE);
+ view.finish(dragLayer);
+ } else {
+ view.mFadeAnimatorSet = view.createFadeAnimation(originalView, dragLayer);
+ view.mFadeAnimatorSet.start();
+ }
+ } else {
+ view.finish(dragLayer);
+ }
+ };
+ return view;
+ }
- if (view.mRevealAnimator != null) {
- view.mRevealAnimator.end();
- }
- }
- });
+ private AnimatorSet createFadeAnimation(View originalView, DragLayer dragLayer) {
+ AnimatorSet fade = new AnimatorSet();
+ fade.setDuration(FADE_DURATION_MS);
+ fade.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ originalView.setVisibility(VISIBLE);
+ }
- if (originalView instanceof FolderIcon) {
- FolderIcon folderIcon = (FolderIcon) originalView;
- folderIcon.setBackgroundVisible(false);
- folderIcon.getFolderName().setTextVisibility(false);
- fade.play(folderIcon.getFolderName().createTextAlphaAnimator(true));
- fade.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- folderIcon.setBackgroundVisible(true);
- folderIcon.animateBgShadowAndStroke();
- if (folderIcon.hasDot()) {
- folderIcon.animateDotScale(0, 1f);
- }
- }
- });
- } else {
- fade.play(ObjectAnimator.ofFloat(originalView, ALPHA, 0f, 1f));
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ finish(dragLayer);
+ }
+ });
+
+ if (originalView instanceof FolderIcon) {
+ FolderIcon folderIcon = (FolderIcon) originalView;
+ folderIcon.setBackgroundVisible(false);
+ folderIcon.getFolderName().setTextVisibility(false);
+ fade.play(folderIcon.getFolderName().createTextAlphaAnimator(true));
+ fade.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ folderIcon.setBackgroundVisible(true);
+ folderIcon.animateBgShadowAndStroke();
+ if (folderIcon.hasDot()) {
+ folderIcon.animateDotScale(0, 1f);
+ }
}
- fade.start();
- // TODO: Do not run fade animation until we fix b/129421279.
- fade.end();
- };
+ });
+ } else {
+ fade.play(ObjectAnimator.ofFloat(originalView, ALPHA, 0f, 1f));
}
- return view;
+
+ return fade;
+ }
+
+ private void finish(DragLayer dragLayer) {
+ ((ViewGroup) dragLayer.getParent()).removeView(this);
+ dragLayer.removeView(mListenerView);
+ recycle();
}
private void recycle() {
@@ -475,10 +515,15 @@ public class FloatingIconView extends View implements Animator.AnimatorListener,
mBackground = null;
mClipPath = null;
mFinalDrawableBounds.setEmpty();
- mBgDrawableBounds.setEmpty();;
+ mBgDrawableBounds.setEmpty();
if (mRevealAnimator != null) {
mRevealAnimator.cancel();
}
mRevealAnimator = null;
+ if (mFadeAnimatorSet != null) {
+ mFadeAnimatorSet.cancel();
+ }
+ mFadeAnimatorSet = null;
+ mListenerView.setListener(null);
}
}
diff --git a/src/com/android/launcher3/views/ListenerView.java b/src/com/android/launcher3/views/ListenerView.java
new file mode 100644
index 000000000..263f7c4c3
--- /dev/null
+++ b/src/com/android/launcher3/views/ListenerView.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2019 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.views;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.launcher3.AbstractFloatingView;
+
+/**
+ * An invisible AbstractFloatingView that can run a callback when it is being closed.
+ */
+public class ListenerView extends AbstractFloatingView {
+
+ public Runnable mCloseListener;
+
+ public ListenerView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setVisibility(View.GONE);
+ }
+
+ public void setListener(Runnable listener) {
+ mCloseListener = listener;
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mIsOpen = true;
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mIsOpen = false;
+ }
+
+ @Override
+ protected void handleClose(boolean animate) {
+ if (mIsOpen) {
+ if (mCloseListener != null) {
+ mCloseListener.run();
+ } else {
+ if (getParent() instanceof ViewGroup) {
+ ((ViewGroup) getParent()).removeView(this);
+ }
+ }
+ }
+ mIsOpen = false;
+ }
+
+ @Override
+ public void logActionCommand(int command) {
+ // Users do not interact with FloatingIconView, so there is nothing to log here.
+ }
+
+ @Override
+ protected boolean isOfType(int type) {
+ return (type & TYPE_LISTENER) != 0;
+ }
+
+ @Override
+ public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ handleClose(false);
+ }
+ // We want other views to be able to intercept the touch so we return false here.
+ return false;
+ }
+}