Merge "Clear PredictorState targets when it's re-registered" into tm-qpr-dev
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
index ba412c9..80bdb6f 100644
--- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
+++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
@@ -193,7 +193,7 @@
icon.setEnabled(false);
icon.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
icon.verifyHighRes();
- CellLayoutLayoutParams lp = new CellLayoutLayoutParams(i, 0, 1, 1, -1);
+ CellLayoutLayoutParams lp = new CellLayoutLayoutParams(i, 0, 1, 1);
mSampleHotseat.addViewToCellLayout(icon, i, info.getViewId(), lp, true);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index 4b7d8fc..9cec881 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -18,6 +18,7 @@
import static android.view.View.AccessibilityDelegate;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
@@ -864,8 +865,8 @@
mAreNavButtonsInSeparateWindow = true;
mContext.getDragLayer().removeView(mNavButtonsView);
mSeparateWindowParent.addView(mNavButtonsView);
- WindowManager.LayoutParams windowLayoutParams = mContext.createDefaultWindowLayoutParams();
- windowLayoutParams.setTitle(NAV_BUTTONS_SEPARATE_WINDOW_TITLE);
+ WindowManager.LayoutParams windowLayoutParams = mContext.createDefaultWindowLayoutParams(
+ TYPE_NAVIGATION_BAR_PANEL, NAV_BUTTONS_SEPARATE_WINDOW_TITLE);
mContext.addWindowView(mSeparateWindowParent, windowLayoutParams);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 20e4b55..dc2c720 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -241,7 +241,8 @@
public void init(@NonNull TaskbarSharedState sharedState) {
mLastRequestedNonFullscreenHeight = getDefaultTaskbarWindowHeight();
- mWindowLayoutParams = createDefaultWindowLayoutParams();
+ mWindowLayoutParams =
+ createDefaultWindowLayoutParams(TYPE_NAVIGATION_BAR_PANEL, WINDOW_TITLE);
// Initialize controllers after all are constructed.
mControllers.init(sharedState);
@@ -317,16 +318,12 @@
return super.getStatsLogManager();
}
- /** @see #createDefaultWindowLayoutParams(int) */
- public WindowManager.LayoutParams createDefaultWindowLayoutParams() {
- return createDefaultWindowLayoutParams(TYPE_NAVIGATION_BAR_PANEL);
- }
-
/**
* Creates LayoutParams for adding a view directly to WindowManager as a new window.
* @param type The window type to pass to the created WindowManager.LayoutParams.
+ * @param title The window title to pass to the created WindowManager.LayoutParams.
*/
- public WindowManager.LayoutParams createDefaultWindowLayoutParams(int type) {
+ public WindowManager.LayoutParams createDefaultWindowLayoutParams(int type, String title) {
DeviceProfile deviceProfile = getDeviceProfile();
// Taskbar is on the logical bottom of the screen
boolean isVerticalBarLayout = TaskbarManager.isPhoneMode(deviceProfile) &&
@@ -346,7 +343,7 @@
type,
windowFlags,
PixelFormat.TRANSLUCENT);
- windowLayoutParams.setTitle(WINDOW_TITLE);
+ windowLayoutParams.setTitle(title);
windowLayoutParams.packageName = getPackageName();
windowLayoutParams.gravity = !isVerticalBarLayout ?
Gravity.BOTTOM :
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index cd27a46..267bee1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -49,6 +49,8 @@
private final AnimatedFloat mNotificationShadeBgTaskbar = new AnimatedFloat(
this::updateBackgroundAlpha);
private final AnimatedFloat mImeBgTaskbar = new AnimatedFloat(this::updateBackgroundAlpha);
+ private final AnimatedFloat mAssistantBgTaskbar = new AnimatedFloat(
+ this::updateBackgroundAlpha);
// Used to hide our background color when someone else (e.g. ScrimView) is handling it.
private final AnimatedFloat mBgOverride = new AnimatedFloat(this::updateBackgroundAlpha);
@@ -60,6 +62,7 @@
private AnimatedFloat mNavButtonDarkIntensityMultiplier;
private float mLastSetBackgroundAlpha;
+ private boolean mIsBackgroundDrawnElsewhere;
public TaskbarDragLayerController(TaskbarActivityContext activity,
TaskbarDragLayer taskbarDragLayer) {
@@ -81,6 +84,7 @@
mKeyguardBgTaskbar.value = 1;
mNotificationShadeBgTaskbar.value = 1;
mImeBgTaskbar.value = 1;
+ mAssistantBgTaskbar.value = 1;
mBgOverride.value = 1;
updateBackgroundAlpha();
}
@@ -119,6 +123,10 @@
return mImeBgTaskbar;
}
+ public AnimatedFloat getAssistantBgTaskbar() {
+ return mAssistantBgTaskbar;
+ }
+
public AnimatedFloat getOverrideBackgroundAlpha() {
return mBgOverride;
}
@@ -143,7 +151,8 @@
private void updateBackgroundAlpha() {
final float bgNavbar = mBgNavbar.value;
final float bgTaskbar = mBgTaskbar.value * mKeyguardBgTaskbar.value
- * mNotificationShadeBgTaskbar.value * mImeBgTaskbar.value;
+ * mNotificationShadeBgTaskbar.value * mImeBgTaskbar.value
+ * mAssistantBgTaskbar.value;
mLastSetBackgroundAlpha = mBgOverride.value * Math.max(bgNavbar, bgTaskbar);
mTaskbarDragLayer.setTaskbarBackgroundAlpha(mLastSetBackgroundAlpha);
@@ -168,9 +177,23 @@
mTaskbarDragLayer.setCornerRoundness(cornerRoundness);
}
+ /**
+ * Set if another controller is temporarily handling background drawing. In this case we:
+ * - Override our background alpha to be 0.
+ * - Keep the nav bar dark intensity assuming taskbar background is at full alpha.
+ */
+ public void setIsBackgroundDrawnElsewhere(boolean isBackgroundDrawnElsewhere) {
+ mIsBackgroundDrawnElsewhere = isBackgroundDrawnElsewhere;
+ mBgOverride.updateValue(mIsBackgroundDrawnElsewhere ? 0 : 1);
+ updateNavBarDarkIntensityMultiplier();
+ }
+
private void updateNavBarDarkIntensityMultiplier() {
// Zero out the app-requested dark intensity when we're drawing our own background.
float effectiveBgAlpha = mLastSetBackgroundAlpha * (1 - mBgOffset.value);
+ if (mIsBackgroundDrawnElsewhere) {
+ effectiveBgAlpha = 1;
+ }
mNavButtonDarkIntensityMultiplier.updateValue(1 - effectiveBgAlpha);
}
@@ -181,6 +204,13 @@
pw.println(prefix + "\tmBgOffset=" + mBgOffset.value);
pw.println(prefix + "\tmFolderMargin=" + mFolderMargin);
pw.println(prefix + "\tmLastSetBackgroundAlpha=" + mLastSetBackgroundAlpha);
+ pw.println(prefix + "\t\tmBgOverride=" + mBgOverride.value);
+ pw.println(prefix + "\t\tmBgNavbar=" + mBgNavbar.value);
+ pw.println(prefix + "\t\tmBgTaskbar=" + mBgTaskbar.value);
+ pw.println(prefix + "\t\tmKeyguardBgTaskbar=" + mKeyguardBgTaskbar.value);
+ pw.println(prefix + "\t\tmNotificationShadeBgTaskbar=" + mNotificationShadeBgTaskbar.value);
+ pw.println(prefix + "\t\tmImeBgTaskbar=" + mImeBgTaskbar.value);
+ pw.println(prefix + "\t\tmAssistantBgTaskbar=" + mAssistantBgTaskbar.value);
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
index c4d1ab2..faf7451 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
@@ -151,7 +151,7 @@
}
override fun dumpLogs(prefix: String?, pw: PrintWriter?) {
- pw?.println("$(prefix)TaskbarEduController:")
+ pw?.println(prefix + "TaskbarEduTooltipController:")
pw?.println("$prefix\tisTooltipEnabled=$isTooltipEnabled")
pw?.println("$prefix\tisOpen=$isOpen")
pw?.println("$prefix\ttooltipStep=$tooltipStep")
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
index edf4648..93ba4eb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
@@ -90,13 +90,8 @@
*/
private void updateIconsForBouncer() {
boolean disableBack = (mKeyguardSysuiFlags & SYSUI_STATE_BACK_DISABLED) != 0;
- boolean disableRecent = (mKeyguardSysuiFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0;
- boolean disableHome = (mKeyguardSysuiFlags & SYSUI_STATE_HOME_DISABLED) != 0;
- boolean onlyBackEnabled = !disableBack && disableRecent && disableHome;
-
- boolean showBackForBouncer = onlyBackEnabled &&
- mKeyguardManager.isDeviceSecure() &&
- mBouncerShowing;
+ boolean showBackForBouncer =
+ !disableBack && mKeyguardManager.isDeviceSecure() && mBouncerShowing;
mNavbarButtonsViewController.setBackForBouncer(showBackForBouncer);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
index 88767dd..5ea00cf 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
@@ -67,7 +67,8 @@
final boolean manageMenuExpanded =
(stateFlags & SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED) != 0;
final boolean showScrim = !mControllers.navbarButtonsViewController.isImeVisible()
- && bubblesExpanded && mControllers.taskbarStashController.isInAppAndNotStashed();
+ && bubblesExpanded
+ && mControllers.taskbarStashController.isTaskbarVisibleAndNotStashing();
final float scrimAlpha = manageMenuExpanded
// When manage menu shows there's the first scrim and second scrim so figure out
// what the total transparency would be.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index a717136..6b7bfa0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -349,10 +349,10 @@
/**
- * Returns whether the taskbar is currently visible and in an app.
+ * Returns whether the taskbar is currently visible and not in the process of being stashed.
*/
- public boolean isInAppAndNotStashed() {
- return !mIsStashed && isInApp();
+ public boolean isTaskbarVisibleAndNotStashing() {
+ return !mIsStashed && mControllers.taskbarViewController.areIconsVisible();
}
public boolean isInApp() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
index 586115d..80f030f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
@@ -113,7 +113,7 @@
return;
}
reset();
- if (mControllers.taskbarStashController.isInAppAndNotStashed()) {
+ if (mControllers.taskbarStashController.isTaskbarVisibleAndNotStashing()) {
mControllers.taskbarEduTooltipController.maybeShowFeaturesEdu();
}
}));
diff --git a/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt
index be34fb1..7a5deb7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt
@@ -1,31 +1,70 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.android.launcher3.taskbar
+import android.animation.AnimatorSet
import android.graphics.Canvas
+import android.view.View
+import android.view.ViewTreeObserver
+import android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION
import android.view.WindowManager
import android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
+import com.android.launcher3.util.DisplayController
import com.android.launcher3.views.BaseDragLayer
import com.android.systemui.animation.ViewRootSync
import java.io.PrintWriter
private const val TASKBAR_ICONS_FADE_DURATION = 300L
private const val STASHED_HANDLE_FADE_DURATION = 180L
+private const val TEMP_BACKGROUND_WINDOW_TITLE = "VoiceInteractionTaskbarBackground"
-/** Controls Taskbar behavior while Voice Interaction Window (assistant) is showing. */
+/**
+ * Controls Taskbar behavior while Voice Interaction Window (assistant) is showing. Specifically:
+ * - We always hide the taskbar icons or stashed handle, whichever is currently showing.
+ * - For persistent taskbar, we also move the taskbar background to a new window/layer
+ * (TYPE_APPLICATION_OVERLAY) which is behind the assistant.
+ * - For transient taskbar, we hide the real taskbar background (if it's showing).
+ */
class VoiceInteractionWindowController(val context: TaskbarActivityContext) :
TaskbarControllers.LoggableTaskbarController, TaskbarControllers.BackgroundRendererController {
+ private val isSeparateBackgroundEnabled = !DisplayController.isTransientTaskbar(context)
private val taskbarBackgroundRenderer = TaskbarBackgroundRenderer(context)
+ private val nonTouchableInsetsComputer =
+ ViewTreeObserver.OnComputeInternalInsetsListener {
+ it.touchableRegion.setEmpty()
+ it.setTouchableInsets(TOUCHABLE_INSETS_REGION)
+ }
// Initialized in init.
private lateinit var controllers: TaskbarControllers
- private lateinit var separateWindowForTaskbarBackground: BaseDragLayer<TaskbarActivityContext>
- private lateinit var separateWindowLayoutParams: WindowManager.LayoutParams
+ // Only initialized if isSeparateBackgroundEnabled
+ private var separateWindowForTaskbarBackground: BaseDragLayer<TaskbarActivityContext>? = null
+ private var separateWindowLayoutParams: WindowManager.LayoutParams? = null
private var isVoiceInteractionWindowVisible: Boolean = false
+ private var pendingAttachedToWindowListener: View.OnAttachStateChangeListener? = null
fun init(controllers: TaskbarControllers) {
this.controllers = controllers
+ if (!isSeparateBackgroundEnabled) {
+ return
+ }
+
separateWindowForTaskbarBackground =
object : BaseDragLayer<TaskbarActivityContext>(context, null, 0) {
override fun recreateControllers() {
@@ -34,24 +73,39 @@
override fun draw(canvas: Canvas) {
super.draw(canvas)
- if (
- this@VoiceInteractionWindowController.context.isGestureNav &&
- controllers.taskbarStashController.isInAppAndNotStashed
- ) {
+ if (controllers.taskbarStashController.isTaskbarVisibleAndNotStashing) {
taskbarBackgroundRenderer.draw(canvas)
}
}
+
+ override fun onAttachedToWindow() {
+ super.onAttachedToWindow()
+ viewTreeObserver.addOnComputeInternalInsetsListener(nonTouchableInsetsComputer)
+ }
+
+ override fun onDetachedFromWindow() {
+ super.onDetachedFromWindow()
+ viewTreeObserver.removeOnComputeInternalInsetsListener(
+ nonTouchableInsetsComputer
+ )
+ }
}
- separateWindowForTaskbarBackground.recreateControllers()
- separateWindowForTaskbarBackground.setWillNotDraw(false)
+ separateWindowForTaskbarBackground?.recreateControllers()
+ separateWindowForTaskbarBackground?.setWillNotDraw(false)
separateWindowLayoutParams =
- context.createDefaultWindowLayoutParams(TYPE_APPLICATION_OVERLAY)
- separateWindowLayoutParams.isSystemApplicationOverlay = true
+ context.createDefaultWindowLayoutParams(
+ TYPE_APPLICATION_OVERLAY,
+ TEMP_BACKGROUND_WINDOW_TITLE
+ )
+ separateWindowLayoutParams?.isSystemApplicationOverlay = true
}
fun onDestroy() {
setIsVoiceInteractionWindowVisible(visible = false, skipAnim = true)
+ separateWindowForTaskbarBackground?.removeOnAttachStateChangeListener(
+ pendingAttachedToWindowListener
+ )
}
fun setIsVoiceInteractionWindowVisible(visible: Boolean, skipAnim: Boolean) {
@@ -72,14 +126,24 @@
.get(StashedHandleViewController.ALPHA_INDEX_ASSISTANT_INVOKED)
.animateToValue(taskbarIconAlpha)
.setDuration(STASHED_HANDLE_FADE_DURATION)
- fadeTaskbarIcons.start()
- fadeStashedHandle.start()
+ val animSet = AnimatorSet()
+ animSet.play(fadeTaskbarIcons)
+ animSet.play(fadeStashedHandle)
+ if (!isSeparateBackgroundEnabled) {
+ val fadeTaskbarBackground =
+ controllers.taskbarDragLayerController.assistantBgTaskbar
+ .animateToValue(taskbarIconAlpha)
+ .setDuration(TASKBAR_ICONS_FADE_DURATION)
+ animSet.play(fadeTaskbarBackground)
+ }
+ animSet.start()
if (skipAnim) {
- fadeTaskbarIcons.end()
- fadeStashedHandle.end()
+ animSet.end()
}
- moveTaskbarBackgroundToAppropriateLayer(skipAnim)
+ if (isSeparateBackgroundEnabled) {
+ moveTaskbarBackgroundToAppropriateLayer(skipAnim)
+ }
}
/**
@@ -92,8 +156,6 @@
* Removes the temporary window and show the TaskbarDragLayer background again.
*/
private fun moveTaskbarBackgroundToAppropriateLayer(skipAnim: Boolean) {
- val taskbarBackgroundOverride =
- controllers.taskbarDragLayerController.overrideBackgroundAlpha
val moveToLowerLayer = isVoiceInteractionWindowVisible
val onWindowsSynchronized =
if (moveToLowerLayer) {
@@ -102,31 +164,60 @@
separateWindowForTaskbarBackground,
separateWindowLayoutParams
);
- { taskbarBackgroundOverride.updateValue(0f) }
+ { controllers.taskbarDragLayerController.setIsBackgroundDrawnElsewhere(true) }
} else {
// First reapply the original taskbar background, then remove the temporary window.
- taskbarBackgroundOverride.updateValue(1f);
+ controllers.taskbarDragLayerController.setIsBackgroundDrawnElsewhere(false);
{ context.removeWindowView(separateWindowForTaskbarBackground) }
}
if (skipAnim) {
onWindowsSynchronized()
} else {
- ViewRootSync.synchronizeNextDraw(
- separateWindowForTaskbarBackground,
- context.dragLayer,
- onWindowsSynchronized
- )
+ separateWindowForTaskbarBackground?.runWhenAttachedToWindow {
+ ViewRootSync.synchronizeNextDraw(
+ separateWindowForTaskbarBackground!!,
+ context.dragLayer,
+ onWindowsSynchronized
+ )
+ }
}
}
+ private fun View.runWhenAttachedToWindow(onAttachedToWindow: () -> Unit) {
+ if (isAttachedToWindow) {
+ onAttachedToWindow()
+ return
+ }
+ removeOnAttachStateChangeListener(pendingAttachedToWindowListener)
+ pendingAttachedToWindowListener =
+ object : View.OnAttachStateChangeListener {
+ override fun onViewAttachedToWindow(v: View?) {
+ onAttachedToWindow()
+ removeOnAttachStateChangeListener(this)
+ pendingAttachedToWindowListener = null
+ }
+
+ override fun onViewDetachedFromWindow(v: View?) {}
+ }
+ addOnAttachStateChangeListener(pendingAttachedToWindowListener)
+ }
+
override fun setCornerRoundness(cornerRoundness: Float) {
+ if (!isSeparateBackgroundEnabled) {
+ return
+ }
taskbarBackgroundRenderer.setCornerRoundness(cornerRoundness)
- separateWindowForTaskbarBackground.invalidate()
+ separateWindowForTaskbarBackground?.invalidate()
}
override fun dumpLogs(prefix: String, pw: PrintWriter) {
pw.println(prefix + "VoiceInteractionWindowController:")
+ pw.println("$prefix\tisSeparateBackgroundEnabled=$isSeparateBackgroundEnabled")
pw.println("$prefix\tisVoiceInteractionWindowVisible=$isVoiceInteractionWindowVisible")
+ pw.println(
+ "$prefix\tisSeparateTaskbarBackgroundAttachedToWindow=" +
+ "${separateWindowForTaskbarBackground?.isAttachedToWindow}"
+ )
}
}
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarKeyguardControllerTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarKeyguardControllerTest.kt
index 59db8c8..148e36c 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarKeyguardControllerTest.kt
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarKeyguardControllerTest.kt
@@ -19,8 +19,6 @@
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BACK_DISABLED
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING
-import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED
-import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED
import org.junit.Before
@@ -34,16 +32,14 @@
class TaskbarKeyguardControllerTest : TaskbarBaseTestCase() {
- @Mock
- lateinit var baseDragLayer: TaskbarDragLayer
- @Mock
- lateinit var keyguardManager: KeyguardManager
+ @Mock lateinit var baseDragLayer: TaskbarDragLayer
+ @Mock lateinit var keyguardManager: KeyguardManager
@Before
override fun setup() {
super.setup()
whenever(taskbarActivityContext.getSystemService(KeyguardManager::class.java))
- .thenReturn(keyguardManager)
+ .thenReturn(keyguardManager)
whenever(baseDragLayer.childCount).thenReturn(0)
whenever(taskbarActivityContext.dragLayer).thenReturn(baseDragLayer)
@@ -60,41 +56,35 @@
@Test
fun keyguardShowing() {
setFlags(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING)
- verify(navbarButtonsViewController, times(1)).setKeyguardVisible(
- true /*isKeyguardVisible*/,
- false /*isKeyguardOccluded*/)
+ verify(navbarButtonsViewController, times(1))
+ .setKeyguardVisible(true /*isKeyguardVisible*/, false /*isKeyguardOccluded*/)
}
@Test
fun dozingShowing() {
setFlags(SYSUI_STATE_DEVICE_DOZING)
- verify(navbarButtonsViewController, times(1)).setKeyguardVisible(
- true /*isKeyguardVisible*/,
- false /*isKeyguardOccluded*/)
+ verify(navbarButtonsViewController, times(1))
+ .setKeyguardVisible(true /*isKeyguardVisible*/, false /*isKeyguardOccluded*/)
}
@Test
fun keyguardOccluded() {
setFlags(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED)
- verify(navbarButtonsViewController, times(1)).setKeyguardVisible(
- false /*isKeyguardVisible*/,
- true /*isKeyguardOccluded*/)
+ verify(navbarButtonsViewController, times(1))
+ .setKeyguardVisible(false /*isKeyguardVisible*/, true /*isKeyguardOccluded*/)
}
@Test
fun keyguardOccludedAndDozing() {
setFlags(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED.or(SYSUI_STATE_DEVICE_DOZING))
- verify(navbarButtonsViewController, times(1)).setKeyguardVisible(
- true /*isKeyguardVisible*/,
- true /*isKeyguardOccluded*/)
+ verify(navbarButtonsViewController, times(1))
+ .setKeyguardVisible(true /*isKeyguardVisible*/, true /*isKeyguardOccluded*/)
}
@Test
fun deviceInsecure_hideBackForBouncer() {
whenever(keyguardManager.isDeviceSecure).thenReturn(false)
- setFlags(SYSUI_STATE_OVERVIEW_DISABLED
- .or(SYSUI_STATE_HOME_DISABLED)
- .or(SYSUI_STATE_BOUNCER_SHOWING))
+ setFlags(SYSUI_STATE_BOUNCER_SHOWING)
verify(navbarButtonsViewController, times(1)).setBackForBouncer(false)
}
@@ -102,49 +92,20 @@
@Test
fun deviceSecure_showBackForBouncer() {
whenever(keyguardManager.isDeviceSecure).thenReturn(true)
- setFlags(SYSUI_STATE_OVERVIEW_DISABLED
- .or(SYSUI_STATE_HOME_DISABLED)
- .or(SYSUI_STATE_BOUNCER_SHOWING))
+ setFlags(SYSUI_STATE_BOUNCER_SHOWING)
verify(navbarButtonsViewController, times(1)).setBackForBouncer(true)
}
@Test
- fun homeShowing_hideBackForBouncer() {
- whenever(keyguardManager.isDeviceSecure).thenReturn(true)
- setFlags(SYSUI_STATE_OVERVIEW_DISABLED
- .or(SYSUI_STATE_BOUNCER_SHOWING))
-
- verify(navbarButtonsViewController, times(1)).setBackForBouncer(false)
- }
-
- @Test
- fun overviewShowing_hideBackForBouncer() {
- whenever(keyguardManager.isDeviceSecure).thenReturn(true)
- setFlags(SYSUI_STATE_HOME_DISABLED
- .or(SYSUI_STATE_BOUNCER_SHOWING))
-
- verify(navbarButtonsViewController, times(1)).setBackForBouncer(false)
- }
-
- @Test
fun backDisabled_hideBackForBouncer() {
whenever(keyguardManager.isDeviceSecure).thenReturn(true)
- setFlags(SYSUI_STATE_BACK_DISABLED
- .or(SYSUI_STATE_BOUNCER_SHOWING))
+ setFlags(SYSUI_STATE_BACK_DISABLED.or(SYSUI_STATE_BOUNCER_SHOWING))
verify(navbarButtonsViewController, times(1)).setBackForBouncer(false)
-
- // back disabled along with home and overview
- setFlags(SYSUI_STATE_BACK_DISABLED
- .or(SYSUI_STATE_HOME_DISABLED)
- .or(SYSUI_STATE_OVERVIEW_DISABLED)
- .or(SYSUI_STATE_BOUNCER_SHOWING))
-
- verify(navbarButtonsViewController, times(2)).setBackForBouncer(false)
}
private fun setFlags(flags: Int) {
taskbarKeyguardController.updateStateForSysuiFlags(flags)
}
-}
\ No newline at end of file
+}
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index 85bd2d3..94b8cd8 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -33,6 +33,7 @@
import com.android.launcher3.accessibility.DragViewStateAnnouncer;
import com.android.launcher3.celllayout.CellLayoutLayoutParams;
+import com.android.launcher3.celllayout.CellPosMapper.CellPos;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.logging.InstanceId;
@@ -268,10 +269,11 @@
CellLayoutLayoutParams lp = (CellLayoutLayoutParams) mWidgetView.getLayoutParams();
ItemInfo widgetInfo = (ItemInfo) mWidgetView.getTag();
- lp.setCellX(widgetInfo.cellX);
- lp.setTmpCellX(widgetInfo.cellX);
- lp.setCellY(widgetInfo.cellY);
- lp.setTmpCellY(widgetInfo.cellY);
+ CellPos presenterPos = mLauncher.getCellPosMapper().mapModelToPresenter(widgetInfo);
+ lp.setCellX(presenterPos.cellX);
+ lp.setTmpCellX(presenterPos.cellX);
+ lp.setCellY(presenterPos.cellY);
+ lp.setTmpCellY(presenterPos.cellY);
lp.cellHSpan = widgetInfo.spanX;
lp.cellVSpan = widgetInfo.spanY;
lp.isLockedToGrid = true;
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 05b225c..d388ebc 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -62,6 +62,7 @@
import com.android.launcher3.accessibility.DragAndDropAccessibilityDelegate;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.celllayout.CellLayoutLayoutParams;
+import com.android.launcher3.celllayout.CellPosMapper.CellPos;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.folder.PreviewBackground;
@@ -267,7 +268,7 @@
mDragCell[0] = mDragCell[1] = -1;
mDragCellSpan[0] = mDragCellSpan[1] = -1;
for (int i = 0; i < mDragOutlines.length; i++) {
- mDragOutlines[i] = new CellLayoutLayoutParams(0, 0, 0, 0, -1);
+ mDragOutlines[i] = new CellLayoutLayoutParams(0, 0, 0, 0);
}
mDragOutlinePaint.setColor(Themes.getAttrColor(context, R.attr.workspaceTextColor));
@@ -1084,8 +1085,8 @@
final int oldY = lp.y;
lp.isLockedToGrid = true;
if (permanent) {
- lp.setCellX(info.cellX = cellX);
- lp.setCellY(info.cellY = cellY);
+ lp.setCellX(cellX);
+ lp.setCellY(cellY);
} else {
lp.setTmpCellX(cellX);
lp.setTmpCellY(cellY);
@@ -1627,20 +1628,16 @@
// We do a null check here because the item info can be null in the case of the
// AllApps button in the hotseat.
if (info != null && child != dragView) {
- final boolean requiresDbUpdate = (info.cellX != lp.getTmpCellX()
- || info.cellY != lp.getTmpCellY() || info.spanX != lp.cellHSpan
- || info.spanY != lp.cellVSpan);
+ CellPos presenterPos = mActivity.getCellPosMapper().mapModelToPresenter(info);
+ final boolean requiresDbUpdate = (presenterPos.cellX != lp.getTmpCellX()
+ || presenterPos.cellY != lp.getTmpCellY() || info.spanX != lp.cellHSpan
+ || info.spanY != lp.cellVSpan || presenterPos.screenId != screenId);
lp.setCellX(lp.getTmpCellX());
- info.cellX = lp.getTmpCellX();
- info.cellY = lp.getTmpCellY();
lp.setCellY(lp.getTmpCellY());
- info.spanX = lp.cellHSpan;
- info.spanY = lp.cellVSpan;
-
if (requiresDbUpdate) {
Launcher.cast(mActivity).getModelWriter().modifyItemInDatabase(info, container,
- screenId, info.cellX, info.cellY, info.spanX, info.spanY);
+ screenId, lp.getCellX(), lp.getCellY(), lp.cellHSpan, lp.cellVSpan);
}
}
}
@@ -2792,7 +2789,8 @@
if (view instanceof LauncherAppWidgetHostView
&& view.getTag() instanceof LauncherAppWidgetInfo) {
LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) view.getTag();
- mOccupied.markCells(info.cellX, info.cellY, info.spanX, info.spanY, true);
+ CellPos pos = mActivity.getCellPosMapper().mapModelToPresenter(info);
+ mOccupied.markCells(pos.cellX, pos.cellY, info.spanX, info.spanY, true);
return;
}
if (view == null || view.getParent() != mShortcutsAndWidgets) return;
@@ -2805,7 +2803,8 @@
if (view instanceof LauncherAppWidgetHostView
&& view.getTag() instanceof LauncherAppWidgetInfo) {
LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) view.getTag();
- mOccupied.markCells(info.cellX, info.cellY, info.spanX, info.spanY, false);
+ CellPos pos = mActivity.getCellPosMapper().mapModelToPresenter(info);
+ mOccupied.markCells(pos.cellX, pos.cellY, info.spanX, info.spanY, false);
return;
}
if (view == null || view.getParent() != mShortcutsAndWidgets) return;
@@ -2858,13 +2857,13 @@
final int screenId;
final int container;
- public CellInfo(View v, ItemInfo info) {
- cellX = info.cellX;
- cellY = info.cellY;
+ public CellInfo(View v, ItemInfo info, CellPos cellPos) {
+ cellX = cellPos.cellX;
+ cellY = cellPos.cellY;
spanX = info.spanX;
spanY = info.spanY;
cell = v;
- screenId = info.screenId;
+ screenId = cellPos.screenId;
container = info.container;
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index e9b9f31..2f1f59c 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -32,6 +32,7 @@
import static com.android.launcher3.LauncherAnimUtils.SCALE_INDEX_WIDGET_TRANSITION;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherAnimUtils.WORKSPACE_SCALE_PROPERTY_FACTORY;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.FLAG_MULTI_PAGE;
@@ -135,6 +136,8 @@
import com.android.launcher3.allapps.BaseSearchConfig;
import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.PropertyListBuilder;
+import com.android.launcher3.celllayout.CellPosMapper;
+import com.android.launcher3.celllayout.CellPosMapper.CellPos;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dot.DotInfo;
@@ -406,6 +409,8 @@
private StringCache mStringCache;
private BaseSearchConfig mBaseSearchConfig;
+ private CellPosMapper mCellPosMapper = CellPosMapper.DEFAULT;
+
@Override
@TargetApi(Build.VERSION_CODES.S)
protected void onCreate(Bundle savedInstanceState) {
@@ -725,10 +730,17 @@
}
onDeviceProfileInitiated();
- mModelWriter = mModel.getWriter(getDeviceProfile().isVerticalBarLayout(), true, this);
+ mCellPosMapper = CellPosMapper.DEFAULT;
+ mModelWriter = mModel.getWriter(getDeviceProfile().isVerticalBarLayout(), true,
+ mCellPosMapper, this);
return true;
}
+ @Override
+ public CellPosMapper getCellPosMapper() {
+ return mCellPosMapper;
+ }
+
public RotationHelper getRotationHelper() {
return mRotationHelper;
}
@@ -794,16 +806,18 @@
*/
private int completeAdd(
int requestCode, Intent intent, int appWidgetId, PendingRequestArgs info) {
- int screenId = info.screenId;
- if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
+ CellPos cellPos = getCellPosMapper().mapModelToPresenter(info);
+ int screenId = cellPos.screenId;
+ if (info.container == CONTAINER_DESKTOP) {
// When the screen id represents an actual screen (as opposed to a rank) we make sure
// that the drop page actually exists.
- screenId = ensurePendingDropLayoutExists(info.screenId);
+ screenId = ensurePendingDropLayoutExists(cellPos.screenId);
}
switch (requestCode) {
case REQUEST_CREATE_SHORTCUT:
- completeAddShortcut(intent, info.container, screenId, info.cellX, info.cellY, info);
+ completeAddShortcut(intent, info.container, screenId,
+ cellPos.cellX, cellPos.cellY, info);
announceForAccessibility(R.string.item_added_to_workspace);
break;
case REQUEST_CREATE_APPWIDGET:
@@ -899,14 +913,17 @@
ON_ACTIVITY_RESULT_ANIMATION_DELAY, false,
() -> getStateManager().goToState(NORMAL));
} else {
- if (requestArgs.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
+ CellPos presenterPos = getCellPosMapper().mapModelToPresenter(requestArgs);
+ if (requestArgs.container == CONTAINER_DESKTOP) {
// When the screen id represents an actual screen (as opposed to a rank)
// we make sure that the drop page actually exists.
- requestArgs.screenId =
- ensurePendingDropLayoutExists(requestArgs.screenId);
+ int newScreenId = ensurePendingDropLayoutExists(presenterPos.screenId);
+ requestArgs.screenId = getCellPosMapper().mapPresenterToModel(
+ presenterPos.cellX, presenterPos.cellY, newScreenId, CONTAINER_DESKTOP)
+ .screenId;
}
final CellLayout dropLayout =
- mWorkspace.getScreenWithId(requestArgs.screenId);
+ mWorkspace.getScreenWithId(presenterPos.screenId);
dropLayout.setDropPending(true);
final Runnable onComplete = new Runnable() {
@@ -964,9 +981,10 @@
setWaitingForResult(null);
View v = null;
- CellLayout layout = getCellLayout(pendingArgs.container, pendingArgs.screenId);
+ CellPos cellPos = getCellPosMapper().mapModelToPresenter(pendingArgs);
+ CellLayout layout = getCellLayout(pendingArgs.container, cellPos.screenId);
if (layout != null) {
- v = layout.getChildAt(pendingArgs.cellX, pendingArgs.cellY);
+ v = layout.getChildAt(cellPos.cellX, cellPos.cellY);
}
Intent intent = pendingArgs.getPendingIntent();
@@ -1002,7 +1020,8 @@
@Thunk
void completeTwoStageWidgetDrop(
final int resultCode, final int appWidgetId, final PendingRequestArgs requestArgs) {
- CellLayout cellLayout = mWorkspace.getScreenWithId(requestArgs.screenId);
+ CellLayout cellLayout = mWorkspace.getScreenWithId(
+ getCellPosMapper().mapModelToPresenter(requestArgs).screenId);
Runnable onCompleteRunnable = null;
int animationType = 0;
@@ -1493,9 +1512,9 @@
launcherInfo.sourceContainer =
((PendingRequestArgs) itemInfo).getWidgetSourceContainer();
}
-
+ CellPos presenterPos = getCellPosMapper().mapModelToPresenter(itemInfo);
getModelWriter().addItemToDatabase(launcherInfo,
- itemInfo.container, itemInfo.screenId, itemInfo.cellX, itemInfo.cellY);
+ itemInfo.container, presenterPos.screenId, presenterPos.cellX, presenterPos.cellY);
hostView.setVisibility(View.VISIBLE);
prepareAppWidget(hostView, launcherInfo);
@@ -1505,7 +1524,7 @@
// Show the widget resize frame.
if (hostView instanceof LauncherAppWidgetHostView) {
final LauncherAppWidgetHostView launcherHostView = (LauncherAppWidgetHostView) hostView;
- CellLayout cellLayout = getCellLayout(launcherInfo.container, launcherInfo.screenId);
+ CellLayout cellLayout = getCellLayout(launcherInfo.container, presenterPos.screenId);
if (mStateManager.getState() == NORMAL) {
AppWidgetResizeFrame.showForWidget(launcherHostView, cellLayout);
} else {
@@ -1887,12 +1906,17 @@
public void addPendingItem(PendingAddItemInfo info, int container, int screenId,
int[] cell, int spanX, int spanY) {
- info.container = container;
- info.screenId = screenId;
- if (cell != null) {
- info.cellX = cell[0];
- info.cellY = cell[1];
+ if (cell == null) {
+ CellPos modelPos = getCellPosMapper().mapPresenterToModel(0, 0, screenId, container);
+ info.screenId = modelPos.screenId;
+ } else {
+ CellPos modelPos = getCellPosMapper().mapPresenterToModel(
+ cell[0], cell[1], screenId, container);
+ info.screenId = modelPos.screenId;
+ info.cellX = modelPos.cellX;
+ info.cellY = modelPos.cellY;
}
+ info.container = container;
info.spanX = spanX;
info.spanY = spanY;
@@ -2455,10 +2479,11 @@
/*
* Remove colliding items.
*/
- if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
- CellLayout cl = mWorkspace.getScreenWithId(item.screenId);
- if (cl != null && cl.isOccupied(item.cellX, item.cellY)) {
- View v = cl.getChildAt(item.cellX, item.cellY);
+ CellPos presenterPos = getCellPosMapper().mapModelToPresenter(item);
+ if (item.container == CONTAINER_DESKTOP) {
+ CellLayout cl = mWorkspace.getScreenWithId(presenterPos.screenId);
+ if (cl != null && cl.isOccupied(presenterPos.cellX, presenterPos.cellY)) {
+ View v = cl.getChildAt(presenterPos.cellX, presenterPos.cellY);
if (v == null) {
Log.e(TAG, "bindItems failed when removing colliding item=" + item);
}
@@ -2484,7 +2509,7 @@
view.setScaleX(0f);
view.setScaleY(0f);
bounceAnims.add(createNewAppBounceAnimation(view, i));
- newItemsScreenId = item.screenId;
+ newItemsScreenId = presenterPos.screenId;
}
if (newView == null) {
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 2c6458b..4472383 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -37,6 +37,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
+import com.android.launcher3.celllayout.CellPosMapper;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.logging.FileLog;
@@ -165,9 +166,9 @@
@NonNull
public ModelWriter getWriter(final boolean hasVerticalHotseat, final boolean verifyChanges,
- @Nullable final Callbacks owner) {
+ CellPosMapper cellPosMapper, @Nullable final Callbacks owner) {
return new ModelWriter(mApp.getContext(), this, mBgDataModel,
- hasVerticalHotseat, verifyChanges, owner);
+ hasVerticalHotseat, verifyChanges, cellPosMapper, owner);
}
@Override
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 460c658..df829f1 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -26,6 +26,7 @@
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.SPRING_LOADED;
import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback;
+import static com.android.launcher3.config.FeatureFlags.FOLDABLE_SINGLE_PAGE;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPELEFT;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPERIGHT;
@@ -69,6 +70,8 @@
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.celllayout.CellLayoutLayoutParams;
+import com.android.launcher3.celllayout.CellPosMapper;
+import com.android.launcher3.celllayout.CellPosMapper.CellPos;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dot.FolderDotInfo;
import com.android.launcher3.dragndrop.DragController;
@@ -585,7 +588,7 @@
}
int cellHSpan = mLauncher.getDeviceProfile().inv.numSearchContainerColumns;
- CellLayoutLayoutParams lp = new CellLayoutLayoutParams(0, 0, cellHSpan, 1, FIRST_SCREEN_ID);
+ CellLayoutLayoutParams lp = new CellLayoutLayoutParams(0, 0, cellHSpan, 1);
lp.canReorder = false;
if (!firstPage.addViewToCellLayout(
mFirstPagePinnedItem, 0, R.id.search_container_workspace, lp, true)) {
@@ -642,7 +645,7 @@
// Inflate the cell layout, but do not add it automatically so that we can get the newly
// created CellLayout.
CellLayout newScreen = (CellLayout) LayoutInflater.from(getContext()).inflate(
- R.layout.workspace_screen, this, false /* attachToRoot */);
+ R.layout.workspace_screen, this, false /* attachToRoot */);
mWorkspaceScreens.put(screenId, newScreen);
mScreenOrder.add(insertIndex, screenId);
@@ -664,7 +667,8 @@
// If the icon was dragged from Hotseat, there is no page pair
if (isTwoPanelEnabled() && !(mDragSourceInternal.getParent() instanceof Hotseat)) {
- int pagePairScreenId = getScreenPair(dragObject.dragInfo.screenId);
+ int pagePairScreenId = getScreenPair(getCellPosMapper().mapModelToPresenter(
+ dragObject.dragInfo).screenId);
CellLayout pagePair = mWorkspaceScreens.get(pagePairScreenId);
dragSourceChildCount += pagePair.getShortcutsAndWidgets().getChildCount();
}
@@ -680,7 +684,7 @@
lastChildOnScreen = true;
}
CellLayout cl = (CellLayout) mDragSourceInternal.getParent();
- if (getLeftmostVisiblePageForIndex(indexOfChild(cl))
+ if (!FOLDABLE_SINGLE_PAGE.get() && getLeftmostVisiblePageForIndex(indexOfChild(cl))
== getLeftmostVisiblePageForIndex(getPageCount() - 1)) {
childOnFinalScreen = true;
}
@@ -1954,8 +1958,11 @@
minSpanY = item.minSpanY;
}
- droppedOnOriginalCell = item.screenId == screenId && item.container == container
- && item.cellX == mTargetCell[0] && item.cellY == mTargetCell[1];
+ CellPos originalPresenterPos = getCellPosMapper().mapModelToPresenter(item);
+ droppedOnOriginalCell = originalPresenterPos.screenId == screenId
+ && item.container == container
+ && originalPresenterPos.cellX == mTargetCell[0]
+ && originalPresenterPos.cellY == mTargetCell[1];
droppedOnOriginalCellDuringTransition = droppedOnOriginalCell && mIsSwitchingState;
// When quickly moving an item, a user may accidentally rearrange their
@@ -3434,6 +3441,11 @@
> deviceProfile.availableWidthPx * SIGNIFICANT_MOVE_SCREEN_WIDTH_PERCENTAGE;
}
+ @Override
+ public CellPosMapper getCellPosMapper() {
+ return mLauncher.getCellPosMapper();
+ }
+
/**
* Used as a workaround to ensure that the AppWidgetService receives the
* PACKAGE_ADDED broadcast before updating widgets.
diff --git a/src/com/android/launcher3/WorkspaceLayoutManager.java b/src/com/android/launcher3/WorkspaceLayoutManager.java
index bf448c9..4768773 100644
--- a/src/com/android/launcher3/WorkspaceLayoutManager.java
+++ b/src/com/android/launcher3/WorkspaceLayoutManager.java
@@ -20,6 +20,8 @@
import android.view.ViewGroup;
import com.android.launcher3.celllayout.CellLayoutLayoutParams;
+import com.android.launcher3.celllayout.CellPosMapper;
+import com.android.launcher3.celllayout.CellPosMapper.CellPos;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.model.data.ItemInfo;
@@ -48,15 +50,16 @@
* See {@link #addInScreen}.
*/
default void addInScreenFromBind(View child, ItemInfo info) {
- int x = info.cellX;
- int y = info.cellY;
+ CellPos presenterPos = getCellPosMapper().mapModelToPresenter(info);
+ int x = presenterPos.cellX;
+ int y = presenterPos.cellY;
if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT
|| info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION) {
- int screenId = info.screenId;
+ int screenId = presenterPos.screenId;
x = getHotseat().getCellXFromOrder(screenId);
y = getHotseat().getCellYFromOrder(screenId);
}
- addInScreen(child, info.container, info.screenId, x, y, info.spanX, info.spanY);
+ addInScreen(child, info.container, presenterPos.screenId, x, y, info.spanX, info.spanY);
}
/**
@@ -64,7 +67,9 @@
* See {@link #addInScreen(View, int, int, int, int, int, int)}.
*/
default void addInScreen(View child, ItemInfo info) {
- addInScreen(child, info.container, info.screenId, info.cellX, info.cellY,
+ CellPos presenterPos = getCellPosMapper().mapModelToPresenter(info);
+ addInScreen(child, info.container,
+ presenterPos.screenId, presenterPos.cellX, presenterPos.cellY,
info.spanX, info.spanY);
}
@@ -114,7 +119,7 @@
ViewGroup.LayoutParams genericLp = child.getLayoutParams();
CellLayoutLayoutParams lp;
if (genericLp == null || !(genericLp instanceof CellLayoutLayoutParams)) {
- lp = new CellLayoutLayoutParams(x, y, spanX, spanY, screenId);
+ lp = new CellLayoutLayoutParams(x, y, spanX, spanY);
} else {
lp = (CellLayoutLayoutParams) genericLp;
lp.setCellX(x);
@@ -151,6 +156,11 @@
return ItemLongClickListener.INSTANCE_WORKSPACE;
}
+ /**
+ * Returns the mapper for converting between model and presenter
+ */
+ CellPosMapper getCellPosMapper();
+
Hotseat getHotseat();
CellLayout getScreenWithId(int screenId);
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 3bb8fb4..da47398 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -426,6 +426,10 @@
return;
}
+ RecyclerView.ItemDecoration decoration = getMainAdapterProvider().getDecorator();
+ getSearchRecyclerView().removeItemDecoration(decoration);
+ getSearchRecyclerView().addItemDecoration(decoration);
+
// replaceAppsRVcontainer() needs to use both mUsingTabs value to remove the old view AND
// showTabs value to create new view. Hence the mUsingTabs new value assignment MUST happen
// after this call.
diff --git a/src/com/android/launcher3/celllayout/CellLayoutLayoutParams.java b/src/com/android/launcher3/celllayout/CellLayoutLayoutParams.java
index 726ef05..4b6a062 100644
--- a/src/com/android/launcher3/celllayout/CellLayoutLayoutParams.java
+++ b/src/com/android/launcher3/celllayout/CellLayoutLayoutParams.java
@@ -29,8 +29,6 @@
*/
public class CellLayoutLayoutParams extends ViewGroup.MarginLayoutParams {
- private int mScreenId = -1;
-
@ViewDebug.ExportedProperty
private int mCellX;
@@ -97,20 +95,17 @@
this.mCellY = source.getCellY();
this.cellHSpan = source.cellHSpan;
this.cellVSpan = source.cellVSpan;
- this.mScreenId = source.getScreenId();
this.mTmpCellX = source.getTmpCellX();
this.mTmpCellY = source.getTmpCellY();
this.useTmpCoords = source.useTmpCoords;
}
- public CellLayoutLayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan,
- int screenId) {
+ public CellLayoutLayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) {
super(CellLayoutLayoutParams.MATCH_PARENT, CellLayoutLayoutParams.MATCH_PARENT);
this.mCellX = cellX;
this.mCellY = cellY;
this.cellHSpan = cellHSpan;
this.cellVSpan = cellVSpan;
- this.mScreenId = screenId;
}
/**
@@ -178,14 +173,6 @@
return "(" + this.getCellX() + ", " + this.getCellY() + ")";
}
- public int getScreenId() {
- return mScreenId;
- }
-
- public void setScreenId(int screenId) {
- this.mScreenId = screenId;
- }
-
/**
* Horizontal location of the item in the grid.
*/
diff --git a/src/com/android/launcher3/celllayout/CellPosMapper.java b/src/com/android/launcher3/celllayout/CellPosMapper.java
new file mode 100644
index 0000000..1891696
--- /dev/null
+++ b/src/com/android/launcher3/celllayout/CellPosMapper.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2026 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.celllayout;
+
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
+
+import com.android.launcher3.model.data.ItemInfo;
+
+import java.util.Objects;
+
+/**
+ * Class for mapping between model position and presenter position.
+ */
+public class CellPosMapper {
+
+ public static final CellPosMapper DEFAULT = new CellPosMapper();
+
+ private CellPosMapper() { }
+
+ /**
+ * Maps the position in model to the position in view
+ */
+ public CellPos mapModelToPresenter(ItemInfo info) {
+ return new CellPos(info.cellX, info.cellY, info.screenId);
+ }
+
+ /**
+ * Maps the position in view to the position in model
+ */
+ public CellPos mapPresenterToModel(int presenterX, int presenterY, int presenterScreen,
+ int container) {
+ return new CellPos(presenterX, presenterY, presenterScreen);
+ }
+
+ /**
+ * Cell mapper which maps two panels into a single layout
+ */
+ public static class TwoPanelCellPosMapper extends CellPosMapper {
+
+ private final int mColumnCount;
+
+ public TwoPanelCellPosMapper(int columnCount) {
+ mColumnCount = columnCount;
+ }
+
+ /**
+ * Maps the position in model to the position in view
+ */
+ public CellPos mapModelToPresenter(ItemInfo info) {
+ if (info.container != CONTAINER_DESKTOP || (info.screenId % 2) == 0) {
+ return super.mapModelToPresenter(info);
+ }
+ return new CellPos(info.cellX + mColumnCount, info.cellY, info.screenId - 1);
+ }
+
+ @Override
+ public CellPos mapPresenterToModel(int presenterX, int presenterY, int presenterScreen,
+ int container) {
+ if (container == CONTAINER_DESKTOP && (presenterScreen % 2) == 0
+ && presenterX >= mColumnCount) {
+ return new CellPos(presenterX - mColumnCount, presenterY, presenterScreen + 1);
+ }
+ return super.mapPresenterToModel(presenterX, presenterY, presenterScreen, container);
+ }
+ }
+
+ /**
+ * Utility class to indicate the position of a cell
+ */
+ public static class CellPos {
+ public final int cellX;
+ public final int cellY;
+ public final int screenId;
+
+ public CellPos(int cellX, int cellY, int screenId) {
+ this.cellX = cellX;
+ this.cellY = cellY;
+ this.screenId = screenId;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof CellPos)) return false;
+ CellPos cellPos = (CellPos) o;
+ return cellX == cellPos.cellX && cellY == cellPos.cellY && screenId == cellPos.screenId;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(cellX, cellY, screenId);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 2841129..a24b30f 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -305,6 +305,9 @@
"FOLDABLE_WORKSPACE_REORDER", true,
"In foldables, when reordering the icons and widgets, is now going to use both sides");
+ public static final BooleanFlag ENABLE_QUICK_LAUNCH_V3 = new DeviceFlag(
+ "ENABLE_QUICK_LAUNCH_V3", false, "Quick Launch V3");
+
public static final BooleanFlag ENABLE_WIDGET_PICKER_DEPTH = new DeviceFlag(
"ENABLE_WIDGET_PICKER_DEPTH", true, "Enable changing depth in widget picker.");
@@ -331,6 +334,10 @@
"ENABLE_DOWNLOAD_APP_UX_V2", true, "Updates the download app UX"
+ " to have better visuals");
+ public static final BooleanFlag ENABLE_DOWNLOAD_APP_UX_V3 = getDebugFlag(
+ "ENABLE_DOWNLOAD_APP_UX_V3", false, "Updates the download app UX"
+ + " to have better visuals, improve contrast, and color");
+
public static final BooleanFlag ENABLE_TASKBAR_REVISED_THRESHOLDS = getDebugFlag(
"ENABLE_TASKBAR_REVISED_THRESHOLDS", true,
"Uses revised thresholds for transient taskbar.");
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index 10a2637..d43731b 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -222,7 +222,7 @@
CellLayoutLayoutParams lp = (CellLayoutLayoutParams) textView.getLayoutParams();
if (lp == null) {
textView.setLayoutParams(new CellLayoutLayoutParams(
- item.cellX, item.cellY, item.spanX, item.spanY, item.screenId));
+ item.cellX, item.cellY, item.spanX, item.spanY));
} else {
lp.setCellX(item.cellX);
lp.setCellY(item.cellY);
diff --git a/src/com/android/launcher3/folder/LauncherDelegate.java b/src/com/android/launcher3/folder/LauncherDelegate.java
index 1f0a011..3e55425 100644
--- a/src/com/android/launcher3/folder/LauncherDelegate.java
+++ b/src/com/android/launcher3/folder/LauncherDelegate.java
@@ -28,6 +28,7 @@
import com.android.launcher3.DropTarget;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.celllayout.CellPosMapper;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
@@ -177,7 +178,7 @@
ModelWriter getModelWriter() {
if (mWriter == null) {
mWriter = LauncherAppState.getInstance((Context) mContext).getModel()
- .getWriter(false, false, null);
+ .getWriter(false, false, CellPosMapper.DEFAULT, null);
}
return mWriter;
}
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 4810b15..b061f8f 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -75,6 +75,7 @@
import com.android.launcher3.Workspace;
import com.android.launcher3.WorkspaceLayoutManager;
import com.android.launcher3.celllayout.CellLayoutLayoutParams;
+import com.android.launcher3.celllayout.CellPosMapper;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.icons.BaseIconFactory;
@@ -348,6 +349,11 @@
return mWorkspaceScreens.get(screenId);
}
+ @Override
+ public CellPosMapper getCellPosMapper() {
+ return CellPosMapper.DEFAULT;
+ }
+
private void inflateAndAddIcon(WorkspaceItemInfo info) {
CellLayout screen = mWorkspaceScreens.get(info.screenId);
BubbleTextView icon = (BubbleTextView) mHomeElementInflater.inflate(
@@ -539,10 +545,9 @@
// Add first page QSB
if (FeatureFlags.QSB_ON_FIRST_SCREEN) {
CellLayout firstScreen = mWorkspaceScreens.get(FIRST_SCREEN_ID);
- View qsb = mHomeElementInflater.inflate(R.layout.qsb_preview, firstScreen,
- false);
- CellLayoutLayoutParams lp = new CellLayoutLayoutParams(0, 0, firstScreen.getCountX(),
- 1, FIRST_SCREEN_ID);
+ View qsb = mHomeElementInflater.inflate(R.layout.qsb_preview, firstScreen, false);
+ CellLayoutLayoutParams lp = new CellLayoutLayoutParams(
+ 0, 0, firstScreen.getCountX(), 1);
lp.canReorder = false;
firstScreen.addViewToCellLayout(qsb, 0, R.id.search_container_workspace, lp, true);
}
diff --git a/src/com/android/launcher3/model/BaseModelUpdateTask.java b/src/com/android/launcher3/model/BaseModelUpdateTask.java
index 74a2c5d..01e58f2 100644
--- a/src/com/android/launcher3/model/BaseModelUpdateTask.java
+++ b/src/com/android/launcher3/model/BaseModelUpdateTask.java
@@ -24,6 +24,7 @@
import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherModel.CallbackTask;
import com.android.launcher3.LauncherModel.ModelUpdateTask;
+import com.android.launcher3.celllayout.CellPosMapper;
import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.model.BgDataModel.FixedContainerItems;
import com.android.launcher3.model.data.AppInfo;
@@ -96,7 +97,8 @@
public ModelWriter getModelWriter() {
// Updates from model task, do not deal with icon position in hotseat. Also no need to
// verify changes as the ModelTasks always push the changes to callbacks
- return mModel.getWriter(false /* hasVerticalHotseat */, false /* verifyChanges */, null);
+ return mModel.getWriter(false /* hasVerticalHotseat */, false /* verifyChanges */,
+ CellPosMapper.DEFAULT, null);
}
public void bindUpdatedWorkspaceItems(@NonNull final List<WorkspaceItemInfo> allUpdates) {
diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java
index f444bd5..772ffa4 100644
--- a/src/com/android/launcher3/model/ModelWriter.java
+++ b/src/com/android/launcher3/model/ModelWriter.java
@@ -37,6 +37,8 @@
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.LauncherSettings.Settings;
import com.android.launcher3.Utilities;
+import com.android.launcher3.celllayout.CellPosMapper;
+import com.android.launcher3.celllayout.CellPosMapper.CellPos;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.BgDataModel.Callbacks;
@@ -81,9 +83,10 @@
// Keep track of delete operations that occur when an Undo option is present; we may not commit.
private final List<Runnable> mDeleteRunnables = new ArrayList<>();
private boolean mPreparingToUndo;
+ private final CellPosMapper mCellPosMapper;
public ModelWriter(Context context, LauncherModel model, BgDataModel dataModel,
- boolean hasVerticalHotseat, boolean verifyChanges,
+ boolean hasVerticalHotseat, boolean verifyChanges, CellPosMapper cellPosMapper,
@Nullable Callbacks owner) {
mContext = context;
mModel = model;
@@ -91,21 +94,24 @@
mHasVerticalHotseat = hasVerticalHotseat;
mVerifyChanges = verifyChanges;
mOwner = owner;
+ mCellPosMapper = cellPosMapper;
mUiExecutor = Executors.MAIN_EXECUTOR;
}
private void updateItemInfoProps(
ItemInfo item, int container, int screenId, int cellX, int cellY) {
+ CellPos modelPos = mCellPosMapper.mapPresenterToModel(cellX, cellY, screenId, container);
+
item.container = container;
- item.cellX = cellX;
- item.cellY = cellY;
+ item.cellX = modelPos.cellX;
+ item.cellY = modelPos.cellY;
// We store hotseat items in canonical form which is this orientation invariant position
// in the hotseat
if (container == Favorites.CONTAINER_HOTSEAT) {
item.screenId = mHasVerticalHotseat
? LauncherAppState.getIDP(mContext).numDatabaseHotseatIcons - cellY - 1 : cellX;
} else {
- item.screenId = screenId;
+ item.screenId = modelPos.screenId;
}
}
diff --git a/src/com/android/launcher3/touch/ItemLongClickListener.java b/src/com/android/launcher3/touch/ItemLongClickListener.java
index 1421ece..7db7b0d 100644
--- a/src/com/android/launcher3/touch/ItemLongClickListener.java
+++ b/src/com/android/launcher3/touch/ItemLongClickListener.java
@@ -80,7 +80,8 @@
}
}
- CellLayout.CellInfo longClickCellInfo = new CellLayout.CellInfo(v, info);
+ CellLayout.CellInfo longClickCellInfo = new CellLayout.CellInfo(v, info,
+ launcher.getCellPosMapper().mapModelToPresenter(info));
launcher.getWorkspace().startDrag(longClickCellInfo, dragOptions);
}
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index fe60eba..2ab4601 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -56,6 +56,7 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.ActivityAllAppsContainerView;
+import com.android.launcher3.celllayout.CellPosMapper;
import com.android.launcher3.dot.DotInfo;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.folder.FolderIcon;
@@ -459,6 +460,10 @@
return false;
}
+ default CellPosMapper getCellPosMapper() {
+ return CellPosMapper.DEFAULT;
+ }
+
/**
* Returns the ActivityContext associated with the given Context, or throws an exception if
* the Context is not associated with any ActivityContext.
diff --git a/tests/src/com/android/launcher3/celllayout/CellPosMapperTest.java b/tests/src/com/android/launcher3/celllayout/CellPosMapperTest.java
new file mode 100644
index 0000000..29efb18
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/CellPosMapperTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.celllayout;
+
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.launcher3.celllayout.CellPosMapper.CellPos;
+import com.android.launcher3.celllayout.CellPosMapper.TwoPanelCellPosMapper;
+import com.android.launcher3.model.data.ItemInfo;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link CellPosMapper}
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class CellPosMapperTest {
+
+ @Test
+ public void testMapModelToPresenter_default() {
+ assertThat(CellPosMapper.DEFAULT.mapModelToPresenter(
+ createInfo(0, 0, 0, CONTAINER_DESKTOP))).isEqualTo(new CellPos(0, 0, 0));
+ assertThat(CellPosMapper.DEFAULT.mapModelToPresenter(
+ createInfo(0, 0, 1, CONTAINER_DESKTOP))).isEqualTo(new CellPos(0, 0, 1));
+ assertThat(CellPosMapper.DEFAULT.mapModelToPresenter(
+ createInfo(5, 0, 1, CONTAINER_DESKTOP))).isEqualTo(new CellPos(5, 0, 1));
+ assertThat(CellPosMapper.DEFAULT.mapModelToPresenter(
+ createInfo(5, 0, 0, CONTAINER_DESKTOP))).isEqualTo(new CellPos(5, 0, 0));
+
+ assertThat(CellPosMapper.DEFAULT.mapModelToPresenter(
+ createInfo(0, 0, 0, CONTAINER_HOTSEAT))).isEqualTo(new CellPos(0, 0, 0));
+ assertThat(CellPosMapper.DEFAULT.mapModelToPresenter(
+ createInfo(0, 0, 1, CONTAINER_HOTSEAT))).isEqualTo(new CellPos(0, 0, 1));
+ assertThat(CellPosMapper.DEFAULT.mapModelToPresenter(
+ createInfo(5, 0, 1, CONTAINER_HOTSEAT))).isEqualTo(new CellPos(5, 0, 1));
+ assertThat(CellPosMapper.DEFAULT.mapModelToPresenter(
+ createInfo(5, 0, 0, CONTAINER_HOTSEAT))).isEqualTo(new CellPos(5, 0, 0));
+ }
+
+ @Test
+ public void testMapPresenterToModel_default() {
+ assertThat(CellPosMapper.DEFAULT.mapPresenterToModel(
+ 0, 0, 0, CONTAINER_DESKTOP)).isEqualTo(new CellPos(0, 0, 0));
+ assertThat(CellPosMapper.DEFAULT.mapPresenterToModel(
+ 0, 0, 1, CONTAINER_DESKTOP)).isEqualTo(new CellPos(0, 0, 1));
+ assertThat(CellPosMapper.DEFAULT.mapPresenterToModel(
+ 5, 0, 1, CONTAINER_DESKTOP)).isEqualTo(new CellPos(5, 0, 1));
+ assertThat(CellPosMapper.DEFAULT.mapPresenterToModel(
+ 5, 0, 0, CONTAINER_DESKTOP)).isEqualTo(new CellPos(5, 0, 0));
+
+ assertThat(CellPosMapper.DEFAULT.mapPresenterToModel(
+ 0, 0, 0, CONTAINER_HOTSEAT)).isEqualTo(new CellPos(0, 0, 0));
+ assertThat(CellPosMapper.DEFAULT.mapPresenterToModel(
+ 0, 0, 1, CONTAINER_HOTSEAT)).isEqualTo(new CellPos(0, 0, 1));
+ assertThat(CellPosMapper.DEFAULT.mapPresenterToModel(
+ 5, 0, 1, CONTAINER_HOTSEAT)).isEqualTo(new CellPos(5, 0, 1));
+ assertThat(CellPosMapper.DEFAULT.mapPresenterToModel(
+ 5, 0, 0, CONTAINER_HOTSEAT)).isEqualTo(new CellPos(5, 0, 0));
+ }
+
+ @Test
+ public void testMapModelToPresenter_twoPanel() {
+ CellPosMapper mapper = new TwoPanelCellPosMapper(8);
+ assertThat(mapper.mapModelToPresenter(
+ createInfo(0, 0, 0, CONTAINER_DESKTOP))).isEqualTo(new CellPos(0, 0, 0));
+ assertThat(mapper.mapModelToPresenter(
+ createInfo(0, 0, 1, CONTAINER_DESKTOP))).isEqualTo(new CellPos(8, 0, 0));
+ assertThat(mapper.mapModelToPresenter(
+ createInfo(5, 0, 1, CONTAINER_DESKTOP))).isEqualTo(new CellPos(13, 0, 0));
+ assertThat(mapper.mapModelToPresenter(
+ createInfo(5, 0, 0, CONTAINER_DESKTOP))).isEqualTo(new CellPos(5, 0, 0));
+
+ assertThat(mapper.mapModelToPresenter(
+ createInfo(0, 0, 0, CONTAINER_HOTSEAT))).isEqualTo(new CellPos(0, 0, 0));
+ assertThat(mapper.mapModelToPresenter(
+ createInfo(0, 0, 1, CONTAINER_HOTSEAT))).isEqualTo(new CellPos(0, 0, 1));
+ assertThat(mapper.mapModelToPresenter(
+ createInfo(5, 0, 1, CONTAINER_HOTSEAT))).isEqualTo(new CellPos(5, 0, 1));
+ assertThat(mapper.mapModelToPresenter(
+ createInfo(5, 0, 0, CONTAINER_HOTSEAT))).isEqualTo(new CellPos(5, 0, 0));
+ }
+
+ @Test
+ public void testMapPresenterToModel_twoPanel() {
+ CellPosMapper mapper = new TwoPanelCellPosMapper(3);
+ assertThat(mapper.mapPresenterToModel(
+ 0, 0, 0, CONTAINER_DESKTOP)).isEqualTo(new CellPos(0, 0, 0));
+ assertThat(mapper.mapPresenterToModel(
+ 0, 0, 1, CONTAINER_DESKTOP)).isEqualTo(new CellPos(0, 0, 1));
+ assertThat(mapper.mapPresenterToModel(
+ 5, 0, 1, CONTAINER_DESKTOP)).isEqualTo(new CellPos(5, 0, 1));
+ assertThat(mapper.mapPresenterToModel(
+ 5, 0, 0, CONTAINER_DESKTOP)).isEqualTo(new CellPos(2, 0, 1));
+
+ assertThat(mapper.mapPresenterToModel(
+ 0, 0, 0, CONTAINER_HOTSEAT)).isEqualTo(new CellPos(0, 0, 0));
+ assertThat(mapper.mapPresenterToModel(
+ 0, 0, 1, CONTAINER_HOTSEAT)).isEqualTo(new CellPos(0, 0, 1));
+ assertThat(mapper.mapPresenterToModel(
+ 5, 0, 1, CONTAINER_HOTSEAT)).isEqualTo(new CellPos(5, 0, 1));
+ assertThat(mapper.mapPresenterToModel(
+ 5, 0, 0, CONTAINER_HOTSEAT)).isEqualTo(new CellPos(5, 0, 0));
+ }
+
+ private ItemInfo createInfo(int cellX, int cellY, int screen, int container) {
+ ItemInfo info = new ItemInfo();
+ info.cellX = cellX;
+ info.cellY = cellY;
+ info.screenId = screen;
+ info.container = container;
+ return info;
+ }
+}