Merge "Add Debug Logs to AllAppsStore's dump for Bitmap flags" into main
diff --git a/OWNERS b/OWNERS
index db8d442..bed2acd 100644
--- a/OWNERS
+++ b/OWNERS
@@ -34,6 +34,8 @@
samcackett@google.com
silvajordan@google.com
uwaisashraf@google.com
+vinayjoglekar@google.com
+willosborn@google.com
# Physical Keyboard & Trackpad eng team
patmanning@google.com
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index bc49146..c3fb150 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -543,4 +543,24 @@
namespace: "launcher"
description: "Enable launcher icon shape customizations"
bug: "348708061"
-}
\ No newline at end of file
+}
+
+flag {
+ name: "predictive_back_to_home_polish"
+ namespace: "launcher"
+ description: "Enables workspace reveal animation for predictive back-to-home"
+ bug: "382453424"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "predictive_back_to_home_blur"
+ namespace: "launcher"
+ description: "Adds blur for predictive back-to-home"
+ bug: "342178850"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/quickstep/dagger/LauncherAppComponent.java b/quickstep/dagger/com/android/launcher3/dagger/LauncherAppComponent.java
similarity index 91%
rename from quickstep/dagger/LauncherAppComponent.java
rename to quickstep/dagger/com/android/launcher3/dagger/LauncherAppComponent.java
index 068f01c..a4cb420 100644
--- a/quickstep/dagger/LauncherAppComponent.java
+++ b/quickstep/dagger/com/android/launcher3/dagger/LauncherAppComponent.java
@@ -17,7 +17,6 @@
package com.android.launcher3.dagger;
-import com.android.quickstep.dagger.QuickStepModule;
import com.android.quickstep.dagger.QuickstepBaseAppComponent;
import dagger.Component;
@@ -26,7 +25,7 @@
* Root component for Dagger injection for Launcher Quickstep.
*/
@LauncherAppSingleton
-@Component(modules = QuickStepModule.class)
+@Component(modules = LauncherAppModule.class)
public interface LauncherAppComponent extends QuickstepBaseAppComponent {
/** Builder for quickstep LauncherAppComponent. */
@Component.Builder
diff --git a/quickstep/dagger/com/android/launcher3/dagger/LauncherAppModule.java b/quickstep/dagger/com/android/launcher3/dagger/LauncherAppModule.java
new file mode 100644
index 0000000..1711fc1
--- /dev/null
+++ b/quickstep/dagger/com/android/launcher3/dagger/LauncherAppModule.java
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+package com.android.launcher3.dagger;
+
+import com.android.quickstep.dagger.QuickStepModule;
+
+import dagger.Module;
+
+@Module(includes = QuickStepModule.class)
+public class LauncherAppModule {}
diff --git a/quickstep/res/drawable/bg_bubble_dismiss_circle.xml b/quickstep/res/drawable/bg_bubble_dismiss_circle.xml
deleted file mode 100644
index b793eec..0000000
--- a/quickstep/res/drawable/bg_bubble_dismiss_circle.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2023 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.
- -->
-
-<shape
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="oval">
-
- <stroke
- android:width="2dp"
- android:color="@android:color/system_accent1_600" />
-
- <solid android:color="@android:color/system_accent1_600" />
-</shape>
\ No newline at end of file
diff --git a/quickstep/res/drawable/ic_bubble_dismiss_white.xml b/quickstep/res/drawable/ic_bubble_dismiss_white.xml
deleted file mode 100644
index b15111b..0000000
--- a/quickstep/res/drawable/ic_bubble_dismiss_white.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2023 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="20dp"
- android:height="20dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M19.000000,6.400000l-1.400000,-1.400000 -5.600000,5.600000 -5.600000,-5.600000 -1.400000,1.400000 5.600000,5.600000 -5.600000,5.600000 1.400000,1.400000 5.600000,-5.600000 5.600000,5.600000 1.400000,-1.400000 -5.600000,-5.600000z"
- android:fillColor="@android:color/system_neutral1_50"/>
-</vector>
diff --git a/quickstep/res/layout/floating_header_content.xml b/quickstep/res/layout/floating_header_content.xml
index b21c34b..0021e22 100644
--- a/quickstep/res/layout/floating_header_content.xml
+++ b/quickstep/res/layout/floating_header_content.xml
@@ -3,8 +3,8 @@
<com.android.launcher3.appprediction.PredictionRowView
android:id="@+id/prediction_row"
- android:accessibilityPaneTitle="@string/title_app_suggestions"
android:layout_width="match_parent"
+ android:importantForAccessibility="yes"
android:layout_height="wrap_content" />
<com.android.launcher3.appprediction.AppsDividerView
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index e8c8505..1f33e08 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -23,7 +23,6 @@
<string name="stats_log_manager_class" translatable="false">com.android.quickstep.logging.StatsLogCompatManager</string>
<string name="test_information_handler_class" translatable="false">com.android.quickstep.QuickstepTestInformationHandler</string>
- <string name="window_manager_proxy_class" translatable="false">com.android.quickstep.util.SystemWindowManagerProxy</string>
<string name="widget_holder_factory_class" translatable="false">com.android.launcher3.uioverrides.QuickstepWidgetHolder$QuickstepHolderFactory</string>
<string name="instant_app_resolver_class" translatable="false">com.android.quickstep.InstantAppResolverImpl</string>
<string name="app_launch_tracker_class" translatable="false">com.android.launcher3.appprediction.PredictionAppTracker</string>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index b221b22..b404bb5 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -467,9 +467,9 @@
<dimen name="bubblebar_icon_elevation">1dp</dimen>
<!-- Bubble bar dismiss view -->
- <dimen name="bubblebar_dismiss_target_size">96dp</dimen>
+ <dimen name="bubblebar_dismiss_target_size">@dimen/floating_dismiss_background_size</dimen>
<dimen name="bubblebar_dismiss_target_small_size">60dp</dimen>
- <dimen name="bubblebar_dismiss_target_icon_size">24dp</dimen>
+ <dimen name="bubblebar_dismiss_target_icon_size">@dimen/floating_dismiss_icon_size</dimen>
<dimen name="bubblebar_dismiss_target_bottom_margin">50dp</dimen>
<dimen name="bubblebar_dismiss_floating_gradient_height">548dp</dimen>
<dimen name="bubblebar_dismiss_zone_width">192dp</dimen>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 026e25c..df949c3 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -125,8 +125,6 @@
<string name="back_gesture_intro_title">Swipe to go back</string>
<!-- Introduction subtitle for the Back gesture tutorial. [CHAR LIMIT=200] -->
<string name="back_gesture_intro_subtitle">To go back to the last screen, swipe from the left or right edge to the middle of the screen.</string>
- <!-- Introduction subtitle for the Back gesture tutorial that will be spoken by screen readers. [CHAR LIMIT=200] -->
- <string name="back_gesture_spoken_intro_subtitle">To go back to the last screen, swipe with 2 fingers from the left or right edge to the middle of the screen.</string>
<!-- Title of the gesture tutorial section educating users on how to go back to the previous screen. [CHAR LIMIT=100] -->
<string name="back_gesture_tutorial_title">Go back</string>
<!-- Subtitle of the gesture tutorial section educating users on how to go to back to the previous screen [CHAR LIMIT=100] -->
@@ -145,8 +143,6 @@
<string name="home_gesture_intro_title">Swipe to go home</string>
<!-- Introduction subtitle for the Home gesture tutorial. [CHAR LIMIT=100] -->
<string name="home_gesture_intro_subtitle">Swipe up from the bottom of your screen. This gesture always takes you to the Home screen.</string>
- <!-- Introduction subtitle for the Home gesture tutorial that will be spoken by screen readers. [CHAR LIMIT=100] -->
- <string name="home_gesture_spoken_intro_subtitle">Swipe up with 2 fingers from the bottom of the screen. This gesture always takes you to the Home screen.</string>
<!-- Title of the gesture tutorial section educating users on how to go to the home screen. [CHAR LIMIT=100] -->
<string name="home_gesture_tutorial_title">Go home</string>
<!-- Subtitle of the gesture tutorial section educating users on how to go to the home screen [CHAR LIMIT=100] -->
@@ -168,8 +164,6 @@
<string name="overview_gesture_intro_title">Swipe to switch apps</string>
<!-- Introduction subtitle for the Overview gesture tutorial. [CHAR LIMIT=100] -->
<string name="overview_gesture_intro_subtitle">To switch between apps, swipe up from the bottom of your screen, hold, then release.</string>
- <!-- Introduction subtitle for the Overview gesture tutorial that will be spoken by screen readers. [CHAR LIMIT=100] -->
- <string name="overview_gesture_spoken_intro_subtitle">To switch between apps, swipe up with 2 fingers from the bottom of your screen, hold, then release.</string>
<!-- Title of the gesture tutorial section educating users on how to switch between apps. [CHAR LIMIT=100] -->
<string name="overview_gesture_tutorial_title">Switch apps</string>
<!-- Subtitle of the gesture tutorial section educating users on how to switch between apps [CHAR LIMIT=100] -->
diff --git a/quickstep/src/com/android/launcher3/QuickstepAccessibilityDelegate.java b/quickstep/src/com/android/launcher3/QuickstepAccessibilityDelegate.java
index 1161720..08ef8fe 100644
--- a/quickstep/src/com/android/launcher3/QuickstepAccessibilityDelegate.java
+++ b/quickstep/src/com/android/launcher3/QuickstepAccessibilityDelegate.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3;
+import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED;
+
import static androidx.recyclerview.widget.RecyclerView.NO_POSITION;
import android.view.KeyEvent;
@@ -48,7 +50,11 @@
public void onPopulateAccessibilityEvent(View view, AccessibilityEvent event) {
super.onPopulateAccessibilityEvent(view, event);
// Scroll to the position if focused view in main allapps list and not completely visible.
- scrollToPositionIfNeeded(view);
+ // Gate based on TYPE_VIEW_ACCESSIBILITY_FOCUSED for unintended scrolling with external
+ // mouse.
+ if (event.getEventType() == TYPE_VIEW_ACCESSIBILITY_FOCUSED) {
+ scrollToPositionIfNeeded(view);
+ }
}
private void scrollToPositionIfNeeded(View view) {
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 2759816..f38693d 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -1670,7 +1670,10 @@
|| mLauncher.getWorkspace().isOverlayShown()
|| shouldPlayFallbackClosingAnimation(appTargets);
- boolean playWorkspaceReveal = !fromPredictiveBack;
+ boolean playWorkspaceReveal = true;
+ if (!Flags.predictiveBackToHomePolish()) {
+ playWorkspaceReveal = !fromPredictiveBack;
+ }
boolean skipAllAppsScale = false;
if (!playFallBackAnimation) {
PointF velocity;
@@ -1689,12 +1692,12 @@
// Skip scaling all apps, otherwise FloatingIconView will get wrong
// layout bounds.
skipAllAppsScale = true;
- } else if (!fromPredictiveBack) {
+ } else if (Flags.predictiveBackToHomePolish() || !fromPredictiveBack) {
if (enableScalingRevealHomeAnimation()) {
anim.play(
- new ScalingWorkspaceRevealAnim(
- mLauncher, rectFSpringAnim,
- rectFSpringAnim.getTargetRect()).getAnimators());
+ new ScalingWorkspaceRevealAnim(mLauncher, rectFSpringAnim,
+ rectFSpringAnim.getTargetRect(),
+ !fromPredictiveBack /* playAlphaReveal */).getAnimators());
} else {
anim.play(new StaggeredWorkspaceAnim(mLauncher, velocity.y,
true /* animateOverviewScrim */, launcherView).getAnimators());
@@ -1713,15 +1716,7 @@
anim.play(getFallbackClosingWindowAnimators(appTargets));
}
- // Normally, we run the launcher content animation when we are transitioning
- // home, but if home is already visible, then we don't want to animate the
- // contents of launcher unless we know that we are animating home as a result
- // of the home button press with quickstep, which will result in launcher being
- // started on touch down, prior to the animation home (and won't be in the
- // targets list because it is already visible). In that case, we force
- // invisibility on touch down, and only reset it after the animation to home
- // is initialized.
- if (launcherIsForceInvisibleOrOpening || fromPredictiveBack) {
+ if (Flags.predictiveBackToHomePolish()) {
AnimatorListenerAdapter endListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -1730,7 +1725,24 @@
mLauncher, WALLPAPER_OPEN_ANIMATION_FINISHED_MESSAGE);
}
};
+ if (rectFSpringAnim != null) {
+ rectFSpringAnim.addAnimatorListener(endListener);
+ } else {
+ anim.addListener(endListener);
+ }
+ }
+ // Normally, we run the launcher content animation when we are transitioning
+ // home, but if home is already visible, then we don't want to animate the
+ // contents of launcher unless we know that we are animating home as a result
+ // of the home button press with quickstep, which will result in launcher being
+ // started on touch down, prior to the animation home (and won't be in the
+ // targets list because it is already visible). In that case, we force
+ // invisibility on touch down, and only reset it after the animation to home
+ // is initialized.
+ boolean legacyFromPredictiveBack =
+ !Flags.predictiveBackToHomePolish() && fromPredictiveBack;
+ if (launcherIsForceInvisibleOrOpening || legacyFromPredictiveBack) {
if (rectFSpringAnim != null && anim.getChildAnimations().isEmpty()) {
addCujInstrumentation(rectFSpringAnim, Cuj.CUJ_LAUNCHER_APP_CLOSE_TO_HOME);
} else {
@@ -1738,17 +1750,26 @@
? Cuj.CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK
: Cuj.CUJ_LAUNCHER_APP_CLOSE_TO_HOME);
}
-
- if (fromPredictiveBack && rectFSpringAnim != null) {
- rectFSpringAnim.addAnimatorListener(endListener);
- } else {
- anim.addListener(endListener);
+ if (!Flags.predictiveBackToHomePolish()) {
+ AnimatorListenerAdapter endListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ AccessibilityManagerCompat.sendTestProtocolEventToTest(
+ mLauncher, WALLPAPER_OPEN_ANIMATION_FINISHED_MESSAGE);
+ }
+ };
+ if (fromPredictiveBack && rectFSpringAnim != null) {
+ rectFSpringAnim.addAnimatorListener(endListener);
+ } else {
+ anim.addListener(endListener);
+ }
}
// Only register the content animation for cancellation when state changes
mLauncher.getStateManager().setCurrentAnimation(anim);
- if (mLauncher.isInState(LauncherState.ALL_APPS) && !fromPredictiveBack) {
+ if (mLauncher.isInState(LauncherState.ALL_APPS) && !legacyFromPredictiveBack) {
Pair<AnimatorSet, Runnable> contentAnimator =
getLauncherContentAnimator(false, LAUNCHER_RESUME_START_DELAY,
skipAllAppsScale);
diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
index 8e80aa5..22e491f 100644
--- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
@@ -16,12 +16,16 @@
package com.android.launcher3.appprediction;
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+
import android.content.Context;
import android.graphics.Canvas;
+import android.os.Build;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
@@ -91,6 +95,14 @@
}
@Override
+ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(info);
+ if (Build.VERSION.SDK_INT >= UPSIDE_DOWN_CAKE) {
+ info.setContainerTitle(mActivityContext.getString(R.string.title_app_suggestions));
+ }
+ }
+
+ @Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mActivityContext.addOnDeviceProfileChangeListener(this);
diff --git a/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java b/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java
index d604742..cd08897 100644
--- a/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java
+++ b/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.EncryptionType.ENCRYPTED;
import static com.android.launcher3.LauncherPrefs.nonRestorableItem;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
+import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
import static com.android.quickstep.InstantAppResolverImpl.COMPONENT_CLASS_MARKER;
import android.app.prediction.AppTarget;
@@ -95,7 +96,7 @@
itemInfo = apps.data.stream()
.filter(info -> user.equals(info.user) && cn.equals(info.componentName))
.map(ai -> {
- app.getIconCache().getTitleAndIcon(ai, false);
+ app.getIconCache().getTitleAndIcon(ai, DEFAULT_LOOKUP_FLAG);
return ai.makeWorkspaceItem(context);
})
.findAny()
@@ -106,7 +107,7 @@
return null;
}
AppInfo ai = new AppInfo(context, lai, user);
- app.getIconCache().getTitleAndIcon(ai, lai, false);
+ app.getIconCache().getTitleAndIcon(ai, lai, DEFAULT_LOOKUP_FLAG);
return ai.makeWorkspaceItem(context);
});
diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
index 2f4c6f6..daba0dd 100644
--- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
+++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
@@ -26,6 +26,7 @@
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
import static com.android.launcher3.hybridhotseat.HotseatPredictionModel.convertDataModelToAppTargetBundle;
+import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
import static com.android.launcher3.model.PredictionHelper.getAppTargetFromItemInfo;
import static com.android.launcher3.model.PredictionHelper.wrapAppTargetWithItemLocation;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -572,7 +573,7 @@
mPmHelper,
mUMS.isUserQuiet(user));
info.container = mContainer;
- mAppState.getIconCache().getTitleAndIcon(info, lai, false);
+ mAppState.getIconCache().getTitleAndIcon(info, lai, DEFAULT_LOOKUP_FLAG);
mReadCount++;
return info.makeWorkspaceItem(mAppState.getContext());
}
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
index fd0243a..488cea5 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
@@ -111,6 +111,17 @@
public boolean areDesktopTasksVisible() {
boolean desktopTasksVisible = mVisibleDesktopTasksCount > 0;
if (DEBUG) {
+ Log.d(TAG, "areDesktopTasksVisible: desktopVisible=" + desktopTasksVisible);
+ }
+ return desktopTasksVisible;
+ }
+
+ /**
+ * Whether desktop tasks are visible in desktop mode.
+ */
+ public boolean areDesktopTasksVisibleAndNotInOverview() {
+ boolean desktopTasksVisible = mVisibleDesktopTasksCount > 0;
+ if (DEBUG) {
Log.d(TAG, "areDesktopTasksVisible: desktopVisible=" + desktopTasksVisible
+ " overview=" + mInOverviewState);
}
@@ -160,9 +171,9 @@
if (visibleTasksCount != mVisibleDesktopTasksCount) {
final boolean wasVisible = mVisibleDesktopTasksCount > 0;
final boolean isVisible = visibleTasksCount > 0;
- final boolean wereDesktopTasksVisibleBefore = areDesktopTasksVisible();
+ final boolean wereDesktopTasksVisibleBefore = areDesktopTasksVisibleAndNotInOverview();
mVisibleDesktopTasksCount = visibleTasksCount;
- final boolean areDesktopTasksVisibleNow = areDesktopTasksVisible();
+ final boolean areDesktopTasksVisibleNow = areDesktopTasksVisibleAndNotInOverview();
if (wereDesktopTasksVisibleBefore != areDesktopTasksVisibleNow) {
notifyDesktopVisibilityListeners(areDesktopTasksVisibleNow);
}
@@ -219,13 +230,12 @@
+ " currentValue=" + mInOverviewState);
}
if (overviewStateEnabled != mInOverviewState) {
- final boolean wereDesktopTasksVisibleBefore = areDesktopTasksVisible();
+ final boolean wereDesktopTasksVisibleBefore = areDesktopTasksVisibleAndNotInOverview();
mInOverviewState = overviewStateEnabled;
- final boolean areDesktopTasksVisibleNow = areDesktopTasksVisible();
+ final boolean areDesktopTasksVisibleNow = areDesktopTasksVisibleAndNotInOverview();
if (wereDesktopTasksVisibleBefore != areDesktopTasksVisibleNow) {
notifyDesktopVisibilityListeners(areDesktopTasksVisibleNow);
}
-
if (ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()) {
return;
}
@@ -279,7 +289,7 @@
if (mBackgroundStateEnabled) {
setLauncherViewsVisibility(View.VISIBLE);
markLauncherResumed();
- } else if (areDesktopTasksVisible() && !mGestureInProgress) {
+ } else if (areDesktopTasksVisibleAndNotInOverview() && !mGestureInProgress) {
// Switching out of background state. If desktop tasks are visible, pause launcher.
setLauncherViewsVisibility(View.INVISIBLE);
markLauncherPaused();
diff --git a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
index 6a908ca..d6327bc 100644
--- a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
@@ -28,7 +28,6 @@
import com.android.launcher3.statemanager.StatefulContainer;
import com.android.quickstep.TopTaskTracker;
import com.android.quickstep.fallback.RecentsState;
-import com.android.quickstep.util.TISBindHelper;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.RecentsViewContainer;
@@ -139,12 +138,6 @@
return topTask.isHomeTask() || topTask.isRecentsTask();
}
- @Nullable
- @Override
- protected TISBindHelper getTISBindHelper() {
- return mRecentsContainer.getTISBindHelper();
- }
-
@Override
protected String getTaskbarUIControllerName() {
return "FallbackTaskbarUIController<" + mRecentsContainer.getClass().getSimpleName() + ">";
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
index de42669..cd38e5e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
@@ -188,8 +188,8 @@
mQuickSwitchViewController = new KeyboardQuickSwitchViewController(
mControllers, mOverlayContext, keyboardQuickSwitchView, mControllerCallbacks);
- final boolean onDesktop =
- mControllers.taskbarDesktopModeController.getAreDesktopTasksVisible();
+ final boolean onDesktop = mControllers.taskbarDesktopModeController
+ .getAreDesktopTasksVisibleAndNotInOverview();
if (mModel.isTaskListValid(mTaskListChangeId)
&& taskIdsToExclude.equals(mExcludedTaskIds)) {
@@ -233,7 +233,7 @@
private void processLoadedTasks(List<GroupTask> tasks, Set<Integer> taskIdsToExclude) {
mHasDesktopTask = false;
mWasDesktopTaskFilteredOut = false;
- if (mControllers.taskbarDesktopModeController.getAreDesktopTasksVisible()) {
+ if (mControllers.taskbarDesktopModeController.getAreDesktopTasksVisibleAndNotInOverview()) {
processLoadedTasksOnDesktop(tasks, taskIdsToExclude);
} else {
processLoadedTasksOutsideDesktop(tasks, taskIdsToExclude);
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 7d75286..80da467 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -49,7 +49,6 @@
import com.android.quickstep.RecentsAnimationCallbacks;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.GroupTask;
-import com.android.quickstep.util.TISBindHelper;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
@@ -217,8 +216,10 @@
private int getTaskbarAnimationDuration(boolean isVisible) {
// fast animation duration since we will not be playing workspace reveal animation.
- boolean shouldOverrideToFastAnimation =
- !isHotseatIconOnTopWhenAligned() || mLauncher.getPredictiveBackToHomeInProgress();
+ boolean shouldOverrideToFastAnimation = !isHotseatIconOnTopWhenAligned();
+ if (!Flags.predictiveBackToHomePolish()) {
+ shouldOverrideToFastAnimation |= mLauncher.getPredictiveBackToHomeInProgress();
+ }
boolean isPinnedTaskbar = DisplayController.isPinnedTaskbar(mLauncher);
if (isVisible || isPinnedTaskbar) {
return getTaskbarToHomeDuration(shouldOverrideToFastAnimation, isPinnedTaskbar);
@@ -243,7 +244,8 @@
}
if (!ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
- && mControllers.taskbarDesktopModeController.getAreDesktopTasksVisible()) {
+ && mControllers.taskbarDesktopModeController
+ .getAreDesktopTasksVisibleAndNotInOverview()) {
// TODO: b/333533253 - Remove after flag rollout
isVisible = false;
}
@@ -483,12 +485,6 @@
mTaskbarLauncherStateController.resetIconAlignment();
}
- @Nullable
- @Override
- protected TISBindHelper getTISBindHelper() {
- return mLauncher.getTISBindHelper();
- }
-
@Override
public void dumpLogs(String prefix, PrintWriter pw) {
super.dumpLogs(prefix, pw);
diff --git a/quickstep/src/com/android/launcher3/taskbar/ManageWindowsTaskbarShortcut.kt b/quickstep/src/com/android/launcher3/taskbar/ManageWindowsTaskbarShortcut.kt
index 032eb51..75ce7c3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/ManageWindowsTaskbarShortcut.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/ManageWindowsTaskbarShortcut.kt
@@ -148,11 +148,19 @@
FLAG_AUTOHIDE_SUSPEND_MULTI_INSTANCE_MENU_OPEN,
false,
)
+ controllers.taskbarPopupController.cleanUpMultiInstanceMenuReference()
}
}
)
}
+ /** Closes the multi-instance menu if it has been initialized. */
+ fun closeMultiInstanceMenu() {
+ if (::taskbarShortcutAllWindowsView.isInitialized) {
+ taskbarShortcutAllWindowsView.animateClose()
+ }
+ }
+
/**
* A view container for displaying the window of open instances of an app
*
@@ -238,6 +246,7 @@
)
taskbarOverlayContext.dragLayer?.removeView(menuView.rootView)
taskbarOverlayContext.dragLayer.removeTouchController(this)
+ controllers.taskbarPopupController.cleanUpMultiInstanceMenuReference()
}
/** TouchController implementations for closing the carousel when touched outside */
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 107facf..060173a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -189,6 +189,7 @@
private final TaskbarControllers mControllers;
private final WindowManager mWindowManager;
+ private final boolean mIsPrimaryDisplay;
private DeviceProfile mDeviceProfile;
private WindowManager.LayoutParams mWindowLayoutParams;
private WindowManager.LayoutParams mLastUpdatedLayoutParams;
@@ -234,11 +235,12 @@
public TaskbarActivityContext(Context windowContext,
@Nullable Context navigationBarPanelContext, DeviceProfile launcherDp,
- TaskbarNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider
- unfoldTransitionProgressProvider,
- @NonNull DesktopVisibilityController desktopVisibilityController) {
+ TaskbarNavButtonController buttonController,
+ ScopedUnfoldTransitionProgressProvider unfoldTransitionProgressProvider,
+ @NonNull DesktopVisibilityController desktopVisibilityController,
+ boolean isPrimaryDisplay) {
super(windowContext);
-
+ mIsPrimaryDisplay = isPrimaryDisplay;
mNavigationBarPanelContext = navigationBarPanelContext;
applyDeviceProfile(launcherDp);
final Resources resources = getResources();
@@ -627,7 +629,8 @@
*/
private WindowManager.LayoutParams createAllWindowParams() {
final int windowType =
- ENABLE_TASKBAR_NAVBAR_UNIFICATION ? TYPE_NAVIGATION_BAR : TYPE_NAVIGATION_BAR_PANEL;
+ (ENABLE_TASKBAR_NAVBAR_UNIFICATION && mIsPrimaryDisplay) ? TYPE_NAVIGATION_BAR
+ : TYPE_NAVIGATION_BAR_PANEL;
WindowManager.LayoutParams windowLayoutParams =
createDefaultWindowLayoutParams(windowType, TaskbarActivityContext.WINDOW_TITLE);
@@ -1297,7 +1300,18 @@
RemoteTransition remoteTransition =
(areDesktopTasksVisible() && canUnminimizeDesktopTask(groupTask.task1.key.id))
? createUnminimizeRemoteTransition() : null;
- handleGroupTaskLaunch(groupTask, remoteTransition, areDesktopTasksVisible());
+ if (areDesktopTasksVisible() && mControllers.uiController.isInOverviewUi()) {
+ RunnableList runnableList = recents.launchRunningDesktopTaskView();
+ // Wrapping it in runnable so we post after DW is ready for the app
+ // launch.
+ if (runnableList != null) {
+ runnableList.add(() -> UI_HELPER_EXECUTOR.execute(
+ () -> handleGroupTaskLaunch(groupTask, remoteTransition,
+ areDesktopTasksVisible())));
+ }
+ } else {
+ handleGroupTaskLaunch(groupTask, remoteTransition, areDesktopTasksVisible());
+ }
mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
} else if (tag instanceof FolderInfo) {
// Tapping an expandable folder icon on Taskbar
@@ -1318,15 +1332,18 @@
RemoteTransition remoteTransition = canUnminimizeDesktopTask(info.getTaskId())
? createUnminimizeRemoteTransition() : null;
- if (areDesktopTasksVisible() && recents != null) {
- TaskView taskView = recents.getTaskViewByTaskId(info.getTaskId());
- if (taskView == null) return;
+ TaskView taskView = null;
+ if (recents != null) {
+ taskView = recents.getTaskViewByTaskId(info.getTaskId());
+ }
+
+ if (areDesktopTasksVisible() && taskView != null) {
RunnableList runnableList = taskView.launchWithAnimation();
if (runnableList != null) {
runnableList.add(() ->
// wrapped it in runnable here since we need the post for DW to be
- // ready. if we don't other DW will be gone and only the launched task
- // will show.
+ // ready. if we don't other DW will be gone and only the launched
+ // task will show.
UI_HELPER_EXECUTOR.execute(() ->
SystemUiProxy.INSTANCE.get(this).showDesktopApp(
info.getTaskId(), remoteTransition)));
@@ -1336,6 +1353,7 @@
SystemUiProxy.INSTANCE.get(this).showDesktopApp(
info.getTaskId(), remoteTransition));
}
+
mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(
/* stash= */ true);
} else if (tag instanceof WorkspaceItemInfo) {
@@ -1417,6 +1435,7 @@
Log.e(TAG, "Unknown type clicked: " + tag);
}
+ mControllers.taskbarPopupController.maybeCloseMultiInstanceMenu();
if (shouldCloseAllOpenViews) {
AbstractFloatingView.closeAllOpenViews(this);
}
@@ -1579,8 +1598,9 @@
.launchAppPair((AppPairIcon) launchingIconView,
-1 /*cuj*/)));
} else {
- if (areDesktopTasksVisible()) {
- RunnableList runnableList = recents.launchDesktopTaskView();
+ if (areDesktopTasksVisible()
+ && mControllers.uiController.isInOverviewUi()) {
+ RunnableList runnableList = recents.launchRunningDesktopTaskView();
// Wrapping it in runnable so we post after DW is ready for the app
// launch.
if (runnableList != null) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index 826722d..af60f10 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -194,7 +194,7 @@
voiceInteractionWindowController
};
- if (taskbarDesktopModeController.getAreDesktopTasksVisible()) {
+ if (taskbarDesktopModeController.getAreDesktopTasksVisibleAndNotInOverview()) {
mCornerRoundness.value = taskbarDesktopModeController.getTaskbarCornerRoundness(
mSharedState.showCornerRadiusInDesktopMode);
} else {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt
index 47a35c5..a7c7381 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt
@@ -27,6 +27,9 @@
private lateinit var taskbarControllers: TaskbarControllers
private lateinit var taskbarSharedState: TaskbarSharedState
+ val areDesktopTasksVisibleAndNotInOverview: Boolean
+ get() = desktopVisibilityController.areDesktopTasksVisibleAndNotInOverview()
+
val areDesktopTasksVisible: Boolean
get() = desktopVisibilityController.areDesktopTasksVisible()
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index fc307b2..a9e8d6d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -344,7 +344,8 @@
// TODO(297921594) clean it up when taskbar to desktop drag is implemented.
// Pre-drag has ended, start the global system drag.
if (mDisallowGlobalDrag
- || mControllers.taskbarDesktopModeController.getAreDesktopTasksVisible()) {
+ || mControllers.taskbarDesktopModeController
+ .getAreDesktopTasksVisibleAndNotInOverview()) {
AbstractFloatingView.closeAllOpenViewsExcept(mActivity, TYPE_TASKBAR_ALL_APPS);
return;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 250e33a..1905561 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -635,7 +635,7 @@
float cornerRoundness = isInLauncher ? 0 : 1;
- if (mControllers.taskbarDesktopModeController.getAreDesktopTasksVisible()
+ if (mControllers.taskbarDesktopModeController.getAreDesktopTasksVisibleAndNotInOverview()
&& mControllers.getSharedState() != null) {
cornerRoundness =
mControllers.taskbarDesktopModeController.getTaskbarCornerRoundness(
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 9407e73..13f9a51 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -47,6 +47,7 @@
import android.provider.Settings;
import android.util.Log;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.view.Display;
import android.view.MotionEvent;
import android.view.WindowManager;
@@ -116,7 +117,6 @@
private final Context mWindowContext;
private final @Nullable Context mNavigationBarPanelContext;
private WindowManager mWindowManager;
- private boolean mAddedWindow;
private final TaskbarNavButtonController mDefaultNavButtonController;
private final ComponentCallbacks mDefaultComponentCallbacks;
@@ -133,6 +133,8 @@
private final SparseArray<TaskbarActivityContext> mTaskbars = new SparseArray<>();
/** DisplayId - {@link FrameLayout} map for Connected Display. */
private final SparseArray<FrameLayout> mRootLayouts = new SparseArray<>();
+ /** DisplayId - {@link Boolean} map indicating if RootLayout was added to window. */
+ private final SparseBooleanArray mAddedRootLayouts = new SparseBooleanArray();
private StatefulActivity mActivity;
private RecentsViewContainer mRecentsViewContainer;
@@ -590,9 +592,12 @@
}
}
- public void setWallpaperVisible(boolean isVisible) {
+ /**
+ * Sets wallpaper visibility for specific display.
+ */
+ public void setWallpaperVisible(int displayId, boolean isVisible) {
mSharedState.wallpaperVisible = isVisible;
- TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
+ TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
if (taskbar != null) {
taskbar.setWallpaperVisible(isVisible);
}
@@ -742,23 +747,42 @@
private void addTaskbarRootViewToWindow(int displayId) {
TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
- if (enableTaskbarNoRecreate() && !mAddedWindow && taskbar != null) {
+ if (!enableTaskbarNoRecreate() || taskbar == null) {
+ return;
+ }
+
+ if (!isTaskbarRootLayoutAddedForDisplay(displayId)) {
mWindowManager.addView(getTaskbarRootLayoutForDisplay(displayId),
taskbar.getWindowLayoutParams());
- mAddedWindow = true;
+ mAddedRootLayouts.put(displayId, true);
}
}
private void removeTaskbarRootViewFromWindow(int displayId) {
FrameLayout rootLayout = getTaskbarRootLayoutForDisplay(displayId);
- if (enableTaskbarNoRecreate() && mAddedWindow && rootLayout != null) {
+ if (!enableTaskbarNoRecreate() || rootLayout == null) {
+ return;
+ }
+
+ if (isTaskbarRootLayoutAddedForDisplay(displayId)) {
mWindowManager.removeViewImmediate(rootLayout);
- mAddedWindow = false;
+ mAddedRootLayouts.put(displayId, false);
removeTaskbarRootLayoutFromMap(displayId);
}
}
/**
+ * Retrieves whether RootLayout was added to window for specific display, or false if no
+ * such mapping has been made.
+ *
+ * @param displayId The ID of the display for which to retrieve the taskbar root layout.
+ * @return if RootLayout was added to window {@link Boolean} for a display or {@code false}.
+ */
+ private boolean isTaskbarRootLayoutAddedForDisplay(int displayId) {
+ return mAddedRootLayouts.get(displayId);
+ }
+
+ /**
* Returns the {@link TaskbarActivityContext} associated with the given display ID.
*
* @param displayId The ID of the display to retrieve the taskbar for.
@@ -776,7 +800,7 @@
private TaskbarActivityContext createTaskbarActivityContext(DeviceProfile dp, int displayId) {
TaskbarActivityContext newTaskbar = new TaskbarActivityContext(mWindowContext,
mNavigationBarPanelContext, dp, mDefaultNavButtonController,
- mUnfoldProgressProvider, mDesktopVisibilityController);
+ mUnfoldProgressProvider, mDesktopVisibilityController, isDefaultDisplay(displayId));
addTaskbarToMap(displayId, newTaskbar);
return newTaskbar;
@@ -824,6 +848,10 @@
addTaskbarRootLayoutToMap(displayId, newTaskbarRootLayout);
}
+ private boolean isDefaultDisplay(int displayId) {
+ return displayId == getDefaultDisplayId();
+ }
+
/**
* Retrieves the root layout of the taskbar for the specified display.
*
@@ -853,6 +881,7 @@
*/
private void removeTaskbarRootLayoutFromMap(int displayId) {
if (mRootLayouts.contains(displayId)) {
+ mAddedRootLayouts.delete(displayId);
mRootLayouts.delete(displayId);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
index 4881836..d1f9be0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
@@ -344,6 +344,10 @@
mCallbacks.onToggleOverview();
}
+ public void hideOverview() {
+ mCallbacks.onHideOverview();
+ }
+
void sendBackKeyEvent(int action, boolean cancelled) {
if (action == mLastSentBackAction) {
// There must always be an alternating sequence of ACTION_DOWN and ACTION_UP events
@@ -411,5 +415,8 @@
/** Callback invoked when the overview button is pressed. */
default void onToggleOverview() {}
+
+ /** Callback invoken when a visible overview needs to be hidden. */
+ default void onHideOverview() { }
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
index bcfc718..23c5070 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
@@ -57,7 +57,10 @@
return
}
val shouldPinTaskbar =
- if (controllers.taskbarDesktopModeController.areDesktopTasksVisible) {
+ if (
+ controllers.taskbarDesktopModeController
+ .areDesktopTasksVisibleAndNotInOverview
+ ) {
!launcherPrefs.get(TASKBAR_PINNING_IN_DESKTOP_MODE)
} else {
!launcherPrefs.get(TASKBAR_PINNING)
@@ -137,7 +140,7 @@
@VisibleForTesting
fun recreateTaskbarAndUpdatePinningValue() {
updateIsAnimatingTaskbarPinningAndNotifyTaskbarDragLayer(false)
- if (controllers.taskbarDesktopModeController.areDesktopTasksVisible) {
+ if (controllers.taskbarDesktopModeController.areDesktopTasksVisibleAndNotInOverview) {
launcherPrefs.put(
TASKBAR_PINNING_IN_DESKTOP_MODE,
!launcherPrefs.get(TASKBAR_PINNING_IN_DESKTOP_MODE),
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
index abf35a2..e704691 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
@@ -17,6 +17,7 @@
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS;
import static com.android.launcher3.model.data.AppInfo.COMPONENT_KEY_COMPARATOR;
+import static com.android.launcher3.popup.SystemShortcut.PIN_UNPIN_ITEM;
import static com.android.launcher3.util.SplitConfigurationOptions.getLogEventForPosition;
import android.content.Intent;
@@ -86,6 +87,8 @@
private TaskbarControllers mControllers;
private boolean mAllowInitialSplitSelection;
private AppInfo[] mAppInfosList;
+ private ManageWindowsTaskbarShortcut<BaseTaskbarContext> mManageWindowsTaskbarShortcut;
+
public TaskbarPopupController(TaskbarActivityContext context) {
mContext = context;
@@ -111,6 +114,19 @@
mPopupDataProvider.setDeepShortcutMap(deepShortcutMapCopy);
}
+ /** Closes the multi-instance menu if it is enabled and currently open. */
+ public void maybeCloseMultiInstanceMenu() {
+ if (Flags.enableMultiInstanceMenuTaskbar() && mManageWindowsTaskbarShortcut != null) {
+ mManageWindowsTaskbarShortcut.closeMultiInstanceMenu();
+ cleanUpMultiInstanceMenuReference();
+ }
+ }
+
+ /** Releases the reference to the Taskbar multi-instance menu */
+ public void cleanUpMultiInstanceMenuReference() {
+ mManageWindowsTaskbarShortcut = null;
+ }
+
public void setAllowInitialSplitSelection(boolean allowInitialSplitSelection) {
mAllowInitialSplitSelection = allowInitialSplitSelection;
}
@@ -195,8 +211,12 @@
// append split options to APP_INFO shortcut if not in Desktop Windowing mode, the order
// here will reflect in the popup
ArrayList<SystemShortcut.Factory> shortcuts = new ArrayList<>();
+ if (Flags.enablePinningAppWithContextMenu()) {
+ shortcuts.add(PIN_UNPIN_ITEM);
+ }
shortcuts.add(APP_INFO);
- if (!mControllers.taskbarDesktopModeController.getAreDesktopTasksVisible()) {
+ if (!mControllers.taskbarDesktopModeController
+ .getAreDesktopTasksVisibleAndNotInOverview()) {
shortcuts.addAll(mControllers.uiController.getSplitMenuOptions().toList());
}
if (com.android.wm.shell.Flags.enableBubbleAnything()) {
@@ -206,6 +226,7 @@
if (Flags.enableMultiInstanceMenuTaskbar()
&& DesktopModeStatus.canEnterDesktopMode(mContext)
&& !mControllers.taskbarStashController.isInOverview()) {
+ maybeCloseMultiInstanceMenu();
shortcuts.addAll(getMultiInstanceMenuOptions().toList());
}
return shortcuts.stream();
@@ -325,8 +346,9 @@
public SystemShortcut.Factory<BaseTaskbarContext> createManageWindowsShortcutFactory() {
return (context, itemInfo, originalView) -> {
if (shouldShowMultiInstanceOptions(itemInfo)) {
- return new ManageWindowsTaskbarShortcut<>(context, itemInfo, originalView,
- mControllers);
+ mManageWindowsTaskbarShortcut = new ManageWindowsTaskbarShortcut<>(
+ context, itemInfo, originalView, mControllers);
+ return mManageWindowsTaskbarShortcut;
}
return null;
};
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
index a64dab1..f4a7d68 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
@@ -77,6 +77,8 @@
public List<BubbleInfo> bubbleInfoItems;
+ public List<BubbleInfo> suppressedBubbleInfoItems;
+
/** Returns whether there are a saved bubbles. */
public boolean hasSavedBubbles() {
return bubbleInfoItems != null && !bubbleInfoItems.isEmpty();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 67be8da..7dd40af 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -1180,7 +1180,8 @@
// Do not stash if hardware keyboard is attached, in 3 button nav and desktop windowing mode
if (isHardwareKeyboard()
&& mActivity.isThreeButtonNav()
- && mControllers.taskbarDesktopModeController.getAreDesktopTasksVisible()) {
+ && mControllers.taskbarDesktopModeController
+ .getAreDesktopTasksVisibleAndNotInOverview()) {
return false;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index 8b636dd..f29f95d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -39,10 +39,7 @@
import com.android.launcher3.taskbar.bubbles.BubbleBarController;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.SplitConfigurationOptions;
-import com.android.quickstep.OverviewCommandHelper;
-import com.android.quickstep.OverviewCommandHelper.CommandType;
import com.android.quickstep.util.GroupTask;
-import com.android.quickstep.util.TISBindHelper;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskContainer;
import com.android.quickstep.views.TaskView;
@@ -389,26 +386,13 @@
/** Adjusts the hotseat for the bubble bar. */
public void adjustHotseatForBubbleBar(boolean isBubbleBarVisible) {}
- @Nullable
- protected TISBindHelper getTISBindHelper() {
- return null;
- }
-
/**
* Launches the focused task in the Keyboard Quick Switch view through the OverviewCommandHelper
* <p>
* Use this helper method when the focused task may be the overview task.
*/
public void launchKeyboardFocusedTask() {
- TISBindHelper tisBindHelper = getTISBindHelper();
- if (tisBindHelper == null) {
- return;
- }
- OverviewCommandHelper overviewCommandHelper = tisBindHelper.getOverviewCommandHelper();
- if (overviewCommandHelper == null) {
- return;
- }
- overviewCommandHelper.addCommand(CommandType.HIDE);
+ mControllers.navButtonController.hideOverview();
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
index dddfdfe..c7ef960 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
@@ -25,6 +25,7 @@
import android.annotation.SuppressLint;
import android.content.Context;
import android.view.GestureDetector;
+import android.view.HapticFeedbackConstants;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.View;
@@ -230,15 +231,19 @@
@Override
public void onLongPress(@NonNull MotionEvent event) {
- maybeShowPinningView(event);
+ if (maybeShowPinningView(event)) {
+ mTaskbarView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ }
}
- private void maybeShowPinningView(@NonNull MotionEvent event) {
+ /** Returns true if the taskbar pinning popup view was shown for {@code event}. */
+ private boolean maybeShowPinningView(@NonNull MotionEvent event) {
if (!DisplayController.isPinnedTaskbar(mActivity) || mTaskbarView.isEventOverAnyItem(
event)) {
- return;
+ return false;
}
mControllers.taskbarPinningController.showPinningView(mTaskbarView, event.getRawX());
+ return true;
}
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 438478f..60de066 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -84,6 +84,7 @@
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.LauncherBindableItemsContainer;
+import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
import com.android.launcher3.util.MultiTranslateDelegate;
@@ -130,8 +131,6 @@
private static final int TRANSITION_FADE_IN_DURATION = 167;
private static final int TRANSITION_FADE_OUT_DURATION = 83;
- private static boolean sEnableModelLoadingForTests = true;
-
private final TaskbarActivityContext mActivity;
private final TaskbarView mTaskbarView;
private final MultiValueAlpha mTaskbarIconAlpha;
@@ -243,7 +242,8 @@
mTaskbarIconTranslationXForPinning.updateValue(pinningValue);
mModelCallbacks.init(controllers);
- if (mActivity.isUserSetupComplete() && sEnableModelLoadingForTests) {
+ if (mActivity.isUserSetupComplete()
+ && !(mActivity.getApplicationContext() instanceof SandboxContext)) {
// Only load the callbacks if user setup is completed
controllers.runAfterInit(() -> LauncherAppState.getInstance(mActivity).getModel()
.addCallbacksAndLoad(mModelCallbacks));
@@ -1215,12 +1215,6 @@
mModelCallbacks.dumpLogs(prefix + "\t", pw);
}
- /** Enables model loading for tests. */
- @VisibleForTesting
- public static void enableModelLoadingForTests(boolean enable) {
- sEnableModelLoadingForTests = enable;
- }
-
private ObjectAnimator createTaskbarIconsShiftAnimator(float translationX) {
ObjectAnimator animator = mIconsTranslationXForNavbar.animateToValue(translationX);
animator.setStartDelay(FADE_OUT_ANIM_POSITION_DURATION_MS);
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
index 07d86e4..ddbf3b7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
@@ -141,6 +141,7 @@
if (isOpen()) {
mSlideInView.close(true);
} else {
+ mControllers.taskbarPopupController.maybeCloseMultiInstanceMenu();
show(true, showKeyboard);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index 5b3c233..9683f8b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -107,6 +107,7 @@
private final Context mContext;
private final BubbleBarView mBarView;
private final ArrayMap<String, BubbleBarBubble> mBubbles = new ArrayMap<>();
+ private final ArrayMap<String, BubbleBarBubble> mSuppressedBubbles = new ArrayMap<>();
private static final Executor BUBBLE_STATE_EXECUTOR = Executors.newSingleThreadExecutor(
new SimpleThreadFactory("BubbleStateUpdates-", THREAD_PRIORITY_BACKGROUND));
@@ -188,6 +189,10 @@
}
});
mSharedState.bubbleInfoItems = Arrays.asList(bubbleInfoItems);
+ mSharedState.suppressedBubbleInfoItems = new ArrayList<>(mSuppressedBubbles.size());
+ for (int i = 0; i < mSuppressedBubbles.size(); i++) {
+ mSharedState.suppressedBubbleInfoItems.add(mSuppressedBubbles.valueAt(i).getInfo());
+ }
}
/** Initializes controllers. */
@@ -290,7 +295,11 @@
if (sharedState.bubbleBarLocation != null) {
updateBubbleBarLocationInternal(sharedState.bubbleBarLocation);
}
- List<BubbleInfo> bubbleInfos = sharedState.bubbleInfoItems;
+ restoreSavedBubbles(sharedState.bubbleInfoItems);
+ restoreSuppressed(sharedState.suppressedBubbleInfoItems);
+ }
+
+ private void restoreSavedBubbles(List<BubbleInfo> bubbleInfos) {
if (bubbleInfos == null || bubbleInfos.isEmpty()) return;
// Iterate in reverse because new bubbles are added in front and the list is in order.
for (int i = bubbleInfos.size() - 1; i >= 0; i--) {
@@ -304,6 +313,18 @@
}
}
+ private void restoreSuppressed(List<BubbleInfo> bubbleInfos) {
+ if (bubbleInfos == null || bubbleInfos.isEmpty()) return;
+ for (BubbleInfo bubbleInfo : bubbleInfos.reversed()) {
+ BubbleBarBubble bb = mBubbleCreator.populateBubble(mContext, bubbleInfo,
+ mBarView, /* existingBubble= */
+ null);
+ if (bb != null) {
+ mSuppressedBubbles.put(bb.getKey(), bb);
+ }
+ }
+ }
+
private void applyViewChanges(BubbleBarViewUpdate update) {
final boolean isCollapsed = (update.expandedChanged && !update.expanded)
|| (!update.expandedChanged && !mBubbleBarViewController.isExpanded());
@@ -375,9 +396,7 @@
// if a bubble was updated upstream, but removed before the update was received, add it back
if (update.updatedBubble != null && !mBubbles.containsKey(update.updatedBubble.getKey())) {
- mBubbles.put(update.updatedBubble.getKey(), update.updatedBubble);
- mBubbleBarViewController.addBubble(
- update.updatedBubble, isExpanding, suppressAnimation);
+ addBubbleInternally(update.updatedBubble, isExpanding, suppressAnimation);
}
if (update.addedBubble != null && isCollapsed) {
@@ -405,10 +424,29 @@
mBubbleBarViewController.showOverflow(true);
}
- // Update the visibility if this is the initial state or if there are no bubbles.
+ if (update.suppressedBubbleKey != null) {
+ BubbleBarBubble bb = mBubbles.remove(update.suppressedBubbleKey);
+ if (bb != null) {
+ mSuppressedBubbles.put(update.suppressedBubbleKey, bb);
+ mBubbleBarViewController.removeBubble(bb);
+ }
+ }
+ if (update.unsuppressedBubbleKey != null) {
+ BubbleBarBubble bb = mSuppressedBubbles.remove(update.unsuppressedBubbleKey);
+ if (bb != null) {
+ // Unsuppressing an existing bubble should not cause the bar to expand or animate
+ addBubbleInternally(bb, /* isExpanding= */ false, /* suppressAnimation= */ true);
+ if (mBubbleBarViewController.isHiddenForNoBubbles()) {
+ mBubbleBarViewController.setHiddenForBubbles(false);
+ }
+ }
+ }
+
+ // Update the visibility if this is the initial state, if there are no bubbles, or if the
+ // animation is suppressed.
// If this is the initial bubble, the bubble bar will become visible as part of the
// animation.
- if (update.initialState || mBubbles.isEmpty()) {
+ if (update.initialState || mBubbles.isEmpty() || suppressAnimation) {
mBubbleBarViewController.setHiddenForBubbles(mBubbles.isEmpty());
}
mBubbleStashedHandleViewController.ifPresent(
@@ -439,12 +477,6 @@
mBubbleBarViewController.reorderBubbles(newOrder);
}
}
- if (update.suppressedBubbleKey != null) {
- // TODO: (b/273316505) handle suppression
- }
- if (update.unsuppressedBubbleKey != null) {
- // TODO: (b/273316505) handle suppression
- }
if (update.selectedBubbleKey != null) {
if (mSelectedBubble == null
|| !update.selectedBubbleKey.equals(mSelectedBubble.getKey())) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index dd1b0ca..d00959e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -183,6 +183,11 @@
if (!Flags.enableOptionalBubbleOverflow()) {
showOverflow(true);
}
+ if (!mBubbleStashController.isTransientTaskBar()) {
+ // TODO(b/380274085) for transient taskbar mode, the click is also handled by the input
+ // consumer. This check can be removed once b/380274085 is fixed.
+ mBarView.setOnClickListener(v -> setExpanded(!mBarView.isExpanded()));
+ }
mBarView.addOnLayoutChangeListener(
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
@@ -650,10 +655,12 @@
}
private void updateVisibilityForStateChange() {
- if (!mHiddenForSysui && !mHiddenForNoBubbles && !mHiddenForStashed) {
- mBarView.setVisibility(VISIBLE);
- } else {
+ boolean hiddenForStashedAndNotAnimating =
+ mHiddenForStashed && !mBubbleBarViewAnimator.isAnimating();
+ if (mHiddenForSysui || mHiddenForNoBubbles || hiddenForStashedAndNotAnimating) {
mBarView.setVisibility(INVISIBLE);
+ } else {
+ mBarView.setVisibility(VISIBLE);
}
}
@@ -1215,6 +1222,7 @@
pw.println("Bubble bar view controller state:");
pw.println(" mHiddenForSysui: " + mHiddenForSysui);
pw.println(" mHiddenForNoBubbles: " + mHiddenForNoBubbles);
+ pw.println(" mHiddenForStashed: " + mHiddenForStashed);
pw.println(" mShouldShowEducation: " + mShouldShowEducation);
pw.println(" mBubbleBarTranslationY.value: " + mBubbleBarTranslationY.value);
pw.println(" mBubbleBarSwipeUpTranslationY: " + mBubbleBarSwipeUpTranslationY);
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissViewExt.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissViewExt.kt
index a8002a5..3245fd1e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissViewExt.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissViewExt.kt
@@ -18,6 +18,7 @@
package com.android.launcher3.taskbar.bubbles
import com.android.launcher3.R
+import com.android.wm.shell.shared.R as SharedR
import com.android.wm.shell.shared.bubbles.DismissView
/**
@@ -36,8 +37,8 @@
bottomMarginResId = R.dimen.bubblebar_dismiss_target_bottom_margin,
floatingGradientHeightResId = R.dimen.bubblebar_dismiss_floating_gradient_height,
floatingGradientColorResId = android.R.color.system_neutral1_900,
- backgroundResId = R.drawable.bg_bubble_dismiss_circle,
- iconResId = R.drawable.ic_bubble_dismiss_white
+ backgroundResId = SharedR.drawable.floating_dismiss_background,
+ iconResId = SharedR.drawable.floating_dismiss_ic_close,
)
)
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
index 3bff58b..745c689 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
@@ -531,7 +531,7 @@
bubbleStashController.getStashedHandlePhysicsAnimator().cancelIfRunning()
resetBubbleBarPropertiesOnInterrupt()
bubbleStashController.onNewBubbleAnimationInterrupted(
- /* isStashed= */ bubbleBarView.alpha == 0f,
+ /* isStashed= */ bubbleStashController.isStashed,
bubbleBarView.translationY,
)
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 3fd9970..cecd2a9 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -48,6 +48,7 @@
import static com.android.launcher3.popup.SystemShortcut.BUBBLE_SHORTCUT;
import static com.android.launcher3.popup.SystemShortcut.DONT_SUGGEST_APP;
import static com.android.launcher3.popup.SystemShortcut.INSTALL;
+import static com.android.launcher3.popup.SystemShortcut.PIN_UNPIN_ITEM;
import static com.android.launcher3.popup.SystemShortcut.PRIVATE_PROFILE_INSTALL;
import static com.android.launcher3.popup.SystemShortcut.UNINSTALL_APP;
import static com.android.launcher3.popup.SystemShortcut.WIDGETS;
@@ -457,6 +458,10 @@
// Order matters as it affects order of appearance in popup container
List<SystemShortcut.Factory> shortcuts = new ArrayList(Arrays.asList(
APP_INFO, WellbeingModel.SHORTCUT_FACTORY, mHotseatPredictionController));
+
+ if (Flags.enablePinningAppWithContextMenu()) {
+ shortcuts.add(0, PIN_UNPIN_ITEM);
+ }
shortcuts.addAll(getSplitShortcuts());
shortcuts.add(WIDGETS);
shortcuts.add(INSTALL);
@@ -1020,7 +1025,7 @@
DesktopVisibilityController desktopVisibilityController = getDesktopVisibilityController();
if (!ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
&& desktopVisibilityController != null
- && desktopVisibilityController.areDesktopTasksVisible()
+ && desktopVisibilityController.areDesktopTasksVisibleAndNotInOverview()
&& !desktopVisibilityController.isRecentsGestureInProgress()) {
// Return early to skip setting activity to appear as resumed
// TODO: b/333533253 - Remove after flag rollout
@@ -1349,7 +1354,7 @@
public boolean areDesktopTasksVisible() {
DesktopVisibilityController desktopVisibilityController = getDesktopVisibilityController();
if (desktopVisibilityController != null) {
- return desktopVisibilityController.areDesktopTasksVisible();
+ return desktopVisibilityController.areDesktopTasksVisibleAndNotInOverview();
}
return false;
}
@@ -1429,12 +1434,6 @@
return (mTaskbarUIController != null && mTaskbarUIController.hasBubbles());
}
- @NonNull
- @Override
- public TISBindHelper getTISBindHelper() {
- return mTISBindHelper;
- }
-
@Override
public boolean handleIncorrectSplitTargetSelection() {
if (!enableSplitContextually() || !mSplitSelectStateController.isSplitSelectActive()) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
index d387794..dae63af 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -102,7 +102,7 @@
@Override
public int getTitle() {
- return R.string.all_apps_label;
+ return R.string.all_apps_list_label;
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
index 8ad00bf..1907b4e 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -122,7 +122,7 @@
config.setInterpolator(ANIM_WORKSPACE_FADE, ACCELERATE);
if (DisplayController.getNavigationMode(mContainer).hasGestures
- && overview.getTaskViewCount() > 0) {
+ && overview.hasTaskViews()) {
// Overview is going offscreen, so keep it at its current scale and opacity.
config.setInterpolator(ANIM_OVERVIEW_SCALE, FINAL_FRAME);
config.setInterpolator(ANIM_OVERVIEW_FADE, FINAL_FRAME);
@@ -178,7 +178,7 @@
config.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCELERATE);
// Scrolling in tasks, so show straight away
- if (overview.getTaskViewCount() > 0) {
+ if (overview.hasTaskViews()) {
config.setInterpolator(ANIM_OVERVIEW_FADE, INSTANT);
} else {
config.setInterpolator(ANIM_OVERVIEW_FADE, OVERSHOOT_1_2);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 9dec332..49a5ac5 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -223,7 +223,7 @@
updateNonOverviewAnim(QUICK_SWITCH_FROM_HOME, nonOverviewBuilder);
mNonOverviewAnim.dispatchOnStart();
- if (mRecentsView.getTaskViewCount() == 0) {
+ if (!mRecentsView.hasTaskViews()) {
mRecentsView.setOnEmptyMessageUpdatedListener(isEmpty -> {
if (!isEmpty && mSwipeDetector.isDraggingState()) {
// We have loaded tasks, update the animators to start at the correct scale etc.
@@ -269,7 +269,7 @@
// since we need to take potential taskbar into account.
xAnim.setViewBackgroundColor(mLauncher.getScrimView(),
QUICK_SWITCH_FROM_HOME.getWorkspaceScrimColor(mLauncher), LINEAR);
- if (mRecentsView.getTaskViewCount() == 0) {
+ if (!mRecentsView.hasTaskViews()) {
xAnim.addFloat(mRecentsView, CONTENT_ALPHA, 0f, 1f, LINEAR);
}
mXOverviewAnim = xAnim.createPlaybackController();
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java
index 8c440b1..68940dc 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java
@@ -48,7 +48,7 @@
* @return true if we should intercept the motion event
*/
boolean canInterceptTouch(MotionEvent ev) {
- if (mRecentsView.getTaskViewCount() > 0) {
+ if (mRecentsView.hasTaskViews()) {
// Allow swiping up in the gap between the hotseat and overview.
return ev.getY() >= mRecentsView.getFirstTaskView().getBottom();
} else {
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 3740a68..03394ef 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -131,7 +131,6 @@
import com.android.launcher3.util.WindowBounds;
import com.android.quickstep.GestureState.GestureEndTarget;
import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle;
-import com.android.quickstep.fallback.window.RecentsWindowFactory;
import com.android.quickstep.util.ActiveGestureErrorDetector;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.ActiveGestureProtoLogProxy;
@@ -310,7 +309,6 @@
private static final int LOG_NO_OP_PAGE_INDEX = -1;
protected final TaskAnimationManager mTaskAnimationManager;
- protected final RecentsWindowFactory mRecentsWindowFactory;
// Either RectFSpringAnim (if animating home) or ObjectAnimator (from mCurrentShift) otherwise
private RunningWindowAnim[] mRunningWindowAnim;
// Possible second animation running at the same time as mRunningWindowAnim
@@ -376,7 +374,7 @@
public AbsSwipeUpHandler(Context context, RecentsAnimationDeviceState deviceState,
TaskAnimationManager taskAnimationManager, GestureState gestureState,
long touchTimeMs, boolean continuingLastGesture,
- InputConsumerController inputConsumer, RecentsWindowFactory recentsWindowFactory,
+ InputConsumerController inputConsumer,
MSDLPlayerWrapper msdlPlayerWrapper) {
super(context, deviceState, gestureState);
mContainerInterface = gestureState.getContainerInterface();
@@ -393,7 +391,6 @@
endLauncherTransitionController();
}, new InputProxyHandlerFactory(mContainerInterface, mGestureState));
mTaskAnimationManager = taskAnimationManager;
- mRecentsWindowFactory = recentsWindowFactory;
mTouchTimeMs = touchTimeMs;
mContinuingLastGesture = continuingLastGesture;
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 1e755eb..1437a6e 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -87,7 +87,7 @@
// We were on our way to this state when we got canceled, end there instead.
startState = stateFromGestureEndTarget(endTarget);
DesktopVisibilityController controller = getDesktopVisibilityController();
- if (controller != null && controller.areDesktopTasksVisible()
+ if (controller != null && controller.areDesktopTasksVisibleAndNotInOverview()
&& endTarget == LAST_TASK) {
// When we are cancelling the transition and going back to last task, move to
// rest state instead when desktop tasks are visible.
diff --git a/quickstep/src/com/android/quickstep/BaseContainerInterface.java b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
index 2164bc2..2171c47 100644
--- a/quickstep/src/com/android/quickstep/BaseContainerInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
@@ -242,7 +242,7 @@
// We were on our way to this state when we got canceled, end there instead.
startState = stateFromGestureEndTarget(endTarget);
DesktopVisibilityController controller = getDesktopVisibilityController();
- if (controller != null && controller.areDesktopTasksVisible()
+ if (controller != null && controller.areDesktopTasksVisibleAndNotInOverview()
&& endTarget == LAST_TASK) {
// When we are cancelling the transition and going back to last task, move to
// rest state instead when desktop tasks are visible.
diff --git a/quickstep/src/com/android/quickstep/DisplayModel.kt b/quickstep/src/com/android/quickstep/DisplayModel.kt
new file mode 100644
index 0000000..cbc2f7d
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/DisplayModel.kt
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+package com.android.quickstep
+
+import android.content.Context
+import android.hardware.display.DisplayManager
+import android.util.Log
+import android.util.SparseArray
+import androidx.core.util.valueIterator
+import com.android.quickstep.DisplayModel.DisplayResource
+
+/** data model for managing resources with lifecycles that match that of the connected display */
+abstract class DisplayModel<RESOURCE_TYPE : DisplayResource>(val context: Context) {
+
+ companion object {
+ private const val TAG = "DisplayViewModel"
+ private const val DEBUG = false
+ }
+
+ protected val displayManager =
+ context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
+ protected val displayResourceArray = SparseArray<RESOURCE_TYPE>()
+
+ abstract fun createDisplayResource(displayId: Int)
+
+ protected val displayListener: DisplayManager.DisplayListener =
+ (object : DisplayManager.DisplayListener {
+ override fun onDisplayAdded(displayId: Int) {
+ if (DEBUG) Log.d(TAG, "onDisplayAdded: displayId=$displayId")
+ createDisplayResource(displayId)
+ }
+
+ override fun onDisplayRemoved(displayId: Int) {
+ if (DEBUG) Log.d(TAG, "onDisplayRemoved: displayId=$displayId")
+ deleteDisplayResource(displayId)
+ }
+
+ override fun onDisplayChanged(displayId: Int) {
+ if (DEBUG) Log.d(TAG, "onDisplayChanged: displayId=$displayId")
+ }
+ })
+
+ fun destroy() {
+ displayResourceArray.valueIterator().forEach { displayResource ->
+ displayResource.cleanup()
+ }
+ displayResourceArray.clear()
+ displayManager.unregisterDisplayListener(displayListener)
+ }
+
+ fun getDisplayResource(displayId: Int): RESOURCE_TYPE? {
+ if (DEBUG) Log.d(TAG, "get: displayId=$displayId")
+ return displayResourceArray[displayId]
+ }
+
+ fun deleteDisplayResource(displayId: Int) {
+ if (DEBUG) Log.d(TAG, "delete: displayId=$displayId")
+ getDisplayResource(displayId)?.cleanup()
+ displayResourceArray.remove(displayId)
+ }
+
+ abstract class DisplayResource() {
+ abstract fun cleanup()
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
index b0c69cf..1e857ca 100644
--- a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -106,7 +106,7 @@
boolean continuingLastGesture, InputConsumerController inputConsumer,
MSDLPlayerWrapper msdlPlayerWrapper) {
super(context, deviceState, taskAnimationManager, gestureState, touchTimeMs,
- continuingLastGesture, inputConsumer, null, msdlPlayerWrapper);
+ continuingLastGesture, inputConsumer, msdlPlayerWrapper);
mRunningOverHome = mGestureState.getRunningTask() != null
&& mGestureState.getRunningTask().isHomeTask();
diff --git a/quickstep/src/com/android/quickstep/FallbackWindowInterface.java b/quickstep/src/com/android/quickstep/FallbackWindowInterface.java
index a202ebd..f7836b0 100644
--- a/quickstep/src/com/android/quickstep/FallbackWindowInterface.java
+++ b/quickstep/src/com/android/quickstep/FallbackWindowInterface.java
@@ -41,8 +41,6 @@
import com.android.quickstep.util.ContextInitListener;
import com.android.quickstep.views.RecentsView;
-import java.util.HashMap;
-import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -53,35 +51,13 @@
*/
public final class FallbackWindowInterface extends BaseWindowInterface{
- static Map<Integer, FallbackWindowInterface> sWindowInterfaceMap = new HashMap<>();
-
private final RecentsWindowManager mRecentsWindowManager;
- /**
- * This is only null before init() or after destroy()
- */
- @Nullable
- public static FallbackWindowInterface getInstance(int displayId) {
- return sWindowInterfaceMap.get(displayId);
- }
- /**
- * initializing instance and mapping it to display id
- */
- public static void init(int displayId, RecentsWindowManager recentsWindowManager) {
- if (!sWindowInterfaceMap.containsKey(displayId)) {
- sWindowInterfaceMap.put(displayId, new FallbackWindowInterface(recentsWindowManager));
- }
- }
-
- private FallbackWindowInterface(RecentsWindowManager recentsWindowManager) {
+ public FallbackWindowInterface(RecentsWindowManager recentsWindowManager) {
super(DEFAULT, BACKGROUND_APP);
mRecentsWindowManager = recentsWindowManager;
}
- public void destroy() {
- sWindowInterfaceMap.clear();
- }
-
/** 2 */
@Override
public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect,
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index ef6a09d..d193fee 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -292,8 +292,7 @@
return;
}
LauncherOverlayManager om = launcher.getOverlayManager();
- if (!SystemUiProxy.INSTANCE.get(launcher).getHomeVisibilityState().isHomeVisible()
- || launcher.isForceInvisible()) {
+ if (!SystemUiProxy.INSTANCE.get(launcher).getHomeVisibilityState().isHomeVisible()) {
om.hideOverlay(false /* animate */);
} else {
om.hideOverlay(150);
diff --git a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
index 4bd9ffb..c1e018d 100644
--- a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
+++ b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
@@ -16,6 +16,7 @@
package com.android.quickstep;
+import static android.util.MathUtils.lerp;
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
@@ -51,11 +52,15 @@
import android.window.BackProgressAnimator;
import android.window.IBackAnimationHandoffHandler;
import android.window.IOnBackInvokedCallback;
+
+import com.android.app.animation.Animations;
import com.android.app.animation.Interpolators;
import com.android.internal.policy.SystemBarUtils;
import com.android.internal.view.AppearanceRegion;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.Flags;
+import com.android.launcher3.LauncherState;
import com.android.launcher3.QuickstepTransitionManager;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -65,6 +70,7 @@
import com.android.launcher3.util.NavigationMode;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
import com.android.quickstep.util.BackAnimState;
+import com.android.quickstep.util.ScalingWorkspaceRevealAnim;
import com.android.systemui.shared.system.QuickStepContract;
import java.lang.ref.WeakReference;
@@ -87,9 +93,12 @@
*/
public class LauncherBackAnimationController {
private static final int SCRIM_FADE_DURATION = 233;
- private static final float MIN_WINDOW_SCALE = 0.85f;
+ private static final float MIN_WINDOW_SCALE =
+ Flags.predictiveBackToHomePolish() ? 0.75f : 0.85f;
private static final float MAX_SCRIM_ALPHA_DARK = 0.8f;
private static final float MAX_SCRIM_ALPHA_LIGHT = 0.2f;
+ private static final int MAX_BLUR_RADIUS = 20;
+ private static final int MIN_BLUR_RADIUS_PRE_COMMIT = 10;
private final QuickstepTransitionManager mQuickstepTransitionManager;
private final Matrix mTransformMatrix = new Matrix();
@@ -119,6 +128,7 @@
private ValueAnimator mScrimAlphaAnimator;
private float mScrimAlpha;
private boolean mOverridingStatusBarFlags;
+ private int mLastBlurRadius = 0;
private final ComponentCallbacks mComponentCallbacks = new ComponentCallbacks() {
@Override
@@ -314,6 +324,17 @@
new RemoteAnimationTarget[]{ mBackTarget });
setLauncherTargetViewVisible(false);
mCurrentRect.set(mStartRect);
+ if (Flags.predictiveBackToHomePolish() && !mLauncher.getWorkspace().isOverlayShown()
+ && !mLauncher.isInState(LauncherState.ALL_APPS)) {
+ Animations.cancelOngoingAnimation(mLauncher.getWorkspace());
+ Animations.cancelOngoingAnimation(mLauncher.getHotseat());
+ if (Flags.predictiveBackToHomeBlur()) {
+ mLauncher.getDepthController().pauseBlursOnWindows(true);
+ }
+ mLauncher.getDepthController().stateDepth.setValue(
+ LauncherState.BACKGROUND_APP.getDepth(mLauncher));
+ setLauncherScale(ScalingWorkspaceRevealAnim.MIN_SIZE);
+ }
if (mScrimLayer == null) {
addScrimLayer();
}
@@ -328,6 +349,13 @@
}
}
+ private void setLauncherScale(float scale) {
+ mLauncher.getWorkspace().setScaleX(scale);
+ mLauncher.getWorkspace().setScaleY(scale);
+ mLauncher.getHotseat().setScaleX(scale);
+ mLauncher.getHotseat().setScaleY(scale);
+ }
+
void addScrimLayer() {
SurfaceControl parent = mLauncherTarget != null ? mLauncherTarget.leash : null;
if (parent == null || !parent.isValid()) {
@@ -346,6 +374,7 @@
final float[] colorComponents = new float[] { 0f, 0f, 0f };
mScrimAlpha = (isDarkTheme)
? MAX_SCRIM_ALPHA_DARK : MAX_SCRIM_ALPHA_LIGHT;
+ setBlur(MAX_BLUR_RADIUS);
mTransaction
.setColor(mScrimLayer, colorComponents)
.setAlpha(mScrimLayer, mScrimAlpha)
@@ -372,6 +401,9 @@
if (mScrimLayer == null) {
// Scrim hasn't been attached yet. Let's attach it.
addScrimLayer();
+ } else {
+ mLastBlurRadius = (int) lerp(MAX_BLUR_RADIUS, MIN_BLUR_RADIUS_PRE_COMMIT, progress);
+ setBlur(mLastBlurRadius);
}
float screenWidth = mStartRect.width();
float screenHeight = mStartRect.height();
@@ -403,6 +435,12 @@
customizeStatusBarAppearance(top > mStatusBarHeight / 2);
}
+ private void setBlur(int blurRadius) {
+ if (Flags.predictiveBackToHomeBlur()) {
+ mTransaction.setBackgroundBlurRadius(mScrimLayer, blurRadius);
+ }
+ }
+
/** Transform the target window to match the target rect. */
private void applyTransform(RectF targetRect, float cornerRadius) {
final float scale = targetRect.width() / mStartRect.width();
@@ -500,6 +538,14 @@
if (mScrimLayer != null) {
removeScrimLayer();
}
+ if (Flags.predictiveBackToHomePolish() && !mLauncher.getWorkspace().isOverlayShown()
+ && !mLauncher.isInState(LauncherState.ALL_APPS)) {
+ setLauncherScale(ScalingWorkspaceRevealAnim.MAX_SIZE);
+ if (Flags.predictiveBackToHomeBlur()) {
+ mLauncher.getDepthController().pauseBlursOnWindows(false);
+ }
+ }
+ mLastBlurRadius = 0;
}
private void startTransitionAnimations(BackAnimState backAnim) {
@@ -513,6 +559,7 @@
float value = (Float) animation.getAnimatedValue();
if (mScrimLayer != null && mScrimLayer.isValid()) {
mTransaction.setAlpha(mScrimLayer, value * mScrimAlpha);
+ setBlur((int) lerp(mLastBlurRadius, 0, 1f - value));
applyTransaction();
}
});
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index 0ddd87b..243a577 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -71,7 +71,7 @@
boolean continuingLastGesture, InputConsumerController inputConsumer,
MSDLPlayerWrapper msdlPlayerWrapper) {
super(context, deviceState, taskAnimationManager, gestureState, touchTimeMs,
- continuingLastGesture, inputConsumer, null, msdlPlayerWrapper);
+ continuingLastGesture, inputConsumer, msdlPlayerWrapper);
}
@@ -106,7 +106,8 @@
&& workspaceView.isAttachedToWindow()
&& workspaceView.getHeight() > 0
&& (mContainer.getDesktopVisibilityController() == null
- || !mContainer.getDesktopVisibilityController().areDesktopTasksVisible());
+ || !mContainer.getDesktopVisibilityController()
+ .areDesktopTasksVisibleAndNotInOverview());
mContainer.getRootView().setForceHideBackArrow(true);
@@ -331,7 +332,7 @@
protected void playScalingRevealAnimation() {
if (mContainer != null) {
new ScalingWorkspaceRevealAnim(mContainer, mSiblingAnimation,
- getWindowTargetRect()).start();
+ getWindowTargetRect(), true /* playAlphaReveal */).start();
}
}
@@ -381,7 +382,7 @@
if (mContainer != null) {
new ScalingWorkspaceRevealAnim(
mContainer, null /* siblingAnimation */,
- null /* windowTargetRect */).start();
+ null /* windowTargetRect */, true /* playAlphaReveal */).start();
}
}
}
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
index c09bf3e..c81edcd 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
@@ -233,7 +233,7 @@
// When running task view is null we return last large taskView - typically focusView when
// grid only is not enabled else last desktop task view.
return if (recentsView.runningTaskView == null) {
- recentsView.lastLargeTaskView ?: recentsView.getTaskViewAt(0)
+ recentsView.lastLargeTaskView ?: recentsView.getFirstTaskView()
} else {
if (
enableLargeDesktopWindowingTile() &&
diff --git a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
index bac5e64..1fc0401 100644
--- a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
+++ b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
@@ -42,6 +42,7 @@
import com.android.launcher3.Flags;
import com.android.launcher3.R;
import com.android.launcher3.util.SimpleBroadcastReceiver;
+import com.android.quickstep.fallback.window.RecentsDisplayModel;
import com.android.quickstep.util.ActiveGestureProtoLogProxy;
import com.android.systemui.shared.system.PackageManagerWrapper;
@@ -181,7 +182,8 @@
if (Flags.enableLauncherOverviewInWindow() || Flags.enableFallbackOverviewInWindow()) {
mContainerInterface =
- FallbackWindowInterface.getInstance(mDeviceState.getDisplayId());
+ RecentsDisplayModel.getINSTANCE().get(mContext)
+ .getFallbackWindowInterface(mDeviceState.getDisplayId());
} else {
mContainerInterface = FallbackActivityInterface.INSTANCE;
}
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 61a150b..17c17cc 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -554,12 +554,6 @@
return overviewCommandHelper == null || overviewCommandHelper.canStartHomeSafely();
}
- @NonNull
- @Override
- public TISBindHelper getTISBindHelper() {
- return mTISBindHelper;
- }
-
@Override
public boolean isRecentsViewVisible() {
return getStateManager().getState().isRecentsViewVisible();
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 2fcfa36..e0d4ddd 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -47,7 +47,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.taskbar.TaskbarUIController;
import com.android.launcher3.util.DisplayController;
-import com.android.quickstep.fallback.window.RecentsWindowFactory;
+import com.android.quickstep.fallback.window.RecentsDisplayModel;
import com.android.quickstep.fallback.window.RecentsWindowManager;
import com.android.quickstep.util.ActiveGestureProtoLogProxy;
import com.android.quickstep.util.SystemUiFlagUtils;
@@ -66,7 +66,6 @@
SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false);
private final Context mCtx;
- private RecentsWindowFactory mRecentsWindowFactory;
private RecentsAnimationController mController;
private RecentsAnimationCallbacks mCallbacks;
private RecentsAnimationTargets mTargets;
@@ -103,11 +102,9 @@
}
};
- TaskAnimationManager(Context ctx, RecentsWindowFactory recentsWindowFactory,
- RecentsAnimationDeviceState deviceState) {
+ TaskAnimationManager(Context ctx, RecentsAnimationDeviceState deviceState) {
mCtx = ctx;
mDeviceState = deviceState;
- mRecentsWindowFactory = recentsWindowFactory;
}
SystemUiProxy getSystemUiProxy() {
return SystemUiProxy.INSTANCE.get(mCtx);
@@ -303,7 +300,8 @@
|| Flags.enableLauncherOverviewInWindow())) {
mRecentsAnimationStartPending = getSystemUiProxy().startRecentsActivity(intent, options,
mCallbacks, gestureState.useSyntheticRecentsTransition());
- mRecentsWindowFactory.create(mDeviceState.getDisplayId())
+ RecentsDisplayModel.getINSTANCE().get(mCtx)
+ .getRecentsWindowManager(mDeviceState.getDisplayId())
.startRecentsWindow(mCallbacks);
} else {
options.setPendingIntentBackgroundActivityStartMode(
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 4ddbcdb..b4a5df7 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -90,7 +90,6 @@
import com.android.launcher3.util.ScreenOnTracker;
import com.android.launcher3.util.TraceHelper;
import com.android.quickstep.OverviewCommandHelper.CommandType;
-import com.android.quickstep.fallback.window.RecentsWindowFactory;
import com.android.quickstep.fallback.window.RecentsWindowSwipeHandler;
import com.android.quickstep.inputconsumers.BubbleBarInputConsumer;
import com.android.quickstep.inputconsumers.OneHandedModeInputConsumer;
@@ -309,10 +308,10 @@
@BinderThread
@Override
public void updateWallpaperVisibility(int displayId, boolean visible) {
- MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis ->
- executeForTaskbarManager(
- taskbarManager -> taskbarManager.setWallpaperVisible(visible))
- ));
+ MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(
+ tis -> executeForTaskbarManager(
+ taskbarManager -> taskbarManager.setWallpaperVisible(displayId,
+ visible))));
}
@BinderThread
@@ -613,6 +612,11 @@
public void onToggleOverview() {
mOverviewCommandHelper.addCommand(CommandType.TOGGLE);
}
+
+ @Override
+ public void onHideOverview() {
+ mOverviewCommandHelper.addCommand(CommandType.HIDE);
+ }
};
private ActivityManagerWrapper mAM;
@@ -632,7 +636,6 @@
private InputEventReceiver mInputEventReceiver;
private TaskbarManager mTaskbarManager;
- private RecentsWindowFactory mRecentsWindowFactory;
private Function<GestureState, AnimatedFloat> mSwipeUpProxyProvider = i -> null;
private AllAppsActionManager mAllAppsActionManager;
private InputManager mInputManager;
@@ -669,9 +672,6 @@
mDesktopAppLaunchTransitionManager =
new DesktopAppLaunchTransitionManager(this, SystemUiProxy.INSTANCE.get(this));
mDesktopAppLaunchTransitionManager.registerTransitions();
- if (Flags.enableLauncherOverviewInWindow() || Flags.enableFallbackOverviewInWindow()) {
- mRecentsWindowFactory = new RecentsWindowFactory(this);
- }
mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
// Call runOnUserUnlocked() before any other callbacks to ensure everything is initialized.
@@ -723,7 +723,7 @@
public void onUserUnlocked() {
Log.d(TAG, "onUserUnlocked: userId=" + getUserId()
+ " instance=" + System.identityHashCode(this));
- mTaskAnimationManager = new TaskAnimationManager(this, mRecentsWindowFactory, mDeviceState);
+ mTaskAnimationManager = new TaskAnimationManager(this, mDeviceState);
mOverviewComponentObserver = new OverviewComponentObserver(this, mDeviceState);
mOverviewCommandHelper = new OverviewCommandHelper(this,
mOverviewComponentObserver, mTaskAnimationManager);
@@ -830,10 +830,6 @@
mTrackpadsConnected.clear();
mTaskbarManager.destroy();
-
- if (mRecentsWindowFactory != null) {
- mRecentsWindowFactory.destroy();
- }
if (mDesktopAppLaunchTransitionManager != null) {
mDesktopAppLaunchTransitionManager.unregisterTransitions();
}
@@ -1289,6 +1285,6 @@
GestureState gestureState, long touchTimeMs) {
return new RecentsWindowSwipeHandler(this, mDeviceState, mTaskAnimationManager,
gestureState, touchTimeMs, mTaskAnimationManager.isRecentsAnimationRunning(),
- mInputConsumer, mRecentsWindowFactory, MSDLPlayerWrapper.INSTANCE.get(this));
+ mInputConsumer, MSDLPlayerWrapper.INSTANCE.get(this));
}
}
diff --git a/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java b/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java
index 9f6360b..a6feff0 100644
--- a/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java
+++ b/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java
@@ -20,7 +20,9 @@
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapperImpl;
import com.android.launcher3.util.ApiWrapper;
import com.android.launcher3.util.PluginManagerWrapper;
+import com.android.launcher3.util.window.WindowManagerProxy;
import com.android.quickstep.contextualeducation.SystemContextualEduStatsManager;
+import com.android.quickstep.util.SystemWindowManagerProxy;
import dagger.Binds;
import dagger.Module;
@@ -32,4 +34,5 @@
@Binds abstract ApiWrapper bindApiWrapper(SystemApiWrapper systemApiWrapper);
@Binds abstract ContextualEduStatsManager bindContextualEduStatsManager(
SystemContextualEduStatsManager manager);
+ @Binds abstract WindowManagerProxy bindWindowManagerProxy(SystemWindowManagerProxy proxy);
}
diff --git a/quickstep/src/com/android/quickstep/dagger/QuickstepBaseAppComponent.java b/quickstep/src/com/android/quickstep/dagger/QuickstepBaseAppComponent.java
index b2670e8..4255372 100644
--- a/quickstep/src/com/android/quickstep/dagger/QuickstepBaseAppComponent.java
+++ b/quickstep/src/com/android/quickstep/dagger/QuickstepBaseAppComponent.java
@@ -20,6 +20,7 @@
import com.android.launcher3.dagger.LauncherBaseAppComponent;
import com.android.launcher3.model.WellbeingModel;
import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.fallback.window.RecentsDisplayModel;
import com.android.quickstep.util.AsyncClockEventDelegate;
/**
@@ -37,4 +38,6 @@
AsyncClockEventDelegate getAsyncClockEventDelegate();
SystemUiProxy getSystemUiProxy();
+
+ RecentsDisplayModel getRecentsDisplayModel();
}
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 28d95e2..9625d29 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -43,9 +43,9 @@
import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource;
import com.android.quickstep.BaseContainerInterface;
import com.android.quickstep.FallbackActivityInterface;
-import com.android.quickstep.FallbackWindowInterface;
import com.android.quickstep.GestureState;
import com.android.quickstep.RotationTouchHelper;
+import com.android.quickstep.fallback.window.RecentsDisplayModel;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.SplitSelectStateController;
import com.android.quickstep.util.TaskViewSimulator;
@@ -80,8 +80,8 @@
@Override
public BaseContainerInterface<RecentsState, ?> getContainerInterface(int displayId) {
return (Flags.enableFallbackOverviewInWindow() || Flags.enableLauncherOverviewInWindow())
- ? FallbackWindowInterface.getInstance(displayId)
- : FallbackActivityInterface.INSTANCE;
+ ? RecentsDisplayModel.getINSTANCE().get(mContext)
+ .getFallbackWindowInterface(displayId) : FallbackActivityInterface.INSTANCE;
}
@Override
@@ -181,7 +181,7 @@
Task runningTask = runningTasks[0];
if (mHomeTask != null && runningTask != null
&& mHomeTask.key.id == runningTask.key.id
- && getTaskViewCount() == 0 && mLoadPlanEverApplied) {
+ && !hasTaskViews() && mLoadPlanEverApplied) {
// Do not add a stub task if we are running over home with empty recents, so that we
// show the empty recents message instead of showing a stub task and later removing it.
// Ignore empty task signal if applyLoadPlan has never run.
@@ -264,13 +264,13 @@
}
setFreezeViewVisibility(true);
- if (mContainer.getDesktopVisibilityController() != null) {
- mContainer.getDesktopVisibilityController().onLauncherStateChanged(toState);
- }
}
@Override
public void onStateTransitionComplete(RecentsState finalState) {
+ if (mContainer.getDesktopVisibilityController() != null) {
+ mContainer.getDesktopVisibilityController().onLauncherStateChanged(finalState);
+ }
if (!finalState.isRecentsViewVisible()) {
// Clean-up logic that occurs when recents is no longer in use/visible.
reset();
diff --git a/quickstep/src/com/android/quickstep/fallback/window/RecentsDisplayModel.kt b/quickstep/src/com/android/quickstep/fallback/window/RecentsDisplayModel.kt
new file mode 100644
index 0000000..a9259d9
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/fallback/window/RecentsDisplayModel.kt
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+package com.android.quickstep.fallback.window
+
+import android.content.Context
+import android.os.Handler
+import android.util.Log
+import android.view.Display
+import com.android.launcher3.Flags
+import com.android.launcher3.dagger.ApplicationContext
+import com.android.launcher3.dagger.LauncherAppSingleton
+import com.android.launcher3.util.DaggerSingletonObject
+import com.android.quickstep.DisplayModel
+import com.android.quickstep.FallbackWindowInterface
+import com.android.quickstep.dagger.QuickstepBaseAppComponent
+import com.android.quickstep.fallback.window.RecentsDisplayModel.RecentsDisplayResource
+import javax.inject.Inject
+
+@LauncherAppSingleton
+class RecentsDisplayModel @Inject constructor(@ApplicationContext context: Context) :
+ DisplayModel<RecentsDisplayResource>(context) {
+
+ companion object {
+ private const val TAG = "RecentsDisplayModel"
+ private const val DEBUG = false
+
+ @JvmStatic
+ val INSTANCE: DaggerSingletonObject<RecentsDisplayModel> =
+ DaggerSingletonObject<RecentsDisplayModel>(
+ QuickstepBaseAppComponent::getRecentsDisplayModel
+ )
+ }
+
+ init {
+ if (Flags.enableFallbackOverviewInWindow() || Flags.enableLauncherOverviewInWindow()) {
+ displayManager.registerDisplayListener(displayListener, Handler.getMain())
+ createDisplayResource(Display.DEFAULT_DISPLAY)
+ }
+ }
+
+ override fun createDisplayResource(displayId: Int) {
+ if (DEBUG) Log.d(TAG, "create: displayId=$displayId")
+ getDisplayResource(displayId)?.let {
+ return
+ }
+ val display = displayManager.getDisplay(displayId)
+ displayResourceArray[displayId] =
+ RecentsDisplayResource(displayId, context.createDisplayContext(display))
+ }
+
+ fun getRecentsWindowManager(displayId: Int): RecentsWindowManager? {
+ return getDisplayResource(displayId)?.recentsWindowManager
+ }
+
+ fun getFallbackWindowInterface(displayId: Int): FallbackWindowInterface? {
+ return getDisplayResource(displayId)?.fallbackWindowInterface
+ }
+
+ data class RecentsDisplayResource(var displayId: Int, var displayContext: Context) :
+ DisplayResource() {
+ val recentsWindowManager = RecentsWindowManager(displayContext)
+ val fallbackWindowInterface: FallbackWindowInterface =
+ FallbackWindowInterface(recentsWindowManager)
+
+ override fun cleanup() {
+ recentsWindowManager.destroy()
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowFactory.kt b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowFactory.kt
deleted file mode 100644
index ac0593e..0000000
--- a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowFactory.kt
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.quickstep.fallback.window
-
-import android.content.Context
-import android.hardware.display.DisplayManager
-import android.os.Handler
-import android.util.Log
-import android.util.SparseArray
-import android.view.Display
-import androidx.core.util.valueIterator
-
-
-/**
- * Factory for creating [RecentsWindowManager] instances based on context per display.
- */
-class RecentsWindowFactory(private val context: Context) {
-
- companion object {
- private const val TAG = "RecentsWindowFactory"
- private const val DEBUG = false
- }
-
- private val displayManager = context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
- private val managerArray = SparseArray<RecentsWindowManager>()
-
- private val displayListener: DisplayManager.DisplayListener =
- (object : DisplayManager.DisplayListener {
- override fun onDisplayAdded(displayId: Int) {
- if (DEBUG) Log.d(TAG, "onDisplayAdded: displayId=$displayId")
- create(displayId)
- }
-
- override fun onDisplayRemoved(displayId: Int) {
- if (DEBUG) Log.d(TAG, "onDisplayRemoved: displayId=$displayId")
- delete(displayId)
- }
-
- override fun onDisplayChanged(displayId: Int) {
- if (DEBUG) Log.d(TAG, "onDisplayChanged: displayId=$displayId")
- }
- })
-
- init {
- create(Display.DEFAULT_DISPLAY) // create manager for first display early.
- displayManager.registerDisplayListener(displayListener, Handler.getMain())
- }
-
- fun destroy() {
- managerArray.valueIterator().forEach { manager ->
- manager.destroy()
- }
- managerArray.clear()
- displayManager.unregisterDisplayListener(displayListener)
- }
-
- fun get(displayId: Int): RecentsWindowManager? {
- if (DEBUG) Log.d(TAG, "get: displayId=$displayId")
- return managerArray[displayId]
- }
-
- fun delete(displayId: Int) {
- if (DEBUG) Log.d(TAG, "delete: displayId=$displayId")
- get(displayId)?.destroy()
- managerArray.remove(displayId)
- }
-
- fun create(displayId: Int): RecentsWindowManager {
- if (DEBUG) Log.d(TAG, "create: displayId=$displayId")
- get(displayId)?.let {
- return it
- }
- val display = displayManager.getDisplay(displayId)
- val displayContext = context.createDisplayContext(display)
- val recentsWindowManager = RecentsWindowManager(displayId, displayContext)
- managerArray[displayId] = recentsWindowManager
- return recentsWindowManager
- }
-}
diff --git a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowManager.kt b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowManager.kt
index b3cc3e9..9bd7a19 100644
--- a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowManager.kt
+++ b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowManager.kt
@@ -50,7 +50,6 @@
import com.android.launcher3.util.SystemUiController
import com.android.launcher3.views.BaseDragLayer
import com.android.launcher3.views.ScrimView
-import com.android.quickstep.FallbackWindowInterface
import com.android.quickstep.OverviewComponentObserver
import com.android.quickstep.RecentsAnimationCallbacks
import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener
@@ -89,7 +88,7 @@
* To add new protologs, see [RecentsWindowProtoLogProxy]. To enable logging to logcat, see
* [QuickstepProtoLogGroup.Constants.DEBUG_RECENTS_WINDOW]
*/
-class RecentsWindowManager(private val displayId: Int, context: Context) :
+class RecentsWindowManager(context: Context) :
RecentsWindowContext(context), RecentsViewContainer, StatefulContainer<RecentsState> {
companion object {
@@ -98,6 +97,9 @@
class RecentsWindowTracker : ContextTracker<RecentsWindowManager?>() {
override fun isHomeStarted(context: RecentsWindowManager?): Boolean {
+ // if we need to change this block to use context in some way, we will need to
+ // refactor RecentsWindowTracker to be an instance (instead of a singleton) managed
+ // by RecentsDisplayModel. Otherwise bad things will occur.
return true
}
}
@@ -152,14 +154,12 @@
}
init {
- FallbackWindowInterface.init(displayId, this)
TaskStackChangeListeners.getInstance().registerTaskStackListener(taskStackChangeListener)
}
override fun destroy() {
super.destroy()
cleanupRecentsWindow()
- FallbackWindowInterface.getInstance(displayId)?.destroy()
TaskStackChangeListeners.getInstance().unregisterTaskStackListener(taskStackChangeListener)
callbacks?.removeListener(recentsAnimationListener)
recentsWindowTracker.onContextDestroyed(this)
@@ -322,10 +322,6 @@
return taskbarUIController
}
- override fun getTISBindHelper(): TISBindHelper {
- return tisBindHelper
- }
-
fun registerInitListener(onInitListener: Predicate<Boolean>) {
this.onInitListener = onInitListener
}
diff --git a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java
index 4a08d12..afc8879 100644
--- a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java
@@ -101,6 +101,8 @@
private static StaticMessageReceiver sMessageReceiver = null;
private FallbackHomeAnimationFactory mActiveAnimationFactory;
+ private final RecentsDisplayModel mRecentsDisplayModel;
+
private final boolean mRunningOverHome;
private final Matrix mTmpMatrix = new Matrix();
@@ -111,10 +113,11 @@
public RecentsWindowSwipeHandler(Context context, RecentsAnimationDeviceState deviceState,
TaskAnimationManager taskAnimationManager, GestureState gestureState, long touchTimeMs,
boolean continuingLastGesture, InputConsumerController inputConsumer,
- RecentsWindowFactory recentsWindowFactory, MSDLPlayerWrapper msdlPlayerWrapper) {
+ MSDLPlayerWrapper msdlPlayerWrapper) {
super(context, deviceState, taskAnimationManager, gestureState, touchTimeMs,
- continuingLastGesture, inputConsumer, recentsWindowFactory, msdlPlayerWrapper);
+ continuingLastGesture, inputConsumer, msdlPlayerWrapper);
+ mRecentsDisplayModel = RecentsDisplayModel.getINSTANCE().get(context);
mRunningOverHome = mGestureState.getRunningTask() != null
&& mGestureState.getRunningTask().isHomeTask();
@@ -160,7 +163,8 @@
boolean fromHomeToHome = mRunningOverHome
&& endTarget == GestureState.GestureEndTarget.HOME;
if (fromHomeToHome) {
- RecentsWindowManager manager = mRecentsWindowFactory.get(mDeviceState.getDisplayId());
+ RecentsWindowManager manager =
+ mRecentsDisplayModel.getRecentsWindowManager(mDeviceState.getDisplayId());
if (manager != null) {
manager.startHome(/* finishRecentsAnimation= */ false);
}
@@ -225,7 +229,7 @@
recentsCallback = () -> {
callback.run();
RecentsWindowManager manager =
- mRecentsWindowFactory.get(mDeviceState.getDisplayId());
+ mRecentsDisplayModel.getRecentsWindowManager(mDeviceState.getDisplayId());
if (manager != null) {
manager.startHome();
}
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
index be7f8e5..7fe4278 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
@@ -65,11 +65,6 @@
}
@Override
- public int getSpokenIntroductionSubtitle() {
- return R.string.back_gesture_spoken_intro_subtitle;
- }
-
- @Override
public int getSuccessFeedbackTitle() {
return R.string.gesture_tutorial_nice;
}
diff --git a/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java b/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java
index 700fbf8..72bff7f 100644
--- a/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java
+++ b/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java
@@ -29,9 +29,9 @@
import androidx.annotation.Nullable;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
import com.android.launcher3.testing.shared.ResourceUtils;
-import com.android.launcher3.util.DisplayController;
/**
* Utility class to handle edge swipes for back gestures.
@@ -45,6 +45,7 @@
"gestures.back_timeout", 250);
private final Context mContext;
+ private final DeviceProfile mDeviceProfile;
private final Point mDisplaySize = new Point();
@@ -89,9 +90,10 @@
}
};
- EdgeBackGestureHandler(Context context) {
+ EdgeBackGestureHandler(Context context, DeviceProfile deviceProfile) {
final Resources res = context.getResources();
mContext = context;
+ mDeviceProfile = deviceProfile;
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mLongPressTimeout = Math.min(MAX_LONG_PRESS_TIMEOUT,
@@ -116,8 +118,7 @@
// Add a nav bar panel window.
mEdgeBackPanel = new EdgeBackGesturePanel(mContext, parent, createLayoutParams());
mEdgeBackPanel.setBackCallback(mBackCallback);
- Point currentSize = DisplayController.INSTANCE.get(mContext).getInfo().currentSize;
- mDisplaySize.set(currentSize.x, currentSize.y);
+ mDisplaySize.set(mDeviceProfile.widthPx, mDeviceProfile.heightPx);
mEdgeBackPanel.setDisplaySize(mDisplaySize);
}
}
diff --git a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
index bc5cc15..0365f89 100644
--- a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
@@ -115,22 +115,13 @@
private void initWindowInsets() {
View root = findViewById(android.R.id.content);
- root.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom,
- int oldLeft, int oldTop, int oldRight, int oldBottom) {
- updateExclusionRects(root);
- }
- });
+ root.addOnLayoutChangeListener(
+ (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
+ updateExclusionRects(root));
// Return CONSUMED if you don't want want the window insets to keep being
// passed down to descendant views.
- root.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
- @Override
- public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
- return WindowInsets.CONSUMED;
- }
- });
+ root.setOnApplyWindowInsetsListener((v, insets) -> WindowInsets.CONSUMED);
}
private void updateExclusionRects(View rootView) {
diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
index bf4eaf2..b059695 100644
--- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
@@ -58,11 +58,6 @@
}
@Override
- public int getSpokenIntroductionSubtitle() {
- return R.string.home_gesture_spoken_intro_subtitle;
- }
-
- @Override
public int getSuccessFeedbackTitle() {
return R.string.home_gesture_tutorial_success;
}
diff --git a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
index c00f508..fdbd509 100644
--- a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
+++ b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
@@ -33,6 +33,7 @@
import androidx.annotation.Nullable;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.testing.shared.ResourceUtils;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.NavigationMode;
@@ -57,15 +58,16 @@
@Nullable
private NavBarGestureAttemptCallback mGestureCallback;
- NavBarGestureHandler(Context context) {
+ NavBarGestureHandler(Context context, DeviceProfile deviceProfile) {
mContext = context;
- DisplayController.Info displayInfo = DisplayController.INSTANCE.get(mContext).getInfo();
- Point currentSize = displayInfo.currentSize;
- mDisplaySize.set(currentSize.x, currentSize.y);
- mSwipeUpTouchTracker =
- new TriggerSwipeUpTouchTracker(context, true /*disableHorizontalSwipe*/,
- new NavBarPosition(NavigationMode.NO_BUTTON, displayInfo),
- this);
+ mDisplaySize.set(deviceProfile.widthPx, deviceProfile.heightPx);
+ mSwipeUpTouchTracker = new TriggerSwipeUpTouchTracker(
+ context,
+ /* disableHorizontalSwipe= */ true,
+ new NavBarPosition(
+ NavigationMode.NO_BUTTON,
+ DisplayController.INSTANCE.get(mContext).getInfo()),
+ /* onSwipeUp= */ this);
mMotionPauseDetector = new MotionPauseDetector(context);
final Resources resources = context.getResources();
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
index e45f8d8..ff0d6d1 100644
--- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
@@ -73,11 +73,6 @@
}
@Override
- public int getSpokenIntroductionSubtitle() {
- return R.string.overview_gesture_spoken_intro_subtitle;
- }
-
- @Override
public int getSuccessFeedbackTitle() {
return R.string.overview_gesture_tutorial_success;
}
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index 9510a05..7d14a3e 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -318,11 +318,6 @@
}
@StringRes
- public int getSpokenIntroductionSubtitle() {
- return NO_ID;
- }
-
- @StringRes
public int getSuccessFeedbackSubtitle() {
return NO_ID;
}
@@ -401,17 +396,13 @@
isGestureSuccessful
? getSuccessFeedbackTitle() : R.string.gesture_tutorial_try_again,
subtitleResId,
- NO_ID,
- isGestureSuccessful,
- false);
+ isGestureSuccessful);
}
void showFeedback(
int titleResId,
int subtitleResId,
- int spokenSubtitleResId,
- boolean isGestureSuccessful,
- boolean useGestureAnimationDelay) {
+ boolean isGestureSuccessful) {
mFeedbackTitleView.removeCallbacks(mTitleViewCallback);
if (mFeedbackViewCallback != null) {
mFeedbackView.removeCallbacks(mFeedbackViewCallback);
@@ -512,7 +503,6 @@
if (mTutorialType == TutorialType.BACK_NAVIGATION) {
resetViewsForBackGesture();
}
-
}
mGestureCompleted = false;
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
index 2ff2c83..8174e13 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
@@ -48,6 +48,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.logging.StatsLogManager;
import com.android.quickstep.interaction.TutorialController.TutorialType;
@@ -175,8 +176,10 @@
Bundle args = savedInstanceState != null ? savedInstanceState : getArguments();
mTutorialType = (TutorialType) args.getSerializable(KEY_TUTORIAL_TYPE);
mGestureComplete = args.getBoolean(KEY_GESTURE_COMPLETE, false);
- mEdgeBackGestureHandler = new EdgeBackGestureHandler(getContext());
- mNavBarGestureHandler = new NavBarGestureHandler(getContext());
+ DeviceProfile deviceProfile = LauncherAppState.getInstance(getContext())
+ .getInvariantDeviceProfile().getDeviceProfile(getContext());
+ mEdgeBackGestureHandler = new EdgeBackGestureHandler(getContext(), deviceProfile);
+ mNavBarGestureHandler = new NavBarGestureHandler(getContext(), deviceProfile);
mDeviceProfile = InvariantDeviceProfile.INSTANCE.get(getContext())
.getDeviceProfile(getContext());
@@ -212,7 +215,6 @@
public View onCreateView(
@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
-
mRootView = (RootSandboxLayout) inflater.inflate(
R.layout.redesigned_gesture_tutorial_fragment,
container,
@@ -268,9 +270,7 @@
mTutorialController.showFeedback(
introTitleResId,
introSubtitleResId,
- mTutorialController.getSpokenIntroductionSubtitle(),
- false,
- true);
+ /* isGestureSuccessful= */ false);
mIntroductionShown = true;
}
}
diff --git a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
index 3aae760..8c26d8f 100644
--- a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
@@ -96,7 +96,7 @@
taskRequests[taskId] =
Pair(
task.key,
- recentsCoroutineScope.launch {
+ recentsCoroutineScope.launch(dispatcherProvider.main) {
Log.i(TAG, "requestTaskData: $taskId")
fetchIcon(task)
fetchThumbnail(task)
@@ -134,7 +134,7 @@
task.key,
object : TaskIconChangedCallback {
override fun onTaskIconChanged() {
- recentsCoroutineScope.launch {
+ recentsCoroutineScope.launch(dispatcherProvider.main) {
updateIcon(task.key.id, getIconFromDataSource(task))
}
}
@@ -152,7 +152,7 @@
}
override fun onHighResLoadingStateChanged() {
- recentsCoroutineScope.launch {
+ recentsCoroutineScope.launch(dispatcherProvider.main) {
updateThumbnail(task.key.id, getThumbnailFromDataSource(task))
}
}
diff --git a/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt b/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
index b78e214..9d8fc4f 100644
--- a/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
+++ b/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
@@ -39,7 +39,6 @@
import com.android.systemui.shared.recents.model.Task
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
internal typealias RecentsScopeId = String
@@ -58,10 +57,13 @@
private fun startDefaultScope(appContext: Context) {
createScope(DEFAULT_SCOPE_ID).apply {
set(RecentsViewData::class.java.simpleName, RecentsViewData())
+ val dispatcherProvider: DispatcherProvider = ProductionDispatchers
val recentsCoroutineScope =
- CoroutineScope(SupervisorJob() + Dispatchers.Main + CoroutineName("RecentsView"))
+ CoroutineScope(
+ SupervisorJob() + dispatcherProvider.unconfined + CoroutineName("RecentsView")
+ )
set(CoroutineScope::class.java.simpleName, recentsCoroutineScope)
- set(DispatcherProvider::class.java.simpleName, ProductionDispatchers)
+ set(DispatcherProvider::class.java.simpleName, dispatcherProvider)
val recentsModel = RecentsModel.INSTANCE.get(appContext)
val taskVisualsChangedDelegate =
TaskVisualsChangedDelegateImpl(
@@ -170,18 +172,6 @@
log("linked scopes: ${getScope(scopeId).scopeIdsLinked}")
val instance: Any =
when (modelClass) {
- RecentTasksRepository::class.java -> {
- with(RecentsModel.INSTANCE.get(appContext)) {
- TasksRepository(
- this,
- thumbnailCache,
- iconCache,
- get(),
- get(),
- ProductionDispatchers,
- )
- }
- }
RecentsViewData::class.java -> RecentsViewData()
TaskContainerData::class.java -> TaskContainerData()
TaskThumbnailViewData::class.java -> TaskThumbnailViewData()
@@ -253,13 +243,17 @@
private const val DEFAULT_SCOPE_ID = "RecentsDependencies::GlobalScope"
private const val TAG = "RecentsDependencies"
private const val DEBUG = false
+ private var activeRecentsCount = 0
@Volatile private lateinit var instance: RecentsDependencies
fun initialize(view: View): RecentsDependencies = initialize(view.context)
fun initialize(context: Context): RecentsDependencies {
- synchronized(this) { instance = RecentsDependencies(context.applicationContext) }
+ synchronized(this) {
+ activeRecentsCount++
+ instance = RecentsDependencies(context.applicationContext)
+ }
return instance
}
@@ -273,9 +267,29 @@
return instance
}
+ @JvmStatic
fun destroy() {
- instance.scopes.clear()
- instance.startDefaultScope(instance.appContext)
+ // When Launcher Activity restarts, the old view's RecentsView.onDetachedFromWindow
+ // happens after the new view's creation. This means that destroy can be called after a
+ // new initialisation. This check prevents a newly initialised tree from being
+ // destroyed. Ideally we would have 1 instance of the dependency tree for each
+ // RecentsView.
+ //
+ // This check is sufficient to avoid a leak of the dependency tree after the Activity is
+ // destroyed while also allowing Launcher auto-restarts (production behaviour) to easily
+ // reinitialise the dependency tree.
+ //
+ // TODO(b/353917593): Better lifecycle decisions will be implemented in this bug or when
+ // replacing with Dagger (b/371370483).
+ activeRecentsCount--
+ if (activeRecentsCount == 0) {
+ instance.scopes.clear()
+ } else {
+ instance.log(
+ "RecentsDependencies was not destroyed. " +
+ "There is still an active RecentsView instance."
+ )
+ }
}
}
}
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
index ea4602d..e334695 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
@@ -29,6 +29,7 @@
import androidx.core.view.isInvisible
import com.android.launcher3.R
import com.android.launcher3.util.ViewPool
+import com.android.launcher3.util.coroutines.DispatcherProvider
import com.android.quickstep.recents.di.RecentsDependencies
import com.android.quickstep.recents.di.get
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.BackgroundOnly
@@ -45,8 +46,12 @@
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
class TaskThumbnailView : FrameLayout, ViewPool.Reusable {
+ private val recentsCoroutineScope: CoroutineScope = RecentsDependencies.get()
+ private val dispatcherProvider: DispatcherProvider = RecentsDependencies.get()
+
private lateinit var viewData: TaskThumbnailViewData
private lateinit var viewModel: TaskThumbnailViewModel
@@ -119,7 +124,9 @@
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
- viewAttachedScope.cancel("TaskThumbnailView detaching from window")
+ recentsCoroutineScope.launch(dispatcherProvider.background) {
+ viewAttachedScope.cancel("TaskThumbnailView detaching from window")
+ }
}
override fun onRecycle() {
diff --git a/quickstep/src/com/android/quickstep/task/util/TaskOverlayHelper.kt b/quickstep/src/com/android/quickstep/task/util/TaskOverlayHelper.kt
index 203177a..e6c8d27 100644
--- a/quickstep/src/com/android/quickstep/task/util/TaskOverlayHelper.kt
+++ b/quickstep/src/com/android/quickstep/task/util/TaskOverlayHelper.kt
@@ -18,6 +18,7 @@
import android.util.Log
import android.view.View.OnLayoutChangeListener
+import com.android.launcher3.util.coroutines.DispatcherProvider
import com.android.quickstep.TaskOverlayFactory
import com.android.quickstep.recents.di.RecentsDependencies
import com.android.quickstep.recents.di.get
@@ -33,12 +34,15 @@
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
/**
* Helper for [TaskOverlayFactory.TaskOverlay] to interact with [TaskOverlayViewModel], this helper
* should merge with [TaskOverlayFactory.TaskOverlay] when it's migrated to MVVM.
*/
class TaskOverlayHelper(val task: Task, val overlay: TaskOverlayFactory.TaskOverlay<*>) {
+ private val recentsCoroutineScope: CoroutineScope = RecentsDependencies.get()
+ private val dispatcherProvider: DispatcherProvider = RecentsDependencies.get()
private lateinit var overlayInitializedScope: CoroutineScope
private var uiState: TaskOverlayUiState = Disabled
@@ -101,7 +105,9 @@
}
fun destroy() {
- overlayInitializedScope.cancel()
+ recentsCoroutineScope.launch(dispatcherProvider.background) {
+ overlayInitializedScope.cancel("TaskOverlay being destroyed")
+ }
uiState = Disabled
overlay.snapshotView.removeOnLayoutChangeListener(snapshotLayoutChangeListener)
reset()
diff --git a/quickstep/src/com/android/quickstep/util/AppPairsController.java b/quickstep/src/com/android/quickstep/util/AppPairsController.java
index 3a0324c..8399792 100644
--- a/quickstep/src/com/android/quickstep/util/AppPairsController.java
+++ b/quickstep/src/com/android/quickstep/util/AppPairsController.java
@@ -215,7 +215,7 @@
newAppPair.getAppContents().forEach(member -> {
member.title = "";
member.bitmap = iconCache.getDefaultIcon(newAppPair.user);
- iconCache.getTitleAndIcon(member, member.usingLowResIcon());
+ iconCache.getTitleAndIcon(member, member.getMatchingLookupFlag());
});
MAIN_EXECUTOR.execute(() -> {
LauncherAccessibilityDelegate delegate =
diff --git a/quickstep/src/com/android/quickstep/util/BackAnimState.kt b/quickstep/src/com/android/quickstep/util/BackAnimState.kt
index 9009eaa..4c1e1ff 100644
--- a/quickstep/src/com/android/quickstep/util/BackAnimState.kt
+++ b/quickstep/src/com/android/quickstep/util/BackAnimState.kt
@@ -18,6 +18,7 @@
import android.animation.AnimatorSet
import android.content.Context
+import com.android.launcher3.Flags
import com.android.launcher3.LauncherAnimationRunner.AnimationResult
import com.android.launcher3.anim.AnimatorListeners.forEndCallback
import com.android.launcher3.util.RunnableList
@@ -36,14 +37,20 @@
BackAnimState {
override fun addOnAnimCompleteCallback(r: Runnable) {
- val springAnimWait = RunnableList()
- springAnim?.addAnimatorListener(forEndCallback(springAnimWait::executeAllAndDestroy))
- ?: springAnimWait.executeAllAndDestroy()
-
val animWait = RunnableList()
- anim?.addListener(
- forEndCallback(Runnable { springAnimWait.add(animWait::executeAllAndDestroy) })
- ) ?: springAnimWait.add(animWait::executeAllAndDestroy)
+ if (Flags.predictiveBackToHomePolish()) {
+ springAnim?.addAnimatorListener(forEndCallback(animWait::executeAllAndDestroy))
+ ?: anim?.addListener(forEndCallback(animWait::executeAllAndDestroy))
+ ?: animWait.executeAllAndDestroy()
+ } else {
+ val springAnimWait = RunnableList()
+ springAnim?.addAnimatorListener(forEndCallback(springAnimWait::executeAllAndDestroy))
+ ?: springAnimWait.executeAllAndDestroy()
+
+ anim?.addListener(
+ forEndCallback(Runnable { springAnimWait.add(animWait::executeAllAndDestroy) })
+ ) ?: springAnimWait.add(animWait::executeAllAndDestroy)
+ }
animWait.add(r)
}
diff --git a/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt b/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt
deleted file mode 100644
index 7393de4..0000000
--- a/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.quickstep.util
-
-import com.android.launcher3.Flags.enableLargeDesktopWindowingTile
-import com.android.quickstep.RecentsAnimationController
-import com.android.quickstep.views.DesktopTaskView
-import com.android.quickstep.views.TaskView
-import com.android.quickstep.views.TaskViewType
-import com.android.systemui.shared.recents.model.ThumbnailData
-
-/**
- * Helper class for [com.android.quickstep.views.RecentsView]. This util class contains refactored
- * and extracted functions from RecentsView to facilitate the implementation of unit tests.
- */
-class RecentsViewUtils {
- /** Takes a screenshot of all [taskView] and return map of taskId to the screenshot */
- fun screenshotTasks(
- taskView: TaskView,
- recentsAnimationController: RecentsAnimationController,
- ): Map<Int, ThumbnailData> =
- taskView.taskContainers.associate {
- it.task.key.id to recentsAnimationController.screenshotTask(it.task.key.id)
- }
-
- /**
- * Sorts task groups to move desktop tasks to the end of the list.
- *
- * @param tasks List of group tasks to be sorted.
- * @return Sorted list of GroupTasks to be used in the RecentsView.
- */
- fun sortDesktopTasksToFront(tasks: List<GroupTask>): List<GroupTask> {
- val (desktopTasks, otherTasks) = tasks.partition { it.taskViewType == TaskViewType.DESKTOP }
- return otherTasks + desktopTasks
- }
-
- /** Counts [TaskView]s that are [DesktopTaskView] instances. */
- fun getDesktopTaskViewCount(taskViews: Iterable<TaskView>): Int =
- taskViews.count { it is DesktopTaskView }
-
- /** Returns a list of all large TaskView Ids from [TaskView]s */
- fun getLargeTaskViewIds(taskViews: Iterable<TaskView>): List<Int> =
- taskViews.filter { it.isLargeTile }.map { it.taskViewId }
-
- /** Counts [TaskView]s that are large tiles. */
- fun getLargeTileCount(taskViews: Iterable<TaskView>): Int = taskViews.count { it.isLargeTile }
-
- /**
- * Returns the first TaskView that should be displayed as a large tile.
- *
- * @param taskViews List of [TaskView]s
- * @param splitSelectActive current split state
- */
- fun getFirstLargeTaskView(
- taskViews: MutableIterable<TaskView>,
- splitSelectActive: Boolean,
- ): TaskView? =
- taskViews.firstOrNull { it.isLargeTile && !(splitSelectActive && it is DesktopTaskView) }
-
- /** Returns the expected focus task. */
- fun getExpectedFocusedTask(taskViews: Iterable<TaskView>): TaskView? =
- if (enableLargeDesktopWindowingTile()) taskViews.firstOrNull { it !is DesktopTaskView }
- else taskViews.firstOrNull()
-
- /**
- * Returns the [TaskView] that should be the current page during task binding, in the following
- * priorities:
- * 1. Running task
- * 2. Focused task
- * 3. First non-desktop task
- * 4. Last desktop task
- * 5. null otherwise
- */
- fun getExpectedCurrentTask(
- runningTaskView: TaskView?,
- focusedTaskView: TaskView?,
- taskViews: Iterable<TaskView>,
- ): TaskView? =
- runningTaskView
- ?: focusedTaskView
- ?: taskViews.firstOrNull { it !is DesktopTaskView }
- ?: taskViews.lastOrNull()
-
- /** Returns the first TaskView if it exists, or null otherwise. */
- fun getFirstTaskView(taskViews: Iterable<TaskView>): TaskView? = taskViews.firstOrNull()
-
- /**
- * Returns the first TaskView that is not large
- *
- * @param taskViews List of [TaskView]s
- */
- fun getFirstSmallTaskView(taskViews: MutableIterable<TaskView>): TaskView? =
- taskViews.firstOrNull { !it.isLargeTile }
-
- /** Returns the last TaskView that should be displayed as a large tile. */
- fun getLastLargeTaskView(taskViews: Iterable<TaskView>): TaskView? =
- taskViews.lastOrNull { it.isLargeTile }
-
- /** Returns the first [TaskView], with some tasks possibly hidden in the carousel. */
- fun getFirstTaskViewInCarousel(
- nonRunningTaskCarouselHidden: Boolean,
- taskViews: Iterable<TaskView>,
- runningTaskView: TaskView?,
- ): TaskView? =
- taskViews.firstOrNull {
- it.isVisibleInCarousel(runningTaskView, nonRunningTaskCarouselHidden)
- }
-
- /** Returns the last [TaskView], with some tasks possibly hidden in the carousel. */
- fun getLastTaskViewInCarousel(
- nonRunningTaskCarouselHidden: Boolean,
- taskViews: Iterable<TaskView>,
- runningTaskView: TaskView?,
- ): TaskView? =
- taskViews.lastOrNull {
- it.isVisibleInCarousel(runningTaskView, nonRunningTaskCarouselHidden)
- }
-
- /** Returns if any small tasks are fully visible */
- fun isAnySmallTaskFullyVisible(
- taskViews: Iterable<TaskView>,
- isTaskViewFullyVisible: (TaskView) -> Boolean,
- ): Boolean = taskViews.any { !it.isLargeTile && isTaskViewFullyVisible(it) }
-
- /** Returns the current list of [TaskView] children. */
- fun getTaskViews(taskViewCount: Int, requireTaskViewAt: (Int) -> TaskView): Iterable<TaskView> =
- (0 until taskViewCount).map(requireTaskViewAt)
-
- /** Apply attachAlpha to all [TaskView] accordingly to different conditions. */
- fun applyAttachAlpha(
- taskViews: Iterable<TaskView>,
- runningTaskView: TaskView?,
- runningTaskAttachAlpha: Float,
- nonRunningTaskCarouselHidden: Boolean,
- ) {
- taskViews.forEach { taskView ->
- taskView.attachAlpha =
- if (taskView == runningTaskView) {
- runningTaskAttachAlpha
- } else {
- if (taskView.isVisibleInCarousel(runningTaskView, nonRunningTaskCarouselHidden))
- 1f
- else 0f
- }
- }
- }
-
- fun TaskView.isVisibleInCarousel(
- runningTaskView: TaskView?,
- nonRunningTaskCarouselHidden: Boolean,
- ): Boolean =
- if (!nonRunningTaskCarouselHidden) true
- else getCarouselType() == runningTaskView.getCarouselType()
-
- /** Returns the carousel type of the TaskView, and default to fullscreen if it's null. */
- private fun TaskView?.getCarouselType(): TaskViewCarousel =
- if (this is DesktopTaskView) TaskViewCarousel.DESKTOP else TaskViewCarousel.FULL_SCREEN
-
- private enum class TaskViewCarousel {
- FULL_SCREEN,
- DESKTOP,
- }
-}
diff --git a/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt b/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
index f719bed..63eae92 100644
--- a/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
+++ b/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
@@ -54,14 +54,15 @@
private val launcher: QuickstepLauncher,
siblingAnimation: RectFSpringAnim?,
windowTargetRect: RectF?,
+ playAlphaReveal: Boolean = true,
) {
companion object {
private const val FADE_DURATION_MS = 200L
private const val SCALE_DURATION_MS = 1000L
private const val MAX_ALPHA = 1f
private const val MIN_ALPHA = 0f
- private const val MAX_SIZE = 1f
- private const val MIN_SIZE = 0.85f
+ internal const val MAX_SIZE = 1f
+ internal const val MIN_SIZE = 0.85f
/**
* Custom interpolator for both the home and wallpaper scaling. Necessary because EMPHASIZED
@@ -132,21 +133,23 @@
SCALE_INTERPOLATOR,
)
- // Fade in quickly at the beginning of the animation, so the content doesn't look like it's
- // popping into existence out of nowhere.
- val fadeClamp = FADE_DURATION_MS.toFloat() / SCALE_DURATION_MS
- workspace.alpha = MIN_ALPHA
- animation.setViewAlpha(
- workspace,
- MAX_ALPHA,
- Interpolators.clampToProgress(LINEAR, 0f, fadeClamp),
- )
- hotseat.alpha = MIN_ALPHA
- animation.setViewAlpha(
- hotseat,
- MAX_ALPHA,
- Interpolators.clampToProgress(LINEAR, 0f, fadeClamp),
- )
+ if (playAlphaReveal) {
+ // Fade in quickly at the beginning of the animation, so the content doesn't look like
+ // it's popping into existence out of nowhere.
+ val fadeClamp = FADE_DURATION_MS.toFloat() / SCALE_DURATION_MS
+ workspace.alpha = MIN_ALPHA
+ animation.setViewAlpha(
+ workspace,
+ MAX_ALPHA,
+ Interpolators.clampToProgress(LINEAR, 0f, fadeClamp),
+ )
+ hotseat.alpha = MIN_ALPHA
+ animation.setViewAlpha(
+ hotseat,
+ MAX_ALPHA,
+ Interpolators.clampToProgress(LINEAR, 0f, fadeClamp),
+ )
+ }
val transitionConfig = StateAnimationConfig()
diff --git a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
index bdfaa48..86090d5 100644
--- a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
@@ -16,6 +16,7 @@
package com.android.quickstep.util;
+import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import android.animation.Animator;
@@ -89,7 +90,7 @@
MODEL_EXECUTOR.execute(() -> {
PackageItemInfo infoInOut = new PackageItemInfo(pendingIntent.getCreatorPackage(),
pendingIntent.getCreatorUserHandle());
- mIconCache.getTitleAndIconForApp(infoInOut, false);
+ mIconCache.getTitleAndIconForApp(infoInOut, DEFAULT_LOOKUP_FLAG);
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
view.post(() -> {
diff --git a/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
index f3b984b8..7fadc7d 100644
--- a/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
+++ b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
@@ -27,7 +27,10 @@
import android.view.WindowMetrics;
import com.android.internal.policy.SystemBarUtils;
+import com.android.launcher3.dagger.ApplicationContext;
+import com.android.launcher3.dagger.LauncherAppSingleton;
import com.android.launcher3.statehandlers.DesktopVisibilityController;
+import com.android.launcher3.util.DaggerSingletonTracker;
import com.android.launcher3.util.WindowBounds;
import com.android.launcher3.util.window.CachedDisplayInfo;
import com.android.launcher3.util.window.WindowManagerProxy;
@@ -37,22 +40,22 @@
import java.util.List;
import java.util.Set;
+import javax.inject.Inject;
+
/**
* Extension of {@link WindowManagerProxy} with some assumption for the default system Launcher
*/
+@LauncherAppSingleton
public class SystemWindowManagerProxy extends WindowManagerProxy {
private final TISBindHelper mTISBindHelper;
- public SystemWindowManagerProxy(Context context) {
+ @Inject
+ public SystemWindowManagerProxy(@ApplicationContext Context context,
+ DaggerSingletonTracker lifecycleTracker) {
super(true);
mTISBindHelper = new TISBindHelper(context, binder -> {});
- }
-
- @Override
- public void close() {
- super.close();
- mTISBindHelper.onDestroy();
+ lifecycleTracker.addCloseable(mTISBindHelper::onDestroy);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/util/TISBindHelper.java b/quickstep/src/com/android/quickstep/util/TISBindHelper.java
index b573604..b238dec 100644
--- a/quickstep/src/com/android/quickstep/util/TISBindHelper.java
+++ b/quickstep/src/com/android/quickstep/util/TISBindHelper.java
@@ -21,6 +21,7 @@
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
import android.util.Log;
import androidx.annotation.Nullable;
@@ -46,7 +47,7 @@
// Max backoff caps at 5 mins
private static final long MAX_BACKOFF_MILLIS = 10 * 60 * 1000;
- private final Handler mHandler = new Handler();
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
private final Runnable mConnectionRunnable = this::internalBindToTIS;
private final Context mContext;
private final Consumer<TISBinder> mConnectionCallback;
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
index 2e94534..3f0b520 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
@@ -38,6 +38,7 @@
import com.android.quickstep.util.SplitSelectStateController
import com.android.systemui.shared.recents.model.Task
import com.android.systemui.shared.system.InteractionJankMonitorWrapper
+import com.android.wm.shell.Flags.enableFlexibleTwoAppSplit
import com.android.wm.shell.shared.split.SplitScreenConstants.PersistentSnapPosition
/**
@@ -52,6 +53,9 @@
*/
class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
TaskView(context, attrs, type = TaskViewType.GROUPED) {
+
+ private val MINIMUM_RATIO_TO_SHOW_ICON = 0.2f
+
// TODO(b/336612373): Support new TTV for GroupedTaskView
var splitBoundsConfig: SplitConfigurationOptions.SplitBounds? = null
private set
@@ -176,14 +180,32 @@
private fun updateIconPlacement() {
val splitBoundsConfig = splitBoundsConfig ?: return
- val taskIconHeight = container.deviceProfile.overviewTaskIconSizePx
+ val deviceProfile = container.deviceProfile
+ val taskIconHeight = deviceProfile.overviewTaskIconSizePx
val isRtl = layoutDirection == LAYOUT_DIRECTION_RTL
val inSplitSelection = getThisTaskCurrentlyInSplitSelection() != INVALID_TASK_ID
+ if (enableFlexibleTwoAppSplit()) {
+ val topLeftTaskPercent =
+ if (deviceProfile.isLeftRightSplit) splitBoundsConfig.leftTaskPercent
+ else splitBoundsConfig.topTaskPercent
+ val bottomRightTaskPercent = 1 - topLeftTaskPercent
+ taskContainers[0]
+ .iconView
+ .setFlexSplitAlpha(
+ if (topLeftTaskPercent < MINIMUM_RATIO_TO_SHOW_ICON) 0f else 1f
+ )
+ taskContainers[1]
+ .iconView
+ .setFlexSplitAlpha(
+ if (bottomRightTaskPercent < MINIMUM_RATIO_TO_SHOW_ICON) 0f else 1f
+ )
+ }
+
if (enableOverviewIconMenu()) {
val groupedTaskViewSizes =
pagedOrientationHandler.getGroupedTaskViewSizes(
- container.deviceProfile,
+ deviceProfile,
splitBoundsConfig,
layoutParams.width,
layoutParams.height,
@@ -197,7 +219,7 @@
layoutParams.height,
layoutParams.width,
isRtl,
- container.deviceProfile,
+ deviceProfile,
splitBoundsConfig,
inSplitSelection,
)
@@ -211,7 +233,7 @@
measuredHeight,
measuredWidth,
isRtl,
- container.deviceProfile,
+ deviceProfile,
splitBoundsConfig,
inSplitSelection,
)
diff --git a/quickstep/src/com/android/quickstep/views/IconAppChipView.java b/quickstep/src/com/android/quickstep/views/IconAppChipView.java
index ba42594..5270477 100644
--- a/quickstep/src/com/android/quickstep/views/IconAppChipView.java
+++ b/quickstep/src/com/android/quickstep/views/IconAppChipView.java
@@ -56,10 +56,12 @@
private static final int MENU_BACKGROUND_REVEAL_DURATION = 417;
private static final int MENU_BACKGROUND_HIDE_DURATION = 333;
- private static final int NUM_ALPHA_CHANNELS = 3;
+ private static final int NUM_ALPHA_CHANNELS = 4;
private static final int INDEX_CONTENT_ALPHA = 0;
private static final int INDEX_COLOR_FILTER_ALPHA = 1;
private static final int INDEX_MODAL_ALPHA = 2;
+ /** Used to hide the app chip for 90:10 flex split. */
+ private static final int INDEX_MINIMUM_RATIO_ALPHA = 3;
private final MultiValueAlpha mMultiValueAlpha;
@@ -349,6 +351,11 @@
}
@Override
+ public void setFlexSplitAlpha(float alpha) {
+ mMultiValueAlpha.get(INDEX_MINIMUM_RATIO_ALPHA).setValue(alpha);
+ }
+
+ @Override
public int getDrawableWidth() {
return mIconView == null ? 0 : mIconView.getDrawableWidth();
}
diff --git a/quickstep/src/com/android/quickstep/views/IconView.kt b/quickstep/src/com/android/quickstep/views/IconView.kt
index 3ee12ab..2e6c4bf 100644
--- a/quickstep/src/com/android/quickstep/views/IconView.kt
+++ b/quickstep/src/com/android/quickstep/views/IconView.kt
@@ -133,6 +133,10 @@
multiValueAlpha[INDEX_MODAL_ALPHA].setValue(alpha)
}
+ override fun setFlexSplitAlpha(alpha: Float) {
+ multiValueAlpha[INDEX_FLEX_SPLIT_ALPHA].setValue(alpha)
+ }
+
/**
* Set the tint color of the icon, useful for scrimming or dimming.
*
@@ -178,8 +182,9 @@
}
companion object {
- private const val NUM_ALPHA_CHANNELS = 2
+ private const val NUM_ALPHA_CHANNELS = 3
private const val INDEX_CONTENT_ALPHA = 0
private const val INDEX_MODAL_ALPHA = 1
+ private const val INDEX_FLEX_SPLIT_ALPHA = 2
}
}
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 4f823e6..b9f44fe 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -164,13 +164,14 @@
}
setFreezeViewVisibility(true);
- if (mContainer.getDesktopVisibilityController() != null) {
- mContainer.getDesktopVisibilityController().onLauncherStateChanged(toState);
- }
}
@Override
public void onStateTransitionComplete(LauncherState finalState) {
+ if (mContainer.getDesktopVisibilityController() != null) {
+ mContainer.getDesktopVisibilityController().onLauncherStateChanged(finalState);
+ }
+
if (!finalState.isRecentsViewVisible) {
// Clean-up logic that occurs when recents is no longer in use/visible.
reset();
@@ -287,7 +288,7 @@
desktopVisibilityController = mContainer.getDesktopVisibilityController();
endTarget = mCurrentGestureEndTarget;
if (endTarget == GestureState.GestureEndTarget.LAST_TASK
- && desktopVisibilityController.areDesktopTasksVisible()) {
+ && desktopVisibilityController.areDesktopTasksVisibleAndNotInOverview()) {
// Recents gesture was cancelled and we are returning to the previous task.
// After super class has handled clean up, show desktop apps on top again
showDesktopApps = true;
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index c2eae66..a43c686 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -25,11 +25,11 @@
import static com.android.app.animation.Interpolators.ACCELERATE_0_75;
import static com.android.app.animation.Interpolators.ACCELERATE_DECELERATE;
import static com.android.app.animation.Interpolators.DECELERATE_2;
+import static com.android.app.animation.Interpolators.EMPHASIZED;
import static com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE;
import static com.android.app.animation.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.app.animation.Interpolators.FINAL_FRAME;
import static com.android.app.animation.Interpolators.LINEAR;
-import static com.android.app.animation.Interpolators.EMPHASIZED;
import static com.android.app.animation.Interpolators.clampToProgress;
import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
import static com.android.launcher3.AbstractFloatingView.TYPE_TASK_MENU;
@@ -179,6 +179,7 @@
import com.android.launcher3.util.TranslateEdgeEffect;
import com.android.launcher3.util.VibratorWrapper;
import com.android.launcher3.util.ViewPool;
+import com.android.launcher3.util.coroutines.DispatcherProvider;
import com.android.quickstep.BaseContainerInterface;
import com.android.quickstep.GestureState;
import com.android.quickstep.OverviewCommandHelper;
@@ -213,7 +214,6 @@
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.RecentsAtomicAnimationFactory;
import com.android.quickstep.util.RecentsOrientedState;
-import com.android.quickstep.util.RecentsViewUtils;
import com.android.quickstep.util.SplitAnimationController.Companion.SplitAnimInitProps;
import com.android.quickstep.util.SplitAnimationTimings;
import com.android.quickstep.util.SplitSelectStateController;
@@ -237,17 +237,22 @@
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource;
import kotlin.Unit;
+import kotlin.collections.CollectionsKt;
+
+import kotlinx.coroutines.CoroutineScope;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
+import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@@ -607,7 +612,8 @@
private int mKeyboardTaskFocusSnapAnimationDuration;
private int mKeyboardTaskFocusIndex = INVALID_PAGE;
- private int[] mDismissPrimaryTranslations;
+ private Map<TaskView, Integer> mTaskViewsDismissPrimaryTranslations =
+ new HashMap<TaskView, Integer>();
/**
* TODO: Call reloadIdNeeded in onTaskStackChanged.
@@ -842,15 +848,81 @@
private final RecentsViewModel mRecentsViewModel;
private final RecentsViewModelHelper mHelper;
- private final RecentsViewUtils mUtils = new RecentsViewUtils();
+ private final RecentsViewUtils mUtils = new RecentsViewUtils(this);
private final Matrix mTmpMatrix = new Matrix();
private int mTaskViewCount = 0;
+ private final TaskViewsIterable mTaskViewsIterable = new TaskViewsIterable();
+
+ public class TaskViewsIterable implements Iterable<TaskView> {
+
+ /**
+ * Iterates TaskViews when its index inside the RecentsView is needed.
+ */
+ public void forEachWithIndexInParent(BiConsumer<TaskView, Integer> consumer) {
+ int childCount = getChildCount();
+ for (int index = 0; index < childCount; index++) {
+ if (getChildAt(index) instanceof TaskView taskView) {
+ consumer.accept(taskView, index);
+ }
+ }
+ }
+
+ @Override
+ public TaskViewsIterator iterator() {
+ return new TaskViewsIterator();
+ }
+ }
+
+ // An Iterator to iterate all the current TaskViews inside the RecentsView.
+ public class TaskViewsIterator implements Iterator<TaskView> {
+ // Refers to the index of the `TaskView` that will be returned when `next()` is called.
+ private int mNextIndex = 0;
+
+ // The "limit" of this iterator. This is the number of children of the RecentsView when
+ // the iterator was created. Adding & removing elements will invalidate the iteration
+ // anyway (and cause next() to throw) so saving this value will guarantee that the
+ // value of hasNext() remains stable and won't flap between true and false when elements
+ // are added and removed from the RecentsView.
+ private final int mLimit = getChildCount();
+
+ TaskViewsIterator() {
+ advanceIfNeeded();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return mNextIndex < mLimit && mNextIndex < getChildCount();
+ }
+
+ @Override
+ public TaskView next() {
+ if (!hasNext()) {
+ throw new IndexOutOfBoundsException(
+ String.format("mNextIndex: %d, child count: %d", mNextIndex,
+ getChildCount()));
+ }
+ TaskView taskView = requireTaskViewAt(mNextIndex);
+ mNextIndex++;
+ advanceIfNeeded();
+ return taskView;
+ }
+
+ // Advances `mNextIndex` until it either points to a `TaskView` or to the end of the
+ // Iterator.
+ private void advanceIfNeeded() {
+ while (mNextIndex < mLimit && mNextIndex < getChildCount() && !(getChildAt(
+ mNextIndex) instanceof TaskView)) {
+ mNextIndex++;
+ }
+ }
+ }
+
@Nullable
public TaskView getFirstTaskView() {
- return mUtils.getFirstTaskView(getTaskViews());
+ return mUtils.getFirstTaskView();
}
public RecentsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
@@ -873,7 +945,11 @@
recentsDependencies.inject(RecentTasksRepository.class),
recentsDependencies.inject(RecentsViewData.class)
);
- mHelper = new RecentsViewModelHelper(mRecentsViewModel);
+ mHelper = new RecentsViewModelHelper(
+ mRecentsViewModel,
+ recentsDependencies.inject(CoroutineScope.class),
+ recentsDependencies.inject(DispatcherProvider.class)
+ );
recentsDependencies.provide(RecentsRotationStateRepository.class,
() -> new RecentsRotationStateRepositoryImpl(mOrientationState));
@@ -1167,7 +1243,7 @@
public void init(OverviewActionsView actionsView, SplitSelectStateController splitController,
@Nullable DesktopRecentsTransitionController desktopRecentsTransitionController) {
mActionsView = actionsView;
- mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, getTaskViewCount() == 0);
+ mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, !hasTaskViews());
// Update flags for 1p/3p launchers
mActionsView.updateFor3pLauncher(!supportsAppPairs());
mSplitSelectStateController = splitController;
@@ -1210,9 +1286,6 @@
if (FeatureFlags.enableSplitContextually()) {
mSplitSelectStateController.registerSplitListener(mSplitSelectionListener);
}
- if (enableRefactorTaskThumbnail()) {
- mHelper.onAttachedToWindow();
- }
}
@Override
@@ -1238,6 +1311,7 @@
reset();
if (enableRefactorTaskThumbnail()) {
mHelper.onDetachedFromWindow();
+ RecentsDependencies.destroy();
}
}
@@ -1263,7 +1337,7 @@
} else {
mTaskViewPool.recycle(taskView);
}
- mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, getTaskViewCount() == 0);
+ mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, !hasTaskViews());
}
}
}
@@ -1471,6 +1545,19 @@
return clearAllScroll + (mIsRtl ? distance : -distance);
}
+ /**
+ * Launch running task view if it is instance of DesktopTaskView.
+ * @return provides runnable list to attach runnable at end of Desktop Mode launch
+ */
+ @Nullable
+ public RunnableList launchRunningDesktopTaskView() {
+ TaskView taskView = getRunningTaskView();
+ if (taskView instanceof DesktopTaskView) {
+ return taskView.launchWithAnimation();
+ }
+ return null;
+ }
+
/*
* Returns if TaskView is within screen bounds defined in [screenStart, screenEnd].
*
@@ -1518,19 +1605,6 @@
}
/**
- * Launch DesktopTaskView if found.
- * @return provides runnable list to attach runnable at end of Desktop Mode launch
- */
- public RunnableList launchDesktopTaskView() {
- for (TaskView taskView : getTaskViews()) {
- if (taskView instanceof DesktopTaskView) {
- return taskView.launchWithAnimation();
- }
- }
- return null;
- }
-
- /**
* Returns a {@link TaskView} that has taskId matching {@code taskId} or null if no match.
*/
@Nullable
@@ -1742,8 +1816,7 @@
}
TaskView taskView = getTaskViewAt(mNextPage);
boolean shouldSnapToLargeTask = taskView != null && taskView.isLargeTile()
- && !mUtils.isAnySmallTaskFullyVisible(getTaskViews(),
- this::isTaskViewFullyVisible);
+ && !mUtils.isAnySmallTaskFullyVisible();
boolean shouldSnapToClearAll = mNextPage == indexOfChild(mClearAllButton);
// Snap to large tile when grid tasks aren't fully visible or the clear all button.
if (!shouldSnapToLargeTask && !shouldSnapToClearAll) {
@@ -1987,7 +2060,7 @@
}
// If the list changed, maybe the focused task doesn't exist anymore.
if (newFocusedTaskView == null) {
- newFocusedTaskView = mUtils.getExpectedFocusedTask(getTaskViews());
+ newFocusedTaskView = mUtils.getExpectedFocusedTask();
}
}
setFocusedTaskViewId(
@@ -2031,8 +2104,7 @@
targetPage = previousFocusedPage;
} else {
targetPage = indexOfChild(
- mUtils.getExpectedCurrentTask(newRunningTaskView, newFocusedTaskView,
- getTaskViews()));
+ mUtils.getExpectedCurrentTask(newRunningTaskView, newFocusedTaskView));
}
if (targetPage != -1 && mCurrentPage != targetPage) {
int finalTargetPage = targetPage;
@@ -2074,19 +2146,21 @@
}
private void removeTasksViewsAndClearAllButton() {
- for (TaskView taskView : getTaskViews()) {
- if (isGestureActive() && taskView.isRunningTask()) {
- // This handles an edge case where applyLoadPlan happens during a gesture when the
- // only Task is one with excludeFromRecents, in which case we should not remove it.
- continue;
- }
- removeView(taskView);
- }
- if (getTaskViewCount() == 0 && indexOfChild(mClearAllButton) != -1) {
+ // This handles an edge case where applyLoadPlan happens during a gesture when the only
+ // Task is one with excludeFromRecents, in which case we should not remove it.
+ CollectionsKt
+ .filter(getTaskViews(), taskView -> !isGestureActive() || !taskView.isRunningTask())
+ .forEach(this::removeView);
+ if (!hasTaskViews() && indexOfChild(mClearAllButton) != -1) {
removeView(mClearAllButton);
}
}
+ /** Returns true if there are at least one TaskView has been added to the RecentsView. */
+ public boolean hasTaskViews() {
+ return CollectionsKt.any(getTaskViews());
+ }
+
public int getTaskViewCount() {
return mTaskViewCount;
}
@@ -2097,7 +2171,7 @@
* @return Number of children that are instances of DesktopTaskView
*/
private int getDesktopTaskViewCount() {
- return mUtils.getDesktopTaskViewCount(getTaskViews());
+ return mUtils.getDesktopTaskViewCount();
}
/**
@@ -2294,7 +2368,7 @@
* Updates TaskView scaling and translation required to support variable width.
*/
private void updateTaskSize() {
- if (getTaskViewCount() == 0) {
+ if (!hasTaskViews()) {
return;
}
@@ -2473,41 +2547,39 @@
return;
}
- int lower = 0;
- int upper = 0;
- int visibleStart = 0;
- int visibleEnd = 0;
+ int lowerIndex, upperIndex, visibleStart, visibleEnd;
if (showAsGrid()) {
int screenStart = getPagedOrientationHandler().getPrimaryScroll(this);
int pageOrientedSize = getPagedOrientationHandler().getMeasuredSize(this);
// For GRID_ONLY_OVERVIEW, use +/- 1 task column as visible area for preloading
// adjacent thumbnails, otherwise use +/-50% screen width
- int extraWidth = enableGridOnlyOverview() ? getLastComputedTaskSize().width()
- + getPageSpacing() : pageOrientedSize / 2;
+ int extraWidth =
+ enableGridOnlyOverview() ? getLastComputedTaskSize().width() + getPageSpacing()
+ : pageOrientedSize / 2;
+ lowerIndex = upperIndex = 0;
visibleStart = screenStart - extraWidth;
visibleEnd = screenStart + pageOrientedSize + extraWidth;
} else {
int centerPageIndex = getPageNearestToCenterOfScreen();
int numChildren = getChildCount();
- lower = Math.max(0, centerPageIndex - 2);
- upper = Math.min(centerPageIndex + 2, numChildren - 1);
+ lowerIndex = Math.max(0, centerPageIndex - 2);
+ upperIndex = Math.min(centerPageIndex + 2, numChildren - 1);
+ visibleStart = visibleEnd = 0;
}
List<Integer> visibleTaskIds = new ArrayList<>();
-
// Update the task data for the in/visible children
- for (int i = 0; i < getTaskViewCount(); i++) {
- TaskView taskView = requireTaskViewAt(i);
+ getTaskViews().forEachWithIndexInParent((taskView, index) -> {
List<TaskContainer> containers = taskView.getTaskContainers();
if (containers.isEmpty()) {
- continue;
+ return;
}
boolean visible;
if (showAsGrid()) {
visible = isTaskViewWithinBounds(taskView, visibleStart, visibleEnd,
- mDismissPrimaryTranslations != null ? mDismissPrimaryTranslations[i] : 0);
+ mTaskViewsDismissPrimaryTranslations.getOrDefault(taskView, 0));
} else {
- visible = lower <= i && i <= upper;
+ visible = index >= lowerIndex && index <= upperIndex;
}
if (visible) {
// Default update all non-null tasks, then remove running ones
@@ -2519,7 +2591,7 @@
tasksToUpdate.stream().map((task) -> task.key.id).toList());
}
if (tasksToUpdate.isEmpty()) {
- continue;
+ return;
}
int visibilityChanges = 0;
for (Task task : tasksToUpdate) {
@@ -2553,7 +2625,7 @@
taskView.onTaskListVisibilityChanged(false /* visible */, visibilityChanges);
}
}
- }
+ });
if (enableRefactorTaskThumbnail()) {
mRecentsViewModel.updateVisibleTasks(visibleTaskIds);
}
@@ -3110,7 +3182,7 @@
private void applyAttachAlpha() {
// Only hide non running task carousel when it's fully off screen, otherwise it needs to
// be visible to move to on screen.
- mUtils.applyAttachAlpha(getTaskViews(), getRunningTaskView(), mRunningTaskAttachAlpha,
+ mUtils.applyAttachAlpha(
/*nonRunningTaskCarouselHidden=*/mDesktopCarouselDetachProgress == 1f);
}
@@ -3179,8 +3251,7 @@
* to skip rebalance
*/
private void updateGridProperties(int startRebalanceAfter) {
- int taskCount = getTaskViewCount();
- if (taskCount == 0) {
+ if (!hasTaskViews()) {
return;
}
@@ -3197,10 +3268,11 @@
IntSet topSet = new IntSet();
IntSet bottomSet = new IntSet();
+ final int taskCount = getTaskViewCount();
// Horizontal grid translation for each task
float[] gridTranslations = new float[taskCount];
- TaskView lastLargeTaskView = mUtils.getLastLargeTaskView(getTaskViews());
+ TaskView lastLargeTaskView = mUtils.getLastLargeTaskView();
int lastLargeTaskIndex =
(lastLargeTaskView == null) ? Integer.MAX_VALUE : indexOfChild(lastLargeTaskView);
Set<Integer> largeTasksIndices = new HashSet<>();
@@ -3738,7 +3810,7 @@
boolean currentPageSnapsToEndOfGrid = currentPageScroll == lastGridTaskScroll;
int topGridRowSize = mTopRowIdSet.size();
- int numLargeTiles = mUtils.getLargeTileCount(getTaskViews());
+ int numLargeTiles = mUtils.getLargeTileCount();
int bottomGridRowSize = taskCount - mTopRowIdSet.size() - numLargeTiles;
boolean topRowLonger = topGridRowSize > bottomGridRowSize;
boolean bottomRowLonger = bottomGridRowSize > topGridRowSize;
@@ -3869,14 +3941,15 @@
int slidingTranslation = 0;
if (isSlidingTasks) {
int nextSnappedPage = isStagingFocusedTask
- ? indexOfChild(mUtils.getFirstSmallTaskView(getTaskViews()))
- : mUtils.getDesktopTaskViewCount(getTaskViews());
+ ? indexOfChild(mUtils.getFirstSmallTaskView())
+ : mUtils.getDesktopTaskViewCount();
slidingTranslation = getPagedOrientationHandler().getPrimaryScroll(this)
- getScrollForPage(nextSnappedPage);
slidingTranslation += mIsRtl ? newClearAllShortTotalWidthTranslation
: -newClearAllShortTotalWidthTranslation;
}
- mDismissPrimaryTranslations = new int[taskCount];
+ mTaskViewsDismissPrimaryTranslations.clear();
+ int lastTaskViewIndex = indexOfChild(mUtils.getLastTaskView());
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (child == dismissedTaskView) {
@@ -3886,7 +3959,8 @@
} else if (!showAsGrid || (enableLargeDesktopWindowingTile()
&& dismissedTaskView != null && dismissedTaskView.isLargeTile()
&& nextFocusedTaskView == null && !dismissingForSplitSelection)) {
- int offset = getOffsetToDismissedTask(scrollDiffPerPage, dismissedIndex, taskCount);
+ int offset = getOffsetToDismissedTask(scrollDiffPerPage, dismissedIndex,
+ lastTaskViewIndex);
int scrollDiff = newScroll[i] - oldScroll[i] + offset;
if (scrollDiff != 0) {
translateTaskWhenDismissed(
@@ -3906,25 +3980,40 @@
: distanceFromDismissedTask;
// Set timings based on if user is initiating splitscreen on the focused task,
// or splitting/dismissing some other task.
- float animationStartProgress = isSlidingTasks
- ? Utilities.boundToRange(
- splitTimings.getGridSlideStartOffset()
- + (splitTimings.getGridSlideStaggerOffset()
- * staggerColumn),
- 0f,
- dismissTranslationInterpolationEnd)
- : Utilities.boundToRange(
- INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
- + ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
- * staggerColumn, 0f, dismissTranslationInterpolationEnd);
- float animationEndProgress = isSlidingTasks
- ? Utilities.boundToRange(
- splitTimings.getGridSlideStartOffset()
- + (splitTimings.getGridSlideStaggerOffset() * staggerColumn)
- + splitTimings.getGridSlideDurationOffset(),
- 0f,
- dismissTranslationInterpolationEnd)
- : dismissTranslationInterpolationEnd;
+ final float animationStartProgress;
+ if (isSlidingTasks) {
+ float slidingStartOffset = splitTimings.getGridSlideStartOffset()
+ + (splitTimings.getGridSlideStaggerOffset() * staggerColumn);
+ if (areAllDesktopTasksDismissed) {
+ animationStartProgress = Utilities.boundToRange(
+ slidingStartOffset
+ + splitTimings.getDesktopFadeSplitAnimationEndOffset(),
+ 0f,
+ dismissTranslationInterpolationEnd);
+ } else {
+ animationStartProgress = Utilities.boundToRange(
+ slidingStartOffset,
+ 0f,
+ dismissTranslationInterpolationEnd);
+ }
+ } else {
+ animationStartProgress = Utilities.boundToRange(
+ INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
+ + ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
+ * staggerColumn, 0f, dismissTranslationInterpolationEnd);
+ }
+
+ final float animationEndProgress;
+ if (isSlidingTasks && taskView != nextFocusedTaskView) {
+ animationEndProgress = Utilities.boundToRange(
+ splitTimings.getGridSlideStartOffset()
+ + (splitTimings.getGridSlideStaggerOffset() * staggerColumn)
+ + splitTimings.getGridSlideDurationOffset(),
+ 0f,
+ dismissTranslationInterpolationEnd);
+ } else {
+ animationEndProgress = dismissTranslationInterpolationEnd;
+ }
Interpolator dismissInterpolator = isSlidingTasks ? EMPHASIZED : LINEAR;
@@ -3936,7 +4025,6 @@
clampToProgress(LINEAR, animationStartProgress,
dismissTranslationInterpolationEnd));
primaryTranslation += dismissedTaskWidth;
- animationEndProgress = dismissTranslationInterpolationEnd;
float secondaryTranslation = -mTaskGridVerticalDiff;
if (!nextFocusedTaskFromTop) {
secondaryTranslation -= mTopBottomRowHeightDiff;
@@ -3964,11 +4052,6 @@
startTranslation = isTaskViewVisible(taskView) ? 0
: finalTranslation + (mIsRtl ? -mLastComputedTaskSize.right
: mLastComputedTaskSize.right);
- animationStartProgress = Utilities.boundToRange(
- animationStartProgress
- + splitTimings.getDesktopFadeSplitAnimationEndOffset(),
- 0f,
- dismissTranslationInterpolationEnd);
}
Animator dismissAnimator = ObjectAnimator.ofFloat(taskView,
taskView.getPrimaryDismissTranslationProperty(),
@@ -3977,7 +4060,7 @@
clampToProgress(dismissInterpolator, animationStartProgress,
animationEndProgress));
anim.add(dismissAnimator);
- mDismissPrimaryTranslations[i] = (int) finalTranslation;
+ mTaskViewsDismissPrimaryTranslations.put(taskView, (int) finalTranslation);
distanceFromDismissedTask++;
}
}
@@ -4107,7 +4190,7 @@
mCurrentPageScrollDiff = primaryScroll - currentPageScroll;
}
}
- } else if (dismissedIndex < pageToSnapTo || pageToSnapTo == taskCount - 1) {
+ } else if (dismissedIndex < pageToSnapTo || pageToSnapTo == lastTaskViewIndex) {
pageToSnapTo--;
}
boolean isHomeTaskDismissed = dismissedTaskView == getHomeTaskView();
@@ -4183,8 +4266,7 @@
// Snap to latest large tile page after dismissing the
// last grid task. This will prevent snapping to page 0 when
// desktop task is visible as large tile.
- pageToSnapTo = indexOfChild(
- mUtils.getLastLargeTaskView(getTaskViews()));
+ pageToSnapTo = indexOfChild(mUtils.getLastLargeTaskView());
}
} else if (taskViewIdToSnapTo != -1) {
// If snapping to another page due to indices rearranging, find
@@ -4214,7 +4296,7 @@
updateCurrentTaskActionsVisibility();
onDismissAnimationEnds();
mPendingAnimation = null;
- mDismissPrimaryTranslations = null;
+ mTaskViewsDismissPrimaryTranslations.clear();
}
});
}
@@ -4228,14 +4310,14 @@
* - Current page is rightmost page (leftmost for RTL)
* - Dragging an adjacent page on the left side (right side for RTL)
*/
- private int getOffsetToDismissedTask(int scrollDiffPerPage, int dismissedIndex, int taskCount) {
- // When mCurrentPage is ClearAllButton, use the last TaskView instead to calculate
- // offset.
- int currentPage = mCurrentPage == taskCount ? taskCount - 1 : mCurrentPage;
+ private int getOffsetToDismissedTask(int scrollDiffPerPage, int dismissedIndex,
+ int lastTaskViewIndex) {
+ // If `mCurrentPage` is beyond `lastTaskViewIndex`, use the last TaskView instead to
+ // calculate offset.
+ int currentPage = Math.min(mCurrentPage, lastTaskViewIndex);
int offset = mIsRtl ? scrollDiffPerPage : 0;
if (currentPage == dismissedIndex) {
- int lastPage = taskCount - 1;
- if (currentPage == lastPage) {
+ if (currentPage == lastTaskViewIndex) {
offset += mIsRtl ? -scrollDiffPerPage : scrollDiffPerPage;
}
} else {
@@ -4289,7 +4371,7 @@
);
if (view instanceof TaskView) {
- mDismissPrimaryTranslations[index] = scrollDiffPerPage;
+ mTaskViewsDismissPrimaryTranslations.put((TaskView) view, scrollDiffPerPage);
}
if (mEnableDrawingLiveTile && view instanceof TaskView
&& ((TaskView) view).isRunningTask()) {
@@ -4478,7 +4560,7 @@
// Init task grid nav helper with top/bottom id arrays.
TaskGridNavHelper taskGridNavHelper = new TaskGridNavHelper(getTopRowIdArray(),
- getBottomRowIdArray(), mUtils.getLargeTaskViewIds(getTaskViews()));
+ getBottomRowIdArray(), mUtils.getLargeTaskViewIds());
// Get current page's task view ID.
TaskView currentPageTaskView = getCurrentPageTaskView();
@@ -4681,11 +4763,11 @@
@Nullable
public TaskView getLastLargeTaskView() {
- return mUtils.getLastLargeTaskView(getTaskViews());
+ return mUtils.getLastLargeTaskView();
}
public int getLargeTilesCount() {
- return mUtils.getLargeTileCount(getTaskViews());
+ return mUtils.getLargeTileCount();
}
@Nullable
@@ -4721,10 +4803,10 @@
}
/**
- * Returns the current list of [TaskView] children.
+ * Returns iterable [TaskView] children.
*/
- public Iterable<TaskView> getTaskViews() {
- return mUtils.getTaskViews(getTaskViewCount(), this::requireTaskViewAt);
+ public TaskViewsIterable getTaskViews() {
+ return mTaskViewsIterable;
}
public void setOnEmptyMessageUpdatedListener(OnEmptyMessageUpdatedListener listener) {
@@ -4732,7 +4814,7 @@
}
public void updateEmptyMessage() {
- boolean isEmpty = getTaskViewCount() == 0;
+ boolean isEmpty = !hasTaskViews();
boolean hasSizeChanged = mLastMeasureSize.x != getWidth()
|| mLastMeasureSize.y != getHeight();
if (isEmpty == mShowEmptyMessage && !hasSizeChanged) {
@@ -4826,7 +4908,7 @@
int modalMidpoint = getCurrentPage();
TaskView carouselHiddenMidpointTask = runningTask != null ? runningTask
: mUtils.getFirstTaskViewInCarousel(/*nonRunningTaskCarouselHidden=*/true,
- getTaskViews(), null);
+ /*runningTaskView=*/null);
int carouselHiddenMidpoint = indexOfChild(carouselHiddenMidpointTask);
boolean shouldCalculateOffsetForAllTasks = showAsGrid
&& (enableGridOnlyOverview() || enableLargeDesktopWindowingTile())
@@ -5157,17 +5239,16 @@
SplitAnimationTimings timings = AnimUtils.getDeviceOverviewToSplitTimings(
mContainer.getDeviceProfile().isTablet);
if (enableLargeDesktopWindowingTile()) {
- for (int i = 0; i < getTaskViewCount(); i++) {
- TaskView taskView = requireTaskViewAt(i);
+ getTaskViews().forEachWithIndexInParent((taskView, index) -> {
if (taskView instanceof DesktopTaskView) {
// Setting pivot to scale down from screen centre.
- if (i >= mCurrentPage - 1 && i <= mCurrentPage + 1) {
- float pivotX;
- if (i == mCurrentPage - 1) {
+ if (isTaskViewVisible(taskView)) {
+ float pivotX = 0f;
+ if (index < mCurrentPage) {
pivotX = mIsRtl ? taskView.getWidth() / 2f - mPageSpacing
- taskView.getWidth()
: taskView.getWidth() / 2f + mPageSpacing + taskView.getWidth();
- } else if (i == mCurrentPage) {
+ } else if (index == mCurrentPage) {
pivotX = taskView.getWidth() / 2f;
} else {
pivotX = mIsRtl ? taskView.getWidth() + mPageSpacing
@@ -5186,7 +5267,7 @@
clampToProgress(deskTopFadeInterPolator, 0f,
timings.getDesktopFadeSplitAnimationEndOffset()));
}
- }
+ });
}
}
@@ -5491,12 +5572,12 @@
// Get the deadzone rect between the task views
mTaskViewDeadZoneRect.setEmpty();
- int count = getTaskViewCount();
- if (count > 0) {
- final View taskView = requireTaskViewAt(0);
- requireTaskViewAt(count - 1).getHitRect(mTaskViewDeadZoneRect);
- mTaskViewDeadZoneRect.union(taskView.getLeft(), taskView.getTop(), taskView.getRight(),
- taskView.getBottom());
+ if (hasTaskViews()) {
+ final View firstTaskView = getFirstTaskView();
+ mUtils.getLastTaskView().getHitRect(mTaskViewDeadZoneRect);
+ mTaskViewDeadZoneRect.union(firstTaskView.getLeft(), firstTaskView.getTop(),
+ firstTaskView.getRight(),
+ firstTaskView.getBottom());
}
}
@@ -5660,7 +5741,7 @@
throw new IllegalStateException("Another pending animation is still running");
}
- if (getTaskViewCount() == 0) {
+ if (!hasTaskViews()) {
return new PendingAnimation(duration);
}
@@ -5766,34 +5847,33 @@
@Override
public void addChildrenForAccessibility(ArrayList<View> outChildren) {
- // Add children in reverse order
- for (int i = getChildCount() - 1; i >= 0; --i) {
- outChildren.add(getChildAt(i));
- }
+ outChildren.addAll(getAccessibilityChildren());
+ }
+
+ public List<View> getAccessibilityChildren() {
+ return mUtils.getAccessibilityChildren();
}
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
final AccessibilityNodeInfo.CollectionInfo
- collectionInfo = AccessibilityNodeInfo.CollectionInfo.obtain(
- 1, getTaskViewCount(), false,
- AccessibilityNodeInfo.CollectionInfo.SELECTION_MODE_NONE);
+ collectionInfo = new AccessibilityNodeInfo.CollectionInfo(
+ 1, getAccessibilityChildren().size(), false);
info.setCollectionInfo(collectionInfo);
}
@Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
-
- final int taskViewCount = getTaskViewCount();
- event.setScrollable(taskViewCount > 0);
+ event.setScrollable(hasTaskViews());
if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
+ final List<View> accessibilityChildren = getAccessibilityChildren();
final int[] visibleTasks = getVisibleChildrenRange();
- event.setFromIndex(taskViewCount - visibleTasks[1]);
- event.setToIndex(taskViewCount - visibleTasks[0]);
- event.setItemCount(taskViewCount);
+ event.setFromIndex(accessibilityChildren.indexOf(getChildAt(visibleTasks[1])));
+ event.setToIndex(accessibilityChildren.indexOf(getChildAt(visibleTasks[0])));
+ event.setItemCount(accessibilityChildren.size());
}
}
@@ -6019,7 +6099,7 @@
@Override
protected int computeMinScroll() {
- if (getTaskViewCount() <= 0) {
+ if (!hasTaskViews()) {
return super.computeMinScroll();
}
@@ -6028,7 +6108,7 @@
@Override
protected int computeMaxScroll() {
- if (getTaskViewCount() <= 0) {
+ if (!hasTaskViews()) {
return super.computeMaxScroll();
}
@@ -6040,17 +6120,15 @@
if (mShowAsGridLastOnLayout) {
// For grid Overview, it always start if a large tile (focused task or desktop task) if
// they exist, otherwise it start with the first task.
- TaskView firstLargeTaskView = mUtils.getFirstLargeTaskView(getTaskViews(),
- isSplitSelectionActive());
+ TaskView firstLargeTaskView = mUtils.getFirstLargeTaskView();
if (firstLargeTaskView != null) {
firstView = firstLargeTaskView;
} else {
- firstView = mUtils.getFirstSmallTaskView(getTaskViews());
+ firstView = mUtils.getFirstSmallTaskView();
}
} else {
firstView = mUtils.getFirstTaskViewInCarousel(
- /*nonRunningTaskCarouselHidden=*/mDesktopCarouselDetachProgress > 0,
- getTaskViews(), getRunningTaskView());
+ /*nonRunningTaskCarouselHidden=*/mDesktopCarouselDetachProgress > 0);
}
return indexOfChild(firstView);
}
@@ -6067,12 +6145,11 @@
if (lastGridTaskView != null) {
lastView = lastGridTaskView;
} else {
- lastView = mUtils.getLastLargeTaskView(getTaskViews());
+ lastView = mUtils.getLastLargeTaskView();
}
} else {
lastView = mUtils.getLastTaskViewInCarousel(
- /*nonRunningTaskCarouselHidden=*/mDesktopCarouselDetachProgress > 0,
- getTaskViews(), getRunningTaskView());
+ /*nonRunningTaskCarouselHidden=*/mDesktopCarouselDetachProgress > 0);
}
return indexOfChild(lastView);
}
@@ -6100,42 +6177,34 @@
mClearAllButton.setScrollOffsetPrimary(mIsRtl ? clearAllWidthDiff : -clearAllWidthDiff);
}
- boolean pageScrollChanged = false;
-
+ int[] oldPageScrolls = Arrays.copyOf(outPageScrolls, outPageScrolls.length);
int clearAllIndex = indexOfChild(mClearAllButton);
int clearAllScroll = 0;
int clearAllWidth = getPagedOrientationHandler().getPrimarySize(mClearAllButton);
if (clearAllIndex != -1 && clearAllIndex < outPageScrolls.length) {
float scrollDiff = mClearAllButton.getScrollAdjustment(showAsFullscreen, showAsGrid);
- clearAllScroll = newPageScrolls[clearAllIndex] + (int) scrollDiff;
- if (outPageScrolls[clearAllIndex] != clearAllScroll) {
- pageScrollChanged = true;
- outPageScrolls[clearAllIndex] = clearAllScroll;
- }
+ clearAllScroll = newPageScrolls[clearAllIndex] + Math.round(scrollDiff);
+ outPageScrolls[clearAllIndex] = clearAllScroll;
}
- final int taskCount = getTaskViewCount();
int lastTaskScroll = getLastTaskScroll(clearAllScroll, clearAllWidth);
- for (int i = 0; i < taskCount; i++) {
- TaskView taskView = requireTaskViewAt(i);
+ getTaskViews().forEachWithIndexInParent((taskView, index) -> {
float scrollDiff = taskView.getScrollAdjustment(showAsGrid);
- int pageScroll = newPageScrolls[i] + Math.round(scrollDiff);
+ int pageScroll = newPageScrolls[index] + Math.round(scrollDiff);
if ((mIsRtl && pageScroll < lastTaskScroll)
|| (!mIsRtl && pageScroll > lastTaskScroll)) {
pageScroll = lastTaskScroll;
}
- if (outPageScrolls[i] != pageScroll) {
- pageScrollChanged = true;
- outPageScrolls[i] = pageScroll;
- }
+ outPageScrolls[index] = pageScroll;
if (DEBUG) {
- Log.d(TAG, "getPageScrolls - outPageScrolls[" + i + "]: " + outPageScrolls[i]);
+ Log.d(TAG,
+ "getPageScrolls - outPageScrolls[" + index + "]: " + outPageScrolls[index]);
}
- }
+ });
if (DEBUG) {
Log.d(TAG, "getPageScrolls - clearAllScroll: " + clearAllScroll);
}
- return pageScrollChanged;
+ return !Arrays.equals(oldPageScrolls, outPageScrolls);
}
@Override
@@ -6408,8 +6477,7 @@
return;
}
- Map<Integer, ThumbnailData> updatedThumbnails = mUtils.screenshotTasks(taskView,
- mRecentsAnimationController);
+ Map<Integer, ThumbnailData> updatedThumbnails = mUtils.screenshotTasks(taskView);
if (enableRefactorTaskThumbnail()) {
mHelper.switchToScreenshot(taskView, updatedThumbnails, onFinishRunnable);
} else {
diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java b/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java
index b04753b..a1d22fe 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java
@@ -25,7 +25,6 @@
import android.view.View;
import android.view.Window;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.BaseActivity;
@@ -34,7 +33,6 @@
import com.android.launcher3.taskbar.TaskbarUIController;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.ScrimView;
-import com.android.quickstep.util.TISBindHelper;
/**
* Interface to be implemented by the parent view of RecentsView
@@ -217,6 +215,4 @@
void setTaskbarUIController(@Nullable TaskbarUIController taskbarUIController);
@Nullable TaskbarUIController getTaskbarUIController();
-
- @NonNull TISBindHelper getTISBindHelper();
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt b/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt
index 3616fbb..87771c6 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt
+++ b/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt
@@ -16,28 +16,24 @@
package com.android.quickstep.views
+import com.android.launcher3.util.coroutines.DispatcherProvider
import com.android.quickstep.ViewUtils
import com.android.quickstep.recents.viewmodel.RecentsViewModel
import com.android.systemui.shared.recents.model.ThumbnailData
-import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
/** Helper for [RecentsView] to interact with the [RecentsViewModel]. */
-class RecentsViewModelHelper(private val recentsViewModel: RecentsViewModel) {
- private lateinit var viewAttachedScope: CoroutineScope
-
- fun onAttachedToWindow() {
- viewAttachedScope =
- CoroutineScope(SupervisorJob() + Dispatchers.Default + CoroutineName("RecentsView"))
- }
-
+class RecentsViewModelHelper(
+ private val recentsViewModel: RecentsViewModel,
+ private val recentsCoroutineScope: CoroutineScope,
+ private val dispatcherProvider: DispatcherProvider,
+) {
fun onDetachedFromWindow() {
- viewAttachedScope.cancel("RecentsView detaching from window")
+ recentsCoroutineScope.cancel("RecentsView detaching from window")
}
fun switchToScreenshot(
@@ -48,7 +44,7 @@
// Update recentsViewModel and apply the thumbnailOverride ASAP, before waiting inside
// viewAttachedScope.
recentsViewModel.setRunningTaskShowScreenshot(true)
- viewAttachedScope.launch {
+ recentsCoroutineScope.launch(dispatcherProvider.main) {
recentsViewModel.waitForRunningTaskShowScreenshotToUpdate()
recentsViewModel.waitForThumbnailsToUpdate(updatedThumbnails)
withContext(Dispatchers.Main) { ViewUtils.postFrameDrawn(taskView, onFinishRunnable) }
diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt b/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt
new file mode 100644
index 0000000..ccf22ce
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ */
+
+package com.android.quickstep.views
+
+import android.view.View
+import androidx.core.view.children
+import com.android.launcher3.Flags.enableLargeDesktopWindowingTile
+import com.android.quickstep.util.GroupTask
+import com.android.quickstep.views.RecentsView.RUNNING_TASK_ATTACH_ALPHA
+import com.android.systemui.shared.recents.model.ThumbnailData
+
+/**
+ * Helper class for [RecentsView]. This util class contains refactored and extracted functions from
+ * RecentsView to facilitate the implementation of unit tests.
+ */
+class RecentsViewUtils(private val recentsView: RecentsView<*, *>) {
+ /** Takes a screenshot of all [taskView] and return map of taskId to the screenshot */
+ fun screenshotTasks(taskView: TaskView): Map<Int, ThumbnailData> {
+ val recentsAnimationController = recentsView.recentsAnimationController ?: return emptyMap()
+ return taskView.taskContainers.associate {
+ it.task.key.id to recentsAnimationController.screenshotTask(it.task.key.id)
+ }
+ }
+
+ /**
+ * Sorts task groups to move desktop tasks to the end of the list.
+ *
+ * @param tasks List of group tasks to be sorted.
+ * @return Sorted list of GroupTasks to be used in the RecentsView.
+ */
+ fun sortDesktopTasksToFront(tasks: List<GroupTask>): List<GroupTask> {
+ val (desktopTasks, otherTasks) = tasks.partition { it.taskViewType == TaskViewType.DESKTOP }
+ return otherTasks + desktopTasks
+ }
+
+ /** Counts [TaskView]s that are [DesktopTaskView] instances. */
+ fun getDesktopTaskViewCount(): Int = recentsView.taskViews.count { it is DesktopTaskView }
+
+ /** Returns a list of all large TaskView Ids from [TaskView]s */
+ fun getLargeTaskViewIds(): List<Int> =
+ recentsView.taskViews.filter { it.isLargeTile }.map { it.taskViewId }
+
+ /** Counts [TaskView]s that are large tiles. */
+ fun getLargeTileCount(): Int = recentsView.taskViews.count { it.isLargeTile }
+
+ /** Returns the first TaskView that should be displayed as a large tile. */
+ fun getFirstLargeTaskView(): TaskView? =
+ recentsView.taskViews.firstOrNull {
+ it.isLargeTile && !(recentsView.isSplitSelectionActive && it is DesktopTaskView)
+ }
+
+ /** Returns the expected focus task. */
+ fun getExpectedFocusedTask(): TaskView? =
+ if (enableLargeDesktopWindowingTile())
+ recentsView.taskViews.firstOrNull { it !is DesktopTaskView }
+ else recentsView.taskViews.firstOrNull()
+
+ /**
+ * Returns the [TaskView] that should be the current page during task binding, in the following
+ * priorities:
+ * 1. Running task
+ * 2. Focused task
+ * 3. First non-desktop task
+ * 4. Last desktop task
+ * 5. null otherwise
+ */
+ fun getExpectedCurrentTask(runningTaskView: TaskView?, focusedTaskView: TaskView?): TaskView? =
+ runningTaskView
+ ?: focusedTaskView
+ ?: recentsView.taskViews.firstOrNull { it !is DesktopTaskView }
+ ?: recentsView.taskViews.lastOrNull()
+
+ /** Returns the first TaskView if it exists, or null otherwise. */
+ fun getFirstTaskView(): TaskView? = recentsView.taskViews.firstOrNull()
+
+ /** Returns the last TaskView if it exists, or null otherwise. */
+ fun getLastTaskView(): TaskView? = recentsView.taskViews.lastOrNull()
+
+ /** Returns the first TaskView that is not large */
+ fun getFirstSmallTaskView(): TaskView? = recentsView.taskViews.firstOrNull { !it.isLargeTile }
+
+ /** Returns the last TaskView that should be displayed as a large tile. */
+ fun getLastLargeTaskView(): TaskView? = recentsView.taskViews.lastOrNull { it.isLargeTile }
+
+ /**
+ * Gets the list of accessibility children. Currently all the children of RecentsViews are
+ * added, and in the reverse order to the list.
+ */
+ fun getAccessibilityChildren(): List<View> = recentsView.children.toList().reversed()
+
+ @JvmOverloads
+ /** Returns the first [TaskView], with some tasks possibly hidden in the carousel. */
+ fun getFirstTaskViewInCarousel(
+ nonRunningTaskCarouselHidden: Boolean,
+ runningTaskView: TaskView? = recentsView.runningTaskView,
+ ): TaskView? =
+ recentsView.taskViews.firstOrNull {
+ it.isVisibleInCarousel(runningTaskView, nonRunningTaskCarouselHidden)
+ }
+
+ /** Returns the last [TaskView], with some tasks possibly hidden in the carousel. */
+ fun getLastTaskViewInCarousel(nonRunningTaskCarouselHidden: Boolean): TaskView? =
+ recentsView.taskViews.lastOrNull {
+ it.isVisibleInCarousel(recentsView.runningTaskView, nonRunningTaskCarouselHidden)
+ }
+
+ /** Returns if any small tasks are fully visible */
+ fun isAnySmallTaskFullyVisible(): Boolean =
+ recentsView.taskViews.any { !it.isLargeTile && recentsView.isTaskViewFullyVisible(it) }
+
+ /** Apply attachAlpha to all [TaskView] accordingly to different conditions. */
+ fun applyAttachAlpha(nonRunningTaskCarouselHidden: Boolean) {
+ recentsView.taskViews.forEach { taskView ->
+ taskView.attachAlpha =
+ if (taskView == recentsView.runningTaskView) {
+ RUNNING_TASK_ATTACH_ALPHA.get(recentsView)
+ } else {
+ if (
+ taskView.isVisibleInCarousel(
+ recentsView.runningTaskView,
+ nonRunningTaskCarouselHidden,
+ )
+ )
+ 1f
+ else 0f
+ }
+ }
+ }
+
+ fun TaskView.isVisibleInCarousel(
+ runningTaskView: TaskView?,
+ nonRunningTaskCarouselHidden: Boolean,
+ ): Boolean =
+ if (!nonRunningTaskCarouselHidden) true
+ else getCarouselType() == runningTaskView.getCarouselType()
+
+ /** Returns the carousel type of the TaskView, and default to fullscreen if it's null. */
+ private fun TaskView?.getCarouselType(): TaskViewCarousel =
+ if (this is DesktopTaskView) TaskViewCarousel.DESKTOP else TaskViewCarousel.FULL_SCREEN
+
+ private enum class TaskViewCarousel {
+ FULL_SCREEN,
+ DESKTOP,
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt
index 084ea4b..0dbad70 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -658,10 +658,10 @@
recentsView?.let {
collectionItemInfo =
- AccessibilityNodeInfo.CollectionItemInfo.obtain(
+ AccessibilityNodeInfo.CollectionItemInfo(
0,
1,
- it.taskViewCount - it.indexOfChild(this@TaskView) - 1,
+ it.getAccessibilityChildren().indexOf(this@TaskView),
1,
false,
)
diff --git a/quickstep/src/com/android/quickstep/views/TaskViewIcon.java b/quickstep/src/com/android/quickstep/views/TaskViewIcon.java
index 94739cb..80e3a2b 100644
--- a/quickstep/src/com/android/quickstep/views/TaskViewIcon.java
+++ b/quickstep/src/com/android/quickstep/views/TaskViewIcon.java
@@ -48,6 +48,11 @@
void setModalAlpha(float alpha);
/**
+ * Sets the opacity of the view for flex split state.
+ */
+ void setFlexSplitAlpha(float alpha);
+
+ /**
* Returns this icon view's drawable.
*/
@Nullable Drawable getDrawable();
diff --git a/quickstep/src_protolog/com/android/launcher3/util/StateManagerProtoLogProxy.java b/quickstep/src_protolog/com/android/launcher3/util/StateManagerProtoLogProxy.java
index bc989dc..c319cb1 100644
--- a/quickstep/src_protolog/com/android/launcher3/util/StateManagerProtoLogProxy.java
+++ b/quickstep/src_protolog/com/android/launcher3/util/StateManagerProtoLogProxy.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.Flags.enableStateManagerProtoLog;
import static com.android.quickstep.util.QuickstepProtoLogGroup.LAUNCHER_STATE_MANAGER;
+import static com.android.quickstep.util.QuickstepProtoLogGroup.isProtoLogInitialized;
import androidx.annotation.NonNull;
@@ -30,7 +31,7 @@
public static void logGoToState(
@NonNull Object fromState, @NonNull Object toState, @NonNull String trace) {
- if (!enableStateManagerProtoLog()) return;
+ if (!enableStateManagerProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(LAUNCHER_STATE_MANAGER,
"StateManager.goToState: fromState: %s, toState: %s, partial trace:\n%s",
fromState,
@@ -40,7 +41,7 @@
public static void logCreateAtomicAnimation(
@NonNull Object fromState, @NonNull Object toState, @NonNull String trace) {
- if (!enableStateManagerProtoLog()) return;
+ if (!enableStateManagerProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(LAUNCHER_STATE_MANAGER, "StateManager.createAtomicAnimation: "
+ "fromState: %s, toState: %s, partial trace:\n%s",
fromState,
@@ -49,17 +50,17 @@
}
public static void logOnStateTransitionStart(@NonNull Object state) {
- if (!enableStateManagerProtoLog()) return;
+ if (!enableStateManagerProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(LAUNCHER_STATE_MANAGER, "StateManager.onStateTransitionStart: state: %s", state);
}
public static void logOnStateTransitionEnd(@NonNull Object state) {
- if (!enableStateManagerProtoLog()) return;
+ if (!enableStateManagerProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(LAUNCHER_STATE_MANAGER, "StateManager.onStateTransitionEnd: state: %s", state);
}
public static void logCancelAnimation(boolean animationOngoing, @NonNull String trace) {
- if (!enableStateManagerProtoLog()) return;
+ if (!enableStateManagerProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(LAUNCHER_STATE_MANAGER,
"StateManager.cancelAnimation: animation ongoing: %b, partial trace:\n%s",
animationOngoing,
diff --git a/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java b/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java
index f25f6f4..be1a4e8 100644
--- a/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java
+++ b/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java
@@ -37,6 +37,7 @@
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.SET_END_TARGET;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.START_RECENTS_ANIMATION;
import static com.android.quickstep.util.QuickstepProtoLogGroup.ACTIVE_GESTURE_LOG;
+import static com.android.quickstep.util.QuickstepProtoLogGroup.isProtoLogInitialized;
import android.graphics.Point;
import android.graphics.RectF;
@@ -62,7 +63,7 @@
public static void logLauncherDestroyed() {
ActiveGestureLog.INSTANCE.addLog("Launcher destroyed", LAUNCHER_DESTROYED);
- if (!enableActiveGestureProtoLog()) return;
+ if (isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "Launcher destroyed");
}
@@ -70,7 +71,7 @@
ActiveGestureLog.INSTANCE.addLog(
/* event= */ "AbsSwipeUpHandler.onRecentsAnimationCanceled",
/* gestureEvent= */ CANCEL_RECENTS_ANIMATION);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "AbsSwipeUpHandler.onRecentsAnimationCanceled");
}
@@ -78,7 +79,7 @@
ActiveGestureLog.INSTANCE.addLog(
/* event= */ "RecentsAnimationCallbacks.onAnimationFinished",
ON_FINISH_RECENTS_ANIMATION);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "AbsSwipeUpHandler.onAnimationFinished");
}
@@ -86,27 +87,27 @@
ActiveGestureLog.INSTANCE.addLog(
"AbsSwipeUpHandler.cancelCurrentAnimation",
ActiveGestureErrorDetector.GestureEvent.CANCEL_CURRENT_ANIMATION);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "AbsSwipeUpHandler.cancelCurrentAnimation");
}
public static void logAbsSwipeUpHandlerOnTasksAppeared() {
ActiveGestureLog.INSTANCE.addLog("AbsSwipeUpHandler.onTasksAppeared: "
+ "force finish recents animation complete; clearing state callback.");
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "AbsSwipeUpHandler.onTasksAppeared: "
+ "force finish recents animation complete; clearing state callback.");
}
public static void logHandOffAnimation() {
ActiveGestureLog.INSTANCE.addLog("AbsSwipeUpHandler.handOffAnimation");
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "AbsSwipeUpHandler.handOffAnimation");
}
public static void logFinishRecentsAnimationOnTasksAppeared() {
ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimationOnTasksAppeared");
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "finishRecentsAnimationOnTasksAppeared");
}
@@ -114,14 +115,14 @@
ActiveGestureLog.INSTANCE.addLog(
/* event= */ "RecentsAnimationCallbacks.onAnimationCanceled",
/* gestureEvent= */ ON_CANCEL_RECENTS_ANIMATION);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "RecentsAnimationCallbacks.onAnimationCanceled");
}
public static void logRecentsAnimationCallbacksOnTasksAppeared() {
ActiveGestureLog.INSTANCE.addLog("RecentsAnimationCallbacks.onTasksAppeared",
ActiveGestureErrorDetector.GestureEvent.TASK_APPEARED);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "RecentsAnimationCallbacks.onTasksAppeared");
}
@@ -129,39 +130,39 @@
ActiveGestureLog.INSTANCE.addLog(
/* event= */ "TaskAnimationManager.startRecentsAnimation",
/* gestureEvent= */ START_RECENTS_ANIMATION);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "TaskAnimationManager.startRecentsAnimation");
}
public static void logLaunchingSideTaskFailed() {
ActiveGestureLog.INSTANCE.addLog("Unable to launch side task (no recents)");
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "Unable to launch side task (no recents)");
}
public static void logContinueRecentsAnimation() {
ActiveGestureLog.INSTANCE.addLog(/* event= */ "continueRecentsAnimation");
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "continueRecentsAnimation");
}
public static void logCleanUpRecentsAnimationSkipped() {
ActiveGestureLog.INSTANCE.addLog(
/* event= */ "cleanUpRecentsAnimation skipped due to wrong callbacks");
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "cleanUpRecentsAnimation skipped due to wrong callbacks");
}
public static void logCleanUpRecentsAnimation() {
ActiveGestureLog.INSTANCE.addLog(/* event= */ "cleanUpRecentsAnimation");
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "cleanUpRecentsAnimation");
}
public static void logOnInputEventUserLocked() {
ActiveGestureLog.INSTANCE.addLog(
"TIS.onInputEvent: Cannot process input event: user is locked");
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"TIS.onInputEvent: Cannot process input event: user is locked");
}
@@ -171,7 +172,7 @@
+ "but a previously-requested recents animation hasn't started. "
+ "Ignoring all following motion events.",
RECENTS_ANIMATION_START_PENDING);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "TIS.onMotionEvent: A new gesture has been started, "
+ "but a previously-requested recents animation hasn't started. "
+ "Ignoring all following motion events.");
@@ -180,53 +181,53 @@
public static void logOnInputEventThreeButtonNav() {
ActiveGestureLog.INSTANCE.addLog("TIS.onInputEvent: Cannot process input event: "
+ "using 3-button nav and event is not a trackpad event");
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "TIS.onInputEvent: Cannot process input event: "
+ "using 3-button nav and event is not a trackpad event");
}
public static void logPreloadRecentsAnimation() {
ActiveGestureLog.INSTANCE.addLog("preloadRecentsAnimation");
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "preloadRecentsAnimation");
}
public static void logRecentTasksMissing() {
ActiveGestureLog.INSTANCE.addLog("Null mRecentTasks", RECENT_TASKS_MISSING);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "Null mRecentTasks");
}
public static void logExecuteHomeCommand() {
ActiveGestureLog.INSTANCE.addLog("OverviewCommandHelper.executeCommand(HOME)");
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "OverviewCommandHelper.executeCommand(HOME)");
}
public static void logFinishRecentsAnimationCallback() {
ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation-callback");
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "finishRecentsAnimation-callback");
}
public static void logOnScrollerAnimationAborted() {
ActiveGestureLog.INSTANCE.addLog("scroller animation aborted",
ActiveGestureErrorDetector.GestureEvent.SCROLLER_ANIMATION_ABORTED);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "scroller animation aborted");
}
public static void logInputConsumerBecameActive(@NonNull String consumerName) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"%s became active", consumerName));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "%s became active", consumerName);
}
public static void logTaskLaunchFailed(int launchedTaskId) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"Launch failed, task (id=%d) finished mid transition", launchedTaskId));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"Launch failed, task (id=%d) finished mid transition", launchedTaskId);
}
@@ -234,7 +235,7 @@
public static void logOnPageEndTransition(int nextPageIndex) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"onPageEndTransition: current page index updated: %d", nextPageIndex));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"onPageEndTransition: current page index updated: %d", nextPageIndex);
}
@@ -244,7 +245,7 @@
"Quick switch from home fallback case: The TaskView at index %d is missing.",
taskIndex),
QUICK_SWITCH_FROM_HOME_FALLBACK);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"Quick switch from home fallback case: The TaskView at index %d is missing.",
taskIndex);
@@ -255,7 +256,7 @@
"Quick switch from home failed: TaskViews at indices %d and 0 are missing.",
taskIndex),
QUICK_SWITCH_FROM_HOME_FAILED);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"Quick switch from home failed: TaskViews at indices %d and 0 are missing.",
taskIndex);
@@ -265,42 +266,42 @@
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"finishRecentsAnimation: %b", toRecents),
/* gestureEvent= */ FINISH_RECENTS_ANIMATION);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "finishRecentsAnimation: %b", toRecents);
}
public static void logSetEndTarget(@NonNull String target) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"setEndTarget %s", target), /* gestureEvent= */ SET_END_TARGET);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "setEndTarget %s", target);
}
public static void logStartHomeIntent(@NonNull String reason) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"OverviewComponentObserver.startHomeIntent: %s", reason));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "OverviewComponentObserver.startHomeIntent: %s", reason);
}
public static void logRunningTaskPackage(@NonNull String packageName) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"Current running task package name=%s", packageName));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "Current running task package name=%s", packageName);
}
public static void logSysuiStateFlags(@NonNull String stateFlags) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"Current SystemUi state flags=%s", stateFlags));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "Current SystemUi state flags=%s", stateFlags);
}
public static void logSetInputConsumer(@NonNull String consumerName, @NonNull String reason) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"setInputConsumer: %s. reason(s):%s", consumerName, reason));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"setInputConsumer: %s. reason(s):%s", consumerName, reason);
}
@@ -312,7 +313,7 @@
+ "one (%s) was excluded from recents",
otherTaskPackage,
runningTaskPackage));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"Changing active task to %s because the previous task running on top of this "
+ "one (%s) was excluded from recents",
@@ -328,7 +329,7 @@
/* gestureEvent= */ action == ACTION_DOWN
? MOTION_DOWN
: MOTION_UP);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"onMotionEvent(%d, %d): %s, %s", x, y, actionString, classification);
}
@@ -341,7 +342,7 @@
classification,
pointerCount),
MOTION_MOVE);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"onMotionEvent: %s, %s, pointerCount: %d", action, classification, pointerCount);
}
@@ -350,7 +351,7 @@
@NonNull String action, @NonNull String classification) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"onMotionEvent: %s, %s", action, classification));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "onMotionEvent: %s, %s", action, classification);
}
@@ -362,7 +363,7 @@
startNavMode,
currentNavMode),
NAVIGATION_MODE_SWITCHED);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"TIS.onInputEvent: Navigation mode switched mid-gesture (%s -> %s); "
+ "cancelling gesture.",
@@ -373,7 +374,7 @@
public static void logUnknownInputEvent(@NonNull String event) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"TIS.onInputEvent: Cannot process input event: received unknown event %s", event));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"TIS.onInputEvent: Cannot process input event: received unknown event %s", event);
}
@@ -381,14 +382,14 @@
public static void logFinishRunningRecentsAnimation(boolean toHome) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"finishRunningRecentsAnimation: %b", toHome));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "finishRunningRecentsAnimation: %b", toHome);
}
public static void logOnRecentsAnimationStartCancelled() {
ActiveGestureLog.INSTANCE.addLog("RecentsAnimationCallbacks.onAnimationStart (canceled): 0",
/* gestureEvent= */ ON_START_RECENTS_ANIMATION);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "RecentsAnimationCallbacks.onAnimationStart (canceled): 0");
}
@@ -396,7 +397,7 @@
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"RecentsAnimationCallbacks.onAnimationStart (canceled): %d", appCount),
/* gestureEvent= */ ON_START_RECENTS_ANIMATION);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"RecentsAnimationCallbacks.onAnimationStart (canceled): %d", appCount);
}
@@ -406,7 +407,7 @@
"TaskAnimationManager.startRecentsAnimation(%s): "
+ "Setting mRecentsAnimationStartPending = false",
callback));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"TaskAnimationManager.startRecentsAnimation(%s): "
+ "Setting mRecentsAnimationStartPending = false",
@@ -418,7 +419,7 @@
"TaskAnimationManager.startRecentsAnimation: "
+ "Setting mRecentsAnimationStartPending = %b",
value));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"TaskAnimationManager.startRecentsAnimation: "
+ "Setting mRecentsAnimationStartPending = %b",
@@ -428,28 +429,28 @@
public static void logLaunchingSideTask(int taskId) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"Launching side task id=%d", taskId));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "Launching side task id=%d", taskId);
}
public static void logOnInputEventActionDown(@NonNull ActiveGestureLog.CompoundString reason) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"TIS.onMotionEvent: ").append(reason));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "TIS.onMotionEvent: %s", reason.toString());
}
public static void logStartNewTask(@NonNull ActiveGestureLog.CompoundString tasks) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"Launching task: ").append(tasks));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "TIS.onMotionEvent: %s", tasks.toString());
}
public static void logMotionPauseDetectorEvent(@NonNull ActiveGestureLog.CompoundString event) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"MotionPauseDetector: ").append(event));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "MotionPauseDetector: %s", event.toString());
}
@@ -457,7 +458,7 @@
@NonNull ActiveGestureLog.CompoundString reason) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"handleTaskAppeared check failed: ").append(reason));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "handleTaskAppeared check failed: %s", reason.toString());
}
@@ -469,7 +470,7 @@
@NonNull String string,
@Nullable ActiveGestureErrorDetector.GestureEvent gestureEvent) {
ActiveGestureLog.INSTANCE.addLog(string, gestureEvent);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "%s", string);
}
@@ -477,7 +478,7 @@
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"onSettledOnEndTarget %s", endTarget),
/* gestureEvent= */ ON_SETTLED_ON_END_TARGET);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "onSettledOnEndTarget %s", endTarget);
}
@@ -488,7 +489,7 @@
velocityY,
angle),
velocityX == 0 && velocityY == 0 ? INVALID_VELOCITY_ON_SWIPE_UP : null);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"calculateEndTarget: velocities=(x=%fdp/ms, y=%fdp/ms), angle=%f",
velocityX,
@@ -501,7 +502,7 @@
"Forcefully finishing recents animation: Unexpected task appeared id=%d, pkg=%s",
taskId,
packageName));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"Forcefully finishing recents animation: Unexpected task appeared id=%d, pkg=%s",
taskId,
@@ -511,7 +512,7 @@
public static void logCreateTouchRegionForDisplay(int displayRotation,
@NonNull Point displaySize, @NonNull RectF swipeRegion, @NonNull RectF ohmRegion,
int gesturalHeight, int largerGesturalHeight, @NonNull String reason) {
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"OrientationTouchTransformer.createRegionForDisplay: "
+ "dispRot=%d, dispSize=%s, swipeRegion=%s, ohmRegion=%s, "
diff --git a/quickstep/src_protolog/com/android/quickstep/util/QuickstepProtoLogGroup.java b/quickstep/src_protolog/com/android/quickstep/util/QuickstepProtoLogGroup.java
index bb02a11..2327cfc 100644
--- a/quickstep/src_protolog/com/android/quickstep/util/QuickstepProtoLogGroup.java
+++ b/quickstep/src_protolog/com/android/quickstep/util/QuickstepProtoLogGroup.java
@@ -16,6 +16,8 @@
package com.android.quickstep.util;
+import android.util.Log;
+
import androidx.annotation.NonNull;
import com.android.internal.protolog.ProtoLog;
@@ -26,7 +28,7 @@
/** Enums used to interface with the ProtoLog API. */
public enum QuickstepProtoLogGroup implements IProtoLogGroup {
- ACTIVE_GESTURE_LOG(true, true, false, "ActiveGestureLog"),
+ ACTIVE_GESTURE_LOG(true, true, Constants.DEBUG_ACTIVE_GESTURE, "ActiveGestureLog"),
RECENTS_WINDOW(true, true, Constants.DEBUG_RECENTS_WINDOW, "RecentsWindow"),
LAUNCHER_STATE_MANAGER(true, true, Constants.DEBUG_STATE_MANAGER, "LauncherStateManager");
@@ -35,7 +37,23 @@
private volatile boolean mLogToLogcat;
private final @NonNull String mTag;
+ public static boolean isProtoLogInitialized() {
+ if (!Variables.sIsInitialized) {
+ Log.w(Constants.TAG,
+ "Attempting to log to ProtoLog before initializing it.",
+ new IllegalStateException());
+ }
+ return Variables.sIsInitialized;
+ }
+
public static void initProtoLog() {
+ if (Variables.sIsInitialized) {
+ Log.e(Constants.TAG,
+ "Attempting to re-initialize ProtoLog.", new IllegalStateException());
+ return;
+ }
+ Log.i(Constants.TAG, "Initializing ProtoLog.");
+ Variables.sIsInitialized = true;
ProtoLog.init(QuickstepProtoLogGroup.values());
}
@@ -95,8 +113,16 @@
this.mLogToLogcat = logToLogcat;
}
+ private static final class Variables {
+
+ private static boolean sIsInitialized = false;
+ }
+
private static final class Constants {
+ private static final String TAG = "QuickstepProtoLogGroup";
+
+ private static final boolean DEBUG_ACTIVE_GESTURE = false;
private static final boolean DEBUG_RECENTS_WINDOW = false;
private static final boolean DEBUG_STATE_MANAGER = true; // b/279059025, b/325463989
diff --git a/quickstep/src_protolog/com/android/quickstep/util/RecentsWindowProtoLogProxy.java b/quickstep/src_protolog/com/android/quickstep/util/RecentsWindowProtoLogProxy.java
index f54ad67..2c9ae33 100644
--- a/quickstep/src_protolog/com/android/quickstep/util/RecentsWindowProtoLogProxy.java
+++ b/quickstep/src_protolog/com/android/quickstep/util/RecentsWindowProtoLogProxy.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.Flags.enableRecentsWindowProtoLog;
import static com.android.quickstep.util.QuickstepProtoLogGroup.RECENTS_WINDOW;
+import static com.android.quickstep.util.QuickstepProtoLogGroup.isProtoLogInitialized;
import androidx.annotation.NonNull;
@@ -36,17 +37,17 @@
public class RecentsWindowProtoLogProxy {
public static void logOnStateSetStart(@NonNull String stateName) {
- if (!enableRecentsWindowProtoLog()) return;
+ if (!enableRecentsWindowProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(RECENTS_WINDOW, "onStateSetStart: %s", stateName);
}
public static void logOnStateSetEnd(@NonNull String stateName) {
- if (!enableRecentsWindowProtoLog()) return;
+ if (!enableRecentsWindowProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(RECENTS_WINDOW, "onStateSetEnd: %s", stateName);
}
public static void logStartRecentsWindow(boolean isShown, boolean windowViewIsNull) {
- if (!enableRecentsWindowProtoLog()) return;
+ if (!enableRecentsWindowProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(RECENTS_WINDOW,
"Starting recents window: isShow= %b, windowViewIsNull=%b",
isShown,
@@ -54,7 +55,7 @@
}
public static void logCleanup(boolean isShown) {
- if (!enableRecentsWindowProtoLog()) return;
+ if (!enableRecentsWindowProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(RECENTS_WINDOW, "Cleaning up recents window: isShow= %b", isShown);
}
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
index 44070cf..5471072 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
@@ -240,6 +240,7 @@
// verify the hide bubble animation is pending
assertThat(animatorScheduler.delayedBlock).isNotNull()
+ whenever(bubbleStashController.isStashed).thenReturn(true)
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.onStashStateChangingWhileAnimating()
}
@@ -249,7 +250,7 @@
assertThat(animator.isAnimating).isFalse()
assertThat(bubbleBarView.scaleX).isEqualTo(1)
assertThat(bubbleBarView.scaleY).isEqualTo(1)
- verify(bubbleStashController).onNewBubbleAnimationInterrupted(any(), any())
+ verify(bubbleStashController).onNewBubbleAnimationInterrupted(eq(true), any())
// PhysicsAnimatorTestUtils posts the cancellation to the main thread so we need to wait
// again
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRule.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRule.kt
index cd4e78b..07b32af 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRule.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRule.kt
@@ -29,7 +29,6 @@
import com.android.launcher3.taskbar.TaskbarControllers
import com.android.launcher3.taskbar.TaskbarManager
import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarNavButtonCallbacks
-import com.android.launcher3.taskbar.TaskbarViewController
import com.android.launcher3.taskbar.bubbles.BubbleControllers
import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule.InjectController
import com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR
@@ -130,15 +129,12 @@
}
try {
- TaskbarViewController.enableModelLoadingForTests(false)
-
// Required to complete initialization.
instrumentation.runOnMainSync { taskbarManager.onUserUnlocked() }
base.evaluate()
} finally {
instrumentation.runOnMainSync { taskbarManager.destroy() }
- TaskbarViewController.enableModelLoadingForTests(true)
}
}
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarWindowSandboxContext.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarWindowSandboxContext.kt
index 8c51216..0b94dfd 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarWindowSandboxContext.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarWindowSandboxContext.kt
@@ -25,6 +25,7 @@
import com.android.launcher3.FakeLauncherPrefs
import com.android.launcher3.LauncherPrefs
import com.android.launcher3.dagger.LauncherAppComponent
+import com.android.launcher3.dagger.LauncherAppModule
import com.android.launcher3.dagger.LauncherAppSingleton
import com.android.launcher3.util.MainThreadInitializedObject.ObjectSandbox
import com.android.launcher3.util.SandboxApplication
@@ -116,7 +117,7 @@
}
@LauncherAppSingleton
-@Component
+@Component(modules = [LauncherAppModule::class])
interface TaskbarSandboxComponent : LauncherAppComponent {
@Component.Builder
interface Builder : LauncherAppComponent.Builder {
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
index 6dce10b..c334552 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
@@ -52,7 +52,6 @@
import android.view.ViewTreeObserver;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.launcher3.DeviceProfile;
@@ -60,9 +59,9 @@
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StatefulContainer;
+import com.android.launcher3.util.LauncherModelHelper;
import com.android.launcher3.util.MSDLPlayerWrapper;
import com.android.launcher3.util.SystemUiController;
-import com.android.quickstep.fallback.window.RecentsWindowFactory;
import com.android.quickstep.util.ContextInitListener;
import com.android.quickstep.util.MotionPauseDetector;
import com.android.quickstep.views.RecentsView;
@@ -90,8 +89,9 @@
SWIPE_HANDLER extends AbsSwipeUpHandler<RECENTS_CONTAINER, RECENTS_VIEW, STATE_TYPE>,
CONTAINER_INTERFACE extends BaseContainerInterface<STATE_TYPE, RECENTS_CONTAINER>> {
- protected final Context mContext =
- InstrumentationRegistry.getInstrumentation().getTargetContext();
+ protected final LauncherModelHelper mLauncherModelHelper = new LauncherModelHelper();
+ protected final LauncherModelHelper.SandboxModelContext mContext =
+ mLauncherModelHelper.sandboxContext;
protected final InputConsumerController mInputConsumerController =
InputConsumerController.getRecentsAnimationInputConsumer();
protected final ActivityManager.RunningTaskInfo mRunningTaskInfo =
@@ -180,8 +180,7 @@
@Before
public void setUpRecentsContainer() {
- mTaskAnimationManager = new TaskAnimationManager(mContext, getRecentsWindowFactory(),
- mRecentsAnimationDeviceState);
+ mTaskAnimationManager = new TaskAnimationManager(mContext, mRecentsAnimationDeviceState);
RecentsViewContainer recentsContainer = getRecentsContainer();
RECENTS_VIEW recentsView = getRecentsView();
@@ -383,11 +382,6 @@
return createSwipeHandler(SystemClock.uptimeMillis(), false);
}
- @Nullable
- protected RecentsWindowFactory getRecentsWindowFactory() {
- return null;
- }
-
@NonNull
protected abstract SWIPE_HANDLER createSwipeHandler(
long touchTimeMs, boolean continuingLastGesture);
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/DisplayModelTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/DisplayModelTest.kt
new file mode 100644
index 0000000..a939e84
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/DisplayModelTest.kt
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+package com.android.quickstep
+
+import android.content.Context
+import android.view.Display
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertNull
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DisplayModelTest {
+ private val context: Context = ApplicationProvider.getApplicationContext()
+
+ class TestableResource : DisplayModel.DisplayResource() {
+ var isCleanupCalled = false
+
+ override fun cleanup() {
+ isCleanupCalled = true
+ }
+ }
+
+ private val testableDisplayModel =
+ object : DisplayModel<TestableResource>(context) {
+ override fun createDisplayResource(displayId: Int) {
+ displayResourceArray.put(displayId, TestableResource())
+ }
+ }
+
+ @Test
+ fun testCreate() {
+ testableDisplayModel.createDisplayResource(Display.DEFAULT_DISPLAY)
+ val resource = testableDisplayModel.getDisplayResource(Display.DEFAULT_DISPLAY)
+ assertNotNull(resource)
+ }
+
+ @Test
+ fun testCleanAndDelete() {
+ testableDisplayModel.createDisplayResource(Display.DEFAULT_DISPLAY)
+ val resource = testableDisplayModel.getDisplayResource(Display.DEFAULT_DISPLAY)!!
+ assertNotNull(resource)
+ testableDisplayModel.deleteDisplayResource(Display.DEFAULT_DISPLAY)
+ assert(resource.isCleanupCalled)
+ assertNull(testableDisplayModel.getDisplayResource(Display.DEFAULT_DISPLAY))
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2Test.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2Test.kt
index 37accdb..50ba55c 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2Test.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2Test.kt
@@ -19,15 +19,13 @@
import android.graphics.PointF
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.launcher3.Flags.enableLauncherOverviewInWindow
import com.android.launcher3.R
import com.android.launcher3.dagger.LauncherAppComponent
+import com.android.launcher3.dagger.LauncherAppModule
import com.android.launcher3.dagger.LauncherAppSingleton
import com.android.launcher3.util.LauncherModelHelper
import com.android.launcher3.util.MSDLPlayerWrapper
-import com.android.quickstep.dagger.QuickStepModule
-import com.android.quickstep.fallback.window.RecentsWindowFactory
+import com.android.quickstep.fallback.window.RecentsDisplayModel
import com.android.systemui.contextualeducation.GestureType
import com.android.systemui.shared.system.InputConsumerController
import dagger.BindsInstance
@@ -55,6 +53,8 @@
@Mock private lateinit var systemUiProxy: SystemUiProxy
+ @Mock private lateinit var recentsDisplayModel: RecentsDisplayModel
+
@Mock private lateinit var msdlPlayerWrapper: MSDLPlayerWrapper
private lateinit var underTest: LauncherSwipeHandlerV2
@@ -70,20 +70,14 @@
@Before
fun setup() {
sandboxContext.initDaggerComponent(
- DaggerTestComponent.builder().bindSystemUiProxy(systemUiProxy)
+ DaggerTestComponent.builder()
+ .bindSystemUiProxy(systemUiProxy)
+ .bindRecentsDisplayModel(recentsDisplayModel)
)
+
val deviceState = mock(RecentsAnimationDeviceState::class.java)
whenever(deviceState.rotationTouchHelper).thenReturn(mock(RotationTouchHelper::class.java))
- if (enableLauncherOverviewInWindow()) {
- // Initialize an instance of RecentsWindowFactory directly to simulate its
- // initialization in TouchInteractionService#onCreate.
- // This instance will then be used in OverviewComponentObserver.
- InstrumentationRegistry.getInstrumentation().runOnMainSync {
- RecentsWindowFactory(sandboxContext)
- }
- }
-
gestureState = spy(GestureState(OverviewComponentObserver(sandboxContext, deviceState), 0))
underTest =
@@ -123,12 +117,14 @@
}
@LauncherAppSingleton
-@Component(modules = [QuickStepModule::class])
+@Component(modules = [LauncherAppModule::class])
interface TestComponent : LauncherAppComponent {
@Component.Builder
interface Builder : LauncherAppComponent.Builder {
@BindsInstance fun bindSystemUiProxy(proxy: SystemUiProxy): Builder
+ @BindsInstance fun bindRecentsDisplayModel(model: RecentsDisplayModel): Builder
+
override fun build(): TestComponent
}
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentsWindowSwipeHandlerTestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentsWindowSwipeHandlerTestCase.java
index 3287fb5..40fefae 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentsWindowSwipeHandlerTestCase.java
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentsWindowSwipeHandlerTestCase.java
@@ -16,17 +16,16 @@
package com.android.quickstep;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.when;
-
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import androidx.test.filters.SmallTest;
+import com.android.launcher3.dagger.LauncherAppComponent;
+import com.android.launcher3.dagger.LauncherAppSingleton;
import com.android.launcher3.util.LauncherMultivalentJUnit;
+import com.android.quickstep.dagger.QuickStepModule;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.fallback.RecentsState;
-import com.android.quickstep.fallback.window.RecentsWindowFactory;
+import com.android.quickstep.fallback.window.RecentsDisplayModel;
import com.android.quickstep.fallback.window.RecentsWindowManager;
import com.android.quickstep.fallback.window.RecentsWindowSwipeHandler;
import com.android.quickstep.views.RecentsViewContainer;
@@ -35,6 +34,9 @@
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import dagger.BindsInstance;
+import dagger.Component;
+
@SmallTest
@RunWith(LauncherMultivalentJUnit.class)
public class RecentsWindowSwipeHandlerTestCase extends AbsSwipeUpHandlerTestCase<
@@ -44,13 +46,14 @@
RecentsWindowSwipeHandler,
FallbackWindowInterface> {
- @Mock private RecentsWindowFactory mRecentsWindowFactory;
+ @Mock private RecentsDisplayModel mRecentsDisplayModel;
@Mock private FallbackRecentsView<RecentsWindowManager> mRecentsView;
@Mock private RecentsWindowManager mRecentsWindowManager;
@Before
- public void setupRecentsWindowFactory() {
- when(mRecentsWindowFactory.get(anyInt())).thenReturn(mRecentsWindowManager);
+ public void setRecentsDisplayModel() {
+ mContext.initDaggerComponent(DaggerRecentsWindowSwipeHandlerTestCase_TestComponent.builder()
+ .bindRecentsDisplayModel(mRecentsDisplayModel));
}
@NonNull
@@ -65,16 +68,9 @@
touchTimeMs,
continuingLastGesture,
mInputConsumerController,
- mRecentsWindowFactory,
mMSDLPlayerWrapper);
}
- @Nullable
- @Override
- protected RecentsWindowFactory getRecentsWindowFactory() {
- return mRecentsWindowFactory;
- }
-
@NonNull
@Override
protected RecentsViewContainer getRecentsContainer() {
@@ -86,4 +82,14 @@
protected FallbackRecentsView<RecentsWindowManager> getRecentsView() {
return mRecentsView;
}
+
+ @LauncherAppSingleton
+ @Component(modules = { QuickStepModule.class })
+ interface TestComponent extends LauncherAppComponent {
+ @Component.Builder
+ interface Builder extends LauncherAppComponent.Builder {
+ @BindsInstance Builder bindRecentsDisplayModel(RecentsDisplayModel model);
+ @Override LauncherAppComponent build();
+ }
+ }
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/window/RecentsDisplayModelTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/window/RecentsDisplayModelTest.kt
new file mode 100644
index 0000000..d2aa6ac
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/window/RecentsDisplayModelTest.kt
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+
+package com.android.quickstep.recents.window
+
+import android.graphics.Point
+import android.hardware.display.DisplayManager
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
+import android.view.Display
+import android.view.DisplayAdjustments
+import android.view.Surface
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.Flags.FLAG_ENABLE_FALLBACK_OVERVIEW_IN_WINDOW
+import com.android.launcher3.Flags.FLAG_ENABLE_LAUNCHER_OVERVIEW_IN_WINDOW
+import com.android.launcher3.dagger.LauncherAppComponent
+import com.android.launcher3.dagger.LauncherAppModule
+import com.android.launcher3.dagger.LauncherAppSingleton
+import com.android.launcher3.util.LauncherModelHelper
+import com.android.launcher3.util.window.CachedDisplayInfo
+import com.android.quickstep.fallback.window.RecentsDisplayModel
+import dagger.BindsInstance
+import dagger.Component
+import org.junit.Assert
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@EnableFlags(FLAG_ENABLE_LAUNCHER_OVERVIEW_IN_WINDOW, FLAG_ENABLE_FALLBACK_OVERVIEW_IN_WINDOW)
+class RecentsDisplayModelTest {
+ @get:Rule val setFlagsRule = SetFlagsRule()
+
+ // initiate dagger components for injection
+ private val launcherModelHelper = LauncherModelHelper()
+ private val context = spy(launcherModelHelper.sandboxContext)
+ private val displayManager: DisplayManager = context.spyService(DisplayManager::class.java)
+ private val display: Display = mock()
+
+ private lateinit var recentsDisplayModel: RecentsDisplayModel
+
+ private val width = 2208
+ private val height = 1840
+
+ @Before
+ fun setup() {
+ // Mock display
+ val displayInfo = CachedDisplayInfo(Point(width, height), Surface.ROTATION_0)
+ whenever(display.rotation).thenReturn(displayInfo.rotation)
+ whenever(display.displayAdjustments).thenReturn(DisplayAdjustments())
+ whenever(context.display).thenReturn(display)
+
+ // Mock displayManager
+ whenever(displayManager.getDisplay(anyInt())).thenReturn(display)
+
+ runOnMainSync { recentsDisplayModel = RecentsDisplayModel.INSTANCE.get(context) }
+ context.initDaggerComponent(
+ DaggerRecentsDisplayModelComponent.builder()
+ .bindRecentsDisplayModel(recentsDisplayModel)
+ )
+ }
+
+ @Test
+ fun testEnsureSingleton() {
+ val recentsDisplayModel2 = RecentsDisplayModel.INSTANCE.get(context)
+ assert(recentsDisplayModel == recentsDisplayModel2)
+ }
+
+ @Test
+ fun testDefaultDisplayCreation() {
+ Assert.assertNotNull(recentsDisplayModel.getRecentsWindowManager(Display.DEFAULT_DISPLAY))
+ Assert.assertNotNull(
+ recentsDisplayModel.getFallbackWindowInterface(Display.DEFAULT_DISPLAY)
+ )
+ }
+
+ @Test
+ fun testCreateSeparateInstances() {
+ val display = Display.DEFAULT_DISPLAY + 1
+ runOnMainSync { recentsDisplayModel.createDisplayResource(display) }
+
+ val defaultManager = recentsDisplayModel.getRecentsWindowManager(Display.DEFAULT_DISPLAY)
+ val secondaryManager = recentsDisplayModel.getRecentsWindowManager(display)
+ Assert.assertNotSame(defaultManager, secondaryManager)
+
+ val defaultInterface =
+ recentsDisplayModel.getFallbackWindowInterface(Display.DEFAULT_DISPLAY)
+ val secondInterface = recentsDisplayModel.getFallbackWindowInterface(display)
+ Assert.assertNotSame(defaultInterface, secondInterface)
+ }
+
+ @Test
+ fun testDestroy() {
+ Assert.assertNotNull(recentsDisplayModel.getRecentsWindowManager(Display.DEFAULT_DISPLAY))
+ Assert.assertNotNull(
+ recentsDisplayModel.getFallbackWindowInterface(Display.DEFAULT_DISPLAY)
+ )
+ recentsDisplayModel.destroy()
+ Assert.assertNull(recentsDisplayModel.getRecentsWindowManager(Display.DEFAULT_DISPLAY))
+ Assert.assertNull(recentsDisplayModel.getFallbackWindowInterface(Display.DEFAULT_DISPLAY))
+ }
+
+ private fun runOnMainSync(f: Runnable) {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync { f.run() }
+ }
+}
+
+@LauncherAppSingleton
+@Component(modules = [LauncherAppModule::class])
+interface RecentsDisplayModelComponent : LauncherAppComponent {
+ @Component.Builder
+ interface Builder : LauncherAppComponent.Builder {
+ @BindsInstance fun bindRecentsDisplayModel(model: RecentsDisplayModel): Builder
+
+ override fun build(): RecentsDisplayModelComponent
+ }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java b/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
index 5b46dc8..f923142 100644
--- a/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
+++ b/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
@@ -101,7 +101,7 @@
}
private TaskView getLatestTask(Launcher launcher) {
- return launcher.<RecentsView>getOverviewPanel().getTaskViewAt(0);
+ return launcher.<RecentsView>getOverviewPanel().getFirstTaskView();
}
private void runWithShellPermission(Runnable action) {
diff --git a/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java b/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java
index 2c6b750..f522a2c 100644
--- a/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java
@@ -56,7 +56,6 @@
import com.android.launcher3.util.LockedUserState;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.views.BaseDragLayer;
-import com.android.quickstep.fallback.window.RecentsWindowFactory;
import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
import com.android.quickstep.inputconsumers.BubbleBarInputConsumer;
import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer;
@@ -122,7 +121,7 @@
@Before
public void setupTaskAnimationManager() {
mTaskAnimationManager = new TaskAnimationManager(
- mContext, mock(RecentsWindowFactory.class), mDeviceState);
+ mContext, mDeviceState);
}
@Before
diff --git a/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
index b15b78e..e065dba 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
@@ -23,6 +23,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeFalse;
+import android.os.Process;
import android.util.Log;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -74,8 +75,9 @@
}
private void createAndStartPrivateProfileUser() {
- String createUserOutput = executeShellCommand("pm create-user --profileOf 0 --user-type "
- + "android.os.usertype.profile.PRIVATE " + PRIVATE_PROFILE_NAME);
+ int myUserId = Process.myUserHandle().getIdentifier();
+ String createUserOutput = executeShellCommand("pm create-user --profileOf " + myUserId
+ + " --user-type android.os.usertype.profile.PRIVATE " + PRIVATE_PROFILE_NAME);
updatePrivateProfileSetupSuccessful("pm create-user", createUserOutput);
String[] tokens = createUserOutput.split("\\s+");
mProfileUserId = Integer.parseInt(tokens[tokens.length - 1]);
diff --git a/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java b/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
index 960a467..098b417 100644
--- a/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
@@ -30,8 +30,6 @@
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
-import com.android.quickstep.fallback.window.RecentsWindowFactory;
-
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
@@ -45,9 +43,6 @@
InstrumentationRegistry.getInstrumentation().getTargetContext();
@Mock
- private RecentsWindowFactory mRecentsWindowFactory;
-
- @Mock
private SystemUiProxy mSystemUiProxy;
private TaskAnimationManager mTaskAnimationManager;
@@ -62,8 +57,7 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mTaskAnimationManager = new TaskAnimationManager(mContext, mRecentsWindowFactory,
- mRecentsAnimationDeviceState) {
+ mTaskAnimationManager = new TaskAnimationManager(mContext, mRecentsAnimationDeviceState) {
@Override
SystemUiProxy getSystemUiProxy() {
return mSystemUiProxy;
diff --git a/quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt b/quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt
index cb59f7d..3148737 100644
--- a/quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt
@@ -70,7 +70,10 @@
whenever(taskbarActivityContext.launcherPrefs).thenReturn(launcherPrefs)
whenever(taskbarActivityContext.dragLayer).thenReturn(taskbarDragLayer)
whenever(taskbarActivityContext.statsLogManager).thenReturn(statsLogManager)
- whenever(taskbarControllers.taskbarDesktopModeController.areDesktopTasksVisible)
+ whenever(
+ taskbarControllers.taskbarDesktopModeController
+ .areDesktopTasksVisibleAndNotInOverview
+ )
.thenAnswer { _ -> isInDesktopMode }
pinningController = spy(TaskbarPinningController(taskbarActivityContext))
pinningController.init(taskbarControllers, taskbarSharedState)
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 4dd5e1d..b9a2065 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Moenie voorstel nie"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Vasspeldvoorspelling"</string>
<string name="bubble" msgid="3072951361014076670">"Borrel"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"installeer kortpaaie"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Laat \'n app toe om kortpaaie by te voeg sonder gebruikerinmenging."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"lees tuis-instellings en -kortpaaie"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index c40ef69..530aa80 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"መተግበሪያውን አይጠቁሙ"</string>
<string name="pin_prediction" msgid="4196423321649756498">"የፒን ግምት"</string>
<string name="bubble" msgid="3072951361014076670">"አረፋ"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"አቋራጮችን ይጭናል"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"መተግበሪያው ያለተጠቃሚ ጣልቃ ገብነት አቋራጭ እንዲያክል ያስችለዋል።"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"የመነሻ ቅንብሮች እና አቋራጮችን ያነባል"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index bbdfebd..879c0db 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -68,10 +68,8 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"تطبيقات العمل"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"المحادثات"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"تدوين الملاحظات"</string>
- <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
- <skip />
- <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
- <skip />
+ <string name="widget_cell_tap_to_show_add_button_label" msgid="4354194214317043581">"إظهار زر الإضافة"</string>
+ <string name="widget_cell_tap_to_hide_add_button_label" msgid="6117805205101555997">"إخفاء زر الإضافة"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"إضافة"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"إضافة التطبيق المصغّر \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\""</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"عرض الكل"</string>
@@ -102,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"عدم اقتراح التطبيق"</string>
<string name="pin_prediction" msgid="4196423321649756498">"تثبيت التطبيق المتوقّع"</string>
<string name="bubble" msgid="3072951361014076670">"فقاعة"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"تثبيت اختصارات"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"للسماح لتطبيق ما بإضافة اختصارات بدون تدخل المستخدم."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"الاطلاع على الإعدادات والاختصارات على الشاشة الرئيسية"</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index acce0d2..eb20bd1 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"পৰামৰ্শ নিদিব"</string>
<string name="pin_prediction" msgid="4196423321649756498">"পূৰ্বানুমান কৰা এপ্টো পিন কৰক"</string>
<string name="bubble" msgid="3072951361014076670">"বাবল"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"শ্বৰ্টকাট ইনষ্টল কৰিব পাৰে"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"ব্য়ৱহাৰকাৰীৰ হস্তক্ষেপ অবিহনেই কোনো এপক শ্বৰ্টকাটবোৰ যোগ কৰাৰ অনুমতি দিয়ে।"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"গৃহ স্ক্ৰীনত ছেটিং আৰু শ্বৰ্টকাটসমূহ পঢ়া"</string>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 8eda426..00850f95 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Tətbiq təklif olunmasın"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Proqnozlaşdırılan tətbiqi bərkidin"</string>
<string name="bubble" msgid="3072951361014076670">"Qabarcıq"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"qısayolları quraşdır"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Tətbiqə istifadəçi müdaxiləsi olmadan qısayolları əlavə etməyə icazə verir."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"Əsas səhifə ayarlarını və qısayollarını oxumaq"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 33941ff..3cad215 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlaži aplikaciju"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Zakači predviđanje"</string>
<string name="bubble" msgid="3072951361014076670">"Oblačić"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instaliranje prečica"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Dozvoljava aplikaciji da dodaje prečice bez intervencije korisnika."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"čitanje podešavanja i prečica na početnom ekranu"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index d395006..88b89c1 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Не прапаноўваць праграму"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Замацаваць прапанаваную праграму"</string>
<string name="bubble" msgid="3072951361014076670">"Бурбалка"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"Стварэнне ярлыкоў"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Дазваляе праграмам дадаваць ярлыкі без умяшання карыстальніка."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"счытваць налады і ярлыкі на галоўным экране"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index cf298c3..b919345 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Без предлагане на приложение"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Фиксиране на предвиждането"</string>
<string name="bubble" msgid="3072951361014076670">"Балонче"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"инсталиране на преки пътища"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Разрешава на приложението да добавя преки пътища без намеса на потребителя."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"четене на настройките и преките пътища на началния екран"</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index f2654bb..7292342 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"অ্যাপ সাজেস্ট করবেন না"</string>
<string name="pin_prediction" msgid="4196423321649756498">"আপনার প্রয়োজন হতে পারে এমন অ্যাপ পিন করুন"</string>
<string name="bubble" msgid="3072951361014076670">"বাবল"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"শর্টকাটগুলি ইনস্টল করে"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"একটি অ্যাপ্লিকেশানকে ব্যবহারকারীর হস্তক্ষেপ ছাড়াই শর্টকাটগুলি যোগ করার অনুমতি দেয়৷"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"হোম স্ক্রিনে সেটিংস ও শর্টকাট পড়ুন"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 3277e22..a89b953 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlaži aplikaciju"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Zakači predviđanje"</string>
<string name="bubble" msgid="3072951361014076670">"Oblačić"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instaliraj prečice"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Dopušta aplikaciji dodavanje prečica bez posredovanja korisnika."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"čita postavke na početnom ekranu i prečice"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index f8f8e28..4d89e6d 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"No suggereixis l\'aplicació"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fixa la predicció"</string>
<string name="bubble" msgid="3072951361014076670">"Bombolla"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instal·la dreceres"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Permet que una aplicació afegeixi dreceres sense la intervenció de l\'usuari."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"llegir la configuració i les dreceres de la pantalla d\'inici"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 5fa9154..3b0895f 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Nenavrhovat aplikaci"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Připnout předpověď"</string>
<string name="bubble" msgid="3072951361014076670">"Bublat"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instalace zástupce"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Umožňuje aplikaci přidat zástupce bez zásahu uživatele."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"čtení nastavení a zkratek plochy"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 16e3473..ee1c7cb 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Foreslå ikke en app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fastgør forslaget"</string>
<string name="bubble" msgid="3072951361014076670">"Boble"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"installere genveje"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Tillader, at en app tilføjer genveje uden brugerens indgriben."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"læs indstillinger og genveje for startskærm"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index cb64821..e3c2fdc 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"App nicht vorschlagen"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Vorgeschlagene App fixieren"</string>
<string name="bubble" msgid="3072951361014076670">"Bubble"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"Verknüpfungen installieren"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Ermöglicht einer App das Hinzufügen von Verknüpfungen ohne Eingreifen des Nutzers"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"Einstellungen und Verknüpfungen auf dem Startbildschirm lesen"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 672ba05..696a0b5 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Να μην προτείνεται"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Καρφίτσωμα πρόβλεψης"</string>
<string name="bubble" msgid="3072951361014076670">"Συννεφάκι"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"εγκατάσταση συντομεύσεων"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Επιτρέπει σε μια εφαρμογή την προσθήκη συντομεύσεων χωρίς την παρέμβαση του χρήστη."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"ανάγνωση ρυθμίσεων και συντομεύσεων αρχικής οθόνης"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index a4f88de..2027683 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Don\'t suggest app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pin prediction"</string>
<string name="bubble" msgid="3072951361014076670">"Bubble"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"install shortcuts"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Allows an app to add shortcuts without user intervention."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"read Home settings and shortcuts"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index 363bb4b..0ebcd18 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -100,6 +100,7 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Don\'t suggest app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pin Prediction"</string>
<string name="bubble" msgid="3072951361014076670">"Bubble"</string>
+ <string name="pin_to_taskbar" msgid="1281337899690299038">"Pin to taskbar"</string>
<string name="permlab_install_shortcut" msgid="5632423390354674437">"install shortcuts"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Allows an app to add shortcuts without user intervention."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"read home settings and shortcuts"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index a4f88de..2027683 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Don\'t suggest app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pin prediction"</string>
<string name="bubble" msgid="3072951361014076670">"Bubble"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"install shortcuts"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Allows an app to add shortcuts without user intervention."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"read Home settings and shortcuts"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index a4f88de..2027683 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Don\'t suggest app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pin prediction"</string>
<string name="bubble" msgid="3072951361014076670">"Bubble"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"install shortcuts"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Allows an app to add shortcuts without user intervention."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"read Home settings and shortcuts"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 0344113..6cafd09 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"No sugerir app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fijar predicción"</string>
<string name="bubble" msgid="3072951361014076670">"Burbuja"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar accesos directos"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite que una aplicación agregue accesos directos sin que el usuario intervenga."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"leer parámetros de configuración y accesos directos de la página principal"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index fc34acf..badd94a 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"No sugerir aplicación"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fijar predicción"</string>
<string name="bubble" msgid="3072951361014076670">"Burbuja"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar accesos directos"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite que una aplicación añada accesos directos sin intervención del usuario."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"leer ajustes y accesos directos de la pantalla de inicio"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 5fc3b82..169a378 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ära soovita rakendust"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Kinnita ennustus"</string>
<string name="bubble" msgid="3072951361014076670">"Mull"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"installi otseteed"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Võimaldab rakendusel lisada otseteid kasutaja sekkumiseta."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"avakuva seadete ja otseteede lugemine"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 99f127a..d194482 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ez iradoki aplikazioa"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Ainguratu iragarpena"</string>
<string name="bubble" msgid="3072951361014076670">"Burbuila"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"Instalatu lasterbideak"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Erabiltzaileak ezer egin gabe lasterbideak gehitzeko baimena ematen die aplikazioei."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"irakurri hasierako pantailako ezarpenak eta lasterbideak"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 99e8718..f6e0896 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"برنامه پیشنهاد داده نشود"</string>
<string name="pin_prediction" msgid="4196423321649756498">"سنجاق کردن پیشنهاد"</string>
<string name="bubble" msgid="3072951361014076670">"حبابک"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"نصب میانبرها"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"به برنامه اجازه میدهد میانبرها را بدون دخالت کاربر اضافه کند."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"خواندن تنظیمات و میانبرهای صفحه اصلی"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 6beb593..64d7b5e 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Älä ehdota sovellusta"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Kiinnitä sovellus"</string>
<string name="bubble" msgid="3072951361014076670">"Kupla"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"asenna pikakuvakkeita"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Antaa sovelluksen lisätä pikakuvakkeita itsenäisesti ilman käyttäjän valintaa."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"lukea aloitusnäytön asetuksia ja pikakuvakkeita"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 696d8af..9f6efe2 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne pas suggérer d\'appli"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Épingler la prédiction"</string>
<string name="bubble" msgid="3072951361014076670">"Bulle"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"installer des raccourcis"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Permet à une appli d\'ajouter des raccourcis sans l\'intervention de l\'utilisateur."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"lire les paramètres et les raccourcis de la page d\'accueil"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index c870afa..e91cd03 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne pas suggérer d\'appli"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Épingler la prédiction"</string>
<string name="bubble" msgid="3072951361014076670">"Bulle"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"installer des raccourcis"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Permettre à une application d\'ajouter des raccourcis sans l\'intervention de l\'utilisateur"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"Lire les paramètres et les raccourcis de la page d\'accueil"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 5bcf2fd..7bfa617 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Non suxerir app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fixar predición"</string>
<string name="bubble" msgid="3072951361014076670">"Burbulla"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar atallos"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite a unha aplicación engadir atallos sen intervención do usuario."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"ler a configuración e os atallos da pantalla de inicio"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 1480ea9..4992dd3 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ઍપ સૂચવશો નહીં"</string>
<string name="pin_prediction" msgid="4196423321649756498">"પૂર્વાનુમાનને પિન કરો"</string>
<string name="bubble" msgid="3072951361014076670">"બબલ"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"શૉર્ટકટ ઇન્સ્ટૉલ કરો"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"એપ્લિકેશનને વપરાશકર્તા હસ્તક્ષેપ વગર શોર્ટકટ્સ ઉમેરવાની મંજૂરી આપે છે."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"હોમ સેટિંગ અને શૉર્ટકટ વાંચો"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 32a2a96..0398a27 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ऐप्लिकेशन का सुझाव न दें"</string>
<string name="pin_prediction" msgid="4196423321649756498">"सुझाए गए ऐप पिन करें"</string>
<string name="bubble" msgid="3072951361014076670">"बबल"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"शॉर्टकट इंस्टॉल करें"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"ऐप को उपयोगकर्ता के हस्तक्षेप के बिना शॉर्टकट जोड़ने देती है."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"होम स्क्रीन की सेटिंग और शॉर्टकट पढ़ने की अनुमति"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 726efe8..ab22e7a 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlaži aplikaciju"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Prikvači predviđenu apl."</string>
<string name="bubble" msgid="3072951361014076670">"Oblačić"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instaliranje prečaca"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Aplikaciji omogućuje dodavanje prečaca bez intervencije korisnika."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"čitati postavke i prečace početnog zaslona"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index b85d3df..ea72c1f 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne javasoljon appot"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Várható kitűzése"</string>
<string name="bubble" msgid="3072951361014076670">"Buborék"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"parancsikonok telepítése"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Lehetővé teszi egy alkalmazás számára, hogy felhasználói beavatkozás nélkül adjon hozzá parancsikonokat."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"kezdőképernyő beállításainak és parancsikonjainak olvasása"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 36e89b4..46d4b35 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Չառաջարկել"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Ամրացնել առաջարկվող հավելվածը"</string>
<string name="bubble" msgid="3072951361014076670">"Ամպիկ"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"Դյուրանցումների տեղադրում"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Հավելվածին թույլ է տալիս ավելացնել դյուրանցումներ՝ առանց օգտագործողի միջամտության:"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"կարդալ հիմնական էկրանի կարգավորումներն ու դյուրանցումները"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 0d5a819..a9cc4fe 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Jangan sarankan apl"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pin Prediksi"</string>
<string name="bubble" msgid="3072951361014076670">"Balon"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"memasang pintasan"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Mengizinkan aplikasi menambahkan pintasan tanpa campur tangan pengguna."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"membaca setelan dan pintasan layar utama"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 8f3c604..764435c 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ekki fá tillögu að forriti"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Festa tillögu"</string>
<string name="bubble" msgid="3072951361014076670">"Blaðra"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"setja upp flýtileiðir"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Leyfir forriti að bæta við flýtileiðum án íhlutunar notanda."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"lesa stillingar og flýtileiðir heimaskjás"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index f125816..47fb620 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Non suggerire app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Blocca previsione"</string>
<string name="bubble" msgid="3072951361014076670">"Fumetto"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"Aggiunta di scorciatoie"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Consente a un\'app di aggiungere scorciatoie automaticamente."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"leggere le impostazioni e le scorciatoie nella schermata Home"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index f7fd83a..7aa7b1a 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"בלי להציע את האפליקציה"</string>
<string name="pin_prediction" msgid="4196423321649756498">"הצמדת החיזוי"</string>
<string name="bubble" msgid="3072951361014076670">"בועה"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"התקנת קיצורי דרך"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"מאפשר לאפליקציה להוסיף קיצורי דרך ללא התערבות המשתמש."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"קריאת ההגדרות וקיצורי הדרך בדף הבית"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 9b012c5..93bfb37 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"アプリを表示しない"</string>
<string name="pin_prediction" msgid="4196423321649756498">"アプリの候補を固定"</string>
<string name="bubble" msgid="3072951361014076670">"ふきだし"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"ショートカットのインストール"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"ユーザー操作なしでショートカットを追加することをアプリに許可します。"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"ホームの設定とショートカットの読み取り"</string>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 955d65f..e116476 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"არ შემომთავაზო აპი"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ჩამაგრების პროგნოზირება"</string>
<string name="bubble" msgid="3072951361014076670">"ბუშტი"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"მალსახმობების დაყენება"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"აპისთვის მალსახმობების დამოუკიდებლად დამატების უფლების მიცემა."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"მთავარი ეკრანის პარამეტრებისა და მალსახმობების წაკითხვა"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index c50d007..6de095e 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Қолданба ұсынбау"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Болжамды бекіту"</string>
<string name="bubble" msgid="3072951361014076670">"Қалқыма терезе"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"таңбаша орнату"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Қолданбаға пайдаланушының қатысуынсыз төте пернелерді қосу мүмкіндігін береді."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"негізгі экран параметрлері мен таңбашаларын оқу"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 7a73e69..2a60788 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"កុំណែនាំកម្មវិធី"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ខ្ទាស់ការព្យាករ"</string>
<string name="bubble" msgid="3072951361014076670">"ពពុះ"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"ដំឡើងផ្លូវកាត់"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"អនុញ្ញាតឲ្យកម្មវិធីបន្ថែមផ្លូវកាត់ ដោយមិនចាំបាច់អំពើពីអ្នកប្រើ។"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"អានការកំណត់ និងផ្លូវកាត់របស់អេក្រង់ដើម"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 8c988bf..31b95db 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ಆ್ಯಪ್ ಅನ್ನು ಸೂಚಿಸಬೇಡಿ"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ಮುನ್ನೋಟ ಪಿನ್ ಮಾಡಿ"</string>
<string name="bubble" msgid="3072951361014076670">"ಬಬಲ್"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಸ್ಥಾಪಿಸಿ"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"ಬಳಕೆದಾರರ ಹಸ್ತಕ್ಷೇಪವಿಲ್ಲದೆ ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಸೇರಿಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"ಹೋಮ್ ಸ್ಕ್ರೀನ್ ಸೆಟ್ಟಿಂಗ್ಗಳು ಮತ್ತು ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಓದಿ"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 9f7217b..38cf0db 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"앱 제안 받지 않음"</string>
<string name="pin_prediction" msgid="4196423321649756498">"예상 앱 고정"</string>
<string name="bubble" msgid="3072951361014076670">"풍선"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"바로가기 설치"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"앱이 사용자의 작업 없이 바로가기를 추가할 수 있도록 합니다."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"홈 설정 및 바로가기 읽기"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index b7ce9d7..407c036 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Cунушталбасын"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Божомолдонгон колдонмону кадап коюу"</string>
<string name="bubble" msgid="3072951361014076670">"Көбүкчө"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"тез чакырмаларды орнотуу"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Колдонмого колдонуучуга кайрылбастан тез чакырма кошууга уруксат берет."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"үйдүн параметрлерин жана ыкчам баскычтарын окуу"</string>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 33fff3d..cdb3eab 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ຢ່າແນະນຳແອັບ"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ປັກໝຸດການຄາດເດົາ"</string>
<string name="bubble" msgid="3072951361014076670">"ຟອງ"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"ຕິດຕັ້ງທາງລັດ"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"ອະນຸຍາດໃຫ້ແອັບຯ ເພີ່ມທາງລັດໂດຍບໍ່ຕ້ອງຮັບການຢືນຢັນຈາກຜູ່ໃຊ້."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"ອ່ານການຕັ້ງຄ່າໜ້າຫຼັກ ແລະ ທາງລັດ"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 0d0f5db..78322c6 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Nesiūlyti programos"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Prisegti numatymą"</string>
<string name="bubble" msgid="3072951361014076670">"Debesėlis"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"įdiegti sparčiuosius klavišus"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Programai leidžiama pridėti sparčiuosius klavišus be naudotojo įsikišimo."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"skaityti pagrindinio ekrano nustatymus ir sparčiuosius klavišus"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index c86c6bb..ff3e105 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Neieteikt lietotni"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Piespraust prognozēto lietotni"</string>
<string name="bubble" msgid="3072951361014076670">"Burbulis"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instalēt saīsnes"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Ļauj lietotnei pievienot saīsnes, nejautājot lietotājam."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"sākuma ekrāna iestatījumu un saīšņu lasīšana"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 2685c60..02de271 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -68,10 +68,8 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Работни"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Разговори"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Фаќање белешки"</string>
- <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
- <skip />
- <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
- <skip />
+ <string name="widget_cell_tap_to_show_add_button_label" msgid="4354194214317043581">"Прикажи го копчето за додавање"</string>
+ <string name="widget_cell_tap_to_hide_add_button_label" msgid="6117805205101555997">"Скриј го копчето за додавање"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Додај"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Додај го виџетот <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Прикажи ги сите"</string>
@@ -102,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Не предлагај апл."</string>
<string name="pin_prediction" msgid="4196423321649756498">"Закачи го предвидувањето"</string>
<string name="bubble" msgid="3072951361014076670">"Балонче"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"инсталирање кратенки"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Овозможува апликацијата да додава кратенки без интервенција на корисникот."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"да чита поставки и кратенки на почетна страница"</string>
@@ -203,7 +203,7 @@
<string name="remote_action_failed" msgid="1383965239183576790">"Не успеа: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Приватен простор"</string>
<string name="private_space_secondary_label" msgid="9203933341714508907">"Допрете за да поставите или отворите"</string>
- <string name="ps_container_title" msgid="4391796149519594205">"Приватен простор"</string>
+ <string name="ps_container_title" msgid="4391796149519594205">"Приватен"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Поставки за „Приватен простор“"</string>
<string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Приватно, отклучено."</string>
<string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Приватно, заклучено."</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 2c82585..567559e 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ആപ്പ് നിർദ്ദേശിക്കേണ്ട"</string>
<string name="pin_prediction" msgid="4196423321649756498">"പ്രവചനം പിൻ ചെയ്യുക"</string>
<string name="bubble" msgid="3072951361014076670">"ബബിൾ"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"കുറുക്കുവഴികൾ ഇൻസ്റ്റാളുചെയ്യുക"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"ഉപയോക്തൃ ഇടപെടൽ ഇല്ലാതെ കുറുക്കുവഴികൾ ചേർക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"ഹോം ക്രമീകരണവും കുറുക്കുവഴികളും വായിക്കുക"</string>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 434a731..3ff8a7b 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Апп бүү санал болго"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Таамаглалыг бэхлэх"</string>
<string name="bubble" msgid="3072951361014076670">"Бөмбөлөг"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"товчлол суулгах"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Апп нь хэрэглэгчийн оролцоогүйгээр товчлолыг нэмэж чадна"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"нүүрний тохиргоо болон товчлолыг унших"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index c872cc6..bc29467 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ॲप सुचवू नका"</string>
<string name="pin_prediction" msgid="4196423321649756498">"पूर्वानुमान पिन करा"</string>
<string name="bubble" msgid="3072951361014076670">"बबल"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"शॉर्टकट इंस्टॉल करा"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"वापरकर्ता हस्तक्षेपाशिवाय शॉर्टकट जोडण्यास अॅप ला अनुमती देते."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"होम सेटिंग्ज आणि शॉर्टकट वाचा"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index f5dca93..016d4b1 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Jangan cadangkan apl"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Sematkan Ramalan"</string>
<string name="bubble" msgid="3072951361014076670">"Gelembung"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"pasang pintasan"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Membenarkan apl menambah pintasan tanpa campur tangan pengguna."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"membaca tetapan dan pintasan skrin utama"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 24f4435..e26a4dc 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"အက်ပ်အကြံမပြုပါနှင့်"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ခန့်မှန်းချက်ကို ပင်ထိုးရန်"</string>
<string name="bubble" msgid="3072951361014076670">"ပူဖောင်းကွက်"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"ဖြတ်လမ်းလင့်ခ်များ ထည့်သွင်းခြင်း"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"အသုံးပြုသူ လုပ်ဆောင်မှုမရှိပဲ အပ်ပလီကေးရှင်းကို အတိုကောက်မှတ်သားမှုများ ပြုလုပ်ခွင့် ပေးခြင်း"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"ပင်မဆက်တင်နှင့် ဖြတ်လမ်းလင့်ခ်များ ဖတ်ခြင်း"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index a79740d..069e232 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ikke foreslå app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fest forslaget"</string>
<string name="bubble" msgid="3072951361014076670">"Boble"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"installere snarveier"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Gir apper tillatelse til å legge til snarveier uten innblanding fra brukeren."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"lese startsideinnstillinger og -snarveier"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index f35b943..cfa4740 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"एप सिफारिस नगर्नुहोस्"</string>
<string name="pin_prediction" msgid="4196423321649756498">"सिफारिस गरिएको एप पिन गर्नुहोस्"</string>
<string name="bubble" msgid="3072951361014076670">"बबल"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"सर्टकट स्थापना गर्नेहोस्"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"प्रयोगकर्ताको हस्तक्षेप बिना एउटा एपलाई सर्टकटमा थप्नको लागि अनुमति दिनुहोस्।"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"होम स्क्रिनका सेटिङ र सर्टकटहरू रिड गर्नुहोस्"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 5083976..39120f9 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Geen app voorstellen"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Voorspelling vastzetten"</string>
<string name="bubble" msgid="3072951361014076670">"Bubbel"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"Snelle links instellen"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Een app toestaan snelkoppelingen toe te voegen zonder tussenkomst van de gebruiker."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"instellingen en snelkoppelingen op startscherm lezen"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index a26a7c5..6351de1 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ଆପ ପରାମର୍ଶ ଦିଅନ୍ତୁ ନାହିଁ"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ପୂର୍ବାନୁମାନକୁ ପିନ୍ କରନ୍ତୁ"</string>
<string name="bubble" msgid="3072951361014076670">"ବବଲ"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"ସର୍ଟକଟ୍ ଇନଷ୍ଟଲ୍ କରନ୍ତୁ"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"ୟୁଜରଙ୍କ ବିନା ହସ୍ତକ୍ଷେପରେ ଶର୍ଟକଟ୍ ଯୋଡ଼ିବାକୁ ଆପକୁ ଅନୁମତି ଦିଏ।"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"ହୋମ ସେଟିଂସ ଏବଂ ସର୍ଟକଟଗୁଡ଼ିକୁ ପଢ଼ନ୍ତୁ"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index feda5b5..c7c6319 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ਐਪ ਦਾ ਸੁਝਾਅ ਨਾ ਦਿਓ"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ਪੂਰਵ-ਅਨੁਮਾਨ ਪਿੰਨ ਕਰੋ"</string>
<string name="bubble" msgid="3072951361014076670">"ਬਬਲ"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"ਸ਼ਾਰਟਕੱਟ ਸਥਾਪਤ ਕਰੋ"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"ਇੱਕ ਐਪ ਨੂੰ ਵਰਤੋਂਕਾਰ ਦੇ ਦਖ਼ਲ ਤੋਂ ਬਿਨਾਂ ਸ਼ਾਰਟਕੱਟ ਸ਼ਾਮਲ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"ਹੋਮ ਸੈਟਿੰਗਾਂ ਅਤੇ ਸ਼ਾਰਟਕੱਟ ਪੜ੍ਹੋ"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index bf1299d..b8cc4b8 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Nie proponuj aplikacji"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Przypnij podpowiedź"</string>
<string name="bubble" msgid="3072951361014076670">"Dymek"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"Instalowanie skrótów"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Pozwala aplikacji dodawać skróty bez interwencji użytkownika."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"Odczytuje ustawienia i skróty na ekranie głównym"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 17af437..aa6062d 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Não sugerir app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fixar previsão"</string>
<string name="bubble" msgid="3072951361014076670">"Balão"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar atalhos"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite a uma app adicionar atalhos sem a intervenção do utilizador."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"ler definições e atalhos do ecrã Principal"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 4bc8e7c..2435d8d 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Não sugerir esse app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fixar previsão"</string>
<string name="bubble" msgid="3072951361014076670">"Balão"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar atalhos"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite que um app adicione atalhos sem intervenção do usuário."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"ler configurações e atalhos da tela inicial"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 5763edb..d1fcefa 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Nu sugera aplicația"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fixează predicția"</string>
<string name="bubble" msgid="3072951361014076670">"Balon"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instalează comenzi rapide"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite unei aplicații să adauge comenzi rapide fără intervenția utilizatorului."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"citește setările și comenzile rapide de pe ecranul de pornire"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index d9f0b40..dd59b78 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Не рекомендовать"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Закрепить рекомендацию"</string>
<string name="bubble" msgid="3072951361014076670">"Подсказка"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"Создание ярлыков"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Приложение сможет самостоятельно добавлять ярлыки."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"Доступ к данным о настройках и ярлыках на главном экране"</string>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 756d6fe..d143032 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"යෙදුම යෝජනා නොකරන්න"</string>
<string name="pin_prediction" msgid="4196423321649756498">"පුරෝකථනය අමුණන්න"</string>
<string name="bubble" msgid="3072951361014076670">"බුබුළ"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"කෙටිමං ස්ථාපනය කරන්න"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"පරිශීලක මැදිහත්වීමෙන් තොරව කෙටිමං එක් කිරීමට යෙදුමකට අවසර දෙයි."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"මුල් පිටු සැකසීම් සහ කෙටි මං කියවන්න"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 5fc0c41..c5b84a1 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Nenavrhovať aplikáciu"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pripnúť predpoveď"</string>
<string name="bubble" msgid="3072951361014076670">"Bublina"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"inštalácia odkazov"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Povoľuje aplikácii pridať odkazy bez zásahu používateľa."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"čítanie nastavení a odkazov plochy"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 5ab0106..263a7f6 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlagaj"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Predvidevanje pripenjanja"</string>
<string name="bubble" msgid="3072951361014076670">"Mehurček"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"namestitev bližnjic"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Aplikaciji dovoli dodajanje bližnjic brez posredovanja uporabnika."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"branje nastavitev in bližnjic na začetnem zaslonu"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 995db0f..e8fd7cb 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -68,10 +68,8 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Puna"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Bisedat"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Mbajtja e shënimeve"</string>
- <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
- <skip />
- <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
- <skip />
+ <string name="widget_cell_tap_to_show_add_button_label" msgid="4354194214317043581">"Shfaq butonin e shtimit"</string>
+ <string name="widget_cell_tap_to_hide_add_button_label" msgid="6117805205101555997">"Fshih butonin e shtimit"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Shto"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Shto miniaplikacionin <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Shfaq të gjitha"</string>
@@ -102,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Mos sugjero aplikacion"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Gozhdo parashikimin"</string>
<string name="bubble" msgid="3072951361014076670">"Flluskë"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instalimi i shkurtoreve"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Lejon një aplikacion të shtojë shkurtore pa ndërhyrjen e përdoruesit."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"lexo cilësimet dhe shkurtoret e ekranit bazë"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 2b2fac8..4ef941a 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Не предлажи апликацију"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Закачи предвиђање"</string>
<string name="bubble" msgid="3072951361014076670">"Облачић"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"инсталирање пречица"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Дозвољава апликацији да додаје пречице без интервенције корисника."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"читање подешавања и пречица на почетном екрану"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 74e35ac..26b1a3b 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Föreslå inte app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fäst förslag"</string>
<string name="bubble" msgid="3072951361014076670">"Bubbla"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"installera genvägar"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Tillåter att en app lägger till genvägar utan åtgärd från användaren."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"läsa inställningar och genvägar på startskärmen"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index d696410..0426cc5 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Isipendekeze programu"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Bandika Utabiri"</string>
<string name="bubble" msgid="3072951361014076670">"Kiputo"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"kuweka njia za mkato"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Huruhusu programu kuongeza njia za mkato bila mtumiaji kuingilia kati."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"kusoma mipangilio ya skrini ya kwanza na njia za mkato"</string>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 0b94252..90f5d80 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"பரிந்துரைக்காதே"</string>
<string name="pin_prediction" msgid="4196423321649756498">"கணிக்கப்பட்டதைப் பின் செய்"</string>
<string name="bubble" msgid="3072951361014076670">"குமிழ்"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"குறுக்குவழிகளை நிறுவுதல்"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"பயனரின் அனுமதி இல்லாமல் குறுக்குவழிகளைச் சேர்க்கப் ஆப்ஸை அனுமதிக்கிறது."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"முகப்புத் திரையின் அமைப்புகளையும் ஷார்ட்கட்களையும் படித்தல்"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 90ebe1e..1fc169a 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"యాప్ సూచించకు"</string>
<string name="pin_prediction" msgid="4196423321649756498">"సూచనను పిన్ చేయండి"</string>
<string name="bubble" msgid="3072951361014076670">"బబుల్"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"షార్ట్కట్లను ఇన్స్టాల్ చేయడం"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"వినియోగదారు ప్రమేయం లేకుండా షార్ట్కట్లను జోడించడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"హోమ్ సెట్టింగ్లు, షార్ట్కట్లను చదవండి"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 08944ed..d8484be 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ไม่ต้องแนะนำแอป"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ปักหมุดแอปที่คาดการณ์ไว้"</string>
<string name="bubble" msgid="3072951361014076670">"บับเบิล"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"ติดตั้งทางลัด"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"อนุญาตให้แอปเพิ่มทางลัดโดยไม่ต้องให้ผู้ใช้จัดการ"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"อ่านการตั้งค่าและทางลัดในหน้าแรก"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index b504adc..5596eb5 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Huwag magmungkahi"</string>
<string name="pin_prediction" msgid="4196423321649756498">"I-pin ang Hula"</string>
<string name="bubble" msgid="3072951361014076670">"Bubble"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"i-install ang mga shortcut"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Pinapayagan ang isang app na magdagdag ng mga shortcut nang walang panghihimasok ng user."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"basahin ang mga setting at shortcut ng home"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 094b597..ca96d8e 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Uygulamayı önerme"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Tahmini Sabitle"</string>
<string name="bubble" msgid="3072951361014076670">"Balon"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"kısayolları yükle"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Uygulamaya, kullanıcı müdahalesi olmadan kısayol ekleme izni verir."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"ana ekran ayarlarını ve kısayollarını oku"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index f90998d..9b02400 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Не пропонувати додаток"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Закріпити передбачений додаток"</string>
<string name="bubble" msgid="3072951361014076670">"Повідомлення"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"створення ярликів"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Дозволяє програмі самостійно додавати ярлики."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"читати налаштування та ярлики головного екрана"</string>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 1a90602..a9f7510 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ایپ تجویز نہ کریں"</string>
<string name="pin_prediction" msgid="4196423321649756498">"پیشگوئی پن کریں"</string>
<string name="bubble" msgid="3072951361014076670">"بلبلہ"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"شارٹ کٹس انسٹال کریں"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"کسی ایپ کو صارف کی مداخلت کے بغیر شارٹ کٹس شامل کرنے کی اجازت دیتا ہے۔"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"ہوم ترتیبات اور شارٹ کٹس کو پڑھیں"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 62fede8..3c800ae 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Tavsiya qilinmasin"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Tavsiyani mahkamlash"</string>
<string name="bubble" msgid="3072951361014076670">"Pufaklar"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"yorliqlar yaratish"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Ilovalarga foydalanuvchidan so‘ramasdan yorliqlar qo‘shishga ruxsat beradi."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"Bosh ekrandagi sozlamalar va yorliqlarni koʻrish"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 8e5f75c..2daa1db 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Không gợi ý ứng dụng"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Ghim ứng dụng dự đoán"</string>
<string name="bubble" msgid="3072951361014076670">"Bong bóng"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"cài đặt lối tắt"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Cho phép ứng dụng thêm lối tắt mà không cần sự can thiệp của người dùng."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"đọc lối tắt và các chế độ cài đặt trên màn hình chính"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index edc5646..01426df 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"不要推荐此应用"</string>
<string name="pin_prediction" msgid="4196423321649756498">"固定预测的应用"</string>
<string name="bubble" msgid="3072951361014076670">"气泡框"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"安装快捷方式"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"允许应用自行添加快捷方式。"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"读取主屏幕设置和快捷方式"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 7f4ac59..0e7a44d 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"不要提供應用程式建議"</string>
<string name="pin_prediction" msgid="4196423321649756498">"固定預測"</string>
<string name="bubble" msgid="3072951361014076670">"氣泡"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"安裝捷徑"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"允許應用程式無需使用者許可也可新增捷徑。"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"讀取主畫面設定和捷徑"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index f527a2a..56fb080 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"不要建議此應用程式"</string>
<string name="pin_prediction" msgid="4196423321649756498">"固定預測的應用程式"</string>
<string name="bubble" msgid="3072951361014076670">"泡泡"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"安裝捷徑"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"允許應用程式自動新增捷徑。"</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"讀取主畫面設定和捷徑"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 3c3a75c..9f479b9 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -100,6 +100,8 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ungaphakamisi uhlelo lokusebenza"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Ukubikezela Iphinikhodi"</string>
<string name="bubble" msgid="3072951361014076670">"Ibhamuza"</string>
+ <!-- no translation found for pin_to_taskbar (1281337899690299038) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="5632423390354674437">"faka izinqamuleli"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Ivumela uhlelo lokusebenza ukufaka izinqamuleli ngaphandle kokungenelela komsebenzisi."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"funda amasethingi wasekhaya nezinqamuleli"</string>
diff --git a/res/values/config.xml b/res/values/config.xml
index f6f3c95..a545f0c 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -68,7 +68,6 @@
<string name="app_launch_tracker_class" translatable="false"></string>
<string name="test_information_handler_class" translatable="false"></string>
<string name="model_delegate_class" translatable="false"></string>
- <string name="window_manager_proxy_class" translatable="false"></string>
<string name="secondary_display_predictions_class" translatable="false"></string>
<string name="widget_holder_factory_class" translatable="false"></string>
<string name="taskbar_search_session_controller_class" translatable="false"></string>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index cdfbefe..6f293b6 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -190,6 +190,8 @@
<!-- Label for the header text of the All Apps section in All Apps view, used to separate Predicted Apps and Actions section from All Apps section. [CHAR_LIMIT=50] -->
<string name="all_apps_label">All apps</string>
+ <string name="all_apps_list_label">Apps list</string>
+
<!-- Popup items -->
<!-- Text to display as the header above notifications. [CHAR_LIMIT=30] -->
<string name="notifications_header">Notifications</string>
@@ -212,6 +214,7 @@
<string name="all_apps_button_personal_label">Personal apps list</string>
<string name="all_apps_button_work_label">Work apps list</string>
+ <!-- System shortcuts -->
<!-- Label for remove drop target (from the homescreen only).
May appear next to uninstall_drop_target_label [CHAR_LIMIT=20] -->
<string name="remove_drop_target_label">Remove</string>
@@ -232,6 +235,8 @@
<string name="pin_prediction">Pin Prediction</string>
<!-- Label for bubbling a launcher item. [CHAR_LIMIT=20] -->
<string name="bubble">Bubble</string>
+ <!-- Label for pinning an item to the taskbar. [CHAR_LIMIT=20] -->
+ <string name="pin_to_taskbar">Pin to taskbar</string>
<!-- Permissions: -->
<skip />
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 247ee48..c78666e 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -743,7 +743,7 @@
appTitleBounds = new RectF((tmpRect.width() - titleLength) / 2.f - getCompoundPaddingLeft(),
0, (tmpRect.width() + titleLength) / 2.f + getCompoundPaddingRight(),
(int) Math.ceil(fm.bottom - fm.top));
- appTitleBounds.inset(mRoundRectPadding * 2, 0);
+ appTitleBounds.inset((mAppTitleHorizontalPadding) * 2, 0);
if (mIcon != null) {
@@ -1351,12 +1351,10 @@
mIconLoadRequest.cancel();
mIconLoadRequest = null;
}
- if (getTag() instanceof ItemInfoWithIcon && !mHighResUpdateInProgress) {
- ItemInfoWithIcon info = (ItemInfoWithIcon) getTag();
- if (info.usingLowResIcon()) {
- mIconLoadRequest = LauncherAppState.getInstance(getContext()).getIconCache()
- .updateIconInBackground(BubbleTextView.this, info);
- }
+ if (getTag() instanceof ItemInfoWithIcon info && !mHighResUpdateInProgress
+ && info.getMatchingLookupFlag().useLowRes()) {
+ mIconLoadRequest = LauncherAppState.getInstance(getContext()).getIconCache()
+ .updateIconInBackground(BubbleTextView.this, info);
}
}
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index 425f277..89d54f8 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -22,6 +22,7 @@
import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.View;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
@@ -131,6 +132,10 @@
ItemInfo item = d.dragInfo;
if (canRemove(item)) {
mDropTargetHandler.onDeleteComplete(item);
+ } else if (mText == getResources().getText(R.string.remove_drop_target_label)) {
+ Log.wtf("b/379606516", "If the drop target text is 'remove', then"
+ + " users should always be able to delete the item from launcher's db."
+ + " Invalid drag ItemInfo: " + item);
}
}
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index dddc43f..28293d1 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -57,6 +57,7 @@
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.DeviceGridState;
import com.android.launcher3.provider.RestoreDbTask;
+import com.android.launcher3.settings.SettingsActivity;
import com.android.launcher3.testing.shared.ResourceUtils;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.Info;
@@ -245,10 +246,6 @@
@TargetApi(23)
private InvariantDeviceProfile(Context context) {
String gridName = getCurrentGridName(context);
- FileLog.d(TAG, "New InvariantDeviceProfile, before initGrid(): "
- + "gridName:" + gridName
- + ", LauncherPrefs GRID_NAME:" + LauncherPrefs.get(context).get(GRID_NAME)
- + ", LauncherPrefs DB_FILE:" + LauncherPrefs.get(context).get(DB_FILE));
initGrid(context, gridName);
DisplayController.INSTANCE.get(context).setPriorityListener(
(displayContext, info, flags) -> {
@@ -259,8 +256,12 @@
}
});
if (Flags.oneGridSpecs()) {
- mLandscapeModePreferenceListener = (String s) -> {
- if (isFixedLandscape != FIXED_LANDSCAPE_MODE.get(context)) {
+ mLandscapeModePreferenceListener = (String preference_name) -> {
+ // Here we need both conditions even though they might seem redundant but because
+ // the update happens in the executable there can be race conditions and this avoids
+ // it.
+ if (isFixedLandscape != FIXED_LANDSCAPE_MODE.get(context)
+ && SettingsActivity.FIXED_LANDSCAPE_MODE.equals(preference_name)) {
MAIN_EXECUTOR.execute(() -> {
Trace.beginSection("InvariantDeviceProfile#setFixedLandscape");
onConfigChanged(context.getApplicationContext());
@@ -353,6 +354,11 @@
}
private String initGrid(Context context, String gridName) {
+ FileLog.d(TAG, "Before initGrid:"
+ + "gridName:" + gridName
+ + ", dbFile:" + dbFile
+ + ", LauncherPrefs GRID_NAME:" + LauncherPrefs.get(context).get(GRID_NAME)
+ + ", LauncherPrefs DB_FILE:" + LauncherPrefs.get(context).get(DB_FILE));
Info displayInfo = DisplayController.INSTANCE.get(context).getInfo();
List<DisplayOption> allOptions = getPredefinedDeviceProfiles(
context,
@@ -378,8 +384,9 @@
}
initGrid(context, displayInfo, displayOption);
- FileLog.d(TAG, "initGrid: "
+ FileLog.d(TAG, "After initGrid:"
+ "gridName:" + gridName
+ + ", dbFile:" + dbFile
+ ", LauncherPrefs GRID_NAME:" + LauncherPrefs.get(context).get(GRID_NAME)
+ ", LauncherPrefs DB_FILE:" + LauncherPrefs.get(context).get(DB_FILE));
return displayOption.grid.name;
@@ -397,7 +404,7 @@
*/
@Deprecated
public void reset(Context context) {
- initGrid(context, getDefaultGridName(context));
+ initGrid(context, getCurrentGridName(context));
}
@VisibleForTesting
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 24d854c..94b1a2a 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -58,6 +58,7 @@
import static com.android.launcher3.LauncherConstants.TraceEvents.ON_NEW_INTENT_EVT;
import static com.android.launcher3.LauncherConstants.TraceEvents.ON_RESUME_EVT;
import static com.android.launcher3.LauncherConstants.TraceEvents.ON_START_EVT;
+import static com.android.launcher3.LauncherPrefs.FIXED_LANDSCAPE_MODE;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
import static com.android.launcher3.LauncherState.ALL_APPS;
@@ -785,9 +786,13 @@
return;
}
// When the flag oneGridSpecs is on we want to disable ALLOW_ROTATION which is replaced
- // by FIXED_LANDSCAPE_MODE, ALLOW_ROTATION will only be used on Tablets afterwards.
- if (getDeviceProfile().isPhone || getDeviceProfile().isTwoPanels) {
+ // by FIXED_LANDSCAPE_MODE, ALLOW_ROTATION will only be used on Tablets and foldables
+ // afterwards.
+ if (getDeviceProfile().isPhone) {
LauncherPrefs.get(this).put(LauncherPrefs.ALLOW_ROTATION, false);
+ } else if (getDeviceProfile().isTablet) {
+ // Tablet do not use fixed landscape mode, make sure it can't be activated by mistake
+ LauncherPrefs.get(this).put(FIXED_LANDSCAPE_MODE, false);
}
getRotationHelper().setFixedLandscape(
Objects.requireNonNull(mDeviceProfile.inv).isFixedLandscape
@@ -1677,7 +1682,7 @@
if (FeatureFlags.enableSplitContextually()) {
handleSplitAnimationGoingToHome(LAUNCHER_SPLIT_SELECTION_EXIT_HOME);
}
- mOverlayManager.hideOverlay(isStarted() && !isForceInvisible());
+ mOverlayManager.hideOverlay(isStarted());
handleGestureContract(intent);
} else if (Intent.ACTION_ALL_APPS.equals(intent.getAction())) {
showAllAppsFromIntent(alreadyOnHome);
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index ebcb5da..9060691 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -631,7 +631,7 @@
Drawable mainIcon = null;
Drawable badge = null;
- if ((info instanceof ItemInfoWithIcon iiwi) && !iiwi.usingLowResIcon()) {
+ if ((info instanceof ItemInfoWithIcon iiwi) && !iiwi.getMatchingLookupFlag().useLowRes()) {
badge = iiwi.bitmap.getBadgeDrawable(context, useTheme);
}
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 68a6e62..ba6ed66 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -24,6 +24,7 @@
import androidx.annotation.Nullable;
+import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.ButtonDropTarget;
import com.android.launcher3.CellLayout;
@@ -48,7 +49,6 @@
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.ArrowPopup;
import com.android.launcher3.popup.PopupContainerWithArrow;
-import com.android.launcher3.shortcuts.DeepShortcutTextView;
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.util.IntArray;
@@ -405,6 +405,11 @@
*/
public boolean addToWorkspace(ItemInfo item, boolean accessibility,
@Nullable Consumer<Boolean> finishCallback) {
+ // Dismiss widget resize frame if it is showing. The frame marks its cells as unoccupied
+ // while it is showing, so findSpaceOnWorkspace may try to use those cells.
+ AbstractFloatingView.closeOpenViews(mContext, /* animate= */ false,
+ AbstractFloatingView.TYPE_WIDGET_RESIZE_FRAME);
+
final int[] coordinates = new int[2];
final int screenId = findSpaceOnWorkspace(item, coordinates);
if (screenId == -1) {
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 8554de5..4cc31d2 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -34,6 +34,7 @@
import static com.android.launcher3.util.SystemUiController.UI_STATE_ALL_APPS;
import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.util.FloatProperty;
import android.view.HapticFeedbackConstants;
@@ -365,6 +366,12 @@
Interpolator verticalProgressInterpolator = config.getInterpolator(ANIM_VERTICAL_PROGRESS,
config.isUserControlled() ? LINEAR : DECELERATE_1_7);
Animator anim = createSpringAnimation(mProgress, targetProgress);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ setProgress(targetProgress);
+ }
+ });
anim.setInterpolator(verticalProgressInterpolator);
builder.add(anim);
diff --git a/src/com/android/launcher3/allapps/WorkUtilityView.java b/src/com/android/launcher3/allapps/WorkUtilityView.java
index b263639..bccc279 100644
--- a/src/com/android/launcher3/allapps/WorkUtilityView.java
+++ b/src/com/android/launcher3/allapps/WorkUtilityView.java
@@ -134,7 +134,8 @@
if (shouldUseScheduler()) {
mSchedulerButton.setVisibility(VISIBLE);
mSchedulerButton.setOnClickListener(view ->
- mContext.startActivity(new Intent(mWorkSchedulerIntentAction)));
+ mActivityContext.startActivitySafely(view,
+ new Intent(mWorkSchedulerIntentAction), null /* itemInfo */));
}
}
diff --git a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
index 1e3df1e..340fb02 100644
--- a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
+++ b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
@@ -32,6 +32,7 @@
import com.android.launcher3.util.SettingsCache;
import com.android.launcher3.util.VibratorWrapper;
import com.android.launcher3.util.window.RefreshRateTracker;
+import com.android.launcher3.util.window.WindowManagerProxy;
import com.android.launcher3.widget.custom.CustomWidgetManager;
import dagger.BindsInstance;
@@ -60,6 +61,7 @@
PluginManagerWrapper getPluginManagerWrapper();
VibratorWrapper getVibratorWrapper();
MSDLPlayerWrapper getMSDLPlayerWrapper();
+ WindowManagerProxy getWmProxy();
/** Builder for LauncherBaseAppComponent. */
interface Builder {
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index a826b9e..41b42b6 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -50,6 +50,7 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.ShortcutAndWidgetContainer;
+import com.android.launcher3.ShortcutAndWidgetContainer.TranslationProvider;
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
import com.android.launcher3.anim.PendingAnimation;
@@ -248,23 +249,27 @@
public void animateViewIntoPosition(DragView dragView, final View child, int duration,
View anchorView) {
- ShortcutAndWidgetContainer parentChildren = (ShortcutAndWidgetContainer) child.getParent();
+ ShortcutAndWidgetContainer childParent = (ShortcutAndWidgetContainer) child.getParent();
CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams();
- parentChildren.measureChild(child);
- parentChildren.layoutChild(child);
+ childParent.measureChild(child);
+ childParent.layoutChild(child);
float coord[] = new float[2];
float childScale = child.getScaleX();
coord[0] = lp.x + (child.getMeasuredWidth() * (1 - childScale) / 2);
coord[1] = lp.y + (child.getMeasuredHeight() * (1 - childScale) / 2);
+ TranslationProvider translationProvider = childParent.getTranslationProvider();
+ if (translationProvider != null) {
+ coord[0] = coord[0] + translationProvider.getTranslationX(lp.getCellX());
+ }
// Since the child hasn't necessarily been laid out, we force the lp to be updated with
// the correct coordinates (above) and use these to determine the final location
float scale = getDescendantCoordRelativeToSelf((View) child.getParent(), coord);
// We need to account for the scale of the child itself, as the above only accounts for
- // for the scale in parents.
+ // the scale in parents.
scale *= childScale;
int toX = Math.round(coord[0]);
int toY = Math.round(coord[1]);
diff --git a/src/com/android/launcher3/dragndrop/SpringLoadedDragController.kt b/src/com/android/launcher3/dragndrop/SpringLoadedDragController.kt
index 2aeab9d..4cbe7bb 100644
--- a/src/com/android/launcher3/dragndrop/SpringLoadedDragController.kt
+++ b/src/com/android/launcher3/dragndrop/SpringLoadedDragController.kt
@@ -47,7 +47,11 @@
override fun onAlarm(alarm: Alarm) {
if (screen != null) {
// Snap to the screen that we are hovering over now
- with(launcher.workspace) { if (!isVisible(screen)) snapToPage(indexOfChild(screen)) }
+ with(launcher.workspace) {
+ if (!isVisible(screen) && launcher.dragController.mDistanceSinceScroll != 0) {
+ snapToPage(indexOfChild(screen))
+ }
+ }
} else {
launcher.dragController.cancelDrag()
}
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index e7c4024..ab4105c 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -17,6 +17,7 @@
package com.android.launcher3.icons;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
+import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.launcher3.widget.WidgetSections.NO_CATEGORY;
@@ -51,6 +52,7 @@
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Utilities;
import com.android.launcher3.icons.cache.BaseIconCache;
+import com.android.launcher3.icons.cache.CacheLookupFlag;
import com.android.launcher3.icons.cache.CachedObject;
import com.android.launcher3.icons.cache.CachedObjectCachingLogic;
import com.android.launcher3.icons.cache.LauncherActivityCachingLogic;
@@ -163,12 +165,12 @@
Supplier<ItemInfoWithIcon> task;
if (info instanceof AppInfo || info instanceof WorkspaceItemInfo) {
task = () -> {
- getTitleAndIcon(info, false);
+ getTitleAndIcon(info, DEFAULT_LOOKUP_FLAG);
return info;
};
} else if (info instanceof PackageItemInfo pii) {
task = () -> {
- getTitleAndIconForApp(pii, false);
+ getTitleAndIconForApp(pii, DEFAULT_LOOKUP_FLAG);
return pii;
};
} else {
@@ -207,7 +209,7 @@
public synchronized void updateTitleAndIcon(AppInfo application) {
CacheEntry entry = cacheLocked(application.componentName,
application.user, () -> null, LauncherActivityCachingLogic.INSTANCE,
- application.usingLowResIcon() ? LookupFlag.USE_LOW_RES : LookupFlag.DEFAULT);
+ application.getMatchingLookupFlag());
if (entry.bitmap != null || !isDefaultIcon(entry.bitmap, application.user)) {
applyCacheEntry(entry, application);
}
@@ -218,11 +220,11 @@
*/
@SuppressWarnings("NewApi")
public synchronized void getTitleAndIcon(ItemInfoWithIcon info,
- LauncherActivityInfo activityInfo, boolean useLowResIcon) {
+ LauncherActivityInfo activityInfo, @NonNull CacheLookupFlag lookupFlag) {
boolean isAppArchived = Flags.enableSupportForArchiving() && activityInfo != null
&& activityInfo.getActivityInfo().isArchived;
// If we already have activity info, no need to use package icon
- getTitleAndIcon(info, () -> activityInfo, isAppArchived, useLowResIcon);
+ getTitleAndIcon(info, () -> activityInfo, lookupFlag.withUsePackageIcon(isAppArchived));
}
/**
@@ -252,7 +254,7 @@
user,
() -> si,
CacheableShortcutCachingLogic.INSTANCE,
- LookupFlag.SKIP_ADD_TO_MEM_CACHE).bitmap;
+ DEFAULT_LOOKUP_FLAG.withSkipAddToMemCache()).bitmap;
if (bitmapInfo.isNullOrLowRes()) {
bitmapInfo = getDefaultIcon(user);
}
@@ -291,12 +293,12 @@
appInfo.intent = new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_LAUNCHER)
.setComponent(cn);
- getTitleAndIcon(appInfo, false);
+ getTitleAndIcon(appInfo, DEFAULT_LOOKUP_FLAG);
return appInfo;
}
}
PackageItemInfo pkgInfo = new PackageItemInfo(pkg, shortcutInfo.getUserHandle());
- getTitleAndIconForApp(pkgInfo, false);
+ getTitleAndIconForApp(pkgInfo, DEFAULT_LOOKUP_FLAG);
return pkgInfo;
}
@@ -304,7 +306,9 @@
* Fill in {@param info} with the icon and label. If the
* corresponding activity is not found, it reverts to the package icon.
*/
- public synchronized void getTitleAndIcon(ItemInfoWithIcon info, boolean useLowResIcon) {
+ public synchronized void getTitleAndIcon(
+ @NonNull ItemInfoWithIcon info,
+ @NonNull CacheLookupFlag lookupFlag) {
// null info means not installed, but if we have a component from the intent then
// we should still look in the cache for restored app icons.
if (info.getTargetComponent() == null) {
@@ -314,7 +318,7 @@
} else {
Intent intent = info.getIntent();
getTitleAndIcon(info, () -> mLauncherApps.resolveActivity(intent, info.user),
- true, useLowResIcon);
+ lookupFlag.withUsePackageIcon());
}
}
@@ -324,7 +328,7 @@
public synchronized String getTitleNoCache(CachedObject info) {
CacheEntry entry = cacheLocked(info.getComponent(), info.getUser(), () -> info,
CachedObjectCachingLogic.INSTANCE,
- LookupFlag.USE_LOW_RES | LookupFlag.SKIP_ADD_TO_MEM_CACHE);
+ DEFAULT_LOOKUP_FLAG.withUseLowRes().withSkipAddToMemCache());
return Utilities.trim(entry.title);
}
@@ -334,12 +338,9 @@
public synchronized void getTitleAndIcon(
@NonNull ItemInfoWithIcon infoInOut,
@NonNull Supplier<LauncherActivityInfo> activityInfoProvider,
- boolean usePkgIcon, boolean useLowResIcon) {
- int lookupFlags = LookupFlag.DEFAULT;
- if (usePkgIcon) lookupFlags |= LookupFlag.USE_PACKAGE_ICON;
- if (useLowResIcon) lookupFlags |= LookupFlag.USE_LOW_RES;
+ @NonNull CacheLookupFlag lookupFlag) {
CacheEntry entry = cacheLocked(infoInOut.getTargetComponent(), infoInOut.user,
- activityInfoProvider, LauncherActivityCachingLogic.INSTANCE, lookupFlags);
+ activityInfoProvider, LauncherActivityCachingLogic.INSTANCE, lookupFlag);
applyCacheEntry(entry, infoInOut);
}
@@ -441,7 +442,7 @@
/* user = */ sectionKey.first,
() -> duplicateIconRequests.get(0).launcherActivityInfo,
LauncherActivityCachingLogic.INSTANCE,
- sectionKey.second ? LookupFlag.USE_LOW_RES : LookupFlag.DEFAULT,
+ DEFAULT_LOOKUP_FLAG.withUseLowRes(sectionKey.second),
c);
for (IconRequestInfo<T> iconRequest : duplicateIconRequests) {
@@ -515,9 +516,10 @@
* Fill in {@param infoInOut} with the corresponding icon and label.
*/
public synchronized void getTitleAndIconForApp(
- @NonNull final PackageItemInfo infoInOut, final boolean useLowResIcon) {
+ @NonNull final PackageItemInfo infoInOut,
+ @NonNull CacheLookupFlag lookupFlag) {
CacheEntry entry = getEntryForPackageLocked(
- infoInOut.packageName, infoInOut.user, useLowResIcon);
+ infoInOut.packageName, infoInOut.user, lookupFlag.useLowRes());
applyCacheEntry(entry, infoInOut);
if (infoInOut.widgetCategory == NO_CATEGORY) {
return;
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index 55bcb70..b936adf 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -194,8 +194,7 @@
WorkspaceItemInfo wii = (WorkspaceItemInfo) itemInfo;
wii.title = "";
wii.bitmap = cache.getDefaultIcon(item.user);
- cache.getTitleAndIcon(wii,
- ((WorkspaceItemInfo) itemInfo).usingLowResIcon());
+ cache.getTitleAndIcon(wii, wii.getMatchingLookupFlag());
}
}
diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java
index 7bc9273..98f9afd 100644
--- a/src/com/android/launcher3/model/AllAppsList.java
+++ b/src/com/android/launcher3/model/AllAppsList.java
@@ -16,6 +16,7 @@
package com.android.launcher3.model;
+import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
import static com.android.launcher3.model.data.AppInfo.COMPONENT_KEY_COMPARATOR;
import static com.android.launcher3.model.data.AppInfo.EMPTY_ARRAY;
@@ -151,7 +152,7 @@
return;
}
if (loadIcon) {
- mIconCache.getTitleAndIcon(info, activityInfo, false /* useLowResIcon */);
+ mIconCache.getTitleAndIcon(info, activityInfo, DEFAULT_LOOKUP_FLAG);
info.sectionName = mIndex.computeSectionName(info.title);
} else {
info.title = "";
@@ -177,7 +178,7 @@
AppInfo promiseAppInfo = new AppInfo(installInfo);
if (loadIcon) {
- mIconCache.getTitleAndIcon(promiseAppInfo, promiseAppInfo.usingLowResIcon());
+ mIconCache.getTitleAndIcon(promiseAppInfo, promiseAppInfo.getMatchingLookupFlag());
promiseAppInfo.sectionName = mIndex.computeSectionName(promiseAppInfo.title);
} else {
promiseAppInfo.title = "";
@@ -338,7 +339,7 @@
} else {
Intent launchIntent = AppInfo.makeLaunchIntent(info);
- mIconCache.getTitleAndIcon(applicationInfo, info, false /* useLowResIcon */);
+ mIconCache.getTitleAndIcon(applicationInfo, info, DEFAULT_LOOKUP_FLAG);
applicationInfo.sectionName = mIndex.computeSectionName(applicationInfo.title);
applicationInfo.intent = launchIntent;
AppInfo.updateRuntimeFlagsForActivityTarget(applicationInfo, info,
diff --git a/src/com/android/launcher3/model/CacheDataUpdatedTask.java b/src/com/android/launcher3/model/CacheDataUpdatedTask.java
index 66b4fd9..b544b91 100644
--- a/src/com/android/launcher3/model/CacheDataUpdatedTask.java
+++ b/src/com/android/launcher3/model/CacheDataUpdatedTask.java
@@ -63,7 +63,7 @@
if (si.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
&& isValidShortcut(si) && cn != null
&& mPackages.contains(cn.getPackageName())) {
- iconCache.getTitleAndIcon(si, si.usingLowResIcon());
+ iconCache.getTitleAndIcon(si, si.getMatchingLookupFlag());
updatedShortcuts.add(si);
}
});
diff --git a/src/com/android/launcher3/model/GridSizeMigrationLogic.kt b/src/com/android/launcher3/model/GridSizeMigrationLogic.kt
index 75fd31e..6f86ae0 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationLogic.kt
+++ b/src/com/android/launcher3/model/GridSizeMigrationLogic.kt
@@ -30,6 +30,7 @@
import com.android.launcher3.LauncherSettings.Favorites.TMP_TABLE
import com.android.launcher3.Utilities
import com.android.launcher3.config.FeatureFlags
+import com.android.launcher3.logging.FileLog
import com.android.launcher3.model.GridSizeMigrationDBController.DbReader
import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction
import com.android.launcher3.provider.LauncherDbUtils.copyTable
@@ -57,10 +58,10 @@
return
}
- val isFirstLoad = get(context).get(LauncherPrefs.IS_FIRST_LOAD_AFTER_RESTORE)
- Log.d(
+ val isAfterRestore = get(context).get(LauncherPrefs.IS_FIRST_LOAD_AFTER_RESTORE)
+ FileLog.d(
TAG,
- "Begin grid migration. First load: $isFirstLoad\n srcDeviceState: " +
+ "Begin grid migration. isAfterRestore: $isAfterRestore\nsrcDeviceState: " +
"$srcDeviceState\ndestDeviceState: $destDeviceState\nisDestNewDb: $isDestNewDb",
)
@@ -112,7 +113,7 @@
t.commit()
}
} catch (e: Exception) {
- Log.e(TAG, "Error during grid migration", e)
+ FileLog.e(TAG, "Error during grid migration", e)
} finally {
Log.v(
TAG,
diff --git a/src/com/android/launcher3/model/ItemInstallQueue.java b/src/com/android/launcher3/model/ItemInstallQueue.java
index f9c6e96..c4f222f 100644
--- a/src/com/android/launcher3/model/ItemInstallQueue.java
+++ b/src/com/android/launcher3/model/ItemInstallQueue.java
@@ -21,6 +21,7 @@
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
+import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
import static com.android.launcher3.model.data.AppInfo.makeLaunchIntent;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_ARCHIVED;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -308,7 +309,8 @@
}
}
LauncherAppState.getInstance(context).getIconCache()
- .getTitleAndIcon(si, () -> lai, usePackageIcon, false);
+ .getTitleAndIcon(si, () -> lai,
+ DEFAULT_LOOKUP_FLAG.withUsePackageIcon(usePackageIcon));
return Pair.create(si, null);
}
case ITEM_TYPE_DEEP_SHORTCUT: {
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index c01b1b6..536d4c9 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
import static com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET;
+import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
import android.content.ComponentName;
import android.content.ContentValues;
@@ -300,7 +301,7 @@
// the fallback icon
if (!loadIcon(info)) {
- mIconCache.getTitleAndIcon(info, false /* useLowResIcon */);
+ mIconCache.getTitleAndIcon(info, DEFAULT_LOOKUP_FLAG);
}
if (hasRestoreFlag(WorkspaceItemInfo.FLAG_RESTORED_ICON)) {
@@ -364,7 +365,8 @@
UserIconInfo userIconInfo = userCache.getUserInfo(user);
if (loadIcon) {
- mIconCache.getTitleAndIcon(info, mActivityInfo, useLowResIcon);
+ mIconCache.getTitleAndIcon(info, mActivityInfo,
+ DEFAULT_LOOKUP_FLAG.withUseLowRes(useLowResIcon));
if (mIconCache.isDefaultIcon(info.bitmap, user)) {
loadIcon(info);
}
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index f96e959..bc0d776 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -25,6 +25,7 @@
import static com.android.launcher3.LauncherPrefs.SHOULD_SHOW_SMARTSPACE;
import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
import static com.android.launcher3.icons.CacheableShortcutInfo.convertShortcutsToCacheableShortcuts;
+import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_CHANGE_PERMISSION;
@@ -213,13 +214,13 @@
ArrayList<ItemInfo> firstScreenItems = new ArrayList<>();
filterCurrentWorkspaceItems(firstScreens, allItems, firstScreenItems,
new ArrayList<>() /* otherScreenItems are ignored */);
- final int launcherBroadcastInstalledApps = Settings.Secure.getInt(
+ final int disableArchivingLauncherBroadcast = Settings.Secure.getInt(
mApp.getContext().getContentResolver(),
- "launcher_broadcast_installed_apps",
- /* def= */ 0);
+ "disable_launcher_broadcast_installed_apps",
+ /* default */ 0);
boolean shouldAttachArchivingExtras = mIsRestoreFromBackup
- && (launcherBroadcastInstalledApps == 1
- || Flags.enableFirstScreenBroadcastArchivingExtras());
+ && disableArchivingLauncherBroadcast == 0
+ && Flags.enableFirstScreenBroadcastArchivingExtras();
if (shouldAttachArchivingExtras) {
List<FirstScreenBroadcastModel> broadcastModels =
FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
@@ -231,6 +232,7 @@
logASplit("Sending first screen broadcast with additional archiving Extras");
FirstScreenBroadcastHelper.sendBroadcastsForModels(mApp.getContext(), broadcastModels);
} else {
+ logASplit("Sending first screen broadcast");
mFirstScreenBroadcast.sendBroadcasts(mApp.getContext(), firstScreenItems);
}
}
@@ -261,6 +263,9 @@
// sanitizeData should not be invoked if the workspace is loaded from a db different
// from the main db as defined in the invariant device profile.
// (e.g. both grid preview and minimal device mode uses a different db)
+ // TODO(b/384731096): Write Unit Test to make sure sanitizeWidgetsShortcutsAndPackages
+ // actually re-pins shortcuts that are in model but not in ShortcutManager, if possible
+ // after a simulated restore.
if (Objects.equals(mApp.getInvariantDeviceProfile().dbFile, mDbName)) {
verifyNotStopped();
sanitizeFolders(mItemsDeleted);
@@ -276,7 +281,6 @@
mModelDelegate.workspaceLoadComplete();
// Notify the installer packages of packages with active installs on the first screen.
sendFirstScreenActiveInstallsBroadcast();
- logASplit("sendFirstScreenBroadcast finished");
// Take a break
waitForIdle();
@@ -389,7 +393,7 @@
}
} catch (CancellationException e) {
// Loader stopped, ignore
- FileLog.w(TAG, "LoaderTask cancelled:", e);
+ FileLog.w(TAG, "LoaderTask cancelled");
} catch (Exception e) {
memoryLogger.printLogs();
throw e;
@@ -398,7 +402,7 @@
}
public synchronized void stopLocked() {
- FileLog.w(TAG, "LoaderTask#stopLocked:", new Exception());
+ FileLog.w(TAG, "stopLocked: Loader stopping");
mStopped = true;
this.notify();
}
@@ -599,10 +603,10 @@
info.rank = rank;
if (info instanceof WorkspaceItemInfo wii
- && wii.usingLowResIcon()
+ && wii.getMatchingLookupFlag().useLowRes()
&& wii.itemType == Favorites.ITEM_TYPE_APPLICATION
&& verifiers.stream().anyMatch(it -> it.isItemInPreview(info.rank))) {
- mIconCache.getTitleAndIcon(wii, false);
+ mIconCache.getTitleAndIcon(wii, DEFAULT_LOOKUP_FLAG);
} else if (info instanceof AppPairInfo api) {
api.fetchHiResIconsIfNeeded(mIconCache);
}
@@ -765,7 +769,7 @@
iconRequestInfos.add(new IconRequestInfo<>(
promiseAppInfo,
/* launcherActivityInfo= */ null,
- promiseAppInfo.usingLowResIcon()));
+ promiseAppInfo.getMatchingLookupFlag().useLowRes()));
}
}
}
diff --git a/src/com/android/launcher3/model/ModelDbController.java b/src/com/android/launcher3/model/ModelDbController.java
index 6ff8547..e76391f 100644
--- a/src/com/android/launcher3/model/ModelDbController.java
+++ b/src/com/android/launcher3/model/ModelDbController.java
@@ -96,7 +96,7 @@
* around it.
*/
public class ModelDbController {
- private static final String TAG = "LauncherProvider";
+ private static final String TAG = "ModelDbController";
private static final String EMPTY_DATABASE_CREATED = "EMPTY_DATABASE_CREATED";
public static final String EXTRA_DB_NAME = "db_name";
@@ -303,7 +303,7 @@
if (restoreEventLogger != null) {
sendMetricsForFailedMigration(restoreEventLogger, getDb());
}
- FileLog.d(TAG, "Migration failed: resetting launcher database");
+ FileLog.d(TAG, "resetLauncherDb: Migration failed: resetting launcher database");
createEmptyDB();
LauncherPrefs.get(mContext).putSync(
getEmptyDbCreatedKey(mOpenHelper.getDatabaseName()).to(true));
@@ -331,7 +331,7 @@
private boolean isThereExistingDb() {
if (LauncherPrefs.get(mContext).get(getEmptyDbCreatedKey())) {
// If we already have a new DB, ignore migration
- FileLog.d(TAG, "migrateGridIfNeeded: new DB already created, skipping migration");
+ FileLog.d(TAG, "isThereExistingDb: new DB already created, skipping migration");
return true;
}
return false;
@@ -342,7 +342,7 @@
if (GridSizeMigrationDBController.needsToMigrate(mContext, idp)) {
return true;
}
- FileLog.d(TAG, "migrateGridIfNeeded: no grid migration needed");
+ FileLog.d(TAG, "isGridMigrationNecessary: no grid migration needed");
return false;
}
@@ -350,7 +350,9 @@
InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext);
String targetDbName = new DeviceGridState(idp).getDbFile();
if (TextUtils.equals(targetDbName, mOpenHelper.getDatabaseName())) {
- FileLog.e(TAG, "migrateGridIfNeeded: target db is same as current: " + targetDbName);
+ FileLog.e(TAG, "isCurrentDbSameAsTarget: target db is same as current"
+ + " current db: " + mOpenHelper.getDatabaseName()
+ + " target db: " + targetDbName);
return true;
}
return false;
@@ -385,13 +387,12 @@
DeviceGridState destDeviceState = new DeviceGridState(idp);
boolean isDestNewDb = !existingDBs.contains(destDeviceState.getDbFile());
-
GridSizeMigrationLogic gridSizeMigrationLogic = new GridSizeMigrationLogic();
gridSizeMigrationLogic.migrateGrid(mContext, srcDeviceState, destDeviceState,
mOpenHelper, oldHelper.getWritableDatabase(), isDestNewDb);
} catch (Exception e) {
resetLauncherDb(restoreEventLogger);
- throw new Exception("Failed to migrate grid", e);
+ throw new Exception("attemptMigrateDb: Failed to migrate grid", e);
} finally {
if (mOpenHelper != oldHelper) {
oldHelper.close();
@@ -415,7 +416,7 @@
sendMetricsForFailedMigration(restoreEventLogger, getDb());
}
}
- FileLog.d(TAG, "Migration failed: resetting launcher database");
+ FileLog.d(TAG, "tryMigrateDB: Migration failed: resetting launcher database");
createEmptyDB();
LauncherPrefs.get(mContext).putSync(
getEmptyDbCreatedKey(mOpenHelper.getDatabaseName()).to(true));
@@ -447,17 +448,17 @@
}
String targetDbName = new DeviceGridState(idp).getDbFile();
if (TextUtils.equals(targetDbName, mOpenHelper.getDatabaseName())) {
- FileLog.e(TAG, "migrateGridIfNeeded: target db is same as current: " + targetDbName);
+ FileLog.e(TAG, "migrateGridIfNeeded: target db is same as current"
+ + " current db: " + mOpenHelper.getDatabaseName()
+ + " target db: " + targetDbName);
return false;
}
DatabaseHelper oldHelper = mOpenHelper;
-
// We save the existing db's before creating the destination db helper so we know what logic
// to run in grid migration based on if that grid already existed before migration or not.
List<String> existingDBs = LauncherFiles.GRID_DB_FILES.stream()
.filter(dbName -> mContext.getDatabasePath(dbName).exists())
.toList();
-
mOpenHelper = (mContext instanceof SandboxContext) ? oldHelper
: createDatabaseHelper(true /* forMigration */, targetDbName);
try {
@@ -465,13 +466,11 @@
DeviceGridState srcDeviceState = new DeviceGridState(mContext);
// This is the state we want to migrate to that is given by the idp
DeviceGridState destDeviceState = new DeviceGridState(idp);
-
boolean isDestNewDb = !existingDBs.contains(destDeviceState.getDbFile());
-
return GridSizeMigrationDBController.migrateGridIfNeeded(mContext, srcDeviceState,
destDeviceState, mOpenHelper, oldHelper.getWritableDatabase(), isDestNewDb);
} catch (Exception e) {
- FileLog.e(TAG, "Failed to migrate grid", e);
+ FileLog.e(TAG, "migrateGridIfNeeded: Failed to migrate grid", e);
return false;
} finally {
if (mOpenHelper != oldHelper) {
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 5464afe..d619965 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -326,7 +326,8 @@
itemInfo.setNonResizeable(ApiWrapper.INSTANCE.get(context)
.isNonResizeableActivity(activities.get(0)));
}
- iconCache.getTitleAndIcon(itemInfo, itemInfo.usingLowResIcon());
+ iconCache.getTitleAndIcon(
+ itemInfo, itemInfo.getMatchingLookupFlag());
infoUpdated = true;
}
}
diff --git a/src/com/android/launcher3/model/SessionFailureTask.kt b/src/com/android/launcher3/model/SessionFailureTask.kt
index 0d006fa..8baf568 100644
--- a/src/com/android/launcher3/model/SessionFailureTask.kt
+++ b/src/com/android/launcher3/model/SessionFailureTask.kt
@@ -48,7 +48,7 @@
for (info in dataModel.itemsIdMap) {
if (info is WorkspaceItemInfo && info.isArchived && user == info.user) {
// Refresh icons on the workspace for archived apps.
- iconCache.getTitleAndIcon(info, info.usingLowResIcon())
+ iconCache.getTitleAndIcon(info, info.matchingLookupFlag)
updatedItems.add(info)
}
}
diff --git a/src/com/android/launcher3/model/WidgetsModel.java b/src/com/android/launcher3/model/WidgetsModel.java
index a27d2f1..a176465 100644
--- a/src/com/android/launcher3/model/WidgetsModel.java
+++ b/src/com/android/launcher3/model/WidgetsModel.java
@@ -4,6 +4,7 @@
import static android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_HIDE_FROM_PICKER;
import static com.android.launcher3.BuildConfig.WIDGETS_ENABLED;
+import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
import static com.android.launcher3.pm.ShortcutConfigActivityInfo.queryList;
import static com.android.launcher3.widget.WidgetSections.NO_CATEGORY;
@@ -203,7 +204,7 @@
// Update each package entry
IconCache iconCache = app.getIconCache();
for (PackageItemInfo p : packageItemInfoCache.values()) {
- iconCache.getTitleAndIconForApp(p, true /* userLowResIcon */);
+ iconCache.getTitleAndIconForApp(p, DEFAULT_LOOKUP_FLAG.withUseLowRes());
}
}
diff --git a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
index e86b592..0272bd9 100644
--- a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
+++ b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
@@ -20,6 +20,7 @@
import android.content.ComponentName
import android.content.Intent
import android.content.pm.LauncherApps
+import android.content.pm.LauncherApps.ShortcutQuery
import android.content.pm.PackageInstaller
import android.content.pm.ShortcutInfo
import android.graphics.Point
@@ -33,6 +34,7 @@
import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError
import com.android.launcher3.config.FeatureFlags
import com.android.launcher3.icons.CacheableShortcutInfo
+import com.android.launcher3.icons.cache.CacheLookupFlag.Companion.DEFAULT_LOOKUP_FLAG
import com.android.launcher3.logging.FileLog
import com.android.launcher3.model.data.AppInfo
import com.android.launcher3.model.data.AppPairInfo
@@ -44,6 +46,7 @@
import com.android.launcher3.pm.PackageInstallInfo
import com.android.launcher3.pm.UserCache
import com.android.launcher3.shortcuts.ShortcutKey
+import com.android.launcher3.shortcuts.ShortcutRequest
import com.android.launcher3.util.ApiWrapper
import com.android.launcher3.util.ApplicationInfoWrapper
import com.android.launcher3.util.ComponentKey
@@ -270,7 +273,8 @@
c.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT -> {
val key = ShortcutKey.fromIntent(intent, c.user)
if (unlockedUsers[c.serialNumber]) {
- val pinnedShortcut = shortcutKeyToPinnedShortcuts[key]
+ val pinnedShortcut =
+ shortcutKeyToPinnedShortcuts[key] ?: retryDeepShortcutById(key)
if (pinnedShortcut == null) {
// The shortcut is no longer valid.
c.markDeleted(
@@ -376,6 +380,25 @@
}
/**
+ * It is possible that the data was cleared from ShortcutManager after it was restored. In that
+ * instance, the Launcher would have a valid Shortcut id, but ShortcutManager wouldn't recognize
+ * it as valid. Here we retry by querying ShortcutManager by package name and shortcut id.
+ */
+ private fun retryDeepShortcutById(key: ShortcutKey): ShortcutInfo? {
+ FileLog.d(TAG, "retryDeepShortcutById: package=${key.packageName}, shortcutId=${key.id}")
+ return launcherApps
+ .getShortcuts(
+ ShortcutQuery().apply {
+ setPackage(key.packageName)
+ setShortcutIds(listOf(key.id))
+ setQueryFlags(ShortcutRequest.ALL)
+ },
+ key.user,
+ )
+ ?.firstOrNull()
+ }
+
+ /**
* Loads CollectionInfo information from the database and formats it. This function runs while
* LoaderTask is still active; some of the processing for folder content items is done after all
* the items in the workspace have been loaded. The loaded and formatted CollectionInfo is then
@@ -521,7 +544,7 @@
appWidgetInfo.providerName,
appWidgetInfo.user,
)
- iconCache.getTitleAndIconForApp(appWidgetInfo.pendingItemInfo, false)
+ iconCache.getTitleAndIconForApp(appWidgetInfo.pendingItemInfo, DEFAULT_LOOKUP_FLAG)
}
WidgetInflater.TYPE_REAL ->
WidgetSizes.updateWidgetSizeRangesAsync(
diff --git a/src/com/android/launcher3/model/data/AppPairInfo.kt b/src/com/android/launcher3/model/data/AppPairInfo.kt
index 82eda36..073d0e0 100644
--- a/src/com/android/launcher3/model/data/AppPairInfo.kt
+++ b/src/com/android/launcher3/model/data/AppPairInfo.kt
@@ -20,6 +20,7 @@
import com.android.launcher3.LauncherSettings
import com.android.launcher3.R
import com.android.launcher3.icons.IconCache
+import com.android.launcher3.icons.cache.CacheLookupFlag.Companion.DEFAULT_LOOKUP_FLAG
import com.android.launcher3.logger.LauncherAtom
import com.android.launcher3.views.ActivityContext
@@ -72,16 +73,17 @@
val isTablet =
(ActivityContext.lookupContext(context) as ActivityContext).getDeviceProfile().isTablet
return Pair(
- isTablet || !getFirstApp().isNonResizeable(),
- isTablet || !getSecondApp().isNonResizeable(),
+ isTablet || !getFirstApp().isNonResizeable,
+ isTablet || !getSecondApp().isNonResizeable,
)
}
/** Fetches high-res icons for member apps if needed. */
fun fetchHiResIconsIfNeeded(iconCache: IconCache) {
- getAppContents().stream().filter(ItemInfoWithIcon::usingLowResIcon).forEach { member ->
- iconCache.getTitleAndIcon(member, false)
- }
+ getAppContents()
+ .stream()
+ .filter { it.matchingLookupFlag.useLowRes() }
+ .forEach { member -> iconCache.getTitleAndIcon(member, DEFAULT_LOOKUP_FLAG) }
}
/**
diff --git a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
index 6ac44ff..772ea7f 100644
--- a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
+++ b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
@@ -23,10 +23,10 @@
import androidx.annotation.Nullable;
import com.android.launcher3.Flags;
-import com.android.launcher3.Utilities;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.BitmapInfo.DrawableCreationFlags;
import com.android.launcher3.icons.FastBitmapDrawable;
+import com.android.launcher3.icons.cache.CacheLookupFlag;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.pm.PackageInstallInfo;
import com.android.launcher3.util.ApiWrapper;
@@ -185,10 +185,10 @@
}
/**
- * Indicates whether we're using a low res icon
+ * Returns the lookup flag to match this current state of this info
*/
- public boolean usingLowResIcon() {
- return bitmap.isLowRes();
+ public CacheLookupFlag getMatchingLookupFlag() {
+ return bitmap.getMatchingLookupFlag();
}
/**
diff --git a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
index 9af61f0..0a5dd62 100644
--- a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
+++ b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
@@ -142,7 +142,7 @@
.put(Favorites.OPTIONS, options)
.put(Favorites.RESTORED, status);
- if (!usingLowResIcon()) {
+ if (!getMatchingLookupFlag().useLowRes()) {
writer.putIcon(bitmap, user);
}
}
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index 63c9d94..329d9df 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -210,6 +210,30 @@
}
}
+ public static final Factory<ActivityContext> PIN_UNPIN_ITEM =
+ (context, itemInfo, originalView) -> {
+ // Predicted items use {@code HotseatPredictionController.PinPrediction} shortcut
+ // to pin.
+ if (itemInfo.isPredictedItem()) {
+ return null;
+ }
+ return new PinUnpinItem<>(context, itemInfo, originalView);
+ };
+
+ private static class PinUnpinItem<T extends ActivityContext> extends SystemShortcut<T> {
+ PinUnpinItem(T target, ItemInfo itemInfo, @NonNull View originalView) {
+ // TODO(b/375648361): Check the pin state of the item to determine if the pin or the
+ // unpin option should be used.
+ super(R.drawable.ic_pin, R.string.pin_to_taskbar, target,
+ itemInfo, originalView);
+ }
+
+ @Override
+ public void onClick(View view) {
+ // TODO(b/375648361): Pin/Unpin the item here.
+ }
+ }
+
public static final Factory<ActivityContext> PRIVATE_PROFILE_INSTALL =
(context, itemInfo, originalView) -> {
if (originalView == null) {
diff --git a/src/com/android/launcher3/states/RotationHelper.java b/src/com/android/launcher3/states/RotationHelper.java
index 7d7ccd3..9376518 100644
--- a/src/com/android/launcher3/states/RotationHelper.java
+++ b/src/com/android/launcher3/states/RotationHelper.java
@@ -29,6 +29,7 @@
import android.content.Context;
import android.os.Handler;
import android.os.Message;
+import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread;
@@ -210,7 +211,9 @@
}
final int activityFlags;
- if (mStateHandlerRequest != REQUEST_NONE) {
+ if (mIsFixedLandscape) {
+ activityFlags = SCREEN_ORIENTATION_USER_LANDSCAPE;
+ } else if (mStateHandlerRequest != REQUEST_NONE) {
activityFlags = mStateHandlerRequest == REQUEST_LOCK ?
SCREEN_ORIENTATION_LOCKED : SCREEN_ORIENTATION_UNSPECIFIED;
} else if (mCurrentTransitionRequest != REQUEST_NONE) {
@@ -218,8 +221,6 @@
SCREEN_ORIENTATION_LOCKED : SCREEN_ORIENTATION_UNSPECIFIED;
} else if (mCurrentStateRequest == REQUEST_LOCK) {
activityFlags = SCREEN_ORIENTATION_LOCKED;
- } else if (mIsFixedLandscape) {
- activityFlags = SCREEN_ORIENTATION_USER_LANDSCAPE;
} else if (mIgnoreAutoRotateSettings || mCurrentStateRequest == REQUEST_ROTATE
|| mHomeRotationEnabled || mForceAllowRotationForTesting) {
activityFlags = SCREEN_ORIENTATION_UNSPECIFIED;
@@ -230,6 +231,7 @@
}
if (activityFlags != mLastActivityFlags) {
mLastActivityFlags = activityFlags;
+ Log.d("b/380940677", toString());
mRequestOrientationHandler.sendEmptyMessage(activityFlags);
}
}
@@ -257,9 +259,9 @@
return String.format("[mStateHandlerRequest=%d, mCurrentStateRequest=%d, "
+ "mLastActivityFlags=%d, mIgnoreAutoRotateSettings=%b, "
+ "mHomeRotationEnabled=%b, mForceAllowRotationForTesting=%b,"
- + " mDestroyed=%b]",
+ + " mDestroyed=%b, mIsFixedLandscape=%b]",
mStateHandlerRequest, mCurrentStateRequest, mLastActivityFlags,
mIgnoreAutoRotateSettings, mHomeRotationEnabled, mForceAllowRotationForTesting,
- mDestroyed);
+ mDestroyed, mIsFixedLandscape);
}
}
diff --git a/src/com/android/launcher3/util/window/WindowManagerProxy.java b/src/com/android/launcher3/util/window/WindowManagerProxy.java
index 84b4a36..1d9751e 100644
--- a/src/com/android/launcher3/util/window/WindowManagerProxy.java
+++ b/src/com/android/launcher3/util/window/WindowManagerProxy.java
@@ -27,7 +27,6 @@
import static com.android.launcher3.testing.shared.ResourceUtils.STATUS_BAR_HEIGHT;
import static com.android.launcher3.testing.shared.ResourceUtils.STATUS_BAR_HEIGHT_LANDSCAPE;
import static com.android.launcher3.testing.shared.ResourceUtils.STATUS_BAR_HEIGHT_PORTRAIT;
-import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
import static com.android.launcher3.util.RotationUtils.deltaRotation;
import static com.android.launcher3.util.RotationUtils.rotateRect;
import static com.android.launcher3.util.RotationUtils.rotateSize;
@@ -52,37 +51,33 @@
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.R;
+import com.android.launcher3.dagger.LauncherAppSingleton;
+import com.android.launcher3.dagger.LauncherBaseAppComponent;
import com.android.launcher3.testing.shared.ResourceUtils;
-import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.DaggerSingletonObject;
import com.android.launcher3.util.NavigationMode;
-import com.android.launcher3.util.ResourceBasedOverride;
-import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.WindowBounds;
import java.util.ArrayList;
import java.util.List;
+import javax.inject.Inject;
+
/**
* Utility class for mocking some window manager behaviours
*/
-public class WindowManagerProxy implements ResourceBasedOverride, SafeCloseable {
+@LauncherAppSingleton
+public class WindowManagerProxy {
private static final String TAG = "WindowManagerProxy";
public static final int MIN_TABLET_WIDTH = 600;
- public static final MainThreadInitializedObject<WindowManagerProxy> INSTANCE =
- forOverride(WindowManagerProxy.class, R.string.window_manager_proxy_class);
+ public static final DaggerSingletonObject<WindowManagerProxy> INSTANCE =
+ new DaggerSingletonObject<>(LauncherBaseAppComponent::getWmProxy);
protected final boolean mTaskbarDrawnInProcess;
- /**
- * Creates a new instance of proxy, applying any overrides
- */
- public static WindowManagerProxy newInstance(Context context) {
- return Overrides.getObject(WindowManagerProxy.class, context,
- R.string.window_manager_proxy_class);
- }
-
+ @Inject
public WindowManagerProxy() {
this(false);
}
@@ -483,9 +478,6 @@
return NavigationMode.NO_BUTTON;
}
- @Override
- public void close() { }
-
/**
* @see DisplayCutout#getSafeInsets
*/
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
index d164dd0..2f123a3 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
@@ -234,12 +234,9 @@
mIconLoadRequest.cancel();
mIconLoadRequest = null;
}
- if (getTag() instanceof ItemInfoWithIcon) {
- ItemInfoWithIcon info = (ItemInfoWithIcon) getTag();
- if (info.usingLowResIcon()) {
- mIconLoadRequest = LauncherAppState.getInstance(getContext()).getIconCache()
- .updateIconInBackground(this, info);
- }
+ if (getTag() instanceof ItemInfoWithIcon info && info.getMatchingLookupFlag().useLowRes()) {
+ mIconLoadRequest = LauncherAppState.getInstance(getContext()).getIconCache()
+ .updateIconInBackground(this, info);
}
}
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
index f9bd5f1..df76400 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
@@ -22,6 +22,7 @@
import static com.android.launcher3.UtilitiesKt.CLIP_TO_PADDING_FALSE_MODIFIER;
import static com.android.launcher3.UtilitiesKt.modifyAttributesOnViewTree;
import static com.android.launcher3.UtilitiesKt.restoreAttributesOnViewTree;
+import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
import static com.android.launcher3.widget.picker.WidgetsListItemAnimator.WIDGET_LIST_ITEM_APPEARANCE_DELAY;
import static com.android.launcher3.widget.picker.model.data.WidgetPickerDataUtils.findContentEntryForPackageUser;
@@ -51,6 +52,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.icons.cache.CacheLookupFlag;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.recyclerview.ViewHolderBinder;
@@ -691,8 +693,8 @@
}
@Override
- public boolean usingLowResIcon() {
- return false;
+ public CacheLookupFlag getMatchingLookupFlag() {
+ return DEFAULT_LOOKUP_FLAG;
}
}
}
diff --git a/src_no_quickstep/com/android/launcher3/dagger/LauncherAppComponent.java b/src_no_quickstep/com/android/launcher3/dagger/LauncherAppComponent.java
index 63d87e8..f4f5a08 100644
--- a/src_no_quickstep/com/android/launcher3/dagger/LauncherAppComponent.java
+++ b/src_no_quickstep/com/android/launcher3/dagger/LauncherAppComponent.java
@@ -22,7 +22,7 @@
* Root component for Dagger injection for Launcher AOSP.
*/
@LauncherAppSingleton
-@Component
+@Component(modules = LauncherAppModule.class)
public interface LauncherAppComponent extends LauncherBaseAppComponent {
/** Builder for aosp LauncherAppComponent. */
@Component.Builder
diff --git a/src_no_quickstep/com/android/launcher3/dagger/LauncherAppModule.java b/src_no_quickstep/com/android/launcher3/dagger/LauncherAppModule.java
new file mode 100644
index 0000000..f7b8489
--- /dev/null
+++ b/src_no_quickstep/com/android/launcher3/dagger/LauncherAppModule.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+package com.android.launcher3.dagger;
+
+import dagger.Module;
+
+@Module
+public class LauncherAppModule { }
diff --git a/tests/multivalentTests/src/com/android/launcher3/AbstractDeviceProfileTest.kt b/tests/multivalentTests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
index c4519eb..8598917 100644
--- a/tests/multivalentTests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
@@ -26,8 +26,11 @@
import android.platform.test.rule.LimitDevicesRule
import android.util.DisplayMetrics
import android.view.Surface
-import androidx.test.core.app.ApplicationProvider
+import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.dagger.LauncherAppComponent
+import com.android.launcher3.dagger.LauncherAppModule
+import com.android.launcher3.dagger.LauncherAppSingleton
import com.android.launcher3.testing.shared.ResourceUtils
import com.android.launcher3.util.DisplayController
import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext
@@ -38,6 +41,8 @@
import com.android.launcher3.util.window.CachedDisplayInfo
import com.android.launcher3.util.window.WindowManagerProxy
import com.google.common.truth.Truth
+import dagger.BindsInstance
+import dagger.Component
import java.io.BufferedReader
import java.io.File
import java.io.PrintWriter
@@ -62,9 +67,9 @@
abstract class AbstractDeviceProfileTest {
protected val testContext: Context = InstrumentationRegistry.getInstrumentation().context
protected lateinit var context: SandboxContext
- protected open val runningContext: Context = ApplicationProvider.getApplicationContext()
+ protected open val runningContext: Context = getApplicationContext()
private val displayController: DisplayController = mock()
- private val windowManagerProxy: WindowManagerProxy = mock()
+ private val windowManagerProxy: MyWmProxy = mock()
private val launcherPrefs: LauncherPrefs = mock()
@get:Rule val setFlagsRule = SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT)
@@ -290,9 +295,9 @@
.thenReturn(
if (isGestureMode) NavigationMode.NO_BUTTON else NavigationMode.THREE_BUTTONS
)
- doReturn(WindowManagerProxy.INSTANCE[runningContext].isTaskbarDrawnInProcess)
+ doReturn(WindowManagerProxy.INSTANCE[getApplicationContext()].isTaskbarDrawnInProcess)
.whenever(windowManagerProxy)
- .isTaskbarDrawnInProcess()
+ .isTaskbarDrawnInProcess
val density = densityDpi / DisplayMetrics.DENSITY_DEFAULT.toFloat()
val config =
@@ -304,8 +309,10 @@
}
val configurationContext = runningContext.createConfigurationContext(config)
context = SandboxContext(configurationContext)
+ context.initDaggerComponent(
+ DaggerAbsDPTestSandboxComponent.builder().bindWMProxy(windowManagerProxy)
+ )
context.putObject(DisplayController.INSTANCE, displayController)
- context.putObject(WindowManagerProxy.INSTANCE, windowManagerProxy)
context.putObject(LauncherPrefs.INSTANCE, launcherPrefs)
whenever(launcherPrefs.get(LauncherPrefs.TASKBAR_PINNING)).thenReturn(false)
@@ -355,3 +362,19 @@
return context.resources.getIdentifier(this, "xml", context.packageName)
}
}
+
+class MyWmProxy : WindowManagerProxy()
+
+@LauncherAppSingleton
+@Component(modules = [LauncherAppModule::class])
+interface AbsDPTestSandboxComponent : LauncherAppComponent {
+
+ override fun getWmProxy(): MyWmProxy
+
+ @Component.Builder
+ interface Builder : LauncherAppComponent.Builder {
+ @BindsInstance fun bindWMProxy(proxy: MyWmProxy): Builder
+
+ override fun build(): AbsDPTestSandboxComponent
+ }
+}
diff --git a/tests/multivalentTests/src/com/android/launcher3/AutoInstallsLayoutTest.kt b/tests/multivalentTests/src/com/android/launcher3/AutoInstallsLayoutTest.kt
index f73a9d3..fcbb94b 100644
--- a/tests/multivalentTests/src/com/android/launcher3/AutoInstallsLayoutTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/AutoInstallsLayoutTest.kt
@@ -42,6 +42,7 @@
import com.android.launcher3.LauncherSettings.Favorites.SPANY
import com.android.launcher3.LauncherSettings.Favorites._ID
import com.android.launcher3.dagger.LauncherAppComponent
+import com.android.launcher3.dagger.LauncherAppModule
import com.android.launcher3.dagger.LauncherAppSingleton
import com.android.launcher3.model.data.AppInfo
import com.android.launcher3.pm.UserCache
@@ -66,7 +67,7 @@
import org.mockito.Mock
import org.mockito.MockitoAnnotations
import org.mockito.kotlin.doReturn
-import org.mockito.kotlin.spy
+import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
/** Tests for [AutoInstallsLayout] */
@@ -165,7 +166,9 @@
@Test
fun work_item_added_to_home() {
- val apiWrapperMock = spy(ApiWrapper.INSTANCE[targetContext])
+ val original = ApiWrapper.INSTANCE[targetContext]
+ val apiWrapperMock =
+ mock<MyApiWrapper>(defaultAnswer = { it.method.invoke(original, *it.arguments) })
targetContext.initDaggerComponent(
DaggerAutoInstallsLayoutTestComponent.builder().bindApiWrapper(apiWrapperMock)
)
@@ -221,12 +224,17 @@
}
}
+class MyApiWrapper : ApiWrapper(null) {}
+
@LauncherAppSingleton
-@Component
+@Component(modules = [LauncherAppModule::class])
interface AutoInstallsLayoutTestComponent : LauncherAppComponent {
+
+ override fun getApiWrapper(): MyApiWrapper
+
@Component.Builder
interface Builder : LauncherAppComponent.Builder {
- @BindsInstance fun bindApiWrapper(wrapper: ApiWrapper): Builder
+ @BindsInstance fun bindApiWrapper(wrapper: MyApiWrapper): Builder
override fun build(): AutoInstallsLayoutTestComponent
}
diff --git a/tests/src/com/android/launcher3/celllayout/testgenerator/ValidGridMigrationTestCaseGenerator.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/ValidGridMigrationTestCaseGenerator.kt
similarity index 95%
rename from tests/src/com/android/launcher3/celllayout/testgenerator/ValidGridMigrationTestCaseGenerator.kt
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/ValidGridMigrationTestCaseGenerator.kt
index a006fd7..ad80b2d 100644
--- a/tests/src/com/android/launcher3/celllayout/testgenerator/ValidGridMigrationTestCaseGenerator.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/ValidGridMigrationTestCaseGenerator.kt
@@ -32,7 +32,7 @@
*/
fun generateItemsForTest(
boards: List<CellLayoutBoard>,
- repeatAfterRange: Point
+ repeatAfterRange: Point,
): List<WorkspaceItem> {
val id = AtomicInteger(0)
val widgetId = AtomicInteger(LauncherAppWidgetInfo.CUSTOM_WIDGET_ID - 1)
@@ -56,7 +56,7 @@
appWidgetProvider = "Hotseat icons don't have a provider",
intent = getIntent(id.get()),
type = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION,
- container = LauncherSettings.Favorites.CONTAINER_HOTSEAT
+ container = LauncherSettings.Favorites.CONTAINER_HOTSEAT,
)
}
var widgetEntries =
@@ -75,7 +75,7 @@
appWidgetProvider = getProvider(id.get()),
intent = "Widgets don't have intent",
type = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET,
- container = LauncherSettings.Favorites.CONTAINER_DESKTOP
+ container = LauncherSettings.Favorites.CONTAINER_DESKTOP,
)
}
widgetEntries = widgetEntries.filter { it.appWidgetProvider.contains("Provider4") }
@@ -95,7 +95,7 @@
appWidgetProvider = "Icons don't have providers",
intent = getIntent(id.get()),
type = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION,
- container = LauncherSettings.Favorites.CONTAINER_DESKTOP
+ container = LauncherSettings.Favorites.CONTAINER_DESKTOP,
)
}
return widgetEntries + hotseatEntries + iconEntries
@@ -106,7 +106,7 @@
val destBoards: List<CellLayoutBoard>,
val srcSize: Point,
val targetSize: Point,
- val seed: Long
+ val seed: Long,
)
class ValidGridMigrationTestCaseGenerator(private val generator: Random) :
@@ -122,7 +122,7 @@
boardGenerator: RandomBoardGenerator,
width: Int,
height: Int,
- boardCount: Int
+ boardCount: Int,
): List<CellLayoutBoard> {
val boards = mutableListOf<CellLayoutBoard>()
for (i in 0 until boardCount) {
@@ -130,7 +130,7 @@
boardGenerator.generateBoard(
width,
height,
- boardGenerator.getRandom(0, width * height)
+ boardGenerator.getRandom(0, width * height),
)
)
}
@@ -145,7 +145,7 @@
val targetSize =
Point(
randomBoardGenerator.getRandom(3, MAX_BOARD_SIZE),
- randomBoardGenerator.getRandom(3, MAX_BOARD_SIZE)
+ randomBoardGenerator.getRandom(3, MAX_BOARD_SIZE),
)
val destBoards =
if (isDestEmpty) {
@@ -155,7 +155,7 @@
boardGenerator = randomBoardGenerator,
width = targetSize.x,
height = targetSize.y,
- boardCount = randomBoardGenerator.getRandom(3, MAX_BOARD_COUNT)
+ boardCount = randomBoardGenerator.getRandom(3, MAX_BOARD_COUNT),
)
}
return GridMigrationUnitTestCase(
@@ -164,12 +164,12 @@
boardGenerator = randomBoardGenerator,
width = width,
height = height,
- boardCount = randomBoardGenerator.getRandom(3, MAX_BOARD_COUNT)
+ boardCount = randomBoardGenerator.getRandom(3, MAX_BOARD_COUNT),
),
destBoards = destBoards,
srcSize = Point(width, height),
targetSize = targetSize,
- seed = seed
+ seed = seed,
)
}
}
diff --git a/tests/multivalentTests/src/com/android/launcher3/folder/FolderTest.kt b/tests/multivalentTests/src/com/android/launcher3/folder/FolderTest.kt
index 4eb335e..bcf5f0d 100644
--- a/tests/multivalentTests/src/com/android/launcher3/folder/FolderTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/folder/FolderTest.kt
@@ -58,6 +58,7 @@
import junit.framework.TestCase.assertNull
import junit.framework.TestCase.assertTrue
import org.junit.After
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito
@@ -74,10 +75,16 @@
@RunWith(AndroidJUnit4::class)
class FolderTest {
- private val context: Context =
- ActivityContextWrapper(ApplicationProvider.getApplicationContext())
- private val workspaceBuilder = TestWorkspaceBuilder(context)
- private val folder: Folder = spy(Folder(context, null))
+ private lateinit var context: Context
+ private lateinit var workspaceBuilder: TestWorkspaceBuilder
+ private lateinit var folder: Folder
+
+ @Before
+ fun setUp() {
+ context = ActivityContextWrapper(ApplicationProvider.getApplicationContext())
+ workspaceBuilder = TestWorkspaceBuilder(context)
+ folder = spy(Folder(context, null))
+ }
@After
fun tearDown() {
@@ -412,7 +419,7 @@
folder.onEditorAction(
Mockito.mock(TextView::class.java),
EditorInfo.IME_ACTION_DONE,
- Mockito.mock(KeyEvent::class.java)
+ Mockito.mock(KeyEvent::class.java),
)
assertTrue(result)
@@ -427,7 +434,7 @@
folder.onEditorAction(
Mockito.mock(TextView::class.java),
EditorInfo.IME_ACTION_NONE,
- Mockito.mock(KeyEvent::class.java)
+ Mockito.mock(KeyEvent::class.java),
)
assertFalse(result)
@@ -824,7 +831,7 @@
val items =
arrayListOf<ItemInfo>(
Mockito.mock(ItemInfo::class.java),
- Mockito.mock(ItemInfo::class.java)
+ Mockito.mock(ItemInfo::class.java),
)
val view1 = Mockito.mock(View::class.java)
val view2 = Mockito.mock(View::class.java)
@@ -845,7 +852,7 @@
val items =
arrayListOf<ItemInfo>(
Mockito.mock(ItemInfo::class.java),
- Mockito.mock(ItemInfo::class.java)
+ Mockito.mock(ItemInfo::class.java),
)
val view1 = Mockito.mock(View::class.java)
val view2 = Mockito.mock(View::class.java)
@@ -867,7 +874,7 @@
val items =
arrayListOf<ItemInfo>(
Mockito.mock(ItemInfo::class.java),
- Mockito.mock(ItemInfo::class.java)
+ Mockito.mock(ItemInfo::class.java),
)
val view1 = Mockito.mock(View::class.java)
val view2 = Mockito.mock(View::class.java)
@@ -887,7 +894,7 @@
val items =
arrayListOf<ItemInfo>(
Mockito.mock(ItemInfo::class.java),
- Mockito.mock(ItemInfo::class.java)
+ Mockito.mock(ItemInfo::class.java),
)
val view1 = Mockito.mock(View::class.java)
val view2 = Mockito.mock(View::class.java)
@@ -908,7 +915,7 @@
val items =
arrayListOf<ItemInfo>(
Mockito.mock(ItemInfo::class.java),
- Mockito.mock(ItemInfo::class.java)
+ Mockito.mock(ItemInfo::class.java),
)
val view1 = Mockito.mock(View::class.java)
val view2 = Mockito.mock(View::class.java)
diff --git a/tests/multivalentTests/src/com/android/launcher3/icons/IconCacheTest.java b/tests/multivalentTests/src/com/android/launcher3/icons/IconCacheTest.java
index 9b4bd71..9026748 100644
--- a/tests/multivalentTests/src/com/android/launcher3/icons/IconCacheTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/icons/IconCacheTest.java
@@ -21,6 +21,7 @@
import static com.android.launcher3.icons.IconCache.EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE;
import static com.android.launcher3.icons.IconCacheUpdateHandlerTestKt.waitForUpdateHandlerToFinish;
+import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
import static com.android.launcher3.model.data.AppInfo.makeLaunchIntent;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY;
@@ -164,7 +165,7 @@
WorkspaceItemInfo info = new WorkspaceItemInfo();
info.intent = makeLaunchIntent(cn);
runOnExecutorSync(MODEL_EXECUTOR,
- () -> mIconCache.getTitleAndIcon(info, lai, false));
+ () -> mIconCache.getTitleAndIcon(info, lai, DEFAULT_LOOKUP_FLAG));
assertNotNull(info.bitmap);
assertFalse(info.bitmap.isLowRes());
diff --git a/tests/multivalentTests/src/com/android/launcher3/icons/cache/CacheLookupFlagTest.kt b/tests/multivalentTests/src/com/android/launcher3/icons/cache/CacheLookupFlagTest.kt
new file mode 100644
index 0000000..7b1851d
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/icons/cache/CacheLookupFlagTest.kt
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+package com.android.launcher3.icons.cache
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.icons.cache.CacheLookupFlag.Companion.DEFAULT_LOOKUP_FLAG
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CacheLookupFlagTest {
+
+ @Test
+ fun `useLowRes preserves lowRes values`() {
+ assertFalse(DEFAULT_LOOKUP_FLAG.useLowRes())
+ assertTrue(DEFAULT_LOOKUP_FLAG.withUseLowRes().useLowRes())
+ assertFalse(DEFAULT_LOOKUP_FLAG.withUseLowRes().withUseLowRes(false).useLowRes())
+ assertTrue(
+ DEFAULT_LOOKUP_FLAG.withUseLowRes().withUseLowRes(false).withUseLowRes().useLowRes()
+ )
+ }
+
+ @Test
+ fun `usePackageIcon preserves lowRes values`() {
+ assertFalse(DEFAULT_LOOKUP_FLAG.usePackageIcon())
+ assertTrue(DEFAULT_LOOKUP_FLAG.withUsePackageIcon().usePackageIcon())
+ assertFalse(
+ DEFAULT_LOOKUP_FLAG.withUsePackageIcon().withUsePackageIcon(false).usePackageIcon()
+ )
+ assertTrue(
+ DEFAULT_LOOKUP_FLAG.withUsePackageIcon()
+ .withUsePackageIcon(false)
+ .withUsePackageIcon()
+ .usePackageIcon()
+ )
+ }
+
+ @Test
+ fun `skipAddToMemCache preserves lowRes values`() {
+ assertFalse(DEFAULT_LOOKUP_FLAG.skipAddToMemCache())
+ assertTrue(DEFAULT_LOOKUP_FLAG.withSkipAddToMemCache().skipAddToMemCache())
+ assertFalse(
+ DEFAULT_LOOKUP_FLAG.withSkipAddToMemCache()
+ .withSkipAddToMemCache(false)
+ .skipAddToMemCache()
+ )
+ assertTrue(
+ DEFAULT_LOOKUP_FLAG.withSkipAddToMemCache()
+ .withSkipAddToMemCache(false)
+ .withSkipAddToMemCache()
+ .skipAddToMemCache()
+ )
+ }
+
+ @Test
+ fun `preserves multiple flags`() {
+ val flag = DEFAULT_LOOKUP_FLAG.withSkipAddToMemCache().withUseLowRes()
+
+ assertTrue(flag.skipAddToMemCache())
+ assertTrue(flag.useLowRes())
+ assertFalse(flag.usePackageIcon())
+ }
+}
diff --git a/tests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt
similarity index 100%
rename from tests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
index 7099d38..d699eee 100644
--- a/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
@@ -393,6 +393,39 @@
}
@Test
+ fun `When Pinned Deep Shortcut is not stored in ShortcutManager re-query by Shortcut ID`() {
+ // Given
+ mockCursor.itemType = ITEM_TYPE_DEEP_SHORTCUT
+ val si =
+ mock<ShortcutInfo>().apply {
+ whenever(id).thenReturn("")
+ whenever(`package`).thenReturn("")
+ whenever(activity).thenReturn(mock())
+ whenever(longLabel).thenReturn("")
+ whenever(isEnabled).thenReturn(true)
+ whenever(disabledMessage).thenReturn("")
+ whenever(disabledReason).thenReturn(0)
+ whenever(persons).thenReturn(EMPTY_PERSON_ARRAY)
+ }
+ whenever(mockLauncherApps.getShortcuts(any(), any())).thenReturn(listOf(si))
+ mKeyToPinnedShortcutsMap.clear()
+ mIconRequestInfos = mutableListOf()
+
+ // When
+ itemProcessorUnderTest =
+ createWorkspaceItemProcessorUnderTest(allDeepShortcuts = mAllDeepShortcuts)
+ itemProcessorUnderTest.processItem()
+
+ // Then
+ verify(mockLauncherApps).getShortcuts(any(), any())
+ assertWithMessage("item restoreFlag should be set to 0")
+ .that(mockCursor.restoreFlag)
+ .isEqualTo(0)
+ verify(mockCursor).markRestored()
+ verify(mockCursor).checkAndAddItem(any(), any(), anyOrNull())
+ }
+
+ @Test
fun `When Pinned Deep Shortcut not found then mark deleted`() {
// Given
diff --git a/tests/src/com/android/launcher3/model/gridmigration/GridMigrationUtils.kt b/tests/multivalentTests/src/com/android/launcher3/model/gridmigration/GridMigrationUtils.kt
similarity index 98%
rename from tests/src/com/android/launcher3/model/gridmigration/GridMigrationUtils.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/gridmigration/GridMigrationUtils.kt
index cc8e61d..174d716 100644
--- a/tests/src/com/android/launcher3/model/gridmigration/GridMigrationUtils.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/gridmigration/GridMigrationUtils.kt
@@ -24,8 +24,11 @@
class MockSet(override val size: Int) : Set<String> {
override fun contains(element: String): Boolean = true
+
override fun containsAll(elements: Collection<String>): Boolean = true
+
override fun isEmpty(): Boolean = false
+
override fun iterator(): Iterator<String> = listOf<String>().iterator()
}
@@ -91,7 +94,7 @@
appWidgetProvider = cursor.getString(indexWidgetProvider),
intent = cursor.getString(indexIntent),
type = cursor.getInt(indexItemType),
- container = cursor.getInt(container)
+ container = cursor.getInt(container),
)
)
}
diff --git a/tests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt
similarity index 100%
rename from tests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt
index a3a680e..d0cf610 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt
@@ -15,7 +15,6 @@
*/
package com.android.launcher3.util
-import android.content.Context
import android.content.res.Configuration
import android.content.res.Resources
import android.graphics.Point
@@ -26,18 +25,22 @@
import android.view.Display
import android.view.Surface
import androidx.test.annotation.UiThreadTest
-import androidx.test.core.app.ApplicationProvider
import androidx.test.filters.SmallTest
import com.android.launcher3.LauncherPrefs
import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING
import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING_IN_DESKTOP_MODE
+import com.android.launcher3.dagger.LauncherAppComponent
+import com.android.launcher3.dagger.LauncherAppModule
+import com.android.launcher3.dagger.LauncherAppSingleton
import com.android.launcher3.util.DisplayController.CHANGE_DENSITY
import com.android.launcher3.util.DisplayController.CHANGE_ROTATION
import com.android.launcher3.util.DisplayController.CHANGE_TASKBAR_PINNING
import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener
-import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext
+import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext
import com.android.launcher3.util.window.CachedDisplayInfo
import com.android.launcher3.util.window.WindowManagerProxy
+import dagger.BindsInstance
+import dagger.Component
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import kotlin.math.min
@@ -51,6 +54,7 @@
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import org.mockito.stubbing.Answer
@@ -60,12 +64,10 @@
@RunWith(LauncherMultivalentJUnit::class)
class DisplayControllerTest {
- private val appContext: Context = ApplicationProvider.getApplicationContext()
-
- private val context: SandboxContext = mock()
- private val windowManagerProxy: WindowManagerProxy = mock()
+ private val context = spy(SandboxModelContext())
+ private val windowManagerProxy: MyWmProxy = mock()
private val launcherPrefs: LauncherPrefs = mock()
- private val displayManager: DisplayManager = mock()
+ private lateinit var displayManager: DisplayManager
private val display: Display = mock()
private val resources: Resources = mock()
private val displayInfoChangeListener: DisplayInfoChangeListener = mock()
@@ -85,7 +87,7 @@
WindowBounds(Rect(0, 0, height, width), Rect(0, inset, 0, 0), Surface.ROTATION_270),
)
private val configuration =
- Configuration(appContext.resources.configuration).apply {
+ Configuration(context.resources.configuration).apply {
densityDpi = this@DisplayControllerTest.densityDpi
screenWidthDp = (bounds[0].bounds.width() / density).toInt()
screenHeightDp = (bounds[0].bounds.height() / density).toInt()
@@ -94,8 +96,12 @@
@Before
fun setUp() {
- whenever(context.getObject(eq(WindowManagerProxy.INSTANCE))).thenReturn(windowManagerProxy)
- whenever(context.getObject(eq(LauncherPrefs.INSTANCE))).thenReturn(launcherPrefs)
+ context.initDaggerComponent(
+ DaggerDisplayControllerTestComponent.builder().bindWMProxy(windowManagerProxy)
+ )
+ context.putObject(LauncherPrefs.INSTANCE, launcherPrefs)
+ displayManager = context.spyService(DisplayManager::class.java)
+
whenever(launcherPrefs.get(TASKBAR_PINNING)).thenReturn(false)
whenever(launcherPrefs.get(TASKBAR_PINNING_IN_DESKTOP_MODE)).thenReturn(true)
@@ -118,15 +124,13 @@
whenever(windowManagerProxy.getNavigationMode(any())).thenReturn(NavigationMode.NO_BUTTON)
// Mock context
- whenever(context.createWindowContext(any(), any(), anyOrNull())).thenReturn(context)
- whenever(context.getSystemService(eq(DisplayManager::class.java)))
- .thenReturn(displayManager)
+ doReturn(context).whenever(context).createWindowContext(any(), any(), anyOrNull())
doNothing().whenever(context).registerComponentCallbacks(any())
// Mock display
whenever(display.rotation).thenReturn(displayInfo.rotation)
- whenever(context.display).thenReturn(display)
- whenever(displayManager.getDisplay(any())).thenReturn(display)
+ doReturn(display).whenever(context).display
+ doReturn(display).whenever(displayManager).getDisplay(any())
// Mock resources
doReturn(context).whenever(context).applicationContext
@@ -143,6 +147,7 @@
// We need to reset the taskbar mode preference override even if a test throws an exception.
// Otherwise, it may break the following tests' assumptions.
DisplayController.enableTaskbarModePreferenceForTests(false)
+ context.onDestroy()
}
@Test
@@ -225,3 +230,19 @@
assertFalse(displayController.getInfo().isTransientTaskbar())
}
}
+
+class MyWmProxy : WindowManagerProxy()
+
+@LauncherAppSingleton
+@Component(modules = [LauncherAppModule::class])
+interface DisplayControllerTestComponent : LauncherAppComponent {
+
+ override fun getWmProxy(): MyWmProxy
+
+ @Component.Builder
+ interface Builder : LauncherAppComponent.Builder {
+ @BindsInstance fun bindWMProxy(proxy: MyWmProxy): Builder
+
+ override fun build(): DisplayControllerTestComponent
+ }
+}
diff --git a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
index 34cbdee..4d181ff 100644
--- a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
+++ b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
@@ -16,6 +16,9 @@
import com.android.launcher3.LauncherAppState
import com.android.launcher3.LauncherModel
import com.android.launcher3.LauncherModel.LoaderTransaction
+import com.android.launcher3.LauncherPrefs
+import com.android.launcher3.LauncherPrefs.Companion.IS_FIRST_LOAD_AFTER_RESTORE
+import com.android.launcher3.LauncherPrefs.Companion.RESTORE_DEVICE
import com.android.launcher3.icons.IconCache
import com.android.launcher3.icons.cache.CachingLogic
import com.android.launcher3.icons.cache.IconCacheUpdateHandler
@@ -130,6 +133,8 @@
@After
fun tearDown() {
+ LauncherPrefs.get(context).removeSync(RESTORE_DEVICE)
+ LauncherPrefs.get(context).putSync(IS_FIRST_LOAD_AFTER_RESTORE.to(false))
context.onDestroy()
mockitoSession.finishMocking()
}
@@ -242,84 +247,8 @@
}
@Test
- @DisableFlags(Flags.FLAG_ENABLE_FIRST_SCREEN_BROADCAST_ARCHIVING_EXTRAS)
- fun `When secure setting true and is restore then send installed item broadcast`() {
- // Given
- val spyContext = spy(context)
- `when`(app.context).thenReturn(spyContext)
- whenever(
- FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
- any(),
- any(),
- any(),
- any(),
- )
- )
- .thenReturn(listOf(expectedBroadcastModel))
-
- whenever(
- FirstScreenBroadcastHelper.sendBroadcastsForModels(
- spyContext,
- listOf(expectedBroadcastModel),
- )
- )
- .thenCallRealMethod()
-
- Settings.Secure.putInt(spyContext.contentResolver, "launcher_broadcast_installed_apps", 1)
- RestoreDbTask.setPending(spyContext)
-
- // When
- LoaderTask(
- app,
- bgAllAppsList,
- BgDataModel(),
- modelDelegate,
- launcherBinder,
- widgetsFilterDataProvider,
- )
- .runSyncOnBackgroundThread()
-
- // Then
- val argumentCaptor = ArgumentCaptor.forClass(Intent::class.java)
- verify(spyContext).sendBroadcast(argumentCaptor.capture())
- val actualBroadcastIntent = argumentCaptor.value
- assertEquals(expectedBroadcastModel.installerPackage, actualBroadcastIntent.`package`)
- assertEquals(
- ArrayList(expectedBroadcastModel.installedWorkspaceItems),
- actualBroadcastIntent.getStringArrayListExtra("workspaceInstalledItems"),
- )
- assertEquals(
- ArrayList(expectedBroadcastModel.installedHotseatItems),
- actualBroadcastIntent.getStringArrayListExtra("hotseatInstalledItems"),
- )
- assertEquals(
- ArrayList(
- expectedBroadcastModel.firstScreenInstalledWidgets +
- expectedBroadcastModel.secondaryScreenInstalledWidgets
- ),
- actualBroadcastIntent.getStringArrayListExtra("widgetInstalledItems"),
- )
- assertEquals(
- ArrayList(expectedBroadcastModel.pendingCollectionItems),
- actualBroadcastIntent.getStringArrayListExtra("folderItem"),
- )
- assertEquals(
- ArrayList(expectedBroadcastModel.pendingWorkspaceItems),
- actualBroadcastIntent.getStringArrayListExtra("workspaceItem"),
- )
- assertEquals(
- ArrayList(expectedBroadcastModel.pendingHotseatItems),
- actualBroadcastIntent.getStringArrayListExtra("hotseatItem"),
- )
- assertEquals(
- ArrayList(expectedBroadcastModel.pendingWidgetItems),
- actualBroadcastIntent.getStringArrayListExtra("widgetItem"),
- )
- }
-
- @Test
@EnableFlags(Flags.FLAG_ENABLE_FIRST_SCREEN_BROADCAST_ARCHIVING_EXTRAS)
- fun `When broadcast flag true and is restore then send installed item broadcast`() {
+ fun `When broadcast flag on and is restore and secure setting off then send new broadcast`() {
// Given
val spyContext = spy(context)
`when`(app.context).thenReturn(spyContext)
@@ -417,7 +346,7 @@
)
.thenCallRealMethod()
- Settings.Secure.putInt(spyContext.contentResolver, "launcher_broadcast_installed_apps", 1)
+ Settings.Secure.putInt(spyContext.contentResolver, "launcher_broadcast_installed_apps", 0)
// When
LoaderTask(
@@ -436,7 +365,7 @@
@Test
@DisableFlags(Flags.FLAG_ENABLE_FIRST_SCREEN_BROADCAST_ARCHIVING_EXTRAS)
- fun `When broadcast flag and secure setting false then installed item broadcast not sent`() {
+ fun `When broadcast flag off then installed item broadcast not sent`() {
// Given
val spyContext = spy(context)
`when`(app.context).thenReturn(spyContext)
@@ -458,7 +387,57 @@
)
.thenCallRealMethod()
- Settings.Secure.putInt(spyContext.contentResolver, "launcher_broadcast_installed_apps", 0)
+ Settings.Secure.putInt(
+ spyContext.contentResolver,
+ "disable_launcher_broadcast_installed_apps",
+ 0,
+ )
+ RestoreDbTask.setPending(spyContext)
+
+ // When
+ LoaderTask(
+ app,
+ bgAllAppsList,
+ BgDataModel(),
+ modelDelegate,
+ launcherBinder,
+ widgetsFilterDataProvider,
+ )
+ .runSyncOnBackgroundThread()
+
+ // Then
+ verify(spyContext, times(0)).sendBroadcast(any())
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_FIRST_SCREEN_BROADCAST_ARCHIVING_EXTRAS)
+ fun `When failsafe secure setting on then installed item broadcast not sent`() {
+ // Given
+ val spyContext = spy(context)
+ `when`(app.context).thenReturn(spyContext)
+ whenever(
+ FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
+ any(),
+ any(),
+ any(),
+ any(),
+ )
+ )
+ .thenReturn(listOf(expectedBroadcastModel))
+
+ whenever(
+ FirstScreenBroadcastHelper.sendBroadcastsForModels(
+ spyContext,
+ listOf(expectedBroadcastModel),
+ )
+ )
+ .thenCallRealMethod()
+
+ Settings.Secure.putInt(
+ spyContext.contentResolver,
+ "disable_launcher_broadcast_installed_apps",
+ 1,
+ )
RestoreDbTask.setPending(spyContext)
// When
diff --git a/tests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt b/tests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt
index ca2ef42..94b2c7e 100644
--- a/tests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt
+++ b/tests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt
@@ -23,6 +23,7 @@
import android.content.pm.PackageInstaller
import android.content.pm.PackageManager
import android.graphics.Bitmap
+import android.os.Process.myUserHandle
import android.os.UserHandle
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -73,14 +74,14 @@
sessionId = 0
installerPackageName = expectedInstallerPackage
appPackageName = expectedAppPackage
- userId = 0
+ userId = myUserHandle().identifier
}
val expectedVerifiedSession2 =
PackageInstaller.SessionInfo().apply {
sessionId = 1
installerPackageName = expectedInstallerPackage
appPackageName = "app2"
- userId = 0
+ userId = myUserHandle().identifier
}
val expectedSessions = listOf(expectedVerifiedSession1, expectedVerifiedSession2)
whenever(launcherApps.allPackageInstallerSessions).thenReturn(expectedSessions)
@@ -97,13 +98,13 @@
PackageInstaller.SessionInfo().apply {
installerPackageName = expectedInstallerPackage
appPackageName = expectedAppPackage
- userId = 0
+ userId = myUserHandle().identifier
}
whenever(launcherApps.allPackageInstallerSessions)
.thenReturn(listOf(expectedVerifiedSession))
// When
val actualSession =
- installSessionHelper.getActiveSessionInfo(UserHandle(0), expectedAppPackage)
+ installSessionHelper.getActiveSessionInfo(myUserHandle(), expectedAppPackage)
// Then
assertThat(actualSession).isEqualTo(expectedVerifiedSession)
}
@@ -116,7 +117,7 @@
sessionId = 1
installerPackageName = expectedInstallerPackage
appPackageName = expectedAppPackage
- userId = 0
+ userId = myUserHandle().identifier
}
whenever(mockPackageInstaller.getSessionInfo(1)).thenReturn(expectedSession)
// When
@@ -147,14 +148,14 @@
sessionId = 0
installerPackageName = expectedInstallerPackage
appPackageName = expectedAppPackage
- userId = 0
+ userId = myUserHandle().identifier
}
val expectedVerifiedSession2 =
PackageInstaller.SessionInfo().apply {
sessionId = 1
installerPackageName = expectedInstallerPackage
appPackageName = "app2"
- userId = 0
+ userId = myUserHandle().identifier
}
val expectedSessions = listOf(expectedVerifiedSession1, expectedVerifiedSession2)
whenever(launcherApps.allPackageInstallerSessions).thenReturn(expectedSessions)
@@ -174,7 +175,7 @@
sessionId = 1
installerPackageName = expectedInstallerPackage
appPackageName = "app2"
- userId = 0
+ userId = myUserHandle().identifier
}
whenever(launcherApps.allPackageInstallerSessions).thenReturn(listOf(expectedSession))
// When
@@ -196,7 +197,7 @@
sessionId = 1
installerPackageName = expectedInstallerPackage
appPackageName = "app2"
- userId = 0
+ userId = myUserHandle().identifier
}
whenever(launcherApps.allPackageInstallerSessions).thenReturn(listOf(expectedSession))
// When
@@ -219,7 +220,7 @@
sessionId = 1
installerPackageName = expectedInstallerPackage
appPackageName = "appPackage"
- userId = 0
+ userId = myUserHandle().identifier
appIcon = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8)
appLabel = "appLabel"
installReason = PackageManager.INSTALL_REASON_USER
@@ -249,7 +250,7 @@
sessionId = 1
installerPackageName = expectedInstallerPackage
appPackageName = "appPackage"
- userId = 0
+ userId = myUserHandle().identifier
appIcon = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8)
appLabel = "appLabel"
installReason = PackageManager.INSTALL_REASON_USER
diff --git a/tests/src/com/android/launcher3/popup/SystemShortcutTest.java b/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
index ae54e95..075f667 100644
--- a/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
+++ b/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
@@ -62,15 +62,12 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.R;
import com.android.launcher3.allapps.PrivateProfileManager;
-import com.android.launcher3.dagger.LauncherAppComponent;
-import com.android.launcher3.dagger.LauncherAppSingleton;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pm.UserCache;
-import com.android.launcher3.util.ApiWrapper;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext;
import com.android.launcher3.util.LauncherMultivalentJUnit;
@@ -81,9 +78,6 @@
import com.android.launcher3.widget.picker.model.WidgetPickerDataProvider;
import com.android.launcher3.widget.picker.model.data.WidgetPickerData;
-import dagger.BindsInstance;
-import dagger.Component;
-
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@@ -109,7 +103,6 @@
private AppInfo mAppInfo;
@Mock UserCache mUserCache;
- @Mock ApiWrapper mApiWrapper;
@Mock UserIconInfo mUserIconInfo;
@Mock LauncherActivityInfo mLauncherActivityInfo;
@Mock ApplicationInfo mApplicationInfo;
@@ -120,9 +113,6 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mSandboxContext.initDaggerComponent(
- DaggerSystemShortcutTest_TestComponent.builder().bindApiWrapper(
- ApiWrapper.INSTANCE.get(mSandboxContext)));
mSandboxContext.putObject(UserCache.INSTANCE, mUserCache);
mTestContext = new TestSandboxModelContextWrapper(mSandboxContext) {
@Override
@@ -412,16 +402,4 @@
systemShortcut.onClick(mView);
verify(mSandboxContext).startActivity(any());
}
-
- @LauncherAppSingleton
- @Component
- interface TestComponent extends LauncherAppComponent {
- @Component.Builder
- interface Builder extends LauncherAppComponent.Builder {
- @BindsInstance Builder bindApiWrapper(ApiWrapper wrapper);
-
- @Override
- TestComponent build();
- }
- }
}
diff --git a/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java b/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
index e5c5c19..d49168f 100644
--- a/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
+++ b/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
@@ -1,11 +1,16 @@
package com.android.launcher3.ui;
+import static com.android.launcher3.LauncherPrefs.FIXED_LANDSCAPE_MODE;
+
import android.util.Log;
import android.view.Surface;
+import com.android.launcher3.Flags;
import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.tapl.TestHelpers;
import com.android.launcher3.util.rule.FailureWatcher;
+import com.android.launcher3.util.window.WindowManagerProxy;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
@@ -67,9 +72,11 @@
Log.e(TAG, "Error", e);
throw e;
} finally {
+
mTest.mDevice.setOrientationNatural();
mTest.executeOnLauncher(launcher ->
{
+ LauncherPrefs.get(launcher).put(FIXED_LANDSCAPE_MODE, false);
if (launcher != null) {
launcher.getRotationHelper().forceAllowRotationForTesting(false);
}
@@ -90,6 +97,13 @@
}
private void evaluateInLandscape() throws Throwable {
+ if (Flags.oneGridSpecs()
+ && WindowManagerProxy.INSTANCE.get(mTest.mTargetContext)
+ .isTaskbarDrawnInProcess()) {
+ mTest.executeOnLauncher(launcher -> LauncherPrefs.get(launcher)
+ .put(FIXED_LANDSCAPE_MODE, true)
+ );
+ }
mTest.mDevice.setOrientationLeft();
mTest.mLauncher.setExpectedRotation(Surface.ROTATION_90);
AbstractLauncherUiTest.checkDetectedLeaks(mTest.mLauncher, true);