Merge "Moving grid customization provider to Dagger" into main
diff --git a/quickstep/res/layout/icon_app_chip_view.xml b/quickstep/res/layout/icon_app_chip_view.xml
index 00b5392..0972be1 100644
--- a/quickstep/res/layout/icon_app_chip_view.xml
+++ b/quickstep/res/layout/icon_app_chip_view.xml
@@ -51,7 +51,7 @@
<TextView
android:id="@+id/icon_text_collapsed"
android:layout_width="@dimen/task_thumbnail_icon_menu_text_collapsed_max_width"
- android:layout_height="@dimen/task_thumbnail_icon_menu_app_icon_collapsed_size"
+ android:layout_height="wrap_content"
android:gravity="start|center_vertical"
android:maxLines="1"
android:ellipsize="end"
@@ -62,7 +62,7 @@
<TextView
android:id="@+id/icon_text_expanded"
android:layout_width="@dimen/task_thumbnail_icon_menu_text_expanded_max_width"
- android:layout_height="@dimen/task_thumbnail_icon_menu_app_icon_collapsed_size"
+ android:layout_height="wrap_content"
android:gravity="start|center_vertical"
android:maxLines="1"
android:ellipsize="end"
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index 5f2a63d..f8ca8d9 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -321,6 +321,7 @@
<item name="android:fontFamily">google-sans-text-medium</item>
<item name="android:textSize">@dimen/task_thumbnail_icon_menu_text_size</item>
<item name="android:textColor">@color/materialColorOnSurface</item>
+ <item name="android:includeFontPadding">false</item>
<item name="android:letterSpacing">0.025</item>
<item name="android:lineHeight">20sp</item>
</style>
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index c748385..67feb6a 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -226,7 +226,6 @@
private static final int TASKBAR_TO_HOME_DURATION_FAST = 300;
private static final int TASKBAR_TO_HOME_DURATION_SLOW = 1000;
protected static final int CONTENT_SCALE_DURATION = 350;
- protected static final int CONTENT_SCRIM_DURATION = 350;
private static final int MAX_NUM_TASKS = 5;
@@ -244,7 +243,13 @@
private final StartingWindowListener mStartingWindowListener =
new StartingWindowListener(this);
- private ContentObserver mAnimationRemovalObserver = new ContentObserver(
+
+ // TODO(b/397690719): Investigate the memory leak from TaskStackChangeListeners#mImpl
+ // This is a temporary fix of memory leak b/397690719. We track registered
+ // {@link TaskRestartedDuringLaunchListener}, and remove them on activity destroy.
+ private final List<TaskRestartedDuringLaunchListener> mRegisteredTaskStackChangeListener =
+ new ArrayList<>();
+ private final ContentObserver mAnimationRemovalObserver = new ContentObserver(
ORDERED_BG_EXECUTOR.getHandler()) {
@Override
public void onChange(boolean selfChange) {
@@ -338,7 +343,14 @@
TaskRestartedDuringLaunchListener restartedListener =
new TaskRestartedDuringLaunchListener();
restartedListener.register(onEndCallback::executeAllAndDestroy);
- onEndCallback.add(restartedListener::unregister);
+ mRegisteredTaskStackChangeListener.add(restartedListener);
+ onEndCallback.add(new Runnable() {
+ @Override
+ public void run() {
+ restartedListener.unregister();
+ mRegisteredTaskStackChangeListener.remove(restartedListener);
+ }
+ });
RemoteAnimationRunnerCompat runner = createAppLaunchRunner(v, onEndCallback);
@@ -1210,6 +1222,12 @@
SystemUiProxy.INSTANCE.get(mLauncher).setStartingWindowListener(null);
ORDERED_BG_EXECUTOR.execute(() -> mLauncher.getContentResolver()
.unregisterContentObserver(mAnimationRemovalObserver));
+ if (BuildConfig.IS_STUDIO_BUILD && !mRegisteredTaskStackChangeListener.isEmpty()) {
+ throw new IllegalStateException("Failed to run onEndCallback created from"
+ + " getActivityLaunchOptions()");
+ }
+ mRegisteredTaskStackChangeListener.forEach(TaskRestartedDuringLaunchListener::unregister);
+ mRegisteredTaskStackChangeListener.clear();
}
/**
diff --git a/quickstep/src/com/android/launcher3/desktop/DesktopAppLaunchAnimatorHelper.kt b/quickstep/src/com/android/launcher3/desktop/DesktopAppLaunchAnimatorHelper.kt
index adbcc75..533a86a 100644
--- a/quickstep/src/com/android/launcher3/desktop/DesktopAppLaunchAnimatorHelper.kt
+++ b/quickstep/src/com/android/launcher3/desktop/DesktopAppLaunchAnimatorHelper.kt
@@ -21,6 +21,7 @@
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Rect
+import android.util.Log
import android.view.Choreographer
import android.view.SurfaceControl.Transaction
import android.view.WindowManager.TRANSIT_CLOSE
@@ -63,7 +64,19 @@
fun createAnimators(info: TransitionInfo, finishCallback: (Animator) -> Unit): List<Animator> {
val launchChange = getLaunchChange(info)
- requireNotNull(launchChange) { "expected an app launch Change" }
+ requireNotNull(launchChange) {
+ val changesString =
+ info.changes.joinToString(", ") { change ->
+ "Change: mode=${change.mode}, " +
+ "taskId=${change.taskInfo?.id}, " +
+ "isFreeform=${change.taskInfo?.isFreeform}"
+ }
+ Log.e(
+ TAG,
+ "No launch change found: Transition type=${info.type}, changes=$changesString",
+ )
+ "expected an app launch Change"
+ }
val transaction = transactionSupplier.get()
@@ -189,4 +202,8 @@
}
}
}
+
+ private companion object {
+ const val TAG = "DesktopAppLaunchAnimatorHelper"
+ }
}
diff --git a/quickstep/src/com/android/launcher3/desktop/DesktopAppLaunchTransition.kt b/quickstep/src/com/android/launcher3/desktop/DesktopAppLaunchTransition.kt
index 578bba5..79072a6 100644
--- a/quickstep/src/com/android/launcher3/desktop/DesktopAppLaunchTransition.kt
+++ b/quickstep/src/com/android/launcher3/desktop/DesktopAppLaunchTransition.kt
@@ -19,6 +19,7 @@
import android.animation.Animator
import android.content.Context
import android.os.IBinder
+import android.util.Log
import android.view.SurfaceControl.Transaction
import android.view.WindowManager.TRANSIT_OPEN
import android.view.WindowManager.TRANSIT_TO_FRONT
@@ -43,7 +44,7 @@
@JvmOverloads
constructor(
context: Context,
- launchType: AppLaunchType,
+ private val launchType: AppLaunchType,
@Cuj.CujType private val cujType: Int,
private val mainExecutor: Executor,
transactionSupplier: Supplier<Transaction> = Supplier { Transaction() },
@@ -66,6 +67,7 @@
transaction: Transaction,
transitionFinishedCallback: IRemoteTransitionFinishedCallback,
) {
+ Log.v(TAG, "startAnimation: launchType=$launchType, cujType=$cujType")
val safeTransitionFinishedCallback = RemoteRunnable {
transitionFinishedCallback.onTransitionFinished(/* wct= */ null, /* sct= */ null)
}
@@ -86,6 +88,7 @@
}
companion object {
+ const val TAG = "DesktopAppLaunchTransition"
/** Change modes that represent a task becoming visible / launching in Desktop mode. */
val LAUNCH_CHANGE_MODES = intArrayOf(TRANSIT_OPEN, TRANSIT_TO_FRONT)
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.kt b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.kt
index 37e8d4d..6ee43ff 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.kt
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.kt
@@ -62,8 +62,6 @@
* (Used only when multiple desks are enabled).
*
* @property displayId The ID of the display this object represents.
- * @property canCreateDesks true if it's possible to create new desks on the display represented
- * by this object.
* @property activeDeskId The ID of the active desk on the associated display (if any). It has a
* value of `INACTIVE_DESK_ID` (-1) if there are no active desks. Note that there can only be
* at most one active desk on each display.
@@ -71,11 +69,18 @@
*/
private data class DisplayDeskConfig(
val displayId: Int,
- var canCreateDesks: Boolean,
var activeDeskId: Int = INACTIVE_DESK_ID,
val deskIds: MutableSet<Int>,
)
+ /** True if it is possible to create new desks on current setup. */
+ var canCreateDesks: Boolean = false
+ private set(value) {
+ if (field == value) return
+ field = value
+ desktopVisibilityListeners.forEach { it.onCanCreateDesksChanged(field) }
+ }
+
/** Maps each display by its ID to its desks configuration. */
private val displaysDesksConfigsMap = SparseArray<DisplayDeskConfig>()
@@ -393,7 +398,10 @@
}
}
- private fun onListenerConnected(displayDeskStates: Array<DisplayDeskState>) {
+ private fun onListenerConnected(
+ displayDeskStates: Array<DisplayDeskState>,
+ canCreateDesks: Boolean,
+ ) {
if (!DesktopModeStatus.enableMultipleDesktops(context)) {
return
}
@@ -404,23 +412,24 @@
displaysDesksConfigsMap[displayDeskState.displayId] =
DisplayDeskConfig(
displayId = displayDeskState.displayId,
- canCreateDesks = displayDeskState.canCreateDesk,
activeDeskId = displayDeskState.activeDeskId,
deskIds = displayDeskState.deskIds.toMutableSet(),
)
}
+
+ this.canCreateDesks = canCreateDesks
}
private fun getDisplayDeskConfig(displayId: Int) =
displaysDesksConfigsMap[displayId]
?: null.also { Slog.e(TAG, "Expected non-null desk config for display: $displayId") }
- private fun onCanCreateDesksChanged(displayId: Int, canCreateDesks: Boolean) {
+ private fun onCanCreateDesksChanged(canCreateDesks: Boolean) {
if (!DesktopModeStatus.enableMultipleDesktops(context)) {
return
}
- getDisplayDeskConfig(displayId)?.canCreateDesks = canCreateDesks
+ this.canCreateDesks = canCreateDesks
}
private fun onDeskAdded(displayId: Int, deskId: Int) {
@@ -525,9 +534,12 @@
) : Stub() {
private val controller = WeakReference(controller)
- override fun onListenerConnected(displayDeskStates: Array<DisplayDeskState>) {
+ override fun onListenerConnected(
+ displayDeskStates: Array<DisplayDeskState>,
+ canCreateDesks: Boolean,
+ ) {
Executors.MAIN_EXECUTOR.execute {
- controller.get()?.onListenerConnected(displayDeskStates)
+ controller.get()?.onListenerConnected(displayDeskStates, canCreateDesks)
}
}
@@ -565,9 +577,9 @@
override fun onExitDesktopModeTransitionStarted(transitionDuration: Int) {}
- override fun onCanCreateDesksChanged(displayId: Int, canCreateDesks: Boolean) {
+ override fun onCanCreateDesksChanged(canCreateDesks: Boolean) {
Executors.MAIN_EXECUTOR.execute {
- controller.get()?.onCanCreateDesksChanged(displayId, canCreateDesks)
+ controller.get()?.onCanCreateDesksChanged(canCreateDesks)
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index d1e63f3..2eb4412 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -18,6 +18,7 @@
import static android.os.Trace.TRACE_TAG_APP;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
@@ -876,7 +877,7 @@
@Override
public void onPopupVisibilityChanged(boolean isVisible) {
- setTaskbarWindowFocusable(isVisible);
+ setTaskbarWindowFocusable(isVisible /* focusable */, false /* imeFocusable */);
}
@Override
@@ -1235,17 +1236,29 @@
}
/**
- * Either adds or removes {@link WindowManager.LayoutParams#FLAG_NOT_FOCUSABLE} on the taskbar
- * window.
+ * Sets whether the taskbar window should be focusable and IME focusable. This won't be IME
+ * focusable unless it is also focusable.
+ *
+ * @param focusable whether it should be focusable.
+ * @param imeFocusable whether it should be IME focusable.
+ *
+ * @see WindowManager.LayoutParams#FLAG_NOT_FOCUSABLE
+ * @see WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM
*/
- public void setTaskbarWindowFocusable(boolean focusable) {
+ public void setTaskbarWindowFocusable(boolean focusable, boolean imeFocusable) {
if (isPhoneMode()) {
return;
}
if (focusable) {
mWindowLayoutParams.flags &= ~FLAG_NOT_FOCUSABLE;
+ if (imeFocusable) {
+ mWindowLayoutParams.flags &= ~FLAG_ALT_FOCUSABLE_IM;
+ } else {
+ mWindowLayoutParams.flags |= FLAG_ALT_FOCUSABLE_IM;
+ }
} else {
mWindowLayoutParams.flags |= FLAG_NOT_FOCUSABLE;
+ mWindowLayoutParams.flags &= ~FLAG_ALT_FOCUSABLE_IM;
}
notifyUpdateLayoutParams();
}
@@ -1266,8 +1279,12 @@
}
/**
- * Either adds or removes {@link WindowManager.LayoutParams#FLAG_NOT_FOCUSABLE} on the taskbar
- * window. If we're now focusable, also move nav buttons to a separate window above IME.
+ * Sets whether the taskbar window should be focusable, as well as IME focusable. If we're now
+ * focusable, also move nav buttons to a separate window above IME.
+ *
+ * @param focusable whether it should be focusable.
+ *
+ * @see WindowManager.LayoutParams#FLAG_NOT_FOCUSABLE
*/
public void setTaskbarWindowFocusableForIme(boolean focusable) {
if (focusable) {
@@ -1275,7 +1292,7 @@
} else {
mControllers.navbarButtonsViewController.moveNavButtonsBackToTaskbarWindow();
}
- setTaskbarWindowFocusable(focusable);
+ setTaskbarWindowFocusable(focusable, true /* imeFocusable */);
}
/** Adds the given view to WindowManager with the provided LayoutParams (creates new window). */
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 6cd2979..34bb6e0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -45,6 +45,7 @@
import android.os.Handler;
import android.os.Trace;
import android.provider.Settings;
+import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -75,14 +76,20 @@
import com.android.quickstep.fallback.window.RecentsDisplayModel;
import com.android.quickstep.fallback.window.RecentsWindowManager;
import com.android.quickstep.util.ContextualSearchInvoker;
+import com.android.quickstep.util.GroupTask;
import com.android.quickstep.views.RecentsViewContainer;
+import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.statusbar.phone.BarTransitions;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
+import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
import java.io.PrintWriter;
+import java.util.Set;
import java.util.StringJoiner;
/**
@@ -194,6 +201,65 @@
recreateTaskbar();
};
+ private final PerceptibleTaskListener mTaskStackListener;
+
+ private class PerceptibleTaskListener implements TaskStackChangeListener {
+ private ArraySet<Integer> mPerceptibleTasks = new ArraySet<Integer>();
+
+ @Override
+ public void onTaskMovedToFront(int taskId) {
+ if (mPerceptibleTasks.contains(taskId)) {
+ return;
+ }
+
+ // This listens to any Task, so we filter them by the ones shown in the launcher.
+ // For Tasks restored after startup, they will by default not be Perceptible, and no
+ // need to until user interacts with it by bringing it to the foreground.
+ for (int i = 0; i < mTaskbars.size(); i++) {
+ // get pinned tasks
+ Set<Integer> taskbarPinnedTasks =
+ mTaskbars.valueAt(i).getControllers().taskbarViewController
+ .getTaskIdsForPinnedApps();
+
+ // mark as perceptible if the foregrounded task is in the list of apps shown in
+ // the launcher.
+ if (taskbarPinnedTasks.contains(taskId)
+ && ActivityManagerWrapper.getInstance()
+ .setTaskIsPerceptible(taskId, true)
+ ) {
+ mPerceptibleTasks.add(taskId);
+ }
+ }
+ }
+
+ /**
+ * Launcher also can display recently launched tasks that are not pinned. Also add
+ * these as perceptible
+ */
+ @Override
+ public void onRecentTaskListUpdated() {
+ for (int i = 0; i < mTaskbars.size(); i++) {
+ for (GroupTask gTask : mTaskbars.valueAt(i).getControllers()
+ .taskbarRecentAppsController.getShownTasks()) {
+ for (Task task : gTask.getTasks()) {
+ int taskId = task.key.id;
+
+ if (!mPerceptibleTasks.contains(taskId)) {
+ ActivityManagerWrapper.getInstance()
+ .setTaskIsPerceptible(taskId, true);
+ mPerceptibleTasks.add(taskId);
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onTaskRemoved(int taskId) {
+ mPerceptibleTasks.remove(taskId);
+ }
+ };
+
private boolean mUserUnlocked = false;
private final SimpleBroadcastReceiver mTaskbarBroadcastReceiver;
@@ -296,6 +362,12 @@
mTaskbarBroadcastReceiver.register(RECEIVER_NOT_EXPORTED, ACTION_SHOW_TASKBAR);
});
+ if (ActivityManagerWrapper.usePerceptibleTasks(getPrimaryWindowContext())) {
+ mTaskStackListener = new PerceptibleTaskListener();
+ TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener);
+ } else {
+ mTaskStackListener = null;
+ }
debugTaskbarManager("TaskbarManager created");
recreateTaskbar();
}
@@ -709,15 +781,14 @@
return;
}
- // TODO (b/391965805): remove once onDisplayAddSystemDecorations is working.
- WindowManager wm = getWindowManager(displayId);
- if (wm == null || !wm.shouldShowSystemDecors(displayId)) {
- return;
- }
-
Context newWindowContext = createWindowContext(displayId);
if (newWindowContext != null) {
addWindowContextToMap(displayId, newWindowContext);
+ // TODO (b/391965805): remove once onDisplayAddSystemDecorations is working.
+ WindowManager wm = getWindowManager(displayId);
+ if (wm == null || !wm.shouldShowSystemDecors(displayId)) {
+ return;
+ }
createTaskbarRootLayout(displayId);
createNavButtonController(displayId);
createAndRegisterComponentCallbacks(displayId);
@@ -788,6 +859,12 @@
Log.d(TASKBAR_NOT_DESTROYED_TAG, "unregistering component callbacks from destroy().");
removeAndUnregisterComponentCallbacks(getDefaultDisplayId());
mShutdownReceiver.unregisterReceiverSafely();
+ if (ActivityManagerWrapper.usePerceptibleTasks(getPrimaryWindowContext())) {
+ for (Integer taskId: mTaskStackListener.mPerceptibleTasks) {
+ ActivityManagerWrapper.getInstance().setTaskIsPerceptible(taskId, false);
+ }
+ }
+ TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener);
destroyAllTaskbars();
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt b/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt
index 6e901ee..1f34969 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt
+++ b/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt
@@ -144,7 +144,7 @@
override fun isNonResizeableActivity(lai: LauncherActivityInfo) =
lai.activityInfo.resizeMode == ActivityInfo.RESIZE_MODE_UNRESIZEABLE
- override fun supportsMultiInstance(lai: LauncherActivityInfo) : Boolean {
+ override fun supportsMultiInstance(lai: LauncherActivityInfo): Boolean {
return try {
super.supportsMultiInstance(lai) || lai.supportsMultiInstance()
} catch (e: Exception) {
@@ -202,4 +202,7 @@
(appInfo.sourceDir?.hashCode() ?: 0).toString() + " " + appInfo.longVersionCode
override fun getRoundIconRes(appInfo: ApplicationInfo) = appInfo.roundIconRes
+
+ override fun isFileDrawable(shortcutInfo: ShortcutInfo) =
+ shortcutInfo.hasIconFile() || shortcutInfo.hasIconUri()
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
index 10513c0..b27c6e8 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -153,7 +153,7 @@
return new PageAlphaProvider(DECELERATE_2) {
@Override
public float getPageAlpha(int pageIndex) {
- return launcher.getDeviceProfile().shouldShowAllAppsOnSheet()
+ return launcher.getDeviceProfile().isTablet
? superPageAlphaProvider.getPageAlpha(pageIndex)
: 0;
}
@@ -164,7 +164,7 @@
public int getVisibleElements(Launcher launcher) {
int elements = ALL_APPS_CONTENT | FLOATING_SEARCH_BAR;
// When All Apps is presented on a bottom sheet, HOTSEAT_ICONS are visible.
- if (launcher.getDeviceProfile().shouldShowAllAppsOnSheet()) {
+ if (launcher.getDeviceProfile().isTablet) {
elements |= HOTSEAT_ICONS;
}
return elements;
diff --git a/quickstep/src/com/android/quickstep/DesktopFullscreenDrawParams.kt b/quickstep/src/com/android/quickstep/DesktopFullscreenDrawParams.kt
index bafb0b2..444e77d 100644
--- a/quickstep/src/com/android/quickstep/DesktopFullscreenDrawParams.kt
+++ b/quickstep/src/com/android/quickstep/DesktopFullscreenDrawParams.kt
@@ -17,7 +17,7 @@
package com.android.quickstep
import android.content.Context
-import com.android.systemui.shared.system.QuickStepContract
+import com.android.launcher3.R
// DesktopTaskView thumbnail's corner radius is independent of fullscreenProgress.
open class DesktopFullscreenDrawParams
@@ -28,6 +28,6 @@
// computeCornerRadius is used as cornerRadiusProvider, so
// QuickStepContract::getWindowCornerRadius can be mocked properly.
private fun computeCornerRadius(context: Context): Float =
- QuickStepContract.getWindowCornerRadius(context)
+ context.resources.getDimension(R.dimen.desktop_windowing_freeform_rounded_corner_radius)
}
}
diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
index c986b88..953b0c5 100644
--- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
@@ -92,6 +92,8 @@
private static final String LOG_TAG = "AllSetActivity";
private static final String URI_SYSTEM_NAVIGATION_SETTING =
"#Intent;action=com.android.settings.SEARCH_RESULT_TRAMPOLINE;S.:settings:fragment_args_key=gesture_system_navigation_input_summary;S.:settings:show_fragment=com.android.settings.gestures.SystemNavigationGestureSettings;end";
+ private static final String INTENT_ACTION_ACTIVITY_CLOSED =
+ "com.android.quickstep.interaction.ACTION_ALL_SET_ACTIVITY_CLOSED";
private static final String EXTRA_ACCENT_COLOR_DARK_MODE = "suwColorAccentDark";
private static final String EXTRA_ACCENT_COLOR_LIGHT_MODE = "suwColorAccentLight";
private static final String EXTRA_DEVICE_NAME = "suwDeviceName";
@@ -332,6 +334,7 @@
mLauncherStartAnim.dispatchOnEnd();
mLauncherStartAnim = null;
}
+ sendBroadcast(new Intent(INTENT_ACTION_ACTIVITY_CLOSED));
}
@Override
diff --git a/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegate.kt b/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegate.kt
index 608fafd..12616a8 100644
--- a/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegate.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegate.kt
@@ -17,6 +17,7 @@
package com.android.quickstep.recents.data
import android.os.UserHandle
+import android.util.Log
import com.android.quickstep.HighResLoadingState.HighResLoadingStateChangedCallback
import com.android.quickstep.recents.data.TaskVisualsChangedDelegate.TaskIconChangedCallback
import com.android.quickstep.recents.data.TaskVisualsChangedDelegate.TaskThumbnailChangedCallback
@@ -58,7 +59,7 @@
fun onTaskThumbnailChanged(thumbnailData: ThumbnailData?)
/** Informs the listener that the default resolution for loading thumbnails has changed */
- fun onHighResLoadingStateChanged()
+ fun onHighResLoadingStateChanged(highResEnabled: Boolean)
}
}
@@ -91,8 +92,9 @@
}
override fun onHighResLoadingStateChanged(enabled: Boolean) {
+ Log.d(TAG, "onHighResLoadingStateChanged(enabled = $enabled)")
taskThumbnailChangedCallbacks.values.forEach { (_, callback) ->
- callback.onHighResLoadingStateChanged()
+ callback.onHighResLoadingStateChanged(enabled)
}
}
@@ -142,4 +144,8 @@
}
}
}
+
+ companion object {
+ const val TAG = "TaskVisualsChangedDelegateImpl"
+ }
}
diff --git a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
index b1a5920..5274ef3 100644
--- a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
@@ -160,7 +160,17 @@
updateThumbnail(task.key.id, thumbnailData)
}
- override fun onHighResLoadingStateChanged() {
+ override fun onHighResLoadingStateChanged(highResEnabled: Boolean) {
+ val isTaskVisible = taskRequests.containsKey(task.key.id)
+ if (!isTaskVisible) return
+
+ val isCurrentThumbnailLowRes =
+ tasks.value[task.key.id]?.thumbnail?.reducedResolution
+ val isRequestedResHigherThanCurrent =
+ isCurrentThumbnailLowRes == null ||
+ (isCurrentThumbnailLowRes && highResEnabled)
+ if (!isRequestedResHigherThanCurrent) return
+
recentsCoroutineScope.launch(dispatcherProvider.background) {
updateThumbnail(task.key.id, getThumbnailFromDataSource(task))
}
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
index e672ec4..e91073a 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
@@ -20,6 +20,7 @@
import android.graphics.Color
import android.graphics.Matrix
import android.graphics.Outline
+import android.graphics.Path
import android.graphics.Rect
import android.graphics.drawable.ShapeDrawable
import android.util.AttributeSet
@@ -52,6 +53,7 @@
private val dimAlpha: MultiPropertyFactory<View> by lazy {
MultiPropertyFactory(scrimView, VIEW_ALPHA, ScrimViewAlpha.entries.size, ::maxOf)
}
+ private val outlinePath = Path()
private var onSizeChanged: ((width: Int, height: Int) -> Unit)? = null
private var taskThumbnailViewHeader: TaskThumbnailViewHeader? = null
@@ -96,7 +98,20 @@
outlineProvider =
object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
- outline.setRoundRect(outlineBounds ?: bounds, cornerRadius)
+ val outlineRect = outlineBounds ?: bounds
+ outlinePath.apply {
+ rewind()
+ addRoundRect(
+ outlineRect.left.toFloat(),
+ outlineRect.top.toFloat(),
+ outlineRect.right.toFloat(),
+ outlineRect.bottom.toFloat(),
+ cornerRadius / scaleX,
+ cornerRadius / scaleY,
+ Path.Direction.CW,
+ )
+ }
+ outline.setPath(outlinePath)
}
}
}
diff --git a/quickstep/src/com/android/quickstep/util/TaskRestartedDuringLaunchListener.java b/quickstep/src/com/android/quickstep/util/TaskRestartedDuringLaunchListener.java
index 91e8376..6e2d469 100644
--- a/quickstep/src/com/android/quickstep/util/TaskRestartedDuringLaunchListener.java
+++ b/quickstep/src/com/android/quickstep/util/TaskRestartedDuringLaunchListener.java
@@ -16,16 +16,11 @@
package com.android.quickstep.util;
-import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-
-import android.app.Activity;
import android.app.ActivityManager;
import android.util.Log;
import androidx.annotation.NonNull;
-import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter;
-import com.android.quickstep.RecentsModel;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
diff --git a/quickstep/src/com/android/quickstep/views/IconView.kt b/quickstep/src/com/android/quickstep/views/IconView.kt
index 6da52d6..cb69b22 100644
--- a/quickstep/src/com/android/quickstep/views/IconView.kt
+++ b/quickstep/src/com/android/quickstep/views/IconView.kt
@@ -78,7 +78,8 @@
override fun setDrawable(d: Drawable?) {
drawable?.callback = null
- drawable = d
+ // Copy drawable so that mutations below do not affect other users of the drawable
+ drawable = d?.constantState?.newDrawable()?.mutate()
drawable?.let {
it.callback = this
setDrawableSizeInternal(width, height)
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index a29d302..c5a76cb 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -157,6 +157,7 @@
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.statehandlers.DepthController;
+import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.statemanager.StatefulContainer;
@@ -179,6 +180,7 @@
import com.android.launcher3.util.VibratorWrapper;
import com.android.launcher3.util.ViewPool;
import com.android.launcher3.util.coroutines.DispatcherProvider;
+import com.android.launcher3.util.window.WindowManagerProxy.DesktopVisibilityListener;
import com.android.quickstep.BaseContainerInterface;
import com.android.quickstep.GestureState;
import com.android.quickstep.HighResLoadingState;
@@ -265,7 +267,7 @@
CONTAINER_TYPE extends Context & RecentsViewContainer & StatefulContainer<STATE_TYPE>,
STATE_TYPE extends BaseState<STATE_TYPE>> extends PagedView implements Insettable,
HighResLoadingState.HighResLoadingStateChangedCallback,
- TaskVisualsChangeListener {
+ TaskVisualsChangeListener, DesktopVisibilityListener {
private static final String TAG = "RecentsView";
private static final boolean DEBUG = false;
@@ -556,6 +558,10 @@
private final Rect mTaskViewDeadZoneRect = new Rect();
private final Rect mTopRowDeadZoneRect = new Rect();
private final Rect mBottomRowDeadZoneRect = new Rect();
+
+ @Nullable
+ private DesktopVisibilityController mDesktopVisibilityController = null;
+
/**
* Reflects if Recents is currently in the middle of a gesture, and if so, which tasks are
* running. If a gesture is not in progress, this will be null.
@@ -913,6 +919,8 @@
mAddDesktopButton = (AddDesktopButton) LayoutInflater.from(context).inflate(
R.layout.overview_add_desktop_button, this, false);
mAddDesktopButton.setOnClickListener(this::createDesk);
+
+ mDesktopVisibilityController = DesktopVisibilityController.INSTANCE.get(mContext);
}
mTaskViewPool = new ViewPool<>(context, this, R.layout.task, 20 /* max size */,
@@ -1227,13 +1235,16 @@
mSyncTransactionApplier = new SurfaceTransactionApplier(this);
runActionOnRemoteHandles(remoteTargetHandle -> remoteTargetHandle.getTransformParams()
.setSyncTransactionApplier(mSyncTransactionApplier));
- RecentsModel.INSTANCE.get(getContext()).addThumbnailChangeListener(this);
+ RecentsModel.INSTANCE.get(mContext).addThumbnailChangeListener(this);
mIPipAnimationListener.setActivityAndRecentsView(mContainer, this);
- SystemUiProxy.INSTANCE.get(getContext()).setPipAnimationListener(
+ SystemUiProxy.INSTANCE.get(mContext).setPipAnimationListener(
mIPipAnimationListener);
mOrientationState.initListeners();
mTaskOverlayFactory.initListeners();
mSplitSelectStateController.registerSplitListener(mSplitSelectionListener);
+ if (mDesktopVisibilityController != null) {
+ mDesktopVisibilityController.registerDesktopVisibilityListener(this);
+ }
}
@Override
@@ -1248,12 +1259,15 @@
runActionOnRemoteHandles(remoteTargetHandle -> remoteTargetHandle.getTransformParams()
.setSyncTransactionApplier(null));
executeSideTaskLaunchCallback();
- RecentsModel.INSTANCE.get(getContext()).removeThumbnailChangeListener(this);
- SystemUiProxy.INSTANCE.get(getContext()).setPipAnimationListener(null);
+ RecentsModel.INSTANCE.get(mContext).removeThumbnailChangeListener(this);
+ SystemUiProxy.INSTANCE.get(mContext).setPipAnimationListener(null);
mIPipAnimationListener.setActivityAndRecentsView(null, null);
mOrientationState.destroyListeners();
mTaskOverlayFactory.removeListeners();
mSplitSelectStateController.unregisterSplitListener(mSplitSelectionListener);
+ if (mDesktopVisibilityController != null) {
+ mDesktopVisibilityController.unregisterDesktopVisibilityListener(this);
+ }
reset();
}
@@ -6859,6 +6873,11 @@
}
}
+ @Override
+ public void onCanCreateDesksChanged(boolean canCreateDesks) {
+ // TODO: b/389209338 - update the AddDesktopButton's visibility on this.
+ }
+
/** Get the color used for foreground scrimming the RecentsView for sharing. */
public static int getForegroundScrimDimColor(Context context) {
return context.getColor(R.color.overview_foreground_scrim_color);
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt
index 49ec31d..ba54232 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -789,11 +789,11 @@
private fun updateThumbnailValidity(container: TaskContainer) {
container.isThumbnailValid =
- viewModel!!.isThumbnailValid(
+ viewModel?.isThumbnailValid(
thumbnail = container.thumbnailData,
width = container.thumbnailView.width,
height = container.thumbnailView.height,
- )
+ ) ?: return
applyThumbnailSplashAlpha()
}
@@ -810,7 +810,8 @@
*/
private fun updateThumbnailMatrix(container: TaskContainer, width: Int, height: Int) {
val thumbnailPosition =
- viewModel!!.getThumbnailPosition(container.thumbnailData, width, height, isLayoutRtl)
+ viewModel?.getThumbnailPosition(container.thumbnailData, width, height, isLayoutRtl)
+ ?: return
container.updateThumbnailMatrix(thumbnailPosition.matrix)
}
diff --git a/quickstep/tests/multivalentScreenshotTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewScreenshotTest.kt b/quickstep/tests/multivalentScreenshotTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewScreenshotTest.kt
index 6f0aaeb..80b2c16 100644
--- a/quickstep/tests/multivalentScreenshotTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewScreenshotTest.kt
+++ b/quickstep/tests/multivalentScreenshotTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewScreenshotTest.kt
@@ -213,6 +213,18 @@
}
}
+ @Test
+ fun taskThumbnailView_scaled_roundRoundedCorners() {
+ screenshotRule.screenshotTest("taskThumbnailView_scaledRoundedCorners") { activity ->
+ activity.actionBar?.hide()
+ createTaskThumbnailView(activity).apply {
+ scaleX = 0.75f
+ scaleY = 0.3f
+ setState(BackgroundOnly(Color.YELLOW))
+ }
+ }
+ }
+
private fun createTaskThumbnailView(context: Context): TaskThumbnailView {
val taskThumbnailView =
LayoutInflater.from(context).inflate(R.layout.task_thumbnail, null, false)
diff --git a/quickstep/tests/src/com/android/quickstep/desktop/DesktopAppLaunchTransitionManagerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/desktop/DesktopAppLaunchTransitionManagerTest.kt
similarity index 90%
rename from quickstep/tests/src/com/android/quickstep/desktop/DesktopAppLaunchTransitionManagerTest.kt
rename to quickstep/tests/multivalentTests/src/com/android/launcher3/desktop/DesktopAppLaunchTransitionManagerTest.kt
index 9ca9fe4..7ebef45 100644
--- a/quickstep/tests/src/com/android/quickstep/desktop/DesktopAppLaunchTransitionManagerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/desktop/DesktopAppLaunchTransitionManagerTest.kt
@@ -27,12 +27,10 @@
import android.window.TransitionFilter
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
import com.android.quickstep.SystemUiProxy
import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
import com.google.common.truth.Truth.assertThat
-import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -43,7 +41,6 @@
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
-import org.mockito.quality.Strictness
@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -51,12 +48,6 @@
@get:Rule val mSetFlagsRule = SetFlagsRule()
- private val mockitoSession =
- mockitoSession()
- .strictness(Strictness.LENIENT)
- .mockStatic(DesktopModeStatus::class.java)
- .startMocking()
-
private val context = mock<Context>()
private val systemUiProxy = mock<SystemUiProxy>()
private lateinit var transitionManager: DesktopAppLaunchTransitionManager
@@ -68,11 +59,6 @@
transitionManager = DesktopAppLaunchTransitionManager(context, systemUiProxy)
}
- @After
- fun tearDown() {
- mockitoSession.finishMocking()
- }
-
@Test
@EnableFlags(FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX)
fun registerTransitions_appLaunchFlagEnabled_registersTransition() {
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskThumbnailDataSource.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskThumbnailDataSource.kt
index e10afc4..40d5e02 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskThumbnailDataSource.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskThumbnailDataSource.kt
@@ -22,7 +22,6 @@
import com.android.systemui.shared.recents.model.ThumbnailData
import kotlinx.coroutines.yield
import org.mockito.kotlin.mock
-import org.mockito.kotlin.whenever
class FakeTaskThumbnailDataSource : TaskThumbnailDataSource {
@@ -31,6 +30,8 @@
private val completionPrevented: MutableSet<Int> = mutableSetOf()
private val getThumbnailCalls = mutableMapOf<Int, Int>()
+ var highResEnabled = true
+
/** Retrieves and sets a thumbnail on [task] from [taskIdToBitmap]. */
override suspend fun getThumbnail(task: Task): ThumbnailData {
getThumbnailCalls[task.key.id] = (getThumbnailCalls[task.key.id] ?: 0) + 1
@@ -38,9 +39,10 @@
while (task.key.id in completionPrevented) {
yield()
}
- return mock<ThumbnailData>().also {
- whenever(it.thumbnail).thenReturn(taskIdToBitmap[task.key.id])
- }
+ return ThumbnailData(
+ thumbnail = taskIdToBitmap[task.key.id],
+ reducedResolution = !highResEnabled,
+ )
}
fun getNumberOfGetThumbnailCalls(taskId: Int): Int = getThumbnailCalls[taskId] ?: 0
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegateTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegateTest.kt
index 41f6bfd..b91f8bd 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegateTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegateTest.kt
@@ -19,16 +19,19 @@
import android.content.ComponentName
import android.content.Intent
import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.quickstep.recents.data.TaskVisualsChangedDelegate.TaskIconChangedCallback
import com.android.quickstep.recents.data.TaskVisualsChangedDelegate.TaskThumbnailChangedCallback
import com.android.systemui.shared.recents.model.Task.TaskKey
import com.android.systemui.shared.recents.model.ThumbnailData
import com.google.common.truth.Truth.assertThat
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
import org.mockito.kotlin.verifyNoMoreInteractions
+@RunWith(AndroidJUnit4::class)
class TaskVisualsChangedDelegateTest {
private val taskVisualsChangeNotifier = FakeTaskVisualsChangeNotifier()
private val highResLoadingStateNotifier = FakeHighResLoadingStateNotifier()
@@ -83,21 +86,21 @@
// Correct match
systemUnderTest.registerTaskIconChangedCallback(
createTaskKey(id = 1, pkg = ALTERNATIVE_PACKAGE_NAME, userId = 1),
- expectedListener
+ expectedListener,
)
// 1 out of 2 match
systemUnderTest.registerTaskIconChangedCallback(
createTaskKey(id = 2, pkg = PACKAGE_NAME, userId = 1),
- listener
+ listener,
)
systemUnderTest.registerTaskIconChangedCallback(
createTaskKey(id = 3, pkg = ALTERNATIVE_PACKAGE_NAME, userId = 2),
- listener
+ listener,
)
// 0 out of 2 match
systemUnderTest.registerTaskIconChangedCallback(
createTaskKey(id = 4, pkg = PACKAGE_NAME, userId = 2),
- listener
+ listener,
)
systemUnderTest.onTaskIconChanged(ALTERNATIVE_PACKAGE_NAME, UserHandle(1))
@@ -112,11 +115,11 @@
val newListener = mock<TaskIconChangedCallback>()
systemUnderTest.registerTaskIconChangedCallback(
createTaskKey(id = 1, pkg = ALTERNATIVE_PACKAGE_NAME, userId = 1),
- replacedListener
+ replacedListener,
)
systemUnderTest.registerTaskIconChangedCallback(
createTaskKey(id = 1, pkg = ALTERNATIVE_PACKAGE_NAME, userId = 1),
- newListener
+ newListener,
)
systemUnderTest.onTaskIconChanged(ALTERNATIVE_PACKAGE_NAME, UserHandle(1))
@@ -132,11 +135,11 @@
val expectedThumbnailData = ThumbnailData(snapshotId = 12345)
systemUnderTest.registerTaskThumbnailChangedCallback(
createTaskKey(id = 1),
- expectedListener
+ expectedListener,
)
systemUnderTest.registerTaskThumbnailChangedCallback(
createTaskKey(id = 2),
- additionalListener
+ additionalListener,
)
systemUnderTest.onTaskThumbnailChanged(1, expectedThumbnailData)
@@ -146,22 +149,41 @@
}
@Test
- fun onHighResLoadingStateChanged_notifiesAllListeners() {
+ fun onHighResLoadingStateChanged_toEnabled_notifiesAllListeners() {
val expectedListener = mock<TaskThumbnailChangedCallback>()
val additionalListener = mock<TaskThumbnailChangedCallback>()
systemUnderTest.registerTaskThumbnailChangedCallback(
createTaskKey(id = 1),
- expectedListener
+ expectedListener,
)
systemUnderTest.registerTaskThumbnailChangedCallback(
createTaskKey(id = 2),
- additionalListener
+ additionalListener,
)
systemUnderTest.onHighResLoadingStateChanged(true)
- verify(expectedListener).onHighResLoadingStateChanged()
- verify(additionalListener).onHighResLoadingStateChanged()
+ verify(expectedListener).onHighResLoadingStateChanged(true)
+ verify(additionalListener).onHighResLoadingStateChanged(true)
+ }
+
+ @Test
+ fun onHighResLoadingStateChanged_toDisabled_notifiesAllListeners() {
+ val expectedListener = mock<TaskThumbnailChangedCallback>()
+ val additionalListener = mock<TaskThumbnailChangedCallback>()
+ systemUnderTest.registerTaskThumbnailChangedCallback(
+ createTaskKey(id = 1),
+ expectedListener,
+ )
+ systemUnderTest.registerTaskThumbnailChangedCallback(
+ createTaskKey(id = 2),
+ additionalListener,
+ )
+
+ systemUnderTest.onHighResLoadingStateChanged(false)
+
+ verify(expectedListener).onHighResLoadingStateChanged(false)
+ verify(additionalListener).onHighResLoadingStateChanged(false)
}
@Test
@@ -171,7 +193,7 @@
val expectedThumbnailData = ThumbnailData(snapshotId = 12345)
systemUnderTest.registerTaskThumbnailChangedCallback(
createTaskKey(id = 1),
- replacedListener1
+ replacedListener1,
)
systemUnderTest.registerTaskThumbnailChangedCallback(createTaskKey(id = 1), newListener1)
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
index 823f808..10be6fd 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
@@ -326,8 +326,9 @@
}
@Test
- fun onHighResLoadingStateChanged_setsNewThumbnailDataOnTask() =
+ fun onHighResLoadingStateChanged_highResReplacesLowResThumbnail() =
testScope.runTest {
+ taskThumbnailDataSource.highResEnabled = false
recentsModel.seedTasks(defaultTaskList)
systemUnderTest.getAllTaskData(forceRefresh = true)
@@ -337,16 +338,77 @@
val expectedPreviousBitmap = taskThumbnailDataSource.taskIdToBitmap[1]
val taskDataFlow = systemUnderTest.getTaskDataById(1)
- val task1ThumbnailValues = mutableListOf<Bitmap?>()
+ val task1ThumbnailValues = mutableListOf<ThumbnailData?>()
testScope.backgroundScope.launch {
- taskDataFlow.map { it?.thumbnail?.thumbnail }.toList(task1ThumbnailValues)
+ taskDataFlow.map { it?.thumbnail }.toList(task1ThumbnailValues)
}
taskThumbnailDataSource.taskIdToBitmap[1] = expectedBitmap
+ taskThumbnailDataSource.highResEnabled = true
taskVisualsChangedDelegate.onHighResLoadingStateChanged(true)
- assertThat(task1ThumbnailValues.first()).isEqualTo(expectedPreviousBitmap)
- assertThat(task1ThumbnailValues.last()).isEqualTo(expectedBitmap)
+ val firstThumbnailValue = task1ThumbnailValues.first()!!
+ assertThat(firstThumbnailValue.thumbnail).isEqualTo(expectedPreviousBitmap)
+ assertThat(firstThumbnailValue.reducedResolution).isTrue()
+
+ val lastThumbnailValue = task1ThumbnailValues.last()!!
+ assertThat(lastThumbnailValue.thumbnail).isEqualTo(expectedBitmap)
+ assertThat(lastThumbnailValue.reducedResolution).isFalse()
+ }
+
+ @Test
+ fun onHighResLoadingStateChanged_invisibleTaskIgnored() =
+ testScope.runTest {
+ taskThumbnailDataSource.highResEnabled = false
+ recentsModel.seedTasks(defaultTaskList)
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+
+ systemUnderTest.setVisibleTasks(setOf(1))
+
+ val invisibleTaskId = 2
+ val taskDataFlow = systemUnderTest.getTaskDataById(invisibleTaskId)
+
+ val task2ThumbnailValues = mutableListOf<ThumbnailData?>()
+ testScope.backgroundScope.launch {
+ taskDataFlow.map { it?.thumbnail }.toList(task2ThumbnailValues)
+ }
+
+ taskThumbnailDataSource.highResEnabled = true
+ taskVisualsChangedDelegate.onHighResLoadingStateChanged(true)
+
+ assertThat(task2ThumbnailValues.filterNotNull()).isEmpty()
+ assertThat(taskThumbnailDataSource.getNumberOfGetThumbnailCalls(2)).isEqualTo(0)
+ }
+
+ @Test
+ fun onHighResLoadingStateChanged_lowResDoesNotReplaceHighResThumbnail() =
+ testScope.runTest {
+ taskThumbnailDataSource.highResEnabled = true
+ recentsModel.seedTasks(defaultTaskList)
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+
+ systemUnderTest.setVisibleTasks(setOf(1))
+
+ val expectedBitmap = mock<Bitmap>()
+ val expectedPreviousBitmap = taskThumbnailDataSource.taskIdToBitmap[1]
+ val taskDataFlow = systemUnderTest.getTaskDataById(1)
+
+ val task1ThumbnailValues = mutableListOf<ThumbnailData?>()
+ testScope.backgroundScope.launch {
+ taskDataFlow.map { it?.thumbnail }.toList(task1ThumbnailValues)
+ }
+
+ taskThumbnailDataSource.taskIdToBitmap[1] = expectedBitmap
+ taskThumbnailDataSource.highResEnabled = false
+ taskVisualsChangedDelegate.onHighResLoadingStateChanged(false)
+
+ val firstThumbnailValue = task1ThumbnailValues.first()!!
+ assertThat(firstThumbnailValue.thumbnail).isEqualTo(expectedPreviousBitmap)
+ assertThat(firstThumbnailValue.reducedResolution).isFalse()
+
+ val lastThumbnailValue = task1ThumbnailValues.last()!!
+ assertThat(lastThumbnailValue.thumbnail).isEqualTo(expectedPreviousBitmap)
+ assertThat(lastThumbnailValue.reducedResolution).isFalse()
}
@Test
diff --git a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
index 76aab39..a523e02 100644
--- a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
@@ -20,6 +20,7 @@
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
+import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.view.Display.DEFAULT_DISPLAY
import androidx.test.platform.app.InstrumentationRegistry
@@ -106,6 +107,7 @@
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
+ @DisableFlags(Flags.FLAG_ENABLE_MODALS_FULLSCREEN_WITH_PERMISSION)
fun createDesktopTaskShortcutFactory_transparentTask() {
val baseComponent = ComponentName("", /* class */ "")
val taskKey =
diff --git a/quickstep/tests/src/com/android/quickstep/ExternalDisplaySystemShortcutTest.kt b/quickstep/tests/src/com/android/quickstep/ExternalDisplaySystemShortcutTest.kt
index 818841a..2db94f6 100644
--- a/quickstep/tests/src/com/android/quickstep/ExternalDisplaySystemShortcutTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/ExternalDisplaySystemShortcutTest.kt
@@ -20,6 +20,7 @@
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
+import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.SetFlagsRule
import android.view.Display.DEFAULT_DISPLAY
@@ -113,6 +114,7 @@
Flags.FLAG_MOVE_TO_EXTERNAL_DISPLAY_SHORTCUT,
Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY,
)
+ @DisableFlags(Flags.FLAG_ENABLE_MODALS_FULLSCREEN_WITH_PERMISSION)
fun createExternalDisplayTaskShortcut_transparentTask() {
val baseComponent = ComponentName("", /* class */ "")
val taskKey =
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index aaaa0e4..1c7f51c 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -50,6 +50,7 @@
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
import com.android.launcher3.util.TestUtil;
import com.android.launcher3.util.Wait;
+import com.android.launcher3.util.rule.ScreenRecordRule;
import com.android.launcher3.util.rule.TestStabilityRule;
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
@@ -542,6 +543,7 @@
@Test
@PortraitLandscape
+ @ScreenRecordRule.ScreenRecord // TODO(b/396447643): Remove screen record.
public void testDismissCancel() throws Exception {
startTestAppsWithCheck();
Overview overview = mLauncher.goHome().switchToOverview();
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 870e6d6..f189549 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -313,7 +313,7 @@
context,
gridName,
displayInfo,
- RestoreDbTask.isPending(mPrefs),
+ (RestoreDbTask.isPending(mPrefs) && !Flags.oneGridSpecs()),
mPrefs.get(FIXED_LANDSCAPE_MODE)
);
@@ -506,6 +506,7 @@
* Updates the current grid, this triggers a new IDP, reloads the database and triggers a grid
* migration.
*/
+ @VisibleForTesting
public void setCurrentGrid(Context context, String newGridName) {
mPrefs.put(GRID_NAME, newGridName);
MAIN_EXECUTOR.execute(() -> {
diff --git a/src/com/android/launcher3/icons/CacheableShortcutInfo.kt b/src/com/android/launcher3/icons/CacheableShortcutInfo.kt
index 225e12f..50dd146 100644
--- a/src/com/android/launcher3/icons/CacheableShortcutInfo.kt
+++ b/src/com/android/launcher3/icons/CacheableShortcutInfo.kt
@@ -30,6 +30,7 @@
import com.android.launcher3.icons.cache.BaseIconCache
import com.android.launcher3.icons.cache.CachingLogic
import com.android.launcher3.shortcuts.ShortcutKey
+import com.android.launcher3.util.ApiWrapper
import com.android.launcher3.util.ApplicationInfoWrapper
import com.android.launcher3.util.PackageUserKey
import com.android.launcher3.util.Themes
@@ -114,7 +115,15 @@
d,
IconOptions()
.setExtractedColor(Themes.getColorAccent(context))
- .setSourceHint(getSourceHint(info, cache)),
+ .setSourceHint(
+ getSourceHint(info, cache)
+ .copy(
+ isFileDrawable =
+ ApiWrapper.INSTANCE[context].isFileDrawable(
+ info.shortcutInfo
+ )
+ )
+ ),
)
} ?: BitmapInfo.LOW_RES_INFO
}
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index 34c9117..0da431f 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -51,6 +51,7 @@
import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread;
+import com.android.launcher3.Flags;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherFiles;
@@ -130,9 +131,11 @@
removeOldDBs(context, oldPhoneFileName);
// The idp before this contains data about the old phone, after this it becomes the idp
// of the current phone.
- FileLog.d(TAG, "Resetting IDP to default for restore dest device");
- idp.reset(context);
- trySettingPreviousGridAsCurrent(context, idp, oldPhoneFileName, previousDbs);
+ if (!Flags.oneGridSpecs()) {
+ FileLog.d(TAG, "Resetting IDP to default for restore dest device");
+ idp.reset(context);
+ trySettingPreviousGridAsCurrent(context, idp, oldPhoneFileName, previousDbs);
+ }
}
diff --git a/src/com/android/launcher3/shapes/ShapesProvider.kt b/src/com/android/launcher3/shapes/ShapesProvider.kt
index 463c816..5427c89 100644
--- a/src/com/android/launcher3/shapes/ShapesProvider.kt
+++ b/src/com/android/launcher3/shapes/ShapesProvider.kt
@@ -193,15 +193,6 @@
"M50 0C77.614 0 100 22.386 100 50C100 85.471 100 86.476 99.9 87.321 99.116 93.916 93.916 99.116 87.321 99.9 86.476 100 85.471 100 83.46 100H16.54C14.529 100 13.524 100 12.679 99.9 6.084 99.116 .884 93.916 .1 87.321 0 86.476 0 85.471 0 83.46L0 50C0 22.386 22.386 0 50 0Z",
folderPathString = folderShapes["arch"]!!,
),
- "sunny" to
- IconShapeModel(
- key = "sunny",
- title = "sunny",
- pathString =
- "M42.846 4.873C46.084 -.531 53.916 -.531 57.154 4.873L60.796 10.951C62.685 14.103 66.414 15.647 69.978 14.754L76.851 13.032C82.962 11.5 88.5 17.038 86.968 23.149L85.246 30.022C84.353 33.586 85.897 37.315 89.049 39.204L95.127 42.846C100.531 46.084 100.531 53.916 95.127 57.154L89.049 60.796C85.897 62.685 84.353 66.414 85.246 69.978L86.968 76.851C88.5 82.962 82.962 88.5 76.851 86.968L69.978 85.246C66.414 84.353 62.685 85.898 60.796 89.049L57.154 95.127C53.916 100.531 46.084 100.531 42.846 95.127L39.204 89.049C37.315 85.898 33.586 84.353 30.022 85.246L23.149 86.968C17.038 88.5 11.5 82.962 13.032 76.851L14.754 69.978C15.647 66.414 14.103 62.685 10.951 60.796L4.873 57.154C -.531 53.916 -.531 46.084 4.873 42.846L10.951 39.204C14.103 37.315 15.647 33.586 14.754 30.022L13.032 23.149C11.5 17.038 17.038 11.5 23.149 13.032L30.022 14.754C33.586 15.647 37.315 14.103 39.204 10.951L42.846 4.873Z",
- folderPathString = folderShapes["clover"]!!,
- iconScale = 72f / 92f,
- ),
)
} else {
mapOf(
diff --git a/src/com/android/launcher3/touch/AllAppsSwipeController.java b/src/com/android/launcher3/touch/AllAppsSwipeController.java
index 107bcc1..2cc4909 100644
--- a/src/com/android/launcher3/touch/AllAppsSwipeController.java
+++ b/src/com/android/launcher3/touch/AllAppsSwipeController.java
@@ -207,6 +207,11 @@
}
config.setInterpolator(ANIM_WORKSPACE_SCALE, DECELERATED_EASE);
config.setInterpolator(ANIM_DEPTH, DECELERATED_EASE);
+ if (launcher.getDeviceProfile().isPhone) {
+ config.setInterpolator(ANIM_WORKSPACE_FADE, INSTANT);
+ config.setInterpolator(ANIM_HOTSEAT_FADE, INSTANT);
+ config.animFlags |= StateAnimationConfig.SKIP_DEPTH_CONTROLLER;
+ }
} else {
if (config.isUserControlled()) {
config.setInterpolator(ANIM_DEPTH, Interpolators.reverse(BLUR_MANUAL));
@@ -248,6 +253,11 @@
}
config.setInterpolator(ANIM_WORKSPACE_SCALE, DECELERATED_EASE);
config.setInterpolator(ANIM_DEPTH, DECELERATED_EASE);
+ if (launcher.getDeviceProfile().isPhone) {
+ config.setInterpolator(ANIM_WORKSPACE_FADE, FINAL_FRAME);
+ config.setInterpolator(ANIM_HOTSEAT_FADE, FINAL_FRAME);
+ config.animFlags |= StateAnimationConfig.SKIP_DEPTH_CONTROLLER;
+ }
} else {
config.setInterpolator(ANIM_DEPTH,
config.isUserControlled() ? BLUR_MANUAL : BLUR_ATOMIC);
diff --git a/src/com/android/launcher3/util/ApiWrapper.java b/src/com/android/launcher3/util/ApiWrapper.java
index 56337b0..0510d59 100644
--- a/src/com/android/launcher3/util/ApiWrapper.java
+++ b/src/com/android/launcher3/util/ApiWrapper.java
@@ -216,6 +216,13 @@
return 0;
}
+ /**
+ * Checks if the shortcut is using an icon with file or URI source
+ */
+ public boolean isFileDrawable(@NonNull ShortcutInfo shortcutInfo) {
+ return false;
+ }
+
private static class NoopDrawable extends ColorDrawable {
@Override
public int getIntrinsicHeight() {
diff --git a/src/com/android/launcher3/util/window/WindowManagerProxy.java b/src/com/android/launcher3/util/window/WindowManagerProxy.java
index 647d170..11f0bc2 100644
--- a/src/com/android/launcher3/util/window/WindowManagerProxy.java
+++ b/src/com/android/launcher3/util/window/WindowManagerProxy.java
@@ -509,7 +509,17 @@
* @param isInDesktopModeAndNotInOverview True if a desktop is currently active on the given
* display, and Overview is currently inactive.
*/
- void onIsInDesktopModeChanged(int displayId, boolean isInDesktopModeAndNotInOverview);
+ default void onIsInDesktopModeChanged(int displayId,
+ boolean isInDesktopModeAndNotInOverview) {
+ }
+
+ /**
+ * Called whenever the conditions that allow the creation of desks change.
+ *
+ * @param canCreateDesks whether it is possible to create new desks.
+ */
+ default void onCanCreateDesksChanged(boolean canCreateDesks) {
+ }
}
}
diff --git a/tests/multivalentTests/src/com/android/launcher3/shapes/ShapesProviderTest.kt b/tests/multivalentTests/src/com/android/launcher3/shapes/ShapesProviderTest.kt
index 508c9a4..49d305b 100644
--- a/tests/multivalentTests/src/com/android/launcher3/shapes/ShapesProviderTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/shapes/ShapesProviderTest.kt
@@ -63,15 +63,6 @@
@Test
@EnableFlags(FLAG_ENABLE_LAUNCHER_ICON_SHAPES, FLAG_NEW_CUSTOMIZATION_PICKER_UI)
- fun `verify valid path sunny`() {
- ShapesProvider.iconShapes["sunny"]?.apply {
- GenericPathShape(pathString)
- PathParser.createPathFromPathData(pathString)
- }
- }
-
- @Test
- @EnableFlags(FLAG_ENABLE_LAUNCHER_ICON_SHAPES, FLAG_NEW_CUSTOMIZATION_PICKER_UI)
fun `verify valid path circle`() {
ShapesProvider.iconShapes["circle"]?.apply {
GenericPathShape(pathString)