From 3a7d13911051a2abf770b95bf59aa3fc8c9dc572 Mon Sep 17 00:00:00 2001 From: Jagrut Desai Date: Wed, 6 Sep 2023 15:56:19 -0700 Subject: [PATCH] Add isTransientTaskbar as DeviceProfile Builder Property - Breakout CL part 5 - This is a breakout cl from ag/24272821 to make it more readable and atomic. - This cl consist of adding isTransientTaskbar as DeviceProfile Builder Poropety - This cl alos consist a shared pref listener for taskbar pinning to update device profile. Test: Manual, Visual Bug: 265170176 Flag: ENABLE_TASKBAR_PINNING Change-Id: I2ade751ffc8c59bd4b862b56c8ca7eb2aa05b7f2 --- src/com/android/launcher3/DeviceProfile.java | 20 ++++- .../launcher3/InvariantDeviceProfile.java | 3 +- src/com/android/launcher3/LauncherPrefs.kt | 2 +- .../launcher3/util/DisplayController.java | 83 ++++++++++++++----- .../launcher3/AbstractDeviceProfileTest.kt | 5 +- .../FakeInvariantDeviceProfileTest.kt | 7 +- .../launcher3/util/DisplayControllerTest.kt | 13 +++ 7 files changed, 101 insertions(+), 32 deletions(-) diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index bf35a0fc32..d8804a163f 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -300,7 +300,6 @@ public class DeviceProfile { // If true, used to layout taskbar in 3 button navigation mode. public final boolean startAlignTaskbar; public final boolean isTransientTaskbar; - // DragController public int flingToDeleteThresholdVelocity; @@ -309,7 +308,8 @@ public class DeviceProfile { SparseArray dotRendererCache, boolean isMultiWindowMode, boolean transposeLayoutWithOrientation, boolean isMultiDisplay, boolean isGestureMode, @NonNull final ViewScaleProvider viewScaleProvider, - @NonNull final Consumer dimensionOverrideProvider) { + @NonNull final Consumer dimensionOverrideProvider, + boolean isTransientTaskbar) { this.inv = inv; this.isLandscape = windowBounds.isLandscape(); @@ -367,7 +367,7 @@ public class DeviceProfile { } } - isTransientTaskbar = DisplayController.isTransientTaskbar(context); + this.isTransientTaskbar = isTransientTaskbar; if (!isTaskbarPresent) { taskbarIconSize = taskbarHeight = stashedTaskbarHeight = taskbarBottomMargin = 0; startAlignTaskbar = false; @@ -2123,10 +2123,13 @@ public class DeviceProfile { private Consumer mOverrideProvider; + private boolean mIsTransientTaskbar; + public Builder(Context context, InvariantDeviceProfile inv, Info info) { mContext = context; mInv = inv; mInfo = info; + mIsTransientTaskbar = info.isTransientTaskbar(); } public Builder setMultiWindowMode(boolean isMultiWindowMode) { @@ -2177,6 +2180,15 @@ public class DeviceProfile { return this; } + /** + * Set the isTransientTaskbar for the builder + * @return This Builder + */ + public Builder setIsTransientTaskbar(boolean isTransientTaskbar) { + mIsTransientTaskbar = isTransientTaskbar; + return this; + } + public DeviceProfile build() { if (mWindowBounds == null) { throw new IllegalArgumentException("Window bounds not set"); @@ -2198,7 +2210,7 @@ public class DeviceProfile { } return new DeviceProfile(mContext, mInv, mInfo, mWindowBounds, mDotRendererCache, mIsMultiWindowMode, mTransposeLayoutWithOrientation, mIsMultiDisplay, - mIsGestureMode, mViewScaleProvider, mOverrideProvider); + mIsGestureMode, mViewScaleProvider, mOverrideProvider, mIsTransientTaskbar); } } } diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java index 8707aba60b..04e8da1f3b 100644 --- a/src/com/android/launcher3/InvariantDeviceProfile.java +++ b/src/com/android/launcher3/InvariantDeviceProfile.java @@ -22,6 +22,7 @@ import static com.android.launcher3.testing.shared.ResourceUtils.INVALID_RESOURC import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY; import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE; import static com.android.launcher3.util.DisplayController.CHANGE_SUPPORTED_BOUNDS; +import static com.android.launcher3.util.DisplayController.CHANGE_TASKBAR_PINNING; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import android.annotation.TargetApi; @@ -224,7 +225,7 @@ public class InvariantDeviceProfile { DisplayController.INSTANCE.get(context).setPriorityListener( (displayContext, info, flags) -> { if ((flags & (CHANGE_DENSITY | CHANGE_SUPPORTED_BOUNDS - | CHANGE_NAVIGATION_MODE)) != 0) { + | CHANGE_NAVIGATION_MODE | CHANGE_TASKBAR_PINNING)) != 0) { onConfigChanged(displayContext); } }); diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt index 00bac1c78c..e8d5116431 100644 --- a/src/com/android/launcher3/LauncherPrefs.kt +++ b/src/com/android/launcher3/LauncherPrefs.kt @@ -287,7 +287,7 @@ class LauncherPrefs(private val encryptedContext: Context) { @JvmField val WORK_EDU_STEP = backedUpItem(WorkProfileManager.KEY_WORK_EDU_STEP, 0) @JvmField val WORKSPACE_SIZE = backedUpItem(DeviceGridState.KEY_WORKSPACE_SIZE, "", true) @JvmField val HOTSEAT_COUNT = backedUpItem(DeviceGridState.KEY_HOTSEAT_COUNT, -1, true) - @JvmField val TASKBAR_PINNING = backedUpItem(TASKBAR_PINNING_KEY, false) + @JvmField val TASKBAR_PINNING = backedUpItem(TASKBAR_PINNING_KEY, false, true) @JvmField val DEVICE_TYPE = diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java index a7c94bb726..26ab5b4cb4 100644 --- a/src/com/android/launcher3/util/DisplayController.java +++ b/src/com/android/launcher3/util/DisplayController.java @@ -20,6 +20,7 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING; +import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING_KEY; import static com.android.launcher3.Utilities.dpiFromPx; import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_PINNING; import static com.android.launcher3.config.FeatureFlags.ENABLE_TRANSIENT_TASKBAR; @@ -32,6 +33,7 @@ import android.annotation.TargetApi; import android.content.ComponentCallbacks; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.content.res.Configuration; import android.graphics.Point; import android.graphics.Rect; @@ -82,9 +84,11 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { public static final int CHANGE_DENSITY = 1 << 2; public static final int CHANGE_SUPPORTED_BOUNDS = 1 << 3; public static final int CHANGE_NAVIGATION_MODE = 1 << 4; + public static final int CHANGE_TASKBAR_PINNING = 1 << 5; public static final int CHANGE_ALL = CHANGE_ACTIVE_SCREEN | CHANGE_ROTATION - | CHANGE_DENSITY | CHANGE_SUPPORTED_BOUNDS | CHANGE_NAVIGATION_MODE; + | CHANGE_DENSITY | CHANGE_SUPPORTED_BOUNDS | CHANGE_NAVIGATION_MODE + | CHANGE_TASKBAR_PINNING; private static final String ACTION_OVERLAY_CHANGED = "android.intent.action.OVERLAY_CHANGED"; private static final String TARGET_OVERLAY_PACKAGE = "android"; @@ -104,13 +108,17 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { private Info mInfo; private boolean mDestroyed = false; - private final LauncherPrefs mPrefs; + private SharedPreferences.OnSharedPreferenceChangeListener + mTaskbarPinningPreferenceChangeListener; @VisibleForTesting protected DisplayController(Context context) { mContext = context; mDM = context.getSystemService(DisplayManager.class); - mPrefs = LauncherPrefs.get(context); + + if (ENABLE_TASKBAR_PINNING.get()) { + attachTaskbarPinningSharedPreferenceChangeListener(mContext); + } Display display = mDM.getDisplay(DEFAULT_DISPLAY); if (Utilities.ATLEAST_S) { @@ -131,6 +139,21 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { FileLog.i(TAG, "(CTOR) perDisplayBounds: " + mInfo.mPerDisplayBounds); } + private void attachTaskbarPinningSharedPreferenceChangeListener(Context context) { + mTaskbarPinningPreferenceChangeListener = + (sharedPreferences, key) -> { + if (TASKBAR_PINNING_KEY.equals(key) + && mInfo.mIsTaskbarPinned != LauncherPrefs.get(mContext).get( + TASKBAR_PINNING) + ) { + handleInfoChange(mWindowContext.getDisplay()); + } + }; + + LauncherPrefs.get(context).addListener( + mTaskbarPinningPreferenceChangeListener, TASKBAR_PINNING); + } + /** * Returns the current navigation mode */ @@ -142,25 +165,7 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { * Returns whether taskbar is transient. */ public static boolean isTransientTaskbar(Context context) { - return INSTANCE.get(context).isTransientTaskbar(); - } - - /** - * Returns whether taskbar is transient. - */ - public boolean isTransientTaskbar() { - // TODO(b/258604917): When running in test harness, use !sTransientTaskbarStatusForTests - // once tests are updated to expect new persistent behavior such as not allowing long press - // to stash. - if (!Utilities.isRunningInTestHarness() - && ENABLE_TASKBAR_PINNING.get() - && mPrefs.get(TASKBAR_PINNING)) { - return false; - } - return getInfo().navigationMode == NavigationMode.NO_BUTTON - && (Utilities.isRunningInTestHarness() - ? sTransientTaskbarStatusForTests - : ENABLE_TRANSIENT_TASKBAR.get()); + return INSTANCE.get(context).getInfo().isTransientTaskbar(); } /** @@ -174,6 +179,10 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { @Override public void close() { mDestroyed = true; + if (ENABLE_TASKBAR_PINNING.get()) { + LauncherPrefs.get(mContext).removeListener( + mTaskbarPinningPreferenceChangeListener, TASKBAR_PINNING); + } if (mWindowContext != null) { mWindowContext.unregisterComponentCallbacks(this); } else { @@ -256,7 +265,8 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { } @AnyThread - private void handleInfoChange(Display display) { + @VisibleForTesting + public void handleInfoChange(Display display) { WindowManagerProxy wmProxy = WindowManagerProxy.INSTANCE.get(mContext); Info oldInfo = mInfo; @@ -289,6 +299,9 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { FileLog.w(TAG, "(CHANGE_SUPPORTED_BOUNDS) perDisplayBounds: " + newInfo.mPerDisplayBounds); } + if (newInfo.mIsTaskbarPinned != oldInfo.mIsTaskbarPinned) { + change |= CHANGE_TASKBAR_PINNING; + } if (DEBUG) { Log.d(TAG, "handleInfoChange - change: " + getChangeFlagsString(change)); } @@ -331,6 +344,8 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { private final ArrayMap> mPerDisplayBounds = new ArrayMap<>(); + private final boolean mIsTaskbarPinned; + public Info(Context displayInfoContext) { /* don't need system overrides for external displays */ this(displayInfoContext, new WindowManagerProxy(), new ArrayMap<>()); @@ -387,6 +402,26 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { Log.d(TAG, "normalizedDisplayInfo: " + normalizedDisplayInfo); Log.d(TAG, "perDisplayBounds: " + mPerDisplayBounds); } + + mIsTaskbarPinned = LauncherPrefs.get(displayInfoContext).get(TASKBAR_PINNING); + } + + /** + * Returns whether taskbar is transient. + */ + public boolean isTransientTaskbar() { + // TODO(b/258604917): Once ENABLE_TASKBAR_PINNING is enabled, remove usage of + // sTransientTaskbarStatusForTests and update test to directly + // toggle shred preference to switch transient taskbar on/of + if (!Utilities.isRunningInTestHarness() + && ENABLE_TASKBAR_PINNING.get() + && mIsTaskbarPinned) { + return false; + } + return navigationMode == NavigationMode.NO_BUTTON + && (Utilities.isRunningInTestHarness() + ? sTransientTaskbarStatusForTests + : ENABLE_TRANSIENT_TASKBAR.get() && !mIsTaskbarPinned); } /** @@ -426,6 +461,7 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { appendFlag(result, change, CHANGE_DENSITY, "CHANGE_DENSITY"); appendFlag(result, change, CHANGE_SUPPORTED_BOUNDS, "CHANGE_SUPPORTED_BOUNDS"); appendFlag(result, change, CHANGE_NAVIGATION_MODE, "CHANGE_NAVIGATION_MODE"); + appendFlag(result, change, CHANGE_TASKBAR_PINNING, "CHANGE_TASKBAR_VARIANT"); return result.toString(); } @@ -440,6 +476,7 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { pw.println(" fontScale=" + info.fontScale); pw.println(" densityDpi=" + info.densityDpi); pw.println(" navigationMode=" + info.navigationMode.name()); + pw.println(" isTaskbarPinned=" + info.mIsTaskbarPinned); pw.println(" currentSize=" + info.currentSize); info.mPerDisplayBounds.forEach((key, value) -> pw.println( " perDisplayBounds - " + key + ": " + value)); diff --git a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt index ed8e32463e..a52ba9ee36 100644 --- a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt +++ b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt @@ -40,6 +40,7 @@ import org.junit.Before import org.junit.Rule import org.mockito.ArgumentMatchers import org.mockito.Mockito.mock +import org.mockito.Mockito.spy import org.mockito.Mockito.`when` as whenever /** @@ -306,9 +307,9 @@ abstract class AbstractDeviceProfileTest { } context = runningContext.createConfigurationContext(config) - val info = DisplayController.Info(context, windowManagerProxy, perDisplayBoundsCache) + val info = spy(DisplayController.Info(context, windowManagerProxy, perDisplayBoundsCache)) whenever(displayController.info).thenReturn(info) - whenever(displayController.isTransientTaskbar).thenReturn(isGestureMode) + whenever(info.isTransientTaskbar).thenReturn(isGestureMode) } /** Create a new dump of DeviceProfile, saves to a file in the device and returns it */ diff --git a/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt b/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt index c22cf40de6..42338bf5cc 100644 --- a/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt +++ b/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt @@ -47,6 +47,7 @@ abstract class FakeInvariantDeviceProfileTest { protected var transposeLayoutWithOrientation: Boolean = false protected var useTwoPanels: Boolean = false protected var isGestureMode: Boolean = true + protected var isTransientTaskbar: Boolean = true @Before fun setUp() { @@ -68,7 +69,8 @@ abstract class FakeInvariantDeviceProfileTest { useTwoPanels, isGestureMode, DEFAULT_PROVIDER, - DEFAULT_DIMENSION_PROVIDER + DEFAULT_DIMENSION_PROVIDER, + isTransientTaskbar, ) protected fun initializeVarsForPhone( @@ -93,6 +95,7 @@ abstract class FakeInvariantDeviceProfileTest { whenever(info.smallestSizeDp(any())).thenReturn(411f) this.isGestureMode = isGestureMode + this.isTransientTaskbar = false transposeLayoutWithOrientation = true inv = @@ -175,6 +178,7 @@ abstract class FakeInvariantDeviceProfileTest { whenever(info.smallestSizeDp(any())).thenReturn(800f) this.isGestureMode = isGestureMode + this.isTransientTaskbar = true useTwoPanels = false inv = @@ -258,6 +262,7 @@ abstract class FakeInvariantDeviceProfileTest { whenever(info.smallestSizeDp(any())).thenReturn(700f) this.isGestureMode = isGestureMode + this.isTransientTaskbar = true useTwoPanels = true inv = diff --git a/tests/src/com/android/launcher3/util/DisplayControllerTest.kt b/tests/src/com/android/launcher3/util/DisplayControllerTest.kt index 8e4e99812e..a94dd2e2d3 100644 --- a/tests/src/com/android/launcher3/util/DisplayControllerTest.kt +++ b/tests/src/com/android/launcher3/util/DisplayControllerTest.kt @@ -30,8 +30,10 @@ import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.launcher3.LauncherPrefs +import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING import com.android.launcher3.util.DisplayController.CHANGE_DENSITY import com.android.launcher3.util.DisplayController.CHANGE_ROTATION +import com.android.launcher3.util.DisplayController.CHANGE_TASKBAR_PINNING import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext import com.android.launcher3.util.window.CachedDisplayInfo @@ -89,6 +91,7 @@ class DisplayControllerTest { MockitoAnnotations.initMocks(this) whenever(context.getObject(eq(WindowManagerProxy.INSTANCE))).thenReturn(windowManagerProxy) whenever(context.getObject(eq(LauncherPrefs.INSTANCE))).thenReturn(launcherPrefs) + whenever(launcherPrefs.get(TASKBAR_PINNING)).thenReturn(false) // Mock WindowManagerProxy val displayInfo = @@ -107,6 +110,7 @@ class DisplayControllerTest { bounds[i.getArgument(1).rotation] } + whenever(windowManagerProxy.getNavigationMode(any())).thenReturn(NavigationMode.NO_BUTTON) // Mock context whenever(context.createWindowContext(any(), any(), nullable())).thenReturn(context) whenever(context.getSystemService(eq(DisplayManager::class.java))) @@ -156,4 +160,13 @@ class DisplayControllerTest { verify(displayInfoChangeListener).onDisplayInfoChanged(any(), any(), eq(CHANGE_DENSITY)) } + + @Test + @UiThreadTest + fun testTaskbarPinning() { + whenever(launcherPrefs.get(TASKBAR_PINNING)).thenReturn(true) + displayController.handleInfoChange(display) + verify(displayInfoChangeListener) + .onDisplayInfoChanged(any(), any(), eq(CHANGE_TASKBAR_PINNING)) + } }