From 7f169c7c6da144f9912d7b121518c09dc4d608b2 Mon Sep 17 00:00:00 2001 From: Jeremy Sim Date: Thu, 16 Mar 2023 13:27:51 -0700 Subject: [PATCH 01/14] Fix animation canceling crash bug (short swipe during split select) This patch fixes a bug where the user could cause a crash by making a gesture during the Overview > OverviewSplitSelect animation. Within Overview, the user is able to make an upward gesture from the bottom of screen to return to Home. However, if the gesture is very short, the user doesn't go back to Home and instead stays in Overview. Under normal situations this doesn't cause any problems. But if we are in the middle of an animation, the short gesture actually triggers an animation cancel followed by an immediate goToState() to the same state that it was already in. This causes problems with the OverviewSplitSelect transition because reset() is called in the middle, clearing important split select data and causing a crash. Fixed by changing a conditional to detect if we are this type of situation, and allowing the animation to play out in these cases. Fixes: 272793237 Test: Manual Change-Id: I4426204b9c8fc55853cf7df31a336ccaee2f5885 --- src/com/android/launcher3/statemanager/StateManager.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/com/android/launcher3/statemanager/StateManager.java b/src/com/android/launcher3/statemanager/StateManager.java index 89d89d6eca..198dad3c89 100644 --- a/src/com/android/launcher3/statemanager/StateManager.java +++ b/src/com/android/launcher3/statemanager/StateManager.java @@ -229,8 +229,10 @@ public class StateManager> { listener.onAnimationEnd(null); } return; - } else if (!mConfig.userControlled && animated && mConfig.targetState == state) { - // We are running the same animation as requested + } else if ((!mConfig.userControlled && animated && mConfig.targetState == state) + || mState.shouldPreserveDataStateOnReapply()) { + // We are running the same animation as requested, and/or target state should not be + // reset -- allow the current animation to complete instead of canceling it. if (listener != null) { mConfig.currentAnimation.addListener(listener); } From 7344766886921cb3c170eecac96706567aced051 Mon Sep 17 00:00:00 2001 From: Mady Mellor Date: Fri, 7 Apr 2023 14:14:09 -0700 Subject: [PATCH 02/14] Modify Taskbar code to accommodate bubble bar gesture to stash/unstash * Bubble bar typically follows the behavior of taskbar - if taskbar is shown, the bubble bar is shown, if taskbar hides, bubble bar hides. * The bubble bar has 3 states: stashed, collapsed (unstashed but the bubbles are not expanded), and expanded. When bubbles are expanded, this means WMShell is rendering the bubble expanded view. In this situation taskbar becomes collapsed. Bug: 253318833 Test: manual, with other CLs, see go/bubble-bar-tests Flag: WM_BUBBLE_BAR Change-Id: Ic210c382e7482c259ae543a0dc083fe9305cbf5b --- .../taskbar/TaskbarActivityContext.java | 24 ++++++- .../taskbar/TaskbarInsetsController.kt | 49 ++++++++++---- .../TaskbarLauncherStateController.java | 10 ++- .../taskbar/TaskbarScrimViewController.java | 6 ++ .../taskbar/TaskbarStashController.java | 65 +++++++++++++++---- .../taskbar/TaskbarStashViaTouchController.kt | 20 +++++- .../taskbar/TaskbarTranslationController.java | 4 ++ .../bubbles/BubbleBarViewController.java | 13 +++- .../bubbles/BubbleStashController.java | 5 +- .../TaskbarUnstashInputConsumer.java | 29 +++++++-- 10 files changed, 188 insertions(+), 37 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index d94d8f7fe0..8bc1fcacce 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -444,6 +444,11 @@ public class TaskbarActivityContext extends BaseTaskbarContext { return mControllers.taskbarDragController; } + @Nullable + public BubbleControllers getBubbleControllers() { + return mControllers.bubbleControllers.orElse(null); + } + @Override public ViewCache getViewCache() { return mViewCache; @@ -620,8 +625,12 @@ public class TaskbarActivityContext extends BaseTaskbarContext { mControllers.taskbarForceVisibleImmersiveController.updateSysuiFlags(systemUiStateFlags); mControllers.voiceInteractionWindowController.setIsVoiceInteractionWindowVisible( (systemUiStateFlags & SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING) != 0, fromInit); - mControllers.uiController.updateStateForSysuiFlags(systemUiStateFlags); + mControllers.bubbleControllers.ifPresent(controllers -> { + controllers.bubbleBarController.updateStateForSysuiFlags(systemUiStateFlags); + controllers.bubbleStashedHandleViewController.setIsHomeButtonDisabled( + mControllers.navbarButtonsViewController.isHomeDisabled()); + }); } /** @@ -717,7 +726,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext { } } mWindowLayoutParams.height = height; - mControllers.taskbarInsetsController.onTaskbarWindowHeightOrInsetsChanged(); + mControllers.taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged(); mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams); } @@ -975,10 +984,19 @@ public class TaskbarActivityContext extends BaseTaskbarContext { * Called when we want to unstash taskbar when user performs swipes up gesture. */ public void onSwipeToUnstashTaskbar() { - mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(false); + mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(/* stash= */ false); mControllers.taskbarEduTooltipController.hide(); } + /** + * Called when we want to open bubblebar when user performs swipes up gesture. + */ + public void onSwipeToOpenBubblebar() { + mControllers.bubbleControllers.ifPresent(controllers -> { + controllers.bubbleStashController.showBubbleBar(/* expandBubbles= */ true); + }); + } + /** Returns {@code true} if taskbar All Apps is open. */ public boolean isTaskbarAllAppsOpen() { return mControllers.taskbarAllAppsController.isOpen(); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt index 4422fd4b75..7adee266c5 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt @@ -53,13 +53,13 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas private val touchableRegion: Region = Region() private val insetsOwner: IBinder = Binder() private val deviceProfileChangeListener = { _: DeviceProfile -> - onTaskbarWindowHeightOrInsetsChanged() + onTaskbarOrBubblebarWindowHeightOrInsetsChanged() } private val gestureNavSettingsObserver = GestureNavigationSettingsObserver( context.mainThreadHandler, context, - this::onTaskbarWindowHeightOrInsetsChanged + this::onTaskbarOrBubblebarWindowHeightOrInsetsChanged ) // Initialized in init. @@ -69,7 +69,7 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas fun init(controllers: TaskbarControllers) { this.controllers = controllers windowLayoutParams = context.windowLayoutParams - onTaskbarWindowHeightOrInsetsChanged() + onTaskbarOrBubblebarWindowHeightOrInsetsChanged() context.addOnDeviceProfileChangeListener(deviceProfileChangeListener) gestureNavSettingsObserver.registerForCallingUser() @@ -80,7 +80,7 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas gestureNavSettingsObserver.unregister() } - fun onTaskbarWindowHeightOrInsetsChanged() { + fun onTaskbarOrBubblebarWindowHeightOrInsetsChanged() { if (context.isGestureNav) { windowLayoutParams.providedInsets = arrayOf( @@ -102,13 +102,33 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas ) } - val touchableHeight = controllers.taskbarStashController.touchableHeight - touchableRegion.set( - 0, - windowLayoutParams.height - touchableHeight, - context.deviceProfile.widthPx, - windowLayoutParams.height - ) + val taskbarTouchableHeight = controllers.taskbarStashController.touchableHeight + val bubblesTouchableHeight = + if (controllers.bubbleControllers.isPresent) + controllers.bubbleControllers.get().bubbleStashController.touchableHeight + else 0 + val touchableHeight = Math.max(taskbarTouchableHeight, bubblesTouchableHeight) + + if ( + controllers.bubbleControllers.isPresent && + controllers.bubbleControllers.get().bubbleStashController.isBubblesShowingOnHome + ) { + val iconBounds = + controllers.bubbleControllers.get().bubbleBarViewController.bubbleBarBounds + touchableRegion.set( + iconBounds.left, + iconBounds.top, + iconBounds.right, + iconBounds.bottom + ) + } else { + touchableRegion.set( + 0, + windowLayoutParams.height - touchableHeight, + context.deviceProfile.widthPx, + windowLayoutParams.height + ) + } val contentHeight = controllers.taskbarStashController.contentHeightToReportToApps val tappableHeight = controllers.taskbarStashController.tappableHeightToReportToApps val res = context.resources @@ -197,6 +217,9 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas context.dragLayer, insetsInfo.touchableRegion ) + val bubbleBarVisible = + controllers.bubbleControllers.isPresent && + controllers.bubbleControllers.get().bubbleBarViewController.isBubbleBarVisible() var insetsIsTouchableRegion = true if (context.dragLayer.alpha < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) { // Let touches pass through us. @@ -217,7 +240,9 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME) insetsIsTouchableRegion = false } else if ( - controllers.taskbarViewController.areIconsVisible() || context.isNavBarKidsModeActive + controllers.taskbarViewController.areIconsVisible() || + context.isNavBarKidsModeActive || + bubbleBarVisible ) { // Taskbar has some touchable elements, take over the full taskbar area insetsInfo.touchableRegion.set(touchableRegion) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java index 75cfd05d41..2b9d968d82 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java @@ -408,6 +408,14 @@ public class TaskbarLauncherStateController { + ", mLauncherState: " + mLauncherState + ", toAlignment: " + toAlignment); } + mControllers.bubbleControllers.ifPresent(controllers -> { + // Show the bubble bar when on launcher home or in overview. + boolean onHome = isInLauncher && mLauncherState == LauncherState.NORMAL; + boolean onOverview = mLauncherState == LauncherState.OVERVIEW; + controllers.bubbleStashController.setBubblesShowingOnHome(onHome); + controllers.bubbleStashController.setBubblesShowingOnOverview(onOverview); + }); + AnimatorSet animatorSet = new AnimatorSet(); if (hasAnyFlag(changedFlags, FLAG_LAUNCHER_IN_STATE_TRANSITION)) { @@ -475,7 +483,7 @@ public class TaskbarLauncherStateController { TaskbarStashController stashController = mControllers.taskbarStashController; stashController.updateAndAnimateTransientTaskbar( - /* stash */ true, /* duration */ 0); + /* stash */ true, /* duration */ 0, true /* bubblesShouldFollow */); } }); } else { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java index 5ea00cf408..1c250bf377 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java @@ -15,6 +15,7 @@ */ package com.android.launcher3.taskbar; +import static com.android.launcher3.taskbar.bubbles.BubbleBarController.BUBBLE_BAR_ENABLED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED; @@ -23,6 +24,7 @@ import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; import com.android.launcher3.anim.AnimatedFloat; +import com.android.launcher3.util.DisplayController; import com.android.quickstep.SystemUiProxy; import java.io.PrintWriter; @@ -63,6 +65,10 @@ public class TaskbarScrimViewController implements TaskbarControllers.LoggableTa * Updates the scrim state based on the flags. */ public void updateStateForSysuiFlags(int stateFlags, boolean skipAnim) { + if (BUBBLE_BAR_ENABLED && DisplayController.isTransientTaskbar(mActivity)) { + // These scrims aren't used if bubble bar & transient taskbar are active. + return; + } final boolean bubblesExpanded = (stateFlags & SYSUI_STATE_BUBBLES_EXPANDED) != 0; final boolean manageMenuExpanded = (stateFlags & SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED) != 0; diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java index c2175f2444..0dd8310aa7 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java @@ -255,14 +255,15 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba private boolean mEnableBlockingTimeoutDuringTests = false; // Evaluate whether the handle should be stashed + private final IntPredicate mIsStashedPredicate = flags -> { + boolean inApp = hasAnyFlag(flags, FLAGS_IN_APP); + boolean stashedInApp = hasAnyFlag(flags, FLAGS_STASHED_IN_APP); + boolean stashedLauncherState = hasAnyFlag(flags, FLAG_IN_STASHED_LAUNCHER_STATE); + boolean forceStashed = hasAnyFlag(flags, FLAGS_FORCE_STASHED); + return (inApp && stashedInApp) || (!inApp && stashedLauncherState) || forceStashed; + }; private final StatePropertyHolder mStatePropertyHolder = new StatePropertyHolder( - flags -> { - boolean inApp = hasAnyFlag(flags, FLAGS_IN_APP); - boolean stashedInApp = hasAnyFlag(flags, FLAGS_STASHED_IN_APP); - boolean stashedLauncherState = hasAnyFlag(flags, FLAG_IN_STASHED_LAUNCHER_STATE); - boolean forceStashed = hasAnyFlag(flags, FLAGS_FORCE_STASHED); - return (inApp && stashedInApp) || (!inApp && stashedLauncherState) || forceStashed; - }); + mIsStashedPredicate); private boolean mIsTaskbarSystemActionRegistered = false; private TaskbarSharedState mTaskbarSharedState; @@ -502,15 +503,29 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba /** * Stash or unstashes the transient taskbar, using the default TASKBAR_STASH_DURATION. + * If bubble bar exists, it will match taskbars stashing behavior. */ public void updateAndAnimateTransientTaskbar(boolean stash) { - updateAndAnimateTransientTaskbar(stash, TASKBAR_STASH_DURATION); + updateAndAnimateTransientTaskbar(stash, TASKBAR_STASH_DURATION, + /* shouldBubblesFollow= */ true); + } + + /** + * Stash or unstashes the transient taskbar, using the default TASKBAR_STASH_DURATION. + * If bubble bar exists, it will match taskbars stashing behavior. + */ + public void updateAndAnimateTransientTaskbar(boolean stash, boolean shouldBubblesFollow) { + updateAndAnimateTransientTaskbar(stash, TASKBAR_STASH_DURATION, shouldBubblesFollow); } /** * Stash or unstashes the transient taskbar. + * @param stash whether transient taskbar should be stashed. + * @param duration how long the duration of the stash should take. + * @param shouldBubblesFollow whether bubbles should match taskbars behavior. */ - public void updateAndAnimateTransientTaskbar(boolean stash, long duration) { + public void updateAndAnimateTransientTaskbar(boolean stash, long duration, + boolean shouldBubblesFollow) { if (!DisplayController.isTransientTaskbar(mActivity)) { return; } @@ -526,6 +541,34 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba updateStateForFlag(FLAG_STASHED_IN_APP_AUTO, stash); applyState(); } + + mControllers.bubbleControllers.ifPresent(controllers -> { + if (shouldBubblesFollow) { + final boolean willStash = mIsStashedPredicate.test(mState); + if (willStash != controllers.bubbleStashController.isStashed()) { + // Typically bubbles gets stashed / unstashed along with Taskbar, however, if + // taskbar is becoming stashed because bubbles is being expanded, we don't want + // to stash bubbles. + if (willStash) { + controllers.bubbleStashController.stashBubbleBar(); + } else { + controllers.bubbleStashController.showBubbleBar(false /* expandBubbles */); + } + } + } + }); + } + + /** + * Stashes transient taskbar after it has timed out. + */ + private void updateAndAnimateTransientTaskbarForTimeout() { + // If bubbles are expanded we shouldn't stash them when taskbar is hidden + // for the timeout. + boolean bubbleBarExpanded = mControllers.bubbleControllers.isPresent() + && mControllers.bubbleControllers.get().bubbleBarViewController.isExpanded(); + updateAndAnimateTransientTaskbar(/* stash= */ true, + /* shouldBubblesFollow= */ !bubbleBarExpanded); } /** @@ -880,7 +923,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba private void onIsStashedChanged(boolean isStashed) { mControllers.runAfterInit(() -> { mControllers.stashedHandleViewController.onIsStashedChanged(isStashed); - mControllers.taskbarInsetsController.onTaskbarWindowHeightOrInsetsChanged(); + mControllers.taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged(); }); } @@ -1127,7 +1170,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba if (mControllers.taskbarAutohideSuspendController.isSuspended()) { return; } - updateAndAnimateTransientTaskbar(true); + updateAndAnimateTransientTaskbarForTimeout(); } @Override diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashViaTouchController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashViaTouchController.kt index 1cc667211c..b194c8e6b2 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashViaTouchController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashViaTouchController.kt @@ -108,7 +108,18 @@ class TaskbarStashViaTouchController(val controllers: TaskbarControllers) : Touc } override fun onControllerInterceptTouchEvent(ev: MotionEvent): Boolean { - if (!enabled || controllers.taskbarStashController.isStashed) { + val bubbleControllers = controllers.bubbleControllers.orElse(null) + if (!enabled || bubbleControllers == null) { + return false + } + if (bubbleControllers.bubbleBarViewController.isExpanded) { + // WMShell / bubbles will handle collapsing + return false + } + if ( + controllers.taskbarStashController.isStashed && + bubbleControllers.bubbleStashController.isStashed + ) { return false } @@ -122,7 +133,12 @@ class TaskbarStashViaTouchController(val controllers: TaskbarControllers) : Touc return true } } else if (ev.action == MotionEvent.ACTION_DOWN) { - if (screenCoordinatesEv.y < gestureHeightYThreshold) { + val isDownOnBubbleBar = + (bubbleControllers != null && + bubbleControllers.bubbleBarViewController.isEventOverAnyItem( + screenCoordinatesEv + )) + if (!isDownOnBubbleBar && screenCoordinatesEv.y < gestureHeightYThreshold) { controllers.taskbarStashController.updateAndAnimateTransientTaskbar(true) } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java index 065d1117c8..2456f4b5ae 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java @@ -92,6 +92,10 @@ public class TaskbarTranslationController implements TaskbarControllers.Loggable mControllers.stashedHandleViewController.setTranslationYForSwipe(transY); mControllers.taskbarViewController.setTranslationYForSwipe(transY); mControllers.taskbarDragLayerController.setTranslationYForSwipe(transY); + mControllers.bubbleControllers.ifPresent(controllers -> { + controllers.bubbleBarViewController.setTranslationYForSwipe(transY); + controllers.bubbleStashedHandleViewController.setTranslationYForSwipe(transY); + }); } /** diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java index 82494c6fda..37861896e0 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java @@ -28,6 +28,8 @@ import com.android.launcher3.R; import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.taskbar.TaskbarActivityContext; import com.android.launcher3.taskbar.TaskbarControllers; +import com.android.launcher3.taskbar.TaskbarInsetsController; +import com.android.launcher3.taskbar.TaskbarStashController; import com.android.launcher3.util.MultiPropertyFactory; import com.android.launcher3.util.MultiValueAlpha; import com.android.quickstep.SystemUiProxy; @@ -51,6 +53,8 @@ public class BubbleBarViewController { // Initialized in init. private BubbleStashController mBubbleStashController; private BubbleBarController mBubbleBarController; + private TaskbarStashController mTaskbarStashController; + private TaskbarInsetsController mTaskbarInsetsController; private View.OnClickListener mBubbleClickListener; private View.OnClickListener mBubbleBarClickListener; @@ -80,6 +84,8 @@ public class BubbleBarViewController { public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) { mBubbleStashController = bubbleControllers.bubbleStashController; mBubbleBarController = bubbleControllers.bubbleBarController; + mTaskbarStashController = controllers.taskbarStashController; + mTaskbarInsetsController = controllers.taskbarInsetsController; mActivity.addOnDeviceProfileChangeListener(dp -> mBarView.getLayoutParams().height = mActivity.getDeviceProfile().taskbarHeight @@ -89,7 +95,9 @@ public class BubbleBarViewController { mBubbleClickListener = v -> onBubbleClicked(v); mBubbleBarClickListener = v -> setExpanded(true); mBarView.setOnClickListener(mBubbleBarClickListener); - // TODO: when barView layout changes tell taskbarInsetsController the insets have changed. + mBarView.addOnLayoutChangeListener((view, i, i1, i2, i3, i4, i5, i6, i7) -> + mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged() + ); } private void onBubbleClicked(View v) { @@ -283,7 +291,8 @@ public class BubbleBarViewController { } else { Log.w(TAG, "trying to expand bubbles when there isn't one selected"); } - // TODO: Tell taskbar stash controller to stash without bubbles following + mTaskbarStashController.updateAndAnimateTransientTaskbar(true /* stash */, + false /* shouldBubblesFollow */); } } } diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java index 0ab53b0c20..b3c7d41e37 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java @@ -25,6 +25,7 @@ import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.taskbar.StashedHandleViewController; import com.android.launcher3.taskbar.TaskbarActivityContext; import com.android.launcher3.taskbar.TaskbarControllers; +import com.android.launcher3.taskbar.TaskbarInsetsController; import com.android.launcher3.taskbar.TaskbarStashController; import com.android.launcher3.util.MultiPropertyFactory; @@ -50,6 +51,7 @@ public class BubbleStashController { // Initialized in init. private TaskbarControllers mControllers; + private TaskbarInsetsController mTaskbarInsetsController; private BubbleBarViewController mBarViewController; private BubbleStashedHandleViewController mHandleViewController; private TaskbarStashController mTaskbarStashController; @@ -77,6 +79,7 @@ public class BubbleStashController { public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) { mControllers = controllers; + mTaskbarInsetsController = controllers.taskbarInsetsController; mBarViewController = bubbleControllers.bubbleBarViewController; mHandleViewController = bubbleControllers.bubbleStashedHandleViewController; mTaskbarStashController = controllers.taskbarStashController; @@ -271,7 +274,7 @@ public class BubbleStashController { private void onIsStashedChanged() { mControllers.runAfterInit(() -> { mHandleViewController.onIsStashedChanged(); - // TODO: when stash changes tell taskbarInsetsController the insets have changed. + mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged(); }); } } diff --git a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java index 65c825c0f6..b9126ebdfc 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java @@ -37,6 +37,7 @@ import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.taskbar.TaskbarActivityContext; import com.android.launcher3.taskbar.TaskbarTranslationController.TransitionCallback; +import com.android.launcher3.taskbar.bubbles.BubbleControllers; import com.android.launcher3.touch.OverScroll; import com.android.launcher3.util.DisplayController; import com.android.quickstep.InputConsumer; @@ -62,6 +63,7 @@ public class TaskbarUnstashInputConsumer extends DelegateInputConsumer { private final int mTaskbarNavThresholdY; private final boolean mIsTaskbarAllAppsOpen; private boolean mHasPassedTaskbarNavThreshold; + private boolean mIsInBubbleBarArea; private final PointF mDownPos = new PointF(); private final PointF mLastPos = new PointF(); @@ -135,7 +137,7 @@ public class TaskbarUnstashInputConsumer extends DelegateInputConsumer { mHasPassedTaskbarNavThreshold = false; mTaskbarActivityContext.setAutohideSuspendFlag( FLAG_AUTOHIDE_SUSPEND_TOUCHING, true); - if (isInArea(x)) { + if (isInTaskbarArea(x)) { if (!mIsTransientTaskbar) { mLongPressDownX = x; mLongPressDownY = y; @@ -144,10 +146,12 @@ public class TaskbarUnstashInputConsumer extends DelegateInputConsumer { mCanceledUnstashHint = false; } } - if (mTransitionCallback != null && !mIsTaskbarAllAppsOpen) { mTransitionCallback.onActionDown(); } + if (mIsTransientTaskbar && isInBubbleBarArea(x)) { + mIsInBubbleBarArea = true; + } break; case MotionEvent.ACTION_POINTER_UP: int ptrIdx = ev.getActionIndex(); @@ -184,7 +188,11 @@ public class TaskbarUnstashInputConsumer extends DelegateInputConsumer { if (!mHasPassedTaskbarNavThreshold && passedTaskbarNavThreshold) { mHasPassedTaskbarNavThreshold = true; - mTaskbarActivityContext.onSwipeToUnstashTaskbar(); + if (mIsInBubbleBarArea) { + mTaskbarActivityContext.onSwipeToOpenBubblebar(); + } else { + mTaskbarActivityContext.onSwipeToUnstashTaskbar(); + } } if (dY < 0) { @@ -207,21 +215,32 @@ public class TaskbarUnstashInputConsumer extends DelegateInputConsumer { mTransitionCallback.onActionEnd(); } mHasPassedTaskbarNavThreshold = false; + mIsInBubbleBarArea = false; break; } } } } - private boolean isInArea(float x) { + private boolean isInTaskbarArea(float x) { float areaFromMiddle = mUnstashArea / 2.0f; float distFromMiddle = Math.abs(mScreenWidth / 2.0f - x); return distFromMiddle < areaFromMiddle; } + private boolean isInBubbleBarArea(float x) { + if (mTaskbarActivityContext != null && mIsTransientTaskbar) { + BubbleControllers controllers = mTaskbarActivityContext.getBubbleControllers(); + if (controllers == null) return false; + Rect bubbleBarBounds = controllers.bubbleBarViewController.getBubbleBarBounds(); + return x >= bubbleBarBounds.left && x <= bubbleBarBounds.right; + } + return false; + } + private void onLongPressDetected(MotionEvent motionEvent) { if (mTaskbarActivityContext != null - && isInArea(motionEvent.getRawX()) + && isInTaskbarArea(motionEvent.getRawX()) && !mIsTransientTaskbar) { boolean taskBarPressed = mTaskbarActivityContext.onLongPressToUnstashTaskbar(); if (taskBarPressed) { From 4952c38e9985ce827c766d696040fce2323c7cda Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Tue, 9 May 2023 16:05:06 -0700 Subject: [PATCH 03/14] Import translations. DO NOT MERGE ANYWHERE Auto-generated-cl: translation import Change-Id: Ia153260da53bbf2027221ca0a2daecec07e1f1da --- quickstep/res/values-cs/strings.xml | 2 +- quickstep/res/values-es/strings.xml | 2 +- quickstep/res/values-in/strings.xml | 2 +- quickstep/res/values-ml/strings.xml | 2 +- quickstep/res/values-or/strings.xml | 2 +- quickstep/res/values-pa/strings.xml | 2 +- quickstep/res/values-sk/strings.xml | 2 +- quickstep/res/values-te/strings.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml index 421b684674..b7241588c7 100644 --- a/quickstep/res/values-cs/strings.xml +++ b/quickstep/res/values-cs/strings.xml @@ -88,7 +88,7 @@ "Sdílet" "Snímek obrazovky" "Rozdělit" - "Klepnutím na jinou aplikaci rozdělíte obrazovku" + "Obrazovku rozdělíte klepnutím na jinou aplikaci" "Vyberte podporovanou aplikaci" "Aplikace nebo organizace zakazuje tuto akci" "Přeskočit výukový program k navigaci?" diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml index e68cab82ac..05828aa49a 100644 --- a/quickstep/res/values-es/strings.xml +++ b/quickstep/res/values-es/strings.xml @@ -88,7 +88,7 @@ "Compartir" "Hacer captura" "Dividir" - "Toca otra app para usar la pantalla dividida" + "Toca otra aplicación para usar la pantalla dividida" "Elige otra app para usar la pantalla dividida" "No puedes hacerlo porque la aplicación o tu organización no lo permiten" "¿Saltar tutorial de navegación?" diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml index ea5c19b1e5..b639e847ec 100644 --- a/quickstep/res/values-in/strings.xml +++ b/quickstep/res/values-in/strings.xml @@ -88,7 +88,7 @@ "Bagikan" "Screenshot" "Pisahkan" - "Ketuk apl lain untuk menggunakan layar terpisah" + "Ketuk aplikasi lain untuk memakai layar terpisah" "Pilih aplikasi lain untuk memakai layar terpisah" "Tindakan ini tidak diizinkan oleh aplikasi atau organisasi Anda" "Lewati tutorial gestur?" diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml index 17363c4058..735cde1887 100644 --- a/quickstep/res/values-ml/strings.xml +++ b/quickstep/res/values-ml/strings.xml @@ -88,7 +88,7 @@ "പങ്കിടുക" "സ്ക്രീൻഷോട്ട്" "വിഭജിക്കുക" - "സ്പ്ലിറ്റ് സ്ക്രീനിനായി മറ്റൊരു ആപ്പ് ടാപ്പുചെയ്യൂ" + "സ്പ്ലിറ്റ് സ്ക്രീനിന് മറ്റൊരു ആപ്പിൽ ടാപ്പ് ചെയ്യൂ" "സ്ക്രീൻ വിഭജന മോഡിന് മറ്റൊരു ആപ്പ് തിരഞ്ഞെടുക്കൂ" "ഈ നടപടി എടുക്കുന്നത് ആപ്പോ നിങ്ങളുടെ സ്ഥാപനമോ അനുവദിക്കുന്നില്ല" "നാവിഗേഷൻ ട്യൂട്ടോറിയൽ ഒഴിവാക്കണോ?" diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml index a2a598beef..5c48ffc168 100644 --- a/quickstep/res/values-or/strings.xml +++ b/quickstep/res/values-or/strings.xml @@ -21,7 +21,7 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "ପିନ୍‍" "ଫ୍ରିଫର୍ମ" - "କୌଣସି ସାମ୍ପ୍ରତିକ ଆଇଟମ୍ ନାହିଁ" + "ବର୍ତ୍ତମାନର କୌଣସି ଆଇଟମ ନାହିଁ" "ଆପ ବ୍ୟବହାର ସେଟିଂସ" "ସବୁ ଖାଲି କରନ୍ତୁ" "ବର୍ତ୍ତମାନର ଆପ୍‌" diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml index bfa881bdca..5797bbc7d5 100644 --- a/quickstep/res/values-pa/strings.xml +++ b/quickstep/res/values-pa/strings.xml @@ -99,7 +99,7 @@ "ਟਾਸਕਬਾਰ ਸਿੱਖਿਆ" "ਟਾਸਕਵਾਰ ਸਿੱਖਿਆ ਪੈਨਲ ਦਿਖਾਇਆ ਗਿਆ" "ਟਾਸਕਵਾਰ ਸਿੱਖਿਆ ਪੈਨਲ ਬੰਦ ਕੀਤਾ ਗਿਆ" - "ਇੱਕ ਵਾਰ ਵਿੱਚ 2 ਐਪਾਂ ਵਰਤਣ ਲਈ, ਐਪ ਨੂੰ ਪਾਸੇ ਵੱਲ ਘਸੀਟੋ" + "ਇੱਕੋ ਸਮੇਂ \'ਤੇ 2 ਐਪਾਂ ਵਰਤਣ ਲਈ, ਐਪ ਨੂੰ ਪਾਸੇ ਵੱਲ ਘਸੀਟੋ" "ਟਾਸਕਬਾਰ ਦਿਖਾਉਣ ਲਈ ਥੋੜ੍ਹਾ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ" "ਤੁਹਾਡੇ ਨਿਯਮਬੱਧ ਕੰਮ ਦੇ ਆਧਾਰ \'ਤੇ ਐਪ ਸੁਝਾਅ ਪ੍ਰਾਪਤ ਕਰੋ" "ਟਾਸਕਬਾਰ ਨੂੰ ਸਵੈ-ਲੁਕਾਉਣ ਲਈ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਇਸ਼ਾਰਾ ਨੈਵੀਗੇਸ਼ਨ ਨੂੰ ਚਾਲੂ ਕਰੋ" diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml index f3bf2b92fc..0d550ea878 100644 --- a/quickstep/res/values-sk/strings.xml +++ b/quickstep/res/values-sk/strings.xml @@ -88,7 +88,7 @@ "Zdieľať" "Snímka obrazovky" "Rozdeliť" - "Rozdelenú obrazovku spustíte klep. na inú aplik." + "Obrazovku rozdelíte klepnutím na inú aplikáciu" "Na použitie rozd. obrazovky vyberte inú aplikáciu" "Aplikácia alebo vaša organizácia túto akciu nepovoľuje" "Chcete preskočiť návod na navigáciu?" diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml index fb00c5bf6c..3cbc842f87 100644 --- a/quickstep/res/values-te/strings.xml +++ b/quickstep/res/values-te/strings.xml @@ -88,7 +88,7 @@ "షేర్ చేయండి" "స్క్రీన్‌షాట్" "స్ప్లిట్ చేయండి" - "మరొక యాప్‌ను ట్యాప్ చేసి, స్ప్లిట్ స్క్రీన్ వాడండి" + "స్ప్లిట్ స్క్రీన్ కోసం మరొక యాప్‌ను ట్యాప్ చేయండి" "స్ప్లిట్ స్క్రీన్ ఉపయోగానికి మరొక యాప్ ఎంచుకోండి" "ఈ చర్యను యాప్ గానీ, మీ సంస్థ గానీ అనుమతించవు" "నావిగేషన్ ట్యుటోరియల్‌ను స్కిప్ చేయాలా?" From 85f0ac5cbc3d2e930f87dade0a3c8b11b6ea136e Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Tue, 9 May 2023 16:06:10 -0700 Subject: [PATCH 04/14] Import translations. DO NOT MERGE ANYWHERE Auto-generated-cl: translation import Change-Id: Id11cd6362595181fbaa9213fb0d3a18ef663f381 --- go/quickstep/res/values-ky/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go/quickstep/res/values-ky/strings.xml b/go/quickstep/res/values-ky/strings.xml index 55e70c8cdf..dcc1e4ea77 100644 --- a/go/quickstep/res/values-ky/strings.xml +++ b/go/quickstep/res/values-ky/strings.xml @@ -11,9 +11,9 @@ "Экрандагы текстти которуу же угуу" "Экрандагы текст, веб-даректер жана скриншоттор сыяктуу маалымат Google менен бөлүшүлүшү мүмкүн.\n\nБөлүшүлгөн маалыматты өзгөртүү үчүн""Параметрлер > Колдонмолор > Демейки колдонмолор > Санариптик жардамчы колдонмосуна өтүңүз""." "Бул функцияны колдонуу үчүн жардамчыны тандаңыз" - "Экраныңыздагы текстти угуу же которуу үчүн Жөндөөлөрдөн санариптик жардамчы колдонмосун тандаңыз" + "Экраныңыздагы текстти угуу же которуу үчүн Параметрлерден санариптик жардамчы колдонмосун тандаңыз" "Бул функцияны колдонуу үчүн жардамчыңызды өзгөртүңүз" - "Экраныңыздагы текстти угуу же которуу үчүн Жөндөөлөрдөн санариптик жардамчы колдонмосун өзгөртүңүз" + "Экраныңыздагы текстти угуу же которуу үчүн Параметрлерден санариптик жардамчы колдонмосун өзгөртүңүз" "Бул экрандагы текстти угуу үчүн бул жерди басыңыз" "Бул экрандагы текстти которуу үчүн бул жерди басыңыз" "Бул колдонмону бөлүшүүгө болбойт" From c875f27912fb881acacd73207dfb6e1ece0d2899 Mon Sep 17 00:00:00 2001 From: Jagrut Desai Date: Wed, 10 May 2023 10:44:58 -0700 Subject: [PATCH 05/14] Fixing TaplTests Test: Pre-Submit Fixes: 281772186 Flag: not needed Change-Id: Ibe2987a69c9ca393ed267e755a3b99826164fee4 --- .../android/quickstep/AbstractTaplTestsTaskbar.java | 7 +++++-- .../android/quickstep/TaplTestsPersistentTaskbar.java | 7 ------- .../src/com/android/quickstep/TaplTestsTaskbar.java | 10 +++++++--- .../android/quickstep/TaplTestsTransientTaskbar.java | 7 ------- 4 files changed, 12 insertions(+), 19 deletions(-) diff --git a/quickstep/tests/src/com/android/quickstep/AbstractTaplTestsTaskbar.java b/quickstep/tests/src/com/android/quickstep/AbstractTaplTestsTaskbar.java index 9c0b2bf312..4ca3563f68 100644 --- a/quickstep/tests/src/com/android/quickstep/AbstractTaplTestsTaskbar.java +++ b/quickstep/tests/src/com/android/quickstep/AbstractTaplTestsTaskbar.java @@ -23,6 +23,7 @@ import android.content.Context; import android.content.Intent; import com.android.launcher3.tapl.LauncherInstrumentation; +import com.android.launcher3.tapl.Overview; import com.android.launcher3.tapl.Taskbar; import com.android.launcher3.ui.AbstractLauncherUiTest; import com.android.launcher3.ui.TaplTestsLauncher3; @@ -57,7 +58,10 @@ public class AbstractTaplTestsTaskbar extends AbstractQuickStepTest { "com.android.launcher3.testcomponent.BaseTestingActivity"); mLauncherLayout = TestUtil.setLauncherDefaultLayout(mTargetContext, layoutBuilder); TaplTestsLauncher3.initialize(this); - + Overview overview = mLauncher.getWorkspace().switchToOverview(); + if (overview.hasTasks()) { + overview.dismissAllTasks(); + } startAppFast(CALCULATOR_APP_PACKAGE); mLauncher.enableBlockTimeout(true); mLauncher.showTaskbarIfHidden(); @@ -65,7 +69,6 @@ public class AbstractTaplTestsTaskbar extends AbstractQuickStepTest { @After public void tearDown() throws Exception { - setTaskbarMode(mLauncher, mTaskbarWasInTransientMode); mLauncher.enableBlockTimeout(false); if (mLauncherLayout != null) { mLauncherLayout.close(); diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java index ee0eeb2d73..1b5313bad0 100644 --- a/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java +++ b/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java @@ -29,13 +29,6 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) public class TaplTestsPersistentTaskbar extends AbstractTaplTestsTaskbar { - @Override - public void setUp() throws Exception { - mTaskbarWasInTransientMode = isTaskbarInTransientMode(mTargetContext); - setTaskbarMode(mLauncher, false); - super.setUp(); - } - @Test @TaskbarModeSwitch(mode = PERSISTENT) public void testHideShowTaskbar() { diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java index 021e118937..40be4806ec 100644 --- a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java +++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java @@ -20,7 +20,6 @@ import static com.android.quickstep.TaplTestsTaskbar.TaskbarMode.TRANSIENT; import androidx.test.filters.LargeTest; -import com.android.launcher3.tapl.LauncherInstrumentation; import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord; import org.junit.Test; @@ -58,14 +57,19 @@ public class TaplTestsTaskbar extends AbstractTaplTestsTaskbar { super.setUp(); } + @Override + public void tearDown() throws Exception { + setTaskbarMode(mLauncher, mTaskbarWasInTransientMode); + super.tearDown(); + } + @Test public void testLaunchApp() { getTaskbar().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE); // We are using parameterized test runner to share code between different test cases with // taskbar variants. But, sometimes we only need to assert things for particular Taskbar // variants. - if (isTaskbarTestModeTransient() && mLauncher.getNavigationModel() - != LauncherInstrumentation.NavigationModel.THREE_BUTTON) { + if (isTaskbarTestModeTransient()) { mLauncher.getLaunchedAppState().assertTaskbarHidden(); } } diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java index 6b61f1884e..b58fe29a96 100644 --- a/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java +++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java @@ -32,13 +32,6 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) public class TaplTestsTransientTaskbar extends AbstractTaplTestsTaskbar { - @Override - public void setUp() throws Exception { - mTaskbarWasInTransientMode = isTaskbarInTransientMode(mTargetContext); - setTaskbarMode(mLauncher, true); - super.setUp(); - } - @Test @TaskbarModeSwitch(mode = TRANSIENT) public void testShowTaskbarUnstashHintOnHover() { From bca4e694f07ad76be5df639f52f345b0bb49d8ef Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 9 May 2023 19:06:45 +0000 Subject: [PATCH 06/14] Revert "Revert "Revert "Revert "Changing GridMigrationTask to use ModelDbController directly"""" This reverts commit 3772b246c2971d93f1b64755dd9249efe4828af1. Reason for revert: Fixed the test failure Change-Id: Ibdc9e184fcb32c7caa4ab25d8753a46fa322b703 --- .../launcher3/AppWidgetsRestoredReceiver.java | 8 +- .../android/launcher3/LauncherProvider.java | 12 - .../android/launcher3/LauncherSettings.java | 26 +- .../graphics/PreviewSurfaceRenderer.java | 34 ++- .../launcher3/model/DatabaseHelper.java | 82 +----- .../model/GridSizeMigrationUtil.java | 131 +++------ .../android/launcher3/model/LoaderCursor.java | 22 +- .../android/launcher3/model/LoaderTask.java | 100 +++---- .../launcher3/model/ModelDbController.java | 140 +++++---- .../launcher3/provider/LauncherDbUtils.java | 2 +- .../launcher3/provider/RestoreDbTask.java | 34 ++- .../android/launcher3/util/ContentWriter.java | 10 +- .../model/DbDowngradeHelperTest.java | 5 +- .../model/GridSizeMigrationUtilTest.kt | 275 +++++++++++------- .../launcher3/model/LoaderCursorTest.java | 3 +- .../provider/LauncherDbUtilsTest.java | 6 +- .../launcher3/provider/RestoreDbTaskTest.java | 84 +++--- .../launcher3/util/LauncherModelHelper.java | 8 +- 18 files changed, 469 insertions(+), 513 deletions(-) diff --git a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java index f041ffbe6c..5fbd48cdaf 100644 --- a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java +++ b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java @@ -16,8 +16,8 @@ import androidx.annotation.NonNull; import androidx.annotation.WorkerThread; import com.android.launcher3.LauncherSettings.Favorites; -import com.android.launcher3.model.DatabaseHelper; import com.android.launcher3.model.LoaderTask; +import com.android.launcher3.model.ModelDbController; import com.android.launcher3.model.WidgetsModel; import com.android.launcher3.model.data.LauncherAppWidgetInfo; import com.android.launcher3.pm.UserCache; @@ -52,7 +52,7 @@ public class AppWidgetsRestoredReceiver extends BroadcastReceiver { * Updates the app widgets whose id has changed during the restore process. */ @WorkerThread - public static void restoreAppWidgetIds(Context context, DatabaseHelper helper, + public static void restoreAppWidgetIds(Context context, ModelDbController controller, int[] oldWidgetIds, int[] newWidgetIds, @NonNull AppWidgetHost host) { if (WidgetsModel.GO_DISABLE_WIDGETS) { Log.e(TAG, "Skipping widget ID remap as widgets not supported"); @@ -92,12 +92,12 @@ public class AppWidgetsRestoredReceiver extends BroadcastReceiver { final String where = "appWidgetId=? and (restored & 1) = 1 and profileId=?"; final String[] args = new String[] { oldWidgetId, Long.toString(mainProfileId) }; int result = new ContentWriter(context, - new ContentWriter.CommitParams(helper, where, args)) + new ContentWriter.CommitParams(controller, where, args)) .put(LauncherSettings.Favorites.APPWIDGET_ID, newWidgetIds[i]) .put(LauncherSettings.Favorites.RESTORED, state) .commit(); if (result == 0) { - Cursor cursor = helper.getWritableDatabase().query( + Cursor cursor = controller.getDb().query( Favorites.TABLE_NAME, new String[] {Favorites.APPWIDGET_ID}, "appWidgetId=?", new String[] { oldWidgetId }, null, null, null); diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java index 0df4bd409e..9abec505c7 100644 --- a/src/com/android/launcher3/LauncherProvider.java +++ b/src/com/android/launcher3/LauncherProvider.java @@ -263,18 +263,6 @@ public class LauncherProvider extends ContentProvider { getModelDbController().refreshHotseatRestoreTable(); return null; } - case LauncherSettings.Settings.METHOD_UPDATE_CURRENT_OPEN_HELPER: { - Bundle result = new Bundle(); - result.putBoolean(LauncherSettings.Settings.EXTRA_VALUE, - getModelDbController().updateCurrentOpenHelper(arg /* dbFile */)); - return result; - } - case LauncherSettings.Settings.METHOD_PREP_FOR_PREVIEW: { - Bundle result = new Bundle(); - result.putBoolean(LauncherSettings.Settings.EXTRA_VALUE, - getModelDbController().prepareForPreview(arg /* dbFile */)); - return result; - } } return null; } diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java index b65e96ba52..7fda326ec2 100644 --- a/src/com/android/launcher3/LauncherSettings.java +++ b/src/com/android/launcher3/LauncherSettings.java @@ -147,11 +147,6 @@ public class LauncherSettings { */ public static final String HYBRID_HOTSEAT_BACKUP_TABLE = "hotseat_restore_backup"; - /** - * Temporary table used specifically for grid migrations during wallpaper preview - */ - public static final String PREVIEW_TABLE_NAME = "favorites_preview"; - /** * Temporary table used specifically for multi-db grid migrations */ @@ -163,18 +158,6 @@ public class LauncherSettings { public static final Uri CONTENT_URI = Uri.parse("content://" + LauncherProvider.AUTHORITY + "/" + TABLE_NAME); - /** - * The content:// style URL for "favorites_preview" table - */ - public static final Uri PREVIEW_CONTENT_URI = Uri.parse("content://" - + LauncherProvider.AUTHORITY + "/" + PREVIEW_TABLE_NAME); - - /** - * The content:// style URL for "favorites_tmp" table - */ - public static final Uri TMP_CONTENT_URI = Uri.parse("content://" - + LauncherProvider.AUTHORITY + "/" + TMP_TABLE); - /** * The content:// style URL for a given row, identified by its id. * @@ -376,10 +359,6 @@ public class LauncherSettings { public static final String METHOD_REFRESH_HOTSEAT_RESTORE_TABLE = "restore_hotseat_table"; - public static final String METHOD_UPDATE_CURRENT_OPEN_HELPER = "update_current_open_helper"; - - public static final String METHOD_PREP_FOR_PREVIEW = "prep_for_preview"; - public static final String EXTRA_VALUE = "value"; public static final String EXTRA_DB_NAME = "db_name"; @@ -393,11 +372,8 @@ public class LauncherSettings { } public static Bundle call(ContentResolver cr, String method, String arg) { - return call(cr, method, arg, null /* extras */); + return cr.call(CONTENT_URI, method, arg, null); } - public static Bundle call(ContentResolver cr, String method, String arg, Bundle extras) { - return cr.call(CONTENT_URI, method, arg, extras); - } } } diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java index 372e9bf2e9..8f0b8ec531 100644 --- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java +++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java @@ -16,6 +16,7 @@ package com.android.launcher3.graphics; +import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; @@ -52,6 +53,8 @@ import com.android.launcher3.graphics.LauncherPreviewRenderer.PreviewContext; import com.android.launcher3.model.BgDataModel; import com.android.launcher3.model.GridSizeMigrationUtil; import com.android.launcher3.model.LoaderTask; +import com.android.launcher3.model.ModelDbController; +import com.android.launcher3.provider.LauncherDbUtils; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.RunnableList; import com.android.launcher3.util.Themes; @@ -145,7 +148,9 @@ public class PreviewSurfaceRenderer { final String query = LauncherSettings.Favorites.ITEM_TYPE + " = " + LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET; - try (Cursor c = context.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI, + ModelDbController mainController = + LauncherAppState.getInstance(mContext).getModel().getModelDbController(); + try (Cursor c = mainController.query(TABLE_NAME, new String[] { LauncherSettings.Favorites.APPWIDGET_ID, LauncherSettings.Favorites.SPANX, @@ -190,8 +195,6 @@ public class PreviewSurfaceRenderer { @WorkerThread private void loadModelData() { - final boolean migrated = doGridMigrationIfNecessary(); - final Context inflationContext; if (mWallpaperColors != null) { // Create a themed context, without affecting the main application context @@ -209,8 +212,20 @@ public class PreviewSurfaceRenderer { Themes.getActivityThemeRes(mContext)); } - if (migrated) { + if (GridSizeMigrationUtil.needsToMigrate(inflationContext, mIdp)) { + // Start the migration PreviewContext previewContext = new PreviewContext(inflationContext, mIdp); + // Copy existing data to preview DB + LauncherDbUtils.copyTable(LauncherAppState.getInstance(mContext) + .getModel().getModelDbController().getDb(), + TABLE_NAME, + LauncherAppState.getInstance(previewContext) + .getModel().getModelDbController().getDb(), + TABLE_NAME, + mContext); + LauncherAppState.getInstance(previewContext) + .getModel().getModelDbController().clearEmptyDbFlag(); + new LoaderTask( LauncherAppState.getInstance(previewContext), /* bgAllAppsList= */ null, @@ -229,8 +244,7 @@ public class PreviewSurfaceRenderer { query += " or " + LauncherSettings.Favorites.SCREEN + " = " + Workspace.SECOND_SCREEN_ID; } - loadWorkspaceForPreviewSurfaceRenderer(new ArrayList<>(), - LauncherSettings.Favorites.PREVIEW_CONTENT_URI, query); + loadWorkspace(new ArrayList<>(), query, null); final SparseArray spanInfo = getLoadedLauncherWidgetInfo(previewContext.getBaseContext()); @@ -253,14 +267,6 @@ public class PreviewSurfaceRenderer { } } - @WorkerThread - private boolean doGridMigrationIfNecessary() { - if (!GridSizeMigrationUtil.needsToMigrate(mContext, mIdp)) { - return false; - } - return GridSizeMigrationUtil.migrateGridIfNeeded(mContext, mIdp); - } - @UiThread private void renderView(Context inflationContext, BgDataModel dataModel, Map widgetProviderInfoMap, diff --git a/src/com/android/launcher3/model/DatabaseHelper.java b/src/com/android/launcher3/model/DatabaseHelper.java index dc5fcf7d4b..ecf5f67a97 100644 --- a/src/com/android/launcher3/model/DatabaseHelper.java +++ b/src/com/android/launcher3/model/DatabaseHelper.java @@ -15,8 +15,8 @@ */ package com.android.launcher3.model; +import static com.android.launcher3.LauncherSettings.Favorites.addTableToDb; import static com.android.launcher3.provider.LauncherDbUtils.dropTable; -import static com.android.launcher3.provider.LauncherDbUtils.tableExists; import android.content.ContentValues; import android.content.Context; @@ -36,9 +36,6 @@ import androidx.annotation.NonNull; import com.android.launcher3.AutoInstallsLayout; import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback; -import com.android.launcher3.InvariantDeviceProfile; -import com.android.launcher3.LauncherFiles; -import com.android.launcher3.LauncherPrefs; import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.Utilities; @@ -58,6 +55,7 @@ import java.io.File; import java.net.URISyntaxException; import java.util.Arrays; import java.util.Locale; +import java.util.function.ToLongFunction; import java.util.stream.Collectors; /** @@ -76,45 +74,23 @@ public class DatabaseHelper extends NoLocaleSQLiteHelper implements private static final boolean LOGD = false; private static final String DOWNGRADE_SCHEMA_FILE = "downgrade_schema.json"; - public static final String EMPTY_DATABASE_CREATED = "EMPTY_DATABASE_CREATED"; private final Context mContext; - private final boolean mForMigration; + private final ToLongFunction mUserSerialProvider; + private final Runnable mOnEmptyDbCreateCallback; + private int mMaxItemId = -1; public boolean mHotseatRestoreTableExists; - public static DatabaseHelper createDatabaseHelper(Context context, boolean forMigration) { - return createDatabaseHelper(context, null, forMigration); - } - - public static DatabaseHelper createDatabaseHelper(Context context, String dbName, - boolean forMigration) { - if (dbName == null) { - dbName = InvariantDeviceProfile.INSTANCE.get(context).dbFile; - } - DatabaseHelper databaseHelper = new DatabaseHelper(context, dbName, forMigration); - // Table creation sometimes fails silently, which leads to a crash loop. - // This way, we will try to create a table every time after crash, so the device - // would eventually be able to recover. - if (!tableExists(databaseHelper.getReadableDatabase(), Favorites.TABLE_NAME)) { - Log.e(TAG, "Tables are missing after onCreate has been called. Trying to recreate"); - // This operation is a no-op if the table already exists. - databaseHelper.addFavoritesTable(databaseHelper.getWritableDatabase(), true); - } - databaseHelper.mHotseatRestoreTableExists = tableExists( - databaseHelper.getReadableDatabase(), Favorites.HYBRID_HOTSEAT_BACKUP_TABLE); - - databaseHelper.initIds(); - return databaseHelper; - } - /** * Constructor used in tests and for restore. */ - public DatabaseHelper(Context context, String dbName, boolean forMigration) { + public DatabaseHelper(Context context, String dbName, + ToLongFunction userSerialProvider, Runnable onEmptyDbCreateCallback) { super(context, dbName, SCHEMA_VERSION); mContext = context; - mForMigration = forMigration; + mUserSerialProvider = userSerialProvider; + mOnEmptyDbCreateCallback = onEmptyDbCreateCallback; } protected void initIds() { @@ -131,13 +107,11 @@ public class DatabaseHelper extends NoLocaleSQLiteHelper implements mMaxItemId = 1; - addFavoritesTable(db, false); + addTableToDb(db, getDefaultUserSerial(), false /* optional */); // Fresh and clean launcher DB. mMaxItemId = initializeMaxItemId(db); - if (!mForMigration) { - onEmptyDbCreated(); - } + mOnEmptyDbCreateCallback.run(); } public void onAddOrDeleteOp(SQLiteDatabase db) { @@ -147,38 +121,8 @@ public class DatabaseHelper extends NoLocaleSQLiteHelper implements } } - /** - * Re-composite given key in respect to database. If the current db is - * {@link LauncherFiles#LAUNCHER_DB}, return the key as-is. Otherwise append the db name to - * given key. e.g. consider key="EMPTY_DATABASE_CREATED", dbName="minimal.db", the returning - * string will be "EMPTY_DATABASE_CREATED@minimal.db". - */ - public String getKey(final String key) { - if (TextUtils.equals(getDatabaseName(), LauncherFiles.LAUNCHER_DB)) { - return key; - } - return key + "@" + getDatabaseName(); - } - - /** - * Overridden in tests. - */ - protected void onEmptyDbCreated() { - // Set the flag for empty DB - LauncherPrefs.getPrefs(mContext).edit().putBoolean(getKey(EMPTY_DATABASE_CREATED), true) - .commit(); - } - - public long getSerialNumberForUser(UserHandle user) { - return UserCache.INSTANCE.get(mContext).getSerialNumberForUser(user); - } - - public long getDefaultUserSerial() { - return getSerialNumberForUser(Process.myUserHandle()); - } - - private void addFavoritesTable(SQLiteDatabase db, boolean optional) { - Favorites.addTableToDb(db, getDefaultUserSerial(), optional); + private long getDefaultUserSerial() { + return mUserSerialProvider.applyAsLong(Process.myUserHandle()); } @Override diff --git a/src/com/android/launcher3/model/GridSizeMigrationUtil.java b/src/com/android/launcher3/model/GridSizeMigrationUtil.java index eded5ea6a9..9a6cde63cd 100644 --- a/src/com/android/launcher3/model/GridSizeMigrationUtil.java +++ b/src/com/android/launcher3/model/GridSizeMigrationUtil.java @@ -16,6 +16,9 @@ package com.android.launcher3.model; +import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME; +import static com.android.launcher3.LauncherSettings.Favorites.TMP_TABLE; +import static com.android.launcher3.provider.LauncherDbUtils.copyTable; import static com.android.launcher3.provider.LauncherDbUtils.dropTable; import android.content.ComponentName; @@ -34,16 +37,15 @@ import android.util.Log; import androidx.annotation.NonNull; import com.android.launcher3.InvariantDeviceProfile; -import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; -import com.android.launcher3.graphics.LauncherPreviewRenderer; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.pm.InstallSessionHelper; import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction; import com.android.launcher3.util.GridOccupancy; import com.android.launcher3.util.IntArray; +import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext; import com.android.launcher3.widget.LauncherAppWidgetProviderInfo; import com.android.launcher3.widget.WidgetManagerHelper; @@ -89,81 +91,38 @@ public class GridSizeMigrationUtil { return needsToMigrate; } - /** See {@link #migrateGridIfNeeded(Context, InvariantDeviceProfile)} */ - public static boolean migrateGridIfNeeded(Context context) { - if (context instanceof LauncherPreviewRenderer.PreviewContext) { - return true; - } - return migrateGridIfNeeded(context, null); - } - /** - * When migrating the grid for preview, we copy the table - * {@link LauncherSettings.Favorites#TABLE_NAME} into - * {@link LauncherSettings.Favorites#PREVIEW_TABLE_NAME}, run grid size migration from the - * former to the later, then use the later table for preview. - * - * Similarly when doing the actual grid migration, the former grid option's table - * {@link LauncherSettings.Favorites#TABLE_NAME} is copied into the new grid option's - * {@link LauncherSettings.Favorites#TMP_TABLE}, we then run the grid size migration algorithm + * When migrating the grid, we copy the table + * {@link LauncherSettings.Favorites#TABLE_NAME} from {@code source} into + * {@link LauncherSettings.Favorites#TMP_TABLE}, run the grid size migration algorithm * to migrate the later to the former, and load the workspace from the default * {@link LauncherSettings.Favorites#TABLE_NAME}. * * @return false if the migration failed. */ - public static boolean migrateGridIfNeeded(Context context, InvariantDeviceProfile idp) { - boolean migrateForPreview = idp != null; - if (!migrateForPreview) { - idp = LauncherAppState.getIDP(context); - } + public static boolean migrateGridIfNeeded( + @NonNull Context context, + @NonNull InvariantDeviceProfile idp, + @NonNull DatabaseHelper target, + @NonNull SQLiteDatabase source) { DeviceGridState srcDeviceState = new DeviceGridState(context); DeviceGridState destDeviceState = new DeviceGridState(idp); if (!needsToMigrate(srcDeviceState, destDeviceState)) { return true; } + copyTable(source, TABLE_NAME, target.getWritableDatabase(), TMP_TABLE, context); HashSet validPackages = getValidPackages(context); - - if (migrateForPreview) { - if (!LauncherSettings.Settings.call( - context.getContentResolver(), - LauncherSettings.Settings.METHOD_PREP_FOR_PREVIEW, - destDeviceState.getDbFile()).getBoolean( - LauncherSettings.Settings.EXTRA_VALUE)) { - return false; - } - } else if (!LauncherSettings.Settings.call( - context.getContentResolver(), - LauncherSettings.Settings.METHOD_UPDATE_CURRENT_OPEN_HELPER, - destDeviceState.getDbFile()).getBoolean( - LauncherSettings.Settings.EXTRA_VALUE)) { - return false; - } - long migrationStartTime = System.currentTimeMillis(); - try (SQLiteTransaction t = (SQLiteTransaction) LauncherSettings.Settings.call( - context.getContentResolver(), - LauncherSettings.Settings.METHOD_NEW_TRANSACTION).getBinder( - LauncherSettings.Settings.EXTRA_VALUE)) { - - DbReader srcReader = new DbReader(t.getDb(), - migrateForPreview ? LauncherSettings.Favorites.TABLE_NAME - : LauncherSettings.Favorites.TMP_TABLE, - context, validPackages); - DbReader destReader = new DbReader(t.getDb(), - migrateForPreview ? LauncherSettings.Favorites.PREVIEW_TABLE_NAME - : LauncherSettings.Favorites.TABLE_NAME, - context, validPackages); + try (SQLiteTransaction t = new SQLiteTransaction(target.getWritableDatabase())) { + DbReader srcReader = new DbReader(t.getDb(), TMP_TABLE, context, validPackages); + DbReader destReader = new DbReader(t.getDb(), TABLE_NAME, context, validPackages); Point targetSize = new Point(destDeviceState.getColumns(), destDeviceState.getRows()); - migrate(context, t.getDb(), srcReader, destReader, destDeviceState.getNumHotseat(), + migrate(target, srcReader, destReader, destDeviceState.getNumHotseat(), targetSize, srcDeviceState, destDeviceState); - - if (!migrateForPreview) { - dropTable(t.getDb(), LauncherSettings.Favorites.TMP_TABLE); - } - + dropTable(t.getDb(), TMP_TABLE); t.commit(); return true; } catch (Exception e) { @@ -174,7 +133,7 @@ public class GridSizeMigrationUtil { Log.v(TAG, "Workspace migration completed in " + (System.currentTimeMillis() - migrationStartTime)); - if (!migrateForPreview) { + if (!(context instanceof SandboxContext)) { // Save current configuration, so that the migration does not run again. destDeviceState.writeToPrefs(context); } @@ -182,7 +141,7 @@ public class GridSizeMigrationUtil { } public static boolean migrate( - @NonNull final Context context, @NonNull final SQLiteDatabase db, + @NonNull DatabaseHelper helper, @NonNull final DbReader srcReader, @NonNull final DbReader destReader, final int destHotseatSize, @NonNull final Point targetSize, @NonNull final DeviceGridState srcDeviceState, @@ -234,8 +193,8 @@ public class GridSizeMigrationUtil { Collections.sort(workspaceToBeAdded); // Migrate hotseat - solveHotseatPlacement(db, srcReader, - destReader, context, destHotseatSize, dstHotseatItems, hotseatToBeAdded); + solveHotseatPlacement(helper, destHotseatSize, + srcReader, destReader, dstHotseatItems, hotseatToBeAdded); // Migrate workspace. // First we create a collection of the screens @@ -255,8 +214,8 @@ public class GridSizeMigrationUtil { if (DEBUG) { Log.d(TAG, "Migrating " + screenId); } - solveGridPlacement(db, srcReader, - destReader, context, screenId, trgX, trgY, workspaceToBeAdded, false); + solveGridPlacement(helper, srcReader, + destReader, screenId, trgX, trgY, workspaceToBeAdded, false); if (workspaceToBeAdded.isEmpty()) { break; } @@ -266,8 +225,8 @@ public class GridSizeMigrationUtil { // any of the screens, in this case we add them to new screens until all of them are placed. int screenId = destReader.mLastScreenId + 1; while (!workspaceToBeAdded.isEmpty()) { - solveGridPlacement(db, srcReader, - destReader, context, screenId, trgX, trgY, workspaceToBeAdded, preservePages); + solveGridPlacement(helper, srcReader, + destReader, screenId, trgX, trgY, workspaceToBeAdded, preservePages); screenId++; } @@ -298,33 +257,33 @@ public class GridSizeMigrationUtil { }); } - private static void insertEntryInDb(SQLiteDatabase db, Context context, DbEntry entry, + private static void insertEntryInDb(DatabaseHelper helper, DbEntry entry, String srcTableName, String destTableName) { - int id = copyEntryAndUpdate(db, context, entry, srcTableName, destTableName); + int id = copyEntryAndUpdate(helper, entry, srcTableName, destTableName); if (entry.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) { for (Set itemIds : entry.mFolderItems.values()) { for (int itemId : itemIds) { - copyEntryAndUpdate(db, context, itemId, id, srcTableName, destTableName); + copyEntryAndUpdate(helper, itemId, id, srcTableName, destTableName); } } } } - private static int copyEntryAndUpdate(SQLiteDatabase db, Context context, + private static int copyEntryAndUpdate(DatabaseHelper helper, DbEntry entry, String srcTableName, String destTableName) { - return copyEntryAndUpdate(db, context, entry, -1, -1, srcTableName, destTableName); + return copyEntryAndUpdate(helper, entry, -1, -1, srcTableName, destTableName); } - private static int copyEntryAndUpdate(SQLiteDatabase db, Context context, + private static int copyEntryAndUpdate(DatabaseHelper helper, int id, int folderId, String srcTableName, String destTableName) { - return copyEntryAndUpdate(db, context, null, id, folderId, srcTableName, destTableName); + return copyEntryAndUpdate(helper, null, id, folderId, srcTableName, destTableName); } - private static int copyEntryAndUpdate(SQLiteDatabase db, Context context, - DbEntry entry, int id, int folderId, String srcTableName, String destTableName) { + private static int copyEntryAndUpdate(DatabaseHelper helper, DbEntry entry, + int id, int folderId, String srcTableName, String destTableName) { int newId = -1; - Cursor c = db.query(srcTableName, null, + Cursor c = helper.getWritableDatabase().query(srcTableName, null, LauncherSettings.Favorites._ID + " = '" + (entry != null ? entry.id : id) + "'", null, null, null, null); while (c.moveToNext()) { @@ -335,11 +294,9 @@ public class GridSizeMigrationUtil { } else { values.put(LauncherSettings.Favorites.CONTAINER, folderId); } - newId = LauncherSettings.Settings.call(context.getContentResolver(), - LauncherSettings.Settings.METHOD_NEW_ITEM_ID).getInt( - LauncherSettings.Settings.EXTRA_VALUE); + newId = helper.generateNewItemId(); values.put(LauncherSettings.Favorites._ID, newId); - db.insert(destTableName, null, values); + helper.getWritableDatabase().insert(destTableName, null, values); } c.close(); return newId; @@ -367,9 +324,9 @@ public class GridSizeMigrationUtil { return validPackages; } - private static void solveGridPlacement(@NonNull final SQLiteDatabase db, + private static void solveGridPlacement(@NonNull final DatabaseHelper helper, @NonNull final DbReader srcReader, @NonNull final DbReader destReader, - @NonNull final Context context, final int screenId, final int trgX, final int trgY, + final int screenId, final int trgX, final int trgY, @NonNull final List sortedItemsToPlace, final boolean matchingScreenIdOnly) { final GridOccupancy occupied = new GridOccupancy(trgX, trgY); final Point trg = new Point(trgX, trgY); @@ -391,7 +348,7 @@ public class GridSizeMigrationUtil { continue; } if (findPlacementForEntry(entry, next, trg, occupied, screenId)) { - insertEntryInDb(db, context, entry, srcReader.mTableName, destReader.mTableName); + insertEntryInDb(helper, entry, srcReader.mTableName, destReader.mTableName); iterator.remove(); } } @@ -428,9 +385,9 @@ public class GridSizeMigrationUtil { return false; } - private static void solveHotseatPlacement(@NonNull final SQLiteDatabase db, + private static void solveHotseatPlacement( + @NonNull final DatabaseHelper helper, final int hotseatSize, @NonNull final DbReader srcReader, @NonNull final DbReader destReader, - @NonNull final Context context, final int hotseatSize, @NonNull final List placedHotseatItems, @NonNull final List itemsToPlace) { @@ -447,7 +404,7 @@ public class GridSizeMigrationUtil { // to something other than -1. entry.cellX = i; entry.cellY = 0; - insertEntryInDb(db, context, entry, srcReader.mTableName, destReader.mTableName); + insertEntryInDb(helper, entry, srcReader.mTableName, destReader.mTableName); occupied[entry.screenId] = true; } } diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java index a5dccc1fab..2054d930e6 100644 --- a/src/com/android/launcher3/model/LoaderCursor.java +++ b/src/com/android/launcher3/model/LoaderCursor.java @@ -16,16 +16,16 @@ package com.android.launcher3.model; +import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME; + import android.content.ComponentName; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; -import android.content.pm.PackageManager; import android.database.Cursor; import android.database.CursorWrapper; -import android.net.Uri; import android.os.UserHandle; import android.provider.BaseColumns; import android.text.TextUtils; @@ -66,9 +66,7 @@ public class LoaderCursor extends CursorWrapper { private final LongSparseArray allUsers; private final LauncherAppState mApp; - private final Uri mContentUri; private final Context mContext; - private final PackageManager mPM; private final IconCache mIconCache; private final InvariantDeviceProfile mIDP; @@ -108,17 +106,14 @@ public class LoaderCursor extends CursorWrapper { public int itemType; public int restoreFlag; - public LoaderCursor(Cursor cursor, Uri contentUri, LauncherAppState app, - UserManagerState userManagerState) { + public LoaderCursor(Cursor cursor, LauncherAppState app, UserManagerState userManagerState) { super(cursor); mApp = app; allUsers = userManagerState.allUsers; - mContentUri = contentUri; mContext = app.getContext(); mIconCache = app.getIconCache(); mIDP = app.getInvariantDeviceProfile(); - mPM = mContext.getPackageManager(); // Init column indices mIconIndex = getColumnIndexOrThrow(Favorites.ICON); @@ -390,7 +385,7 @@ public class LoaderCursor extends CursorWrapper { */ public ContentWriter updater() { return new ContentWriter(mContext, new ContentWriter.CommitParams( - mApp.getModel().getModelDbController().getDatabaseHelper(), + mApp.getModel().getModelDbController(), BaseColumns._ID + "= ?", new String[]{Integer.toString(id)})); } @@ -409,8 +404,8 @@ public class LoaderCursor extends CursorWrapper { public boolean commitDeleted() { if (mItemsToRemove.size() > 0) { // Remove dead items - mContext.getContentResolver().delete(mContentUri, Utilities.createDbSelectionQuery( - Favorites._ID, mItemsToRemove), null); + mApp.getModel().getModelDbController().delete(TABLE_NAME, + Utilities.createDbSelectionQuery(Favorites._ID, mItemsToRemove), null); return true; } return false; @@ -435,9 +430,8 @@ public class LoaderCursor extends CursorWrapper { // Update restored items that no longer require special handling ContentValues values = new ContentValues(); values.put(Favorites.RESTORED, 0); - mContext.getContentResolver().update(mContentUri, values, - Utilities.createDbSelectionQuery( - Favorites._ID, mRestoredRows), null); + mApp.getModel().getModelDbController().update(TABLE_NAME, values, + Utilities.createDbSelectionQuery(Favorites._ID, mRestoredRows), null); } } diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index 9053d19f84..d4eded5968 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -16,6 +16,7 @@ package com.android.launcher3.model; +import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME; import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION; import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_CHANGE_PERMISSION; import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED; @@ -41,7 +42,6 @@ import android.content.pm.PackageInstaller.SessionInfo; import android.content.pm.PackageManager; import android.content.pm.ShortcutInfo; import android.graphics.Point; -import android.net.Uri; import android.os.Bundle; import android.os.Trace; import android.os.UserHandle; @@ -50,7 +50,6 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; import android.util.LongSparseArray; -import android.util.TimingLogger; import androidx.annotation.Nullable; @@ -200,25 +199,10 @@ public class LoaderTask implements Runnable { } Object traceToken = TraceHelper.INSTANCE.beginSection(TAG); - TimingLogger timingLogger = new TimingLogger(TAG, "run"); LoaderMemoryLogger memoryLogger = new LoaderMemoryLogger(); try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) { List allShortcuts = new ArrayList<>(); - Trace.beginSection("LoadWorkspace"); - try { - loadWorkspace(allShortcuts, memoryLogger); - } finally { - Trace.endSection(); - } - logASplit(timingLogger, "loadWorkspace"); - - if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) { - verifyNotStopped(); - mModelDelegate.loadAndBindWorkspaceItems(mUserManagerState, - mLauncherBinder.mCallbacksList, mShortcutKeyToPinnedShortcuts); - mModelDelegate.markActive(); - logASplit(timingLogger, "workspaceDelegateItems"); - } + loadWorkspace(allShortcuts, "", memoryLogger); // Sanitize data re-syncs widgets/shortcuts based on the workspace loaded from db. // sanitizeData should not be invoked if the workspace is loaded from a db different @@ -228,21 +212,21 @@ public class LoaderTask implements Runnable { verifyNotStopped(); sanitizeFolders(mItemsDeleted); sanitizeWidgetsShortcutsAndPackages(); - logASplit(timingLogger, "sanitizeData"); + logASplit("sanitizeData"); } verifyNotStopped(); mLauncherBinder.bindWorkspace(true /* incrementBindId */, /* isBindSync= */ false); - logASplit(timingLogger, "bindWorkspace"); + logASplit("bindWorkspace"); mModelDelegate.workspaceLoadComplete(); // Notify the installer packages of packages with active installs on the first screen. sendFirstScreenActiveInstallsBroadcast(); - logASplit(timingLogger, "sendFirstScreenActiveInstallsBroadcast"); + logASplit("sendFirstScreenActiveInstallsBroadcast"); // Take a break waitForIdle(); - logASplit(timingLogger, "step 1 complete"); + logASplit("step 1 complete"); verifyNotStopped(); // second step @@ -253,16 +237,16 @@ public class LoaderTask implements Runnable { } finally { Trace.endSection(); } - logASplit(timingLogger, "loadAllApps"); + logASplit("loadAllApps"); if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) { mModelDelegate.loadAndBindAllAppsItems(mUserManagerState, mLauncherBinder.mCallbacksList, mShortcutKeyToPinnedShortcuts); - logASplit(timingLogger, "allAppsDelegateItems"); + logASplit("allAppsDelegateItems"); } verifyNotStopped(); mLauncherBinder.bindAllApps(); - logASplit(timingLogger, "bindAllApps"); + logASplit("bindAllApps"); verifyNotStopped(); IconCacheUpdateHandler updateHandler = mIconCache.getUpdateHandler(); @@ -270,75 +254,73 @@ public class LoaderTask implements Runnable { updateHandler.updateIcons(allActivityList, LauncherActivityCachingLogic.newInstance(mApp.getContext()), mApp.getModel()::onPackageIconsUpdated); - logASplit(timingLogger, "update icon cache"); + logASplit("update icon cache"); verifyNotStopped(); - logASplit(timingLogger, "save shortcuts in icon cache"); + logASplit("save shortcuts in icon cache"); updateHandler.updateIcons(allShortcuts, new ShortcutCachingLogic(), mApp.getModel()::onPackageIconsUpdated); // Take a break waitForIdle(); - logASplit(timingLogger, "step 2 complete"); + logASplit("step 2 complete"); verifyNotStopped(); // third step List allDeepShortcuts = loadDeepShortcuts(); - logASplit(timingLogger, "loadDeepShortcuts"); + logASplit("loadDeepShortcuts"); verifyNotStopped(); mLauncherBinder.bindDeepShortcuts(); - logASplit(timingLogger, "bindDeepShortcuts"); + logASplit("bindDeepShortcuts"); verifyNotStopped(); - logASplit(timingLogger, "save deep shortcuts in icon cache"); + logASplit("save deep shortcuts in icon cache"); updateHandler.updateIcons(allDeepShortcuts, new ShortcutCachingLogic(), (pkgs, user) -> { }); // Take a break waitForIdle(); - logASplit(timingLogger, "step 3 complete"); + logASplit("step 3 complete"); verifyNotStopped(); // fourth step List allWidgetsList = mBgDataModel.widgetsModel.update(mApp, null); - logASplit(timingLogger, "load widgets"); + logASplit("load widgets"); verifyNotStopped(); mLauncherBinder.bindWidgets(); - logASplit(timingLogger, "bindWidgets"); + logASplit("bindWidgets"); verifyNotStopped(); if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) { mModelDelegate.loadAndBindOtherItems(mLauncherBinder.mCallbacksList); - logASplit(timingLogger, "otherDelegateItems"); + logASplit("otherDelegateItems"); verifyNotStopped(); } updateHandler.updateIcons(allWidgetsList, new ComponentWithIconCachingLogic(mApp.getContext(), true), mApp.getModel()::onWidgetLabelsUpdated); - logASplit(timingLogger, "save widgets in icon cache"); + logASplit("save widgets in icon cache"); // fifth step loadFolderNames(); verifyNotStopped(); updateHandler.finish(); - logASplit(timingLogger, "finish icon update"); + logASplit("finish icon update"); mModelDelegate.modelLoadComplete(); transaction.commit(); memoryLogger.clearLogs(); } catch (CancellationException e) { // Loader stopped, ignore - logASplit(timingLogger, "Cancelled"); + logASplit("Cancelled"); } catch (Exception e) { memoryLogger.printLogs(); throw e; - } finally { - timingLogger.dumpToLog(); } TraceHelper.INSTANCE.endSection(traceToken); } @@ -348,25 +330,29 @@ public class LoaderTask implements Runnable { this.notify(); } - private void loadWorkspace( - List allDeepShortcuts, LoaderMemoryLogger memoryLogger) { - loadWorkspace(allDeepShortcuts, Favorites.CONTENT_URI, - null /* selection */, memoryLogger); - } + protected void loadWorkspace( + List allDeepShortcuts, + String selection, + LoaderMemoryLogger memoryLogger) { + Trace.beginSection("LoadWorkspace"); + try { + loadWorkspaceImpl(allDeepShortcuts, selection, memoryLogger); + } finally { + Trace.endSection(); + } + logASplit("loadWorkspace"); - protected void loadWorkspaceForPreviewSurfaceRenderer( - List allDeepShortcuts, Uri contentUri, String selection) { - loadWorkspace(allDeepShortcuts, contentUri, selection, null); if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) { + verifyNotStopped(); mModelDelegate.loadAndBindWorkspaceItems(mUserManagerState, mLauncherBinder.mCallbacksList, mShortcutKeyToPinnedShortcuts); mModelDelegate.markActive(); + logASplit("workspaceDelegateItems"); } } - protected void loadWorkspace( + private void loadWorkspaceImpl( List allDeepShortcuts, - Uri contentUri, String selection, @Nullable LoaderMemoryLogger memoryLogger) { final Context context = mApp.getContext(); @@ -377,7 +363,7 @@ public class LoaderTask implements Runnable { final WidgetManagerHelper widgetHelper = new WidgetManagerHelper(context); boolean clearDb = false; - if (!GridSizeMigrationUtil.migrateGridIfNeeded(context)) { + if (!mApp.getModel().getModelDbController().migrateGridIfNeeded()) { // Migration failed. Clear workspace. clearDb = true; } @@ -402,8 +388,9 @@ public class LoaderTask implements Runnable { mFirstScreenBroadcast = new FirstScreenBroadcast(installingPkgs); mShortcutKeyToPinnedShortcuts = new HashMap<>(); + ModelDbController dbController = mApp.getModel().getModelDbController(); final LoaderCursor c = new LoaderCursor( - contentResolver.query(contentUri, null, selection, null, null), contentUri, + dbController.query(TABLE_NAME, null, selection, null, null), mApp, mUserManagerState); final Bundle extras = c.getExtras(); mDbName = extras == null ? null : extras.getString(Settings.EXTRA_DB_NAME); @@ -1112,12 +1099,9 @@ public class LoaderTask implements Runnable { FileLog.d(TAG, widgetDimension.toString()); } - private static void logASplit(@Nullable TimingLogger timingLogger, String label) { - if (timingLogger != null) { - timingLogger.addSplit(label); - if (DEBUG) { - Log.d(TAG, label); - } + private static void logASplit(String label) { + if (DEBUG) { + Log.d(TAG, label); } } } diff --git a/src/com/android/launcher3/model/ModelDbController.java b/src/com/android/launcher3/model/ModelDbController.java index 97bce8c25a..f0e5ef6bbd 100644 --- a/src/com/android/launcher3/model/ModelDbController.java +++ b/src/com/android/launcher3/model/ModelDbController.java @@ -19,11 +19,10 @@ import static android.util.Base64.NO_PADDING; import static android.util.Base64.NO_WRAP; import static com.android.launcher3.DefaultLayoutParser.RES_PARTNER_DEFAULT_LAYOUT; +import static com.android.launcher3.LauncherSettings.Favorites.addTableToDb; import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_KEY; import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_LABEL; import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_TAG; -import static com.android.launcher3.model.DatabaseHelper.EMPTY_DATABASE_CREATED; -import static com.android.launcher3.provider.LauncherDbUtils.copyTable; import static com.android.launcher3.provider.LauncherDbUtils.tableExists; import android.app.blob.BlobHandle; @@ -31,7 +30,6 @@ import android.app.blob.BlobStoreManager; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; -import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.ProviderInfo; import android.content.res.Resources; @@ -43,6 +41,7 @@ import android.os.Binder; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.Process; +import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.text.TextUtils; @@ -54,18 +53,22 @@ import androidx.annotation.WorkerThread; import com.android.launcher3.AutoInstallsLayout; import com.android.launcher3.AutoInstallsLayout.SourceResources; +import com.android.launcher3.ConstantItem; import com.android.launcher3.DefaultLayoutParser; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherFiles; import com.android.launcher3.LauncherPrefs; import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.Utilities; +import com.android.launcher3.pm.UserCache; import com.android.launcher3.provider.LauncherDbUtils; import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction; import com.android.launcher3.provider.RestoreDbTask; import com.android.launcher3.util.IOUtils; import com.android.launcher3.util.IntArray; +import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext; import com.android.launcher3.util.Partner; import com.android.launcher3.widget.LauncherWidgetHolder; @@ -73,7 +76,6 @@ import org.xmlpull.v1.XmlPullParser; import java.io.InputStream; import java.io.StringReader; -import java.util.function.Supplier; /** * Utility class which maintains an instance of Launcher database and provides utility methods @@ -82,6 +84,8 @@ import java.util.function.Supplier; public class ModelDbController { private static final String TAG = "LauncherProvider"; + private static final String EMPTY_DATABASE_CREATED = "EMPTY_DATABASE_CREATED"; + protected DatabaseHelper mOpenHelper; private final Context mContext; @@ -92,26 +96,36 @@ public class ModelDbController { private synchronized void createDbIfNotExists() { if (mOpenHelper == null) { - mOpenHelper = DatabaseHelper.createDatabaseHelper( - mContext, false /* forMigration */); - - RestoreDbTask.restoreIfNeeded(mContext, mOpenHelper); + mOpenHelper = createDatabaseHelper(false /* forMigration */); + RestoreDbTask.restoreIfNeeded(mContext, this); } } - private synchronized boolean prepForMigration(String dbFile, String targetTableName, - Supplier src, Supplier dst) { - if (TextUtils.equals(dbFile, mOpenHelper.getDatabaseName())) { - Log.e(TAG, "prepForMigration - target db is same as current: " + dbFile); - return false; - } + protected DatabaseHelper createDatabaseHelper(boolean forMigration) { + boolean isSandbox = mContext instanceof SandboxContext; + String dbName = isSandbox ? null : InvariantDeviceProfile.INSTANCE.get(mContext).dbFile; - final DatabaseHelper helper = src.get(); - mOpenHelper = dst.get(); - copyTable(helper.getReadableDatabase(), Favorites.TABLE_NAME, - mOpenHelper.getWritableDatabase(), targetTableName, mContext); - helper.close(); - return true; + // Set the flag for empty DB + Runnable onEmptyDbCreateCallback = forMigration ? () -> { } + : () -> LauncherPrefs.get(mContext).putSync(getEmptyDbCreatedKey(dbName).to(true)); + + DatabaseHelper databaseHelper = new DatabaseHelper(mContext, dbName, + this::getSerialNumberForUser, onEmptyDbCreateCallback); + // Table creation sometimes fails silently, which leads to a crash loop. + // This way, we will try to create a table every time after crash, so the device + // would eventually be able to recover. + if (!tableExists(databaseHelper.getReadableDatabase(), Favorites.TABLE_NAME)) { + Log.e(TAG, "Tables are missing after onCreate has been called. Trying to recreate"); + // This operation is a no-op if the table already exists. + addTableToDb(databaseHelper.getWritableDatabase(), + getSerialNumberForUser(Process.myUserHandle()), + true /* optional */); + } + databaseHelper.mHotseatRestoreTableExists = tableExists( + databaseHelper.getReadableDatabase(), Favorites.HYBRID_HOTSEAT_BACKUP_TABLE); + + databaseHelper.initIds(); + return databaseHelper; } /** @@ -267,42 +281,41 @@ public class ModelDbController { } /** - * Updates the current DB and copies all the existing data to the temp table - * @param dbFile name of the target db file name + * Migrates the DB if needed, and returns false if the migration failed + * and DB needs to be cleared. + * @return true if migration was success or ignored, false if migration failed + * and the DB should be reset. */ - @WorkerThread - public boolean updateCurrentOpenHelper(String dbFile) { + public boolean migrateGridIfNeeded() { createDbIfNotExists(); - return prepForMigration( - dbFile, - Favorites.TMP_TABLE, - () -> mOpenHelper, - () -> DatabaseHelper.createDatabaseHelper( - mContext, true /* forMigration */)); + InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext); + if (!GridSizeMigrationUtil.needsToMigrate(mContext, idp)) { + return true; + } + String targetDbName = new DeviceGridState(idp).getDbFile(); + if (TextUtils.equals(targetDbName, mOpenHelper.getDatabaseName())) { + Log.e(TAG, "migrateGridIfNeeded - target db is same as current: " + targetDbName); + return false; + } + DatabaseHelper oldHelper = mOpenHelper; + mOpenHelper = (mContext instanceof SandboxContext) ? oldHelper + : createDatabaseHelper(true /* forMigration */); + try { + return GridSizeMigrationUtil.migrateGridIfNeeded(mContext, idp, mOpenHelper, + oldHelper.getWritableDatabase()); + } finally { + if (mOpenHelper != oldHelper) { + oldHelper.close(); + } + } } /** - * Returns the current DatabaseHelper. - * Only for tests + * Returns the underlying model database */ - @WorkerThread - public DatabaseHelper getDatabaseHelper() { + public SQLiteDatabase getDb() { createDbIfNotExists(); - return mOpenHelper; - } - - /** - * Prepares the DB for preview by copying all existing data to preview table - */ - @WorkerThread - public boolean prepareForPreview(String dbFile) { - createDbIfNotExists(); - return prepForMigration( - dbFile, - Favorites.PREVIEW_TABLE_NAME, - () -> DatabaseHelper.createDatabaseHelper( - mContext, dbFile, true /* forMigration */), - () -> mOpenHelper); + return mOpenHelper.getWritableDatabase(); } private void onAddOrDeleteOp(SQLiteDatabase db) { @@ -345,8 +358,7 @@ public class ModelDbController { } private void clearFlagEmptyDbCreated() { - LauncherPrefs.getPrefs(mContext).edit() - .remove(mOpenHelper.getKey(EMPTY_DATABASE_CREATED)).commit(); + LauncherPrefs.get(mContext).removeSync(getEmptyDbCreatedKey(mOpenHelper.getDatabaseName())); } /** @@ -359,9 +371,8 @@ public class ModelDbController { @WorkerThread public synchronized void loadDefaultFavoritesIfNecessary() { createDbIfNotExists(); - SharedPreferences sp = LauncherPrefs.getPrefs(mContext); - if (sp.getBoolean(mOpenHelper.getKey(EMPTY_DATABASE_CREATED), false)) { + if (LauncherPrefs.get(mContext).get(getEmptyDbCreatedKey(mOpenHelper.getDatabaseName()))) { Log.d(TAG, "loading default workspace"); LauncherWidgetHolder widgetHolder = mOpenHelper.newLauncherWidgetHolder(); @@ -479,4 +490,27 @@ public class ModelDbController { return new DefaultLayoutParser(mContext, widgetHolder, mOpenHelper, mContext.getResources(), defaultLayout); } + + /** + * Re-composite given key in respect to database. If the current db is + * {@link LauncherFiles#LAUNCHER_DB}, return the key as-is. Otherwise append the db name to + * given key. e.g. consider key="EMPTY_DATABASE_CREATED", dbName="minimal.db", the returning + * string will be "EMPTY_DATABASE_CREATED@minimal.db". + */ + private ConstantItem getEmptyDbCreatedKey(String dbName) { + if (mContext instanceof SandboxContext) { + return LauncherPrefs.nonRestorableItem(EMPTY_DATABASE_CREATED, + false /* default value */, false /* boot aware */); + } + String key = TextUtils.equals(dbName, LauncherFiles.LAUNCHER_DB) + ? EMPTY_DATABASE_CREATED : EMPTY_DATABASE_CREATED + "@" + dbName; + return LauncherPrefs.backedUpItem(key, false /* default value */, false /* boot aware */); + } + + /** + * Returns the serial number for the provided user + */ + public long getSerialNumberForUser(UserHandle user) { + return UserCache.INSTANCE.get(mContext).getSerialNumberForUser(user); + } } diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.java b/src/com/android/launcher3/provider/LauncherDbUtils.java index 48969fc44e..c718dcc877 100644 --- a/src/com/android/launcher3/provider/LauncherDbUtils.java +++ b/src/com/android/launcher3/provider/LauncherDbUtils.java @@ -101,7 +101,7 @@ public class LauncherDbUtils { UserManagerState ums = new UserManagerState(); ums.init(UserCache.INSTANCE.get(context), context.getSystemService(UserManager.class)); - LoaderCursor lc = new LoaderCursor(c, null, LauncherAppState.getInstance(context), ums); + LoaderCursor lc = new LoaderCursor(c, LauncherAppState.getInstance(context), ums); IntSet deletedShortcuts = new IntSet(); while (lc.moveToNext()) { diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java index ac7216449b..a6e064a4ed 100644 --- a/src/com/android/launcher3/provider/RestoreDbTask.java +++ b/src/com/android/launcher3/provider/RestoreDbTask.java @@ -16,6 +16,8 @@ package com.android.launcher3.provider; +import static android.os.Process.myUserHandle; + import static com.android.launcher3.InvariantDeviceProfile.TYPE_MULTI_DISPLAY; import static com.android.launcher3.LauncherPrefs.APP_WIDGET_IDS; import static com.android.launcher3.LauncherPrefs.OLD_APP_WIDGET_IDS; @@ -47,8 +49,8 @@ import com.android.launcher3.LauncherPrefs; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.Utilities; import com.android.launcher3.logging.FileLog; -import com.android.launcher3.model.DatabaseHelper; import com.android.launcher3.model.DeviceGridState; +import com.android.launcher3.model.ModelDbController; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.LauncherAppWidgetInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; @@ -83,12 +85,12 @@ public class RestoreDbTask { /** * Tries to restore the backup DB if needed */ - public static void restoreIfNeeded(Context context, DatabaseHelper helper) { + public static void restoreIfNeeded(Context context, ModelDbController dbController) { if (!isPending(context)) { return; } - if (!performRestore(context, helper)) { - helper.createEmptyDB(helper.getWritableDatabase()); + if (!performRestore(context, dbController)) { + dbController.createEmptyDB(); } // Obtain InvariantDeviceProfile first before setting pending to false, so @@ -102,12 +104,12 @@ public class RestoreDbTask { idp.reinitializeAfterRestore(context); } - private static boolean performRestore(Context context, DatabaseHelper helper) { - SQLiteDatabase db = helper.getWritableDatabase(); + private static boolean performRestore(Context context, ModelDbController controller) { + SQLiteDatabase db = controller.getDb(); try (SQLiteTransaction t = new SQLiteTransaction(db)) { RestoreDbTask task = new RestoreDbTask(); - task.sanitizeDB(context, helper, db, new BackupManager(context)); - task.restoreAppWidgetIdsIfExists(context, helper); + task.sanitizeDB(context, controller, db, new BackupManager(context)); + task.restoreAppWidgetIdsIfExists(context, controller); t.commit(); return true; } catch (Exception e) { @@ -129,10 +131,10 @@ public class RestoreDbTask { * @return number of items deleted. */ @VisibleForTesting - protected int sanitizeDB(Context context, DatabaseHelper helper, SQLiteDatabase db, + protected int sanitizeDB(Context context, ModelDbController controller, SQLiteDatabase db, BackupManager backupManager) throws Exception { // Primary user ids - long myProfileId = helper.getDefaultUserSerial(); + long myProfileId = controller.getSerialNumberForUser(myUserHandle()); long oldProfileId = getDefaultProfileId(db); LongSparseArray oldManagedProfileIds = getManagedProfileIds(db, oldProfileId); LongSparseArray profileMapping = new LongSparseArray<>(oldManagedProfileIds.size() @@ -144,7 +146,7 @@ public class RestoreDbTask { long oldManagedProfileId = oldManagedProfileIds.keyAt(i); UserHandle user = getUserForAncestralSerialNumber(backupManager, oldManagedProfileId); if (user != null) { - long newManagedProfileId = helper.getSerialNumberForUser(user); + long newManagedProfileId = controller.getSerialNumberForUser(user); profileMapping.put(oldManagedProfileId, newManagedProfileId); } } @@ -213,7 +215,7 @@ public class RestoreDbTask { } // Override shortcuts - maybeOverrideShortcuts(context, helper, db, myProfileId); + maybeOverrideShortcuts(context, controller, db, myProfileId); return itemsDeleted; } @@ -321,11 +323,11 @@ public class RestoreDbTask { .putSync(RESTORE_DEVICE.to(new DeviceGridState(context).getDeviceType())); } - private void restoreAppWidgetIdsIfExists(Context context, DatabaseHelper helper) { + private void restoreAppWidgetIdsIfExists(Context context, ModelDbController controller) { LauncherPrefs lp = LauncherPrefs.get(context); if (lp.has(APP_WIDGET_IDS, OLD_APP_WIDGET_IDS)) { AppWidgetHost host = new AppWidgetHost(context, APPWIDGET_HOST_ID); - AppWidgetsRestoredReceiver.restoreAppWidgetIds(context, helper, + AppWidgetsRestoredReceiver.restoreAppWidgetIds(context, controller, IntArray.fromConcatString(lp.get(OLD_APP_WIDGET_IDS)).toArray(), IntArray.fromConcatString(lp.get(APP_WIDGET_IDS)).toArray(), host); @@ -343,7 +345,7 @@ public class RestoreDbTask { APP_WIDGET_IDS.to(IntArray.wrap(newIds).toConcatString())); } - protected static void maybeOverrideShortcuts(Context context, DatabaseHelper helper, + protected static void maybeOverrideShortcuts(Context context, ModelDbController controller, SQLiteDatabase db, long currentUser) { Map activityOverrides = ApiWrapper.getActivityOverrides( context); @@ -367,7 +369,7 @@ public class RestoreDbTask { if (override != null) { ContentValues values = new ContentValues(); values.put(Favorites.PROFILE_ID, - helper.getSerialNumberForUser(override.getUser())); + controller.getSerialNumberForUser(override.getUser())); values.put(Favorites.INTENT, AppInfo.makeLaunchIntent(override).toUri(0)); db.update(Favorites.TABLE_NAME, values, String.format("%s=?", Favorites._ID), new String[]{String.valueOf(c.getInt(idIndex))}); diff --git a/src/com/android/launcher3/util/ContentWriter.java b/src/com/android/launcher3/util/ContentWriter.java index e509235688..7c5ef4db0c 100644 --- a/src/com/android/launcher3/util/ContentWriter.java +++ b/src/com/android/launcher3/util/ContentWriter.java @@ -26,7 +26,7 @@ import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.icons.GraphicsUtils; -import com.android.launcher3.model.DatabaseHelper; +import com.android.launcher3.model.ModelDbController; import com.android.launcher3.pm.UserCache; /** @@ -106,7 +106,7 @@ public class ContentWriter { public int commit() { if (mCommitParams != null) { - mCommitParams.mDatabaseHelper.getWritableDatabase().update( + mCommitParams.mDbController.update( Favorites.TABLE_NAME, getValues(mContext), mCommitParams.mWhere, mCommitParams.mSelectionArgs); } @@ -115,12 +115,12 @@ public class ContentWriter { public static final class CommitParams { - final DatabaseHelper mDatabaseHelper; + final ModelDbController mDbController; final String mWhere; final String[] mSelectionArgs; - public CommitParams(DatabaseHelper helper, String where, String[] selectionArgs) { - mDatabaseHelper = helper; + public CommitParams(ModelDbController controller, String where, String[] selectionArgs) { + mDbController = controller; mWhere = where; mSelectionArgs = selectionArgs; } diff --git a/tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java b/tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java index 0a1a9ba6a9..cea95e5a50 100644 --- a/tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java +++ b/tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java @@ -39,6 +39,7 @@ import androidx.test.platform.app.InstrumentationRegistry; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.R; +import com.android.launcher3.pm.UserCache; import org.junit.Before; import org.junit.Test; @@ -222,7 +223,9 @@ public class DbDowngradeHelperTest { private class MyDatabaseHelper extends DatabaseHelper { MyDatabaseHelper() { - super(mContext, DB_FILE, false); + super(mContext, DB_FILE, + UserCache.INSTANCE.get(mContext)::getSerialNumberForUser, + () -> { }); } @Override diff --git a/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt b/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt index f24f0dab76..63dbaa752d 100644 --- a/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt +++ b/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt @@ -15,6 +15,7 @@ */ package com.android.launcher3.model +import android.content.ContentValues import android.content.Context import android.content.Intent import android.database.Cursor @@ -23,6 +24,7 @@ import android.graphics.Point import android.os.Process import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest +import androidx.test.platform.app.InstrumentationRegistry import com.android.launcher3.InvariantDeviceProfile import com.android.launcher3.LauncherPrefs import com.android.launcher3.LauncherPrefs.Companion.WORKSPACE_SIZE @@ -31,10 +33,7 @@ import com.android.launcher3.config.FeatureFlags import com.android.launcher3.model.GridSizeMigrationUtil.DbReader import com.android.launcher3.pm.UserCache import com.android.launcher3.provider.LauncherDbUtils -import com.android.launcher3.util.LauncherModelHelper -import com.android.launcher3.util.LauncherModelHelper.* import com.google.common.truth.Truth.assertThat -import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -43,11 +42,12 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class GridSizeMigrationUtilTest { - private lateinit var modelHelper: LauncherModelHelper + private lateinit var context: Context - private lateinit var db: SQLiteDatabase private lateinit var validPackages: Set private lateinit var idp: InvariantDeviceProfile + private lateinit var dbHelper: DatabaseHelper + private lateinit var db: SQLiteDatabase private val testPackage1 = "com.android.launcher3.validpackage1" private val testPackage2 = "com.android.launcher3.validpackage2" private val testPackage3 = "com.android.launcher3.validpackage3" @@ -61,13 +61,17 @@ class GridSizeMigrationUtilTest { @Before fun setUp() { - modelHelper = LauncherModelHelper() - context = modelHelper.sandboxContext - db = modelHelper.provider.db + context = InstrumentationRegistry.getInstrumentation().targetContext + dbHelper = + DatabaseHelper( + context, + null, + UserCache.INSTANCE.get(context)::getSerialNumberForUser + ) {} + db = dbHelper.writableDatabase validPackages = setOf( - TEST_PACKAGE, testPackage1, testPackage2, testPackage3, @@ -86,11 +90,6 @@ class GridSizeMigrationUtilTest { addTableToDb(db, userSerial, false, TMP_TABLE) } - @After - fun tearDown() { - modelHelper.destroy() - } - /** * Old migration logic, should be modified once [FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC] is not * needed anymore @@ -99,26 +98,26 @@ class GridSizeMigrationUtilTest { @Throws(Exception::class) fun testMigration() { // Src Hotseat icons - modelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI) - modelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI) - modelHelper.addItem(SHORTCUT, 3, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI) - modelHelper.addItem(APP_ICON, 4, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI) + addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_HOTSEAT, 0, 0, testPackage1, 1, TMP_TABLE) + addItem(ITEM_TYPE_SHORTCUT, 1, CONTAINER_HOTSEAT, 0, 0, testPackage2, 2, TMP_TABLE) + addItem(ITEM_TYPE_SHORTCUT, 3, CONTAINER_HOTSEAT, 0, 0, testPackage3, 3, TMP_TABLE) + addItem(ITEM_TYPE_APPLICATION, 4, CONTAINER_HOTSEAT, 0, 0, testPackage4, 4, TMP_TABLE) // Src grid icons // _ _ _ _ _ // _ _ _ _ 5 // _ _ 6 _ 7 // _ _ 8 _ 9 // _ _ _ _ _ - modelHelper.addItem(APP_ICON, 0, DESKTOP, 4, 1, testPackage5, 5, TMP_CONTENT_URI) - modelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 2, testPackage6, 6, TMP_CONTENT_URI) - modelHelper.addItem(APP_ICON, 0, DESKTOP, 4, 2, testPackage7, 7, TMP_CONTENT_URI) - modelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 3, testPackage8, 8, TMP_CONTENT_URI) - modelHelper.addItem(APP_ICON, 0, DESKTOP, 4, 3, testPackage9, 9, TMP_CONTENT_URI) + addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 4, 1, testPackage5, 5, TMP_TABLE) + addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 2, testPackage6, 6, TMP_TABLE) + addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 4, 2, testPackage7, 7, TMP_TABLE) + addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 3, testPackage8, 8, TMP_TABLE) + addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 4, 3, testPackage9, 9, TMP_TABLE) // Dest hotseat icons - modelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2) + addItem(ITEM_TYPE_SHORTCUT, 1, CONTAINER_HOTSEAT, 0, 0, testPackage2) // Dest grid icons - modelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 2, testPackage10) + addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 2, testPackage10) idp.numDatabaseHotseatIcons = 4 idp.numColumns = 4 @@ -126,8 +125,7 @@ class GridSizeMigrationUtilTest { val srcReader = DbReader(db, TMP_TABLE, context, validPackages) val destReader = DbReader(db, TABLE_NAME, context, validPackages) GridSizeMigrationUtil.migrate( - context, - db, + dbHelper, srcReader, destReader, idp.numDatabaseHotseatIcons, @@ -138,12 +136,13 @@ class GridSizeMigrationUtilTest { // Check hotseat items var c = - context.contentResolver.query( - CONTENT_URI, + db.query( + TABLE_NAME, arrayOf(SCREEN, INTENT), "container=$CONTAINER_HOTSEAT", null, SCREEN, + null, null ) ?: throw IllegalStateException() @@ -168,12 +167,13 @@ class GridSizeMigrationUtilTest { // Check workspace items c = - context.contentResolver.query( - CONTENT_URI, + db.query( + TABLE_NAME, arrayOf(CELLX, CELLY, INTENT), "container=$CONTAINER_DESKTOP", null, null, + null, null ) ?: throw IllegalStateException() @@ -209,30 +209,30 @@ class GridSizeMigrationUtilTest { fun testMigrationBackAndForth() { // Hotseat items in grid A // 1 2 _ 3 4 - modelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI) - modelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI) - modelHelper.addItem(SHORTCUT, 3, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI) - modelHelper.addItem(APP_ICON, 4, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI) + addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_HOTSEAT, 0, 0, testPackage1, 1, TMP_TABLE) + addItem(ITEM_TYPE_SHORTCUT, 1, CONTAINER_HOTSEAT, 0, 0, testPackage2, 2, TMP_TABLE) + addItem(ITEM_TYPE_SHORTCUT, 3, CONTAINER_HOTSEAT, 0, 0, testPackage3, 3, TMP_TABLE) + addItem(ITEM_TYPE_APPLICATION, 4, CONTAINER_HOTSEAT, 0, 0, testPackage4, 4, TMP_TABLE) // Workspace items in grid A // _ _ _ _ _ // _ _ _ _ 5 // _ _ 6 _ 7 // _ _ 8 _ _ // _ _ _ _ _ - modelHelper.addItem(APP_ICON, 0, DESKTOP, 4, 1, testPackage5, 5, TMP_CONTENT_URI) - modelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 2, testPackage6, 6, TMP_CONTENT_URI) - modelHelper.addItem(APP_ICON, 0, DESKTOP, 4, 2, testPackage7, 7, TMP_CONTENT_URI) - modelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 3, testPackage8, 8, TMP_CONTENT_URI) + addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 4, 1, testPackage5, 5, TMP_TABLE) + addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 2, testPackage6, 6, TMP_TABLE) + addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 4, 2, testPackage7, 7, TMP_TABLE) + addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 3, testPackage8, 8, TMP_TABLE) // Hotseat items in grid B // 2 _ _ _ - modelHelper.addItem(SHORTCUT, 0, HOTSEAT, 0, 0, testPackage2) + addItem(ITEM_TYPE_SHORTCUT, 0, CONTAINER_HOTSEAT, 0, 0, testPackage2) // Workspace items in grid B // _ _ _ _ // _ _ _ 10 // _ _ _ _ // _ _ _ _ - modelHelper.addItem(APP_ICON, 0, DESKTOP, 1, 3, testPackage10) + addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 1, 3, testPackage10) idp.numDatabaseHotseatIcons = 4 idp.numColumns = 4 @@ -241,8 +241,7 @@ class GridSizeMigrationUtilTest { val readerGridB = DbReader(db, TABLE_NAME, context, validPackages) // migrate from A -> B GridSizeMigrationUtil.migrate( - context, - db, + dbHelper, readerGridA, readerGridB, idp.numDatabaseHotseatIcons, @@ -253,12 +252,13 @@ class GridSizeMigrationUtilTest { // Check hotseat items in grid B var c = - context.contentResolver.query( - CONTENT_URI, + db.query( + TABLE_NAME, arrayOf(SCREEN, INTENT), "container=$CONTAINER_HOTSEAT", null, SCREEN, + null, null ) ?: throw IllegalStateException() @@ -272,12 +272,13 @@ class GridSizeMigrationUtilTest { // Check workspace items in grid B c = - context.contentResolver.query( - CONTENT_URI, + db.query( + TABLE_NAME, arrayOf(SCREEN, CELLX, CELLY, INTENT), "container=$CONTAINER_DESKTOP", null, null, + null, null ) ?: throw IllegalStateException() @@ -294,12 +295,11 @@ class GridSizeMigrationUtilTest { assertThat(locMap[testPackage8]).isEqualTo(Triple(0, 3, 1)) // add item in B - modelHelper.addItem(APP_ICON, 0, DESKTOP, 0, 2, testPackage9) + addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 0, 2, testPackage9) // migrate from B -> A GridSizeMigrationUtil.migrate( - context, - db, + dbHelper, readerGridB, readerGridA, 5, @@ -309,12 +309,13 @@ class GridSizeMigrationUtilTest { ) // Check hotseat items in grid A c = - context.contentResolver.query( - TMP_CONTENT_URI, + db.query( + TMP_TABLE, arrayOf(SCREEN, INTENT), "container=$CONTAINER_HOTSEAT", null, SCREEN, + null, null ) ?: throw IllegalStateException() @@ -328,12 +329,13 @@ class GridSizeMigrationUtilTest { // Check workspace items in grid A c = - context.contentResolver.query( - TMP_CONTENT_URI, + db.query( + TMP_TABLE, arrayOf(SCREEN, CELLX, CELLY, INTENT), "container=$CONTAINER_DESKTOP", null, null, + null, null ) ?: throw IllegalStateException() @@ -354,12 +356,11 @@ class GridSizeMigrationUtilTest { assertThat(locMap[testPackage9]).isEqualTo(Triple(0, 0, 2)) // remove item from B - modelHelper.deleteItem(7, TMP_TABLE) + db.delete(TMP_TABLE, "$_ID=7", null) // migrate from A -> B GridSizeMigrationUtil.migrate( - context, - db, + dbHelper, readerGridA, readerGridB, idp.numDatabaseHotseatIcons, @@ -370,12 +371,13 @@ class GridSizeMigrationUtilTest { // Check hotseat items in grid B c = - context.contentResolver.query( - CONTENT_URI, + db.query( + TABLE_NAME, arrayOf(SCREEN, INTENT), "container=$CONTAINER_HOTSEAT", null, SCREEN, + null, null ) ?: throw IllegalStateException() @@ -389,12 +391,13 @@ class GridSizeMigrationUtilTest { // Check workspace items in grid B c = - context.contentResolver.query( - CONTENT_URI, + db.query( + TABLE_NAME, arrayOf(SCREEN, CELLX, CELLY, INTENT), "container=$CONTAINER_DESKTOP", null, null, + null, null ) ?: throw IllegalStateException() @@ -443,10 +446,28 @@ class GridSizeMigrationUtilTest { fun migrateToLargerHotseat() { val srcHotseatItems = intArrayOf( - modelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI), - modelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI), - modelHelper.addItem(APP_ICON, 2, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI), - modelHelper.addItem(SHORTCUT, 3, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI) + addItem( + ITEM_TYPE_APPLICATION, + 0, + CONTAINER_HOTSEAT, + 0, + 0, + testPackage1, + 1, + TMP_TABLE + ), + addItem(ITEM_TYPE_SHORTCUT, 1, CONTAINER_HOTSEAT, 0, 0, testPackage2, 2, TMP_TABLE), + addItem( + ITEM_TYPE_APPLICATION, + 2, + CONTAINER_HOTSEAT, + 0, + 0, + testPackage3, + 3, + TMP_TABLE + ), + addItem(ITEM_TYPE_SHORTCUT, 3, CONTAINER_HOTSEAT, 0, 0, testPackage4, 4, TMP_TABLE) ) val numSrcDatabaseHotseatIcons = srcHotseatItems.size idp.numDatabaseHotseatIcons = 6 @@ -455,8 +476,7 @@ class GridSizeMigrationUtilTest { val srcReader = DbReader(db, TMP_TABLE, context, validPackages) val destReader = DbReader(db, TABLE_NAME, context, validPackages) GridSizeMigrationUtil.migrate( - context, - db, + dbHelper, srcReader, destReader, idp.numDatabaseHotseatIcons, @@ -467,12 +487,13 @@ class GridSizeMigrationUtilTest { // Check hotseat items val c = - context.contentResolver.query( - CONTENT_URI, + db.query( + TABLE_NAME, arrayOf(SCREEN, INTENT), "container=$CONTAINER_HOTSEAT", null, SCREEN, + null, null ) ?: throw IllegalStateException() @@ -501,11 +522,11 @@ class GridSizeMigrationUtilTest { @Test fun migrateFromLargerHotseat() { - modelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI) - modelHelper.addItem(SHORTCUT, 2, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI) - modelHelper.addItem(APP_ICON, 3, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI) - modelHelper.addItem(SHORTCUT, 4, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI) - modelHelper.addItem(APP_ICON, 5, HOTSEAT, 0, 0, testPackage5, 5, TMP_CONTENT_URI) + addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_HOTSEAT, 0, 0, testPackage1, 1, TMP_TABLE) + addItem(ITEM_TYPE_SHORTCUT, 2, CONTAINER_HOTSEAT, 0, 0, testPackage2, 2, TMP_TABLE) + addItem(ITEM_TYPE_APPLICATION, 3, CONTAINER_HOTSEAT, 0, 0, testPackage3, 3, TMP_TABLE) + addItem(ITEM_TYPE_SHORTCUT, 4, CONTAINER_HOTSEAT, 0, 0, testPackage4, 4, TMP_TABLE) + addItem(ITEM_TYPE_APPLICATION, 5, CONTAINER_HOTSEAT, 0, 0, testPackage5, 5, TMP_TABLE) idp.numDatabaseHotseatIcons = 4 idp.numColumns = 4 @@ -513,8 +534,7 @@ class GridSizeMigrationUtilTest { val srcReader = DbReader(db, TMP_TABLE, context, validPackages) val destReader = DbReader(db, TABLE_NAME, context, validPackages) GridSizeMigrationUtil.migrate( - context, - db, + dbHelper, srcReader, destReader, idp.numDatabaseHotseatIcons, @@ -525,12 +545,13 @@ class GridSizeMigrationUtilTest { // Check hotseat items val c = - context.contentResolver.query( - CONTENT_URI, + db.query( + TABLE_NAME, arrayOf(SCREEN, INTENT), "container=$CONTAINER_HOTSEAT", null, SCREEN, + null, null ) ?: throw IllegalStateException() @@ -568,11 +589,11 @@ class GridSizeMigrationUtilTest { enableNewMigrationLogic("4,4") // Setup src grid - modelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 2, testPackage1, 5, TMP_CONTENT_URI) - modelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 3, testPackage2, 6, TMP_CONTENT_URI) - modelHelper.addItem(APP_ICON, 1, DESKTOP, 3, 1, testPackage3, 7, TMP_CONTENT_URI) - modelHelper.addItem(APP_ICON, 1, DESKTOP, 3, 2, testPackage4, 8, TMP_CONTENT_URI) - modelHelper.addItem(APP_ICON, 2, DESKTOP, 3, 3, testPackage5, 9, TMP_CONTENT_URI) + addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 2, testPackage1, 5, TMP_TABLE) + addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 3, testPackage2, 6, TMP_TABLE) + addItem(ITEM_TYPE_APPLICATION, 1, CONTAINER_DESKTOP, 3, 1, testPackage3, 7, TMP_TABLE) + addItem(ITEM_TYPE_APPLICATION, 1, CONTAINER_DESKTOP, 3, 2, testPackage4, 8, TMP_TABLE) + addItem(ITEM_TYPE_APPLICATION, 2, CONTAINER_DESKTOP, 3, 3, testPackage5, 9, TMP_TABLE) idp.numDatabaseHotseatIcons = 4 idp.numColumns = 6 @@ -581,8 +602,7 @@ class GridSizeMigrationUtilTest { val srcReader = DbReader(db, TMP_TABLE, context, validPackages) val destReader = DbReader(db, TABLE_NAME, context, validPackages) GridSizeMigrationUtil.migrate( - context, - db, + dbHelper, srcReader, destReader, idp.numDatabaseHotseatIcons, @@ -593,12 +613,13 @@ class GridSizeMigrationUtilTest { // Get workspace items val c = - context.contentResolver.query( - CONTENT_URI, + db.query( + TABLE_NAME, arrayOf(INTENT, SCREEN), "container=$CONTAINER_DESKTOP", null, null, + null, null ) ?: throw IllegalStateException() @@ -630,11 +651,11 @@ class GridSizeMigrationUtilTest { enableNewMigrationLogic("2,2") // Setup src grid - modelHelper.addItem(APP_ICON, 0, DESKTOP, 0, 1, testPackage1, 5, TMP_CONTENT_URI) - modelHelper.addItem(APP_ICON, 0, DESKTOP, 1, 1, testPackage2, 6, TMP_CONTENT_URI) - modelHelper.addItem(APP_ICON, 1, DESKTOP, 0, 0, testPackage3, 7, TMP_CONTENT_URI) - modelHelper.addItem(APP_ICON, 1, DESKTOP, 1, 0, testPackage4, 8, TMP_CONTENT_URI) - modelHelper.addItem(APP_ICON, 2, DESKTOP, 0, 0, testPackage5, 9, TMP_CONTENT_URI) + addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 0, 1, testPackage1, 5, TMP_TABLE) + addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 1, 1, testPackage2, 6, TMP_TABLE) + addItem(ITEM_TYPE_APPLICATION, 1, CONTAINER_DESKTOP, 0, 0, testPackage3, 7, TMP_TABLE) + addItem(ITEM_TYPE_APPLICATION, 1, CONTAINER_DESKTOP, 1, 0, testPackage4, 8, TMP_TABLE) + addItem(ITEM_TYPE_APPLICATION, 2, CONTAINER_DESKTOP, 0, 0, testPackage5, 9, TMP_TABLE) idp.numDatabaseHotseatIcons = 4 idp.numColumns = 5 @@ -642,8 +663,7 @@ class GridSizeMigrationUtilTest { val srcReader = DbReader(db, TMP_TABLE, context, validPackages) val destReader = DbReader(db, TABLE_NAME, context, validPackages) GridSizeMigrationUtil.migrate( - context, - db, + dbHelper, srcReader, destReader, idp.numDatabaseHotseatIcons, @@ -654,12 +674,13 @@ class GridSizeMigrationUtilTest { // Get workspace items val c = - context.contentResolver.query( - CONTENT_URI, + db.query( + TABLE_NAME, arrayOf(INTENT, SCREEN), "container=$CONTAINER_DESKTOP", null, null, + null, null ) ?: throw IllegalStateException() @@ -691,11 +712,11 @@ class GridSizeMigrationUtilTest { enableNewMigrationLogic("5,5") // Setup src grid - modelHelper.addItem(APP_ICON, 0, DESKTOP, 0, 1, testPackage1, 5, TMP_CONTENT_URI) - modelHelper.addItem(APP_ICON, 0, DESKTOP, 1, 1, testPackage2, 6, TMP_CONTENT_URI) - modelHelper.addItem(APP_ICON, 1, DESKTOP, 0, 0, testPackage3, 7, TMP_CONTENT_URI) - modelHelper.addItem(APP_ICON, 1, DESKTOP, 1, 0, testPackage4, 8, TMP_CONTENT_URI) - modelHelper.addItem(APP_ICON, 2, DESKTOP, 0, 0, testPackage5, 9, TMP_CONTENT_URI) + addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 0, 1, testPackage1, 5, TMP_TABLE) + addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 1, 1, testPackage2, 6, TMP_TABLE) + addItem(ITEM_TYPE_APPLICATION, 1, CONTAINER_DESKTOP, 0, 0, testPackage3, 7, TMP_TABLE) + addItem(ITEM_TYPE_APPLICATION, 1, CONTAINER_DESKTOP, 1, 0, testPackage4, 8, TMP_TABLE) + addItem(ITEM_TYPE_APPLICATION, 2, CONTAINER_DESKTOP, 0, 0, testPackage5, 9, TMP_TABLE) idp.numDatabaseHotseatIcons = 4 idp.numColumns = 4 @@ -703,8 +724,7 @@ class GridSizeMigrationUtilTest { val srcReader = DbReader(db, TMP_TABLE, context, validPackages) val destReader = DbReader(db, TABLE_NAME, context, validPackages) GridSizeMigrationUtil.migrate( - context, - db, + dbHelper, srcReader, destReader, idp.numDatabaseHotseatIcons, @@ -715,12 +735,13 @@ class GridSizeMigrationUtilTest { // Get workspace items val c = - context.contentResolver.query( - CONTENT_URI, + db.query( + TABLE_NAME, arrayOf(INTENT, SCREEN), "container=$CONTAINER_DESKTOP", null, null, + null, null ) ?: throw IllegalStateException() @@ -747,4 +768,48 @@ class GridSizeMigrationUtilTest { private fun enableNewMigrationLogic(srcGridSize: String) { LauncherPrefs.get(context).putSync(WORKSPACE_SIZE.to(srcGridSize)) } + + private fun addItem( + type: Int, + screen: Int, + container: Int, + x: Int, + y: Int, + packageName: String? + ): Int { + return addItem( + type, + screen, + container, + x, + y, + packageName, + dbHelper.generateNewItemId(), + TABLE_NAME + ) + } + + private fun addItem( + type: Int, + screen: Int, + container: Int, + x: Int, + y: Int, + packageName: String?, + id: Int, + tableName: String + ): Int { + val values = ContentValues() + values.put(_ID, id) + values.put(CONTAINER, container) + values.put(SCREEN, screen) + values.put(CELLX, x) + values.put(CELLY, y) + values.put(SPANX, 1) + values.put(SPANY, 1) + values.put(ITEM_TYPE, type) + values.put(INTENT, Intent(Intent.ACTION_MAIN).setPackage(packageName).toUri(0)) + db.insert(tableName, null, values) + return id + } } diff --git a/tests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/src/com/android/launcher3/model/LoaderCursorTest.java index d192be408c..78812c0778 100644 --- a/tests/src/com/android/launcher3/model/LoaderCursorTest.java +++ b/tests/src/com/android/launcher3/model/LoaderCursorTest.java @@ -59,7 +59,6 @@ import androidx.test.filters.SmallTest; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; -import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.util.Executors; @@ -102,7 +101,7 @@ public class LoaderCursorTest { }); UserManagerState ums = new UserManagerState(); - mLoaderCursor = new LoaderCursor(mCursor, Favorites.CONTENT_URI, mApp, ums); + mLoaderCursor = new LoaderCursor(mCursor, mApp, ums); ums.allUsers.put(0, Process.myUserHandle()); } diff --git a/tests/src/com/android/launcher3/provider/LauncherDbUtilsTest.java b/tests/src/com/android/launcher3/provider/LauncherDbUtilsTest.java index 2b6f9ff193..54b8489134 100644 --- a/tests/src/com/android/launcher3/provider/LauncherDbUtilsTest.java +++ b/tests/src/com/android/launcher3/provider/LauncherDbUtilsTest.java @@ -45,6 +45,7 @@ import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.R; import com.android.launcher3.model.DatabaseHelper; import com.android.launcher3.model.DbDowngradeHelper; +import com.android.launcher3.pm.UserCache; import com.android.launcher3.settings.SettingsActivity; import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.util.IOUtils; @@ -165,12 +166,11 @@ public class LauncherDbUtilsTest { private class MyDatabaseHelper extends DatabaseHelper { MyDatabaseHelper() { - super(mContext, null, false); + super(mContext, null, UserCache.INSTANCE.get(mContext)::getSerialNumberForUser, + () -> { }); } @Override protected void handleOneTimeDataUpgrade(SQLiteDatabase db) { } - - protected void onEmptyDbCreated() { } } } diff --git a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java index 67de1f5fb1..73bb5865ee 100644 --- a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java +++ b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java @@ -45,8 +45,11 @@ import androidx.test.filters.SmallTest; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings.Favorites; -import com.android.launcher3.model.DatabaseHelper; +import com.android.launcher3.model.ModelDbController; +import com.android.launcher3.util.LauncherModelHelper; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -61,15 +64,29 @@ public class RestoreDbTaskTest { private final UserHandle mWorkUser = UserHandle.getUserHandleForUid(PER_USER_RANGE); + private LauncherModelHelper mModelHelper; + private Context mContext; + + @Before + public void setup() { + mModelHelper = new LauncherModelHelper(); + mContext = mModelHelper.sandboxContext; + } + + @After + public void teardown() { + mModelHelper.destroy(); + } + @Test public void testGetProfileId() throws Exception { - SQLiteDatabase db = new MyDatabaseHelper(23).getWritableDatabase(); + SQLiteDatabase db = new MyModelDbController(23).getDb(); assertEquals(23, new RestoreDbTask().getDefaultProfileId(db)); } @Test public void testMigrateProfileId() throws Exception { - SQLiteDatabase db = new MyDatabaseHelper(42).getWritableDatabase(); + SQLiteDatabase db = new MyModelDbController(42).getDb(); // Add some mock data for (int i = 0; i < 5; i++) { ContentValues values = new ContentValues(); @@ -89,7 +106,7 @@ public class RestoreDbTaskTest { @Test public void testChangeDefaultColumn() throws Exception { - SQLiteDatabase db = new MyDatabaseHelper(42).getWritableDatabase(); + SQLiteDatabase db = new MyModelDbController(42).getDb(); // Add some mock data for (int i = 0; i < 5; i++) { ContentValues values = new ContentValues(); @@ -112,28 +129,27 @@ public class RestoreDbTaskTest { @Test public void testSanitizeDB_bothProfiles() throws Exception { - Context context = getInstrumentation().getTargetContext(); UserHandle myUser = myUserHandle(); - long myProfileId = context.getSystemService(UserManager.class) + long myProfileId = mContext.getSystemService(UserManager.class) .getSerialNumberForUser(myUser); long myProfileId_old = myProfileId + 1; long workProfileId = myProfileId + 2; long workProfileId_old = myProfileId + 3; - MyDatabaseHelper helper = new MyDatabaseHelper(myProfileId); - SQLiteDatabase db = helper.getWritableDatabase(); - BackupManager bm = spy(new BackupManager(context)); + MyModelDbController controller = new MyModelDbController(myProfileId); + SQLiteDatabase db = controller.getDb(); + BackupManager bm = spy(new BackupManager(mContext)); doReturn(myUserHandle()).when(bm).getUserForAncestralSerialNumber(eq(myProfileId_old)); doReturn(mWorkUser).when(bm).getUserForAncestralSerialNumber(eq(workProfileId_old)); - helper.users.put(workProfileId, mWorkUser); + controller.users.put(workProfileId, mWorkUser); - addIconsBulk(helper, 10, 1, myProfileId_old); - addIconsBulk(helper, 6, 2, workProfileId_old); + addIconsBulk(controller, 10, 1, myProfileId_old); + addIconsBulk(controller, 6, 2, workProfileId_old); assertEquals(10, getItemCountForProfile(db, myProfileId_old)); assertEquals(6, getItemCountForProfile(db, workProfileId_old)); RestoreDbTask task = new RestoreDbTask(); - task.sanitizeDB(context, helper, helper.getWritableDatabase(), bm); + task.sanitizeDB(mContext, controller, controller.getDb(), bm); // All the data has been migrated to the new user ids assertEquals(0, getItemCountForProfile(db, myProfileId_old)); @@ -144,27 +160,26 @@ public class RestoreDbTaskTest { @Test public void testSanitizeDB_workItemsRemoved() throws Exception { - Context context = getInstrumentation().getTargetContext(); UserHandle myUser = myUserHandle(); - long myProfileId = context.getSystemService(UserManager.class) + long myProfileId = mContext.getSystemService(UserManager.class) .getSerialNumberForUser(myUser); long myProfileId_old = myProfileId + 1; long workProfileId_old = myProfileId + 3; - MyDatabaseHelper helper = new MyDatabaseHelper(myProfileId); - SQLiteDatabase db = helper.getWritableDatabase(); - BackupManager bm = spy(new BackupManager(context)); + MyModelDbController controller = new MyModelDbController(myProfileId); + SQLiteDatabase db = controller.getDb(); + BackupManager bm = spy(new BackupManager(mContext)); doReturn(myUserHandle()).when(bm).getUserForAncestralSerialNumber(eq(myProfileId_old)); // Work profile is not migrated doReturn(null).when(bm).getUserForAncestralSerialNumber(eq(workProfileId_old)); - addIconsBulk(helper, 10, 1, myProfileId_old); - addIconsBulk(helper, 6, 2, workProfileId_old); + addIconsBulk(controller, 10, 1, myProfileId_old); + addIconsBulk(controller, 6, 2, workProfileId_old); assertEquals(10, getItemCountForProfile(db, myProfileId_old)); assertEquals(6, getItemCountForProfile(db, workProfileId_old)); RestoreDbTask task = new RestoreDbTask(); - task.sanitizeDB(context, helper, helper.getWritableDatabase(), bm); + task.sanitizeDB(mContext, controller, controller.getDb(), bm); // All the data has been migrated to the new user ids assertEquals(0, getItemCountForProfile(db, myProfileId_old)); @@ -173,12 +188,13 @@ public class RestoreDbTaskTest { assertEquals(10, getCount(db, "select * from favorites")); } - private void addIconsBulk(DatabaseHelper helper, int count, int screen, long profileId) { - int columns = LauncherAppState.getIDP(getInstrumentation().getTargetContext()).numColumns; + private void addIconsBulk(MyModelDbController controller, + int count, int screen, long profileId) { + int columns = LauncherAppState.getIDP(mContext).numColumns; String packageName = getInstrumentation().getContext().getPackageName(); for (int i = 0; i < count; i++) { ContentValues values = new ContentValues(); - values.put(LauncherSettings.Favorites._ID, helper.generateNewItemId()); + values.put(LauncherSettings.Favorites._ID, controller.generateNewItemId()); values.put(LauncherSettings.Favorites.CONTAINER, CONTAINER_DESKTOP); values.put(LauncherSettings.Favorites.SCREEN, screen); values.put(LauncherSettings.Favorites.CELLX, i % columns); @@ -189,11 +205,11 @@ public class RestoreDbTaskTest { values.put(LauncherSettings.Favorites.ITEM_TYPE, ITEM_TYPE_APPLICATION); values.put(LauncherSettings.Favorites.INTENT, new Intent(Intent.ACTION_MAIN).setPackage(packageName).toUri(0)); - helper.getWritableDatabase().insert(TABLE_NAME, null, values); + + controller.insert(TABLE_NAME, values); } } - @Test public void testRemoveScreenIdGaps_firstScreenEmpty() { runRemoveScreenIdGapsTest( @@ -216,7 +232,7 @@ public class RestoreDbTaskTest { } private void runRemoveScreenIdGapsTest(int[] screenIds, int[] expectedScreenIds) { - SQLiteDatabase db = new MyDatabaseHelper(42).getWritableDatabase(); + SQLiteDatabase db = new MyModelDbController(42).getDb(); // Add some mock data for (int i = 0; i < screenIds.length; i++) { ContentValues values = new ContentValues(); @@ -254,13 +270,12 @@ public class RestoreDbTaskTest { } } - private class MyDatabaseHelper extends DatabaseHelper { + private class MyModelDbController extends ModelDbController { - public final LongSparseArray users; + public final LongSparseArray users = new LongSparseArray<>(); - MyDatabaseHelper(long profileId) { - super(getInstrumentation().getTargetContext(), null, false); - users = new LongSparseArray<>(); + MyModelDbController(long profileId) { + super(mContext); users.put(profileId, myUserHandle()); } @@ -269,10 +284,5 @@ public class RestoreDbTaskTest { int index = users.indexOfValue(user); return index >= 0 ? users.keyAt(index) : -1; } - - @Override - protected void handleOneTimeDataUpgrade(SQLiteDatabase db) { } - - protected void onEmptyDbCreated() { } } } diff --git a/tests/src/com/android/launcher3/util/LauncherModelHelper.java b/tests/src/com/android/launcher3/util/LauncherModelHelper.java index bf31e39ccc..6fca965600 100644 --- a/tests/src/com/android/launcher3/util/LauncherModelHelper.java +++ b/tests/src/com/android/launcher3/util/LauncherModelHelper.java @@ -363,12 +363,6 @@ public class LauncherModelHelper { sandboxContext.getContentResolver().insert(contentUri, values); } - public void deleteItem(int itemId, @NonNull final String tableName) { - final Uri uri = Uri.parse("content://" - + LauncherProvider.AUTHORITY + "/" + tableName + "/" + itemId); - sandboxContext.getContentResolver().delete(uri, null, null); - } - /** * Sets up a mock provider to load the provided layout by default, next time the layout loads */ @@ -426,7 +420,7 @@ public class LauncherModelHelper { } public SQLiteDatabase getDb() { - return getModelDbController().getDatabaseHelper().getWritableDatabase(); + return getModelDbController().getDb(); } } From 233ab990935a8d34f0a4290ca4a3910bf48c0554 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Tue, 9 May 2023 22:18:24 +0000 Subject: [PATCH 07/14] Consistently multiply touch slop for InputConsumers Fixes: 268651129 Test: TaplTestsQuickstep; manually swipe up from various InputConsumers Change-Id: I0a3baf654092a1a0bdafbfc734ec394668ba60f6 --- .../quickstep/RecentsAnimationDeviceState.java | 18 ++++++++++++++++++ .../DeviceLockedInputConsumer.java | 3 +-- .../OneHandedModeInputConsumer.java | 5 ++--- .../OtherActivityInputConsumer.java | 9 +-------- .../TaskbarUnstashInputConsumer.java | 1 + 5 files changed, 23 insertions(+), 13 deletions(-) diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java index d3e4ce5db8..64ec1d8a6d 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java @@ -58,6 +58,7 @@ import android.os.SystemProperties; import android.os.UserManager; import android.provider.Settings; import android.view.MotionEvent; +import android.view.ViewConfiguration; import androidx.annotation.BinderThread; import androidx.annotation.NonNull; @@ -87,6 +88,10 @@ public class RecentsAnimationDeviceState implements DisplayInfoChangeListener { static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode"; + // TODO: Move to quickstep contract + private static final float QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON = 9; + private static final float QUICKSTEP_TOUCH_SLOP_RATIO_GESTURAL = 2; + private final Context mContext; private final DisplayController mDisplayController; private final int mDisplayId; @@ -577,6 +582,19 @@ public class RecentsAnimationDeviceState implements DisplayInfoChangeListener { && ((mSystemUiStateFlags & SYSUI_STATE_IME_SHOWING) != 0); } + /** + * Returns the touch slop for {@link InputConsumer}s to compare against before pilfering + * pointers. Note that this is squared because it expects to be compared against + * {@link com.android.launcher3.Utilities#squaredHypot} (to avoid square root on each event). + */ + public float getSquaredTouchSlop() { + float slopMultiplier = isFullyGesturalNavMode() + ? QUICKSTEP_TOUCH_SLOP_RATIO_GESTURAL + : QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON; + float touchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop(); + return slopMultiplier * touchSlop * touchSlop; + } + public String getSystemUiStateString() { return QuickStepContract.getSystemUiStateString(mSystemUiStateFlags); } diff --git a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java index 42a74d9251..59a9582c1f 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java @@ -20,7 +20,6 @@ import static android.view.MotionEvent.ACTION_POINTER_DOWN; import static android.view.MotionEvent.ACTION_UP; import static com.android.launcher3.Utilities.squaredHypot; -import static com.android.launcher3.Utilities.squaredTouchSlop; import static com.android.launcher3.util.VelocityUtils.PX_PER_MS; import static com.android.quickstep.AbsSwipeUpHandler.MIN_PROGRESS_FOR_OVERVIEW; import static com.android.quickstep.MultiStateCallback.DEBUG_STATES; @@ -115,7 +114,7 @@ public class DeviceLockedInputConsumer implements InputConsumer, mDeviceState = deviceState; mTaskAnimationManager = taskAnimationManager; mGestureState = gestureState; - mTouchSlopSquared = squaredTouchSlop(context); + mTouchSlopSquared = mDeviceState.getSquaredTouchSlop(); mTransformParams = new TransformParams(); mInputMonitorCompat = inputMonitorCompat; mMaxTranslationY = context.getResources().getDimensionPixelSize( diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OneHandedModeInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OneHandedModeInputConsumer.java index d7ed79ba0a..5387c8a852 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/OneHandedModeInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/OneHandedModeInputConsumer.java @@ -21,8 +21,8 @@ import static android.view.MotionEvent.ACTION_DOWN; import static android.view.MotionEvent.ACTION_MOVE; import static android.view.MotionEvent.ACTION_UP; -import static com.android.launcher3.testing.shared.ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE; import static com.android.launcher3.Utilities.squaredHypot; +import static com.android.launcher3.testing.shared.ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE; import android.content.Context; import android.graphics.Point; @@ -31,7 +31,6 @@ import android.view.MotionEvent; import com.android.launcher3.R; import com.android.launcher3.testing.shared.ResourceUtils; -import com.android.launcher3.Utilities; import com.android.launcher3.util.DisplayController; import com.android.quickstep.InputConsumer; import com.android.quickstep.RecentsAnimationDeviceState; @@ -69,7 +68,7 @@ public class OneHandedModeInputConsumer extends DelegateInputConsumer { mDeviceState = deviceState; mDragDistThreshold = context.getResources().getDimensionPixelSize( R.dimen.gestures_onehanded_drag_threshold); - mSquaredSlop = Utilities.squaredTouchSlop(context); + mSquaredSlop = mDeviceState.getSquaredTouchSlop(); mDisplaySize = DisplayController.INSTANCE.get(mContext).getInfo().currentSize; mNavBarSize = ResourceUtils.getNavbarSize(NAVBAR_BOTTOM_GESTURE_SIZE, mContext.getResources()); diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java index 2dcbbb907a..f9cd4ee1cd 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java @@ -80,10 +80,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC public static final String DOWN_EVT = "OtherActivityInputConsumer.DOWN"; private static final String UP_EVT = "OtherActivityInputConsumer.UP"; - // TODO: Move to quickstep contract - public static final float QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON = 9; - public static final float QUICKSTEP_TOUCH_SLOP_RATIO_GESTURAL = 2; - // Minimum angle of a gesture's coordinate where a release goes to overview. public static final int OVERVIEW_MIN_DEGREES = 15; @@ -157,11 +153,8 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC boolean continuingPreviousGesture = mTaskAnimationManager.isRecentsAnimationRunning(); mIsDeferredDownTarget = !continuingPreviousGesture && isDeferredDownTarget; - float slopMultiplier = mDeviceState.isFullyGesturalNavMode() - ? QUICKSTEP_TOUCH_SLOP_RATIO_GESTURAL - : QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON; mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop(); - mSquaredTouchSlop = slopMultiplier * mTouchSlop * mTouchSlop; + mSquaredTouchSlop = mDeviceState.getSquaredTouchSlop(); mPassedPilferInputSlop = mPassedWindowMoveSlop = continuingPreviousGesture; mDisableHorizontalSwipe = !mPassedPilferInputSlop && disableHorizontalSwipe; diff --git a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java index b9126ebdfc..e9a0761caf 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java @@ -83,6 +83,7 @@ public class TaskbarUnstashInputConsumer extends DelegateInputConsumer { InputMonitorCompat inputMonitor, TaskbarActivityContext taskbarActivityContext) { super(delegate, inputMonitor); mTaskbarActivityContext = taskbarActivityContext; + // TODO(b/270395798): remove this when cleaning up old Persistent Taskbar code. mSquaredTouchSlop = Utilities.squaredTouchSlop(context); mScreenWidth = taskbarActivityContext.getDeviceProfile().widthPx; From 2792271688e3745de79578121f0e2b92a574eec5 Mon Sep 17 00:00:00 2001 From: Jerry Chang Date: Thu, 20 Apr 2023 07:43:04 +0000 Subject: [PATCH 08/14] Defer intercepting touch events to actually start shifting tasks Fix: 278740578 Test: http://recall/-/fLARJNt42LVxc3tt86SneW/d9A443iE2UQVktVc2YqwT2 Change-Id: I81efc87f19775dba96bab581a1c443d6070f6ebc --- .../com/android/quickstep/AbsSwipeUpHandler.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 7d47945fc4..b49eb24971 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -334,6 +334,7 @@ public abstract class AbsSwipeUpHandler, private boolean mCanSlowSwipeGoHome = true; // Indicates whether the divider is shown, only used when split screen is activated. private boolean mIsDividerShown = true; + private boolean mStartMovingTasks; @Nullable private RemoteAnimationTargets.ReleaseCheck mSwipePipToHomeReleaseCheck = null; @@ -1722,12 +1723,19 @@ public abstract class AbsSwipeUpHandler, return keepClearArea; } + /** + * Notifies to start intercepting touches in the app window and hide the divider bar if needed. + * @see RecentsAnimationController#enableInputConsumer() + */ private void startInterceptingTouchesForGesture() { - if (mRecentsAnimationController == null) { + if (mRecentsAnimationController == null || !mStartMovingTasks) { return; } mRecentsAnimationController.enableInputConsumer(); + + // Hide the divider as it starts intercepting touches in the app window. + setDividerShown(false); } private void computeRecentsScrollIfInvisible() { @@ -2339,9 +2347,9 @@ public abstract class AbsSwipeUpHandler, boolean setRecentsScroll = mRecentsViewScrollLinked && mRecentsView != null; float progress = Math.max(mCurrentShift.value, getScaleProgressDueToScroll()); int scrollOffset = setRecentsScroll ? mRecentsView.getScrollOffset() : 0; - if (progress > 0 || scrollOffset != 0) { - // Hide the divider as the tasks start moving. - setDividerShown(false); + if (!mStartMovingTasks && (progress > 0 || scrollOffset != 0)) { + mStartMovingTasks = true; + startInterceptingTouchesForGesture(); } for (RemoteTargetHandle remoteHandle : mRemoteTargetHandles) { AnimatorControllerWithResistance playbackController = From 87ed2f117688465558c80c3e7c2415335e2ca602 Mon Sep 17 00:00:00 2001 From: Jerry Chang Date: Thu, 11 May 2023 08:41:13 +0000 Subject: [PATCH 09/14] Fix not tracking splitting tasks correctly When drag-to-repace one of the splitting tasks, it might reports to TopTaskTracker the original task changed to undefined after repoting the new task appeared in a split pair. Result to clear the split tasks record unexpectedly in TopTaskTracker. This makes sure to clear the correct stage and prevent override the correct split record. Fix: 277982233 Test: manual check the behavior and verify the reocrd in TopTaskTracker Change-Id: Ifce2efdde6d99508f1afa844b3ad424071e13a8f --- .../com/android/quickstep/TopTaskTracker.java | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/quickstep/src/com/android/quickstep/TopTaskTracker.java b/quickstep/src/com/android/quickstep/TopTaskTracker.java index 6f502d0ece..24cf72c718 100644 --- a/quickstep/src/com/android/quickstep/TopTaskTracker.java +++ b/quickstep/src/com/android/quickstep/TopTaskTracker.java @@ -127,23 +127,16 @@ public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskSta @Override public void onTaskStageChanged(int taskId, @StageType int stage, boolean visible) { - // If task is not visible but we are tracking it, stop tracking it - if (!visible) { + // If a task is not visible anymore or has been moved to undefined, stop tracking it. + if (!visible || stage == SplitConfigurationOptions.STAGE_TYPE_UNDEFINED) { if (mMainStagePosition.taskId == taskId) { - resetTaskId(mMainStagePosition); + mMainStagePosition.taskId = INVALID_TASK_ID; } else if (mSideStagePosition.taskId == taskId) { - resetTaskId(mSideStagePosition); + mSideStagePosition.taskId = INVALID_TASK_ID; } // else it's an un-tracked child return; } - // If stage has moved to undefined, stop tracking the task - if (stage == SplitConfigurationOptions.STAGE_TYPE_UNDEFINED) { - resetTaskId(taskId == mMainStagePosition.taskId - ? mMainStagePosition : mSideStagePosition); - return; - } - if (stage == SplitConfigurationOptions.STAGE_TYPE_MAIN) { mMainStagePosition.taskId = taskId; } else { @@ -161,10 +154,6 @@ public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskSta mPinnedTaskId = INVALID_TASK_ID; } - private void resetTaskId(SplitStageInfo taskPosition) { - taskPosition.taskId = -1; - } - /** * @return index 0 will be task in left/top position, index 1 in right/bottom position. * Will return empty array if device is not in staged split From 3bc763f5a34b8638083ece79f19658e3f8d66793 Mon Sep 17 00:00:00 2001 From: Thales Lima Date: Wed, 3 May 2023 18:34:36 +0100 Subject: [PATCH 10/14] Make taskbar touchable region smaller in Overview While in overview, makes the touchable region smaller so touches can go to the window below and trigger tapping on overview to go home. Bug: 269985301 Test: Manual (TAPL in a following CL) Flag: none Change-Id: Ie8c7719090c387f951d78cf0fc47e6d9ed192f27 --- .../launcher3/taskbar/TaskbarInsetsController.kt | 13 ++++++++++++- .../taskbar/TaskbarLauncherStateController.java | 4 ++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt index 4422fd4b75..d6e559a9b4 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt @@ -33,11 +33,13 @@ import android.view.WindowInsets.Type.tappableElement import android.view.WindowManager import android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD import android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION +import androidx.core.graphics.toRegion import com.android.internal.policy.GestureNavigationSettingsObserver import com.android.launcher3.DeviceProfile import com.android.launcher3.R import com.android.launcher3.anim.AlphaUpdateListener import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController +import com.android.launcher3.util.DisplayController import java.io.PrintWriter /** Handles the insets that Taskbar provides to underlying apps and the IME. */ @@ -220,7 +222,16 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas controllers.taskbarViewController.areIconsVisible() || context.isNavBarKidsModeActive ) { // Taskbar has some touchable elements, take over the full taskbar area - insetsInfo.touchableRegion.set(touchableRegion) + if ( + controllers.uiController.isInOverview && + DisplayController.isTransientTaskbar(context) + ) { + insetsInfo.touchableRegion.set( + controllers.taskbarActivityContext.dragLayer.lastDrawnTransientRect.toRegion() + ) + } else { + insetsInfo.touchableRegion.set(touchableRegion) + } insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION) insetsIsTouchableRegion = false } else { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java index 75cfd05d41..84fb077ab1 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java @@ -424,6 +424,10 @@ public class TaskbarLauncherStateController { // We're changing state to home, should close open popups e.g. Taskbar AllApps handleOpenFloatingViews = true; } + if (mLauncherState == LauncherState.OVERVIEW) { + // Calling to update the insets in TaskbarInsetController#updateInsetsTouchability + mControllers.taskbarActivityContext.notifyUpdateLayoutParams(); + } } if (hasAnyFlag(changedFlags, FLAGS_LAUNCHER_ACTIVE)) { From 662787540c415afe59547baff48ee5d1b87bf3af Mon Sep 17 00:00:00 2001 From: Mady Mellor Date: Thu, 11 May 2023 18:50:35 +0000 Subject: [PATCH 11/14] Revert "Modify Taskbar code to accommodate bubble bar gesture to stash/unstash" This reverts commit 7344766886921cb3c170eecac96706567aced051. Reason for revert: b/282035015 Change-Id: I38db287f730048d3e1e5041f1853bdae214e1a66 --- .../taskbar/TaskbarActivityContext.java | 24 +------ .../taskbar/TaskbarInsetsController.kt | 49 ++++---------- .../TaskbarLauncherStateController.java | 10 +-- .../taskbar/TaskbarScrimViewController.java | 6 -- .../taskbar/TaskbarStashController.java | 65 ++++--------------- .../taskbar/TaskbarStashViaTouchController.kt | 20 +----- .../taskbar/TaskbarTranslationController.java | 4 -- .../bubbles/BubbleBarViewController.java | 13 +--- .../bubbles/BubbleStashController.java | 5 +- .../TaskbarUnstashInputConsumer.java | 29 ++------- 10 files changed, 37 insertions(+), 188 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index 8bc1fcacce..d94d8f7fe0 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -444,11 +444,6 @@ public class TaskbarActivityContext extends BaseTaskbarContext { return mControllers.taskbarDragController; } - @Nullable - public BubbleControllers getBubbleControllers() { - return mControllers.bubbleControllers.orElse(null); - } - @Override public ViewCache getViewCache() { return mViewCache; @@ -625,12 +620,8 @@ public class TaskbarActivityContext extends BaseTaskbarContext { mControllers.taskbarForceVisibleImmersiveController.updateSysuiFlags(systemUiStateFlags); mControllers.voiceInteractionWindowController.setIsVoiceInteractionWindowVisible( (systemUiStateFlags & SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING) != 0, fromInit); + mControllers.uiController.updateStateForSysuiFlags(systemUiStateFlags); - mControllers.bubbleControllers.ifPresent(controllers -> { - controllers.bubbleBarController.updateStateForSysuiFlags(systemUiStateFlags); - controllers.bubbleStashedHandleViewController.setIsHomeButtonDisabled( - mControllers.navbarButtonsViewController.isHomeDisabled()); - }); } /** @@ -726,7 +717,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext { } } mWindowLayoutParams.height = height; - mControllers.taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged(); + mControllers.taskbarInsetsController.onTaskbarWindowHeightOrInsetsChanged(); mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams); } @@ -984,19 +975,10 @@ public class TaskbarActivityContext extends BaseTaskbarContext { * Called when we want to unstash taskbar when user performs swipes up gesture. */ public void onSwipeToUnstashTaskbar() { - mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(/* stash= */ false); + mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(false); mControllers.taskbarEduTooltipController.hide(); } - /** - * Called when we want to open bubblebar when user performs swipes up gesture. - */ - public void onSwipeToOpenBubblebar() { - mControllers.bubbleControllers.ifPresent(controllers -> { - controllers.bubbleStashController.showBubbleBar(/* expandBubbles= */ true); - }); - } - /** Returns {@code true} if taskbar All Apps is open. */ public boolean isTaskbarAllAppsOpen() { return mControllers.taskbarAllAppsController.isOpen(); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt index 7adee266c5..4422fd4b75 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt @@ -53,13 +53,13 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas private val touchableRegion: Region = Region() private val insetsOwner: IBinder = Binder() private val deviceProfileChangeListener = { _: DeviceProfile -> - onTaskbarOrBubblebarWindowHeightOrInsetsChanged() + onTaskbarWindowHeightOrInsetsChanged() } private val gestureNavSettingsObserver = GestureNavigationSettingsObserver( context.mainThreadHandler, context, - this::onTaskbarOrBubblebarWindowHeightOrInsetsChanged + this::onTaskbarWindowHeightOrInsetsChanged ) // Initialized in init. @@ -69,7 +69,7 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas fun init(controllers: TaskbarControllers) { this.controllers = controllers windowLayoutParams = context.windowLayoutParams - onTaskbarOrBubblebarWindowHeightOrInsetsChanged() + onTaskbarWindowHeightOrInsetsChanged() context.addOnDeviceProfileChangeListener(deviceProfileChangeListener) gestureNavSettingsObserver.registerForCallingUser() @@ -80,7 +80,7 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas gestureNavSettingsObserver.unregister() } - fun onTaskbarOrBubblebarWindowHeightOrInsetsChanged() { + fun onTaskbarWindowHeightOrInsetsChanged() { if (context.isGestureNav) { windowLayoutParams.providedInsets = arrayOf( @@ -102,33 +102,13 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas ) } - val taskbarTouchableHeight = controllers.taskbarStashController.touchableHeight - val bubblesTouchableHeight = - if (controllers.bubbleControllers.isPresent) - controllers.bubbleControllers.get().bubbleStashController.touchableHeight - else 0 - val touchableHeight = Math.max(taskbarTouchableHeight, bubblesTouchableHeight) - - if ( - controllers.bubbleControllers.isPresent && - controllers.bubbleControllers.get().bubbleStashController.isBubblesShowingOnHome - ) { - val iconBounds = - controllers.bubbleControllers.get().bubbleBarViewController.bubbleBarBounds - touchableRegion.set( - iconBounds.left, - iconBounds.top, - iconBounds.right, - iconBounds.bottom - ) - } else { - touchableRegion.set( - 0, - windowLayoutParams.height - touchableHeight, - context.deviceProfile.widthPx, - windowLayoutParams.height - ) - } + val touchableHeight = controllers.taskbarStashController.touchableHeight + touchableRegion.set( + 0, + windowLayoutParams.height - touchableHeight, + context.deviceProfile.widthPx, + windowLayoutParams.height + ) val contentHeight = controllers.taskbarStashController.contentHeightToReportToApps val tappableHeight = controllers.taskbarStashController.tappableHeightToReportToApps val res = context.resources @@ -217,9 +197,6 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas context.dragLayer, insetsInfo.touchableRegion ) - val bubbleBarVisible = - controllers.bubbleControllers.isPresent && - controllers.bubbleControllers.get().bubbleBarViewController.isBubbleBarVisible() var insetsIsTouchableRegion = true if (context.dragLayer.alpha < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) { // Let touches pass through us. @@ -240,9 +217,7 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME) insetsIsTouchableRegion = false } else if ( - controllers.taskbarViewController.areIconsVisible() || - context.isNavBarKidsModeActive || - bubbleBarVisible + controllers.taskbarViewController.areIconsVisible() || context.isNavBarKidsModeActive ) { // Taskbar has some touchable elements, take over the full taskbar area insetsInfo.touchableRegion.set(touchableRegion) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java index 2b9d968d82..75cfd05d41 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java @@ -408,14 +408,6 @@ public class TaskbarLauncherStateController { + ", mLauncherState: " + mLauncherState + ", toAlignment: " + toAlignment); } - mControllers.bubbleControllers.ifPresent(controllers -> { - // Show the bubble bar when on launcher home or in overview. - boolean onHome = isInLauncher && mLauncherState == LauncherState.NORMAL; - boolean onOverview = mLauncherState == LauncherState.OVERVIEW; - controllers.bubbleStashController.setBubblesShowingOnHome(onHome); - controllers.bubbleStashController.setBubblesShowingOnOverview(onOverview); - }); - AnimatorSet animatorSet = new AnimatorSet(); if (hasAnyFlag(changedFlags, FLAG_LAUNCHER_IN_STATE_TRANSITION)) { @@ -483,7 +475,7 @@ public class TaskbarLauncherStateController { TaskbarStashController stashController = mControllers.taskbarStashController; stashController.updateAndAnimateTransientTaskbar( - /* stash */ true, /* duration */ 0, true /* bubblesShouldFollow */); + /* stash */ true, /* duration */ 0); } }); } else { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java index 1c250bf377..5ea00cf408 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java @@ -15,7 +15,6 @@ */ package com.android.launcher3.taskbar; -import static com.android.launcher3.taskbar.bubbles.BubbleBarController.BUBBLE_BAR_ENABLED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED; @@ -24,7 +23,6 @@ import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; import com.android.launcher3.anim.AnimatedFloat; -import com.android.launcher3.util.DisplayController; import com.android.quickstep.SystemUiProxy; import java.io.PrintWriter; @@ -65,10 +63,6 @@ public class TaskbarScrimViewController implements TaskbarControllers.LoggableTa * Updates the scrim state based on the flags. */ public void updateStateForSysuiFlags(int stateFlags, boolean skipAnim) { - if (BUBBLE_BAR_ENABLED && DisplayController.isTransientTaskbar(mActivity)) { - // These scrims aren't used if bubble bar & transient taskbar are active. - return; - } final boolean bubblesExpanded = (stateFlags & SYSUI_STATE_BUBBLES_EXPANDED) != 0; final boolean manageMenuExpanded = (stateFlags & SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED) != 0; diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java index 0dd8310aa7..c2175f2444 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java @@ -255,15 +255,14 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba private boolean mEnableBlockingTimeoutDuringTests = false; // Evaluate whether the handle should be stashed - private final IntPredicate mIsStashedPredicate = flags -> { - boolean inApp = hasAnyFlag(flags, FLAGS_IN_APP); - boolean stashedInApp = hasAnyFlag(flags, FLAGS_STASHED_IN_APP); - boolean stashedLauncherState = hasAnyFlag(flags, FLAG_IN_STASHED_LAUNCHER_STATE); - boolean forceStashed = hasAnyFlag(flags, FLAGS_FORCE_STASHED); - return (inApp && stashedInApp) || (!inApp && stashedLauncherState) || forceStashed; - }; private final StatePropertyHolder mStatePropertyHolder = new StatePropertyHolder( - mIsStashedPredicate); + flags -> { + boolean inApp = hasAnyFlag(flags, FLAGS_IN_APP); + boolean stashedInApp = hasAnyFlag(flags, FLAGS_STASHED_IN_APP); + boolean stashedLauncherState = hasAnyFlag(flags, FLAG_IN_STASHED_LAUNCHER_STATE); + boolean forceStashed = hasAnyFlag(flags, FLAGS_FORCE_STASHED); + return (inApp && stashedInApp) || (!inApp && stashedLauncherState) || forceStashed; + }); private boolean mIsTaskbarSystemActionRegistered = false; private TaskbarSharedState mTaskbarSharedState; @@ -503,29 +502,15 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba /** * Stash or unstashes the transient taskbar, using the default TASKBAR_STASH_DURATION. - * If bubble bar exists, it will match taskbars stashing behavior. */ public void updateAndAnimateTransientTaskbar(boolean stash) { - updateAndAnimateTransientTaskbar(stash, TASKBAR_STASH_DURATION, - /* shouldBubblesFollow= */ true); - } - - /** - * Stash or unstashes the transient taskbar, using the default TASKBAR_STASH_DURATION. - * If bubble bar exists, it will match taskbars stashing behavior. - */ - public void updateAndAnimateTransientTaskbar(boolean stash, boolean shouldBubblesFollow) { - updateAndAnimateTransientTaskbar(stash, TASKBAR_STASH_DURATION, shouldBubblesFollow); + updateAndAnimateTransientTaskbar(stash, TASKBAR_STASH_DURATION); } /** * Stash or unstashes the transient taskbar. - * @param stash whether transient taskbar should be stashed. - * @param duration how long the duration of the stash should take. - * @param shouldBubblesFollow whether bubbles should match taskbars behavior. */ - public void updateAndAnimateTransientTaskbar(boolean stash, long duration, - boolean shouldBubblesFollow) { + public void updateAndAnimateTransientTaskbar(boolean stash, long duration) { if (!DisplayController.isTransientTaskbar(mActivity)) { return; } @@ -541,34 +526,6 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba updateStateForFlag(FLAG_STASHED_IN_APP_AUTO, stash); applyState(); } - - mControllers.bubbleControllers.ifPresent(controllers -> { - if (shouldBubblesFollow) { - final boolean willStash = mIsStashedPredicate.test(mState); - if (willStash != controllers.bubbleStashController.isStashed()) { - // Typically bubbles gets stashed / unstashed along with Taskbar, however, if - // taskbar is becoming stashed because bubbles is being expanded, we don't want - // to stash bubbles. - if (willStash) { - controllers.bubbleStashController.stashBubbleBar(); - } else { - controllers.bubbleStashController.showBubbleBar(false /* expandBubbles */); - } - } - } - }); - } - - /** - * Stashes transient taskbar after it has timed out. - */ - private void updateAndAnimateTransientTaskbarForTimeout() { - // If bubbles are expanded we shouldn't stash them when taskbar is hidden - // for the timeout. - boolean bubbleBarExpanded = mControllers.bubbleControllers.isPresent() - && mControllers.bubbleControllers.get().bubbleBarViewController.isExpanded(); - updateAndAnimateTransientTaskbar(/* stash= */ true, - /* shouldBubblesFollow= */ !bubbleBarExpanded); } /** @@ -923,7 +880,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba private void onIsStashedChanged(boolean isStashed) { mControllers.runAfterInit(() -> { mControllers.stashedHandleViewController.onIsStashedChanged(isStashed); - mControllers.taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged(); + mControllers.taskbarInsetsController.onTaskbarWindowHeightOrInsetsChanged(); }); } @@ -1170,7 +1127,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba if (mControllers.taskbarAutohideSuspendController.isSuspended()) { return; } - updateAndAnimateTransientTaskbarForTimeout(); + updateAndAnimateTransientTaskbar(true); } @Override diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashViaTouchController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashViaTouchController.kt index b194c8e6b2..1cc667211c 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashViaTouchController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashViaTouchController.kt @@ -108,18 +108,7 @@ class TaskbarStashViaTouchController(val controllers: TaskbarControllers) : Touc } override fun onControllerInterceptTouchEvent(ev: MotionEvent): Boolean { - val bubbleControllers = controllers.bubbleControllers.orElse(null) - if (!enabled || bubbleControllers == null) { - return false - } - if (bubbleControllers.bubbleBarViewController.isExpanded) { - // WMShell / bubbles will handle collapsing - return false - } - if ( - controllers.taskbarStashController.isStashed && - bubbleControllers.bubbleStashController.isStashed - ) { + if (!enabled || controllers.taskbarStashController.isStashed) { return false } @@ -133,12 +122,7 @@ class TaskbarStashViaTouchController(val controllers: TaskbarControllers) : Touc return true } } else if (ev.action == MotionEvent.ACTION_DOWN) { - val isDownOnBubbleBar = - (bubbleControllers != null && - bubbleControllers.bubbleBarViewController.isEventOverAnyItem( - screenCoordinatesEv - )) - if (!isDownOnBubbleBar && screenCoordinatesEv.y < gestureHeightYThreshold) { + if (screenCoordinatesEv.y < gestureHeightYThreshold) { controllers.taskbarStashController.updateAndAnimateTransientTaskbar(true) } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java index 2456f4b5ae..065d1117c8 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java @@ -92,10 +92,6 @@ public class TaskbarTranslationController implements TaskbarControllers.Loggable mControllers.stashedHandleViewController.setTranslationYForSwipe(transY); mControllers.taskbarViewController.setTranslationYForSwipe(transY); mControllers.taskbarDragLayerController.setTranslationYForSwipe(transY); - mControllers.bubbleControllers.ifPresent(controllers -> { - controllers.bubbleBarViewController.setTranslationYForSwipe(transY); - controllers.bubbleStashedHandleViewController.setTranslationYForSwipe(transY); - }); } /** diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java index 37861896e0..82494c6fda 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java @@ -28,8 +28,6 @@ import com.android.launcher3.R; import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.taskbar.TaskbarActivityContext; import com.android.launcher3.taskbar.TaskbarControllers; -import com.android.launcher3.taskbar.TaskbarInsetsController; -import com.android.launcher3.taskbar.TaskbarStashController; import com.android.launcher3.util.MultiPropertyFactory; import com.android.launcher3.util.MultiValueAlpha; import com.android.quickstep.SystemUiProxy; @@ -53,8 +51,6 @@ public class BubbleBarViewController { // Initialized in init. private BubbleStashController mBubbleStashController; private BubbleBarController mBubbleBarController; - private TaskbarStashController mTaskbarStashController; - private TaskbarInsetsController mTaskbarInsetsController; private View.OnClickListener mBubbleClickListener; private View.OnClickListener mBubbleBarClickListener; @@ -84,8 +80,6 @@ public class BubbleBarViewController { public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) { mBubbleStashController = bubbleControllers.bubbleStashController; mBubbleBarController = bubbleControllers.bubbleBarController; - mTaskbarStashController = controllers.taskbarStashController; - mTaskbarInsetsController = controllers.taskbarInsetsController; mActivity.addOnDeviceProfileChangeListener(dp -> mBarView.getLayoutParams().height = mActivity.getDeviceProfile().taskbarHeight @@ -95,9 +89,7 @@ public class BubbleBarViewController { mBubbleClickListener = v -> onBubbleClicked(v); mBubbleBarClickListener = v -> setExpanded(true); mBarView.setOnClickListener(mBubbleBarClickListener); - mBarView.addOnLayoutChangeListener((view, i, i1, i2, i3, i4, i5, i6, i7) -> - mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged() - ); + // TODO: when barView layout changes tell taskbarInsetsController the insets have changed. } private void onBubbleClicked(View v) { @@ -291,8 +283,7 @@ public class BubbleBarViewController { } else { Log.w(TAG, "trying to expand bubbles when there isn't one selected"); } - mTaskbarStashController.updateAndAnimateTransientTaskbar(true /* stash */, - false /* shouldBubblesFollow */); + // TODO: Tell taskbar stash controller to stash without bubbles following } } } diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java index b3c7d41e37..0ab53b0c20 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java @@ -25,7 +25,6 @@ import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.taskbar.StashedHandleViewController; import com.android.launcher3.taskbar.TaskbarActivityContext; import com.android.launcher3.taskbar.TaskbarControllers; -import com.android.launcher3.taskbar.TaskbarInsetsController; import com.android.launcher3.taskbar.TaskbarStashController; import com.android.launcher3.util.MultiPropertyFactory; @@ -51,7 +50,6 @@ public class BubbleStashController { // Initialized in init. private TaskbarControllers mControllers; - private TaskbarInsetsController mTaskbarInsetsController; private BubbleBarViewController mBarViewController; private BubbleStashedHandleViewController mHandleViewController; private TaskbarStashController mTaskbarStashController; @@ -79,7 +77,6 @@ public class BubbleStashController { public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) { mControllers = controllers; - mTaskbarInsetsController = controllers.taskbarInsetsController; mBarViewController = bubbleControllers.bubbleBarViewController; mHandleViewController = bubbleControllers.bubbleStashedHandleViewController; mTaskbarStashController = controllers.taskbarStashController; @@ -274,7 +271,7 @@ public class BubbleStashController { private void onIsStashedChanged() { mControllers.runAfterInit(() -> { mHandleViewController.onIsStashedChanged(); - mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged(); + // TODO: when stash changes tell taskbarInsetsController the insets have changed. }); } } diff --git a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java index b9126ebdfc..65c825c0f6 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java @@ -37,7 +37,6 @@ import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.taskbar.TaskbarActivityContext; import com.android.launcher3.taskbar.TaskbarTranslationController.TransitionCallback; -import com.android.launcher3.taskbar.bubbles.BubbleControllers; import com.android.launcher3.touch.OverScroll; import com.android.launcher3.util.DisplayController; import com.android.quickstep.InputConsumer; @@ -63,7 +62,6 @@ public class TaskbarUnstashInputConsumer extends DelegateInputConsumer { private final int mTaskbarNavThresholdY; private final boolean mIsTaskbarAllAppsOpen; private boolean mHasPassedTaskbarNavThreshold; - private boolean mIsInBubbleBarArea; private final PointF mDownPos = new PointF(); private final PointF mLastPos = new PointF(); @@ -137,7 +135,7 @@ public class TaskbarUnstashInputConsumer extends DelegateInputConsumer { mHasPassedTaskbarNavThreshold = false; mTaskbarActivityContext.setAutohideSuspendFlag( FLAG_AUTOHIDE_SUSPEND_TOUCHING, true); - if (isInTaskbarArea(x)) { + if (isInArea(x)) { if (!mIsTransientTaskbar) { mLongPressDownX = x; mLongPressDownY = y; @@ -146,12 +144,10 @@ public class TaskbarUnstashInputConsumer extends DelegateInputConsumer { mCanceledUnstashHint = false; } } + if (mTransitionCallback != null && !mIsTaskbarAllAppsOpen) { mTransitionCallback.onActionDown(); } - if (mIsTransientTaskbar && isInBubbleBarArea(x)) { - mIsInBubbleBarArea = true; - } break; case MotionEvent.ACTION_POINTER_UP: int ptrIdx = ev.getActionIndex(); @@ -188,11 +184,7 @@ public class TaskbarUnstashInputConsumer extends DelegateInputConsumer { if (!mHasPassedTaskbarNavThreshold && passedTaskbarNavThreshold) { mHasPassedTaskbarNavThreshold = true; - if (mIsInBubbleBarArea) { - mTaskbarActivityContext.onSwipeToOpenBubblebar(); - } else { - mTaskbarActivityContext.onSwipeToUnstashTaskbar(); - } + mTaskbarActivityContext.onSwipeToUnstashTaskbar(); } if (dY < 0) { @@ -215,32 +207,21 @@ public class TaskbarUnstashInputConsumer extends DelegateInputConsumer { mTransitionCallback.onActionEnd(); } mHasPassedTaskbarNavThreshold = false; - mIsInBubbleBarArea = false; break; } } } } - private boolean isInTaskbarArea(float x) { + private boolean isInArea(float x) { float areaFromMiddle = mUnstashArea / 2.0f; float distFromMiddle = Math.abs(mScreenWidth / 2.0f - x); return distFromMiddle < areaFromMiddle; } - private boolean isInBubbleBarArea(float x) { - if (mTaskbarActivityContext != null && mIsTransientTaskbar) { - BubbleControllers controllers = mTaskbarActivityContext.getBubbleControllers(); - if (controllers == null) return false; - Rect bubbleBarBounds = controllers.bubbleBarViewController.getBubbleBarBounds(); - return x >= bubbleBarBounds.left && x <= bubbleBarBounds.right; - } - return false; - } - private void onLongPressDetected(MotionEvent motionEvent) { if (mTaskbarActivityContext != null - && isInTaskbarArea(motionEvent.getRawX()) + && isInArea(motionEvent.getRawX()) && !mIsTransientTaskbar) { boolean taskBarPressed = mTaskbarActivityContext.onLongPressToUnstashTaskbar(); if (taskBarPressed) { From 88a91bbd163775421902c3611d1cf430ffd7d050 Mon Sep 17 00:00:00 2001 From: Vinit Nayak Date: Thu, 11 May 2023 10:39:20 -0700 Subject: [PATCH 12/14] Add logs to check which userId is used for workProfile matcher Flag: none Test: compiles Bug: 243688989 Change-Id: I0a579203cc0c51f7707180b323ed4828f1dea297 --- .../android/launcher3/allapps/WorkProfileManager.java | 6 +++++- .../android/launcher3/model/PackageUpdatedTask.java | 2 +- src/com/android/launcher3/util/ItemInfoMatcher.java | 11 ++++++++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/com/android/launcher3/allapps/WorkProfileManager.java b/src/com/android/launcher3/allapps/WorkProfileManager.java index bf36e02dad..a671c6efec 100644 --- a/src/com/android/launcher3/allapps/WorkProfileManager.java +++ b/src/com/android/launcher3/allapps/WorkProfileManager.java @@ -97,7 +97,11 @@ public class WorkProfileManager implements PersonalWorkSlidingTabStrip.OnActiveP StatsLogManager statsLogManager) { mUserManager = userManager; mAllApps = allApps; - if (FeatureFlags.ENABLE_APP_CLONING_CHANGES_IN_LAUNCHER.get()) { + boolean cloningChanges = FeatureFlags.ENABLE_APP_CLONING_CHANGES_IN_LAUNCHER.get(); + if (TestProtocol.sDebugTracing) { + Log.d(WORK_TAB_MISSING, "matcher flag: " + cloningChanges); + } + if (cloningChanges) { mMatcher = ofWorkProfileUser(userManager); } else { mMatcher = mAllApps.mPersonalMatcher.negate(); diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java index d4a5e1b9d9..8c938f4124 100644 --- a/src/com/android/launcher3/model/PackageUpdatedTask.java +++ b/src/com/android/launcher3/model/PackageUpdatedTask.java @@ -95,7 +95,7 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { mPackages = packages; if (TestProtocol.sDebugTracing) { Log.d(TestProtocol.WORK_TAB_MISSING, "PackageUpdatedTask mOp: " + mOp + - " packageCount: " + mPackages.length); + " packageCount: " + mPackages.length + " user: " + user); DEBUG = true; } } diff --git a/src/com/android/launcher3/util/ItemInfoMatcher.java b/src/com/android/launcher3/util/ItemInfoMatcher.java index b6af3140fa..8a27381a0b 100644 --- a/src/com/android/launcher3/util/ItemInfoMatcher.java +++ b/src/com/android/launcher3/util/ItemInfoMatcher.java @@ -18,6 +18,7 @@ package com.android.launcher3.util; import android.content.ComponentName; import android.os.UserHandle; +import android.util.Log; import androidx.annotation.NonNull; @@ -25,6 +26,7 @@ import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.shortcuts.ShortcutKey; +import com.android.launcher3.testing.shared.TestProtocol; import java.util.Collection; import java.util.HashSet; @@ -42,7 +44,14 @@ public abstract class ItemInfoMatcher { private static final ComponentName EMPTY_COMPONENT = new ComponentName("", ""); public static Predicate ofUser(UserHandle user) { - return info -> info != null && info.user.equals(user); + return info -> { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.WORK_TAB_MISSING, "userHandle: " + user + + ", itemUserHandle: " + info.user + + " package: " + info.getTargetPackage()); + } + return info != null && info.user.equals(user); + }; } public static Predicate ofComponents( From 09905cfa90a46b5fb4868d0ba4963f9c45e3f336 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 11 May 2023 22:22:16 +0000 Subject: [PATCH 13/14] Revert "Revert "Revert "Revert "Revert "Changing GridMigrationTask to use ModelDbController directly""""" This reverts commit bca4e694f07ad76be5df639f52f345b0bb49d8ef. Reason for revert: post submit broken Change-Id: I8afc63b5aa67ee14127f79e2245ef543bff8cf31 --- .../launcher3/AppWidgetsRestoredReceiver.java | 8 +- .../android/launcher3/LauncherProvider.java | 12 + .../android/launcher3/LauncherSettings.java | 26 +- .../graphics/PreviewSurfaceRenderer.java | 34 +-- .../launcher3/model/DatabaseHelper.java | 82 +++++- .../model/GridSizeMigrationUtil.java | 131 ++++++--- .../android/launcher3/model/LoaderCursor.java | 22 +- .../android/launcher3/model/LoaderTask.java | 100 ++++--- .../launcher3/model/ModelDbController.java | 138 ++++----- .../launcher3/provider/LauncherDbUtils.java | 2 +- .../launcher3/provider/RestoreDbTask.java | 34 +-- .../android/launcher3/util/ContentWriter.java | 10 +- .../model/DbDowngradeHelperTest.java | 5 +- .../model/GridSizeMigrationUtilTest.kt | 275 +++++++----------- .../launcher3/model/LoaderCursorTest.java | 3 +- .../provider/LauncherDbUtilsTest.java | 6 +- .../launcher3/provider/RestoreDbTaskTest.java | 84 +++--- .../launcher3/util/LauncherModelHelper.java | 8 +- 18 files changed, 512 insertions(+), 468 deletions(-) diff --git a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java index 5fbd48cdaf..f041ffbe6c 100644 --- a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java +++ b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java @@ -16,8 +16,8 @@ import androidx.annotation.NonNull; import androidx.annotation.WorkerThread; import com.android.launcher3.LauncherSettings.Favorites; +import com.android.launcher3.model.DatabaseHelper; import com.android.launcher3.model.LoaderTask; -import com.android.launcher3.model.ModelDbController; import com.android.launcher3.model.WidgetsModel; import com.android.launcher3.model.data.LauncherAppWidgetInfo; import com.android.launcher3.pm.UserCache; @@ -52,7 +52,7 @@ public class AppWidgetsRestoredReceiver extends BroadcastReceiver { * Updates the app widgets whose id has changed during the restore process. */ @WorkerThread - public static void restoreAppWidgetIds(Context context, ModelDbController controller, + public static void restoreAppWidgetIds(Context context, DatabaseHelper helper, int[] oldWidgetIds, int[] newWidgetIds, @NonNull AppWidgetHost host) { if (WidgetsModel.GO_DISABLE_WIDGETS) { Log.e(TAG, "Skipping widget ID remap as widgets not supported"); @@ -92,12 +92,12 @@ public class AppWidgetsRestoredReceiver extends BroadcastReceiver { final String where = "appWidgetId=? and (restored & 1) = 1 and profileId=?"; final String[] args = new String[] { oldWidgetId, Long.toString(mainProfileId) }; int result = new ContentWriter(context, - new ContentWriter.CommitParams(controller, where, args)) + new ContentWriter.CommitParams(helper, where, args)) .put(LauncherSettings.Favorites.APPWIDGET_ID, newWidgetIds[i]) .put(LauncherSettings.Favorites.RESTORED, state) .commit(); if (result == 0) { - Cursor cursor = controller.getDb().query( + Cursor cursor = helper.getWritableDatabase().query( Favorites.TABLE_NAME, new String[] {Favorites.APPWIDGET_ID}, "appWidgetId=?", new String[] { oldWidgetId }, null, null, null); diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java index 9abec505c7..0df4bd409e 100644 --- a/src/com/android/launcher3/LauncherProvider.java +++ b/src/com/android/launcher3/LauncherProvider.java @@ -263,6 +263,18 @@ public class LauncherProvider extends ContentProvider { getModelDbController().refreshHotseatRestoreTable(); return null; } + case LauncherSettings.Settings.METHOD_UPDATE_CURRENT_OPEN_HELPER: { + Bundle result = new Bundle(); + result.putBoolean(LauncherSettings.Settings.EXTRA_VALUE, + getModelDbController().updateCurrentOpenHelper(arg /* dbFile */)); + return result; + } + case LauncherSettings.Settings.METHOD_PREP_FOR_PREVIEW: { + Bundle result = new Bundle(); + result.putBoolean(LauncherSettings.Settings.EXTRA_VALUE, + getModelDbController().prepareForPreview(arg /* dbFile */)); + return result; + } } return null; } diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java index 7fda326ec2..b65e96ba52 100644 --- a/src/com/android/launcher3/LauncherSettings.java +++ b/src/com/android/launcher3/LauncherSettings.java @@ -147,6 +147,11 @@ public class LauncherSettings { */ public static final String HYBRID_HOTSEAT_BACKUP_TABLE = "hotseat_restore_backup"; + /** + * Temporary table used specifically for grid migrations during wallpaper preview + */ + public static final String PREVIEW_TABLE_NAME = "favorites_preview"; + /** * Temporary table used specifically for multi-db grid migrations */ @@ -158,6 +163,18 @@ public class LauncherSettings { public static final Uri CONTENT_URI = Uri.parse("content://" + LauncherProvider.AUTHORITY + "/" + TABLE_NAME); + /** + * The content:// style URL for "favorites_preview" table + */ + public static final Uri PREVIEW_CONTENT_URI = Uri.parse("content://" + + LauncherProvider.AUTHORITY + "/" + PREVIEW_TABLE_NAME); + + /** + * The content:// style URL for "favorites_tmp" table + */ + public static final Uri TMP_CONTENT_URI = Uri.parse("content://" + + LauncherProvider.AUTHORITY + "/" + TMP_TABLE); + /** * The content:// style URL for a given row, identified by its id. * @@ -359,6 +376,10 @@ public class LauncherSettings { public static final String METHOD_REFRESH_HOTSEAT_RESTORE_TABLE = "restore_hotseat_table"; + public static final String METHOD_UPDATE_CURRENT_OPEN_HELPER = "update_current_open_helper"; + + public static final String METHOD_PREP_FOR_PREVIEW = "prep_for_preview"; + public static final String EXTRA_VALUE = "value"; public static final String EXTRA_DB_NAME = "db_name"; @@ -372,8 +393,11 @@ public class LauncherSettings { } public static Bundle call(ContentResolver cr, String method, String arg) { - return cr.call(CONTENT_URI, method, arg, null); + return call(cr, method, arg, null /* extras */); } + public static Bundle call(ContentResolver cr, String method, String arg, Bundle extras) { + return cr.call(CONTENT_URI, method, arg, extras); + } } } diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java index 8f0b8ec531..372e9bf2e9 100644 --- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java +++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java @@ -16,7 +16,6 @@ package com.android.launcher3.graphics; -import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; @@ -53,8 +52,6 @@ import com.android.launcher3.graphics.LauncherPreviewRenderer.PreviewContext; import com.android.launcher3.model.BgDataModel; import com.android.launcher3.model.GridSizeMigrationUtil; import com.android.launcher3.model.LoaderTask; -import com.android.launcher3.model.ModelDbController; -import com.android.launcher3.provider.LauncherDbUtils; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.RunnableList; import com.android.launcher3.util.Themes; @@ -148,9 +145,7 @@ public class PreviewSurfaceRenderer { final String query = LauncherSettings.Favorites.ITEM_TYPE + " = " + LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET; - ModelDbController mainController = - LauncherAppState.getInstance(mContext).getModel().getModelDbController(); - try (Cursor c = mainController.query(TABLE_NAME, + try (Cursor c = context.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI, new String[] { LauncherSettings.Favorites.APPWIDGET_ID, LauncherSettings.Favorites.SPANX, @@ -195,6 +190,8 @@ public class PreviewSurfaceRenderer { @WorkerThread private void loadModelData() { + final boolean migrated = doGridMigrationIfNecessary(); + final Context inflationContext; if (mWallpaperColors != null) { // Create a themed context, without affecting the main application context @@ -212,20 +209,8 @@ public class PreviewSurfaceRenderer { Themes.getActivityThemeRes(mContext)); } - if (GridSizeMigrationUtil.needsToMigrate(inflationContext, mIdp)) { - // Start the migration + if (migrated) { PreviewContext previewContext = new PreviewContext(inflationContext, mIdp); - // Copy existing data to preview DB - LauncherDbUtils.copyTable(LauncherAppState.getInstance(mContext) - .getModel().getModelDbController().getDb(), - TABLE_NAME, - LauncherAppState.getInstance(previewContext) - .getModel().getModelDbController().getDb(), - TABLE_NAME, - mContext); - LauncherAppState.getInstance(previewContext) - .getModel().getModelDbController().clearEmptyDbFlag(); - new LoaderTask( LauncherAppState.getInstance(previewContext), /* bgAllAppsList= */ null, @@ -244,7 +229,8 @@ public class PreviewSurfaceRenderer { query += " or " + LauncherSettings.Favorites.SCREEN + " = " + Workspace.SECOND_SCREEN_ID; } - loadWorkspace(new ArrayList<>(), query, null); + loadWorkspaceForPreviewSurfaceRenderer(new ArrayList<>(), + LauncherSettings.Favorites.PREVIEW_CONTENT_URI, query); final SparseArray spanInfo = getLoadedLauncherWidgetInfo(previewContext.getBaseContext()); @@ -267,6 +253,14 @@ public class PreviewSurfaceRenderer { } } + @WorkerThread + private boolean doGridMigrationIfNecessary() { + if (!GridSizeMigrationUtil.needsToMigrate(mContext, mIdp)) { + return false; + } + return GridSizeMigrationUtil.migrateGridIfNeeded(mContext, mIdp); + } + @UiThread private void renderView(Context inflationContext, BgDataModel dataModel, Map widgetProviderInfoMap, diff --git a/src/com/android/launcher3/model/DatabaseHelper.java b/src/com/android/launcher3/model/DatabaseHelper.java index ecf5f67a97..dc5fcf7d4b 100644 --- a/src/com/android/launcher3/model/DatabaseHelper.java +++ b/src/com/android/launcher3/model/DatabaseHelper.java @@ -15,8 +15,8 @@ */ package com.android.launcher3.model; -import static com.android.launcher3.LauncherSettings.Favorites.addTableToDb; import static com.android.launcher3.provider.LauncherDbUtils.dropTable; +import static com.android.launcher3.provider.LauncherDbUtils.tableExists; import android.content.ContentValues; import android.content.Context; @@ -36,6 +36,9 @@ import androidx.annotation.NonNull; import com.android.launcher3.AutoInstallsLayout; import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback; +import com.android.launcher3.InvariantDeviceProfile; +import com.android.launcher3.LauncherFiles; +import com.android.launcher3.LauncherPrefs; import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.Utilities; @@ -55,7 +58,6 @@ import java.io.File; import java.net.URISyntaxException; import java.util.Arrays; import java.util.Locale; -import java.util.function.ToLongFunction; import java.util.stream.Collectors; /** @@ -74,23 +76,45 @@ public class DatabaseHelper extends NoLocaleSQLiteHelper implements private static final boolean LOGD = false; private static final String DOWNGRADE_SCHEMA_FILE = "downgrade_schema.json"; + public static final String EMPTY_DATABASE_CREATED = "EMPTY_DATABASE_CREATED"; private final Context mContext; - private final ToLongFunction mUserSerialProvider; - private final Runnable mOnEmptyDbCreateCallback; - + private final boolean mForMigration; private int mMaxItemId = -1; public boolean mHotseatRestoreTableExists; + public static DatabaseHelper createDatabaseHelper(Context context, boolean forMigration) { + return createDatabaseHelper(context, null, forMigration); + } + + public static DatabaseHelper createDatabaseHelper(Context context, String dbName, + boolean forMigration) { + if (dbName == null) { + dbName = InvariantDeviceProfile.INSTANCE.get(context).dbFile; + } + DatabaseHelper databaseHelper = new DatabaseHelper(context, dbName, forMigration); + // Table creation sometimes fails silently, which leads to a crash loop. + // This way, we will try to create a table every time after crash, so the device + // would eventually be able to recover. + if (!tableExists(databaseHelper.getReadableDatabase(), Favorites.TABLE_NAME)) { + Log.e(TAG, "Tables are missing after onCreate has been called. Trying to recreate"); + // This operation is a no-op if the table already exists. + databaseHelper.addFavoritesTable(databaseHelper.getWritableDatabase(), true); + } + databaseHelper.mHotseatRestoreTableExists = tableExists( + databaseHelper.getReadableDatabase(), Favorites.HYBRID_HOTSEAT_BACKUP_TABLE); + + databaseHelper.initIds(); + return databaseHelper; + } + /** * Constructor used in tests and for restore. */ - public DatabaseHelper(Context context, String dbName, - ToLongFunction userSerialProvider, Runnable onEmptyDbCreateCallback) { + public DatabaseHelper(Context context, String dbName, boolean forMigration) { super(context, dbName, SCHEMA_VERSION); mContext = context; - mUserSerialProvider = userSerialProvider; - mOnEmptyDbCreateCallback = onEmptyDbCreateCallback; + mForMigration = forMigration; } protected void initIds() { @@ -107,11 +131,13 @@ public class DatabaseHelper extends NoLocaleSQLiteHelper implements mMaxItemId = 1; - addTableToDb(db, getDefaultUserSerial(), false /* optional */); + addFavoritesTable(db, false); // Fresh and clean launcher DB. mMaxItemId = initializeMaxItemId(db); - mOnEmptyDbCreateCallback.run(); + if (!mForMigration) { + onEmptyDbCreated(); + } } public void onAddOrDeleteOp(SQLiteDatabase db) { @@ -121,8 +147,38 @@ public class DatabaseHelper extends NoLocaleSQLiteHelper implements } } - private long getDefaultUserSerial() { - return mUserSerialProvider.applyAsLong(Process.myUserHandle()); + /** + * Re-composite given key in respect to database. If the current db is + * {@link LauncherFiles#LAUNCHER_DB}, return the key as-is. Otherwise append the db name to + * given key. e.g. consider key="EMPTY_DATABASE_CREATED", dbName="minimal.db", the returning + * string will be "EMPTY_DATABASE_CREATED@minimal.db". + */ + public String getKey(final String key) { + if (TextUtils.equals(getDatabaseName(), LauncherFiles.LAUNCHER_DB)) { + return key; + } + return key + "@" + getDatabaseName(); + } + + /** + * Overridden in tests. + */ + protected void onEmptyDbCreated() { + // Set the flag for empty DB + LauncherPrefs.getPrefs(mContext).edit().putBoolean(getKey(EMPTY_DATABASE_CREATED), true) + .commit(); + } + + public long getSerialNumberForUser(UserHandle user) { + return UserCache.INSTANCE.get(mContext).getSerialNumberForUser(user); + } + + public long getDefaultUserSerial() { + return getSerialNumberForUser(Process.myUserHandle()); + } + + private void addFavoritesTable(SQLiteDatabase db, boolean optional) { + Favorites.addTableToDb(db, getDefaultUserSerial(), optional); } @Override diff --git a/src/com/android/launcher3/model/GridSizeMigrationUtil.java b/src/com/android/launcher3/model/GridSizeMigrationUtil.java index 9a6cde63cd..eded5ea6a9 100644 --- a/src/com/android/launcher3/model/GridSizeMigrationUtil.java +++ b/src/com/android/launcher3/model/GridSizeMigrationUtil.java @@ -16,9 +16,6 @@ package com.android.launcher3.model; -import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME; -import static com.android.launcher3.LauncherSettings.Favorites.TMP_TABLE; -import static com.android.launcher3.provider.LauncherDbUtils.copyTable; import static com.android.launcher3.provider.LauncherDbUtils.dropTable; import android.content.ComponentName; @@ -37,15 +34,16 @@ import android.util.Log; import androidx.annotation.NonNull; import com.android.launcher3.InvariantDeviceProfile; +import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.graphics.LauncherPreviewRenderer; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.pm.InstallSessionHelper; import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction; import com.android.launcher3.util.GridOccupancy; import com.android.launcher3.util.IntArray; -import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext; import com.android.launcher3.widget.LauncherAppWidgetProviderInfo; import com.android.launcher3.widget.WidgetManagerHelper; @@ -91,38 +89,81 @@ public class GridSizeMigrationUtil { return needsToMigrate; } + /** See {@link #migrateGridIfNeeded(Context, InvariantDeviceProfile)} */ + public static boolean migrateGridIfNeeded(Context context) { + if (context instanceof LauncherPreviewRenderer.PreviewContext) { + return true; + } + return migrateGridIfNeeded(context, null); + } + /** - * When migrating the grid, we copy the table - * {@link LauncherSettings.Favorites#TABLE_NAME} from {@code source} into - * {@link LauncherSettings.Favorites#TMP_TABLE}, run the grid size migration algorithm + * When migrating the grid for preview, we copy the table + * {@link LauncherSettings.Favorites#TABLE_NAME} into + * {@link LauncherSettings.Favorites#PREVIEW_TABLE_NAME}, run grid size migration from the + * former to the later, then use the later table for preview. + * + * Similarly when doing the actual grid migration, the former grid option's table + * {@link LauncherSettings.Favorites#TABLE_NAME} is copied into the new grid option's + * {@link LauncherSettings.Favorites#TMP_TABLE}, we then run the grid size migration algorithm * to migrate the later to the former, and load the workspace from the default * {@link LauncherSettings.Favorites#TABLE_NAME}. * * @return false if the migration failed. */ - public static boolean migrateGridIfNeeded( - @NonNull Context context, - @NonNull InvariantDeviceProfile idp, - @NonNull DatabaseHelper target, - @NonNull SQLiteDatabase source) { + public static boolean migrateGridIfNeeded(Context context, InvariantDeviceProfile idp) { + boolean migrateForPreview = idp != null; + if (!migrateForPreview) { + idp = LauncherAppState.getIDP(context); + } DeviceGridState srcDeviceState = new DeviceGridState(context); DeviceGridState destDeviceState = new DeviceGridState(idp); if (!needsToMigrate(srcDeviceState, destDeviceState)) { return true; } - copyTable(source, TABLE_NAME, target.getWritableDatabase(), TMP_TABLE, context); HashSet validPackages = getValidPackages(context); + + if (migrateForPreview) { + if (!LauncherSettings.Settings.call( + context.getContentResolver(), + LauncherSettings.Settings.METHOD_PREP_FOR_PREVIEW, + destDeviceState.getDbFile()).getBoolean( + LauncherSettings.Settings.EXTRA_VALUE)) { + return false; + } + } else if (!LauncherSettings.Settings.call( + context.getContentResolver(), + LauncherSettings.Settings.METHOD_UPDATE_CURRENT_OPEN_HELPER, + destDeviceState.getDbFile()).getBoolean( + LauncherSettings.Settings.EXTRA_VALUE)) { + return false; + } + long migrationStartTime = System.currentTimeMillis(); - try (SQLiteTransaction t = new SQLiteTransaction(target.getWritableDatabase())) { - DbReader srcReader = new DbReader(t.getDb(), TMP_TABLE, context, validPackages); - DbReader destReader = new DbReader(t.getDb(), TABLE_NAME, context, validPackages); + try (SQLiteTransaction t = (SQLiteTransaction) LauncherSettings.Settings.call( + context.getContentResolver(), + LauncherSettings.Settings.METHOD_NEW_TRANSACTION).getBinder( + LauncherSettings.Settings.EXTRA_VALUE)) { + + DbReader srcReader = new DbReader(t.getDb(), + migrateForPreview ? LauncherSettings.Favorites.TABLE_NAME + : LauncherSettings.Favorites.TMP_TABLE, + context, validPackages); + DbReader destReader = new DbReader(t.getDb(), + migrateForPreview ? LauncherSettings.Favorites.PREVIEW_TABLE_NAME + : LauncherSettings.Favorites.TABLE_NAME, + context, validPackages); Point targetSize = new Point(destDeviceState.getColumns(), destDeviceState.getRows()); - migrate(target, srcReader, destReader, destDeviceState.getNumHotseat(), + migrate(context, t.getDb(), srcReader, destReader, destDeviceState.getNumHotseat(), targetSize, srcDeviceState, destDeviceState); - dropTable(t.getDb(), TMP_TABLE); + + if (!migrateForPreview) { + dropTable(t.getDb(), LauncherSettings.Favorites.TMP_TABLE); + } + t.commit(); return true; } catch (Exception e) { @@ -133,7 +174,7 @@ public class GridSizeMigrationUtil { Log.v(TAG, "Workspace migration completed in " + (System.currentTimeMillis() - migrationStartTime)); - if (!(context instanceof SandboxContext)) { + if (!migrateForPreview) { // Save current configuration, so that the migration does not run again. destDeviceState.writeToPrefs(context); } @@ -141,7 +182,7 @@ public class GridSizeMigrationUtil { } public static boolean migrate( - @NonNull DatabaseHelper helper, + @NonNull final Context context, @NonNull final SQLiteDatabase db, @NonNull final DbReader srcReader, @NonNull final DbReader destReader, final int destHotseatSize, @NonNull final Point targetSize, @NonNull final DeviceGridState srcDeviceState, @@ -193,8 +234,8 @@ public class GridSizeMigrationUtil { Collections.sort(workspaceToBeAdded); // Migrate hotseat - solveHotseatPlacement(helper, destHotseatSize, - srcReader, destReader, dstHotseatItems, hotseatToBeAdded); + solveHotseatPlacement(db, srcReader, + destReader, context, destHotseatSize, dstHotseatItems, hotseatToBeAdded); // Migrate workspace. // First we create a collection of the screens @@ -214,8 +255,8 @@ public class GridSizeMigrationUtil { if (DEBUG) { Log.d(TAG, "Migrating " + screenId); } - solveGridPlacement(helper, srcReader, - destReader, screenId, trgX, trgY, workspaceToBeAdded, false); + solveGridPlacement(db, srcReader, + destReader, context, screenId, trgX, trgY, workspaceToBeAdded, false); if (workspaceToBeAdded.isEmpty()) { break; } @@ -225,8 +266,8 @@ public class GridSizeMigrationUtil { // any of the screens, in this case we add them to new screens until all of them are placed. int screenId = destReader.mLastScreenId + 1; while (!workspaceToBeAdded.isEmpty()) { - solveGridPlacement(helper, srcReader, - destReader, screenId, trgX, trgY, workspaceToBeAdded, preservePages); + solveGridPlacement(db, srcReader, + destReader, context, screenId, trgX, trgY, workspaceToBeAdded, preservePages); screenId++; } @@ -257,33 +298,33 @@ public class GridSizeMigrationUtil { }); } - private static void insertEntryInDb(DatabaseHelper helper, DbEntry entry, + private static void insertEntryInDb(SQLiteDatabase db, Context context, DbEntry entry, String srcTableName, String destTableName) { - int id = copyEntryAndUpdate(helper, entry, srcTableName, destTableName); + int id = copyEntryAndUpdate(db, context, entry, srcTableName, destTableName); if (entry.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) { for (Set itemIds : entry.mFolderItems.values()) { for (int itemId : itemIds) { - copyEntryAndUpdate(helper, itemId, id, srcTableName, destTableName); + copyEntryAndUpdate(db, context, itemId, id, srcTableName, destTableName); } } } } - private static int copyEntryAndUpdate(DatabaseHelper helper, + private static int copyEntryAndUpdate(SQLiteDatabase db, Context context, DbEntry entry, String srcTableName, String destTableName) { - return copyEntryAndUpdate(helper, entry, -1, -1, srcTableName, destTableName); + return copyEntryAndUpdate(db, context, entry, -1, -1, srcTableName, destTableName); } - private static int copyEntryAndUpdate(DatabaseHelper helper, + private static int copyEntryAndUpdate(SQLiteDatabase db, Context context, int id, int folderId, String srcTableName, String destTableName) { - return copyEntryAndUpdate(helper, null, id, folderId, srcTableName, destTableName); + return copyEntryAndUpdate(db, context, null, id, folderId, srcTableName, destTableName); } - private static int copyEntryAndUpdate(DatabaseHelper helper, DbEntry entry, - int id, int folderId, String srcTableName, String destTableName) { + private static int copyEntryAndUpdate(SQLiteDatabase db, Context context, + DbEntry entry, int id, int folderId, String srcTableName, String destTableName) { int newId = -1; - Cursor c = helper.getWritableDatabase().query(srcTableName, null, + Cursor c = db.query(srcTableName, null, LauncherSettings.Favorites._ID + " = '" + (entry != null ? entry.id : id) + "'", null, null, null, null); while (c.moveToNext()) { @@ -294,9 +335,11 @@ public class GridSizeMigrationUtil { } else { values.put(LauncherSettings.Favorites.CONTAINER, folderId); } - newId = helper.generateNewItemId(); + newId = LauncherSettings.Settings.call(context.getContentResolver(), + LauncherSettings.Settings.METHOD_NEW_ITEM_ID).getInt( + LauncherSettings.Settings.EXTRA_VALUE); values.put(LauncherSettings.Favorites._ID, newId); - helper.getWritableDatabase().insert(destTableName, null, values); + db.insert(destTableName, null, values); } c.close(); return newId; @@ -324,9 +367,9 @@ public class GridSizeMigrationUtil { return validPackages; } - private static void solveGridPlacement(@NonNull final DatabaseHelper helper, + private static void solveGridPlacement(@NonNull final SQLiteDatabase db, @NonNull final DbReader srcReader, @NonNull final DbReader destReader, - final int screenId, final int trgX, final int trgY, + @NonNull final Context context, final int screenId, final int trgX, final int trgY, @NonNull final List sortedItemsToPlace, final boolean matchingScreenIdOnly) { final GridOccupancy occupied = new GridOccupancy(trgX, trgY); final Point trg = new Point(trgX, trgY); @@ -348,7 +391,7 @@ public class GridSizeMigrationUtil { continue; } if (findPlacementForEntry(entry, next, trg, occupied, screenId)) { - insertEntryInDb(helper, entry, srcReader.mTableName, destReader.mTableName); + insertEntryInDb(db, context, entry, srcReader.mTableName, destReader.mTableName); iterator.remove(); } } @@ -385,9 +428,9 @@ public class GridSizeMigrationUtil { return false; } - private static void solveHotseatPlacement( - @NonNull final DatabaseHelper helper, final int hotseatSize, + private static void solveHotseatPlacement(@NonNull final SQLiteDatabase db, @NonNull final DbReader srcReader, @NonNull final DbReader destReader, + @NonNull final Context context, final int hotseatSize, @NonNull final List placedHotseatItems, @NonNull final List itemsToPlace) { @@ -404,7 +447,7 @@ public class GridSizeMigrationUtil { // to something other than -1. entry.cellX = i; entry.cellY = 0; - insertEntryInDb(helper, entry, srcReader.mTableName, destReader.mTableName); + insertEntryInDb(db, context, entry, srcReader.mTableName, destReader.mTableName); occupied[entry.screenId] = true; } } diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java index 2054d930e6..a5dccc1fab 100644 --- a/src/com/android/launcher3/model/LoaderCursor.java +++ b/src/com/android/launcher3/model/LoaderCursor.java @@ -16,16 +16,16 @@ package com.android.launcher3.model; -import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME; - import android.content.ComponentName; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; +import android.content.pm.PackageManager; import android.database.Cursor; import android.database.CursorWrapper; +import android.net.Uri; import android.os.UserHandle; import android.provider.BaseColumns; import android.text.TextUtils; @@ -66,7 +66,9 @@ public class LoaderCursor extends CursorWrapper { private final LongSparseArray allUsers; private final LauncherAppState mApp; + private final Uri mContentUri; private final Context mContext; + private final PackageManager mPM; private final IconCache mIconCache; private final InvariantDeviceProfile mIDP; @@ -106,14 +108,17 @@ public class LoaderCursor extends CursorWrapper { public int itemType; public int restoreFlag; - public LoaderCursor(Cursor cursor, LauncherAppState app, UserManagerState userManagerState) { + public LoaderCursor(Cursor cursor, Uri contentUri, LauncherAppState app, + UserManagerState userManagerState) { super(cursor); mApp = app; allUsers = userManagerState.allUsers; + mContentUri = contentUri; mContext = app.getContext(); mIconCache = app.getIconCache(); mIDP = app.getInvariantDeviceProfile(); + mPM = mContext.getPackageManager(); // Init column indices mIconIndex = getColumnIndexOrThrow(Favorites.ICON); @@ -385,7 +390,7 @@ public class LoaderCursor extends CursorWrapper { */ public ContentWriter updater() { return new ContentWriter(mContext, new ContentWriter.CommitParams( - mApp.getModel().getModelDbController(), + mApp.getModel().getModelDbController().getDatabaseHelper(), BaseColumns._ID + "= ?", new String[]{Integer.toString(id)})); } @@ -404,8 +409,8 @@ public class LoaderCursor extends CursorWrapper { public boolean commitDeleted() { if (mItemsToRemove.size() > 0) { // Remove dead items - mApp.getModel().getModelDbController().delete(TABLE_NAME, - Utilities.createDbSelectionQuery(Favorites._ID, mItemsToRemove), null); + mContext.getContentResolver().delete(mContentUri, Utilities.createDbSelectionQuery( + Favorites._ID, mItemsToRemove), null); return true; } return false; @@ -430,8 +435,9 @@ public class LoaderCursor extends CursorWrapper { // Update restored items that no longer require special handling ContentValues values = new ContentValues(); values.put(Favorites.RESTORED, 0); - mApp.getModel().getModelDbController().update(TABLE_NAME, values, - Utilities.createDbSelectionQuery(Favorites._ID, mRestoredRows), null); + mContext.getContentResolver().update(mContentUri, values, + Utilities.createDbSelectionQuery( + Favorites._ID, mRestoredRows), null); } } diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index d4eded5968..9053d19f84 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -16,7 +16,6 @@ package com.android.launcher3.model; -import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME; import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION; import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_CHANGE_PERMISSION; import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED; @@ -42,6 +41,7 @@ import android.content.pm.PackageInstaller.SessionInfo; import android.content.pm.PackageManager; import android.content.pm.ShortcutInfo; import android.graphics.Point; +import android.net.Uri; import android.os.Bundle; import android.os.Trace; import android.os.UserHandle; @@ -50,6 +50,7 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; import android.util.LongSparseArray; +import android.util.TimingLogger; import androidx.annotation.Nullable; @@ -199,10 +200,25 @@ public class LoaderTask implements Runnable { } Object traceToken = TraceHelper.INSTANCE.beginSection(TAG); + TimingLogger timingLogger = new TimingLogger(TAG, "run"); LoaderMemoryLogger memoryLogger = new LoaderMemoryLogger(); try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) { List allShortcuts = new ArrayList<>(); - loadWorkspace(allShortcuts, "", memoryLogger); + Trace.beginSection("LoadWorkspace"); + try { + loadWorkspace(allShortcuts, memoryLogger); + } finally { + Trace.endSection(); + } + logASplit(timingLogger, "loadWorkspace"); + + if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) { + verifyNotStopped(); + mModelDelegate.loadAndBindWorkspaceItems(mUserManagerState, + mLauncherBinder.mCallbacksList, mShortcutKeyToPinnedShortcuts); + mModelDelegate.markActive(); + logASplit(timingLogger, "workspaceDelegateItems"); + } // Sanitize data re-syncs widgets/shortcuts based on the workspace loaded from db. // sanitizeData should not be invoked if the workspace is loaded from a db different @@ -212,21 +228,21 @@ public class LoaderTask implements Runnable { verifyNotStopped(); sanitizeFolders(mItemsDeleted); sanitizeWidgetsShortcutsAndPackages(); - logASplit("sanitizeData"); + logASplit(timingLogger, "sanitizeData"); } verifyNotStopped(); mLauncherBinder.bindWorkspace(true /* incrementBindId */, /* isBindSync= */ false); - logASplit("bindWorkspace"); + logASplit(timingLogger, "bindWorkspace"); mModelDelegate.workspaceLoadComplete(); // Notify the installer packages of packages with active installs on the first screen. sendFirstScreenActiveInstallsBroadcast(); - logASplit("sendFirstScreenActiveInstallsBroadcast"); + logASplit(timingLogger, "sendFirstScreenActiveInstallsBroadcast"); // Take a break waitForIdle(); - logASplit("step 1 complete"); + logASplit(timingLogger, "step 1 complete"); verifyNotStopped(); // second step @@ -237,16 +253,16 @@ public class LoaderTask implements Runnable { } finally { Trace.endSection(); } - logASplit("loadAllApps"); + logASplit(timingLogger, "loadAllApps"); if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) { mModelDelegate.loadAndBindAllAppsItems(mUserManagerState, mLauncherBinder.mCallbacksList, mShortcutKeyToPinnedShortcuts); - logASplit("allAppsDelegateItems"); + logASplit(timingLogger, "allAppsDelegateItems"); } verifyNotStopped(); mLauncherBinder.bindAllApps(); - logASplit("bindAllApps"); + logASplit(timingLogger, "bindAllApps"); verifyNotStopped(); IconCacheUpdateHandler updateHandler = mIconCache.getUpdateHandler(); @@ -254,73 +270,75 @@ public class LoaderTask implements Runnable { updateHandler.updateIcons(allActivityList, LauncherActivityCachingLogic.newInstance(mApp.getContext()), mApp.getModel()::onPackageIconsUpdated); - logASplit("update icon cache"); + logASplit(timingLogger, "update icon cache"); verifyNotStopped(); - logASplit("save shortcuts in icon cache"); + logASplit(timingLogger, "save shortcuts in icon cache"); updateHandler.updateIcons(allShortcuts, new ShortcutCachingLogic(), mApp.getModel()::onPackageIconsUpdated); // Take a break waitForIdle(); - logASplit("step 2 complete"); + logASplit(timingLogger, "step 2 complete"); verifyNotStopped(); // third step List allDeepShortcuts = loadDeepShortcuts(); - logASplit("loadDeepShortcuts"); + logASplit(timingLogger, "loadDeepShortcuts"); verifyNotStopped(); mLauncherBinder.bindDeepShortcuts(); - logASplit("bindDeepShortcuts"); + logASplit(timingLogger, "bindDeepShortcuts"); verifyNotStopped(); - logASplit("save deep shortcuts in icon cache"); + logASplit(timingLogger, "save deep shortcuts in icon cache"); updateHandler.updateIcons(allDeepShortcuts, new ShortcutCachingLogic(), (pkgs, user) -> { }); // Take a break waitForIdle(); - logASplit("step 3 complete"); + logASplit(timingLogger, "step 3 complete"); verifyNotStopped(); // fourth step List allWidgetsList = mBgDataModel.widgetsModel.update(mApp, null); - logASplit("load widgets"); + logASplit(timingLogger, "load widgets"); verifyNotStopped(); mLauncherBinder.bindWidgets(); - logASplit("bindWidgets"); + logASplit(timingLogger, "bindWidgets"); verifyNotStopped(); if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) { mModelDelegate.loadAndBindOtherItems(mLauncherBinder.mCallbacksList); - logASplit("otherDelegateItems"); + logASplit(timingLogger, "otherDelegateItems"); verifyNotStopped(); } updateHandler.updateIcons(allWidgetsList, new ComponentWithIconCachingLogic(mApp.getContext(), true), mApp.getModel()::onWidgetLabelsUpdated); - logASplit("save widgets in icon cache"); + logASplit(timingLogger, "save widgets in icon cache"); // fifth step loadFolderNames(); verifyNotStopped(); updateHandler.finish(); - logASplit("finish icon update"); + logASplit(timingLogger, "finish icon update"); mModelDelegate.modelLoadComplete(); transaction.commit(); memoryLogger.clearLogs(); } catch (CancellationException e) { // Loader stopped, ignore - logASplit("Cancelled"); + logASplit(timingLogger, "Cancelled"); } catch (Exception e) { memoryLogger.printLogs(); throw e; + } finally { + timingLogger.dumpToLog(); } TraceHelper.INSTANCE.endSection(traceToken); } @@ -330,29 +348,25 @@ public class LoaderTask implements Runnable { this.notify(); } - protected void loadWorkspace( - List allDeepShortcuts, - String selection, - LoaderMemoryLogger memoryLogger) { - Trace.beginSection("LoadWorkspace"); - try { - loadWorkspaceImpl(allDeepShortcuts, selection, memoryLogger); - } finally { - Trace.endSection(); - } - logASplit("loadWorkspace"); + private void loadWorkspace( + List allDeepShortcuts, LoaderMemoryLogger memoryLogger) { + loadWorkspace(allDeepShortcuts, Favorites.CONTENT_URI, + null /* selection */, memoryLogger); + } + protected void loadWorkspaceForPreviewSurfaceRenderer( + List allDeepShortcuts, Uri contentUri, String selection) { + loadWorkspace(allDeepShortcuts, contentUri, selection, null); if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) { - verifyNotStopped(); mModelDelegate.loadAndBindWorkspaceItems(mUserManagerState, mLauncherBinder.mCallbacksList, mShortcutKeyToPinnedShortcuts); mModelDelegate.markActive(); - logASplit("workspaceDelegateItems"); } } - private void loadWorkspaceImpl( + protected void loadWorkspace( List allDeepShortcuts, + Uri contentUri, String selection, @Nullable LoaderMemoryLogger memoryLogger) { final Context context = mApp.getContext(); @@ -363,7 +377,7 @@ public class LoaderTask implements Runnable { final WidgetManagerHelper widgetHelper = new WidgetManagerHelper(context); boolean clearDb = false; - if (!mApp.getModel().getModelDbController().migrateGridIfNeeded()) { + if (!GridSizeMigrationUtil.migrateGridIfNeeded(context)) { // Migration failed. Clear workspace. clearDb = true; } @@ -388,9 +402,8 @@ public class LoaderTask implements Runnable { mFirstScreenBroadcast = new FirstScreenBroadcast(installingPkgs); mShortcutKeyToPinnedShortcuts = new HashMap<>(); - ModelDbController dbController = mApp.getModel().getModelDbController(); final LoaderCursor c = new LoaderCursor( - dbController.query(TABLE_NAME, null, selection, null, null), + contentResolver.query(contentUri, null, selection, null, null), contentUri, mApp, mUserManagerState); final Bundle extras = c.getExtras(); mDbName = extras == null ? null : extras.getString(Settings.EXTRA_DB_NAME); @@ -1099,9 +1112,12 @@ public class LoaderTask implements Runnable { FileLog.d(TAG, widgetDimension.toString()); } - private static void logASplit(String label) { - if (DEBUG) { - Log.d(TAG, label); + private static void logASplit(@Nullable TimingLogger timingLogger, String label) { + if (timingLogger != null) { + timingLogger.addSplit(label); + if (DEBUG) { + Log.d(TAG, label); + } } } } diff --git a/src/com/android/launcher3/model/ModelDbController.java b/src/com/android/launcher3/model/ModelDbController.java index f0e5ef6bbd..97bce8c25a 100644 --- a/src/com/android/launcher3/model/ModelDbController.java +++ b/src/com/android/launcher3/model/ModelDbController.java @@ -19,10 +19,11 @@ import static android.util.Base64.NO_PADDING; import static android.util.Base64.NO_WRAP; import static com.android.launcher3.DefaultLayoutParser.RES_PARTNER_DEFAULT_LAYOUT; -import static com.android.launcher3.LauncherSettings.Favorites.addTableToDb; import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_KEY; import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_LABEL; import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_TAG; +import static com.android.launcher3.model.DatabaseHelper.EMPTY_DATABASE_CREATED; +import static com.android.launcher3.provider.LauncherDbUtils.copyTable; import static com.android.launcher3.provider.LauncherDbUtils.tableExists; import android.app.blob.BlobHandle; @@ -30,6 +31,7 @@ import android.app.blob.BlobStoreManager; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; +import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.ProviderInfo; import android.content.res.Resources; @@ -41,7 +43,6 @@ import android.os.Binder; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.Process; -import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.text.TextUtils; @@ -53,22 +54,18 @@ import androidx.annotation.WorkerThread; import com.android.launcher3.AutoInstallsLayout; import com.android.launcher3.AutoInstallsLayout.SourceResources; -import com.android.launcher3.ConstantItem; import com.android.launcher3.DefaultLayoutParser; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; -import com.android.launcher3.LauncherFiles; import com.android.launcher3.LauncherPrefs; import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.Utilities; -import com.android.launcher3.pm.UserCache; import com.android.launcher3.provider.LauncherDbUtils; import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction; import com.android.launcher3.provider.RestoreDbTask; import com.android.launcher3.util.IOUtils; import com.android.launcher3.util.IntArray; -import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext; import com.android.launcher3.util.Partner; import com.android.launcher3.widget.LauncherWidgetHolder; @@ -76,6 +73,7 @@ import org.xmlpull.v1.XmlPullParser; import java.io.InputStream; import java.io.StringReader; +import java.util.function.Supplier; /** * Utility class which maintains an instance of Launcher database and provides utility methods @@ -84,8 +82,6 @@ import java.io.StringReader; public class ModelDbController { private static final String TAG = "LauncherProvider"; - private static final String EMPTY_DATABASE_CREATED = "EMPTY_DATABASE_CREATED"; - protected DatabaseHelper mOpenHelper; private final Context mContext; @@ -96,36 +92,26 @@ public class ModelDbController { private synchronized void createDbIfNotExists() { if (mOpenHelper == null) { - mOpenHelper = createDatabaseHelper(false /* forMigration */); - RestoreDbTask.restoreIfNeeded(mContext, this); + mOpenHelper = DatabaseHelper.createDatabaseHelper( + mContext, false /* forMigration */); + + RestoreDbTask.restoreIfNeeded(mContext, mOpenHelper); } } - protected DatabaseHelper createDatabaseHelper(boolean forMigration) { - boolean isSandbox = mContext instanceof SandboxContext; - String dbName = isSandbox ? null : InvariantDeviceProfile.INSTANCE.get(mContext).dbFile; - - // Set the flag for empty DB - Runnable onEmptyDbCreateCallback = forMigration ? () -> { } - : () -> LauncherPrefs.get(mContext).putSync(getEmptyDbCreatedKey(dbName).to(true)); - - DatabaseHelper databaseHelper = new DatabaseHelper(mContext, dbName, - this::getSerialNumberForUser, onEmptyDbCreateCallback); - // Table creation sometimes fails silently, which leads to a crash loop. - // This way, we will try to create a table every time after crash, so the device - // would eventually be able to recover. - if (!tableExists(databaseHelper.getReadableDatabase(), Favorites.TABLE_NAME)) { - Log.e(TAG, "Tables are missing after onCreate has been called. Trying to recreate"); - // This operation is a no-op if the table already exists. - addTableToDb(databaseHelper.getWritableDatabase(), - getSerialNumberForUser(Process.myUserHandle()), - true /* optional */); + private synchronized boolean prepForMigration(String dbFile, String targetTableName, + Supplier src, Supplier dst) { + if (TextUtils.equals(dbFile, mOpenHelper.getDatabaseName())) { + Log.e(TAG, "prepForMigration - target db is same as current: " + dbFile); + return false; } - databaseHelper.mHotseatRestoreTableExists = tableExists( - databaseHelper.getReadableDatabase(), Favorites.HYBRID_HOTSEAT_BACKUP_TABLE); - databaseHelper.initIds(); - return databaseHelper; + final DatabaseHelper helper = src.get(); + mOpenHelper = dst.get(); + copyTable(helper.getReadableDatabase(), Favorites.TABLE_NAME, + mOpenHelper.getWritableDatabase(), targetTableName, mContext); + helper.close(); + return true; } /** @@ -281,41 +267,42 @@ public class ModelDbController { } /** - * Migrates the DB if needed, and returns false if the migration failed - * and DB needs to be cleared. - * @return true if migration was success or ignored, false if migration failed - * and the DB should be reset. + * Updates the current DB and copies all the existing data to the temp table + * @param dbFile name of the target db file name */ - public boolean migrateGridIfNeeded() { + @WorkerThread + public boolean updateCurrentOpenHelper(String dbFile) { createDbIfNotExists(); - InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext); - if (!GridSizeMigrationUtil.needsToMigrate(mContext, idp)) { - return true; - } - String targetDbName = new DeviceGridState(idp).getDbFile(); - if (TextUtils.equals(targetDbName, mOpenHelper.getDatabaseName())) { - Log.e(TAG, "migrateGridIfNeeded - target db is same as current: " + targetDbName); - return false; - } - DatabaseHelper oldHelper = mOpenHelper; - mOpenHelper = (mContext instanceof SandboxContext) ? oldHelper - : createDatabaseHelper(true /* forMigration */); - try { - return GridSizeMigrationUtil.migrateGridIfNeeded(mContext, idp, mOpenHelper, - oldHelper.getWritableDatabase()); - } finally { - if (mOpenHelper != oldHelper) { - oldHelper.close(); - } - } + return prepForMigration( + dbFile, + Favorites.TMP_TABLE, + () -> mOpenHelper, + () -> DatabaseHelper.createDatabaseHelper( + mContext, true /* forMigration */)); } /** - * Returns the underlying model database + * Returns the current DatabaseHelper. + * Only for tests */ - public SQLiteDatabase getDb() { + @WorkerThread + public DatabaseHelper getDatabaseHelper() { createDbIfNotExists(); - return mOpenHelper.getWritableDatabase(); + return mOpenHelper; + } + + /** + * Prepares the DB for preview by copying all existing data to preview table + */ + @WorkerThread + public boolean prepareForPreview(String dbFile) { + createDbIfNotExists(); + return prepForMigration( + dbFile, + Favorites.PREVIEW_TABLE_NAME, + () -> DatabaseHelper.createDatabaseHelper( + mContext, dbFile, true /* forMigration */), + () -> mOpenHelper); } private void onAddOrDeleteOp(SQLiteDatabase db) { @@ -358,7 +345,8 @@ public class ModelDbController { } private void clearFlagEmptyDbCreated() { - LauncherPrefs.get(mContext).removeSync(getEmptyDbCreatedKey(mOpenHelper.getDatabaseName())); + LauncherPrefs.getPrefs(mContext).edit() + .remove(mOpenHelper.getKey(EMPTY_DATABASE_CREATED)).commit(); } /** @@ -371,8 +359,9 @@ public class ModelDbController { @WorkerThread public synchronized void loadDefaultFavoritesIfNecessary() { createDbIfNotExists(); + SharedPreferences sp = LauncherPrefs.getPrefs(mContext); - if (LauncherPrefs.get(mContext).get(getEmptyDbCreatedKey(mOpenHelper.getDatabaseName()))) { + if (sp.getBoolean(mOpenHelper.getKey(EMPTY_DATABASE_CREATED), false)) { Log.d(TAG, "loading default workspace"); LauncherWidgetHolder widgetHolder = mOpenHelper.newLauncherWidgetHolder(); @@ -490,27 +479,4 @@ public class ModelDbController { return new DefaultLayoutParser(mContext, widgetHolder, mOpenHelper, mContext.getResources(), defaultLayout); } - - /** - * Re-composite given key in respect to database. If the current db is - * {@link LauncherFiles#LAUNCHER_DB}, return the key as-is. Otherwise append the db name to - * given key. e.g. consider key="EMPTY_DATABASE_CREATED", dbName="minimal.db", the returning - * string will be "EMPTY_DATABASE_CREATED@minimal.db". - */ - private ConstantItem getEmptyDbCreatedKey(String dbName) { - if (mContext instanceof SandboxContext) { - return LauncherPrefs.nonRestorableItem(EMPTY_DATABASE_CREATED, - false /* default value */, false /* boot aware */); - } - String key = TextUtils.equals(dbName, LauncherFiles.LAUNCHER_DB) - ? EMPTY_DATABASE_CREATED : EMPTY_DATABASE_CREATED + "@" + dbName; - return LauncherPrefs.backedUpItem(key, false /* default value */, false /* boot aware */); - } - - /** - * Returns the serial number for the provided user - */ - public long getSerialNumberForUser(UserHandle user) { - return UserCache.INSTANCE.get(mContext).getSerialNumberForUser(user); - } } diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.java b/src/com/android/launcher3/provider/LauncherDbUtils.java index c718dcc877..48969fc44e 100644 --- a/src/com/android/launcher3/provider/LauncherDbUtils.java +++ b/src/com/android/launcher3/provider/LauncherDbUtils.java @@ -101,7 +101,7 @@ public class LauncherDbUtils { UserManagerState ums = new UserManagerState(); ums.init(UserCache.INSTANCE.get(context), context.getSystemService(UserManager.class)); - LoaderCursor lc = new LoaderCursor(c, LauncherAppState.getInstance(context), ums); + LoaderCursor lc = new LoaderCursor(c, null, LauncherAppState.getInstance(context), ums); IntSet deletedShortcuts = new IntSet(); while (lc.moveToNext()) { diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java index a6e064a4ed..ac7216449b 100644 --- a/src/com/android/launcher3/provider/RestoreDbTask.java +++ b/src/com/android/launcher3/provider/RestoreDbTask.java @@ -16,8 +16,6 @@ package com.android.launcher3.provider; -import static android.os.Process.myUserHandle; - import static com.android.launcher3.InvariantDeviceProfile.TYPE_MULTI_DISPLAY; import static com.android.launcher3.LauncherPrefs.APP_WIDGET_IDS; import static com.android.launcher3.LauncherPrefs.OLD_APP_WIDGET_IDS; @@ -49,8 +47,8 @@ import com.android.launcher3.LauncherPrefs; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.Utilities; import com.android.launcher3.logging.FileLog; +import com.android.launcher3.model.DatabaseHelper; import com.android.launcher3.model.DeviceGridState; -import com.android.launcher3.model.ModelDbController; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.LauncherAppWidgetInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; @@ -85,12 +83,12 @@ public class RestoreDbTask { /** * Tries to restore the backup DB if needed */ - public static void restoreIfNeeded(Context context, ModelDbController dbController) { + public static void restoreIfNeeded(Context context, DatabaseHelper helper) { if (!isPending(context)) { return; } - if (!performRestore(context, dbController)) { - dbController.createEmptyDB(); + if (!performRestore(context, helper)) { + helper.createEmptyDB(helper.getWritableDatabase()); } // Obtain InvariantDeviceProfile first before setting pending to false, so @@ -104,12 +102,12 @@ public class RestoreDbTask { idp.reinitializeAfterRestore(context); } - private static boolean performRestore(Context context, ModelDbController controller) { - SQLiteDatabase db = controller.getDb(); + private static boolean performRestore(Context context, DatabaseHelper helper) { + SQLiteDatabase db = helper.getWritableDatabase(); try (SQLiteTransaction t = new SQLiteTransaction(db)) { RestoreDbTask task = new RestoreDbTask(); - task.sanitizeDB(context, controller, db, new BackupManager(context)); - task.restoreAppWidgetIdsIfExists(context, controller); + task.sanitizeDB(context, helper, db, new BackupManager(context)); + task.restoreAppWidgetIdsIfExists(context, helper); t.commit(); return true; } catch (Exception e) { @@ -131,10 +129,10 @@ public class RestoreDbTask { * @return number of items deleted. */ @VisibleForTesting - protected int sanitizeDB(Context context, ModelDbController controller, SQLiteDatabase db, + protected int sanitizeDB(Context context, DatabaseHelper helper, SQLiteDatabase db, BackupManager backupManager) throws Exception { // Primary user ids - long myProfileId = controller.getSerialNumberForUser(myUserHandle()); + long myProfileId = helper.getDefaultUserSerial(); long oldProfileId = getDefaultProfileId(db); LongSparseArray oldManagedProfileIds = getManagedProfileIds(db, oldProfileId); LongSparseArray profileMapping = new LongSparseArray<>(oldManagedProfileIds.size() @@ -146,7 +144,7 @@ public class RestoreDbTask { long oldManagedProfileId = oldManagedProfileIds.keyAt(i); UserHandle user = getUserForAncestralSerialNumber(backupManager, oldManagedProfileId); if (user != null) { - long newManagedProfileId = controller.getSerialNumberForUser(user); + long newManagedProfileId = helper.getSerialNumberForUser(user); profileMapping.put(oldManagedProfileId, newManagedProfileId); } } @@ -215,7 +213,7 @@ public class RestoreDbTask { } // Override shortcuts - maybeOverrideShortcuts(context, controller, db, myProfileId); + maybeOverrideShortcuts(context, helper, db, myProfileId); return itemsDeleted; } @@ -323,11 +321,11 @@ public class RestoreDbTask { .putSync(RESTORE_DEVICE.to(new DeviceGridState(context).getDeviceType())); } - private void restoreAppWidgetIdsIfExists(Context context, ModelDbController controller) { + private void restoreAppWidgetIdsIfExists(Context context, DatabaseHelper helper) { LauncherPrefs lp = LauncherPrefs.get(context); if (lp.has(APP_WIDGET_IDS, OLD_APP_WIDGET_IDS)) { AppWidgetHost host = new AppWidgetHost(context, APPWIDGET_HOST_ID); - AppWidgetsRestoredReceiver.restoreAppWidgetIds(context, controller, + AppWidgetsRestoredReceiver.restoreAppWidgetIds(context, helper, IntArray.fromConcatString(lp.get(OLD_APP_WIDGET_IDS)).toArray(), IntArray.fromConcatString(lp.get(APP_WIDGET_IDS)).toArray(), host); @@ -345,7 +343,7 @@ public class RestoreDbTask { APP_WIDGET_IDS.to(IntArray.wrap(newIds).toConcatString())); } - protected static void maybeOverrideShortcuts(Context context, ModelDbController controller, + protected static void maybeOverrideShortcuts(Context context, DatabaseHelper helper, SQLiteDatabase db, long currentUser) { Map activityOverrides = ApiWrapper.getActivityOverrides( context); @@ -369,7 +367,7 @@ public class RestoreDbTask { if (override != null) { ContentValues values = new ContentValues(); values.put(Favorites.PROFILE_ID, - controller.getSerialNumberForUser(override.getUser())); + helper.getSerialNumberForUser(override.getUser())); values.put(Favorites.INTENT, AppInfo.makeLaunchIntent(override).toUri(0)); db.update(Favorites.TABLE_NAME, values, String.format("%s=?", Favorites._ID), new String[]{String.valueOf(c.getInt(idIndex))}); diff --git a/src/com/android/launcher3/util/ContentWriter.java b/src/com/android/launcher3/util/ContentWriter.java index 7c5ef4db0c..e509235688 100644 --- a/src/com/android/launcher3/util/ContentWriter.java +++ b/src/com/android/launcher3/util/ContentWriter.java @@ -26,7 +26,7 @@ import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.icons.GraphicsUtils; -import com.android.launcher3.model.ModelDbController; +import com.android.launcher3.model.DatabaseHelper; import com.android.launcher3.pm.UserCache; /** @@ -106,7 +106,7 @@ public class ContentWriter { public int commit() { if (mCommitParams != null) { - mCommitParams.mDbController.update( + mCommitParams.mDatabaseHelper.getWritableDatabase().update( Favorites.TABLE_NAME, getValues(mContext), mCommitParams.mWhere, mCommitParams.mSelectionArgs); } @@ -115,12 +115,12 @@ public class ContentWriter { public static final class CommitParams { - final ModelDbController mDbController; + final DatabaseHelper mDatabaseHelper; final String mWhere; final String[] mSelectionArgs; - public CommitParams(ModelDbController controller, String where, String[] selectionArgs) { - mDbController = controller; + public CommitParams(DatabaseHelper helper, String where, String[] selectionArgs) { + mDatabaseHelper = helper; mWhere = where; mSelectionArgs = selectionArgs; } diff --git a/tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java b/tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java index cea95e5a50..0a1a9ba6a9 100644 --- a/tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java +++ b/tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java @@ -39,7 +39,6 @@ import androidx.test.platform.app.InstrumentationRegistry; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.R; -import com.android.launcher3.pm.UserCache; import org.junit.Before; import org.junit.Test; @@ -223,9 +222,7 @@ public class DbDowngradeHelperTest { private class MyDatabaseHelper extends DatabaseHelper { MyDatabaseHelper() { - super(mContext, DB_FILE, - UserCache.INSTANCE.get(mContext)::getSerialNumberForUser, - () -> { }); + super(mContext, DB_FILE, false); } @Override diff --git a/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt b/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt index 63dbaa752d..f24f0dab76 100644 --- a/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt +++ b/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt @@ -15,7 +15,6 @@ */ package com.android.launcher3.model -import android.content.ContentValues import android.content.Context import android.content.Intent import android.database.Cursor @@ -24,7 +23,6 @@ import android.graphics.Point import android.os.Process import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest -import androidx.test.platform.app.InstrumentationRegistry import com.android.launcher3.InvariantDeviceProfile import com.android.launcher3.LauncherPrefs import com.android.launcher3.LauncherPrefs.Companion.WORKSPACE_SIZE @@ -33,7 +31,10 @@ import com.android.launcher3.config.FeatureFlags import com.android.launcher3.model.GridSizeMigrationUtil.DbReader import com.android.launcher3.pm.UserCache import com.android.launcher3.provider.LauncherDbUtils +import com.android.launcher3.util.LauncherModelHelper +import com.android.launcher3.util.LauncherModelHelper.* import com.google.common.truth.Truth.assertThat +import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -42,12 +43,11 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class GridSizeMigrationUtilTest { - + private lateinit var modelHelper: LauncherModelHelper private lateinit var context: Context + private lateinit var db: SQLiteDatabase private lateinit var validPackages: Set private lateinit var idp: InvariantDeviceProfile - private lateinit var dbHelper: DatabaseHelper - private lateinit var db: SQLiteDatabase private val testPackage1 = "com.android.launcher3.validpackage1" private val testPackage2 = "com.android.launcher3.validpackage2" private val testPackage3 = "com.android.launcher3.validpackage3" @@ -61,17 +61,13 @@ class GridSizeMigrationUtilTest { @Before fun setUp() { - context = InstrumentationRegistry.getInstrumentation().targetContext - dbHelper = - DatabaseHelper( - context, - null, - UserCache.INSTANCE.get(context)::getSerialNumberForUser - ) {} - db = dbHelper.writableDatabase + modelHelper = LauncherModelHelper() + context = modelHelper.sandboxContext + db = modelHelper.provider.db validPackages = setOf( + TEST_PACKAGE, testPackage1, testPackage2, testPackage3, @@ -90,6 +86,11 @@ class GridSizeMigrationUtilTest { addTableToDb(db, userSerial, false, TMP_TABLE) } + @After + fun tearDown() { + modelHelper.destroy() + } + /** * Old migration logic, should be modified once [FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC] is not * needed anymore @@ -98,26 +99,26 @@ class GridSizeMigrationUtilTest { @Throws(Exception::class) fun testMigration() { // Src Hotseat icons - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_HOTSEAT, 0, 0, testPackage1, 1, TMP_TABLE) - addItem(ITEM_TYPE_SHORTCUT, 1, CONTAINER_HOTSEAT, 0, 0, testPackage2, 2, TMP_TABLE) - addItem(ITEM_TYPE_SHORTCUT, 3, CONTAINER_HOTSEAT, 0, 0, testPackage3, 3, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 4, CONTAINER_HOTSEAT, 0, 0, testPackage4, 4, TMP_TABLE) + modelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI) + modelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI) + modelHelper.addItem(SHORTCUT, 3, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 4, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI) // Src grid icons // _ _ _ _ _ // _ _ _ _ 5 // _ _ 6 _ 7 // _ _ 8 _ 9 // _ _ _ _ _ - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 4, 1, testPackage5, 5, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 2, testPackage6, 6, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 4, 2, testPackage7, 7, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 3, testPackage8, 8, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 4, 3, testPackage9, 9, TMP_TABLE) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 4, 1, testPackage5, 5, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 2, testPackage6, 6, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 4, 2, testPackage7, 7, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 3, testPackage8, 8, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 4, 3, testPackage9, 9, TMP_CONTENT_URI) // Dest hotseat icons - addItem(ITEM_TYPE_SHORTCUT, 1, CONTAINER_HOTSEAT, 0, 0, testPackage2) + modelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2) // Dest grid icons - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 2, testPackage10) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 2, testPackage10) idp.numDatabaseHotseatIcons = 4 idp.numColumns = 4 @@ -125,7 +126,8 @@ class GridSizeMigrationUtilTest { val srcReader = DbReader(db, TMP_TABLE, context, validPackages) val destReader = DbReader(db, TABLE_NAME, context, validPackages) GridSizeMigrationUtil.migrate( - dbHelper, + context, + db, srcReader, destReader, idp.numDatabaseHotseatIcons, @@ -136,13 +138,12 @@ class GridSizeMigrationUtilTest { // Check hotseat items var c = - db.query( - TABLE_NAME, + context.contentResolver.query( + CONTENT_URI, arrayOf(SCREEN, INTENT), "container=$CONTAINER_HOTSEAT", null, SCREEN, - null, null ) ?: throw IllegalStateException() @@ -167,13 +168,12 @@ class GridSizeMigrationUtilTest { // Check workspace items c = - db.query( - TABLE_NAME, + context.contentResolver.query( + CONTENT_URI, arrayOf(CELLX, CELLY, INTENT), "container=$CONTAINER_DESKTOP", null, null, - null, null ) ?: throw IllegalStateException() @@ -209,30 +209,30 @@ class GridSizeMigrationUtilTest { fun testMigrationBackAndForth() { // Hotseat items in grid A // 1 2 _ 3 4 - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_HOTSEAT, 0, 0, testPackage1, 1, TMP_TABLE) - addItem(ITEM_TYPE_SHORTCUT, 1, CONTAINER_HOTSEAT, 0, 0, testPackage2, 2, TMP_TABLE) - addItem(ITEM_TYPE_SHORTCUT, 3, CONTAINER_HOTSEAT, 0, 0, testPackage3, 3, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 4, CONTAINER_HOTSEAT, 0, 0, testPackage4, 4, TMP_TABLE) + modelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI) + modelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI) + modelHelper.addItem(SHORTCUT, 3, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 4, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI) // Workspace items in grid A // _ _ _ _ _ // _ _ _ _ 5 // _ _ 6 _ 7 // _ _ 8 _ _ // _ _ _ _ _ - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 4, 1, testPackage5, 5, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 2, testPackage6, 6, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 4, 2, testPackage7, 7, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 3, testPackage8, 8, TMP_TABLE) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 4, 1, testPackage5, 5, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 2, testPackage6, 6, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 4, 2, testPackage7, 7, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 3, testPackage8, 8, TMP_CONTENT_URI) // Hotseat items in grid B // 2 _ _ _ - addItem(ITEM_TYPE_SHORTCUT, 0, CONTAINER_HOTSEAT, 0, 0, testPackage2) + modelHelper.addItem(SHORTCUT, 0, HOTSEAT, 0, 0, testPackage2) // Workspace items in grid B // _ _ _ _ // _ _ _ 10 // _ _ _ _ // _ _ _ _ - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 1, 3, testPackage10) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 1, 3, testPackage10) idp.numDatabaseHotseatIcons = 4 idp.numColumns = 4 @@ -241,7 +241,8 @@ class GridSizeMigrationUtilTest { val readerGridB = DbReader(db, TABLE_NAME, context, validPackages) // migrate from A -> B GridSizeMigrationUtil.migrate( - dbHelper, + context, + db, readerGridA, readerGridB, idp.numDatabaseHotseatIcons, @@ -252,13 +253,12 @@ class GridSizeMigrationUtilTest { // Check hotseat items in grid B var c = - db.query( - TABLE_NAME, + context.contentResolver.query( + CONTENT_URI, arrayOf(SCREEN, INTENT), "container=$CONTAINER_HOTSEAT", null, SCREEN, - null, null ) ?: throw IllegalStateException() @@ -272,13 +272,12 @@ class GridSizeMigrationUtilTest { // Check workspace items in grid B c = - db.query( - TABLE_NAME, + context.contentResolver.query( + CONTENT_URI, arrayOf(SCREEN, CELLX, CELLY, INTENT), "container=$CONTAINER_DESKTOP", null, null, - null, null ) ?: throw IllegalStateException() @@ -295,11 +294,12 @@ class GridSizeMigrationUtilTest { assertThat(locMap[testPackage8]).isEqualTo(Triple(0, 3, 1)) // add item in B - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 0, 2, testPackage9) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 0, 2, testPackage9) // migrate from B -> A GridSizeMigrationUtil.migrate( - dbHelper, + context, + db, readerGridB, readerGridA, 5, @@ -309,13 +309,12 @@ class GridSizeMigrationUtilTest { ) // Check hotseat items in grid A c = - db.query( - TMP_TABLE, + context.contentResolver.query( + TMP_CONTENT_URI, arrayOf(SCREEN, INTENT), "container=$CONTAINER_HOTSEAT", null, SCREEN, - null, null ) ?: throw IllegalStateException() @@ -329,13 +328,12 @@ class GridSizeMigrationUtilTest { // Check workspace items in grid A c = - db.query( - TMP_TABLE, + context.contentResolver.query( + TMP_CONTENT_URI, arrayOf(SCREEN, CELLX, CELLY, INTENT), "container=$CONTAINER_DESKTOP", null, null, - null, null ) ?: throw IllegalStateException() @@ -356,11 +354,12 @@ class GridSizeMigrationUtilTest { assertThat(locMap[testPackage9]).isEqualTo(Triple(0, 0, 2)) // remove item from B - db.delete(TMP_TABLE, "$_ID=7", null) + modelHelper.deleteItem(7, TMP_TABLE) // migrate from A -> B GridSizeMigrationUtil.migrate( - dbHelper, + context, + db, readerGridA, readerGridB, idp.numDatabaseHotseatIcons, @@ -371,13 +370,12 @@ class GridSizeMigrationUtilTest { // Check hotseat items in grid B c = - db.query( - TABLE_NAME, + context.contentResolver.query( + CONTENT_URI, arrayOf(SCREEN, INTENT), "container=$CONTAINER_HOTSEAT", null, SCREEN, - null, null ) ?: throw IllegalStateException() @@ -391,13 +389,12 @@ class GridSizeMigrationUtilTest { // Check workspace items in grid B c = - db.query( - TABLE_NAME, + context.contentResolver.query( + CONTENT_URI, arrayOf(SCREEN, CELLX, CELLY, INTENT), "container=$CONTAINER_DESKTOP", null, null, - null, null ) ?: throw IllegalStateException() @@ -446,28 +443,10 @@ class GridSizeMigrationUtilTest { fun migrateToLargerHotseat() { val srcHotseatItems = intArrayOf( - addItem( - ITEM_TYPE_APPLICATION, - 0, - CONTAINER_HOTSEAT, - 0, - 0, - testPackage1, - 1, - TMP_TABLE - ), - addItem(ITEM_TYPE_SHORTCUT, 1, CONTAINER_HOTSEAT, 0, 0, testPackage2, 2, TMP_TABLE), - addItem( - ITEM_TYPE_APPLICATION, - 2, - CONTAINER_HOTSEAT, - 0, - 0, - testPackage3, - 3, - TMP_TABLE - ), - addItem(ITEM_TYPE_SHORTCUT, 3, CONTAINER_HOTSEAT, 0, 0, testPackage4, 4, TMP_TABLE) + modelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI), + modelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI), + modelHelper.addItem(APP_ICON, 2, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI), + modelHelper.addItem(SHORTCUT, 3, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI) ) val numSrcDatabaseHotseatIcons = srcHotseatItems.size idp.numDatabaseHotseatIcons = 6 @@ -476,7 +455,8 @@ class GridSizeMigrationUtilTest { val srcReader = DbReader(db, TMP_TABLE, context, validPackages) val destReader = DbReader(db, TABLE_NAME, context, validPackages) GridSizeMigrationUtil.migrate( - dbHelper, + context, + db, srcReader, destReader, idp.numDatabaseHotseatIcons, @@ -487,13 +467,12 @@ class GridSizeMigrationUtilTest { // Check hotseat items val c = - db.query( - TABLE_NAME, + context.contentResolver.query( + CONTENT_URI, arrayOf(SCREEN, INTENT), "container=$CONTAINER_HOTSEAT", null, SCREEN, - null, null ) ?: throw IllegalStateException() @@ -522,11 +501,11 @@ class GridSizeMigrationUtilTest { @Test fun migrateFromLargerHotseat() { - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_HOTSEAT, 0, 0, testPackage1, 1, TMP_TABLE) - addItem(ITEM_TYPE_SHORTCUT, 2, CONTAINER_HOTSEAT, 0, 0, testPackage2, 2, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 3, CONTAINER_HOTSEAT, 0, 0, testPackage3, 3, TMP_TABLE) - addItem(ITEM_TYPE_SHORTCUT, 4, CONTAINER_HOTSEAT, 0, 0, testPackage4, 4, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 5, CONTAINER_HOTSEAT, 0, 0, testPackage5, 5, TMP_TABLE) + modelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI) + modelHelper.addItem(SHORTCUT, 2, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 3, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI) + modelHelper.addItem(SHORTCUT, 4, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 5, HOTSEAT, 0, 0, testPackage5, 5, TMP_CONTENT_URI) idp.numDatabaseHotseatIcons = 4 idp.numColumns = 4 @@ -534,7 +513,8 @@ class GridSizeMigrationUtilTest { val srcReader = DbReader(db, TMP_TABLE, context, validPackages) val destReader = DbReader(db, TABLE_NAME, context, validPackages) GridSizeMigrationUtil.migrate( - dbHelper, + context, + db, srcReader, destReader, idp.numDatabaseHotseatIcons, @@ -545,13 +525,12 @@ class GridSizeMigrationUtilTest { // Check hotseat items val c = - db.query( - TABLE_NAME, + context.contentResolver.query( + CONTENT_URI, arrayOf(SCREEN, INTENT), "container=$CONTAINER_HOTSEAT", null, SCREEN, - null, null ) ?: throw IllegalStateException() @@ -589,11 +568,11 @@ class GridSizeMigrationUtilTest { enableNewMigrationLogic("4,4") // Setup src grid - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 2, testPackage1, 5, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 3, testPackage2, 6, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 1, CONTAINER_DESKTOP, 3, 1, testPackage3, 7, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 1, CONTAINER_DESKTOP, 3, 2, testPackage4, 8, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 2, CONTAINER_DESKTOP, 3, 3, testPackage5, 9, TMP_TABLE) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 2, testPackage1, 5, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 3, testPackage2, 6, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 1, DESKTOP, 3, 1, testPackage3, 7, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 1, DESKTOP, 3, 2, testPackage4, 8, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 2, DESKTOP, 3, 3, testPackage5, 9, TMP_CONTENT_URI) idp.numDatabaseHotseatIcons = 4 idp.numColumns = 6 @@ -602,7 +581,8 @@ class GridSizeMigrationUtilTest { val srcReader = DbReader(db, TMP_TABLE, context, validPackages) val destReader = DbReader(db, TABLE_NAME, context, validPackages) GridSizeMigrationUtil.migrate( - dbHelper, + context, + db, srcReader, destReader, idp.numDatabaseHotseatIcons, @@ -613,13 +593,12 @@ class GridSizeMigrationUtilTest { // Get workspace items val c = - db.query( - TABLE_NAME, + context.contentResolver.query( + CONTENT_URI, arrayOf(INTENT, SCREEN), "container=$CONTAINER_DESKTOP", null, null, - null, null ) ?: throw IllegalStateException() @@ -651,11 +630,11 @@ class GridSizeMigrationUtilTest { enableNewMigrationLogic("2,2") // Setup src grid - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 0, 1, testPackage1, 5, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 1, 1, testPackage2, 6, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 1, CONTAINER_DESKTOP, 0, 0, testPackage3, 7, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 1, CONTAINER_DESKTOP, 1, 0, testPackage4, 8, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 2, CONTAINER_DESKTOP, 0, 0, testPackage5, 9, TMP_TABLE) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 0, 1, testPackage1, 5, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 1, 1, testPackage2, 6, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 1, DESKTOP, 0, 0, testPackage3, 7, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 1, DESKTOP, 1, 0, testPackage4, 8, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 2, DESKTOP, 0, 0, testPackage5, 9, TMP_CONTENT_URI) idp.numDatabaseHotseatIcons = 4 idp.numColumns = 5 @@ -663,7 +642,8 @@ class GridSizeMigrationUtilTest { val srcReader = DbReader(db, TMP_TABLE, context, validPackages) val destReader = DbReader(db, TABLE_NAME, context, validPackages) GridSizeMigrationUtil.migrate( - dbHelper, + context, + db, srcReader, destReader, idp.numDatabaseHotseatIcons, @@ -674,13 +654,12 @@ class GridSizeMigrationUtilTest { // Get workspace items val c = - db.query( - TABLE_NAME, + context.contentResolver.query( + CONTENT_URI, arrayOf(INTENT, SCREEN), "container=$CONTAINER_DESKTOP", null, null, - null, null ) ?: throw IllegalStateException() @@ -712,11 +691,11 @@ class GridSizeMigrationUtilTest { enableNewMigrationLogic("5,5") // Setup src grid - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 0, 1, testPackage1, 5, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 1, 1, testPackage2, 6, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 1, CONTAINER_DESKTOP, 0, 0, testPackage3, 7, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 1, CONTAINER_DESKTOP, 1, 0, testPackage4, 8, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 2, CONTAINER_DESKTOP, 0, 0, testPackage5, 9, TMP_TABLE) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 0, 1, testPackage1, 5, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 1, 1, testPackage2, 6, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 1, DESKTOP, 0, 0, testPackage3, 7, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 1, DESKTOP, 1, 0, testPackage4, 8, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 2, DESKTOP, 0, 0, testPackage5, 9, TMP_CONTENT_URI) idp.numDatabaseHotseatIcons = 4 idp.numColumns = 4 @@ -724,7 +703,8 @@ class GridSizeMigrationUtilTest { val srcReader = DbReader(db, TMP_TABLE, context, validPackages) val destReader = DbReader(db, TABLE_NAME, context, validPackages) GridSizeMigrationUtil.migrate( - dbHelper, + context, + db, srcReader, destReader, idp.numDatabaseHotseatIcons, @@ -735,13 +715,12 @@ class GridSizeMigrationUtilTest { // Get workspace items val c = - db.query( - TABLE_NAME, + context.contentResolver.query( + CONTENT_URI, arrayOf(INTENT, SCREEN), "container=$CONTAINER_DESKTOP", null, null, - null, null ) ?: throw IllegalStateException() @@ -768,48 +747,4 @@ class GridSizeMigrationUtilTest { private fun enableNewMigrationLogic(srcGridSize: String) { LauncherPrefs.get(context).putSync(WORKSPACE_SIZE.to(srcGridSize)) } - - private fun addItem( - type: Int, - screen: Int, - container: Int, - x: Int, - y: Int, - packageName: String? - ): Int { - return addItem( - type, - screen, - container, - x, - y, - packageName, - dbHelper.generateNewItemId(), - TABLE_NAME - ) - } - - private fun addItem( - type: Int, - screen: Int, - container: Int, - x: Int, - y: Int, - packageName: String?, - id: Int, - tableName: String - ): Int { - val values = ContentValues() - values.put(_ID, id) - values.put(CONTAINER, container) - values.put(SCREEN, screen) - values.put(CELLX, x) - values.put(CELLY, y) - values.put(SPANX, 1) - values.put(SPANY, 1) - values.put(ITEM_TYPE, type) - values.put(INTENT, Intent(Intent.ACTION_MAIN).setPackage(packageName).toUri(0)) - db.insert(tableName, null, values) - return id - } } diff --git a/tests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/src/com/android/launcher3/model/LoaderCursorTest.java index 78812c0778..d192be408c 100644 --- a/tests/src/com/android/launcher3/model/LoaderCursorTest.java +++ b/tests/src/com/android/launcher3/model/LoaderCursorTest.java @@ -59,6 +59,7 @@ import androidx.test.filters.SmallTest; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.util.Executors; @@ -101,7 +102,7 @@ public class LoaderCursorTest { }); UserManagerState ums = new UserManagerState(); - mLoaderCursor = new LoaderCursor(mCursor, mApp, ums); + mLoaderCursor = new LoaderCursor(mCursor, Favorites.CONTENT_URI, mApp, ums); ums.allUsers.put(0, Process.myUserHandle()); } diff --git a/tests/src/com/android/launcher3/provider/LauncherDbUtilsTest.java b/tests/src/com/android/launcher3/provider/LauncherDbUtilsTest.java index 54b8489134..2b6f9ff193 100644 --- a/tests/src/com/android/launcher3/provider/LauncherDbUtilsTest.java +++ b/tests/src/com/android/launcher3/provider/LauncherDbUtilsTest.java @@ -45,7 +45,6 @@ import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.R; import com.android.launcher3.model.DatabaseHelper; import com.android.launcher3.model.DbDowngradeHelper; -import com.android.launcher3.pm.UserCache; import com.android.launcher3.settings.SettingsActivity; import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.util.IOUtils; @@ -166,11 +165,12 @@ public class LauncherDbUtilsTest { private class MyDatabaseHelper extends DatabaseHelper { MyDatabaseHelper() { - super(mContext, null, UserCache.INSTANCE.get(mContext)::getSerialNumberForUser, - () -> { }); + super(mContext, null, false); } @Override protected void handleOneTimeDataUpgrade(SQLiteDatabase db) { } + + protected void onEmptyDbCreated() { } } } diff --git a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java index 73bb5865ee..67de1f5fb1 100644 --- a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java +++ b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java @@ -45,11 +45,8 @@ import androidx.test.filters.SmallTest; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings.Favorites; -import com.android.launcher3.model.ModelDbController; -import com.android.launcher3.util.LauncherModelHelper; +import com.android.launcher3.model.DatabaseHelper; -import org.junit.After; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -64,29 +61,15 @@ public class RestoreDbTaskTest { private final UserHandle mWorkUser = UserHandle.getUserHandleForUid(PER_USER_RANGE); - private LauncherModelHelper mModelHelper; - private Context mContext; - - @Before - public void setup() { - mModelHelper = new LauncherModelHelper(); - mContext = mModelHelper.sandboxContext; - } - - @After - public void teardown() { - mModelHelper.destroy(); - } - @Test public void testGetProfileId() throws Exception { - SQLiteDatabase db = new MyModelDbController(23).getDb(); + SQLiteDatabase db = new MyDatabaseHelper(23).getWritableDatabase(); assertEquals(23, new RestoreDbTask().getDefaultProfileId(db)); } @Test public void testMigrateProfileId() throws Exception { - SQLiteDatabase db = new MyModelDbController(42).getDb(); + SQLiteDatabase db = new MyDatabaseHelper(42).getWritableDatabase(); // Add some mock data for (int i = 0; i < 5; i++) { ContentValues values = new ContentValues(); @@ -106,7 +89,7 @@ public class RestoreDbTaskTest { @Test public void testChangeDefaultColumn() throws Exception { - SQLiteDatabase db = new MyModelDbController(42).getDb(); + SQLiteDatabase db = new MyDatabaseHelper(42).getWritableDatabase(); // Add some mock data for (int i = 0; i < 5; i++) { ContentValues values = new ContentValues(); @@ -129,27 +112,28 @@ public class RestoreDbTaskTest { @Test public void testSanitizeDB_bothProfiles() throws Exception { + Context context = getInstrumentation().getTargetContext(); UserHandle myUser = myUserHandle(); - long myProfileId = mContext.getSystemService(UserManager.class) + long myProfileId = context.getSystemService(UserManager.class) .getSerialNumberForUser(myUser); long myProfileId_old = myProfileId + 1; long workProfileId = myProfileId + 2; long workProfileId_old = myProfileId + 3; - MyModelDbController controller = new MyModelDbController(myProfileId); - SQLiteDatabase db = controller.getDb(); - BackupManager bm = spy(new BackupManager(mContext)); + MyDatabaseHelper helper = new MyDatabaseHelper(myProfileId); + SQLiteDatabase db = helper.getWritableDatabase(); + BackupManager bm = spy(new BackupManager(context)); doReturn(myUserHandle()).when(bm).getUserForAncestralSerialNumber(eq(myProfileId_old)); doReturn(mWorkUser).when(bm).getUserForAncestralSerialNumber(eq(workProfileId_old)); - controller.users.put(workProfileId, mWorkUser); + helper.users.put(workProfileId, mWorkUser); - addIconsBulk(controller, 10, 1, myProfileId_old); - addIconsBulk(controller, 6, 2, workProfileId_old); + addIconsBulk(helper, 10, 1, myProfileId_old); + addIconsBulk(helper, 6, 2, workProfileId_old); assertEquals(10, getItemCountForProfile(db, myProfileId_old)); assertEquals(6, getItemCountForProfile(db, workProfileId_old)); RestoreDbTask task = new RestoreDbTask(); - task.sanitizeDB(mContext, controller, controller.getDb(), bm); + task.sanitizeDB(context, helper, helper.getWritableDatabase(), bm); // All the data has been migrated to the new user ids assertEquals(0, getItemCountForProfile(db, myProfileId_old)); @@ -160,26 +144,27 @@ public class RestoreDbTaskTest { @Test public void testSanitizeDB_workItemsRemoved() throws Exception { + Context context = getInstrumentation().getTargetContext(); UserHandle myUser = myUserHandle(); - long myProfileId = mContext.getSystemService(UserManager.class) + long myProfileId = context.getSystemService(UserManager.class) .getSerialNumberForUser(myUser); long myProfileId_old = myProfileId + 1; long workProfileId_old = myProfileId + 3; - MyModelDbController controller = new MyModelDbController(myProfileId); - SQLiteDatabase db = controller.getDb(); - BackupManager bm = spy(new BackupManager(mContext)); + MyDatabaseHelper helper = new MyDatabaseHelper(myProfileId); + SQLiteDatabase db = helper.getWritableDatabase(); + BackupManager bm = spy(new BackupManager(context)); doReturn(myUserHandle()).when(bm).getUserForAncestralSerialNumber(eq(myProfileId_old)); // Work profile is not migrated doReturn(null).when(bm).getUserForAncestralSerialNumber(eq(workProfileId_old)); - addIconsBulk(controller, 10, 1, myProfileId_old); - addIconsBulk(controller, 6, 2, workProfileId_old); + addIconsBulk(helper, 10, 1, myProfileId_old); + addIconsBulk(helper, 6, 2, workProfileId_old); assertEquals(10, getItemCountForProfile(db, myProfileId_old)); assertEquals(6, getItemCountForProfile(db, workProfileId_old)); RestoreDbTask task = new RestoreDbTask(); - task.sanitizeDB(mContext, controller, controller.getDb(), bm); + task.sanitizeDB(context, helper, helper.getWritableDatabase(), bm); // All the data has been migrated to the new user ids assertEquals(0, getItemCountForProfile(db, myProfileId_old)); @@ -188,13 +173,12 @@ public class RestoreDbTaskTest { assertEquals(10, getCount(db, "select * from favorites")); } - private void addIconsBulk(MyModelDbController controller, - int count, int screen, long profileId) { - int columns = LauncherAppState.getIDP(mContext).numColumns; + private void addIconsBulk(DatabaseHelper helper, int count, int screen, long profileId) { + int columns = LauncherAppState.getIDP(getInstrumentation().getTargetContext()).numColumns; String packageName = getInstrumentation().getContext().getPackageName(); for (int i = 0; i < count; i++) { ContentValues values = new ContentValues(); - values.put(LauncherSettings.Favorites._ID, controller.generateNewItemId()); + values.put(LauncherSettings.Favorites._ID, helper.generateNewItemId()); values.put(LauncherSettings.Favorites.CONTAINER, CONTAINER_DESKTOP); values.put(LauncherSettings.Favorites.SCREEN, screen); values.put(LauncherSettings.Favorites.CELLX, i % columns); @@ -205,11 +189,11 @@ public class RestoreDbTaskTest { values.put(LauncherSettings.Favorites.ITEM_TYPE, ITEM_TYPE_APPLICATION); values.put(LauncherSettings.Favorites.INTENT, new Intent(Intent.ACTION_MAIN).setPackage(packageName).toUri(0)); - - controller.insert(TABLE_NAME, values); + helper.getWritableDatabase().insert(TABLE_NAME, null, values); } } + @Test public void testRemoveScreenIdGaps_firstScreenEmpty() { runRemoveScreenIdGapsTest( @@ -232,7 +216,7 @@ public class RestoreDbTaskTest { } private void runRemoveScreenIdGapsTest(int[] screenIds, int[] expectedScreenIds) { - SQLiteDatabase db = new MyModelDbController(42).getDb(); + SQLiteDatabase db = new MyDatabaseHelper(42).getWritableDatabase(); // Add some mock data for (int i = 0; i < screenIds.length; i++) { ContentValues values = new ContentValues(); @@ -270,12 +254,13 @@ public class RestoreDbTaskTest { } } - private class MyModelDbController extends ModelDbController { + private class MyDatabaseHelper extends DatabaseHelper { - public final LongSparseArray users = new LongSparseArray<>(); + public final LongSparseArray users; - MyModelDbController(long profileId) { - super(mContext); + MyDatabaseHelper(long profileId) { + super(getInstrumentation().getTargetContext(), null, false); + users = new LongSparseArray<>(); users.put(profileId, myUserHandle()); } @@ -284,5 +269,10 @@ public class RestoreDbTaskTest { int index = users.indexOfValue(user); return index >= 0 ? users.keyAt(index) : -1; } + + @Override + protected void handleOneTimeDataUpgrade(SQLiteDatabase db) { } + + protected void onEmptyDbCreated() { } } } diff --git a/tests/src/com/android/launcher3/util/LauncherModelHelper.java b/tests/src/com/android/launcher3/util/LauncherModelHelper.java index 6fca965600..bf31e39ccc 100644 --- a/tests/src/com/android/launcher3/util/LauncherModelHelper.java +++ b/tests/src/com/android/launcher3/util/LauncherModelHelper.java @@ -363,6 +363,12 @@ public class LauncherModelHelper { sandboxContext.getContentResolver().insert(contentUri, values); } + public void deleteItem(int itemId, @NonNull final String tableName) { + final Uri uri = Uri.parse("content://" + + LauncherProvider.AUTHORITY + "/" + tableName + "/" + itemId); + sandboxContext.getContentResolver().delete(uri, null, null); + } + /** * Sets up a mock provider to load the provided layout by default, next time the layout loads */ @@ -420,7 +426,7 @@ public class LauncherModelHelper { } public SQLiteDatabase getDb() { - return getModelDbController().getDb(); + return getModelDbController().getDatabaseHelper().getWritableDatabase(); } } From de1b42b957227cea81e2cea27e42415d62188a9a Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Wed, 10 May 2023 23:07:01 +0000 Subject: [PATCH 14/14] Only refresh the launcher resume state when the task launch fails - The previous call from TaskbarLauncherStateController caused a regression due to the inability for the code to distinguish Normal -> Background -> Normal when tapping on the bar area or from failing to launch a task, so both cases were triggering the resumed state to cycle and start an animation. For now we can only handle the task-launch fail case. Bug: 268448123 Fixes: 281966662 Test: Quickswitch to an activity that finishes when resumed Change-Id: Ie4692dd85252540ff47633978c0e6e4adbb1bdd0 --- .../launcher3/taskbar/LauncherTaskbarUIController.java | 4 ++++ .../launcher3/taskbar/TaskbarLauncherStateController.java | 4 ---- .../com/android/launcher3/taskbar/TaskbarUIController.java | 5 +++++ quickstep/src/com/android/quickstep/views/TaskView.java | 7 +++++++ 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java index fdef39f2eb..ba6f1651ed 100644 --- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java @@ -197,6 +197,10 @@ public class LauncherTaskbarUIController extends TaskbarUIController { return mTaskbarLauncherStateController.applyState(fromInit ? 0 : duration, startAnimation); } + public void refreshResumedState() { + onLauncherResumedOrPaused(mLauncher.hasBeenResumed()); + } + /** * Create Taskbar animation when going from an app to Launcher as part of recents transition. * @param toState If known, the state we will end up in when reaching Launcher. diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java index 75cfd05d41..ed78e2d238 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java @@ -207,10 +207,6 @@ public class TaskbarLauncherStateController { com.android.launcher3.taskbar.Utilities.setOverviewDragState( mControllers, finalState.disallowTaskbarGlobalDrag(), disallowLongClick, finalState.allowTaskbarInitialSplitSelection()); - // LauncherTaskbarUIController depends on the state when checking whether - // to handle resume, so it should also be poked if current state changes - mLauncher.getTaskbarUIController().onLauncherResumedOrPaused( - mLauncher.hasBeenResumed()); } }; diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java index f3e2ee2e9d..f3513fdb97 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java @@ -318,4 +318,9 @@ public class TaskbarUIController { } return null; } + + /** + * Refreshes the resumed state of this ui controller. + */ + public void refreshResumedState() {} } diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java index 134ef6cce3..d57070847b 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/src/com/android/quickstep/views/TaskView.java @@ -849,6 +849,13 @@ public class TaskView extends FrameLayout implements Reusable { // QuickstepTransitionManager.createWallpaperOpenAnimations when launcher // shows again getRecentsView().startHome(false /* animated */); + RecentsView rv = getRecentsView(); + if (rv != null && rv.mSizeStrategy.getTaskbarController() != null) { + // LauncherTaskbarUIController depends on the launcher state when checking + // whether to handle resume, but that can come in before startHome() changes + // the state, so force-refresh here to ensure the taskbar is updated + rv.mSizeStrategy.getTaskbarController().refreshResumedState(); + } }); } // Indicate success once the system has indicated that the transition has started