Merge "Use equals() to compare UserHandle when building LauncherAtom#ItemInfo." into sc-v2-dev
diff --git a/Android.bp b/Android.bp
index c8d9186..d04dca0 100644
--- a/Android.bp
+++ b/Android.bp
@@ -152,9 +152,13 @@
],
srcs: [
"src/**/*.java",
+ "src/**/*.kt",
"src_shortcuts_overrides/**/*.java",
+ "src_shortcuts_overrides/**/*.kt",
"src_ui_overrides/**/*.java",
+ "src_ui_overrides/**/*.kt",
"ext_tests/src/**/*.java",
+ "ext_tests/src/**/*.kt",
],
resource_dirs: [
"ext_tests/res",
@@ -211,7 +215,10 @@
// Source code used for test helpers
filegroup {
name: "launcher-src-ext-tests",
- srcs: ["ext_tests/src/**/*.java"],
+ srcs: [
+ "ext_tests/src/**/*.java",
+ "ext_tests/src/**/*.kt",
+ ],
}
// Common source files used to build launcher
@@ -219,8 +226,11 @@
name: "launcher-src-no-build-config",
srcs: [
"src/**/*.java",
+ "src/**/*.kt",
"src_shortcuts_overrides/**/*.java",
+ "src_shortcuts_overrides/**/*.kt",
"quickstep/src/**/*.java",
+ "quickstep/src/**/*.kt",
],
}
@@ -235,9 +245,13 @@
name: "LauncherGoResLib",
srcs: [
"src/**/*.java",
+ "src/**/*.kt",
"quickstep/src/**/*.java",
+ "quickstep/src/**/*.kt",
"go/src/**/*.java",
+ "go/src/**/*.kt",
"go/quickstep/src/**/*.java",
+ "go/quickstep/src/**/*.kt",
],
resource_dirs: [
"go/res",
diff --git a/Android.mk b/Android.mk
index c1dbc53..ceaaf13 100644
--- a/Android.mk
+++ b/Android.mk
@@ -105,7 +105,7 @@
LOCAL_SDK_VERSION := system_current
LOCAL_MIN_SDK_VERSION := 26
endif
-LOCAL_STATIC_ANDROID_LIBRARIES := Launcher3CommonDepsLib
+LOCAL_STATIC_ANDROID_LIBRARIES := LauncherGoResLib
LOCAL_SRC_FILES := \
$(call all-java-files-under, src) \
diff --git a/quickstep/res/layout/rotate_suggestion.xml b/quickstep/res/layout/rotate_suggestion.xml
new file mode 100644
index 0000000..07cf0c8
--- /dev/null
+++ b/quickstep/res/layout/rotate_suggestion.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 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
+ -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
+ <com.android.systemui.shared.rotation.FloatingRotationButtonView
+ android:id="@+id/rotate_suggestion"
+ android:layout_width="@dimen/floating_rotation_button_diameter"
+ android:layout_height="@dimen/floating_rotation_button_diameter"
+ android:paddingStart="@dimen/navigation_key_padding"
+ android:paddingEnd="@dimen/navigation_key_padding"
+ android:layout_gravity="bottom|left"
+ android:scaleType="center"
+ android:visibility="invisible" />
+</FrameLayout>
diff --git a/quickstep/res/values-sw600dp/dimens.xml b/quickstep/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..5d9e059
--- /dev/null
+++ b/quickstep/res/values-sw600dp/dimens.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ * Copyright (c) 2021, 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.
+*/
+-->
+<resources>
+ <dimen name="navigation_key_padding">25dp</dimen>
+</resources>
diff --git a/quickstep/res/values-sw900dp/dimens.xml b/quickstep/res/values-sw900dp/dimens.xml
new file mode 100644
index 0000000..3efa5e3
--- /dev/null
+++ b/quickstep/res/values-sw900dp/dimens.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ * Copyright (c) 2021, 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.
+*/
+-->
+<resources>
+ <!-- The maximum width of the navigation bar ripples. -->
+ <dimen name="key_button_ripple_max_width">76dp</dimen>
+
+ <!-- The padding around the navigation buttons -->
+ <dimen name="navigation_key_padding">0dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/quickstep/res/values/colors.xml b/quickstep/res/values/colors.xml
index fb2ee1c..f237d26 100644
--- a/quickstep/res/values/colors.xml
+++ b/quickstep/res/values/colors.xml
@@ -30,6 +30,9 @@
<color name="taskbar_stashed_handle_light_color">#EBffffff</color>
<color name="taskbar_stashed_handle_dark_color">#99000000</color>
+ <color name="rotation_button_light_color">#FFF</color>
+ <color name="rotation_button_dark_color">#99000000</color>
+
<!-- Gesture navigation tutorial -->
<color name="gesture_tutorial_back_arrow_color">#FFFFFFFF</color>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 4ebf5cf..98d43f1 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -197,6 +197,19 @@
<!-- Minimum distance to swipe to trigger accessibility gesture -->
<dimen name="accessibility_gesture_min_swipe_distance">80dp</dimen>
+ <!-- The maximum width of the navigation bar ripples. -->
+ <dimen name="key_button_ripple_max_width">95dp</dimen>
+
+ <dimen name="rounded_corner_content_padding">0dp</dimen>
+
+ <dimen name="navigation_key_padding">0dp</dimen>
+
+ <!-- Floating rotation button -->
+ <dimen name="floating_rotation_button_diameter">40dp</dimen>
+ <dimen name="floating_rotation_button_min_margin">20dp</dimen>
+ <dimen name="floating_rotation_button_taskbar_left_margin">20dp</dimen>
+ <dimen name="floating_rotation_button_taskbar_bottom_margin">10dp</dimen>
+
<!-- Taskbar -->
<dimen name="taskbar_size">@*android:dimen/taskbar_frame_height</dimen>
<dimen name="taskbar_icon_touch_size">48dp</dimen>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 88c98c0..151b8e4 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -208,6 +208,9 @@
<!-- Button text shown on a button on the tutorial skip dialog to exit the tutorial. [CHAR LIMIT=14] -->
<string name="gesture_tutorial_action_button_label_skip">Skip</string>
+ <!-- Accessibility label for the rotation suggestion button -->
+ <string name="accessibility_rotate_button">Rotate screen</string>
+
<!-- ******* Taskbar Edu ******* -->
<!-- Accessibility text spoken when the taskbar education panel appears [CHAR_LIMIT=NONE] -->
<string name="taskbar_edu_opened">Taskbar education appeared</string>
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 8a05533..7e5bda5 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -110,7 +110,6 @@
import com.android.quickstep.RemoteAnimationTargets;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskViewUtils;
-import com.android.quickstep.util.AppCloseConfig;
import com.android.quickstep.util.MultiValueUpdateListener;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.RemoteAnimationProvider;
@@ -1338,12 +1337,11 @@
RectFSpringAnim.OnUpdateListener runner = new SpringAnimRunner(targets, targetRect) {
@Override
- public void onUpdate(@Nullable AppCloseConfig values, RectF currentRectF,
- float progress) {
+ public void onUpdate(RectF currentRectF, float progress) {
finalFloatingIconView.update(1f, 255 /* fgAlpha */, currentRectF, progress,
windowAlphaThreshold, getCornerRadius(progress), false);
- super.onUpdate(values, currentRectF, progress);
+ super.onUpdate(currentRectF, progress);
}
};
anim.addOnUpdateListener(runner);
@@ -1356,8 +1354,7 @@
FloatingWidgetView finalFloatingWidget = floatingWidget;
RectFSpringAnim.OnUpdateListener runner = new SpringAnimRunner(targets, targetRect) {
@Override
- public void onUpdate(@Nullable AppCloseConfig values, RectF currentRectF,
- float progress) {
+ public void onUpdate(RectF currentRectF, float progress) {
final float fallbackBackgroundAlpha =
1 - mapBoundToRange(progress, 0.8f, 1, 0, 1, EXAGGERATED_EASE);
final float foregroundAlpha =
@@ -1365,7 +1362,7 @@
finalFloatingWidget.update(currentRectF, floatingWidgetAlpha, foregroundAlpha,
fallbackBackgroundAlpha, 1 - progress);
- super.onUpdate(values, currentRectF, progress);
+ super.onUpdate(currentRectF, progress);
}
};
anim.addOnUpdateListener(runner);
@@ -1776,7 +1773,7 @@
}
@Override
- public void onUpdate(@Nullable AppCloseConfig values, RectF currentRectF, float progress) {
+ public void onUpdate(RectF currentRectF, float progress) {
SurfaceParams[] params = new SurfaceParams[mAppTargets.length];
for (int i = mAppTargets.length - 1; i >= 0; i--) {
RemoteAnimationTargetCompat target = mAppTargets[i];
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 648a16e..bc6348d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -345,7 +345,8 @@
* @return Whether any Taskbar item could handle the given MotionEvent if given the chance.
*/
public boolean isEventOverAnyTaskbarItem(MotionEvent ev) {
- return mControllers.taskbarViewController.isEventOverAnyItem(ev);
+ return mControllers.taskbarViewController.isEventOverAnyItem(ev)
+ || mControllers.navbarButtonsViewController.isEventOverAnyItem(ev);
}
public boolean isDraggingItem() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index 113bd91..d35b0f6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.taskbar;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
+
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_A11Y;
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_A11Y_LONG_CLICK;
@@ -38,6 +40,7 @@
import android.annotation.DrawableRes;
import android.annotation.IdRes;
import android.annotation.LayoutRes;
+import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Rect;
import android.graphics.Region;
@@ -45,6 +48,7 @@
import android.graphics.drawable.AnimatedVectorDrawable;
import android.util.Property;
import android.view.Gravity;
+import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnHoverListener;
@@ -57,11 +61,12 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AlphaUpdateListener;
import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton;
-import com.android.launcher3.taskbar.contextual.RotationButton;
-import com.android.launcher3.taskbar.contextual.RotationButtonController;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.Themes;
import com.android.quickstep.AnimatedFloat;
+import com.android.systemui.shared.rotation.FloatingRotationButton;
+import com.android.systemui.shared.rotation.RotationButton;
+import com.android.systemui.shared.rotation.RotationButtonController;
import java.util.ArrayList;
import java.util.function.IntPredicate;
@@ -103,12 +108,16 @@
this::updateNavButtonTranslationY);
private final AnimatedFloat mNavButtonTranslationYMultiplier = new AnimatedFloat(
this::updateNavButtonTranslationY);
+ private final RotationButtonListener mRotationButtonListener = new RotationButtonListener();
+
+ private final Rect mFloatingRotationButtonBounds = new Rect();
// Initialized in init.
private TaskbarControllers mControllers;
private View mA11yButton;
private int mSysuiStateFlags;
private View mBackButton;
+ private FloatingRotationButton mFloatingRotationButton;
public NavbarButtonsViewController(TaskbarActivityContext context, FrameLayout navButtonsView) {
mContext = context;
@@ -198,9 +207,21 @@
addButton(mEndContextualContainer, R.id.rotate_suggestion,
R.layout.taskbar_contextual_button));
rotationButton.hide();
- mControllers.rotationButtonController.setRotationButton(rotationButton);
+ mControllers.rotationButtonController.setRotationButton(rotationButton, null);
} else {
- mControllers.rotationButtonController.setRotationButton(new RotationButton() {});
+ mFloatingRotationButton = new FloatingRotationButton(mContext,
+ R.string.accessibility_rotate_button,
+ R.layout.rotate_suggestion,
+ R.id.rotate_suggestion,
+ R.dimen.floating_rotation_button_min_margin,
+ R.dimen.rounded_corner_content_padding,
+ R.dimen.floating_rotation_button_taskbar_left_margin,
+ R.dimen.floating_rotation_button_taskbar_bottom_margin,
+ R.dimen.floating_rotation_button_diameter,
+ R.dimen.key_button_ripple_max_width);
+ mControllers.rotationButtonController.setRotationButton(mFloatingRotationButton,
+ mRotationButtonListener);
+
View imeDownButton = addButton(R.drawable.ic_sysbar_back, BUTTON_BACK,
mStartContextualContainer, mControllers.navButtonController, R.id.back);
imeDownButton.setRotation(Utilities.isRtl(mContext.getResources()) ? 90 : -90);
@@ -213,6 +234,14 @@
mPropertyHolders.forEach(StatePropertyHolder::endAnimation);
}
+ public void onDestroy() {
+ mPropertyHolders.clear();
+ mControllers.rotationButtonController.unregisterListeners();
+ if (mFloatingRotationButton != null) {
+ mFloatingRotationButton.hide();
+ }
+ }
+
private void initButtons(ViewGroup navContainer, ViewGroup endContainer,
TaskbarNavButtonController navButtonController) {
@@ -405,8 +434,20 @@
return buttonView;
}
- public void onDestroy() {
- mPropertyHolders.clear();
+ public boolean isEventOverAnyItem(MotionEvent ev) {
+ return mFloatingRotationButtonBounds.contains((int) ev.getX(), (int) ev.getY());
+ }
+
+ private class RotationButtonListener implements RotationButton.RotationButtonUpdatesCallback {
+ @Override
+ public void onVisibilityChanged(boolean isVisible) {
+ if (isVisible) {
+ mFloatingRotationButton.getCurrentView()
+ .getBoundsOnScreen(mFloatingRotationButtonBounds);
+ } else {
+ mFloatingRotationButtonBounds.setEmpty();
+ }
+ }
}
private class RotationButtonImpl implements RotationButton {
@@ -424,6 +465,8 @@
mImageDrawable = (AnimatedVectorDrawable) mButton.getContext()
.getDrawable(rotationButtonController.getIconResId());
mButton.setImageDrawable(mImageDrawable);
+ mButton.setContentDescription(mButton.getResources()
+ .getString(R.string.accessibility_rotate_button));
mImageDrawable.setCallback(mButton);
}
@@ -433,17 +476,19 @@
}
@Override
- public void show() {
+ public boolean show() {
mButton.setVisibility(View.VISIBLE);
mState |= FLAG_ROTATION_BUTTON_VISIBLE;
applyState();
+ return true;
}
@Override
- public void hide() {
+ public boolean hide() {
mButton.setVisibility(View.GONE);
mState &= ~FLAG_ROTATION_BUTTON_VISIBLE;
applyState();
+ return true;
}
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index db3156b..72d9d5b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -60,7 +60,6 @@
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.taskbar.contextual.RotationButtonController;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.SettingsCache;
@@ -71,6 +70,7 @@
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.rotation.RotationButtonController;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.WindowManagerWrapper;
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
@@ -147,8 +147,14 @@
new TaskbarDragController(this),
buttonController,
new NavbarButtonsViewController(this, navButtonsView),
- new RotationButtonController(this, R.color.popup_color_primary_light,
- R.color.popup_color_primary_light),
+ new RotationButtonController(this,
+ c.getColor(R.color.rotation_button_light_color),
+ c.getColor(R.color.rotation_button_dark_color),
+ R.drawable.ic_sysbar_rotate_button_ccw_start_0,
+ R.drawable.ic_sysbar_rotate_button_ccw_start_90,
+ R.drawable.ic_sysbar_rotate_button_cw_start_0,
+ R.drawable.ic_sysbar_rotate_button_cw_start_90,
+ () -> getDisplay().getRotation()),
new TaskbarDragLayerController(this, mDragLayer),
new TaskbarViewController(this, taskbarView),
new TaskbarScrimViewController(this, taskbarScrimView),
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index d739eea..08a79c0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -17,7 +17,7 @@
import androidx.annotation.NonNull;
-import com.android.launcher3.taskbar.contextual.RotationButtonController;
+import com.android.systemui.shared.rotation.RotationButtonController;
/**
* Hosts various taskbar controllers to facilitate passing between one another.
@@ -80,9 +80,7 @@
public void init(TaskbarSharedState sharedState) {
taskbarDragController.init(this);
navbarButtonsViewController.init(this);
- if (taskbarActivityContext.isThreeButtonNav()) {
- rotationButtonController.init();
- }
+ rotationButtonController.init();
taskbarDragLayerController.init(this);
taskbarViewController.init(this);
taskbarScrimViewController.init(this);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 5986e22..089c265 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -16,8 +16,7 @@
package com.android.launcher3.taskbar;
import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
import static com.android.launcher3.util.DisplayController.CHANGE_SUPPORTED_BOUNDS;
@@ -91,7 +90,7 @@
mSysUINavigationMode = SysUINavigationMode.INSTANCE.get(service);
Display display =
service.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY);
- mContext = service.createWindowContext(display, TYPE_APPLICATION_OVERLAY, null);
+ mContext = service.createWindowContext(display, TYPE_NAVIGATION_BAR_PANEL, null);
mNavButtonController = new TaskbarNavButtonController(service);
mUserSetupCompleteListener = isUserSetupComplete -> recreateTaskbar();
mComponentCallbacks = new ComponentCallbacks() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index d11eb36..acb4aa8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -94,6 +94,7 @@
private final SharedPreferences mPrefs;
private final int mStashedHeight;
private final int mUnstashedHeight;
+ private final SystemUiProxy mSystemUiProxy;
// Initialized in init.
private TaskbarControllers mControllers;
@@ -127,6 +128,7 @@
mPrefs = Utilities.getPrefs(mActivity);
final Resources resources = mActivity.getResources();
mStashedHeight = resources.getDimensionPixelSize(R.dimen.taskbar_stashed_size);
+ mSystemUiProxy = SystemUiProxy.INSTANCE.get(activity);
mUnstashedHeight = mActivity.getDeviceProfile().taskbarSize;
}
@@ -155,8 +157,7 @@
!mActivity.isUserSetupComplete() || sharedState.setupUIVisible);
applyState();
- SystemUiProxy.INSTANCE.get(mActivity)
- .notifyTaskbarStatus(/* visible */ false, /* stashed */ isStashedInApp());
+ notifyStashChange(/* visible */ false, /* stashed */ isStashedInApp());
}
/**
@@ -440,8 +441,7 @@
mControllers.uiController.onStashedInAppChanged();
}
if (hasAnyFlag(changedFlags, FLAGS_STASHED_IN_APP | FLAG_IN_APP)) {
- SystemUiProxy.INSTANCE.get(mActivity)
- .notifyTaskbarStatus(/* visible */ hasAnyFlag(FLAG_IN_APP),
+ notifyStashChange(/* visible */ hasAnyFlag(FLAG_IN_APP),
/* stashed */ isStashedInApp());
}
if (hasAnyFlag(changedFlags, FLAG_STASHED_IN_APP_MANUAL)) {
@@ -453,6 +453,11 @@
}
}
+ private void notifyStashChange(boolean visible, boolean stashed) {
+ mSystemUiProxy.notifyTaskbarStatus(visible, stashed);
+ mControllers.rotationButtonController.onTaskbarStateChange(visible, stashed);
+ }
+
private class StatePropertyHolder {
private final IntPredicate mStashCondition;
diff --git a/quickstep/src/com/android/launcher3/taskbar/contextual/RotationButton.java b/quickstep/src/com/android/launcher3/taskbar/contextual/RotationButton.java
deleted file mode 100644
index 4093097..0000000
--- a/quickstep/src/com/android/launcher3/taskbar/contextual/RotationButton.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2021 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.taskbar.contextual;
-
-import android.graphics.drawable.AnimatedVectorDrawable;
-import android.view.View;
-
-/**
- * Interface of a rotation button that interacts {@link RotationButtonController}.
- * This interface exists because of the two different styles of rotation button in Sysui,
- * one in contextual for 3 button nav and a floating rotation button for gestural.
- * Keeping the interface for eventual migration of floating button, so some methods are
- * pass through to "super" while others are trivially implemented.
- *
- * Changes:
- * * Directly use AnimatedVectorDrawable instead of KeyButtonDrawable
- */
-public interface RotationButton {
- default void setRotationButtonController(RotationButtonController rotationButtonController) { }
-
- default View getCurrentView() {
- return null;
- }
- default void show() { }
- default void hide() { }
- default boolean isVisible() {
- return false;
- }
-
- default void updateIcon(int lightIconColor, int darkIconColor) { }
- default void setOnClickListener(View.OnClickListener onClickListener) { }
- default void setOnHoverListener(View.OnHoverListener onHoverListener) { }
- default AnimatedVectorDrawable getImageDrawable() {
- return null;
- }
- default void setDarkIntensity(float darkIntensity) { }
- default boolean acceptRotationProposal() {
- return getCurrentView() != null;
- }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/contextual/RotationButtonController.java b/quickstep/src/com/android/launcher3/taskbar/contextual/RotationButtonController.java
deleted file mode 100644
index c776f16..0000000
--- a/quickstep/src/com/android/launcher3/taskbar/contextual/RotationButtonController.java
+++ /dev/null
@@ -1,512 +0,0 @@
-/*
- * Copyright 2021 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.taskbar.contextual;
-
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import static com.android.internal.view.RotationPolicy.NATURAL_ROTATION;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.annotation.ColorInt;
-import android.annotation.DrawableRes;
-import android.annotation.SuppressLint;
-import android.app.StatusBarManager;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.graphics.drawable.AnimatedVectorDrawable;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.RemoteException;
-import android.provider.Settings;
-import android.util.Log;
-import android.view.IRotationWatcher;
-import android.view.MotionEvent;
-import android.view.Surface;
-import android.view.View;
-import android.view.WindowInsetsController;
-import android.view.WindowManagerGlobal;
-import android.view.accessibility.AccessibilityManager;
-
-import com.android.internal.logging.UiEvent;
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.logging.UiEventLoggerImpl;
-import com.android.internal.view.RotationPolicy;
-import com.android.launcher3.R;
-import com.android.launcher3.util.DisplayController;
-import com.android.systemui.shared.recents.utilities.Utilities;
-import com.android.systemui.shared.recents.utilities.ViewRippler;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.TaskStackChangeListener;
-import com.android.systemui.shared.system.TaskStackChangeListeners;
-
-import java.util.Optional;
-
-/**
- * Copied over from the SysUI equivalent class. Known issues/things not ported over
- * * When rotation button visible and in auto-hide mode, we ask auto-hide controller to
- * keep the navbar around longer. Will need to implement if we use auto-hide on taskbar
- *
- * Contains logic that deals with showing a rotate suggestion button with animation.
- */
-public class RotationButtonController {
-
- private static final String TAG = "StatusBar/RotationButtonController";
- private static final int BUTTON_FADE_IN_OUT_DURATION_MS = 100;
- private static final int NAVBAR_HIDDEN_PENDING_ICON_TIMEOUT_MS = 20000;
-
- private static final int NUM_ACCEPTED_ROTATION_SUGGESTIONS_FOR_INTRODUCTION = 3;
-
- private final Context mContext;
- private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
- private final UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
- private final ViewRippler mViewRippler = new ViewRippler();
- private final DisplayController mDisplayController;
- private RotationButton mRotationButton;
-
- private int mLastRotationSuggestion;
- private boolean mPendingRotationSuggestion;
- private boolean mHoveringRotationSuggestion;
- private final AccessibilityManager mAccessibilityManager;
- private final TaskStackListenerImpl mTaskStackListener;
- private boolean mListenersRegistered = false;
- private boolean mIsTaskbarShowing;
- @SuppressLint("InlinedApi")
- private @WindowInsetsController.Behavior
- int mBehavior = WindowInsetsController.BEHAVIOR_DEFAULT;
- private boolean mSkipOverrideUserLockPrefsOnce;
- private final int mLightIconColor;
- private final int mDarkIconColor;
- private int mIconResId = R.drawable.ic_sysbar_rotate_button_ccw_start_90;
-
- private final Runnable mRemoveRotationProposal =
- () -> setRotateSuggestionButtonState(false /* visible */);
- private final Runnable mCancelPendingRotationProposal =
- () -> mPendingRotationSuggestion = false;
- private Animator mRotateHideAnimator;
-
-
- private final IRotationWatcher.Stub mRotationWatcher = new IRotationWatcher.Stub() {
- @Override
- public void onRotationChanged(final int rotation) {
- // We need this to be scheduled as early as possible to beat the redrawing of
- // window in response to the orientation change.
- mMainThreadHandler.postAtFrontOfQueue(() -> {
- // If the screen rotation changes while locked, potentially update lock to flow with
- // new screen rotation and hide any showing suggestions.
- if (isRotationLocked()) {
- if (shouldOverrideUserLockPrefs(rotation)) {
- setRotationLockedAtAngle(rotation);
- }
- setRotateSuggestionButtonState(false /* visible */, true /* forced */);
- }
- });
- }
- };
-
- /**
- * Determines if rotation suggestions disabled2 flag exists in flag
- * @param disable2Flags see if rotation suggestion flag exists in this flag
- * @return whether flag exists
- */
- static boolean hasDisable2RotateSuggestionFlag(int disable2Flags) {
- return (disable2Flags & StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS) != 0;
- }
-
- public RotationButtonController(Context context, @ColorInt int lightIconColor,
- @ColorInt int darkIconColor) {
- mContext = context;
- mLightIconColor = lightIconColor;
- mDarkIconColor = darkIconColor;
-
- mAccessibilityManager = AccessibilityManager.getInstance(context);
- mTaskStackListener = new TaskStackListenerImpl();
- mDisplayController = DisplayController.INSTANCE.get(context);
- }
-
- public void setRotationButton(RotationButton rotationButton) {
- mRotationButton = rotationButton;
- mRotationButton.setRotationButtonController(this);
- mRotationButton.setOnClickListener(this::onRotateSuggestionClick);
- mRotationButton.setOnHoverListener(this::onRotateSuggestionHover);
- }
-
- public void init() {
- registerListeners();
- if (mContext.getDisplay().getDisplayId() != DEFAULT_DISPLAY) {
- // Currently there is no accelerometer sensor on non-default display, disable fixed
- // rotation for non-default display
- onDisable2FlagChanged(StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS);
- }
- }
-
- public void onDestroy() {
- unregisterListeners();
- }
-
- private void registerListeners() {
- if (mListenersRegistered) {
- return;
- }
-
- mListenersRegistered = true;
- try {
- WindowManagerGlobal.getWindowManagerService()
- .watchRotation(mRotationWatcher, DEFAULT_DISPLAY);
- } catch (IllegalArgumentException e) {
- mListenersRegistered = false;
- Log.w(TAG, "RegisterListeners for the display failed");
- } catch (RemoteException e) {
- Log.e(TAG, "RegisterListeners caught a RemoteException", e);
- return;
- }
-
- TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener);
- }
-
- void unregisterListeners() {
- if (!mListenersRegistered) {
- return;
- }
-
- mListenersRegistered = false;
- try {
- WindowManagerGlobal.getWindowManagerService().removeRotationWatcher(mRotationWatcher);
- } catch (RemoteException e) {
- Log.e(TAG, "UnregisterListeners caught a RemoteException", e);
- return;
- }
-
- TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener);
- }
-
- void setRotationLockedAtAngle(int rotationSuggestion) {
- RotationPolicy.setRotationLockAtAngle(mContext, true, rotationSuggestion);
- }
-
- public boolean isRotationLocked() {
- return RotationPolicy.isRotationLocked(mContext);
- }
-
- public void setRotateSuggestionButtonState(boolean visible) {
- setRotateSuggestionButtonState(visible, false /* force */);
- }
-
- void setRotateSuggestionButtonState(final boolean visible, final boolean force) {
- // At any point the button can become invisible because an a11y service became active.
- // Similarly, a call to make the button visible may be rejected because an a11y service is
- // active. Must account for this.
- // Rerun a show animation to indicate change but don't rerun a hide animation
- if (!visible && !mRotationButton.isVisible()) return;
-
- final View view = mRotationButton.getCurrentView();
- if (view == null) return;
-
- final AnimatedVectorDrawable currentDrawable = mRotationButton.getImageDrawable();
- if (currentDrawable == null) return;
-
- // Clear any pending suggestion flag as it has either been nullified or is being shown
- mPendingRotationSuggestion = false;
- mMainThreadHandler.removeCallbacks(mCancelPendingRotationProposal);
-
- // Handle the visibility change and animation
- if (visible) { // Appear and change (cannot force)
- // Stop and clear any currently running hide animations
- if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) {
- mRotateHideAnimator.cancel();
- }
- mRotateHideAnimator = null;
-
- // Reset the alpha if any has changed due to hide animation
- view.setAlpha(1f);
-
- // Run the rotate icon's animation if it has one
- currentDrawable.reset();
- currentDrawable.start();
-
- // TODO(b/187754252): No idea why this doesn't work. If we remove the "false"
- // we see the animation show the pressed state... but it only shows the first time.
- if (!isRotateSuggestionIntroduced()) mViewRippler.start(view);
-
- // Set visibility unless a11y service is active.
- mRotationButton.show();
- } else { // Hide
- mViewRippler.stop(); // Prevent any pending ripples, force hide or not
-
- if (force) {
- // If a hide animator is running stop it and make invisible
- if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) {
- mRotateHideAnimator.pause();
- }
- mRotationButton.hide();
- return;
- }
-
- // Don't start any new hide animations if one is running
- if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) return;
-
- ObjectAnimator fadeOut = ObjectAnimator.ofFloat(view, "alpha", 0f);
- fadeOut.setDuration(BUTTON_FADE_IN_OUT_DURATION_MS);
- fadeOut.setInterpolator(LINEAR);
- fadeOut.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mRotationButton.hide();
- }
- });
-
- mRotateHideAnimator = fadeOut;
- fadeOut.start();
- }
- }
-
- void setDarkIntensity(float darkIntensity) {
- mRotationButton.setDarkIntensity(darkIntensity);
- }
-
- public void onRotationProposal(int rotation, boolean isValid) {
- int windowRotation = mDisplayController.getInfo().rotation;
-
- if (!mRotationButton.acceptRotationProposal()) {
- return;
- }
-
- // This method will be called on rotation suggestion changes even if the proposed rotation
- // is not valid for the top app. Use invalid rotation choices as a signal to remove the
- // rotate button if shown.
- if (!isValid) {
- setRotateSuggestionButtonState(false /* visible */);
- return;
- }
-
- // If window rotation matches suggested rotation, remove any current suggestions
- if (rotation == windowRotation) {
- mMainThreadHandler.removeCallbacks(mRemoveRotationProposal);
- setRotateSuggestionButtonState(false /* visible */);
- return;
- }
-
- // Prepare to show the navbar icon by updating the icon style to change anim params
- mLastRotationSuggestion = rotation; // Remember rotation for click
- final boolean rotationCCW = Utilities.isRotationAnimationCCW(windowRotation, rotation);
- if (windowRotation == Surface.ROTATION_0 || windowRotation == Surface.ROTATION_180) {
- mIconResId = rotationCCW
- ? R.drawable.ic_sysbar_rotate_button_ccw_start_90
- : R.drawable.ic_sysbar_rotate_button_cw_start_90;
- } else { // 90 or 270
- mIconResId = rotationCCW
- ? R.drawable.ic_sysbar_rotate_button_ccw_start_0
- : R.drawable.ic_sysbar_rotate_button_ccw_start_0;
- }
- mRotationButton.updateIcon(mLightIconColor, mDarkIconColor);
-
- if (canShowRotationButton()) {
- // The navbar is visible / it's in visual immersive mode, so show the icon right away
- showAndLogRotationSuggestion();
- } else {
- // If the navbar isn't shown, flag the rotate icon to be shown should the navbar become
- // visible given some time limit.
- mPendingRotationSuggestion = true;
- mMainThreadHandler.removeCallbacks(mCancelPendingRotationProposal);
- mMainThreadHandler.postDelayed(mCancelPendingRotationProposal,
- NAVBAR_HIDDEN_PENDING_ICON_TIMEOUT_MS);
- }
- }
-
- public void onDisable2FlagChanged(int state2) {
- final boolean rotateSuggestionsDisabled = hasDisable2RotateSuggestionFlag(state2);
- if (rotateSuggestionsDisabled) onRotationSuggestionsDisabled();
- }
-
- public void onBehaviorChanged(int displayId, @WindowInsetsController.Behavior int behavior) {
- if (DEFAULT_DISPLAY != displayId) {
- return;
- }
-
- if (mBehavior != behavior) {
- mBehavior = behavior;
- showPendingRotationButtonIfNeeded();
- }
- }
-
- public void onTaskBarVisibilityChange(boolean showing) {
- if (mIsTaskbarShowing != showing) {
- mIsTaskbarShowing = showing;
- showPendingRotationButtonIfNeeded();
- }
- }
-
- private void showPendingRotationButtonIfNeeded() {
- if (canShowRotationButton() && mPendingRotationSuggestion) {
- showAndLogRotationSuggestion();
- }
- }
-
- /** Return true when either the task bar is visible or it's in visual immersive mode. */
- @SuppressLint("InlinedApi")
- private boolean canShowRotationButton() {
- return mIsTaskbarShowing || mBehavior == WindowInsetsController.BEHAVIOR_DEFAULT;
- }
-
- public @DrawableRes
- int getIconResId() {
- return mIconResId;
- }
-
- public @ColorInt int getLightIconColor() {
- return mLightIconColor;
- }
-
- public @ColorInt int getDarkIconColor() {
- return mDarkIconColor;
- }
-
- private void onRotateSuggestionClick(View v) {
- mUiEventLogger.log(RotationButtonEvent.ROTATION_SUGGESTION_ACCEPTED);
- incrementNumAcceptedRotationSuggestionsIfNeeded();
- setRotationLockedAtAngle(mLastRotationSuggestion);
- }
-
- private boolean onRotateSuggestionHover(View v, MotionEvent event) {
- final int action = event.getActionMasked();
- mHoveringRotationSuggestion = (action == MotionEvent.ACTION_HOVER_ENTER)
- || (action == MotionEvent.ACTION_HOVER_MOVE);
- rescheduleRotationTimeout(true /* reasonHover */);
- return false; // Must return false so a11y hover events are dispatched correctly.
- }
-
- private void onRotationSuggestionsDisabled() {
- // Immediately hide the rotate button and clear any planned removal
- setRotateSuggestionButtonState(false /* visible */, true /* force */);
- mMainThreadHandler.removeCallbacks(mRemoveRotationProposal);
- }
-
- private void showAndLogRotationSuggestion() {
- setRotateSuggestionButtonState(true /* visible */);
- rescheduleRotationTimeout(false /* reasonHover */);
- mUiEventLogger.log(RotationButtonEvent.ROTATION_SUGGESTION_SHOWN);
- }
-
- /**
- * Makes {@link #shouldOverrideUserLockPrefs} always return {@code false} once. It is used to
- * avoid losing original user rotation when display rotation is changed by entering the fixed
- * orientation overview.
- */
- void setSkipOverrideUserLockPrefsOnce() {
- mSkipOverrideUserLockPrefsOnce = true;
- }
-
- private boolean shouldOverrideUserLockPrefs(final int rotation) {
- if (mSkipOverrideUserLockPrefsOnce) {
- mSkipOverrideUserLockPrefsOnce = false;
- return false;
- }
- // Only override user prefs when returning to the natural rotation (normally portrait).
- // Don't let apps that force landscape or 180 alter user lock.
- return rotation == NATURAL_ROTATION;
- }
-
- private void rescheduleRotationTimeout(final boolean reasonHover) {
- // May be called due to a new rotation proposal or a change in hover state
- if (reasonHover) {
- // Don't reschedule if a hide animator is running
- if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) return;
- // Don't reschedule if not visible
- if (!mRotationButton.isVisible()) return;
- }
-
- // Stop any pending removal
- mMainThreadHandler.removeCallbacks(mRemoveRotationProposal);
- // Schedule timeout
- mMainThreadHandler.postDelayed(mRemoveRotationProposal,
- computeRotationProposalTimeout());
- }
-
- private int computeRotationProposalTimeout() {
- return mAccessibilityManager.getRecommendedTimeoutMillis(
- mHoveringRotationSuggestion ? 16000 : 5000,
- AccessibilityManager.FLAG_CONTENT_CONTROLS);
- }
-
- private boolean isRotateSuggestionIntroduced() {
- ContentResolver cr = mContext.getContentResolver();
- return Settings.Secure.getInt(cr, Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED, 0)
- >= NUM_ACCEPTED_ROTATION_SUGGESTIONS_FOR_INTRODUCTION;
- }
-
- private void incrementNumAcceptedRotationSuggestionsIfNeeded() {
- // Get the number of accepted suggestions
- ContentResolver cr = mContext.getContentResolver();
- final int numSuggestions = Settings.Secure.getInt(cr,
- Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED, 0);
-
- // Increment the number of accepted suggestions only if it would change intro mode
- if (numSuggestions < NUM_ACCEPTED_ROTATION_SUGGESTIONS_FOR_INTRODUCTION) {
- Settings.Secure.putInt(cr, Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED,
- numSuggestions + 1);
- }
- }
-
- private class TaskStackListenerImpl extends TaskStackChangeListener {
- // Invalidate any rotation suggestion on task change or activity orientation change
- // Note: all callbacks happen on main thread
-
- @Override
- public void onTaskStackChanged() {
- setRotateSuggestionButtonState(false /* visible */);
- }
-
- @Override
- public void onTaskRemoved(int taskId) {
- setRotateSuggestionButtonState(false /* visible */);
- }
-
- @Override
- public void onTaskMovedToFront(int taskId) {
- setRotateSuggestionButtonState(false /* visible */);
- }
-
- @Override
- public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) {
- // Only hide the icon if the top task changes its requestedOrientation
- // Launcher can alter its requestedOrientation while it's not on top, don't hide on this
- Optional.ofNullable(ActivityManagerWrapper.getInstance())
- .map(ActivityManagerWrapper::getRunningTask)
- .ifPresent(a -> {
- if (a.id == taskId) setRotateSuggestionButtonState(false /* visible */);
- });
- }
- }
-
- enum RotationButtonEvent implements UiEventLogger.UiEventEnum {
- @UiEvent(doc = "The rotation button was shown")
- ROTATION_SUGGESTION_SHOWN(206),
- @UiEvent(doc = "The rotation button was clicked")
- ROTATION_SUGGESTION_ACCEPTED(207);
-
- private final int mId;
- RotationButtonEvent(int id) {
- mId = id;
- }
- @Override public int getId() {
- return mId;
- }
- }
-}
-
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index e8aa2fa..30a0fdf 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -677,6 +677,9 @@
public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) {
WindowInsets result = view.onApplyWindowInsets(windowInsets);
buildAnimationController();
+ // Reapply the current shift to ensure it takes new insets into account, e.g. when long
+ // pressing to stash taskbar without moving the finger.
+ updateFinalShift();
return result;
}
@@ -961,8 +964,10 @@
} else {
mStateCallback.setState(STATE_RESUME_LAST_TASK);
}
- TaskViewUtils.setSplitAuxiliarySurfacesShown(
- mRecentsAnimationTargets.nonApps, true);
+ if (mRecentsAnimationTargets != null) {
+ TaskViewUtils.setSplitAuxiliarySurfacesShown(
+ mRecentsAnimationTargets.nonApps, true);
+ }
break;
}
ActiveGestureLog.INSTANCE.addLog("onSettledOnEndTarget " + endTarget);
@@ -1447,7 +1452,7 @@
}
private void setupWindowAnimation(RectFSpringAnim[] anims) {
- anims[0].addOnUpdateListener((v, r, p) -> {
+ anims[0].addOnUpdateListener((r, p) -> {
updateSysUiFlags(Math.max(p, mCurrentShift.value));
});
anims[0].addAnimatorListener(new AnimationSuccessListener() {
@@ -1734,7 +1739,10 @@
endLauncherTransitionController();
mRecentsView.onSwipeUpAnimationSuccess();
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
- mTaskAnimationManager.setLiveTileCleanUpHandler(mInputConsumerProxy::destroy);
+ mTaskAnimationManager.setLiveTileCleanUpHandler(() -> {
+ mRecentsView.cleanupRemoteTargets();
+ mInputConsumerProxy.destroy();
+ });
mTaskAnimationManager.enableLiveTileRestartListener();
}
diff --git a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
index c1b45e0..fed5ae5 100644
--- a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -50,7 +50,6 @@
import android.view.SurfaceControl.Transaction;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
@@ -59,7 +58,6 @@
import com.android.launcher3.anim.SpringAnimationBuilder;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.fallback.RecentsState;
-import com.android.quickstep.util.AppCloseConfig;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.util.TransformParams.BuilderProxy;
@@ -317,8 +315,7 @@
}
@Override
- public void update(@Nullable AppCloseConfig config, RectF currentRect, float progress,
- float radius) {
+ public void update(RectF currentRect, float progress, float radius) {
if (mSurfaceControl != null) {
currentRect.roundOut(mTempRect);
Transaction t = new Transaction();
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index 0181cd7..8a30aad 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -18,18 +18,14 @@
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.Utilities.boundToRange;
import static com.android.launcher3.Utilities.dpToPx;
import static com.android.launcher3.Utilities.mapBoundToRange;
import static com.android.launcher3.anim.Interpolators.EXAGGERATED_EASE;
import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.config.FeatureFlags.PROTOTYPE_APP_CLOSE;
import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
import static com.android.launcher3.views.FloatingIconView.getFloatingIconView;
-import static java.lang.Math.round;
-
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
@@ -59,10 +55,8 @@
import com.android.launcher3.views.FloatingIconView;
import com.android.launcher3.views.FloatingView;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
-import com.android.quickstep.util.AppCloseConfig;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.StaggeredWorkspaceAnim;
-import com.android.quickstep.util.WorkspaceRevealAnim;
import com.android.quickstep.views.FloatingWidgetView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
@@ -167,15 +161,9 @@
}
@Override
- public void update(@Nullable AppCloseConfig config, RectF currentRect,
- float progress, float radius) {
- super.update(config, currentRect, progress, radius);
- int fgAlpha = 255;
- if (config != null && PROTOTYPE_APP_CLOSE.get()) {
- progress = config.getInterpolatedProgress();
- fgAlpha = config.getFgAlpha();
- }
- floatingIconView.update(1f, fgAlpha, currentRect, progress,
+ public void update(RectF currentRect, float progress, float radius) {
+ super.update(currentRect, progress, radius);
+ floatingIconView.update(1f /* alpha */, 255 /* fgAlpha */, currentRect, progress,
windowAlphaThreshold, radius, false);
}
};
@@ -232,9 +220,8 @@
}
@Override
- public void update(@Nullable AppCloseConfig config, RectF currentRect, float progress,
- float radius) {
- super.update(config, currentRect, progress, radius);
+ public void update(RectF currentRect, float progress, float radius) {
+ super.update(currentRect, progress, radius);
final float fallbackBackgroundAlpha =
1 - mapBoundToRange(progress, 0.8f, 1, 0, 1, EXAGGERATED_EASE);
final float foregroundAlpha =
@@ -293,27 +280,12 @@
private final float mTransY;
private final FloatingView mFloatingView;
private ValueAnimator mBounceBackAnimator;
- private final AnimatorSet mWorkspaceReveal;
FloatingViewHomeAnimationFactory(FloatingView floatingView) {
mFloatingView = floatingView;
ResourceProvider rp = DynamicResource.provider(mActivity);
mTransY = dpToPx(rp.getFloat(R.dimen.swipe_up_trans_y_dp));
-
- mWorkspaceReveal = PROTOTYPE_APP_CLOSE.get()
- ? new WorkspaceRevealAnim(mActivity, true /* animateScrim */).getAnimators()
- : null;
- }
-
- @Override
- public @NonNull RectF getWindowTargetRect() {
- if (PROTOTYPE_APP_CLOSE.get()) {
- // We want the target rect to be at this offset position, so that all
- // launcher content can spring back upwards.
- mFloatingView.setPositionOffsetY(mTransY);
- }
- return super.getWindowTargetRect();
}
@Override
@@ -321,20 +293,6 @@
return false;
}
- @Override
- public void update(@Nullable AppCloseConfig config, RectF currentRect, float progress,
- float radius) {
- if (config != null && PROTOTYPE_APP_CLOSE.get()) {
- DragLayer dl = mActivity.getDragLayer();
- float translationY = config.getWorkspaceTransY();
- dl.setTranslationY(translationY);
-
- long duration = mWorkspaceReveal.getDuration();
- long playTime = boundToRange(round(duration * progress), 0, duration);
- mWorkspaceReveal.setCurrentPlayTime(playTime);
- }
- }
-
protected void bounceBackToRestingPosition() {
final float startValue = mTransY;
final float endValue = 0;
@@ -369,31 +327,6 @@
}
@Override
- public void setAnimation(RectFSpringAnim anim) {
- if (PROTOTYPE_APP_CLOSE.get()) {
- // Use a spring to put drag layer translation back to 0.
- anim.addAnimatorListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mFloatingView.setPositionOffsetY(0);
- bounceBackToRestingPosition();
- }
- });
-
- // Will be updated manually below so that the two animations are in sync.
- mWorkspaceReveal.start();
- mWorkspaceReveal.pause();
-
- anim.addAnimatorListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mWorkspaceReveal.end();
- }
- });
- }
- }
-
- @Override
public void onCancel() {
mFloatingView.fastFinish();
if (mBounceBackAnimator != null) {
@@ -425,13 +358,9 @@
@Override
public void playAtomicAnimation(float velocity) {
- if (!PROTOTYPE_APP_CLOSE.get()) {
- new StaggeredWorkspaceAnim(mActivity, velocity, true /* animateOverviewScrim */,
- getViewIgnoredInWorkspaceRevealAnimation())
- .start();
- } else if (shouldPlayAtomicWorkspaceReveal()) {
- new WorkspaceRevealAnim(mActivity, true).start();
- }
+ new StaggeredWorkspaceAnim(mActivity, velocity, true /* animateOverviewScrim */,
+ getViewIgnoredInWorkspaceRevealAnimation())
+ .start();
}
@Override
diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
index 825abed..5f2b49d 100644
--- a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
+++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
@@ -17,7 +17,6 @@
package com.android.quickstep;
import android.content.Context;
-import android.util.Log;
import androidx.annotation.Nullable;
@@ -33,8 +32,6 @@
* {@link TaskViewSimulator}
*/
public class RemoteTargetGluer {
- private static final String TAG = "RemoteTargetGluer";
-
private RemoteTargetHandle[] mRemoteTargetHandles;
private SplitConfigurationOptions.StagedSplitBounds mStagedSplitBounds;
@@ -94,25 +91,18 @@
public RemoteTargetHandle[] assignTargetsForSplitScreen(RemoteAnimationTargets targets) {
int[] splitIds = LauncherSplitScreenListener.INSTANCE.getNoCreate()
.getRunningSplitTaskIds();
- Log.d(TAG, "splitIds length: " + splitIds.length
- + " targetAppsLength: " + targets.apps.length
- + " remoteHandlesLength: " + mRemoteTargetHandles.length);
- if (splitIds.length == 0 && mRemoteTargetHandles.length > 1) {
- // There's a chance that between the creation of this class and assigning targets,
- // LauncherSplitScreenListener may have received callback that removes split
- mRemoteTargetHandles = new RemoteTargetHandle[]{mRemoteTargetHandles[0]};
- Log.w(TAG, "splitTaskIds changed between creation and assignment");
- }
RemoteAnimationTargetCompat primaryTaskTarget;
RemoteAnimationTargetCompat secondaryTaskTarget;
if (mRemoteTargetHandles.length == 1) {
// If we're not in split screen, the splitIds count doesn't really matter since we
- // should always hit this case. Right now there's no use case for multiple app targets
- // without being in split screen
- primaryTaskTarget = targets.apps[0];
+ // should always hit this case.
mRemoteTargetHandles[0].mTransformParams.setTargetSet(targets);
- mRemoteTargetHandles[0].mTaskViewSimulator.setPreview(primaryTaskTarget, null);
+ if (targets.apps.length > 0) {
+ // Unclear why/when target.apps length == 0, but it sure does happen :(
+ primaryTaskTarget = targets.apps[0];
+ mRemoteTargetHandles[0].mTaskViewSimulator.setPreview(primaryTaskTarget, null);
+ }
} else {
// split screen
primaryTaskTarget = targets.findTask(splitIds[0]);
diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index f64d506..b36cb0a 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -18,7 +18,6 @@
import static com.android.launcher3.anim.Interpolators.ACCEL_1_5;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_SELECT;
-import static com.android.launcher3.config.FeatureFlags.PROTOTYPE_APP_CLOSE;
import android.animation.Animator;
import android.content.Context;
@@ -28,7 +27,6 @@
import android.graphics.RectF;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import com.android.launcher3.DeviceProfile;
@@ -39,10 +37,8 @@
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle;
import com.android.quickstep.util.AnimatorControllerWithResistance;
-import com.android.quickstep.util.AppCloseConfig;
import com.android.quickstep.util.LauncherSplitScreenListener;
import com.android.quickstep.util.RectFSpringAnim;
-import com.android.quickstep.util.RectFSpringAnim2;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.util.TransformParams.BuilderProxy;
@@ -189,8 +185,7 @@
public boolean keepWindowOpaque() { return false; }
- public void update(@Nullable AppCloseConfig config, RectF currentRect, float progress,
- float radius) { }
+ public void update(RectF currentRect, float progress, float radius) { }
public void onCancel() { }
@@ -290,14 +285,7 @@
homeToWindowPositionMap.invert(windowToHomePositionMap);
windowToHomePositionMap.mapRect(startRect);
- RectFSpringAnim anim;
- if (PROTOTYPE_APP_CLOSE.get()) {
- anim = new RectFSpringAnim2(startRect, targetRect, mContext,
- taskViewSimulator.getCurrentCornerRadius(),
- homeAnimationFactory.getEndRadius(cropRectF));
- } else {
- anim = new RectFSpringAnim(startRect, targetRect, mContext, mDp);
- }
+ RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mContext, mDp);
homeAnimationFactory.setAnimation(anim);
SpringAnimationRunner runner = new SpringAnimationRunner(
@@ -343,17 +331,13 @@
}
@Override
- public void onUpdate(@Nullable AppCloseConfig config, RectF currentRect, float progress) {
+ public void onUpdate(RectF currentRect, float progress) {
mHomeAnim.setPlayFraction(progress);
mHomeToWindowPositionMap.mapRect(mWindowCurrentRect, currentRect);
mMatrix.setRectToRect(mCropRectF, mWindowCurrentRect, ScaleToFit.FILL);
float cornerRadius = Utilities.mapRange(progress, mStartRadius, mEndRadius);
float alpha = mAnimationFactory.getWindowAlpha(progress);
- if (config != null && PROTOTYPE_APP_CLOSE.get()) {
- alpha = config.getWindowAlpha();
- cornerRadius = config.getCornerRadius();
- }
if (mAnimationFactory.keepWindowOpaque()) {
alpha = 1f;
}
@@ -362,8 +346,7 @@
.setCornerRadius(cornerRadius);
mLocalTransformParams.applySurfaceParams(mLocalTransformParams
.createSurfaceParams(this));
- mAnimationFactory.update(config, currentRect, progress,
- mMatrix.mapRadius(cornerRadius));
+ mAnimationFactory.update(currentRect, progress, mMatrix.mapRadius(cornerRadius));
}
@Override
diff --git a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
index 68df208..672687d 100644
--- a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
@@ -53,7 +53,6 @@
import com.android.quickstep.RemoteTargetGluer;
import com.android.quickstep.SwipeUpAnimationLogic;
import com.android.quickstep.SwipeUpAnimationLogic.RunningWindowAnim;
-import com.android.quickstep.util.AppCloseConfig;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.TransformParams;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
@@ -331,8 +330,7 @@
}
@Override
- public void update(@Nullable AppCloseConfig config, RectF rect, float progress,
- float radius) {
+ public void update(RectF rect, float progress, float radius) {
mFakeIconView.setVisibility(View.VISIBLE);
mFakeIconView.update(rect, progress,
1f - SHAPE_PROGRESS_DURATION /* shapeProgressStart */,
diff --git a/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java b/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
index 158fba9..c4909de 100644
--- a/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
+++ b/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
@@ -328,7 +328,7 @@
break;
}
for (OnUpdateListener onUpdateListener : mOnUpdateListeners) {
- onUpdateListener.onUpdate(null, mCurrentRect, mCurrentScaleProgress);
+ onUpdateListener.onUpdate(mCurrentRect, mCurrentScaleProgress);
}
}
}
@@ -353,7 +353,12 @@
}
public interface OnUpdateListener {
- void onUpdate(@Nullable AppCloseConfig values, RectF currentRect, float progress);
+ /**
+ * Called when an update is made to the animation.
+ * @param currentRect The rect of the window.
+ * @param progress [0, 1] The progress of the rect scale animation.
+ */
+ void onUpdate(RectF currentRect, float progress);
default void onCancel() { }
}
diff --git a/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java b/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java
deleted file mode 100644
index cb35809..0000000
--- a/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * Copyright (C) 2021 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.quickstep.util;
-
-import static com.android.launcher3.Utilities.dpToPx;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.graphics.PointF;
-import android.graphics.RectF;
-import android.util.PathParser;
-import android.util.Property;
-import android.view.animation.Interpolator;
-
-import androidx.core.view.animation.PathInterpolatorCompat;
-import androidx.dynamicanimation.animation.FloatPropertyCompat;
-import androidx.dynamicanimation.animation.SpringAnimation;
-import androidx.dynamicanimation.animation.SpringForce;
-
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.util.DynamicResource;
-import com.android.systemui.plugins.ResourceProvider;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-
-/**
- * Applies spring forces to animate from a starting rect to a target rect,
- * while providing update callbacks to the caller.
- */
-public class RectFSpringAnim2 extends RectFSpringAnim {
-
- private static final FloatPropertyCompat<RectFSpringAnim2> RECT_CENTER_X =
- new FloatPropertyCompat<RectFSpringAnim2>("rectCenterXSpring") {
- @Override
- public float getValue(RectFSpringAnim2 anim) {
- return anim.mCurrentCenterX;
- }
-
- @Override
- public void setValue(RectFSpringAnim2 anim, float currentCenterX) {
- anim.mCurrentCenterX = currentCenterX;
- anim.onUpdate();
- }
- };
-
- private static final FloatPropertyCompat<RectFSpringAnim2> RECT_Y =
- new FloatPropertyCompat<RectFSpringAnim2>("rectYSpring") {
- @Override
- public float getValue(RectFSpringAnim2 anim) {
- return anim.mCurrentCenterY;
- }
-
- @Override
- public void setValue(RectFSpringAnim2 anim, float y) {
- anim.mCurrentCenterY = y;
- anim.onUpdate();
- }
- };
-
- private static final Property<RectFSpringAnim2, Float> PROGRESS =
- new Property<RectFSpringAnim2, Float>(Float.class, "rectFProgress") {
- @Override
- public Float get(RectFSpringAnim2 rectFSpringAnim) {
- return rectFSpringAnim.mProgress;
- }
-
- @Override
- public void set(RectFSpringAnim2 rectFSpringAnim, Float progress) {
- rectFSpringAnim.mProgress = progress;
- rectFSpringAnim.onUpdate();
- }
- };
-
- private final RectF mStartRect;
- private final RectF mTargetRect;
- private final RectF mCurrentRect = new RectF();
- private final List<OnUpdateListener> mOnUpdateListeners = new ArrayList<>();
- private final List<Animator.AnimatorListener> mAnimatorListeners = new ArrayList<>();
-
- private float mCurrentCenterX;
- private float mCurrentCenterY;
-
- private float mTargetX;
- private float mTargetY;
-
- // If true, tracking the bottom of the rects, else tracking the top.
- private float mProgress;
- private SpringAnimation mRectXAnim;
- private SpringAnimation mRectYAnim;
- private ValueAnimator mRectScaleAnim;
- private boolean mAnimsStarted;
- private boolean mRectXAnimEnded;
- private boolean mRectYAnimEnded;
- private boolean mRectScaleAnimEnded;
-
- private final float mXDamping;
- private final float mXStiffness;
-
- private final float mYDamping;
- private float mYStiffness;
-
- private long mDuration;
-
- private final Interpolator mCloseInterpolator;
-
- private AppCloseConfig mValues;
- final float mStartRadius;
- final float mEndRadius;
-
- final float mHomeTransYEnd;
- final float mScaleStart;
-
- public RectFSpringAnim2(RectF startRect, RectF targetRect, Context context, float startRadius,
- float endRadius) {
- super(startRect, targetRect, context, null);
- mStartRect = startRect;
- mTargetRect = targetRect;
-
- mCurrentCenterY = mStartRect.centerY();
- mCurrentCenterX = mStartRect.centerX();
-
- mTargetY = mTargetRect.centerY();
- mTargetX = mTargetRect.centerX();
-
- ResourceProvider rp = DynamicResource.provider(context);
- mXDamping = rp.getFloat(R.dimen.swipe_up_rect_2_x_damping_ratio);
- mXStiffness = rp.getFloat(R.dimen.swipe_up_rect_2_x_stiffness);
-
- mYDamping = rp.getFloat(R.dimen.swipe_up_rect_2_y_damping_ratio);
- mYStiffness = rp.getFloat(R.dimen.swipe_up_rect_2_y_stiffness);
- mDuration = Math.round(rp.getFloat(R.dimen.swipe_up_duration));
-
- mHomeTransYEnd = dpToPx(rp.getFloat(R.dimen.swipe_up_trans_y_dp));
- mScaleStart = rp.getFloat(R.dimen.swipe_up_scale_start);
-
- mCloseInterpolator = getAppCloseInterpolator(context);
-
- // End on a "round-enough" radius so that the shape reveal doesn't have to do too much
- // rounding at the end of the animation.
- mStartRadius = startRadius;
- mEndRadius = endRadius;
-
- setCanRelease(true);
- }
-
- public void onTargetPositionChanged() {
- if (mRectXAnim != null && mTargetX != mTargetRect.centerX()) {
- mTargetX = mTargetRect.centerX();
- mRectXAnim.animateToFinalPosition(mTargetX);
- }
-
- if (mRectYAnim != null) {
- if (mTargetY != mTargetRect.centerY()) {
- mTargetY = mTargetRect.centerY();
- mRectYAnim.animateToFinalPosition(mTargetY);
- }
- }
- }
-
- public void addOnUpdateListener(OnUpdateListener onUpdateListener) {
- mOnUpdateListeners.add(onUpdateListener);
- }
-
- public void addAnimatorListener(Animator.AnimatorListener animatorListener) {
- mAnimatorListeners.add(animatorListener);
- }
-
- /**
- * Starts the fling/spring animation.
- * @param context The activity context.
- * @param velocityPxPerMs Velocity of swipe in px/ms.
- */
- public void start(Context context, PointF velocityPxPerMs) {
- mRectXAnim = new SpringAnimation(this, RECT_CENTER_X)
- .setStartValue(mCurrentCenterX)
- .setStartVelocity(velocityPxPerMs.x * 1000)
- .setSpring(new SpringForce(mTargetX)
- .setStiffness(mXStiffness)
- .setDampingRatio(mXDamping));
- mRectXAnim.addEndListener(((animation, canceled, centerX, velocityX) -> {
- mRectXAnimEnded = true;
- maybeOnEnd();
- }));
-
- mRectYAnim = new SpringAnimation(this, RECT_Y)
- .setStartValue(mCurrentCenterY)
- .setStartVelocity(velocityPxPerMs.y * 1000)
- .setSpring(new SpringForce(mTargetY)
- .setStiffness(mYStiffness)
- .setDampingRatio(mYDamping));
- mRectYAnim.addEndListener(((animation, canceled, centerY, velocityY) -> {
- mRectYAnimEnded = true;
- maybeOnEnd();
- }));
-
- mRectScaleAnim = ObjectAnimator.ofFloat(this, PROGRESS, 0, 1f)
- .setDuration(mDuration);
- mRectScaleAnim.setInterpolator(mCloseInterpolator);
- mRectScaleAnim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mRectScaleAnimEnded = true;
- maybeOnEnd();
- }
- });
-
- mValues = buildConfig();
- mRectScaleAnim.addUpdateListener(mValues);
-
- setCanRelease(false);
- mAnimsStarted = true;
-
- mRectXAnim.start();
- mRectYAnim.start();
- mRectScaleAnim.start();
- for (Animator.AnimatorListener animatorListener : mAnimatorListeners) {
- animatorListener.onAnimationStart(null);
- }
- }
-
- private AppCloseConfig buildConfig() {
- return new AppCloseConfig() {
- FloatProp mHomeTransY = new FloatProp(0, mHomeTransYEnd, 0, mDuration, LINEAR);
- FloatProp mHomeScale = new FloatProp(mScaleStart, 1f, 0, mDuration, LINEAR);
- FloatProp mWindowFadeOut = new FloatProp(1f, 0f, 0, 116, LINEAR);
- // There should be a slight overlap b/w window fading out and fg fading in.
- // (fg startDelay < window fade out duration)
- FloatProp mFgFadeIn = new FloatProp(0, 255f, 100, mDuration - 100, LINEAR);
- FloatProp mRadius = new FloatProp(mStartRadius, mEndRadius, 0, mDuration, LINEAR);
- FloatProp mThreePointInterpolation = new FloatProp(0, 1, 0, mDuration, LINEAR);
-
- @Override
- public float getWorkspaceTransY() {
- return mHomeTransY.value;
- }
-
- @Override
- public float getWorkspaceScale() {
- return mHomeScale.value;
- }
-
- @Override
- public float getWindowAlpha() {
- return mWindowFadeOut.value;
- }
-
- @Override
- public int getFgAlpha() {
- return (int) mFgFadeIn.value;
- }
-
- @Override
- public float getCornerRadius() {
- return mRadius.value;
- }
-
- @Override
- public float getInterpolatedProgress() {
- return mThreePointInterpolation.value;
- }
-
- @Override
- public void onUpdate(float percent, boolean initOnly) {}
- };
- }
-
- public void end() {
- if (mAnimsStarted) {
- if (mRectXAnim.canSkipToEnd()) {
- mRectXAnim.skipToEnd();
- }
- if (mRectYAnim.canSkipToEnd()) {
- mRectYAnim.skipToEnd();
- }
- mRectScaleAnim.end();
- }
- mRectXAnimEnded = true;
- mRectYAnimEnded = true;
- mRectScaleAnimEnded = true;
- maybeOnEnd();
- }
-
- private boolean isEnded() {
- return mRectXAnimEnded && mRectYAnimEnded && mRectScaleAnimEnded;
- }
-
- private void onUpdate() {
- if (isEnded()) {
- // Prevent further updates from being called. This can happen between callbacks for
- // ending the x/y/scale animations.
- return;
- }
-
- if (!mOnUpdateListeners.isEmpty()) {
- float rectProgress = mProgress;
- float currentWidth = Utilities.mapRange(rectProgress, mStartRect.width(),
- mTargetRect.width());
- float currentHeight = Utilities.mapRange(rectProgress, mStartRect.height(),
- mTargetRect.height());
-
- mCurrentRect.set(mCurrentCenterX - currentWidth / 2,
- mCurrentCenterY - currentHeight / 2,
- mCurrentCenterX + currentWidth / 2,
- mCurrentCenterY + currentHeight / 2);
-
- float currentPlayTime = mRectScaleAnimEnded ? mRectScaleAnim.getDuration()
- : mRectScaleAnim.getCurrentPlayTime();
- float linearProgress = Math.min(1f, currentPlayTime / mRectScaleAnim.getDuration());
- for (OnUpdateListener onUpdateListener : mOnUpdateListeners) {
- onUpdateListener.onUpdate(mValues, mCurrentRect, linearProgress);
- }
- }
- }
-
- private void maybeOnEnd() {
- if (mAnimsStarted && isEnded()) {
- mAnimsStarted = false;
- setCanRelease(true);
- for (Animator.AnimatorListener animatorListener : mAnimatorListeners) {
- animatorListener.onAnimationEnd(null);
- }
- }
- }
-
- public void cancel() {
- if (mAnimsStarted) {
- for (OnUpdateListener onUpdateListener : mOnUpdateListeners) {
- onUpdateListener.onCancel();
- }
- }
- end();
- }
-
- private Interpolator getAppCloseInterpolator(Context context) {
- ResourceProvider rp = DynamicResource.provider(context);
- String path = String.format(Locale.ENGLISH,
- "M 0,0 C %f, %f, %f, %f, %f, %f C %f, %f, %f, %f, 1, 1",
- rp.getFloat(R.dimen.c1_a),
- rp.getFloat(R.dimen.c1_b),
- rp.getFloat(R.dimen.c1_c),
- rp.getFloat(R.dimen.c1_d),
- rp.getFloat(R.dimen.mp_x),
- rp.getFloat(R.dimen.mp_y),
- rp.getFloat(R.dimen.c2_a),
- rp.getFloat(R.dimen.c2_b),
- rp.getFloat(R.dimen.c2_c),
- rp.getFloat(R.dimen.c2_d));
- return PathInterpolatorCompat.create(PathParser.createPathFromPathData(path));
- }
-}
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index a30216c..a534450 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -158,7 +158,7 @@
t.reparent(mContentOverlay, mLeash);
t.apply();
- addOnUpdateListener((values, currentRect, progress) -> {
+ addOnUpdateListener((currentRect, progress) -> {
float alpha = progress < 0.5f
? 0
: Utilities.mapToRange(Math.min(progress, 1f), 0.5f, 1f,
@@ -201,8 +201,7 @@
addOnUpdateListener(this::onAnimationUpdate);
}
- private void onAnimationUpdate(@Nullable AppCloseConfig values, RectF currentRect,
- float progress) {
+ private void onAnimationUpdate(RectF currentRect, float progress) {
if (mHasAnimationEnded) return;
final SurfaceControl.Transaction tx =
PipSurfaceTransactionHelper.newSurfaceControlTransaction();
diff --git a/quickstep/src/com/android/quickstep/util/TaskKeyLruCache.java b/quickstep/src/com/android/quickstep/util/TaskKeyLruCache.java
index d87feec..08a65fa 100644
--- a/quickstep/src/com/android/quickstep/util/TaskKeyLruCache.java
+++ b/quickstep/src/com/android/quickstep/util/TaskKeyLruCache.java
@@ -20,6 +20,7 @@
import com.android.systemui.shared.recents.model.Task.TaskKey;
import java.util.LinkedHashMap;
+import java.util.Map;
import java.util.function.Predicate;
/**
@@ -117,7 +118,7 @@
}
@Override
- protected boolean removeEldestEntry(Entry<Integer, TaskKeyLruCache.Entry<V>> eldest) {
+ protected boolean removeEldestEntry(Map.Entry<Integer, TaskKeyLruCache.Entry<V>> eldest) {
return size() > mMaxSize;
}
}
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index 76d3591..16c3c7f 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -16,6 +16,8 @@
package com.android.quickstep.views;
+import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS;
+
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
@@ -30,6 +32,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
+import com.android.launcher3.uioverrides.ApiWrapper;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.quickstep.SysUINavigationMode;
@@ -146,7 +149,7 @@
public void setInsets(Rect insets) {
mInsets.set(insets);
updateVerticalMargin(SysUINavigationMode.getMode(getContext()));
- updateHorizontalPadding();
+ updatePaddingAndTranslations();
}
public void updateHiddenFlags(@ActionsHiddenFlags int visibilityFlags, boolean enable) {
@@ -189,8 +192,37 @@
return mMultiValueAlpha.getProperty(INDEX_FULLSCREEN_ALPHA);
}
- private void updateHorizontalPadding() {
- setPadding(mInsets.left, 0, mInsets.right, 0);
+ /**
+ * Aligns OverviewActionsView vertically with and offsets horizontal position based on
+ * 3 button nav container in taskbar.
+ */
+ private void updatePaddingAndTranslations() {
+ boolean alignFor3ButtonTaskbar = mDp.isTaskbarPresent &&
+ SysUINavigationMode.getMode(getContext()) == THREE_BUTTONS;
+ if (alignFor3ButtonTaskbar) {
+ // Add extra horizontal spacing
+ int additionalPadding = ApiWrapper.getHotseatEndOffset(getContext());
+ if (isLayoutRtl()) {
+ setPadding(mInsets.left + additionalPadding, 0, mInsets.right, 0);
+ } else {
+ setPadding(mInsets.left, 0, mInsets.right + additionalPadding, 0);
+ }
+
+ // Align vertically, using taskbar height + mDp.taskbarOffsetY() to guestimate
+ // where the button nav top is
+ View startActionView = findViewById(R.id.action_buttons);
+ int marginBottom = getOverviewActionsBottomMarginPx(
+ SysUINavigationMode.getMode(getContext()), mDp);
+ int actionsTop = (mDp.heightPx - marginBottom - mInsets.bottom);
+ int navTop = mDp.heightPx - (mDp.taskbarSize + mDp.getTaskbarOffsetY());
+ int transY = navTop - actionsTop
+ + ((mDp.taskbarSize - startActionView.getHeight()) / 2);
+ setTranslationY(transY);
+ } else {
+ setPadding(mInsets.left, 0, mInsets.right, 0);
+ setTranslationX(0);
+ setTranslationY(0);
+ }
}
/** Updates vertical margins for different navigation mode or configuration changes. */
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 687a13a..d825fad 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -1094,7 +1094,7 @@
for (int i = 0; i < taskCount; i++) {
View v = getTaskViewAt(i);
if (!(v instanceof GroupedTaskView)) {
- return;
+ continue;
}
GroupedTaskView gtv = (GroupedTaskView) v;
gtv.onTaskListVisibilityChanged(false);
@@ -4390,7 +4390,7 @@
public void finishRecentsAnimation(boolean toRecents, boolean shouldPip,
Runnable onFinishComplete) {
// TODO(b/197232424#comment#10) Move this back into onRecentsAnimationComplete(). Maybe?
- mRemoteTargetHandles = null;
+ cleanupRemoteTargets();
if (!toRecents && ENABLE_QUICKSTEP_LIVE_TILE.get()) {
// Reset the minimized state since we force-toggled the minimized state when entering
// overview, but never actually finished the recents animation. This is a catch all for
@@ -4849,6 +4849,10 @@
&& mCurrentGestureEndTarget != GestureState.GestureEndTarget.RECENTS;
}
+ public void cleanupRemoteTargets() {
+ mRemoteTargetHandles = null;
+ }
+
/**
* Used to register callbacks for when our empty message state changes.
*
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
new file mode 100644
index 0000000..9b86c73
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
@@ -0,0 +1,14 @@
+package com.android.quickstep.views
+
+import android.util.Log
+
+// TODO(http://b/193432925)
+class TaskMenuViewWithArrow {
+ companion object {
+ const val TAG = "TaskMenuViewWithArrow"
+
+ fun logSomething() {
+ Log.d(TAG, "It worked!")
+ }
+ }
+}
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 8d77e44..eef5fb3 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -115,6 +115,7 @@
public class TaskView extends FrameLayout implements Reusable {
private static final String TAG = TaskView.class.getSimpleName();
+ private static final boolean DEBUG = false;
public static final int FLAG_UPDATE_ICON = 1;
public static final int FLAG_UPDATE_THUMBNAIL = FLAG_UPDATE_ICON << 1;
@@ -808,6 +809,8 @@
}
protected boolean showTaskMenuWithContainer(IconView iconView) {
+ // TODO(http://b/193432925)
+ if (DEBUG) TaskMenuViewWithArrow.Companion.logSomething();
return TaskMenuView.showForTask(mTaskIdAttributeContainer[0]);
}
diff --git a/quickstep/tests/src/com/android/quickstep/NavigationBarRotationContextTest.java b/quickstep/tests/src/com/android/quickstep/NavigationBarRotationContextTest.java
index af5819a..de6740d 100644
--- a/quickstep/tests/src/com/android/quickstep/NavigationBarRotationContextTest.java
+++ b/quickstep/tests/src/com/android/quickstep/NavigationBarRotationContextTest.java
@@ -31,8 +31,8 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.launcher3.taskbar.contextual.RotationButton;
-import com.android.launcher3.taskbar.contextual.RotationButtonController;
+import com.android.systemui.shared.rotation.RotationButton;
+import com.android.systemui.shared.rotation.RotationButtonController;
import org.junit.Before;
import org.junit.Test;
@@ -55,8 +55,9 @@
Context mTargetContext = InstrumentationRegistry.getTargetContext();
final View view = new View(mTargetContext);
RotationButton rotationButton = mock(RotationButton.class);
- mRotationButtonController = new RotationButtonController(mTargetContext, 0, 0);
- mRotationButtonController.setRotationButton(rotationButton);
+ mRotationButtonController = new RotationButtonController(mTargetContext, 0, 0, 0, 0, 0, 0,
+ () -> 0);
+ mRotationButtonController.setRotationButton(rotationButton, null);
// Due to a mockito issue, only spy the object after setting the initial state
mRotationButtonController = spy(mRotationButtonController);
final AnimatedVectorDrawable kbd = mock(AnimatedVectorDrawable.class);
@@ -85,7 +86,7 @@
// No navigation bar should not call to set visibility state
mRotationButtonController.onBehaviorChanged(DEFAULT_DISPLAY,
WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
- mRotationButtonController.onTaskBarVisibilityChange(false /* showing */);
+ mRotationButtonController.onNavigationBarWindowVisibilityChange(false /* showing */);
verify(mRotationButtonController, times(0)).setRotateSuggestionButtonState(
false /* visible */);
verify(mRotationButtonController, times(0)).setRotateSuggestionButtonState(
@@ -100,7 +101,7 @@
true /* visible */);
// Since rotation has changed rotation should be pending, show mButton when showing nav bar
- mRotationButtonController.onTaskBarVisibilityChange(true /* showing */);
+ mRotationButtonController.onNavigationBarWindowVisibilityChange(true /* showing */);
verify(mRotationButtonController, times(1)).setRotateSuggestionButtonState(
true /* visible */);
}
@@ -108,7 +109,7 @@
@Test
public void testOnRotationProposalShowButton() {
// Navigation bar being visible should not call to set visibility state
- mRotationButtonController.onTaskBarVisibilityChange(true /* showing */);
+ mRotationButtonController.onNavigationBarWindowVisibilityChange(true /* showing */);
verify(mRotationButtonController, times(0))
.setRotateSuggestionButtonState(false /* visible */);
verify(mRotationButtonController, times(0))
diff --git a/res/values/config.xml b/res/values/config.xml
index 6fdb4de..25911e6 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -136,7 +136,6 @@
<item name="swipe_up_rect_xy_fling_friction" type="dimen" format="float">1.5</item>
<item name="swipe_up_scale_start" type="dimen" format="float">0.88</item>
- <item name="swipe_up_duration" type="dimen" format="float">400</item>
<item name="swipe_up_trans_y_dp" type="dimen" format="float">4.5</item>
<item name="swipe_up_trans_y_dp_per_s" type="dimen" format="float">3</item>
@@ -147,33 +146,10 @@
<item name="swipe_up_rect_xy_damping_ratio" type="dimen" format="float">0.8</item>
<item name="swipe_up_rect_xy_stiffness" type="dimen" format="float">200</item>
-
- <item name="swipe_up_rect_2_x_damping_ratio" type="dimen" format="float">1</item>
- <item name="swipe_up_rect_2_x_stiffness" type="dimen" format="float">250</item>
-
- <item name="swipe_up_rect_2_y_damping_ratio" type="dimen" format="float">1</item>
- <item name="swipe_up_rect_2_y_stiffness" type="dimen" format="float">600</item>
-
- <item name="swipe_up_rect_2_y_stiffness_low_swipe_multiplier" type="dimen" format="float">0.8</item>
<item name="swipe_up_low_swipe_duration_multiplier" type="dimen" format="float">1</item>
<item name="swipe_up_launcher_alpha_max_progress" type="dimen" format="float">0.85</item>
-
- <item name="c1_a" type="dimen" format="float">0.05</item>
- <item name="c1_b" type="dimen" format="float">0</item>
- <item name="c1_c" type="dimen" format="float">0.133333</item>
- <item name="c1_d" type="dimen" format="float">0.06</item>
-
- <item name="mp_x" type="dimen" format="float">0.166666</item>
- <item name="mp_y" type="dimen" format="float">.4</item>
-
- <item name="c2_a" type="dimen" format="float">0.208333</item>
- <item name="c2_b" type="dimen" format="float">.82</item>
- <item name="c2_c" type="dimen" format="float">.25</item>
- <item name="c2_d" type="dimen" format="float">1</item>
-
-
<item name="staggered_damping_ratio" type="dimen" format="float">0.7</item>
<item name="staggered_stiffness" type="dimen" format="float">150</item>
<dimen name="unlock_staggered_velocity_dp_per_s">2dp</dimen>
@@ -188,33 +164,14 @@
<dimen name="swipe_up_max_velocity">7.619dp</dimen>
<array name="dynamic_resources">
- <item>@dimen/swipe_up_duration</item>
<item>@dimen/swipe_up_scale_start</item>
<item>@dimen/swipe_up_trans_y_dp</item>
<item>@dimen/swipe_up_trans_y_dp_per_s</item>
<item>@dimen/swipe_up_trans_y_damping</item>
<item>@dimen/swipe_up_trans_y_stiffness</item>
- <item>@dimen/swipe_up_rect_2_x_damping_ratio</item>
- <item>@dimen/swipe_up_rect_2_x_stiffness</item>
- <item>@dimen/swipe_up_rect_2_y_damping_ratio</item>
- <item>@dimen/swipe_up_rect_2_y_stiffness</item>
<item>@dimen/swipe_up_launcher_alpha_max_progress</item>
- <item>@dimen/swipe_up_rect_2_y_stiffness_low_swipe_multiplier</item>
<item>@dimen/swipe_up_low_swipe_duration_multiplier</item>
<item>@dimen/swipe_up_max_velocity</item>
-
- <item>@dimen/c1_a</item>
- <item>@dimen/c1_b</item>
- <item>@dimen/c1_c</item>
- <item>@dimen/c1_d</item>
-
- <item>@dimen/mp_x</item>
- <item>@dimen/mp_y</item>
-
- <item>@dimen/c2_a</item>
- <item>@dimen/c2_b</item>
- <item>@dimen/c2_c</item>
- <item>@dimen/c2_d</item>
</array>
<string-array name="filtered_components" ></string-array>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d7a1506..e215c20 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -251,7 +251,7 @@
<string name="wallpaper_button_text">Wallpapers</string>
<!-- Text for wallpaper change button [CHAR LIMIT=30]-->
<string name="styles_wallpaper_button_text">Wallpaper & style</string>
- <!-- Text for settings button [CHAR LIMIT=30]-->
+ <!-- Text for settings button [CHAR LIMIT=20]-->
<string name="settings_button_text">Home settings</string>
<!-- Message shown when a feature is disabled by the administrator -->
<string name="msg_disabled_by_admin">Disabled by your admin</string>
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 796c912..1358387 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -233,9 +233,6 @@
public static final BooleanFlag NOTIFY_CRASHES = getDebugFlag("NOTIFY_CRASHES", false,
"Sends a notification whenever launcher encounters an uncaught exception.");
- public static final BooleanFlag PROTOTYPE_APP_CLOSE = getDebugFlag(
- "PROTOTYPE_APP_CLOSE", false, "Enables new app close");
-
public static final BooleanFlag ENABLE_WALLPAPER_SCRIM = getDebugFlag(
"ENABLE_WALLPAPER_SCRIM", false,
"Enables scrim over wallpaper for text protection.");
diff --git a/tests/src/com/android/launcher3/ui/WorkProfileTest.java b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
index 41cdf0f..27a2375 100644
--- a/tests/src/com/android/launcher3/ui/WorkProfileTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
@@ -32,6 +32,7 @@
import com.android.launcher3.allapps.WorkEduCard;
import com.android.launcher3.allapps.WorkProfileManager;
import com.android.launcher3.tapl.LauncherInstrumentation;
+import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
import org.junit.After;
import org.junit.Before;
@@ -86,6 +87,7 @@
}
@Test
+ @ScreenRecord // b/202735477
public void workTabExists() {
mDevice.pressHome();
waitForLauncherCondition("Launcher didn't start", Objects::nonNull);