Merge "Extract TaskbarViewCallbacks to a separate class + factory." into main
diff --git a/quickstep/res/drawable/view_carousel.xml b/quickstep/res/drawable/view_carousel.xml
new file mode 100644
index 0000000..16c8e78
--- /dev/null
+++ b/quickstep/res/drawable/view_carousel.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <group>
+ <clip-path
+ android:pathData="M0,0h24v24h-24z"/>
+ <path
+ android:pathData="M17,19H7V4H17V19ZM6,6H2V17H6V6ZM9,6H15V17H9V6ZM22,6H18V17H22V6Z"
+ android:fillColor="#ffffff"
+ android:fillType="evenOdd"/>
+ </group>
+</vector>
diff --git a/quickstep/res/layout/keyboard_quick_switch_overview.xml b/quickstep/res/layout/keyboard_quick_switch_overview.xml
index 4a9b023..30ca32d 100644
--- a/quickstep/res/layout/keyboard_quick_switch_overview.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_overview.xml
@@ -40,7 +40,7 @@
android:layout_width="@dimen/keyboard_quick_switch_recents_icon_size"
android:layout_height="@dimen/keyboard_quick_switch_recents_icon_size"
android:layout_marginBottom="8dp"
- android:src="@drawable/ic_empty_recents"
+ android:src="@drawable/view_carousel"
android:tint="?androidprv:attr/materialColorOnSurface"
app:layout_constraintVertical_chainStyle="packed"
diff --git a/quickstep/res/layout/keyboard_quick_switch_view.xml b/quickstep/res/layout/keyboard_quick_switch_view.xml
index 3256b0b..2bba788 100644
--- a/quickstep/res/layout/keyboard_quick_switch_view.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_view.xml
@@ -42,7 +42,7 @@
android:layout_width="@dimen/keyboard_quick_switch_no_recent_items_icon_size"
android:layout_height="@dimen/keyboard_quick_switch_no_recent_items_icon_size"
android:layout_marginBottom="@dimen/keyboard_quick_switch_no_recent_items_icon_margin"
- android:src="@drawable/ic_empty_recents"
+ android:src="@drawable/view_carousel"
android:tint="?androidprv:attr/materialColorOnSurface"
android:importantForAccessibility="no"
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
index 2421c94..3e262e5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
@@ -32,7 +32,6 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
-import com.android.launcher3.taskbar.overlay.TaskbarOverlayDragLayer;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.SlideInRemoteTransition;
@@ -84,9 +83,7 @@
boolean updateTasks,
int currentFocusIndexOverride,
boolean onDesktop) {
- TaskbarOverlayDragLayer dragLayer = mOverlayContext.getDragLayer();
- dragLayer.addView(mKeyboardQuickSwitchView);
- dragLayer.runOnClickOnce(v -> closeQuickSwitchView(true));
+ mOverlayContext.getDragLayer().addView(mKeyboardQuickSwitchView);
mOnDesktop = onDesktop;
mKeyboardQuickSwitchView.applyLoadPlan(
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index b8e6889..aa457ca 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -24,11 +24,13 @@
import android.inputmethodservice.InputMethodService.ENABLE_HIDE_IME_CAPTION_BAR
import android.os.Binder
import android.os.IBinder
+import android.view.DisplayInfo
import android.view.Gravity
import android.view.InsetsFrameProvider
import android.view.InsetsFrameProvider.SOURCE_DISPLAY
import android.view.InsetsSource.FLAG_INSETS_ROUNDED_CORNER
import android.view.InsetsSource.FLAG_SUPPRESS_SCRIM
+import android.view.Surface
import android.view.ViewTreeObserver
import android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME
import android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION
@@ -155,19 +157,20 @@
}
val gravity = windowLayoutParams.gravity
- for (provider in windowLayoutParams.providedInsets) {
- setProviderInsets(provider, gravity)
- }
- if (windowLayoutParams.paramsForRotation != null) {
+ // Pre-calculate insets for different providers across different rotations for this gravity
+ for (rotation in Surface.ROTATION_0..Surface.ROTATION_270) {
// Add insets for navbar rotated params
- for (layoutParams in windowLayoutParams.paramsForRotation) {
+ if (windowLayoutParams.paramsForRotation != null) {
+ val layoutParams = windowLayoutParams.paramsForRotation[rotation]
for (provider in layoutParams.providedInsets) {
- setProviderInsets(provider, layoutParams.gravity)
+ setProviderInsets(provider, layoutParams.gravity, rotation)
}
}
+ for (provider in windowLayoutParams.providedInsets) {
+ setProviderInsets(provider, gravity, rotation)
+ }
}
-
context.notifyUpdateLayoutParams()
}
@@ -211,12 +214,12 @@
)
}
- private fun setProviderInsets(provider: InsetsFrameProvider, gravity: Int) {
+ private fun setProviderInsets(provider: InsetsFrameProvider, gravity: Int, endRotation: Int) {
val contentHeight = controllers.taskbarStashController.contentHeightToReportToApps
val tappableHeight = controllers.taskbarStashController.tappableHeightToReportToApps
val res = context.resources
if (provider.type == navigationBars() || provider.type == mandatorySystemGestures()) {
- provider.insetsSize = getInsetsForGravity(contentHeight, gravity)
+ provider.insetsSize = getInsetsForGravityWithCutout(contentHeight, gravity, endRotation)
} else if (provider.type == tappableElement()) {
provider.insetsSize = getInsetsForGravity(tappableHeight, gravity)
} else if (provider.type == systemGestures() && provider.index == INDEX_LEFT) {
@@ -275,6 +278,30 @@
}
/**
+ * Calculate the [Insets] for taskbar after a rotation, specifically for any potential cutouts
+ * in the screen that can come from the camera.
+ */
+ private fun getInsetsForGravityWithCutout(inset: Int, gravity: Int, rot: Int): Insets {
+ val display = context.display
+ // If there is no cutout, fall back to the original method of calculating insets
+ val cutout = display.cutout ?: return getInsetsForGravity(inset, gravity)
+ val rotation = display.rotation
+ val info = DisplayInfo()
+ display.getDisplayInfo(info)
+ val rotatedCutout = cutout.getRotated(info.logicalWidth, info.logicalHeight, rotation, rot)
+
+ if ((gravity and Gravity.BOTTOM) == Gravity.BOTTOM) {
+ return Insets.of(0, 0, 0, maxOf(inset, rotatedCutout.safeInsetBottom))
+ }
+
+ // TODO(b/230394142): seascape
+ val isSeascape = (gravity and Gravity.START) == Gravity.START
+ val leftInset = if (isSeascape) maxOf(inset, rotatedCutout.safeInsetLeft) else 0
+ val rightInset = if (isSeascape) 0 else maxOf(inset, rotatedCutout.safeInsetRight)
+ return Insets.of(leftInset, 0, rightInset, 0)
+ }
+
+ /**
* @return [Insets] where the [inset] is either used as a bottom inset or right/left inset if
* using 3 button nav
*/
@@ -309,9 +336,11 @@
controllers.bubbleControllers.isPresent &&
controllers.bubbleControllers.get().bubbleBarViewController.isBubbleBarVisible()
var insetsIsTouchableRegion = true
- if (context.isPhoneButtonNavMode &&
- (!controllers.navbarButtonsViewController.isImeVisible
- || !controllers.navbarButtonsViewController.isImeRenderingNavButtons)) {
+ if (
+ context.isPhoneButtonNavMode &&
+ (!controllers.navbarButtonsViewController.isImeVisible ||
+ !controllers.navbarButtonsViewController.isImeRenderingNavButtons)
+ ) {
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME)
insetsIsTouchableRegion = false
} else if (context.dragLayer.alpha < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index f3db0ee..8db343f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -802,6 +802,11 @@
private void addJankMonitorListener(
AnimatorSet animator, boolean expanding, @StashAnimation int animationType) {
View v = mControllers.taskbarActivityContext.getDragLayer();
+ if (!v.isAttachedToWindow()) {
+ // If the task bar drag layer is not attached to window, we don't need to monitor jank
+ // (actually we can't pass in an unattached view either).
+ return;
+ }
int action = expanding ? InteractionJankMonitor.CUJ_TASKBAR_EXPAND :
InteractionJankMonitor.CUJ_TASKBAR_COLLAPSE;
animator.addListener(new AnimatorListenerAdapter() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
index 432d272..9c3e8af 100644
--- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
@@ -40,7 +40,6 @@
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
/** Root drag layer for the Taskbar overlay window. */
public class TaskbarOverlayDragLayer extends
@@ -48,28 +47,6 @@
ViewTreeObserver.OnComputeInternalInsetsListener {
private SafeCloseable mViewCaptureCloseable;
- private final List<OnClickListener> mOnClickListeners = new CopyOnWriteArrayList<>();
- private final TouchController mClickListenerTouchController = new TouchController() {
- @Override
- public boolean onControllerTouchEvent(MotionEvent ev) {
- if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
- for (OnClickListener listener : mOnClickListeners) {
- listener.onClick(TaskbarOverlayDragLayer.this);
- }
- }
- return false;
- }
-
- @Override
- public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
- for (int i = 0; i < getChildCount(); i++) {
- if (isEventOverView(getChildAt(i), ev)) {
- return false;
- }
- }
- return true;
- }
- };
private final List<TouchController> mTouchControllers = new ArrayList<>();
TaskbarOverlayDragLayer(Context context) {
@@ -98,9 +75,6 @@
List<TouchController> controllers = new ArrayList<>();
controllers.add(mActivity.getDragController());
controllers.addAll(mTouchControllers);
- if (!mOnClickListeners.isEmpty()) {
- controllers.add(mClickListenerTouchController);
- }
mControllers = controllers.toArray(new TouchController[0]);
}
@@ -152,51 +126,6 @@
mActivity.getOverlayController().maybeCloseWindow();
}
- /**
- * Adds the given callback to clicks to this drag layer.
- * <p>
- * Clicks are only accepted on this drag layer if they fall within this drag layer's bounds and
- * outside the bounds of all child views.
- * <p>
- * If the click falls within the bounds of a child view, then this callback does not run and
- * that child can optionally handle it.
- */
- private void addOnClickListener(@NonNull OnClickListener listener) {
- boolean wasEmpty = mOnClickListeners.isEmpty();
- mOnClickListeners.add(listener);
- if (wasEmpty) {
- recreateControllers();
- }
- }
-
- /**
- * Removes the given on click callback.
- * <p>
- * No-op if the callback was never added.
- */
- private void removeOnClickListener(@NonNull OnClickListener listener) {
- boolean wasEmpty = mOnClickListeners.isEmpty();
- mOnClickListeners.remove(listener);
- if (!wasEmpty && mOnClickListeners.isEmpty()) {
- recreateControllers();
- }
- }
-
- /**
- * Queues the given callback on the next click on this drag layer.
- * <p>
- * Once run, this callback is immediately removed.
- */
- public void runOnClickOnce(@NonNull OnClickListener listener) {
- addOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- listener.onClick(v);
- removeOnClickListener(this);
- }
- });
- }
-
/** Adds a {@link TouchController} to this drag layer. */
public void addTouchController(@NonNull TouchController touchController) {
mTouchControllers.add(touchController);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
index 0650f9d..72218bf 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -55,14 +55,12 @@
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
import android.animation.ValueAnimator;
-import android.util.Log;
import com.android.launcher3.CellLayout;
import com.android.launcher3.Hotseat;
import com.android.launcher3.LauncherState;
import com.android.launcher3.Workspace;
import com.android.launcher3.states.StateAnimationConfig;
-import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.touch.AllAppsSwipeController;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.DisplayController;
@@ -96,8 +94,6 @@
@Override
public void prepareForAtomicAnimation(LauncherState fromState, LauncherState toState,
StateAnimationConfig config) {
- Log.d(TestProtocol.OVERVIEW_OVER_HOME, "creating animation fromState: "
- + fromState + " toState: " + toState);
RecentsView overview = mActivity.getOverviewPanel();
if ((fromState == OVERVIEW || fromState == OVERVIEW_SPLIT_SELECT) && toState == NORMAL) {
overview.switchToScreenshot(() ->
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 879312d..2341e4c 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -425,11 +425,14 @@
if (activity == null) {
return null;
}
+ RecentsView recentsView = activity.getOverviewPanel();
STATE_TYPE state = stateFromGestureEndTarget(endTarget);
ScrimView scrimView = activity.getScrimView();
ObjectAnimator anim = ObjectAnimator.ofArgb(scrimView, VIEW_BACKGROUND_COLOR,
getOverviewScrimColorForState(activity, state));
anim.setDuration(duration);
+ anim.setInterpolator(recentsView == null || !recentsView.isKeyboardTaskFocusPending()
+ ? LINEAR : INSTANT);
return anim;
}
return null;
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 9bb9775a..a27875a 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -31,7 +31,6 @@
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.MotionEvent;
import androidx.annotation.Nullable;
@@ -45,7 +44,6 @@
import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.statemanager.StateManager.StateListener;
-import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.PendingSplitSelectInfo;
import com.android.launcher3.util.SplitConfigurationOptions;
@@ -187,8 +185,6 @@
@Override
public void setOverviewStateEnabled(boolean enabled) {
super.setOverviewStateEnabled(enabled);
- Log.d(TestProtocol.OVERVIEW_OVER_HOME, "overview state enabled state has changed: "
- + enabled);
if (enabled) {
LauncherState state = mActivity.getStateManager().getState();
boolean hasClearAllButton = (state.getVisibleElements(mActivity)
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
index 87cbdd1..02a49a3 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
@@ -1,12 +1,12 @@
package com.android.launcher3.taskbar.navbutton
+import android.content.res.Configuration
import android.content.res.Resources
import android.view.Surface
import android.view.Surface.ROTATION_270
import android.view.Surface.Rotation
import android.view.View
import android.view.ViewGroup
-import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.Space
@@ -14,7 +14,9 @@
import com.android.launcher3.DeviceProfile
import com.android.launcher3.R
import com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION
-import com.android.launcher3.taskbar.TaskbarManager
+import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_END_CONTEXTUAL_BUTTONS
+import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_END_NAV_BUTTONS
+import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_START_CONTEXTUAL_BUTTONS
import com.android.systemui.shared.rotation.RotationButton
import java.lang.IllegalStateException
import org.junit.Assume.assumeTrue
@@ -40,6 +42,7 @@
private val mockRotationButton: RotationButton = mock()
private val mockA11yButton: ImageView = mock()
private val mockSpace: Space = mock()
+ private val mockConfiguration: Configuration = mock();
private var surfaceRotation = Surface.ROTATION_0
@@ -52,12 +55,15 @@
whenever(mockNavLayout.findViewById<View>(R.id.recent_apps)).thenReturn(mockRecentsButton)
// Init top level layout
- whenever(mockParentButtonContainer.findViewById<LinearLayout>(R.id.end_nav_buttons))
+ whenever(mockParentButtonContainer.requireViewById<LinearLayout>(ID_END_NAV_BUTTONS))
.thenReturn(mockNavLayout)
- whenever(mockParentButtonContainer.findViewById<ViewGroup>(R.id.end_contextual_buttons))
+ whenever(mockParentButtonContainer.requireViewById<ViewGroup>(ID_END_CONTEXTUAL_BUTTONS))
.thenReturn(mockEndContextualLayout)
- whenever(mockParentButtonContainer.findViewById<ViewGroup>(R.id.start_contextual_buttons))
+ whenever(mockParentButtonContainer.requireViewById<ViewGroup>(ID_START_CONTEXTUAL_BUTTONS))
.thenReturn(mockStartContextualLayout)
+ whenever(mockBackButton.resources).thenReturn(mockResources)
+ whenever(mockResources.configuration).thenReturn(mockConfiguration)
+ whenever(mockConfiguration.layoutDirection).thenReturn(0)
}
@Test
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 496cb4e..2b203e1 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -258,7 +258,7 @@
import com.android.systemui.plugins.LauncherOverlayPlugin;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.shared.LauncherOverlayManager;
-import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlay;
+import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayTouchProxy;
import com.android.wm.shell.Flags;
import java.io.FileDescriptor;
@@ -2810,7 +2810,7 @@
/**
* Call this after onCreate to set or clear overlay.
*/
- public void setLauncherOverlay(LauncherOverlay overlay) {
+ public void setLauncherOverlay(LauncherOverlayTouchProxy overlay) {
mWorkspace.setLauncherOverlay(overlay);
}
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index ca83245..1fede56 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -1140,7 +1140,7 @@
mEdgeGlowLeft.onPullDistance(0f, 1f - displacement);
}
if (!mEdgeGlowRight.isFinished()) {
- mEdgeGlowRight.onPullDistance(0f, displacement);
+ mEdgeGlowRight.onPullDistance(0f, displacement, ev);
}
}
@@ -1320,10 +1320,10 @@
int consumed = 0;
if (delta < 0 && mEdgeGlowRight.getDistance() != 0f) {
consumed = Math.round(size *
- mEdgeGlowRight.onPullDistance(delta / size, displacement));
+ mEdgeGlowRight.onPullDistance(delta / size, displacement, ev));
} else if (delta > 0 && mEdgeGlowLeft.getDistance() != 0f) {
consumed = Math.round(-size *
- mEdgeGlowLeft.onPullDistance(-delta / size, 1 - displacement));
+ mEdgeGlowLeft.onPullDistance(-delta / size, 1 - displacement, ev));
}
delta -= consumed;
}
@@ -1341,14 +1341,14 @@
final float pulledToX = oldScroll + delta;
if (pulledToX < mMinScroll) {
- mEdgeGlowLeft.onPullDistance(-delta / size, 1.f - displacement);
+ mEdgeGlowLeft.onPullDistance(-delta / size, 1.f - displacement, ev);
if (!mEdgeGlowRight.isFinished()) {
- mEdgeGlowRight.onRelease();
+ mEdgeGlowRight.onRelease(ev);
}
} else if (pulledToX > mMaxScroll) {
- mEdgeGlowRight.onPullDistance(delta / size, displacement);
+ mEdgeGlowRight.onPullDistance(delta / size, displacement, ev);
if (!mEdgeGlowLeft.isFinished()) {
- mEdgeGlowLeft.onRelease();
+ mEdgeGlowLeft.onRelease(ev);
}
}
@@ -1356,7 +1356,6 @@
postInvalidateOnAnimation();
}
}
-
} else {
awakenScrollBars();
}
@@ -1456,10 +1455,11 @@
}
invalidate();
}
+ mEdgeGlowLeft.onFlingVelocity(velocity);
+ mEdgeGlowRight.onFlingVelocity(velocity);
}
-
- mEdgeGlowLeft.onRelease();
- mEdgeGlowRight.onRelease();
+ mEdgeGlowLeft.onRelease(ev);
+ mEdgeGlowRight.onRelease(ev);
// End any intermediate reordering states
resetTouchState();
break;
@@ -1468,8 +1468,8 @@
if (mIsBeingDragged) {
runOnPageScrollsInitialized(this::snapToDestination);
}
- mEdgeGlowLeft.onRelease();
- mEdgeGlowRight.onRelease();
+ mEdgeGlowLeft.onRelease(ev);
+ mEdgeGlowRight.onRelease(ev);
resetTouchState();
break;
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index ac0d7ce..86f31a1 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -125,8 +125,8 @@
import com.android.launcher3.widget.WidgetManagerHelper;
import com.android.launcher3.widget.dragndrop.AppWidgetHostViewDragListener;
import com.android.launcher3.widget.util.WidgetSizes;
-import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlay;
import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayCallbacks;
+import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayTouchProxy;
import java.util.ArrayList;
import java.util.Iterator;
@@ -1237,7 +1237,7 @@
mLauncher.onPageEndTransition();
}
- public void setLauncherOverlay(LauncherOverlay overlay) {
+ public void setLauncherOverlay(LauncherOverlayTouchProxy overlay) {
final EdgeEffectCompat newEffect;
if (overlay == null) {
newEffect = new EdgeEffectCompat(getContext());
diff --git a/src/com/android/launcher3/statemanager/StateManager.java b/src/com/android/launcher3/statemanager/StateManager.java
index e8b3066..e6e7133 100644
--- a/src/com/android/launcher3/statemanager/StateManager.java
+++ b/src/com/android/launcher3/statemanager/StateManager.java
@@ -38,7 +38,6 @@
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
import com.android.launcher3.states.StateAnimationConfig.AnimationPropertyFlags;
-import com.android.launcher3.testing.shared.TestProtocol;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -52,6 +51,8 @@
public class StateManager<STATE_TYPE extends BaseState<STATE_TYPE>> {
public static final String TAG = "StateManager";
+ // b/279059025
+ private static final boolean DEBUG = true;
private final AnimationState mConfig = new AnimationState();
private final Handler mUiHandler;
@@ -231,15 +232,18 @@
private void goToState(
STATE_TYPE state, boolean animated, long delay, AnimatorListener listener) {
- String stackTrace = Log.getStackTraceString(new Exception("tracing state transition"));
- String truncatedTrace =
- Arrays.stream(stackTrace.split("\\n"))
- .limit(5)
- .skip(1) // Removes the line "java.lang.Exception: tracing state transition"
- .filter(traceLine -> !traceLine.contains("StateManager.goToState"))
- .collect(Collectors.joining("\n"));
- Log.d(TestProtocol.OVERVIEW_OVER_HOME,
- "go to state " + state + " partial trace:\n" + truncatedTrace);
+ if (DEBUG) {
+ String stackTrace = Log.getStackTraceString(new Exception("tracing state transition"));
+ String truncatedTrace =
+ Arrays.stream(stackTrace.split("\\n"))
+ .limit(5)
+ .skip(1) // Removes the line "java.lang.Exception: tracing state
+ // transition"
+ .filter(traceLine -> !traceLine.contains("StateManager.goToState"))
+ .collect(Collectors.joining("\n"));
+ Log.d(TAG, "goToState - fromState: " + mState + ", toState: " + state
+ + ", partial trace:\n" + truncatedTrace);
+ }
animated &= areAnimatorsEnabled();
if (mActivity.isInState(state)) {
@@ -324,6 +328,20 @@
*/
public AnimatorSet createAtomicAnimation(
STATE_TYPE fromState, STATE_TYPE toState, StateAnimationConfig config) {
+ if (DEBUG) {
+ String stackTrace = Log.getStackTraceString(new Exception("tracing state transition"));
+ String truncatedTrace =
+ Arrays.stream(stackTrace.split("\\n"))
+ .limit(5)
+ .skip(1) // Removes the line "java.lang.Exception: tracing state
+ // transition"
+ .filter(traceLine -> !traceLine.contains(
+ "StateManager.createAtomicAnimation"))
+ .collect(Collectors.joining("\n"));
+ Log.d(TAG, "createAtomicAnimation - fromState: " + fromState + ", toState: " + toState
+ + ", partial trace:\n" + truncatedTrace);
+ }
+
PendingAnimation builder = new PendingAnimation(config.duration);
prepareForAtomicAnimation(fromState, toState, config);
@@ -395,8 +413,9 @@
mState = state;
mActivity.onStateSetStart(mState);
- Log.d(TestProtocol.OVERVIEW_OVER_HOME, "Notifying listeners for state transition start"
- + " to state: " + state.toString());
+ if (DEBUG) {
+ Log.d(TAG, "onStateTransitionStart - state: " + state);
+ }
for (int i = mListeners.size() - 1; i >= 0; i--) {
mListeners.get(i).onStateTransitionStart(state);
}
@@ -414,8 +433,9 @@
setRestState(null);
}
- Log.d(TestProtocol.OVERVIEW_OVER_HOME, "Notifying " + mListeners.size() + " listeners "
- + "for end transition for state: " + state.toString());
+ if (DEBUG) {
+ Log.d(TAG, "onStateTransitionEnd - state: " + state);
+ }
for (int i = mListeners.size() - 1; i >= 0; i--) {
mListeners.get(i).onStateTransitionComplete(state);
}
@@ -453,7 +473,9 @@
* Cancels the current animation.
*/
public void cancelAnimation() {
- Log.d(TestProtocol.OVERVIEW_OVER_HOME, "current animation cancelled");
+ if (DEBUG && mConfig.currentAnimation != null) {
+ Log.d(TAG, "cancelAnimation - with ongoing animation");
+ }
mConfig.reset();
// It could happen that a new animation is set as a result of an endListener on the
// existing animation.
@@ -485,7 +507,6 @@
* @param toState The state we are animating towards.
*/
public void setCurrentAnimation(AnimatorSet anim, STATE_TYPE toState) {
- Log.d(TestProtocol.OVERVIEW_OVER_HOME, "setting animation to " + toState.toString());
cancelAnimation();
setCurrentAnimation(anim);
anim.addListener(createStateAnimationListener(toState));
diff --git a/src/com/android/launcher3/util/EdgeEffectCompat.java b/src/com/android/launcher3/util/EdgeEffectCompat.java
index 491582b..ca37259 100644
--- a/src/com/android/launcher3/util/EdgeEffectCompat.java
+++ b/src/com/android/launcher3/util/EdgeEffectCompat.java
@@ -16,6 +16,7 @@
package com.android.launcher3.util;
import android.content.Context;
+import android.view.MotionEvent;
import android.widget.EdgeEffect;
import com.android.launcher3.Utilities;
@@ -43,4 +44,14 @@
return deltaDistance;
}
}
+
+ public float onPullDistance(float deltaDistance, float displacement, MotionEvent ev) {
+ return onPullDistance(deltaDistance, displacement);
+ }
+
+ public void onFlingVelocity(int velocity) { }
+
+ public void onRelease(MotionEvent ev) {
+ onRelease();
+ }
}
diff --git a/src/com/android/launcher3/util/OverlayEdgeEffect.java b/src/com/android/launcher3/util/OverlayEdgeEffect.java
index 2ef1e1f..d09d801 100644
--- a/src/com/android/launcher3/util/OverlayEdgeEffect.java
+++ b/src/com/android/launcher3/util/OverlayEdgeEffect.java
@@ -17,10 +17,13 @@
import android.content.Context;
import android.graphics.Canvas;
+import android.os.SystemClock;
+import android.view.MotionEvent;
import android.widget.EdgeEffect;
+import com.android.launcher3.BuildConfig;
import com.android.launcher3.Utilities;
-import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlay;
+import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayTouchProxy;
/**
* Extension of {@link EdgeEffect} which shows the Launcher overlay
@@ -28,11 +31,11 @@
public class OverlayEdgeEffect extends EdgeEffectCompat {
protected float mDistance;
- protected final LauncherOverlay mOverlay;
+ protected final LauncherOverlayTouchProxy mOverlay;
protected boolean mIsScrolling;
protected final boolean mIsRtl;
- public OverlayEdgeEffect(Context context, LauncherOverlay overlay) {
+ public OverlayEdgeEffect(Context context, LauncherOverlayTouchProxy overlay) {
super(context);
mOverlay = overlay;
mIsRtl = Utilities.isRtl(context.getResources());
@@ -44,12 +47,30 @@
}
public float onPullDistance(float deltaDistance, float displacement) {
+ // Fallback implementation, will never actually get called
+ if (BuildConfig.IS_DEBUG_DEVICE) {
+ throw new RuntimeException("Wrong method called");
+ }
+ MotionEvent mv = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
+ MotionEvent.ACTION_MOVE, displacement, 0, 0);
+ try {
+ return onPullDistance(deltaDistance, displacement, mv);
+ } finally {
+ mv.recycle();
+ }
+ }
+
+ @Override
+ public float onPullDistance(float deltaDistance, float displacement, MotionEvent ev) {
mDistance = Math.max(0f, deltaDistance + mDistance);
if (!mIsScrolling) {
- mOverlay.onScrollInteractionBegin();
+ int originalAction = ev.getAction();
+ ev.setAction(MotionEvent.ACTION_DOWN);
+ mOverlay.onOverlayMotionEvent(ev, 0);
+ ev.setAction(originalAction);
mIsScrolling = true;
}
- mOverlay.onScrollChange(mDistance, mIsRtl);
+ mOverlay.onOverlayMotionEvent(ev, mDistance);
return mDistance > 0 ? deltaDistance : 0;
}
@@ -63,9 +84,30 @@
@Override
public void onRelease() {
+ // Fallback implementation, will never actually get called
+ if (BuildConfig.IS_DEBUG_DEVICE) {
+ throw new RuntimeException("Wrong method called");
+ }
+ MotionEvent mv = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
+ MotionEvent.ACTION_UP, mDistance, 0, 0);
+ onRelease(mv);
+ mv.recycle();
+ }
+
+ @Override
+ public void onFlingVelocity(int velocity) {
+ mOverlay.onFlingVelocity(velocity);
+ }
+
+ @Override
+ public void onRelease(MotionEvent ev) {
if (mIsScrolling) {
+ int originalAction = ev.getAction();
+ ev.setAction(MotionEvent.ACTION_UP);
+ mOverlay.onOverlayMotionEvent(ev, mDistance);
+ ev.setAction(originalAction);
+
mDistance = 0;
- mOverlay.onScrollInteractionEnd();
mIsScrolling = false;
}
}
diff --git a/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java b/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java
index 54cc0bc..a940774 100644
--- a/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java
+++ b/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java
@@ -15,6 +15,8 @@
*/
package com.android.systemui.plugins.shared;
+import android.view.MotionEvent;
+
import java.io.PrintWriter;
/**
@@ -47,7 +49,11 @@
default void onActivityDestroyed() { }
- interface LauncherOverlay {
+ /**
+ * @deprecated use LauncherOverlayTouchProxy directly
+ */
+ @Deprecated
+ interface LauncherOverlay extends LauncherOverlayTouchProxy {
/**
* Touch interaction leading to overscroll has begun
@@ -70,6 +76,38 @@
* @param callbacks A set of callbacks provided by Launcher in relation to the overlay
*/
void setOverlayCallbacks(LauncherOverlayCallbacks callbacks);
+
+ @Override
+ default void onFlingVelocity(float velocity) { }
+
+ @Override
+ default void onOverlayMotionEvent(MotionEvent ev, float scrollProgress) {
+ switch (ev.getAction()) {
+ case MotionEvent.ACTION_DOWN -> onScrollInteractionBegin();
+ case MotionEvent.ACTION_MOVE -> onScrollChange(scrollProgress, false);
+ case MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> onScrollInteractionEnd();
+ }
+
+ }
+ }
+
+ interface LauncherOverlayTouchProxy {
+
+ /**
+ * Called just before finishing scroll interaction to indicate the fling velocity
+ */
+ void onFlingVelocity(float velocity);
+
+ /**
+ * Called to dispatch various motion events to the overlay
+ */
+ void onOverlayMotionEvent(MotionEvent ev, float scrollProgress);
+
+ /**
+ * Called when the launcher is ready to use the overlay
+ * @param callbacks A set of callbacks provided by Launcher in relation to the overlay
+ */
+ default void setOverlayCallbacks(LauncherOverlayCallbacks callbacks) { }
}
interface LauncherOverlayCallbacks {
diff --git a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index 8d40ff2..c750c7e 100644
--- a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -167,7 +167,6 @@
public static final String TWO_NEXUS_LAUNCHER_ACTIVITY_WHILE_UNLOCKING = "b/273347463";
public static final String TWO_TASKBAR_LONG_CLICKS = "b/262282528";
public static final String ICON_MISSING = "b/282963545";
- public static final String OVERVIEW_OVER_HOME = "b/279059025";
public static final String REQUEST_EMULATE_DISPLAY = "emulate-display";
public static final String REQUEST_STOP_EMULATE_DISPLAY = "stop-emulate-display";
diff --git a/tests/multivalentTests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java b/tests/multivalentTests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
index 8eebdb2..5ef63da 100644
--- a/tests/multivalentTests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
+++ b/tests/multivalentTests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
@@ -14,6 +14,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import java.util.concurrent.TimeUnit;
public class PortraitLandscapeRunner implements TestRule {
private static final String TAG = "PortraitLandscapeRunner";
@@ -49,7 +50,8 @@
mTest.mDevice.pressHome();
mTest.waitForLauncherCondition("Launcher activity wasn't created",
- launcher -> launcher != null);
+ launcher -> launcher != null,
+ TimeUnit.SECONDS.toMillis(20));
mTest.executeOnLauncher(launcher ->
launcher.getRotationHelper().forceAllowRotationForTesting(