Loading src/com/android/launcher3/AbstractFloatingView.java +7 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading @@ -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 Loading @@ -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 | Loading src/com/android/launcher3/views/FloatingIconView.java +88 −43 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); } /** Loading Loading @@ -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(); Loading Loading @@ -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; } Loading Loading @@ -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) {} Loading Loading @@ -410,12 +433,31 @@ 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 = () -> { view.mEndRunnable = null; 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; } private AnimatorSet createFadeAnimation(View originalView, DragLayer dragLayer) { AnimatorSet fade = new AnimatorSet(); fade.setDuration(200); fade.setDuration(FADE_DURATION_MS); fade.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { Loading @@ -424,11 +466,7 @@ public class FloatingIconView extends View implements Animator.AnimatorListener, @Override public void onAnimationEnd(Animator animation) { ((ViewGroup) dragLayer.getParent()).getOverlay().remove(view); if (view.mRevealAnimator != null) { view.mRevealAnimator.end(); } finish(dragLayer); } }); Loading @@ -450,12 +488,14 @@ public class FloatingIconView extends View implements Animator.AnimatorListener, } else { fade.play(ObjectAnimator.ofFloat(originalView, ALPHA, 0f, 1f)); } fade.start(); // TODO: Do not run fade animation until we fix b/129421279. fade.end(); }; return fade; } return view; private void finish(DragLayer dragLayer) { ((ViewGroup) dragLayer.getParent()).removeView(this); dragLayer.removeView(mListenerView); recycle(); } private void recycle() { Loading @@ -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); } } src/com/android/launcher3/views/ListenerView.java 0 → 100644 +86 −0 Original line number Diff line number Diff line /* * 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; } } Loading
src/com/android/launcher3/AbstractFloatingView.java +7 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading @@ -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 Loading @@ -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 | Loading
src/com/android/launcher3/views/FloatingIconView.java +88 −43 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); } /** Loading Loading @@ -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(); Loading Loading @@ -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; } Loading Loading @@ -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) {} Loading Loading @@ -410,12 +433,31 @@ 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 = () -> { view.mEndRunnable = null; 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; } private AnimatorSet createFadeAnimation(View originalView, DragLayer dragLayer) { AnimatorSet fade = new AnimatorSet(); fade.setDuration(200); fade.setDuration(FADE_DURATION_MS); fade.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { Loading @@ -424,11 +466,7 @@ public class FloatingIconView extends View implements Animator.AnimatorListener, @Override public void onAnimationEnd(Animator animation) { ((ViewGroup) dragLayer.getParent()).getOverlay().remove(view); if (view.mRevealAnimator != null) { view.mRevealAnimator.end(); } finish(dragLayer); } }); Loading @@ -450,12 +488,14 @@ public class FloatingIconView extends View implements Animator.AnimatorListener, } else { fade.play(ObjectAnimator.ofFloat(originalView, ALPHA, 0f, 1f)); } fade.start(); // TODO: Do not run fade animation until we fix b/129421279. fade.end(); }; return fade; } return view; private void finish(DragLayer dragLayer) { ((ViewGroup) dragLayer.getParent()).removeView(this); dragLayer.removeView(mListenerView); recycle(); } private void recycle() { Loading @@ -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); } }
src/com/android/launcher3/views/ListenerView.java 0 → 100644 +86 −0 Original line number Diff line number Diff line /* * 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; } }