Merge "Skip stash animation when destroying LauncherTaskbarUIController" into main
diff --git a/Android.bp b/Android.bp
index bcbd362..4e1c9d3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -17,7 +17,7 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
-min_launcher3_sdk_version = "30"
+min_launcher3_sdk_version = "31"
// Targets that don't inherit framework aconfig libs (i.e., those that don't set
// `platform_apis: true`) must manually link them.
diff --git a/quickstep/dagger/LauncherAppComponent.java b/quickstep/dagger/LauncherAppComponent.java
index bd6008e..068f01c 100644
--- a/quickstep/dagger/LauncherAppComponent.java
+++ b/quickstep/dagger/LauncherAppComponent.java
@@ -18,6 +18,7 @@
import com.android.quickstep.dagger.QuickStepModule;
+import com.android.quickstep.dagger.QuickstepBaseAppComponent;
import dagger.Component;
@@ -26,7 +27,7 @@
*/
@LauncherAppSingleton
@Component(modules = QuickStepModule.class)
-public interface LauncherAppComponent extends LauncherBaseAppComponent {
+public interface LauncherAppComponent extends QuickstepBaseAppComponent {
/** Builder for quickstep LauncherAppComponent. */
@Component.Builder
interface Builder extends LauncherBaseAppComponent.Builder {
diff --git a/quickstep/res/layout/bubblebar_flyout.xml b/quickstep/res/layout/bubblebar_flyout.xml
index ff5047f..fc1e914 100644
--- a/quickstep/res/layout/bubblebar_flyout.xml
+++ b/quickstep/res/layout/bubblebar_flyout.xml
@@ -20,11 +20,12 @@
<ImageView
android:id="@+id/bubble_flyout_avatar"
- android:layout_width="36dp"
+ android:layout_width="50dp"
android:layout_height="36dp"
- android:padding="@dimen/bubblebar_flyout_avatar_message_space"
+ android:paddingEnd="@dimen/bubblebar_flyout_avatar_message_space"
android:scaleType="centerInside"
app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:src="#ff0000"/>
diff --git a/quickstep/res/values-night/colors.xml b/quickstep/res/values-night/colors.xml
index 2052446..98e4871 100644
--- a/quickstep/res/values-night/colors.xml
+++ b/quickstep/res/values-night/colors.xml
@@ -25,7 +25,7 @@
<color name="all_set_page_background">@android:color/system_neutral1_900</color>
<!-- Turn on work apps button -->
- <color name="work_turn_on_stroke">?androidprv:attr/colorAccentSecondaryVariant</color>
+ <color name="work_turn_on_stroke">?attr/materialColorPrimary</color>
<color name="work_fab_bg_color">?attr/materialColorPrimaryFixedDim</color>
<color name="work_fab_icon_color">?attr/materialColorOnPrimaryFixed</color>
</resources>
\ No newline at end of file
diff --git a/quickstep/res/values/colors.xml b/quickstep/res/values/colors.xml
index 0bb971e..4c48bd3 100644
--- a/quickstep/res/values/colors.xml
+++ b/quickstep/res/values/colors.xml
@@ -94,7 +94,7 @@
<color name="lottie_yellow600">#f9ab00</color>
<!-- Turn on work apps button -->
- <color name="work_turn_on_stroke">?androidprv:attr/colorAccentPrimaryVariant</color>
+ <color name="work_turn_on_stroke">?attr/materialColorPrimary</color>
<color name="work_fab_bg_color">?attr/materialColorPrimaryFixedDim</color>
<color name="work_fab_icon_color">?attr/materialColorOnPrimaryFixed</color>
</resources>
\ No newline at end of file
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index e99e9b5..8957e0d 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -480,11 +480,15 @@
<dimen name="bubble_expanded_view_drop_target_margin">16dp</dimen>
<!-- Bubble bar flyout view -->
- <dimen name="bubblebar_flyout_padding_horizontal">14dp</dimen>
- <dimen name="bubblebar_flyout_padding_vertical">10dp</dimen>
+ <dimen name="bubblebar_flyout_padding">16dp</dimen>
<dimen name="bubblebar_flyout_elevation">4dp</dimen>
- <dimen name="bubblebar_flyout_avatar_message_space">6dp</dimen>
- <dimen name="bubblebar_flyout_max_width">96dp</dimen>
+ <dimen name="bubblebar_flyout_avatar_message_space">14dp</dimen>
+ <dimen name="bubblebar_flyout_min_width">238dp</dimen>
+ <dimen name="bubblebar_flyout_max_width">276dp</dimen>
+ <dimen name="bubblebar_flyout_triangle_width">12dp</dimen>
+ <dimen name="bubblebar_flyout_triangle_height">10dp</dimen>
+ <dimen name="bubblebar_flyout_triangle_overlap_amount">1dp</dimen>
+ <dimen name="bubblebar_flyout_triangle_radius">2dp</dimen>
<!-- Launcher splash screen -->
<!-- Note: keep this value in sync with the WindowManager/Shell dimens.xml -->
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
index f29980b..4e6d00a 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
@@ -16,9 +16,9 @@
package com.android.launcher3.statehandlers;
import static android.view.View.VISIBLE;
+import static android.window.flags.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY;
import android.content.Context;
import android.os.Debug;
@@ -167,7 +167,8 @@
notifyDesktopVisibilityListeners(areDesktopTasksVisibleNow);
}
- if (!WALLPAPER_ACTIVITY.isEnabled(mContext) && wasVisible != isVisible) {
+ if (!ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
+ && wasVisible != isVisible) {
// TODO: b/333533253 - Remove after flag rollout
if (mVisibleDesktopTasksCount > 0) {
setLauncherViewsVisibility(View.INVISIBLE);
@@ -225,7 +226,7 @@
notifyDesktopVisibilityListeners(areDesktopTasksVisibleNow);
}
- if (WALLPAPER_ACTIVITY.isEnabled(mContext)) {
+ if (ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()) {
return;
}
// TODO: b/333533253 - Clean up after flag rollout
@@ -341,7 +342,7 @@
if (mContext == null) {
return;
}
- if (WALLPAPER_ACTIVITY.isEnabled(mContext)) {
+ if (ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()) {
return;
}
if (DEBUG) {
@@ -376,7 +377,7 @@
if (mContext == null) {
return;
}
- if (WALLPAPER_ACTIVITY.isEnabled(mContext)) {
+ if (ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()) {
return;
}
if (DEBUG) {
@@ -396,7 +397,7 @@
if (mContext == null) {
return;
}
- if (WALLPAPER_ACTIVITY.isEnabled(mContext)) {
+ if (ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()) {
return;
}
if (DEBUG) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 94ca887..1bebfbd 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -15,11 +15,12 @@
*/
package com.android.launcher3.taskbar;
+import static android.window.flags.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY;
+
import static com.android.launcher3.QuickstepTransitionManager.TRANSIENT_TASKBAR_TRANSITION_DURATION;
import static com.android.launcher3.statemanager.BaseState.FLAG_NON_INTERACTIVE;
import static com.android.launcher3.taskbar.TaskbarEduTooltipControllerKt.TOOLTIP_STEP_FEATURES;
import static com.android.launcher3.taskbar.TaskbarLauncherStateController.FLAG_VISIBLE;
-import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY;
import android.animation.Animator;
import android.animation.AnimatorSet;
@@ -242,7 +243,7 @@
return null;
}
- if (!WALLPAPER_ACTIVITY.isEnabled(mLauncher)
+ if (!ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
&& mControllers.taskbarDesktopModeController.getAreDesktopTasksVisible()) {
// TODO: b/333533253 - Remove after flag rollout
isVisible = false;
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index e9bd30a..2ac5793 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -400,12 +400,6 @@
}
};
mSeparateWindowParent.recreateControllers();
- if (com.android.wm.shell.Flags.enableBubbleBarInPersistentTaskBar()
- && mControllers.bubbleControllers.isPresent()) {
- BubbleBarLocation bubblesLocation = mControllers.bubbleControllers.get()
- .bubbleBarViewController.getBubbleBarLocation();
- onBubbleBarLocationUpdated(bubblesLocation);
- }
}
private void initButtons(ViewGroup navContainer, ViewGroup endContainer,
@@ -1223,6 +1217,16 @@
return (int) navBarTargetStartX - mNavButtonContainer.getLeft();
}
+ /** Adjusts the navigation buttons layout position according to the bubble bar location. */
+ public void onTaskbarLayoutChange() {
+ if (com.android.wm.shell.Flags.enableBubbleBarInPersistentTaskBar()
+ && mControllers.bubbleControllers.isPresent()) {
+ BubbleBarLocation bubblesLocation = mControllers.bubbleControllers.get()
+ .bubbleBarViewController.getBubbleBarLocation();
+ onBubbleBarLocationUpdated(bubblesLocation);
+ }
+ }
+
private class RotationButtonListener implements RotationButton.RotationButtonUpdatesCallback {
@Override
public void onVisibilityChanged(boolean isVisible) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/NewWindowTaskbarShortcut.kt b/quickstep/src/com/android/launcher3/taskbar/NewWindowTaskbarShortcut.kt
new file mode 100644
index 0000000..dc66e0b
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/NewWindowTaskbarShortcut.kt
@@ -0,0 +1,47 @@
+/*
+ * 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.taskbar
+
+import android.content.Context
+import android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK
+import android.view.View
+import com.android.launcher3.AbstractFloatingView
+import com.android.launcher3.R
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.popup.SystemShortcut
+import com.android.launcher3.views.ActivityContext
+
+/**
+ * A single menu item shortcut to execute creating a new instance of an app. Default interaction for
+ * [onClick] is to launch the app in full screen or as a floating window in Desktop Mode.
+ */
+class NewWindowTaskbarShortcut<T>(target: T, itemInfo: ItemInfo?, originalView: View?) :
+ SystemShortcut<T>(
+ R.drawable.desktop_mode_ic_taskbar_menu_new_window,
+ R.string.new_window_option_taskbar,
+ target,
+ itemInfo,
+ originalView
+ ) where T : Context?, T : ActivityContext? {
+
+ override fun onClick(v: View?) {
+ val intent = mItemInfo.intent ?: return
+ intent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK)
+ mTarget?.startActivitySafely(v, intent, mItemInfo)
+ AbstractFloatingView.closeAllOpenViews(mTarget)
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index e301dc4..876221b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -300,6 +300,7 @@
stashController.updateStateForFlag(FLAG_IN_APP, false);
updateStateForFlag(FLAG_TRANSITION_TO_VISIBLE, true);
+ mLauncherState = toState;
animatorSet.play(stashController.createApplyStateAnimator(duration));
animatorSet.play(applyState(duration, false));
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 1b4db7a..78e7b47 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -60,6 +60,7 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.contextualeducation.ContextualEduStatsManager;
import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarNavButtonCallbacks;
@@ -247,6 +248,7 @@
context,
navCallbacks,
SystemUiProxy.INSTANCE.get(mContext),
+ ContextualEduStatsManager.INSTANCE.get(mContext),
new Handler(),
AssistUtils.newInstance(mContext));
mComponentCallbacks = new ComponentCallbacks() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
index 5024cd8..bdefea6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
@@ -250,6 +250,7 @@
Map<PackageUserKey, Integer> packageUserKeytoUidMap) {
Preconditions.assertUIThread();
mControllers.taskbarAllAppsController.setApps(apps, flags, packageUserKeytoUidMap);
+ mControllers.taskbarPopupController.setApps(apps);
}
protected void dumpLogs(String prefix, PrintWriter pw) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
index 872a4d0..15c35b6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
@@ -45,12 +45,14 @@
import androidx.annotation.StringRes;
import com.android.launcher3.R;
+import com.android.launcher3.contextualeducation.ContextualEduStatsManager;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskUtils;
import com.android.quickstep.util.AssistUtils;
+import com.android.systemui.contextualeducation.GestureType;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
import java.io.PrintWriter;
@@ -109,6 +111,7 @@
private final Context mContext;
private final TaskbarNavButtonCallbacks mCallbacks;
private final SystemUiProxy mSystemUiProxy;
+ private final ContextualEduStatsManager mContextualEduStatsManager;
private final Handler mHandler;
private final AssistUtils mAssistUtils;
@Nullable private StatsLogManager mStatsLogManager;
@@ -119,11 +122,13 @@
Context context,
TaskbarNavButtonCallbacks callbacks,
SystemUiProxy systemUiProxy,
+ ContextualEduStatsManager contextualEduStatsManager,
Handler handler,
AssistUtils assistUtils) {
mContext = context;
mCallbacks = callbacks;
mSystemUiProxy = systemUiProxy;
+ mContextualEduStatsManager = contextualEduStatsManager;
mHandler = handler;
mAssistUtils = assistUtils;
}
@@ -137,14 +142,20 @@
switch (buttonType) {
case BUTTON_BACK:
logEvent(LAUNCHER_TASKBAR_BACK_BUTTON_TAP);
+ mContextualEduStatsManager.updateEduStats(/* isTrackpadGesture= */ false,
+ GestureType.BACK);
executeBack();
break;
case BUTTON_HOME:
logEvent(LAUNCHER_TASKBAR_HOME_BUTTON_TAP);
+ mContextualEduStatsManager.updateEduStats(/* isTrackpadGesture= */ false,
+ GestureType.HOME);
navigateHome();
break;
case BUTTON_RECENTS:
logEvent(LAUNCHER_TASKBAR_OVERVIEW_BUTTON_TAP);
+ mContextualEduStatsManager.updateEduStats(/* isTrackpadGesture= */ false,
+ GestureType.OVERVIEW);
navigateToOverview();
break;
case BUTTON_IME_SWITCH:
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
index 2cee77d..70d4bb1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.taskbar;
+import static com.android.launcher3.model.data.AppInfo.COMPONENT_KEY_COMPARATOR;
import static com.android.launcher3.util.SplitConfigurationOptions.getLogEventForPosition;
import android.content.Intent;
@@ -29,11 +30,13 @@
import com.android.internal.logging.InstanceId;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.Flags;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
import com.android.launcher3.dot.FolderDotInfo;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -51,9 +54,11 @@
import com.android.launcher3.views.ActivityContext;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.LogUtils;
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
@@ -79,6 +84,7 @@
// Initialized in init.
private TaskbarControllers mControllers;
private boolean mAllowInitialSplitSelection;
+ private AppInfo[] mAppInfosList;
public TaskbarPopupController(TaskbarActivityContext context) {
mContext = context;
@@ -195,6 +201,10 @@
if (com.android.wm.shell.Flags.enableBubbleAnything()) {
shortcuts.add(BUBBLE);
}
+ if (Flags.enableMultiInstanceMenuTaskbar()
+ && DesktopModeStatus.canEnterDesktopMode(mContext)) {
+ shortcuts.addAll(getMultiInstanceMenuOptions().toList());
+ }
return shortcuts.stream();
}
@@ -258,7 +268,55 @@
originalView, position, mAllowInitialSplitSelection);
}
- /**
+ /**
+ * Set the list of AppInfos to be able to pull from later
+ */
+ public void setApps(AppInfo[] apps) {
+ mAppInfosList = apps;
+ }
+
+ /**
+ * Finds and returns an AppInfo object from a list, using its ComponentKey for identification.
+ * Based off of {@link com.android.launcher3.allapps.AllAppsStore#getApp(ComponentKey)}
+ * since we cannot access AllAppsStore from here.
+ */
+ public AppInfo getApp(ComponentKey key) {
+ if (key == null) {
+ return null;
+ }
+ AppInfo tempInfo = new AppInfo();
+ tempInfo.componentName = key.componentName;
+ tempInfo.user = key.user;
+ int index = Arrays.binarySearch(mAppInfosList, tempInfo, COMPONENT_KEY_COMPARATOR);
+ return index < 0 ? null : mAppInfosList[index];
+ }
+
+ /**
+ * Returns a stream of Multi Instance menu options if an app supports it.
+ */
+ Stream<SystemShortcut.Factory<BaseTaskbarContext>> getMultiInstanceMenuOptions() {
+ SystemShortcut.Factory<BaseTaskbarContext> factory = createNewWindowShortcutFactory();
+ return factory != null ? Stream.of(factory) : Stream.empty();
+
+ }
+
+ /**
+ * Creates a factory function representing a "New Window" menu item only if the calling app
+ * supports multi-instance.
+ * @return A factory function to be used in populating the long-press menu.
+ */
+ SystemShortcut.Factory<BaseTaskbarContext> createNewWindowShortcutFactory() {
+ return (context, itemInfo, originalView) -> {
+ ComponentKey key = itemInfo.getComponentKey();
+ AppInfo app = getApp(key);
+ if (app != null && app.supportsMultiInstance()) {
+ return new NewWindowTaskbarShortcut<>(context, itemInfo, originalView);
+ }
+ return null;
+ };
+ }
+
+ /**
* A single menu item ("Split left," "Split right," or "Split top") that executes a split
* from the taskbar, as if the user performed a drag and drop split.
* Includes an onClick method that initiates the actual split.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
index 72bdafe..57d4dbb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
@@ -16,6 +16,7 @@
package com.android.launcher3.taskbar
import android.content.Context
+import android.window.flags.DesktopModeFlags
import androidx.annotation.VisibleForTesting
import com.android.launcher3.Flags.enableRecentsInTaskbar
import com.android.launcher3.model.data.ItemInfo
@@ -26,7 +27,6 @@
import com.android.quickstep.RecentsModel
import com.android.quickstep.util.DesktopTask
import com.android.quickstep.util.GroupTask
-import com.android.wm.shell.shared.desktopmode.DesktopModeFlags
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
import java.io.PrintWriter
@@ -40,7 +40,7 @@
var canShowRunningApps =
DesktopModeStatus.canEnterDesktopMode(context) &&
- DesktopModeFlags.TASKBAR_RUNNING_APPS.isEnabled(context)
+ DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS.isTrue
@VisibleForTesting
set(isEnabledFromTest) {
field = isEnabledFromTest
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index b663ccb..0a67ac2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -140,10 +140,6 @@
private final AnimatedFloat mTaskbarIconTranslationYForPinning = new AnimatedFloat(
this::updateTranslationY);
- private final View.OnLayoutChangeListener mTaskbarViewLayoutChangeListener =
- (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom)
- -> updateTaskbarIconTranslationXForPinning();
-
private AnimatedFloat mTaskbarNavButtonTranslationY;
private AnimatedFloat mTaskbarNavButtonTranslationYForInAppDisplay;
@@ -158,6 +154,12 @@
// Initialized in init.
private TaskbarControllers mControllers;
+ private final View.OnLayoutChangeListener mTaskbarViewLayoutChangeListener =
+ (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+ updateTaskbarIconTranslationXForPinning();
+ mControllers.navbarButtonsViewController.onTaskbarLayoutChange();
+ };
+
// Animation to align icons with Launcher, created lazily. This allows the controller to be
// active only during the animation and does not need to worry about layout changes.
private AnimatorPlaybackController mIconAlignControllerLazy = null;
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
index 152dcf7..4939c99 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
@@ -28,12 +28,12 @@
) {
private var flyout: BubbleBarFlyoutView? = null
- val horizontalMargin =
+ private val horizontalMargin =
container.context.resources.getDimensionPixelSize(R.dimen.transient_taskbar_bottom_margin)
fun setUpFlyout(message: BubbleBarFlyoutMessage) {
flyout?.let(container::removeView)
- val flyout = BubbleBarFlyoutView(container.context)
+ val flyout = BubbleBarFlyoutView(container.context, onLeft = positioner.isOnLeft)
flyout.translationY = positioner.targetTy
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
index d3dc3f8..4b91f46 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
@@ -21,14 +21,17 @@
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
+import android.graphics.Path
import android.view.LayoutInflater
import android.widget.ImageView
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import com.android.launcher3.R
+import com.android.launcher3.popup.RoundedArrowDrawable
/** The flyout view used to notify the user of a new bubble notification. */
-class BubbleBarFlyoutView(context: Context) : ConstraintLayout(context) {
+class BubbleBarFlyoutView(context: Context, private val onLeft: Boolean) :
+ ConstraintLayout(context) {
private val sender: TextView by
lazy(LazyThreadSafetyMode.NONE) { findViewById(R.id.bubble_flyout_name) }
@@ -39,9 +42,36 @@
private val message: TextView by
lazy(LazyThreadSafetyMode.NONE) { findViewById(R.id.bubble_flyout_text) }
- private val flyoutHorizontalPadding by
+ private val flyoutPadding by
lazy(LazyThreadSafetyMode.NONE) {
- context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_padding_horizontal)
+ context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_padding)
+ }
+
+ private val triangleHeight by
+ lazy(LazyThreadSafetyMode.NONE) {
+ context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_triangle_height)
+ }
+
+ private val triangleOverlap by
+ lazy(LazyThreadSafetyMode.NONE) {
+ context.resources.getDimensionPixelSize(
+ R.dimen.bubblebar_flyout_triangle_overlap_amount
+ )
+ }
+
+ private val triangleWidth by
+ lazy(LazyThreadSafetyMode.NONE) {
+ context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_triangle_width)
+ }
+
+ private val triangleRadius by
+ lazy(LazyThreadSafetyMode.NONE) {
+ context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_triangle_radius)
+ }
+
+ private val minFlyoutWidth by
+ lazy(LazyThreadSafetyMode.NONE) {
+ context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_min_width)
}
private val maxFlyoutWidth by
@@ -50,6 +80,7 @@
}
private val cornerRadius: Float
+ private val triangle: Path = Path()
private var backgroundColor = Color.BLACK
/**
@@ -69,13 +100,19 @@
clipChildren = false
clipToPadding = false
- val horizontalPadding =
- context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_padding_horizontal)
- val verticalPadding =
- context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_padding_vertical)
- setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding)
+ val padding = context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_padding)
+ // add extra padding to the bottom of the view to include the triangle
+ setPadding(padding, padding, padding, padding + triangleHeight - triangleOverlap)
translationZ =
context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_elevation).toFloat()
+
+ RoundedArrowDrawable.addDownPointingRoundedTriangleToPath(
+ triangleWidth.toFloat(),
+ triangleHeight.toFloat(),
+ triangleRadius.toFloat(),
+ triangle,
+ )
+
applyConfigurationColors(resources.configuration)
}
@@ -88,15 +125,28 @@
avatar.visibility = GONE
}
- val maxTextViewWidth = maxFlyoutWidth - flyoutHorizontalPadding * 2
+ val minTextViewWidth: Int
+ val maxTextViewWidth: Int
+ if (avatar.visibility == VISIBLE) {
+ minTextViewWidth = minFlyoutWidth - avatar.width - flyoutPadding * 2
+ maxTextViewWidth = maxFlyoutWidth - avatar.width - flyoutPadding * 2
+ } else {
+ // when there's no avatar, the width of the text view is constant, so we're setting the
+ // min and max to the same value
+ minTextViewWidth = minFlyoutWidth - flyoutPadding * 2
+ maxTextViewWidth = minTextViewWidth
+ }
+
if (flyoutMessage.senderName.isEmpty()) {
sender.visibility = GONE
} else {
+ sender.minWidth = minTextViewWidth
sender.maxWidth = maxTextViewWidth
sender.text = flyoutMessage.senderName
sender.visibility = VISIBLE
}
+ message.minWidth = minTextViewWidth
message.maxWidth = maxTextViewWidth
message.text = flyoutMessage.message
}
@@ -106,14 +156,23 @@
0f,
0f,
width.toFloat(),
- height.toFloat(),
+ height.toFloat() - triangleHeight + triangleOverlap,
cornerRadius,
cornerRadius,
backgroundPaint,
)
+ drawTriangle(canvas)
super.onDraw(canvas)
}
+ private fun drawTriangle(canvas: Canvas) {
+ canvas.save()
+ val triangleX = if (onLeft) cornerRadius else width - cornerRadius - triangleWidth
+ canvas.translate(triangleX, (height - triangleHeight).toFloat())
+ canvas.drawPath(triangle, backgroundPaint)
+ canvas.restore()
+ }
+
private fun applyConfigurationColors(configuration: Configuration) {
val nightModeFlags = configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
val isNightModeOn = nightModeFlags == Configuration.UI_MODE_NIGHT_YES
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
index 93cbdc7..26a1322 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
@@ -29,7 +29,6 @@
import android.widget.RemoteViews;
import android.window.SplashScreen;
-import com.android.launcher3.Utilities;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.util.ActivityOptionsWrapper;
@@ -66,7 +65,7 @@
Pair<Intent, ActivityOptions> options = remoteResponse.getLaunchOptions(view);
ActivityOptionsWrapper activityOptions = mLauncher.getAppTransitionManager()
.getActivityLaunchOptions(hostView, (ItemInfo) hostView.getTag());
- if (Utilities.ATLEAST_S && !pendingIntent.isActivity()) {
+ if (!pendingIntent.isActivity()) {
// In the event this pending intent eventually launches an activity, i.e. a trampoline,
// use the Quickstep transition animation.
try {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 1f5cd3a..e80e838 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -19,6 +19,7 @@
import static android.os.Trace.TRACE_TAG_APP;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE;
import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED;
+import static android.window.flags.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY;
import static com.android.app.animation.Interpolators.EMPHASIZED;
import static com.android.internal.jank.Cuj.CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_WORKSPACE;
@@ -64,7 +65,6 @@
import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
import static com.android.quickstep.util.SplitAnimationTimings.TABLET_HOME_TO_SPLIT;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
-import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_50_50;
import android.animation.Animator;
@@ -1003,7 +1003,7 @@
@Override
public void setResumed() {
DesktopVisibilityController desktopVisibilityController = getDesktopVisibilityController();
- if (!WALLPAPER_ACTIVITY.isEnabled(this)
+ if (!ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
&& desktopVisibilityController != null
&& desktopVisibilityController.areDesktopTasksVisible()
&& !desktopVisibilityController.isRecentsGestureInProgress()) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
index 11e0ed5..1d9e492 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
@@ -45,6 +45,7 @@
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.contextualeducation.ContextualEduStatsManager;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.touch.SingleAxisSwipeDetector;
import com.android.launcher3.util.DisplayController;
@@ -53,6 +54,7 @@
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.OverviewToHomeAnim;
import com.android.quickstep.views.RecentsView;
+import com.android.systemui.contextualeducation.GestureType;
import java.util.function.BiConsumer;
@@ -219,6 +221,8 @@
}
if (mStartState != mEndState) {
logHomeGesture();
+ ContextualEduStatsManager.INSTANCE.get(mLauncher).updateEduStats(
+ mSwipeDetector.isTrackpadGesture(), GestureType.HOME);
}
AbstractFloatingView topOpenView = AbstractFloatingView.getTopOpenView(mLauncher);
if (topOpenView != null) {
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 240d6ad..a6d651c 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -92,6 +92,7 @@
import android.view.animation.Interpolator;
import android.widget.Toast;
import android.window.PictureInPictureSurfaceTransaction;
+import android.window.flags.DesktopModeFlags;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -152,7 +153,6 @@
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.wm.shell.shared.TransactionPool;
-import com.android.wm.shell.shared.desktopmode.DesktopModeFlags;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.shared.startingsurface.SplashScreenExitAnimationUtils;
@@ -1256,8 +1256,8 @@
? mRecentsView.getCurrentPageTaskView() : null;
if (DesktopModeStatus.canEnterDesktopMode(mContext)
- && !(DesktopModeFlags.WALLPAPER_ACTIVITY.isEnabled(mContext)
- && DesktopModeFlags.QUICK_SWITCH.isEnabled(mContext))) {
+ && !(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
+ && DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_QUICK_SWITCH.isTrue())) {
if ((nextPageTaskView instanceof DesktopTaskView
|| currentPageTaskView instanceof DesktopTaskView)
&& endTarget == NEW_TASK) {
@@ -1423,8 +1423,8 @@
};
if (DesktopModeStatus.canEnterDesktopMode(mContext)
- && !(DesktopModeFlags.WALLPAPER_ACTIVITY.isEnabled(mContext)
- && DesktopModeFlags.QUICK_SWITCH.isEnabled(mContext))) {
+ && !(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
+ && DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_QUICK_SWITCH.isTrue())) {
if (mRecentsView != null && (mRecentsView.getCurrentPageTaskView() != null
&& !(mRecentsView.getCurrentPageTaskView() instanceof DesktopTaskView))) {
ActiveGestureLog.INSTANCE.trackEvent(ActiveGestureErrorDetector.GestureEvent
@@ -2249,8 +2249,8 @@
});
if (DesktopModeStatus.canEnterDesktopMode(mContext)
- && !(DesktopModeFlags.WALLPAPER_ACTIVITY.isEnabled(mContext)
- && DesktopModeFlags.QUICK_SWITCH.isEnabled(mContext))) {
+ && !(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
+ && DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_QUICK_SWITCH.isTrue())) {
if (mRecentsView.getNextPageTaskView() instanceof DesktopTaskView
|| mRecentsView.getCurrentPageTaskView() instanceof DesktopTaskView) {
mRecentsViewScrollLinked = false;
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
index f92c557..520bec3 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
@@ -80,14 +80,6 @@
*/
private var keyboardTaskFocusIndex = -1
- /**
- * Whether we should incoming toggle commands while a previous toggle command is still ongoing.
- * This serves as a rate-limiter to prevent overlapping animations that can clobber each other
- * and prevent clean-up callbacks from running. This thus prevents a recurring set of bugs with
- * janky recents animations and unresponsive home and overview buttons.
- */
- private var waitForToggleCommandComplete = false
-
private val activityInterface: BaseActivityInterface<*, *>
get() = overviewComponentObserver.activityInterface
@@ -174,12 +166,6 @@
*/
@VisibleForTesting
fun executeCommand(command: CommandInfo, onCallbackResult: () -> Unit): Boolean {
- // This shouldn't happen if we execute 1 command per time.
- if (waitForToggleCommandComplete && command.type == TOGGLE) {
- Log.d(TAG, "executeCommand: $command - waiting for toggle command complete")
- return true
- }
-
val recentsView = visibleRecentsView
Log.d(TAG, "executeCommand: $command - visibleRecentsView: $recentsView")
return if (recentsView != null) {
@@ -251,7 +237,6 @@
): Boolean {
var callbackList: RunnableList? = null
if (taskView != null) {
- waitForToggleCommandComplete = true
taskView.isEndQuickSwitchCuj = true
callbackList = taskView.launchWithAnimation()
}
@@ -260,13 +245,11 @@
callbackList.add {
Log.d(TAG, "launching task callback: $command")
onCallbackResult()
- waitForToggleCommandComplete = false
}
Log.d(TAG, "launching task - waiting for callback: $command")
return false
} else {
recents.startHome()
- waitForToggleCommandComplete = false
return true
}
}
@@ -517,7 +500,6 @@
pw.println(" pendingCommandType=${commandQueue.first().type}")
}
pw.println(" keyboardTaskFocusIndex=$keyboardTaskFocusIndex")
- pw.println(" waitForToggleCommandComplete=$waitForToggleCommandComplete")
}
@VisibleForTesting
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index b4bd3e3..f9b4dab 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -51,6 +51,7 @@
import android.window.RemoteTransition;
import android.window.TaskSnapshot;
import android.window.TransitionFilter;
+import android.window.flags.DesktopModeFlags;
import androidx.annotation.MainThread;
import androidx.annotation.Nullable;
@@ -85,14 +86,13 @@
import com.android.wm.shell.desktopmode.IDesktopTaskListener;
import com.android.wm.shell.draganddrop.IDragAndDrop;
import com.android.wm.shell.onehanded.IOneHanded;
-import com.android.wm.shell.recents.IRecentsAnimationController;
-import com.android.wm.shell.recents.IRecentsAnimationRunner;
import com.android.wm.shell.recents.IRecentTasks;
import com.android.wm.shell.recents.IRecentTasksListener;
+import com.android.wm.shell.recents.IRecentsAnimationController;
+import com.android.wm.shell.recents.IRecentsAnimationRunner;
import com.android.wm.shell.shared.GroupedRecentTaskInfo;
import com.android.wm.shell.shared.IShellTransitions;
import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
-import com.android.wm.shell.shared.desktopmode.DesktopModeFlags;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource;
import com.android.wm.shell.shared.split.SplitBounds;
@@ -1395,7 +1395,7 @@
private boolean shouldEnableRunningTasksForDesktopMode() {
return DesktopModeStatus.canEnterDesktopMode(mContext)
- && DesktopModeFlags.TASKBAR_RUNNING_APPS.isEnabled(mContext);
+ && DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS.isTrue();
}
private boolean handleMessageAsync(Message msg) {
diff --git a/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java b/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java
index db29636..08345b8 100644
--- a/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java
+++ b/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java
@@ -15,10 +15,8 @@
*/
package com.android.quickstep.dagger;
-import com.android.quickstep.logging.LoggingModule;
-
import dagger.Module;
-@Module(includes = {LoggingModule.class})
+@Module
public class QuickStepModule {
}
diff --git a/quickstep/src/com/android/quickstep/dagger/QuickstepBaseAppComponent.java b/quickstep/src/com/android/quickstep/dagger/QuickstepBaseAppComponent.java
new file mode 100644
index 0000000..f2d5715
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/dagger/QuickstepBaseAppComponent.java
@@ -0,0 +1,33 @@
+/*
+ * 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.dagger;
+
+import com.android.launcher3.dagger.LauncherAppComponent;
+import com.android.launcher3.dagger.LauncherBaseAppComponent;
+import com.android.quickstep.logging.SettingsChangeLogger;
+
+/**
+ * Launcher Quickstep base component for Dagger injection.
+ *
+ * This class is not actually annotated as a Dagger component, since it is not used directly as one.
+ * Doing so generates unnecessary code bloat.
+ *
+ * See {@link LauncherAppComponent} for the one actually used.
+ */
+public interface QuickstepBaseAppComponent extends LauncherBaseAppComponent {
+ SettingsChangeLogger getSettingsChangeLogger();
+}
diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
index b56958a..f7f3157 100644
--- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
@@ -219,7 +219,7 @@
}
private void startBackgroundAnimation(boolean forTablet) {
- if (!Utilities.ATLEAST_S || mVibrator == null) {
+ if (mVibrator == null) {
return;
}
boolean supportsThud = mVibrator.areAllPrimitivesSupported(
diff --git a/quickstep/src/com/android/quickstep/logging/LoggingModule.java b/quickstep/src/com/android/quickstep/logging/LoggingModule.java
deleted file mode 100644
index 8fdf3c7..0000000
--- a/quickstep/src/com/android/quickstep/logging/LoggingModule.java
+++ /dev/null
@@ -1,34 +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.logging;
-
-import android.content.Context;
-
-import com.android.launcher3.dagger.ApplicationContext;
-import com.android.launcher3.dagger.LauncherAppSingleton;
-
-import dagger.Module;
-import dagger.Provides;
-
-@Module
-public class LoggingModule {
- @Provides
- @LauncherAppSingleton
- SettingsChangeLogger provideSettingsChangeLogger(@ApplicationContext Context context) {
- return SettingsChangeLogger.INSTANCE.get(context);
- }
-}
diff --git a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
index 717f6c8..995635f 100644
--- a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
+++ b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
@@ -43,16 +43,21 @@
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.R;
+import com.android.launcher3.dagger.ApplicationContext;
+import com.android.launcher3.dagger.LauncherAppSingleton;
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
import com.android.launcher3.model.DeviceGridState;
+import com.android.launcher3.util.DaggerSingletonObject;
+import com.android.launcher3.util.DaggerSingletonTracker;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.Info;
-import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.ExecutorUtil;
import com.android.launcher3.util.NavigationMode;
import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.SettingsCache;
+import com.android.quickstep.dagger.QuickstepBaseAppComponent;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -60,9 +65,12 @@
import java.io.IOException;
import java.util.Optional;
+import javax.inject.Inject;
+
/**
* Utility class to log launcher settings changes
*/
+@LauncherAppSingleton
public class SettingsChangeLogger implements
DisplayController.DisplayInfoChangeListener, OnSharedPreferenceChangeListener,
SafeCloseable {
@@ -70,8 +78,8 @@
/**
* Singleton instance
*/
- public static MainThreadInitializedObject<SettingsChangeLogger> INSTANCE =
- new MainThreadInitializedObject<>(SettingsChangeLogger::new);
+ public static DaggerSingletonObject<SettingsChangeLogger> INSTANCE =
+ new DaggerSingletonObject<>(QuickstepBaseAppComponent::getSettingsChangeLogger);
private static final String TAG = "SettingsChangeLogger";
private static final String BOOLEAN_PREF = "SwitchPreference";
@@ -84,25 +92,31 @@
private StatsLogManager.LauncherEvent mNotificationDotsEvent;
private StatsLogManager.LauncherEvent mHomeScreenSuggestionEvent;
- private SettingsChangeLogger(Context context) {
- this(context, StatsLogManager.newInstance(context));
+ @Inject
+ SettingsChangeLogger(@ApplicationContext Context context, DaggerSingletonTracker tracker) {
+ this(context, StatsLogManager.newInstance(context), tracker);
}
@VisibleForTesting
- SettingsChangeLogger(Context context, StatsLogManager statsLogManager) {
+ SettingsChangeLogger(Context context, StatsLogManager statsLogManager,
+ DaggerSingletonTracker tracker) {
mContext = context;
mStatsLogManager = statsLogManager;
mLoggablePrefs = loadPrefKeys(context);
- DisplayController.INSTANCE.get(context).addChangeListener(this);
- mNavMode = DisplayController.getNavigationMode(context);
- getPrefs(context).registerOnSharedPreferenceChangeListener(this);
- getDevicePrefs(context).registerOnSharedPreferenceChangeListener(this);
+ ExecutorUtil.executeSyncOnMainOrFail(() -> {
+ DisplayController.INSTANCE.get(context).addChangeListener(this);
+ mNavMode = DisplayController.getNavigationMode(context);
- SettingsCache mSettingsCache = SettingsCache.INSTANCE.get(context);
- mSettingsCache.register(NOTIFICATION_BADGING_URI,
- this::onNotificationDotsChanged);
- onNotificationDotsChanged(mSettingsCache.getValue(NOTIFICATION_BADGING_URI));
+ getPrefs(context).registerOnSharedPreferenceChangeListener(this);
+ getDevicePrefs(context).registerOnSharedPreferenceChangeListener(this);
+
+ SettingsCache settingsCache = SettingsCache.INSTANCE.get(context);
+ settingsCache.register(NOTIFICATION_BADGING_URI,
+ this::onNotificationDotsChanged);
+ onNotificationDotsChanged(settingsCache.getValue(NOTIFICATION_BADGING_URI));
+ tracker.addCloseable(this);
+ });
}
private static ArrayMap<String, LoggablePref> loadPrefKeys(Context context) {
@@ -209,6 +223,8 @@
public void close() {
getPrefs(mContext).unregisterOnSharedPreferenceChangeListener(this);
getDevicePrefs(mContext).unregisterOnSharedPreferenceChangeListener(this);
+ SettingsCache settingsCache = SettingsCache.INSTANCE.get(mContext);
+ settingsCache.unregister(NOTIFICATION_BADGING_URI, this::onNotificationDotsChanged);
}
@VisibleForTesting
diff --git a/quickstep/src/com/android/quickstep/views/FloatingWidgetBackgroundView.java b/quickstep/src/com/android/quickstep/views/FloatingWidgetBackgroundView.java
index 4ea7753..f17be05 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingWidgetBackgroundView.java
+++ b/quickstep/src/com/android/quickstep/views/FloatingWidgetBackgroundView.java
@@ -32,7 +32,6 @@
import com.android.launcher3.R;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
-import com.android.launcher3.widget.RoundedCornerEnforcement;
import java.util.stream.IntStream;
@@ -171,8 +170,7 @@
/** Corner radius from source view's outline, or enforced view. */
private static float getOutlineRadius(LauncherAppWidgetHostView hostView, View v) {
- if (RoundedCornerEnforcement.isRoundedCornerEnabled()
- && hostView.hasEnforcedCornerRadius()) {
+ if (hostView.hasEnforcedCornerRadius()) {
return hostView.getEnforcedCornerRadius();
} else if (v.getOutlineProvider() instanceof RemoteViewOutlineProvider
&& v.getClipToOutline()) {
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index d20d0a5..73edb9e 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -16,6 +16,7 @@
package com.android.quickstep.views;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.window.flags.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.CLEAR_ALL_BUTTON;
@@ -26,7 +27,6 @@
import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
import static com.android.launcher3.LauncherState.SPRING_LOADED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_HOME;
-import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY;
import android.annotation.TargetApi;
import android.content.Context;
@@ -268,7 +268,8 @@
super.onGestureAnimationStart(runningTasks, rotationTouchHelper);
DesktopVisibilityController desktopVisibilityController =
mContainer.getDesktopVisibilityController();
- if (!WALLPAPER_ACTIVITY.isEnabled(mContext) && desktopVisibilityController != null) {
+ if (!ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
+ && desktopVisibilityController != null) {
// TODO: b/333533253 - Remove after flag rollout
desktopVisibilityController.setRecentsGestureStart();
}
@@ -291,7 +292,8 @@
}
}
super.onGestureAnimationEnd();
- if (!WALLPAPER_ACTIVITY.isEnabled(mContext) && desktopVisibilityController != null) {
+ if (!ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
+ && desktopVisibilityController != null) {
// TODO: b/333533253 - Remove after flag rollout
desktopVisibilityController.setRecentsGestureEnd(endTarget);
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index bb46a2c..f502e31 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -343,7 +343,7 @@
};
public static final int SCROLL_VIBRATION_PRIMITIVE =
- Utilities.ATLEAST_S ? VibrationEffect.Composition.PRIMITIVE_LOW_TICK : -1;
+ VibrationEffect.Composition.PRIMITIVE_LOW_TICK;
public static final float SCROLL_VIBRATION_PRIMITIVE_SCALE = 0.6f;
public static final VibrationEffect SCROLL_VIBRATION_FALLBACK =
VibrationConstants.EFFECT_TEXTURE_TICK;
diff --git a/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutViewScreenshotTest.kt b/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutViewScreenshotTest.kt
index b1ff4a1..537a755 100644
--- a/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutViewScreenshotTest.kt
+++ b/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutViewScreenshotTest.kt
@@ -56,10 +56,10 @@
)
@Test
- fun bubbleBarFlyoutView_noAvatar() {
- screenshotRule.screenshotTest("bubbleBarFlyoutView_noAvatar") { activity ->
+ fun bubbleBarFlyoutView_noAvatar_onRight() {
+ screenshotRule.screenshotTest("bubbleBarFlyoutView_noAvatar_onRight") { activity ->
activity.actionBar?.hide()
- val flyout = BubbleBarFlyoutView(context)
+ val flyout = BubbleBarFlyoutView(context, onLeft = false)
flyout.setData(
BubbleBarFlyoutMessage(
senderAvatar = null,
@@ -73,10 +73,44 @@
}
@Test
- fun bubbleBarFlyoutView_avatar() {
- screenshotRule.screenshotTest("bubbleBarFlyoutView_avatar") { activity ->
+ fun bubbleBarFlyoutView_noAvatar_onLeft() {
+ screenshotRule.screenshotTest("bubbleBarFlyoutView_noAvatar_onLeft") { activity ->
activity.actionBar?.hide()
- val flyout = BubbleBarFlyoutView(context)
+ val flyout = BubbleBarFlyoutView(context, onLeft = true)
+ flyout.setData(
+ BubbleBarFlyoutMessage(
+ senderAvatar = null,
+ senderName = "sender",
+ message = "message",
+ isGroupChat = false,
+ )
+ )
+ flyout
+ }
+ }
+
+ @Test
+ fun bubbleBarFlyoutView_noAvatar_longMessage() {
+ screenshotRule.screenshotTest("bubbleBarFlyoutView_noAvatar_longMessage") { activity ->
+ activity.actionBar?.hide()
+ val flyout = BubbleBarFlyoutView(context, onLeft = true)
+ flyout.setData(
+ BubbleBarFlyoutMessage(
+ senderAvatar = null,
+ senderName = "sender",
+ message = "really, really, really, really, really long message. like really.",
+ isGroupChat = false,
+ )
+ )
+ flyout
+ }
+ }
+
+ @Test
+ fun bubbleBarFlyoutView_avatar_onRight() {
+ screenshotRule.screenshotTest("bubbleBarFlyoutView_avatar_onRight") { activity ->
+ activity.actionBar?.hide()
+ val flyout = BubbleBarFlyoutView(context, onLeft = false)
flyout.setData(
BubbleBarFlyoutMessage(
senderAvatar = ColorDrawable(Color.RED),
@@ -88,4 +122,38 @@
flyout
}
}
+
+ @Test
+ fun bubbleBarFlyoutView_avatar_onLeft() {
+ screenshotRule.screenshotTest("bubbleBarFlyoutView_avatar_onLeft") { activity ->
+ activity.actionBar?.hide()
+ val flyout = BubbleBarFlyoutView(context, onLeft = true)
+ flyout.setData(
+ BubbleBarFlyoutMessage(
+ senderAvatar = ColorDrawable(Color.RED),
+ senderName = "sender",
+ message = "message",
+ isGroupChat = true,
+ )
+ )
+ flyout
+ }
+ }
+
+ @Test
+ fun bubbleBarFlyoutView_avatar_longMessage() {
+ screenshotRule.screenshotTest("bubbleBarFlyoutView_avatar_longMessage") { activity ->
+ activity.actionBar?.hide()
+ val flyout = BubbleBarFlyoutView(context, onLeft = true)
+ flyout.setData(
+ BubbleBarFlyoutMessage(
+ senderAvatar = ColorDrawable(Color.RED),
+ senderName = "sender",
+ message = "really, really, really, really, really long message. like really.",
+ isGroupChat = true,
+ )
+ )
+ flyout
+ }
+ }
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
index 399aea6..02d6218 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
@@ -20,6 +20,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
@@ -33,11 +34,13 @@
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.launcher3.contextualeducation.ContextualEduStatsManager;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarNavButtonCallbacks;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TouchInteractionService;
import com.android.quickstep.util.AssistUtils;
+import com.android.systemui.contextualeducation.GestureType;
import org.junit.Before;
import org.junit.Test;
@@ -52,6 +55,10 @@
@Mock
SystemUiProxy mockSystemUiProxy;
+
+ @Mock
+ ContextualEduStatsManager mockContextualEduStatsManager;
+
@Mock
TouchInteractionService mockService;
@Mock
@@ -100,6 +107,7 @@
mockService,
mCallbacks,
mockSystemUiProxy,
+ mockContextualEduStatsManager,
mockHandler,
mockAssistUtils);
}
@@ -111,6 +119,13 @@
}
@Test
+ public void testPressBack_updateContextualEduData() {
+ mNavButtonController.onButtonClick(BUTTON_BACK, mockView);
+ verify(mockContextualEduStatsManager, times(1))
+ .updateEduStats(/* isTrackpad= */ eq(false), eq(GestureType.BACK));
+ }
+
+ @Test
public void testPressImeSwitcher() {
mNavButtonController.init(mockTaskbarControllers);
mNavButtonController.onButtonClick(BUTTON_IME_SWITCH, mockView);
@@ -195,12 +210,26 @@
}
@Test
+ public void testPressHome_updateContextualEduData() {
+ mNavButtonController.onButtonClick(BUTTON_HOME, mockView);
+ verify(mockContextualEduStatsManager, times(1))
+ .updateEduStats(/* isTrackpad= */ eq(false), eq(GestureType.HOME));
+ }
+
+ @Test
public void testPressRecents() {
mNavButtonController.onButtonClick(BUTTON_RECENTS, mockView);
assertThat(mOverviewToggleCount).isEqualTo(1);
}
@Test
+ public void testPressRecents_updateContextualEduData() {
+ mNavButtonController.onButtonClick(BUTTON_RECENTS, mockView);
+ verify(mockContextualEduStatsManager, times(1))
+ .updateEduStats(/* isTrackpad= */ eq(false), eq(GestureType.OVERVIEW));
+ }
+
+ @Test
public void testPressRecentsWithScreenPinned_noNavigationToOverview() {
mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
mNavButtonController.onButtonClick(BUTTON_RECENTS, mockView);
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt
index 7c48ea4..0a60774 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt
@@ -34,6 +34,7 @@
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NOTIFICATION_DOT_ENABLED
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_THEMED_ICON_DISABLED
import com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY
+import com.android.launcher3.util.DaggerSingletonTracker
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
@@ -62,6 +63,7 @@
@Mock private lateinit var mMockLogger: StatsLogManager.StatsLogger
@Captor private lateinit var mEventCaptor: ArgumentCaptor<StatsLogManager.EventEnum>
+ @Mock private lateinit var mTracker: DaggerSingletonTracker
private var mDefaultThemedIcons = false
private var mDefaultAllowRotation = false
@@ -79,7 +81,7 @@
// To match the default value of ALLOW_ROTATION
LauncherPrefs.get(mContext).put(item = ALLOW_ROTATION, value = false)
- mSystemUnderTest = SettingsChangeLogger(mContext, mStatsLogManager)
+ mSystemUnderTest = SettingsChangeLogger(mContext, mStatsLogManager, mTracker)
}
@After
@@ -90,7 +92,7 @@
@Test
fun loggingPrefs_correctDefaultValue() {
- val systemUnderTest = SettingsChangeLogger(mContext, mStatsLogManager)
+ val systemUnderTest = SettingsChangeLogger(mContext, mStatsLogManager, mTracker)
assertThat(systemUnderTest.loggingPrefs[ALLOW_ROTATION_PREFERENCE_KEY]!!.defaultValue)
.isFalse()
@@ -117,7 +119,7 @@
LauncherPrefs.get(mContext).put(item = ALLOW_ROTATION, value = true)
// This a new object so the values of mLoggablePrefs will be different
- SettingsChangeLogger(mContext, mStatsLogManager).logSnapshot(mInstanceId)
+ SettingsChangeLogger(mContext, mStatsLogManager, mTracker).logSnapshot(mInstanceId)
verify(mMockLogger, atLeastOnce()).log(mEventCaptor.capture())
val capturedEvents = mEventCaptor.allValues
diff --git a/res/drawable/desktop_mode_ic_taskbar_menu_new_window.xml b/res/drawable/desktop_mode_ic_taskbar_menu_new_window.xml
new file mode 100644
index 0000000..b96a596
--- /dev/null
+++ b/res/drawable/desktop_mode_ic_taskbar_menu_new_window.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20">
+ <path
+ android:pathData="M15 16V14H13V12.5H15V10.5H16.5V12.5H18.5V14H16.5V16H15ZM3.5 17C3.09722 17 2.74306 16.8542 2.4375 16.5625C2.14583 16.2569 2 15.9028 2 15.5V4.5C2 4.08333 2.14583 3.72917 2.4375 3.4375C2.74306 3.14583 3.09722 3 3.5 3H14.5C14.9167 3 15.2708 3.14583 15.5625 3.4375C15.8542 3.72917 16 4.08333 16 4.5V9H14.5V7H3.5V15.5H13.625V17H3.5ZM3.5 5.5H14.5V4.5H3.5V5.5ZM3.5 5.5V4.5V5.5Z"
+ android:fillColor="#1C1C14"/>
+</vector>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index d9f2072..f62384c 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -189,7 +189,7 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrirajte"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Nije uspjelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privatni prostor"</string>
- <string name="private_space_secondary_label" msgid="9203933341714508907">"Dodirnite da biste postavili ili otvorili"</string>
+ <string name="private_space_secondary_label" msgid="9203933341714508907">"Dodirnite za postavljanje ili otvaranje"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Privatno"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Postavke privatnog prostora"</string>
<string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privatno, otključano."</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 3c9135b..ebd68f7 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -117,7 +117,7 @@
<string name="folder_name_format_exact" msgid="8626242716117004803">"ថត៖ <xliff:g id="NAME">%1$s</xliff:g>, ធាតុ <xliff:g id="SIZE">%2$d</xliff:g>"</string>
<string name="folder_name_format_overflow" msgid="4270108890534995199">"ថត៖ <xliff:g id="NAME">%1$s</xliff:g>, ធាតុ <xliff:g id="SIZE">%2$d</xliff:g> ឬច្រើនជាងនេះ"</string>
<string name="app_pair_name_format" msgid="8134106404716224054">"គូកម្មវិធី៖ <xliff:g id="APP1">%1$s</xliff:g> និង <xliff:g id="APP2">%2$s</xliff:g>"</string>
- <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"ផ្ទាំងរូបភាព និងរចនាប័ទ្ម"</string>
+ <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"ផ្ទាំងរូបភាព និងរចនាបថ"</string>
<string name="edit_home_screen" msgid="8947858375782098427">"កែអេក្រង់ដើម"</string>
<string name="settings_button_text" msgid="8873672322605444408">"ការកំណត់ទំព័រដើម"</string>
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"បានបិទដំណើរការដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index fd724a5..9d06021 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -45,6 +45,9 @@
<string name="split_app_info_accessibility">App info for %1$s</string>
<string name="split_app_usage_settings">Usage settings for %1$s</string>
+ <!-- Title for an option to open a new window for a given app -->
+ <string name="new_window_option_taskbar">New Window</string>
+
<!-- App pairs -->
<string name="save_app_pair">Save app pair</string>
<!-- App pair default title -->
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 0bc192d..b0ec9b0 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -448,12 +448,10 @@
.logStart(LAUNCHER_LATENCY_STARTUP_TOTAL_DURATION)
.logStart(LAUNCHER_LATENCY_STARTUP_ACTIVITY_ON_CREATE);
// Only use a hard-coded cookie since we only want to trace this once.
- if (Utilities.ATLEAST_S) {
- Trace.beginAsyncSection(
- DISPLAY_WORKSPACE_TRACE_METHOD_NAME, DISPLAY_WORKSPACE_TRACE_COOKIE);
- Trace.beginAsyncSection(DISPLAY_ALL_APPS_TRACE_METHOD_NAME,
- DISPLAY_ALL_APPS_TRACE_COOKIE);
- }
+ Trace.beginAsyncSection(
+ DISPLAY_WORKSPACE_TRACE_METHOD_NAME, DISPLAY_WORKSPACE_TRACE_COOKIE);
+ Trace.beginAsyncSection(DISPLAY_ALL_APPS_TRACE_METHOD_NAME,
+ DISPLAY_ALL_APPS_TRACE_COOKIE);
TraceHelper.INSTANCE.beginSection(ON_CREATE_EVT);
if (DEBUG_STRICT_MODE) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
@@ -732,13 +730,6 @@
public void onEnterAnimationComplete() {
super.onEnterAnimationComplete();
mRotationHelper.setCurrentTransitionRequest(REQUEST_NONE);
- // Starting with Android S, onEnterAnimationComplete is sent immediately
- // causing the surface to get removed before the animation completed (b/175345344).
- // Instead we rely on next user touch event to remove the view and optionally a callback
- // from system from Android T onwards.
- if (!Utilities.ATLEAST_S) {
- AbstractFloatingView.closeOpenViews(this, false, TYPE_ICON_SURFACE);
- }
}
@Override
@@ -2579,10 +2570,8 @@
public void bindAllApplications(AppInfo[] apps, int flags,
Map<PackageUserKey, Integer> packageUserKeytoUidMap) {
mModelCallbacks.bindAllApplications(apps, flags, packageUserKeytoUidMap);
- if (Utilities.ATLEAST_S) {
- Trace.endAsyncSection(DISPLAY_ALL_APPS_TRACE_METHOD_NAME,
- DISPLAY_ALL_APPS_TRACE_COOKIE);
- }
+ Trace.endAsyncSection(DISPLAY_ALL_APPS_TRACE_METHOD_NAME,
+ DISPLAY_ALL_APPS_TRACE_COOKIE);
}
/**
diff --git a/src/com/android/launcher3/LauncherApplication.java b/src/com/android/launcher3/LauncherApplication.java
index 490186a..4c82e56 100644
--- a/src/com/android/launcher3/LauncherApplication.java
+++ b/src/com/android/launcher3/LauncherApplication.java
@@ -18,6 +18,7 @@
import android.app.Application;
import com.android.launcher3.dagger.DaggerLauncherAppComponent;
+import com.android.launcher3.dagger.LauncherAppComponent;
import com.android.launcher3.dagger.LauncherBaseAppComponent;
/**
@@ -30,10 +31,18 @@
public void onCreate() {
super.onCreate();
MainProcessInitializer.initialize(this);
- mAppComponent = DaggerLauncherAppComponent.builder().appContext(this).build();
+ initDagger();
}
- public LauncherBaseAppComponent getAppComponent() {
- return mAppComponent;
+ public LauncherAppComponent getAppComponent() {
+ // Since supertype setters will return a supertype.builder and @Component.Builder types
+ // must not have any generic types.
+ // We need to cast mAppComponent to {@link LauncherAppComponent} since appContext()
+ // method is defined in the super class LauncherBaseComponent#Builder.
+ return (LauncherAppComponent) mAppComponent;
+ }
+
+ protected void initDagger() {
+ mAppComponent = DaggerLauncherAppComponent.builder().appContext(this).build();
}
}
diff --git a/src/com/android/launcher3/ModelCallbacks.kt b/src/com/android/launcher3/ModelCallbacks.kt
index d57f8a0..496d517 100644
--- a/src/com/android/launcher3/ModelCallbacks.kt
+++ b/src/com/android/launcher3/ModelCallbacks.kt
@@ -61,7 +61,7 @@
AbstractFloatingView.closeOpenViews(
launcher,
true,
- AbstractFloatingView.TYPE_ALL and AbstractFloatingView.TYPE_REBIND_SAFE.inv()
+ AbstractFloatingView.TYPE_ALL and AbstractFloatingView.TYPE_REBIND_SAFE.inv(),
)
workspaceLoading = true
@@ -76,7 +76,7 @@
TAG,
"startBinding: " +
"hotseat layout was vertical: ${launcher.hotseat?.isHasVerticalHotseat}" +
- " and is setting to ${launcher.deviceProfile.isVerticalBarLayout}"
+ " and is setting to ${launcher.deviceProfile.isVerticalBarLayout}",
)
launcher.hotseat?.resetLayout(launcher.deviceProfile.isVerticalBarLayout)
TraceHelper.INSTANCE.endSection()
@@ -88,14 +88,12 @@
pendingTasks: RunnableList,
onCompleteSignal: RunnableList,
workspaceItemCount: Int,
- isBindSync: Boolean
+ isBindSync: Boolean,
) {
- if (Utilities.ATLEAST_S) {
- Trace.endAsyncSection(
- TraceEvents.DISPLAY_WORKSPACE_TRACE_METHOD_NAME,
- TraceEvents.DISPLAY_WORKSPACE_TRACE_COOKIE
- )
- }
+ Trace.endAsyncSection(
+ TraceEvents.DISPLAY_WORKSPACE_TRACE_METHOD_NAME,
+ TraceEvents.DISPLAY_WORKSPACE_TRACE_COOKIE,
+ )
synchronouslyBoundPages = boundPages
pagesToBindSynchronously = LIntSet()
clearPendingBinds()
@@ -149,14 +147,14 @@
// Cache one page worth of icons
launcher.viewCache.setCacheSize(
R.layout.folder_application,
- deviceProfile.numFolderColumns * deviceProfile.numFolderRows
+ deviceProfile.numFolderColumns * deviceProfile.numFolderRows,
)
launcher.viewCache.setCacheSize(R.layout.folder_page, 2)
TraceHelper.INSTANCE.endSection()
launcher.workspace.removeExtraEmptyScreen(/* stripEmptyScreens= */ true)
launcher.workspace.pageIndicator.setPauseScroll(
/*pause=*/ false,
- deviceProfile.isTwoPanels
+ deviceProfile.isTwoPanels,
)
TestEventEmitter.INSTANCE.get(launcher).sendEvent(TestEvent.WORKSPACE_FINISH_LOADING)
}
@@ -182,7 +180,7 @@
val snackbar =
AbstractFloatingView.getOpenView<AbstractFloatingView>(
launcher,
- AbstractFloatingView.TYPE_SNACKBAR
+ AbstractFloatingView.TYPE_SNACKBAR,
)
snackbar?.post { snackbar.close(true) }
}
@@ -191,7 +189,7 @@
override fun bindAllApplications(
apps: Array<AppInfo?>?,
flags: Int,
- packageUserKeytoUidMap: Map<PackageUserKey?, Int?>?
+ packageUserKeytoUidMap: Map<PackageUserKey?, Int?>?,
) {
Preconditions.assertUIThread()
val hadWorkApps = launcher.appsView.shouldShowTabs()
@@ -312,7 +310,7 @@
val info =
PendingAddWidgetInfo(
widgetsListBaseEntry.mWidgets[0].widgetInfo,
- LauncherSettings.Favorites.CONTAINER_DESKTOP
+ LauncherSettings.Favorites.CONTAINER_DESKTOP,
)
launcher.addPendingItem(
info,
@@ -320,14 +318,14 @@
WorkspaceLayoutManager.FIRST_SCREEN_ID,
intArrayOf(0, 0),
info.spanX,
- info.spanY
+ info.spanY,
)
}
override fun bindScreens(orderedScreenIds: LIntArray) {
launcher.workspace.pageIndicator.setPauseScroll(
/*pause=*/ true,
- launcher.deviceProfile.isTwoPanels
+ launcher.deviceProfile.isTwoPanels,
)
val firstScreenPosition = 0
if (
@@ -354,7 +352,7 @@
override fun bindAppsAdded(
newScreens: LIntArray?,
addNotAnimated: java.util.ArrayList<ItemInfo?>?,
- addAnimated: java.util.ArrayList<ItemInfo?>?
+ addAnimated: java.util.ArrayList<ItemInfo?>?,
) {
// Add the new screens
if (newScreens != null) {
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index fde7014..f8ac48a 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -122,9 +122,6 @@
public static final String[] EMPTY_STRING_ARRAY = new String[0];
public static final Person[] EMPTY_PERSON_ARRAY = new Person[0];
- @ChecksSdkIntAtLeast(api = VERSION_CODES.S)
- public static final boolean ATLEAST_S = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;
-
@ChecksSdkIntAtLeast(api = VERSION_CODES.TIRAMISU, codename = "T")
public static final boolean ATLEAST_T = Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU;
diff --git a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
index 1a59d82..0a50e8b 100644
--- a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
+++ b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
@@ -18,6 +18,8 @@
import android.content.Context;
+import com.android.launcher3.util.DaggerSingletonTracker;
+
import dagger.BindsInstance;
/**
@@ -29,6 +31,7 @@
* See {@link LauncherAppComponent} for the one actually used by AOSP.
*/
public interface LauncherBaseAppComponent {
+ DaggerSingletonTracker getDaggerSingletonTracker();
/** Builder for LauncherBaseAppComponent. */
interface Builder {
@BindsInstance Builder appContext(@ApplicationContext Context context);
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 4af9e2f..40c0cc6 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -69,7 +69,6 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
import com.android.launcher3.WorkspaceLayoutManager;
import com.android.launcher3.apppairs.AppPairIcon;
@@ -207,15 +206,12 @@
mWorkspaceScreens.put(Workspace.SECOND_SCREEN_ID, rightPanel);
}
- if (Utilities.ATLEAST_S) {
- WallpaperColors wallpaperColors = wallpaperColorsOverride != null
- ? wallpaperColorsOverride
- : WallpaperManager.getInstance(context).getWallpaperColors(FLAG_SYSTEM);
- mWallpaperColorResources = wallpaperColors != null ? LocalColorExtractor.newInstance(
- context).generateColorsOverride(wallpaperColors) : null;
- } else {
- mWallpaperColorResources = null;
- }
+ WallpaperColors wallpaperColors = wallpaperColorsOverride != null
+ ? wallpaperColorsOverride
+ : WallpaperManager.getInstance(context).getWallpaperColors(FLAG_SYSTEM);
+ mWallpaperColorResources = wallpaperColors != null
+ ? LocalColorExtractor.newInstance(context).generateColorsOverride(wallpaperColors)
+ : null;
mAppWidgetHost = new LauncherPreviewAppWidgetHost(context);
}
diff --git a/src/com/android/launcher3/model/WidgetItem.java b/src/com/android/launcher3/model/WidgetItem.java
index 3f88717..ac9f2d6 100644
--- a/src/com/android/launcher3/model/WidgetItem.java
+++ b/src/com/android/launcher3/model/WidgetItem.java
@@ -4,8 +4,6 @@
import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD;
import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX;
-import static com.android.launcher3.Utilities.ATLEAST_S;
-
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.ActivityInfo;
@@ -48,7 +46,7 @@
super(info.provider, info.getProfile());
label = iconCache.getTitleNoCache(info);
- description = ATLEAST_S ? info.loadDescription(context) : null;
+ description = info.loadDescription(context);
widgetInfo = info;
activityInfo = null;
@@ -107,7 +105,7 @@
/** Returns whether this {@link WidgetItem} has a preview layout that can be used. */
@SuppressLint("NewApi") // Already added API check.
public boolean hasPreviewLayout() {
- return ATLEAST_S && widgetInfo != null && widgetInfo.previewLayout != Resources.ID_NULL;
+ return widgetInfo != null && widgetInfo.previewLayout != Resources.ID_NULL;
}
/** Returns whether this {@link WidgetItem} is for a shortcut rather than an app widget. */
diff --git a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
index 90e47d6..1f1e514 100644
--- a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
+++ b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
@@ -30,7 +30,6 @@
import com.android.launcher3.InvariantDeviceProfile
import com.android.launcher3.LauncherAppState
import com.android.launcher3.LauncherSettings.Favorites
-import com.android.launcher3.Utilities
import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError
import com.android.launcher3.config.FeatureFlags
import com.android.launcher3.logging.FileLog
@@ -76,7 +75,7 @@
private val pmHelper: PackageManagerHelper,
private val iconRequestInfos: MutableList<IconRequestInfo<WorkspaceItemInfo>>,
private val unlockedUsers: LongSparseArray<Boolean>,
- private val allDeepShortcuts: MutableList<ShortcutInfo>
+ private val allDeepShortcuts: MutableList<ShortcutInfo>,
) {
private val isSafeMode = app.isSafeModeEnabled
@@ -97,7 +96,7 @@
// User has been deleted, remove the item.
c.markDeleted(
"User has been deleted for item id=${c.id}",
- RestoreError.PROFILE_DELETED
+ RestoreError.PROFILE_DELETED,
)
return
}
@@ -168,7 +167,7 @@
FileLog.d(
TAG,
"Activity not enabled for id=${c.id}, component=$cn, user=${c.user}." +
- " Will attempt to find fallback Activity for targetPkg=$targetPkg."
+ " Will attempt to find fallback Activity for targetPkg=$targetPkg.",
)
intent = pmHelper.getAppLaunchIntent(targetPkg, c.user)
if (intent != null) {
@@ -178,7 +177,7 @@
c.markDeleted(
"No Activities found for id=${c.id}, targetPkg=$targetPkg, component=$cn." +
" Unable to create launch Intent.",
- RestoreError.MISSING_INFO
+ RestoreError.MISSING_INFO,
)
return
}
@@ -213,7 +212,7 @@
else -> {
c.markDeleted(
"removing app that is not restored and not installing. package: $targetPkg",
- RestoreError.APP_NOT_INSTALLED
+ RestoreError.APP_NOT_INSTALLED,
)
return
}
@@ -238,7 +237,7 @@
// Do not wait for external media load anymore.
c.markDeleted(
"Invalid package removed: $targetPkg",
- RestoreError.APP_NOT_INSTALLED
+ RestoreError.APP_NOT_INSTALLED,
)
return
}
@@ -270,7 +269,7 @@
// The shortcut is no longer valid.
c.markDeleted(
"Pinned shortcut not found from request. package=${key.packageName}, user=${c.user}",
- RestoreError.SHORTCUT_NOT_FOUND
+ RestoreError.SHORTCUT_NOT_FOUND,
)
return
}
@@ -337,7 +336,7 @@
activityInfo,
userCache.getUserInfo(c.user),
ApiWrapper.INSTANCE[app.context],
- pmHelper
+ pmHelper,
)
}
if (
@@ -445,7 +444,7 @@
", id=${c.id}," +
", appWidgetId=${c.appWidgetId}," +
", component=${component}",
- RestoreError.INVALID_LOCATION
+ RestoreError.INVALID_LOCATION,
)
return
}
@@ -456,7 +455,7 @@
", appWidgetId=${c.appWidgetId}," +
", component=${component}," +
", container=${c.container}",
- RestoreError.INVALID_LOCATION
+ RestoreError.INVALID_LOCATION,
)
return
}
@@ -470,7 +469,7 @@
TAG,
"processWidget: id=${c.id}" +
", appWidgetId=${c.appWidgetId}" +
- ", inflationResult=$inflationResult"
+ ", inflationResult=$inflationResult",
)
when (inflationResult.type) {
WidgetInflater.TYPE_DELETE -> {
@@ -496,7 +495,7 @@
", appWidgetId=${c.appWidgetId}" +
", component=${component}" +
", restoreFlag:=${c.restoreFlag}",
- RestoreError.APP_NOT_INSTALLED
+ RestoreError.APP_NOT_INSTALLED,
)
return
} else if (
@@ -512,7 +511,7 @@
WidgetsModel.newPendingItemInfo(
app.context,
appWidgetInfo.providerName,
- appWidgetInfo.user
+ appWidgetInfo.user,
)
iconCache.getTitleAndIconForApp(appWidgetInfo.pendingItemInfo, false)
}
@@ -522,7 +521,7 @@
lapi,
app.context,
appWidgetInfo.spanX,
- appWidgetInfo.spanY
+ appWidgetInfo.spanY,
)
}
@@ -541,7 +540,7 @@
" processWidget: Widget ${lapi.component} minSizes not met: span=${appWidgetInfo.spanX}x${appWidgetInfo.spanY} minSpan=${lapi.minSpanX}x${lapi.minSpanY}," +
" id: ${c.id}," +
" appWidgetId: ${c.appWidgetId}," +
- " component=${component}"
+ " component=${component}",
)
logWidgetInfo(app.invariantDeviceProfile, lapi)
}
@@ -554,7 +553,7 @@
private fun logWidgetInfo(
idp: InvariantDeviceProfile,
- widgetProviderInfo: LauncherAppWidgetProviderInfo
+ widgetProviderInfo: LauncherAppWidgetProviderInfo,
) {
val cellSize = Point()
for (deviceProfile in idp.supportedProfiles) {
@@ -565,7 +564,7 @@
" available height: ${deviceProfile.availableHeightPx}," +
" cellLayoutBorderSpacePx Horizontal: ${deviceProfile.cellLayoutBorderSpacePx.x}," +
" cellLayoutBorderSpacePx Vertical: ${deviceProfile.cellLayoutBorderSpacePx.y}," +
- " cellSize: $cellSize"
+ " cellSize: $cellSize",
)
}
val widgetDimension = StringBuilder()
@@ -583,21 +582,19 @@
.append("defaultHeight: ")
.append(widgetProviderInfo.minHeight)
.append("\n")
- if (Utilities.ATLEAST_S) {
- widgetDimension
- .append("targetCellWidth: ")
- .append(widgetProviderInfo.targetCellWidth)
- .append("\n")
- .append("targetCellHeight: ")
- .append(widgetProviderInfo.targetCellHeight)
- .append("\n")
- .append("maxResizeWidth: ")
- .append(widgetProviderInfo.maxResizeWidth)
- .append("\n")
- .append("maxResizeHeight: ")
- .append(widgetProviderInfo.maxResizeHeight)
- .append("\n")
- }
+ widgetDimension
+ .append("targetCellWidth: ")
+ .append(widgetProviderInfo.targetCellWidth)
+ .append("\n")
+ .append("targetCellHeight: ")
+ .append(widgetProviderInfo.targetCellHeight)
+ .append("\n")
+ .append("maxResizeWidth: ")
+ .append(widgetProviderInfo.maxResizeWidth)
+ .append("\n")
+ .append("maxResizeHeight: ")
+ .append(widgetProviderInfo.maxResizeHeight)
+ .append("\n")
FileLog.d(TAG, widgetDimension.toString())
}
}
diff --git a/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java b/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java
index f4dda55..361f09d 100644
--- a/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java
+++ b/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java
@@ -21,7 +21,6 @@
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PIN_WIDGETS;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_TRAY;
-import static com.android.launcher3.Utilities.ATLEAST_S;
import android.appwidget.AppWidgetHostView;
import android.content.ComponentName;
@@ -233,16 +232,16 @@
if (providerInfo.isConfigurationOptional()) {
widgetFeatures |= FEATURE_OPTIONAL_CONFIGURATION;
}
- if (ATLEAST_S && providerInfo.previewLayout != Resources.ID_NULL) {
+ if (providerInfo.previewLayout != Resources.ID_NULL) {
widgetFeatures |= FEATURE_PREVIEW_LAYOUT;
}
- if (ATLEAST_S && providerInfo.targetCellWidth > 0 || providerInfo.targetCellHeight > 0) {
+ if (providerInfo.targetCellWidth > 0 || providerInfo.targetCellHeight > 0) {
widgetFeatures |= FEATURE_TARGET_CELL_SIZE;
}
if (providerInfo.minResizeWidth > 0 || providerInfo.minResizeHeight > 0) {
widgetFeatures |= FEATURE_MIN_SIZE;
}
- if (ATLEAST_S && providerInfo.maxResizeWidth > 0 || providerInfo.maxResizeHeight > 0) {
+ if (providerInfo.maxResizeWidth > 0 || providerInfo.maxResizeHeight > 0) {
widgetFeatures |= FEATURE_MAX_SIZE;
}
if (hostView instanceof LauncherAppWidgetHostView &&
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index 3817563..efd1f0d 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -40,11 +40,13 @@
import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.contextualeducation.ContextualEduStatsManager;
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.util.FlingBlockCheck;
import com.android.launcher3.util.TouchController;
+import com.android.systemui.contextualeducation.GestureType;
/**
* TouchController for handling state changes
@@ -388,6 +390,7 @@
} else {
logReachedState(mToState);
}
+ updateContextualEduStats(targetState);
}
protected void goToTargetState(LauncherState targetState) {
@@ -403,6 +406,21 @@
.setDuration(0).start();
}
+ private void updateContextualEduStats(LauncherState targetState) {
+ if (targetState == NORMAL) {
+ ContextualEduStatsManager.INSTANCE.get(
+ mLauncher).updateEduStats(mDetector.isTrackpadGesture(), GestureType.HOME);
+ } else if (targetState == OVERVIEW) {
+ ContextualEduStatsManager.INSTANCE.get(
+ mLauncher).updateEduStats(mDetector.isTrackpadGesture(), GestureType.OVERVIEW);
+ } else if (targetState == ALL_APPS && !mDetector.isTrackpadGesture()) {
+ // Only update if it is touch gesture as trackpad gesture is not relevant for all apps
+ // which only provides keyboard education.
+ ContextualEduStatsManager.INSTANCE.get(
+ mLauncher).updateEduStats(/* isTrackpadGesture= */ false, GestureType.ALL_APPS);
+ }
+ }
+
private void logReachedState(LauncherState targetState) {
if (mStartState == targetState) {
return;
diff --git a/src/com/android/launcher3/touch/BaseSwipeDetector.java b/src/com/android/launcher3/touch/BaseSwipeDetector.java
index 52c3581..faac4a3 100644
--- a/src/com/android/launcher3/touch/BaseSwipeDetector.java
+++ b/src/com/android/launcher3/touch/BaseSwipeDetector.java
@@ -17,6 +17,8 @@
import static android.view.MotionEvent.INVALID_POINTER_ID;
+import static com.android.launcher3.MotionEventsUtils.isTrackpadMotionEvent;
+
import android.content.Context;
import android.graphics.PointF;
import android.util.Log;
@@ -64,6 +66,7 @@
protected PointF mSubtractDisplacement = new PointF();
@VisibleForTesting ScrollState mState = ScrollState.IDLE;
private boolean mIsSettingState;
+ protected boolean mIsTrackpadGesture;
protected boolean mIgnoreSlopWhenSettling;
protected Context mContext;
@@ -122,6 +125,10 @@
return mState == ScrollState.DRAGGING || mState == ScrollState.SETTLING;
}
+ public boolean isTrackpadGesture() {
+ return mIsTrackpadGesture;
+ }
+
public void finishedScrolling() {
setState(ScrollState.IDLE);
}
@@ -147,7 +154,7 @@
mLastPos.set(mDownPos);
mLastDisplacement.set(0, 0);
mDisplacement.set(0, 0);
-
+ mIsTrackpadGesture = isTrackpadMotionEvent(ev);
if (mState == ScrollState.SETTLING && mIgnoreSlopWhenSettling) {
setState(ScrollState.DRAGGING);
}
diff --git a/src/com/android/launcher3/util/DaggerSingletonObject.java b/src/com/android/launcher3/util/DaggerSingletonObject.java
new file mode 100644
index 0000000..b8cf2ae
--- /dev/null
+++ b/src/com/android/launcher3/util/DaggerSingletonObject.java
@@ -0,0 +1,44 @@
+/*
+ * 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.util;
+
+import android.content.Context;
+
+import com.android.launcher3.LauncherApplication;
+import com.android.launcher3.dagger.LauncherAppComponent;
+
+import java.util.function.Function;
+
+/**
+ * A class to provide DaggerSingleton objects in a traditional way for
+ * {@link MainThreadInitializedObject}.
+ * We should delete this class at the end and use @Inject to get dagger provided singletons.
+ */
+
+public class DaggerSingletonObject<T extends SafeCloseable> {
+ private final Function<LauncherAppComponent, T> mFunction;
+
+ public DaggerSingletonObject(Function<LauncherAppComponent, T> function) {
+ mFunction = function;
+ }
+
+ public T get(Context context) {
+ LauncherAppComponent component =
+ ((LauncherApplication) context.getApplicationContext()).getAppComponent();
+ return mFunction.apply(component);
+ }
+}
diff --git a/src/com/android/launcher3/util/DaggerSingletonTracker.java b/src/com/android/launcher3/util/DaggerSingletonTracker.java
new file mode 100644
index 0000000..2946da1
--- /dev/null
+++ b/src/com/android/launcher3/util/DaggerSingletonTracker.java
@@ -0,0 +1,57 @@
+/*
+ * 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.util;
+
+import com.android.launcher3.dagger.LauncherAppSingleton;
+
+import java.util.ArrayList;
+
+import javax.inject.Inject;
+
+/**
+ * A tracker class for keeping track of Dagger created singletons.
+ * Dagger will take care of creating singletons. But we should take care of unregistering callbacks
+ * if at all registered during singleton construction.
+ * All singletons should be declared as SafeCloseable so that we can call close() method.
+ */
+@LauncherAppSingleton
+public class DaggerSingletonTracker implements SafeCloseable {
+
+ private final ArrayList<SafeCloseable> mLauncherAppSingletons = new ArrayList<>();
+
+ @Inject
+ DaggerSingletonTracker() {
+ }
+
+ /**
+ * Adds the SafeCloseable Singletons to the mLauncherAppSingletons list.
+ * This helps to track the singletons and close them appropriately.
+ * See {@link DaggerSingletonTracker#close()} and
+ * {@link MainThreadInitializedObject.SandboxContext#onDestroy()}
+ */
+ public void addCloseable(SafeCloseable closeable) {
+ mLauncherAppSingletons.add(closeable);
+ }
+
+ @Override
+ public void close() {
+ // Destroy in reverse order
+ for (int i = mLauncherAppSingletons.size() - 1; i >= 0; i--) {
+ mLauncherAppSingletons.get(i).close();
+ }
+ }
+}
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index dff9a07..afa5075 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -15,7 +15,6 @@
*/
package com.android.launcher3.util;
-import static android.content.Intent.ACTION_CONFIGURATION_CHANGED;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -33,7 +32,6 @@
import static com.android.launcher3.util.window.WindowManagerProxy.MIN_TABLET_WIDTH;
import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
import android.content.ComponentCallbacks;
import android.content.Context;
import android.content.Intent;
@@ -42,7 +40,6 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
-import android.os.Build;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
@@ -132,21 +129,15 @@
}
Display display = mDM.getDisplay(DEFAULT_DISPLAY);
- if (Utilities.ATLEAST_S) {
- mWindowContext = mContext.createWindowContext(display, TYPE_APPLICATION, null);
- mWindowContext.registerComponentCallbacks(this);
- } else {
- mWindowContext = null;
- mReceiver.register(mContext, ACTION_CONFIGURATION_CHANGED);
- }
+ mWindowContext = mContext.createWindowContext(display, TYPE_APPLICATION, null);
+ mWindowContext.registerComponentCallbacks(this);
// Initialize navigation mode change listener
mReceiver.registerPkgActions(mContext, TARGET_OVERLAY_PACKAGE, ACTION_OVERLAY_CHANGED);
WindowManagerProxy wmProxy = WindowManagerProxy.INSTANCE.get(context);
- Context displayInfoContext = getDisplayInfoContext(display);
- mInfo = new Info(displayInfoContext, wmProxy,
- wmProxy.estimateInternalDisplayBounds(displayInfoContext));
+ mInfo = new Info(mWindowContext, wmProxy,
+ wmProxy.estimateInternalDisplayBounds(mWindowContext));
FileLog.i(TAG, "(CTOR) perDisplayBounds: " + mInfo.mPerDisplayBounds);
}
@@ -161,7 +152,7 @@
&& mInfo.mIsTaskbarPinnedInDesktopMode != prefs.get(
TASKBAR_PINNING_IN_DESKTOP_MODE);
if (isTaskbarPinningChanged || isTaskbarPinningDesktopModeChanged) {
- handleInfoChange(mWindowContext.getDisplay());
+ handleInfoChange();
}
};
@@ -191,14 +182,14 @@
* Handles info change for desktop mode.
*/
public static void handleInfoChangeForDesktopMode(Context context) {
- INSTANCE.get(context).handleInfoChange(context.getDisplay());
+ INSTANCE.get(context).handleInfoChange();
}
/**
* Handles info change for launcher visibility.
*/
public static void handleInfoChangeForLauncherVisibilityChanged(Context context) {
- INSTANCE.get(context).handleInfoChange(context.getDisplay());
+ INSTANCE.get(context).handleInfoChange();
}
/**
@@ -266,36 +257,22 @@
if (mDestroyed) {
return;
}
- boolean reconfigure = false;
if (ACTION_OVERLAY_CHANGED.equals(intent.getAction())) {
- reconfigure = true;
- } else if (ACTION_CONFIGURATION_CHANGED.equals(intent.getAction())) {
- Configuration config = mContext.getResources().getConfiguration();
- reconfigure = mInfo.fontScale != config.fontScale
- || mInfo.densityDpi != config.densityDpi;
- }
-
- if (reconfigure) {
- Log.d(TAG, "Configuration changed, notifying listeners");
- Display display = mDM.getDisplay(DEFAULT_DISPLAY);
- if (display != null) {
- handleInfoChange(display);
- }
+ Log.d(TAG, "Overlay changed, notifying listeners");
+ handleInfoChange();
}
}
@UiThread
@Override
- @TargetApi(Build.VERSION_CODES.S)
public final void onConfigurationChanged(Configuration config) {
Log.d(TASKBAR_NOT_DESTROYED_TAG, "DisplayController#onConfigurationChanged: " + config);
- Display display = mWindowContext.getDisplay();
if (config.densityDpi != mInfo.densityDpi
|| config.fontScale != mInfo.fontScale
- || display.getRotation() != mInfo.rotation
|| !mInfo.mScreenSizeDp.equals(
- new PortraitSize(config.screenHeightDp, config.screenWidthDp))) {
- handleInfoChange(display);
+ new PortraitSize(config.screenHeightDp, config.screenWidthDp))
+ || mWindowContext.getDisplay().getRotation() != mInfo.rotation) {
+ handleInfoChange();
}
}
@@ -318,17 +295,13 @@
return mInfo;
}
- private Context getDisplayInfoContext(Display display) {
- return Utilities.ATLEAST_S ? mWindowContext : mContext.createDisplayContext(display);
- }
-
@AnyThread
@VisibleForTesting
- public void handleInfoChange(Display display) {
+ public void handleInfoChange() {
WindowManagerProxy wmProxy = WindowManagerProxy.INSTANCE.get(mContext);
Info oldInfo = mInfo;
- Context displayInfoContext = getDisplayInfoContext(display);
+ Context displayInfoContext = mWindowContext;
Info newInfo = new Info(displayInfoContext, wmProxy, oldInfo.mPerDisplayBounds);
if (newInfo.densityDpi != oldInfo.densityDpi || newInfo.fontScale != oldInfo.fontScale
diff --git a/src/com/android/launcher3/util/EdgeEffectCompat.java b/src/com/android/launcher3/util/EdgeEffectCompat.java
index ca37259..a949f50 100644
--- a/src/com/android/launcher3/util/EdgeEffectCompat.java
+++ b/src/com/android/launcher3/util/EdgeEffectCompat.java
@@ -19,8 +19,6 @@
import android.view.MotionEvent;
import android.widget.EdgeEffect;
-import com.android.launcher3.Utilities;
-
/**
* Extension of {@link EdgeEffect} to allow backwards compatibility
*/
@@ -30,21 +28,6 @@
super(context);
}
- @Override
- public float getDistance() {
- return Utilities.ATLEAST_S ? super.getDistance() : 0;
- }
-
- @Override
- public float onPullDistance(float deltaDistance, float displacement) {
- if (Utilities.ATLEAST_S) {
- return super.onPullDistance(deltaDistance, displacement);
- } else {
- onPull(deltaDistance, displacement);
- return deltaDistance;
- }
- }
-
public float onPullDistance(float deltaDistance, float displacement, MotionEvent ev) {
return onPullDistance(deltaDistance, displacement);
}
diff --git a/src/com/android/launcher3/util/ExecutorUtil.java b/src/com/android/launcher3/util/ExecutorUtil.java
new file mode 100644
index 0000000..efc0eec
--- /dev/null
+++ b/src/com/android/launcher3/util/ExecutorUtil.java
@@ -0,0 +1,37 @@
+/*
+ * 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.util;
+
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+
+import android.os.Looper;
+
+import java.util.concurrent.ExecutionException;
+
+public final class ExecutorUtil {
+
+ /**
+ * Executes runnable on {@link Looper#getMainLooper()}, otherwise fails with an exception.
+ */
+ public static void executeSyncOnMainOrFail(Runnable runnable) {
+ try {
+ MAIN_EXECUTOR.submit(runnable).get();
+ } catch (InterruptedException | ExecutionException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/util/MainThreadInitializedObject.java b/src/com/android/launcher3/util/MainThreadInitializedObject.java
index 63f14bd..e12ccbc 100644
--- a/src/com/android/launcher3/util/MainThreadInitializedObject.java
+++ b/src/com/android/launcher3/util/MainThreadInitializedObject.java
@@ -18,13 +18,13 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import android.content.Context;
-import android.content.ContextWrapper;
import android.os.Looper;
import android.util.Log;
import androidx.annotation.UiThread;
import androidx.annotation.VisibleForTesting;
+import com.android.launcher3.LauncherApplication;
import com.android.launcher3.util.ResourceBasedOverride.Overrides;
import java.util.ArrayList;
@@ -118,7 +118,7 @@
* Abstract Context which allows custom implementations for
* {@link MainThreadInitializedObject} providers
*/
- public static class SandboxContext extends ContextWrapper implements SandboxApplication {
+ public static class SandboxContext extends LauncherApplication implements SandboxApplication {
private static final String TAG = "SandboxContext";
@@ -129,7 +129,8 @@
private boolean mDestroyed = false;
public SandboxContext(Context base) {
- super(base);
+ attachBaseContext(base);
+ initDagger();
}
@Override
@@ -138,6 +139,7 @@
}
public void onDestroy() {
+ getAppComponent().getDaggerSingletonTracker().close();
synchronized (mDestroyLock) {
// Destroy in reverse order
for (int i = mOrderedObjects.size() - 1; i >= 0; i--) {
diff --git a/src/com/android/launcher3/util/OverlayEdgeEffect.java b/src/com/android/launcher3/util/OverlayEdgeEffect.java
index d09d801..0623af7 100644
--- a/src/com/android/launcher3/util/OverlayEdgeEffect.java
+++ b/src/com/android/launcher3/util/OverlayEdgeEffect.java
@@ -46,6 +46,7 @@
return mDistance;
}
+ @Override
public float onPullDistance(float deltaDistance, float displacement) {
// Fallback implementation, will never actually get called
if (BuildConfig.IS_DEBUG_DEVICE) {
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index 469e363..b1913c0 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -303,10 +303,7 @@
/** Returns the incremental download progress for the given shortcut's app. */
public static int getLoadingProgress(LauncherActivityInfo info) {
- if (Utilities.ATLEAST_S) {
- return (int) (100 * info.getLoadingProgress());
- }
- return 100;
+ return (int) (100 * info.getLoadingProgress());
}
/** Returns true in case app is installed on the device or in archived state. */
diff --git a/src/com/android/launcher3/util/Themes.java b/src/com/android/launcher3/util/Themes.java
index 60951ba..104040a 100644
--- a/src/com/android/launcher3/util/Themes.java
+++ b/src/com/android/launcher3/util/Themes.java
@@ -52,10 +52,8 @@
}
public static int getActivityThemeRes(Context context, int wallpaperColorHints) {
- boolean supportsDarkText = Utilities.ATLEAST_S
- && (wallpaperColorHints & HINT_SUPPORTS_DARK_TEXT) != 0;
- boolean isMainColorDark = Utilities.ATLEAST_S
- && (wallpaperColorHints & HINT_SUPPORTS_DARK_THEME) != 0;
+ boolean supportsDarkText = (wallpaperColorHints & HINT_SUPPORTS_DARK_TEXT) != 0;
+ boolean isMainColorDark = (wallpaperColorHints & HINT_SUPPORTS_DARK_THEME) != 0;
if (Utilities.isDarkTheme(context)) {
return supportsDarkText ? R.style.AppTheme_Dark_DarkText
diff --git a/src/com/android/launcher3/util/VibratorWrapper.java b/src/com/android/launcher3/util/VibratorWrapper.java
index a4b8eb0..adb8f9d 100644
--- a/src/com/android/launcher3/util/VibratorWrapper.java
+++ b/src/com/android/launcher3/util/VibratorWrapper.java
@@ -31,8 +31,6 @@
import androidx.annotation.VisibleForTesting;
-import com.android.launcher3.Utilities;
-
/**
* Wrapper around {@link Vibrator} to easily perform haptic feedback where necessary.
*/
@@ -129,7 +127,7 @@
/** Indicates that Taskbar has been invoked. */
public void vibrateForTaskbarUnstash() {
- if (Utilities.ATLEAST_S && mVibrator.areAllPrimitivesSupported(PRIMITIVE_LOW_TICK)) {
+ if (mVibrator.areAllPrimitivesSupported(PRIMITIVE_LOW_TICK)) {
VibrationEffect primitiveLowTickEffect = VibrationEffect
.startComposition()
.addPrimitive(PRIMITIVE_LOW_TICK, LOW_TICK_SCALE)
diff --git a/src/com/android/launcher3/util/WallpaperColorHints.kt b/src/com/android/launcher3/util/WallpaperColorHints.kt
index 1361c1e..11d4c25 100644
--- a/src/com/android/launcher3/util/WallpaperColorHints.kt
+++ b/src/com/android/launcher3/util/WallpaperColorHints.kt
@@ -23,7 +23,6 @@
import android.content.Context
import androidx.annotation.MainThread
import androidx.annotation.VisibleForTesting
-import com.android.launcher3.Utilities
import com.android.launcher3.util.Executors.MAIN_EXECUTOR
import com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR
@@ -34,36 +33,34 @@
class WallpaperColorHints(private val context: Context) : SafeCloseable {
var hints: Int = 0
private set
+
private val wallpaperManager
get() = context.getSystemService(WallpaperManager::class.java)!!
+
private val onColorHintsChangedListeners = mutableListOf<OnColorHintListener>()
private val onClose: SafeCloseable
init {
- if (Utilities.ATLEAST_S) {
- hints = wallpaperManager.getWallpaperColors(FLAG_SYSTEM)?.colorHints ?: 0
- val onColorsChangedListener = OnColorsChangedListener { colors, which ->
- onColorsChanged(colors, which)
- }
+ hints = wallpaperManager.getWallpaperColors(FLAG_SYSTEM)?.colorHints ?: 0
+ val onColorsChangedListener = OnColorsChangedListener { colors, which ->
+ onColorsChanged(colors, which)
+ }
+ UI_HELPER_EXECUTOR.execute {
+ wallpaperManager.addOnColorsChangedListener(
+ onColorsChangedListener,
+ MAIN_EXECUTOR.handler,
+ )
+ }
+ onClose = SafeCloseable {
UI_HELPER_EXECUTOR.execute {
- wallpaperManager.addOnColorsChangedListener(
- onColorsChangedListener,
- MAIN_EXECUTOR.handler
- )
+ wallpaperManager.removeOnColorsChangedListener(onColorsChangedListener)
}
- onClose = SafeCloseable {
- UI_HELPER_EXECUTOR.execute {
- wallpaperManager.removeOnColorsChangedListener(onColorsChangedListener)
- }
- }
- } else {
- onClose = SafeCloseable {}
}
}
@MainThread
private fun onColorsChanged(colors: WallpaperColors?, which: Int) {
- if ((which and FLAG_SYSTEM) != 0 && Utilities.ATLEAST_S) {
+ if ((which and FLAG_SYSTEM) != 0) {
val newHints = colors?.colorHints ?: 0
if (newHints != hints) {
hints = newHints
@@ -86,6 +83,7 @@
@VisibleForTesting
@JvmField
val INSTANCE = MainThreadInitializedObject { WallpaperColorHints(it) }
+
@JvmStatic fun get(context: Context): WallpaperColorHints = INSTANCE.get(context)
}
}
diff --git a/src/com/android/launcher3/util/window/WindowManagerProxy.java b/src/com/android/launcher3/util/window/WindowManagerProxy.java
index 22ecf68..84b4a36 100644
--- a/src/com/android/launcher3/util/window/WindowManagerProxy.java
+++ b/src/com/android/launcher3/util/window/WindowManagerProxy.java
@@ -32,7 +32,6 @@
import static com.android.launcher3.util.RotationUtils.rotateRect;
import static com.android.launcher3.util.RotationUtils.rotateSize;
-import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -40,7 +39,6 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
-import android.os.Build;
import android.util.ArrayMap;
import android.util.Log;
import android.view.Display;
@@ -54,7 +52,6 @@
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.testing.shared.ResourceUtils;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.NavigationMode;
@@ -230,7 +227,7 @@
int screenWidthPx,
@NonNull WindowInsets windowInsets,
@NonNull WindowInsets.Builder insetsBuilder) {
- if (!isLargeScreen || !Utilities.ATLEAST_S) {
+ if (!isLargeScreen) {
return;
}
@@ -405,25 +402,16 @@
/**
* Returns a CachedDisplayInfo initialized for the current display
*/
- @TargetApi(Build.VERSION_CODES.S)
public CachedDisplayInfo getDisplayInfo(Context displayInfoContext) {
int rotation = getRotation(displayInfoContext);
- if (Utilities.ATLEAST_S) {
- WindowMetrics windowMetrics = displayInfoContext.getSystemService(WindowManager.class)
- .getMaximumWindowMetrics();
- return getDisplayInfo(windowMetrics, rotation);
- } else {
- Point size = new Point();
- Display display = getDisplay(displayInfoContext);
- display.getRealSize(size);
- return new CachedDisplayInfo(size, rotation);
- }
+ WindowMetrics windowMetrics = displayInfoContext.getSystemService(WindowManager.class)
+ .getMaximumWindowMetrics();
+ return getDisplayInfo(windowMetrics, rotation);
}
/**
* Returns a CachedDisplayInfo initialized for the current display
*/
- @TargetApi(Build.VERSION_CODES.S)
protected CachedDisplayInfo getDisplayInfo(WindowMetrics windowMetrics, int rotation) {
Point size = new Point(windowMetrics.getBounds().right, windowMetrics.getBounds().bottom);
return new CachedDisplayInfo(size, rotation,
@@ -492,8 +480,7 @@
}
}
}
- return Utilities.ATLEAST_S ? NavigationMode.NO_BUTTON :
- NavigationMode.THREE_BUTTONS;
+ return NavigationMode.NO_BUTTON;
}
@Override
diff --git a/src/com/android/launcher3/views/SpringRelativeLayout.java b/src/com/android/launcher3/views/SpringRelativeLayout.java
index 923eb19..a13152e 100644
--- a/src/com/android/launcher3/views/SpringRelativeLayout.java
+++ b/src/com/android/launcher3/views/SpringRelativeLayout.java
@@ -25,8 +25,6 @@
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory;
-import com.android.launcher3.Utilities;
-
/**
* View group to allow rendering overscroll effect in a child at the parent level
*/
@@ -46,10 +44,8 @@
public SpringRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mEdgeGlowTop = Utilities.ATLEAST_S
- ? new EdgeEffect(context, attrs) : new EdgeEffect(context);
- mEdgeGlowBottom = Utilities.ATLEAST_S
- ? new EdgeEffect(context, attrs) : new EdgeEffect(context);
+ mEdgeGlowTop = new EdgeEffect(context, attrs);
+ mEdgeGlowBottom = new EdgeEffect(context, attrs);
setWillNotDraw(false);
}
diff --git a/src/com/android/launcher3/widget/BaseLauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/BaseLauncherAppWidgetHostView.java
index 856f4b3..12a14c2 100644
--- a/src/com/android/launcher3/widget/BaseLauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/BaseLauncherAppWidgetHostView.java
@@ -104,7 +104,7 @@
@UiThread
private void enforceRoundedCorners() {
- if (mEnforcedCornerRadius <= 0 || !RoundedCornerEnforcement.isRoundedCornerEnabled()) {
+ if (mEnforcedCornerRadius <= 0) {
resetRoundedCorners();
return;
}
diff --git a/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java b/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java
index 2817299..ab42839 100644
--- a/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java
+++ b/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java
@@ -183,19 +183,14 @@
// Draw horizontal and vertical lines to represent individual columns.
final Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
+ boxRect = new RectF(/* left= */ 0, /* top= */ 0, /* right= */
+ previewWidthF, /* bottom= */ previewHeightF);
- if (Utilities.ATLEAST_S) {
- boxRect = new RectF(/* left= */ 0, /* top= */ 0, /* right= */
- previewWidthF, /* bottom= */ previewHeightF);
-
- p.setStyle(Paint.Style.FILL);
- p.setColor(Color.WHITE);
- float roundedCorner = mContext.getResources().getDimension(
- android.R.dimen.system_app_widget_background_radius);
- c.drawRoundRect(boxRect, roundedCorner, roundedCorner, p);
- } else {
- boxRect = drawBoxWithShadow(c, previewWidthF, previewHeightF);
- }
+ p.setStyle(Paint.Style.FILL);
+ p.setColor(Color.WHITE);
+ float roundedCorner = mContext.getResources().getDimension(
+ android.R.dimen.system_app_widget_background_radius);
+ c.drawRoundRect(boxRect, roundedCorner, roundedCorner, p);
p.setStyle(Paint.Style.STROKE);
p.setStrokeWidth(mContext.getResources()
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java
index 3e4fd8c..e77ba24 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java
@@ -1,7 +1,5 @@
package com.android.launcher3.widget;
-import static com.android.launcher3.Utilities.ATLEAST_S;
-
import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.content.Context;
@@ -116,15 +114,13 @@
getSpanY(widgetPadding, minResizeHeight, dp.cellLayoutBorderSpacePx.y,
cellSize.y));
- if (ATLEAST_S) {
- if (maxResizeWidth > 0) {
- maxSpanX = Math.min(maxSpanX, getSpanX(widgetPadding, maxResizeWidth,
- dp.cellLayoutBorderSpacePx.x, cellSize.x));
- }
- if (maxResizeHeight > 0) {
- maxSpanY = Math.min(maxSpanY, getSpanY(widgetPadding, maxResizeHeight,
- dp.cellLayoutBorderSpacePx.y, cellSize.y));
- }
+ if (maxResizeWidth > 0) {
+ maxSpanX = Math.min(maxSpanX, getSpanX(widgetPadding, maxResizeWidth,
+ dp.cellLayoutBorderSpacePx.x, cellSize.x));
+ }
+ if (maxResizeHeight > 0) {
+ maxSpanY = Math.min(maxSpanY, getSpanY(widgetPadding, maxResizeHeight,
+ dp.cellLayoutBorderSpacePx.y, cellSize.y));
}
spanX = Math.max(spanX,
@@ -135,18 +131,16 @@
cellSize.y));
}
- if (ATLEAST_S) {
- // Ensures maxSpan >= minSpan
- maxSpanX = Math.max(maxSpanX, minSpanX);
- maxSpanY = Math.max(maxSpanY, minSpanY);
+ // Ensures maxSpan >= minSpan
+ maxSpanX = Math.max(maxSpanX, minSpanX);
+ maxSpanY = Math.max(maxSpanY, minSpanY);
- // Use targetCellWidth/Height if it is within the min/max ranges.
- // Otherwise, use the span of minWidth/Height.
- if (targetCellWidth >= minSpanX && targetCellWidth <= maxSpanX
- && targetCellHeight >= minSpanY && targetCellHeight <= maxSpanY) {
- spanX = targetCellWidth;
- spanY = targetCellHeight;
- }
+ // Use targetCellWidth/Height if it is within the min/max ranges.
+ // Otherwise, use the span of minWidth/Height.
+ if (targetCellWidth >= minSpanX && targetCellWidth <= maxSpanX
+ && targetCellHeight >= minSpanY && targetCellHeight <= maxSpanY) {
+ spanX = targetCellWidth;
+ spanY = targetCellHeight;
}
// If minSpanX/Y > spanX/Y, ignore the minSpanX/Y to match the behavior described in
@@ -213,8 +207,7 @@
}
public boolean isConfigurationOptional() {
- return ATLEAST_S
- && isReconfigurable()
+ return isReconfigurable()
&& (getWidgetFeatures() & WIDGET_FEATURE_CONFIGURATION_OPTIONAL) != 0;
}
diff --git a/src/com/android/launcher3/widget/PendingItemDragHelper.java b/src/com/android/launcher3/widget/PendingItemDragHelper.java
index 8857774..130d533 100644
--- a/src/com/android/launcher3/widget/PendingItemDragHelper.java
+++ b/src/com/android/launcher3/widget/PendingItemDragHelper.java
@@ -136,9 +136,7 @@
Drawable p = new FastBitmapDrawable(new DatabaseWidgetPreviewLoader(launcher)
.generateWidgetPreview(
createWidgetInfo.info, maxWidth, previewSizeBeforeScale));
- if (RoundedCornerEnforcement.isRoundedCornerEnabled()) {
- p = new RoundDrawableWrapper(p, mEnforcedRoundedCornersForWidget);
- }
+ p = new RoundDrawableWrapper(p, mEnforcedRoundedCornersForWidget);
preview = p;
}
diff --git a/src/com/android/launcher3/widget/RoundedCornerEnforcement.java b/src/com/android/launcher3/widget/RoundedCornerEnforcement.java
index a2fac46..cadaf89 100644
--- a/src/com/android/launcher3/widget/RoundedCornerEnforcement.java
+++ b/src/com/android/launcher3/widget/RoundedCornerEnforcement.java
@@ -28,7 +28,6 @@
import androidx.annotation.Nullable;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import java.util.ArrayList;
import java.util.List;
@@ -70,11 +69,6 @@
return background.getId() == android.R.id.background && background.getClipToOutline();
}
- /** Check if the app widget is in the deny list. */
- public static boolean isRoundedCornerEnabled() {
- return Utilities.ATLEAST_S;
- }
-
/**
* Computes the rounded rectangle needed for this app widget.
*
@@ -101,9 +95,6 @@
* in the given context.
*/
public static float computeEnforcedRadius(@NonNull Context context) {
- if (!Utilities.ATLEAST_S) {
- return 0;
- }
Resources res = context.getResources();
float systemRadius = res.getDimension(android.R.dimen.system_app_widget_background_radius);
float defaultRadius = res.getDimension(R.dimen.enforced_rounded_corner_max_radius);
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt
index d4e4bd2..d2cce12 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt
@@ -41,6 +41,7 @@
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import kotlin.math.min
+import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -81,7 +82,7 @@
WindowBounds(Rect(0, 0, width, height), Rect(0, inset, 0, 0), Surface.ROTATION_0),
WindowBounds(Rect(0, 0, height, width), Rect(0, inset, 0, 0), Surface.ROTATION_90),
WindowBounds(Rect(0, 0, width, height), Rect(0, inset, 0, 0), Surface.ROTATION_180),
- WindowBounds(Rect(0, 0, height, width), Rect(0, inset, 0, 0), Surface.ROTATION_270)
+ WindowBounds(Rect(0, 0, height, width), Rect(0, inset, 0, 0), Surface.ROTATION_270),
)
private val configuration =
Configuration(appContext.resources.configuration).apply {
@@ -137,6 +138,13 @@
displayController.addChangeListener(displayInfoChangeListener)
}
+ @After
+ fun tearDown() {
+ // 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)
+ }
+
@Test
@UiThreadTest
fun testRotation() {
@@ -170,7 +178,7 @@
@UiThreadTest
fun testTaskbarPinning() {
whenever(launcherPrefs.get(TASKBAR_PINNING)).thenReturn(true)
- displayController.handleInfoChange(display)
+ displayController.handleInfoChange()
verify(displayInfoChangeListener)
.onDisplayInfoChanged(any(), any(), eq(CHANGE_TASKBAR_PINNING))
}
@@ -179,7 +187,7 @@
@UiThreadTest
fun testTaskbarPinningChangeInDesktopMode() {
whenever(launcherPrefs.get(TASKBAR_PINNING_IN_DESKTOP_MODE)).thenReturn(false)
- displayController.handleInfoChange(display)
+ displayController.handleInfoChange()
verify(displayInfoChangeListener)
.onDisplayInfoChanged(any(), any(), eq(CHANGE_TASKBAR_PINNING))
}
@@ -194,7 +202,7 @@
DisplayController.enableTaskbarModePreferenceForTests(true)
assertTrue(displayController.getInfo().isTransientTaskbar())
- displayController.handleInfoChange(display)
+ displayController.handleInfoChange()
verify(displayInfoChangeListener)
.onDisplayInfoChanged(any(), any(), eq(CHANGE_TASKBAR_PINNING))
assertFalse(displayController.getInfo().isTransientTaskbar())