Merge "Simplifying widget cell layout" into udc-dev
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 6c7decd..5d2df70 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -292,6 +292,8 @@
<dimen name="taskbar_stashed_small_screen">108dp</dimen>
<dimen name="taskbar_unstash_input_area">316dp</dimen>
<dimen name="taskbar_stashed_handle_height">4dp</dimen>
+ <dimen name="taskbar_stashed_screen_edge_hover_deadzone_height">10dp</dimen>
+ <dimen name="taskbar_stashed_below_hover_deadzone_height">1dp</dimen>
<dimen name="taskbar_edu_horizontal_margin">112dp</dimen>
<dimen name="taskbar_nav_buttons_width_kids">88dp</dimen>
<dimen name="taskbar_nav_buttons_height_kids">40dp</dimen>
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 7e0530b..37f6284 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -929,6 +929,13 @@
}
/**
+ * Returns whether the taskbar is currently visually stashed.
+ */
+ public boolean isTaskbarStashed() {
+ return mControllers.taskbarStashController.isStashed();
+ }
+
+ /**
* Called when we detect a long press in the nav region before passing the gesture slop.
* @return Whether taskbar handled the long press, and thus should cancel the gesture.
*/
@@ -972,10 +979,23 @@
/**
* Called when we detect a motion down or up/cancel in the nav region while stashed.
+ *
* @param animateForward Whether to animate towards the unstashed hint state or back to stashed.
*/
public void startTaskbarUnstashHint(boolean animateForward) {
- mControllers.taskbarStashController.startUnstashHint(animateForward);
+ // TODO(b/270395798): Clean up forceUnstash after removing long-press unstashing code.
+ startTaskbarUnstashHint(animateForward, /* forceUnstash = */ false);
+ }
+
+ /**
+ * Called when we detect a motion down or up/cancel in the nav region while stashed.
+ *
+ * @param animateForward Whether to animate towards the unstashed hint state or back to stashed.
+ * @param forceUnstash Whether we force the unstash hint.
+ */
+ public void startTaskbarUnstashHint(boolean animateForward, boolean forceUnstash) {
+ // TODO(b/270395798): Clean up forceUnstash after removing long-press unstashing code.
+ mControllers.taskbarStashController.startUnstashHint(animateForward, forceUnstash);
}
/**
@@ -1123,4 +1143,9 @@
public int getTaskbarAllAppsScroll() {
return mControllers.taskbarAllAppsController.getTaskbarAllAppsScroll();
}
+
+ @VisibleForTesting
+ public float getStashedTaskbarScale() {
+ return mControllers.stashedHandleViewController.getStashedHandleHintScale().value;
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index b2f9378..5de5904 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -856,15 +856,18 @@
/**
* Creates and starts a partial unstash animation, hinting at the new state that will trigger
* when long press is detected.
+ *
* @param animateForward Whether we are going towards the new unstashed state or returning to
* the stashed state.
+ * @param forceUnstash Whether we force the unstash hint to animate.
*/
- public void startUnstashHint(boolean animateForward) {
+ protected void startUnstashHint(boolean animateForward, boolean forceUnstash) {
if (!isStashed()) {
// Already unstashed, no need to hint in that direction.
return;
}
- if (!canCurrentlyManuallyUnstash()) {
+ // TODO(b/270395798): Clean up after removing long-press unstashing code path.
+ if (!canCurrentlyManuallyUnstash() && !forceUnstash) {
// If any other flags are causing us to be stashed, long press won't cause us to
// unstash, so don't hint that it will.
return;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashViaTouchController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashViaTouchController.kt
index 2373142..1cc6672 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashViaTouchController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashViaTouchController.kt
@@ -25,7 +25,7 @@
import com.android.launcher3.touch.SingleAxisSwipeDetector.VERTICAL
import com.android.launcher3.util.DisplayController
import com.android.launcher3.util.TouchController
-import com.android.quickstep.inputconsumers.TaskbarStashInputConsumer
+import com.android.quickstep.inputconsumers.TaskbarUnstashInputConsumer
/**
* A helper [TouchController] for [TaskbarDragLayerController], specifically to handle touch events
@@ -34,7 +34,7 @@
* or [MotionEvent.ACTION_OUTSIDE].
* - Touches inside Transient Taskbar bounds will stash if it is detected as a swipe down gesture.
*
- * Note: touches to *unstash* Taskbar are handled by [TaskbarStashInputConsumer].
+ * Note: touches to *unstash* Taskbar are handled by [TaskbarUnstashInputConsumer].
*/
class TaskbarStashViaTouchController(val controllers: TaskbarControllers) : TouchController {
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java
index 623e234..b4b83f6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java
@@ -19,15 +19,21 @@
import android.util.AttributeSet;
import android.view.View;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.R;
import com.android.launcher3.allapps.ActivityAllAppsContainerView;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
+import java.util.Optional;
+
/** All apps container accessible from taskbar. */
public class TaskbarAllAppsContainerView extends
ActivityAllAppsContainerView<TaskbarOverlayContext> {
+ private @Nullable OnInvalidateHeaderListener mOnInvalidateHeaderListener;
+
public TaskbarAllAppsContainerView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
@@ -36,6 +42,10 @@
super(context, attrs, defStyleAttr);
}
+ void setOnInvalidateHeaderListener(OnInvalidateHeaderListener onInvalidateHeaderListener) {
+ mOnInvalidateHeaderListener = onInvalidateHeaderListener;
+ }
+
@Override
protected View inflateSearchBox() {
if (isSearchSupported()) {
@@ -54,6 +64,13 @@
}
@Override
+ public void invalidateHeader() {
+ super.invalidateHeader();
+ Optional.ofNullable(mOnInvalidateHeaderListener).ifPresent(
+ OnInvalidateHeaderListener::onInvalidateHeader);
+ }
+
+ @Override
protected boolean isSearchSupported() {
return FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get();
}
@@ -63,4 +80,8 @@
// All apps is always open
return true;
}
+
+ interface OnInvalidateHeaderListener {
+ void onInvalidateHeader();
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
index f0d28df..cfa1027 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
@@ -19,6 +19,7 @@
import android.animation.PropertyValuesHolder;
import android.content.Context;
+import android.graphics.Canvas;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
@@ -99,12 +100,13 @@
mAppsView = findViewById(R.id.apps_view);
mContent = mAppsView;
+ // Setup header protection for search bar, if enabled.
+ if (FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
+ mAppsView.setOnInvalidateHeaderListener(this::invalidate);
+ }
+
DeviceProfile dp = mActivityContext.getDeviceProfile();
setShiftRange(dp.allAppsShiftRange);
-
- setContentBackgroundWithParent(
- getContext().getDrawable(R.drawable.bg_rounded_corner_bottom_sheet),
- mAppsView.getBottomSheetBackground());
}
@Override
@@ -137,6 +139,12 @@
}
@Override
+ protected void dispatchDraw(Canvas canvas) {
+ mAppsView.drawOnScrimWithScale(canvas, mSlideInViewScale.value);
+ super.dispatchDraw(canvas);
+ }
+
+ @Override
protected void onScaleProgressChanged() {
super.onScaleProgressChanged();
mAppsView.setClipChildren(!mIsBackProgressing);
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java
index 476e0a8..8de0e40 100644
--- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java
@@ -36,6 +36,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.taskbar.TaskbarActivityContext;
import com.android.launcher3.taskbar.TaskbarControllers;
+import com.android.quickstep.views.DesktopTaskView;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
@@ -65,7 +66,9 @@
@Override
public void onTaskMovedToFront(int taskId) {
- mProxyView.close(false);
+ if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+ mProxyView.close(false);
+ }
}
};
diff --git a/quickstep/src/com/android/quickstep/InputConsumer.java b/quickstep/src/com/android/quickstep/InputConsumer.java
index 64c9295..6b189cf 100644
--- a/quickstep/src/com/android/quickstep/InputConsumer.java
+++ b/quickstep/src/com/android/quickstep/InputConsumer.java
@@ -41,6 +41,7 @@
int TYPE_ONE_HANDED = 1 << 11;
int TYPE_TASKBAR_STASH = 1 << 12;
int TYPE_STATUS_BAR = 1 << 13;
+ int TYPE_CURSOR_HOVER = 1 << 14;
String[] NAMES = new String[] {
"TYPE_NO_OP", // 0
@@ -57,6 +58,7 @@
"TYPE_ONE_HANDED", // 11
"TYPE_TASKBAR_STASH", // 12
"TYPE_STATUS_BAR", // 13
+ "TYPE_CURSOR_HOVER", // 14
};
InputConsumer NO_OP = () -> TYPE_NO_OP;
diff --git a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
index ab3ae9f..4c9cf8b 100644
--- a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -116,6 +116,16 @@
return response;
}
+ case TestProtocol.REQUEST_STASHED_TASKBAR_SCALE: {
+ runOnTISBinder(tisBinder -> {
+ response.putFloat(TestProtocol.TEST_INFO_RESPONSE_FIELD,
+ tisBinder.getTaskbarManager()
+ .getCurrentActivityContext()
+ .getStashedTaskbarScale());
+ });
+ return response;
+ }
+
case TestProtocol.REQUEST_TASKBAR_ALL_APPS_TOP_PADDING: {
return getTISBinderUIProperty(Bundle::putInt, tisBinder ->
tisBinder.getTaskbarManager()
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 89f06f6..36aa6f5 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -51,6 +51,7 @@
import android.window.TaskSnapshot;
import android.window.TransitionFilter;
+import androidx.annotation.MainThread;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
@@ -58,6 +59,7 @@
import com.android.internal.util.ScreenshotRequest;
import com.android.internal.view.AppearanceRegion;
import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -200,12 +202,17 @@
return null;
}
+ /**
+ * Sets proxy state, including death linkage, various listeners, and other configuration objects
+ */
+ @MainThread
public void setProxy(ISystemUiProxy proxy, IPip pip, ISplitScreen splitScreen,
IOneHanded oneHanded, IShellTransitions shellTransitions,
IStartingWindow startingWindow, IRecentTasks recentTasks,
ISysuiUnlockAnimationController sysuiUnlockAnimationController,
IBackAnimation backAnimation, IDesktopMode desktopMode,
IUnfoldAnimation unfoldAnimation, IDragAndDrop dragAndDrop) {
+ Preconditions.assertUIThread();
unlinkToDeath();
mSystemUiProxy = proxy;
mPip = pip;
@@ -232,6 +239,10 @@
setUnfoldAnimationListener(mUnfoldAnimationListener);
}
+ /**
+ * Clear the proxy to release held resources and turn the majority of its operations into no-ops
+ */
+ @MainThread
public void clearProxy() {
setProxy(null, null, null, null, null, null, null, null, null, null, null, null);
}
@@ -292,8 +303,10 @@
}
}
+ @MainThread
@Override
public void onStatusBarMotionEvent(MotionEvent event) {
+ Preconditions.assertUIThread();
if (mSystemUiProxy != null) {
try {
mSystemUiProxy.onStatusBarMotionEvent(event);
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 6ea171e..66aeee7 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -29,6 +29,7 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.quickstep.GestureState.DEFAULT_STATE;
import static com.android.quickstep.GestureState.TrackpadGestureType.getTrackpadGestureType;
+import static com.android.quickstep.InputConsumer.TYPE_CURSOR_HOVER;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.MOTION_DOWN;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.MOTION_MOVE;
@@ -110,7 +111,7 @@
import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer;
import com.android.quickstep.inputconsumers.StatusBarInputConsumer;
import com.android.quickstep.inputconsumers.SysUiOverlayInputConsumer;
-import com.android.quickstep.inputconsumers.TaskbarStashInputConsumer;
+import com.android.quickstep.inputconsumers.TaskbarUnstashInputConsumer;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.ActiveGestureLog.CompoundString;
import com.android.quickstep.util.ProtoTracer;
@@ -641,12 +642,17 @@
TraceHelper.FLAG_ALLOW_BINDER_TRACKING);
final int action = event.getActionMasked();
- if (action == ACTION_DOWN) {
+ // Note this will create a new consumer every mouse click, as after ACTION_UP from the click
+ // an ACTION_HOVER_ENTER will fire as well.
+ boolean isHoverActionWithoutConsumer =
+ event.isHoverEvent() && (mUncheckedConsumer.getType() & TYPE_CURSOR_HOVER) == 0;
+ if (action == ACTION_DOWN || isHoverActionWithoutConsumer) {
mRotationTouchHelper.setOrientationTransformIfNeeded(event);
- if (!mDeviceState.isOneHandedModeActive()
+ if ((!mDeviceState.isOneHandedModeActive()
&& mRotationTouchHelper.isInSwipeUpTouchRegion(event,
- mOverviewComponentObserver.getActivityInterface())) {
+ mOverviewComponentObserver.getActivityInterface()))
+ || isHoverActionWithoutConsumer) {
// Clone the previous gesture state since onConsumerAboutToBeSwitched might trigger
// onConsumerInactive and wipe the previous gesture state
GestureState prevGestureState = new GestureState(mGestureState);
@@ -723,6 +729,8 @@
if (action == ACTION_POINTER_DOWN) {
mGestureState.setTrackpadGestureType(getTrackpadGestureType(event));
}
+ } else if (event.isHoverEvent()) {
+ mUncheckedConsumer.onHoverEvent(event);
} else {
mUncheckedConsumer.onMotionEvent(event);
}
@@ -846,7 +854,7 @@
base = tryCreateAssistantInputConsumer(base, newGestureState, event, reasonString);
}
- // If Taskbar is present, we listen for long press to unstash it.
+ // If Taskbar is present, we listen for long press or cursor hover events to unstash it.
TaskbarActivityContext tac = mTaskbarManager.getCurrentActivityContext();
if (tac != null) {
// Present always on large screen or on small screen w/ flag
@@ -857,8 +865,8 @@
.append(reasonPrefix)
.append(SUBSTRING_PREFIX)
.append("TaskbarActivityContext != null, "
- + "using TaskbarStashInputConsumer");
- base = new TaskbarStashInputConsumer(this, base, mInputMonitorCompat, tac);
+ + "using TaskbarUnstashInputConsumer");
+ base = new TaskbarUnstashInputConsumer(this, base, mInputMonitorCompat, tac);
}
}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarStashInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
similarity index 69%
rename from quickstep/src/com/android/quickstep/inputconsumers/TaskbarStashInputConsumer.java
rename to quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
index 51c2b48..65c825c 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarStashInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
@@ -19,17 +19,20 @@
import static com.android.launcher3.MotionEventsUtils.isTrackpadMotionEvent;
import static com.android.launcher3.Utilities.squaredHypot;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_CURSOR_HOVER_STATES;
import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_TOUCHING;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.PointF;
+import android.graphics.Rect;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import androidx.annotation.Nullable;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.taskbar.TaskbarActivityContext;
@@ -40,9 +43,11 @@
import com.android.systemui.shared.system.InputMonitorCompat;
/**
- * Listens for a long press, and cancels the current gesture if that causes Taskbar to be unstashed.
+ * Listens for touch and hover events to unstash the Taskbar.
+ *
+ * <p>Cancels the current gesture if the long press causes the Taskbar to be unstashed.
*/
-public class TaskbarStashInputConsumer extends DelegateInputConsumer {
+public class TaskbarUnstashInputConsumer extends DelegateInputConsumer {
private final TaskbarActivityContext mTaskbarActivityContext;
private final GestureDetector mLongPressDetector;
@@ -64,9 +69,15 @@
private final boolean mIsTransientTaskbar;
+ private boolean mIsStashedTaskbarHovered = false;
+ private final Rect mStashedTaskbarHandleBounds = new Rect();
+ private final Rect mBottomEdgeBounds = new Rect();
+ private final int mBottomScreenEdge;
+ private final int mStashedTaskbarBottomEdge;
+
private final @Nullable TransitionCallback mTransitionCallback;
- public TaskbarStashInputConsumer(Context context, InputConsumer delegate,
+ public TaskbarUnstashInputConsumer(Context context, InputConsumer delegate,
InputMonitorCompat inputMonitor, TaskbarActivityContext taskbarActivityContext) {
super(delegate, inputMonitor);
mTaskbarActivityContext = taskbarActivityContext;
@@ -90,6 +101,11 @@
}
});
+ mBottomScreenEdge = res.getDimensionPixelSize(
+ R.dimen.taskbar_stashed_screen_edge_hover_deadzone_height);
+ mStashedTaskbarBottomEdge =
+ res.getDimensionPixelSize(R.dimen.taskbar_stashed_below_hover_deadzone_height);
+
mTransitionCallback = mIsTransientTaskbar
? taskbarActivityContext.getTranslationCallbacks()
: null;
@@ -97,7 +113,7 @@
@Override
public int getType() {
- return TYPE_TASKBAR_STASH | mDelegate.getType();
+ return TYPE_TASKBAR_STASH | TYPE_CURSOR_HOVER | mDelegate.getType();
}
@Override
@@ -213,4 +229,73 @@
}
}
}
+
+ /**
+ * Listen for hover events for the stashed taskbar.
+ *
+ * <p>When hovered over the stashed taskbar handle, show the unstash hint.
+ * <p>When the cursor is touching the bottom edge below the stashed taskbar, unstash it.
+ * <p>When the cursor is within a defined threshold of the screen's bottom edge outside of
+ * the stashed taskbar, unstash it.
+ */
+ @Override
+ public void onHoverEvent(MotionEvent ev) {
+ if (!ENABLE_CURSOR_HOVER_STATES.get() || mTaskbarActivityContext == null
+ || !mTaskbarActivityContext.isTaskbarStashed()) {
+ return;
+ }
+
+ if (mIsStashedTaskbarHovered) {
+ updateHoveredTaskbarState((int) ev.getX(), (int) ev.getY());
+ } else {
+ updateUnhoveredTaskbarState((int) ev.getX(), (int) ev.getY());
+ }
+ }
+
+ private void updateHoveredTaskbarState(int x, int y) {
+ DeviceProfile dp = mTaskbarActivityContext.getDeviceProfile();
+ mStashedTaskbarHandleBounds.set(
+ (dp.widthPx - (int) mUnstashArea) / 2,
+ dp.heightPx - dp.stashedTaskbarHeight,
+ (int) (((dp.widthPx - mUnstashArea) / 2) + mUnstashArea),
+ dp.heightPx);
+ mBottomEdgeBounds.set(mStashedTaskbarHandleBounds);
+ mBottomEdgeBounds.top = dp.heightPx - mStashedTaskbarBottomEdge;
+
+ if (mBottomEdgeBounds.contains(x, y)) {
+ // If hovering stashed taskbar and then hover screen bottom edge, unstash it.
+ mTaskbarActivityContext.onSwipeToUnstashTaskbar();
+ mIsStashedTaskbarHovered = false;
+ } else if (!mStashedTaskbarHandleBounds.contains(x, y)) {
+ // If exit hovering stashed taskbar, remove hint.
+ startStashedTaskbarHover(/* isHovered = */ false);
+ }
+ }
+
+ private void updateUnhoveredTaskbarState(int x, int y) {
+ DeviceProfile dp = mTaskbarActivityContext.getDeviceProfile();
+ mStashedTaskbarHandleBounds.set(
+ (dp.widthPx - (int) mUnstashArea) / 2,
+ dp.heightPx - dp.stashedTaskbarHeight,
+ (int) (((dp.widthPx - mUnstashArea) / 2) + mUnstashArea),
+ dp.heightPx);
+ mBottomEdgeBounds.set(
+ 0,
+ dp.heightPx - mBottomScreenEdge,
+ dp.widthPx,
+ dp.heightPx);
+
+ if (mStashedTaskbarHandleBounds.contains(x, y)) {
+ // If enter hovering stashed taskbar, start hint.
+ startStashedTaskbarHover(/* isHovered = */ true);
+ } else if (mBottomEdgeBounds.contains(x, y)) {
+ // If hover screen's bottom edge not below the stashed taskbar, unstash it.
+ mTaskbarActivityContext.onSwipeToUnstashTaskbar();
+ }
+ }
+
+ private void startStashedTaskbarHover(boolean isHovered) {
+ mTaskbarActivityContext.startTaskbarUnstashHint(isHovered, /* forceUnstash = */ true);
+ mIsStashedTaskbarHovered = isHovered;
+ }
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
index 6243471..f5c78f6 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
@@ -17,6 +17,7 @@
import static androidx.test.InstrumentationRegistry.getInstrumentation;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_CURSOR_HOVER_STATES;
import static com.android.quickstep.TaskbarModeSwitchRule.Mode.PERSISTENT;
import static com.android.quickstep.TaskbarModeSwitchRule.Mode.TRANSIENT;
@@ -264,6 +265,39 @@
.dragToSplitscreen(TEST_APP_PACKAGE, CALCULATOR_APP_PACKAGE);
}
+ @Test
+ @TaskbarModeSwitch(mode = TRANSIENT)
+ public void testShowTaskbarUnstashHintOnHover() {
+ try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_CURSOR_HOVER_STATES, true)) {
+ getTaskbar().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE);
+ mLauncher.getLaunchedAppState().hoverToShowTaskbarUnstashHint();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Test
+ @TaskbarModeSwitch(mode = TRANSIENT)
+ public void testUnstashTaskbarOnScreenBottomEdgeHover() {
+ try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_CURSOR_HOVER_STATES, true)) {
+ getTaskbar().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE);
+ mLauncher.getLaunchedAppState().hoverScreenBottomEdgeToUnstashTaskbar();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Test
+ @TaskbarModeSwitch(mode = TRANSIENT)
+ public void testHoverBelowHintedTaskbarToUnstash() {
+ try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_CURSOR_HOVER_STATES, true)) {
+ getTaskbar().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE);
+ mLauncher.getLaunchedAppState().hoverBelowHintedTaskbarToUnstash();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
private Taskbar getTaskbar() {
Taskbar taskbar = mLauncher.getLaunchedAppState().getTaskbar();
List<String> taskbarIconNames = taskbar.getIconNames();
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 0714863..11861b9 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -314,6 +314,7 @@
<style name="DropTargetButtonBase" parent="@android:style/TextAppearance.DeviceDefault.Medium">
<item name="android:drawablePadding">@dimen/drop_target_button_drawable_padding</item>
<item name="android:padding">14dp</item>
+ <item name="android:includeFontPadding">false</item>
<item name="android:textColor">@color/drop_target_text</item>
<item name="android:textSize">@dimen/drop_target_text_size</item>
<item name="android:singleLine">true</item>
diff --git a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
index f041ffb..5fbd48c 100644
--- a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
+++ b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
@@ -16,8 +16,8 @@
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 @@
* 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 @@
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/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index fc7f614..1a86009 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.res.Resources;
+import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.text.InputType;
@@ -58,8 +59,6 @@
public static final int TOOLTIP_LEFT = 1;
public static final int TOOLTIP_RIGHT = 2;
- private final Rect mTempRect = new Rect();
-
protected final ActivityContext mActivityContext;
protected final DropTargetHandler mDropTargetHandler;
protected DropTargetBar mDropTargetBar;
@@ -417,15 +416,11 @@
*/
@VisibleForTesting
protected boolean isTextClippedVertically(int availableHeight) {
- availableHeight -= getPaddingTop() + getPaddingBottom();
- if (availableHeight <= 0) {
- return true;
- }
+ Paint.FontMetricsInt fontMetricsInt = getPaint().getFontMetricsInt();
+ int lineCount = (getLineCount() <= 0) ? 1 : getLineCount();
+ int textHeight = lineCount * (fontMetricsInt.bottom - fontMetricsInt.top);
- getPaint().getTextBounds(mText.toString(), 0, mText.length(), mTempRect);
- // Add bounds bottom to height, as text bounds height measures from the text baseline and
- // above, which characters can descend below
- return mTempRect.bottom + mTempRect.height() >= availableHeight;
+ return textHeight + getPaddingTop() + getPaddingBottom() >= availableHeight;
}
/**
diff --git a/src/com/android/launcher3/DropTargetBar.java b/src/com/android/launcher3/DropTargetBar.java
index bb6d8b0..addcac9 100644
--- a/src/com/android/launcher3/DropTargetBar.java
+++ b/src/com/android/launcher3/DropTargetBar.java
@@ -152,6 +152,7 @@
firstButton.setTextVisible(true);
firstButton.setIconVisible(true);
firstButton.measure(widthSpec, heightSpec);
+ firstButton.resizeTextToFit();
} else if (visibleCount == 2) {
DeviceProfile dp = mLauncher.getDeviceProfile();
int verticalPadding = dp.dropTargetVerticalPaddingPx;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 86a5f9f..4764d72 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -3160,6 +3160,16 @@
}
@Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_ESCAPE) {
+ // Close any open floating views.
+ closeOpenViews();
+ return true;
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
+ @Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_MENU) {
// KEYCODE_MENU is sent by some tests, for example
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 0df4bd4..9abec50 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -263,18 +263,6 @@
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 b65e96b..7fda326 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -148,11 +148,6 @@
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
*/
public static final String TMP_TABLE = "favorites_tmp";
@@ -164,18 +159,6 @@
+ 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.
*
* @param id The row id.
@@ -376,10 +359,6 @@
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 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/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 01a4876..21dfbe1 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -871,8 +871,8 @@
boolean visible = deviceProfile.isTablet || mForceBottomSheetVisible;
mBottomSheetBackground.setVisibility(visible ? View.VISIBLE : View.GONE);
// Note: For tablets, the opaque background and header protection are added in drawOnScrim.
- // For the taskbar entrypoint, the scrim is drawn differently, so a static background is
- // added in TaskbarAllAppsContainerView and header protection is not yet supported.
+ // For the taskbar entrypoint, the scrim is drawn by its abstract slide in view container,
+ // so its header protection is derived from this scrim instead.
}
private void setBottomSheetAlpha(float alpha) {
diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
index 372e9bf..8f0b8ec 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.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 @@
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 @@
@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 @@
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 @@
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<Size> spanInfo =
getLoadedLauncherWidgetInfo(previewContext.getBaseContext());
@@ -253,14 +267,6 @@
}
}
- @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<ComponentKey, AppWidgetProviderInfo> widgetProviderInfoMap,
diff --git a/src/com/android/launcher3/model/DatabaseHelper.java b/src/com/android/launcher3/model/DatabaseHelper.java
index dc5fcf7..ecf5f67 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 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.net.URISyntaxException;
import java.util.Arrays;
import java.util.Locale;
+import java.util.function.ToLongFunction;
import java.util.stream.Collectors;
/**
@@ -76,45 +74,23 @@
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<UserHandle> 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<UserHandle> userSerialProvider, Runnable onEmptyDbCreateCallback) {
super(context, dbName, SCHEMA_VERSION);
mContext = context;
- mForMigration = forMigration;
+ mUserSerialProvider = userSerialProvider;
+ mOnEmptyDbCreateCallback = onEmptyDbCreateCallback;
}
protected void initIds() {
@@ -131,13 +107,11 @@
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 @@
}
}
- /**
- * 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 eded5ea..9a6cde6 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 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 @@
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<String> 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 @@
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 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 @@
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 @@
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 @@
// 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 @@
});
}
- 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<Integer> 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 @@
} 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 @@
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<DbEntry> sortedItemsToPlace, final boolean matchingScreenIdOnly) {
final GridOccupancy occupied = new GridOccupancy(trgX, trgY);
final Point trg = new Point(trgX, trgY);
@@ -391,7 +348,7 @@
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 @@
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<DbEntry> placedHotseatItems,
@NonNull final List<DbEntry> itemsToPlace) {
@@ -447,7 +404,7 @@
// 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 a5dccc1..2054d93 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 @@
private final LongSparseArray<UserHandle> 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 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 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 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 @@
// 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 9053d19..d4eded5 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.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.util.ArrayMap;
import android.util.Log;
import android.util.LongSparseArray;
-import android.util.TimingLogger;
import androidx.annotation.Nullable;
@@ -200,25 +199,10 @@
}
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<ShortcutInfo> 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 @@
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 @@
} 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 @@
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<ShortcutInfo> 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<ComponentWithLabelAndIcon> 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 @@
this.notify();
}
- private void loadWorkspace(
- List<ShortcutInfo> allDeepShortcuts, LoaderMemoryLogger memoryLogger) {
- loadWorkspace(allDeepShortcuts, Favorites.CONTENT_URI,
- null /* selection */, memoryLogger);
- }
+ protected void loadWorkspace(
+ List<ShortcutInfo> allDeepShortcuts,
+ String selection,
+ LoaderMemoryLogger memoryLogger) {
+ Trace.beginSection("LoadWorkspace");
+ try {
+ loadWorkspaceImpl(allDeepShortcuts, selection, memoryLogger);
+ } finally {
+ Trace.endSection();
+ }
+ logASplit("loadWorkspace");
- protected void loadWorkspaceForPreviewSurfaceRenderer(
- List<ShortcutInfo> 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<ShortcutInfo> allDeepShortcuts,
- Uri contentUri,
String selection,
@Nullable LoaderMemoryLogger memoryLogger) {
final Context context = mApp.getContext();
@@ -377,7 +363,7 @@
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 @@
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 @@
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 97bce8c..43d8958 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_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.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.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 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 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 @@
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 @@
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<DatabaseHelper> src, Supplier<DatabaseHelper> 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,40 @@
}
/**
- * 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) {
- createDbIfNotExists();
- return prepForMigration(
- dbFile,
- Favorites.TMP_TABLE,
- () -> mOpenHelper,
- () -> DatabaseHelper.createDatabaseHelper(
- mContext, true /* forMigration */));
+ public boolean migrateGridIfNeeded() {
+ 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 +357,7 @@
}
private void clearFlagEmptyDbCreated() {
- LauncherPrefs.getPrefs(mContext).edit()
- .remove(mOpenHelper.getKey(EMPTY_DATABASE_CREATED)).commit();
+ LauncherPrefs.get(mContext).removeSync(getEmptyDbCreatedKey(mOpenHelper.getDatabaseName()));
}
/**
@@ -359,9 +370,8 @@
@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 +489,27 @@
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<Boolean> 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 48969fc..c718dcc 100644
--- a/src/com/android/launcher3/provider/LauncherDbUtils.java
+++ b/src/com/android/launcher3/provider/LauncherDbUtils.java
@@ -101,7 +101,7 @@
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 ac72164..a6e064a 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.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 @@
/**
* 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 @@
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 @@
* @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<Long> oldManagedProfileIds = getManagedProfileIds(db, oldProfileId);
LongSparseArray<Long> profileMapping = new LongSparseArray<>(oldManagedProfileIds.size()
@@ -144,7 +146,7 @@
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 @@
}
// Override shortcuts
- maybeOverrideShortcuts(context, helper, db, myProfileId);
+ maybeOverrideShortcuts(context, controller, db, myProfileId);
return itemsDeleted;
}
@@ -321,11 +323,11 @@
.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 @@
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<String, LauncherActivityInfo> activityOverrides = ApiWrapper.getActivityOverrides(
context);
@@ -367,7 +369,7 @@
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 e509235..7c5ef4d 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.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 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 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/src/com/android/launcher3/util/LogConfig.java b/src/com/android/launcher3/util/LogConfig.java
index 5abf95c..04f83b9 100644
--- a/src/com/android/launcher3/util/LogConfig.java
+++ b/src/com/android/launcher3/util/LogConfig.java
@@ -55,4 +55,9 @@
* When turned on, we enable quick launch v2 related logging.
*/
public static final String QUICK_LAUNCH_V2 = "QuickLaunchV2";
+
+ /**
+ * When turned on, we enable Gms Play related logging.
+ */
+ public static final String GMS_PLAY = "GmsPlay";
}
diff --git a/src/com/android/launcher3/views/AbstractSlideInView.java b/src/com/android/launcher3/views/AbstractSlideInView.java
index 99616f1..ec7ec0b 100644
--- a/src/com/android/launcher3/views/AbstractSlideInView.java
+++ b/src/com/android/launcher3/views/AbstractSlideInView.java
@@ -99,7 +99,7 @@
protected @Nullable OnCloseListener mOnCloseBeginListener;
protected List<OnCloseListener> mOnCloseListeners = new ArrayList<>();
- private final AnimatedFloat mSlideInViewScale =
+ protected final AnimatedFloat mSlideInViewScale =
new AnimatedFloat(this::onScaleProgressChanged, VIEW_NO_SCALE);
protected boolean mIsBackProgressing;
@Nullable private Drawable mContentBackground;
diff --git a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index b472cdb..601b07e 100644
--- a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -90,6 +90,7 @@
public static final String REQUEST_DISABLE_TRANSIENT_TASKBAR = "disable-transient-taskbar";
public static final String REQUEST_UNSTASH_TASKBAR_IF_STASHED = "unstash-taskbar-if-stashed";
public static final String REQUEST_STASHED_TASKBAR_HEIGHT = "stashed-taskbar-height";
+ public static final String REQUEST_STASHED_TASKBAR_SCALE = "taskbar-stash-handle-scale";
public static final String REQUEST_RECREATE_TASKBAR = "recreate-taskbar";
public static final String REQUEST_APP_LIST_FREEZE_FLAGS = "app-list-freeze-flags";
public static final String REQUEST_APPS_LIST_SCROLL_Y = "apps-list-scroll-y";
diff --git a/tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java b/tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java
index 0a1a9ba..cea95e5 100644
--- a/tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java
+++ b/tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java
@@ -39,6 +39,7 @@
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 @@
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 f24f0da..63dbaa7 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.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.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 @@
@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<String>
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 @@
@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 @@
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 @@
@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 @@
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 @@
// 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 @@
// 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 @@
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 @@
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 @@
// 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 @@
// 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 @@
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 @@
)
// 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 @@
// 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 @@
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 @@
// 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 @@
// 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 @@
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 @@
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 @@
// 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 @@
@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 @@
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 @@
// 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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
// 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 @@
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 d192be4..78812c0 100644
--- a/tests/src/com/android/launcher3/model/LoaderCursorTest.java
+++ b/tests/src/com/android/launcher3/model/LoaderCursorTest.java
@@ -59,7 +59,6 @@
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 @@
});
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 2b6f9ff..54b8489 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.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 @@
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 67de1f5..1b1b294 100644
--- a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
+++ b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
@@ -46,6 +46,7 @@
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.model.DatabaseHelper;
+import com.android.launcher3.model.ModelDbController;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -63,13 +64,13 @@
@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 +90,7 @@
@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();
@@ -120,20 +121,20 @@
long workProfileId = myProfileId + 2;
long workProfileId_old = myProfileId + 3;
- MyDatabaseHelper helper = new MyDatabaseHelper(myProfileId);
- SQLiteDatabase db = helper.getWritableDatabase();
+ MyModelDbController controller = new MyModelDbController(myProfileId);
+ SQLiteDatabase db = controller.getDb();
BackupManager bm = spy(new BackupManager(context));
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(context, controller, controller.getDb(), bm);
// All the data has been migrated to the new user ids
assertEquals(0, getItemCountForProfile(db, myProfileId_old));
@@ -151,20 +152,20 @@
long myProfileId_old = myProfileId + 1;
long workProfileId_old = myProfileId + 3;
- MyDatabaseHelper helper = new MyDatabaseHelper(myProfileId);
- SQLiteDatabase db = helper.getWritableDatabase();
+ MyModelDbController controller = new MyModelDbController(myProfileId);
+ SQLiteDatabase db = controller.getDb();
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(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(context, controller, controller.getDb(), bm);
// All the data has been migrated to the new user ids
assertEquals(0, getItemCountForProfile(db, myProfileId_old));
@@ -173,12 +174,13 @@
assertEquals(10, getCount(db, "select * from favorites"));
}
- private void addIconsBulk(DatabaseHelper helper, int count, int screen, long profileId) {
+ private void addIconsBulk(MyModelDbController controller,
+ 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, 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 +191,11 @@
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 +218,7 @@
}
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,14 +256,15 @@
}
}
- private class MyDatabaseHelper extends DatabaseHelper {
+ private class MyModelDbController extends ModelDbController {
- public final LongSparseArray<UserHandle> users;
+ public final LongSparseArray<UserHandle> users = new LongSparseArray<>();
- MyDatabaseHelper(long profileId) {
- super(getInstrumentation().getTargetContext(), null, false);
- users = new LongSparseArray<>();
+ MyModelDbController(long profileId) {
+ super(getInstrumentation().getTargetContext());
users.put(profileId, myUserHandle());
+ mOpenHelper = new DatabaseHelper(getInstrumentation().getTargetContext(), null,
+ this::getSerialNumberForUser, () -> { });
}
@Override
@@ -269,10 +272,5 @@
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 bf31e39..6fca965 100644
--- a/tests/src/com/android/launcher3/util/LauncherModelHelper.java
+++ b/tests/src/com/android/launcher3/util/LauncherModelHelper.java
@@ -363,12 +363,6 @@
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 SQLiteDatabase getDb() {
- return getModelDbController().getDatabaseHelper().getWritableDatabase();
+ return getModelDbController().getDb();
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
index 58d5a36..f52b82d 100644
--- a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
+++ b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
@@ -25,13 +25,17 @@
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_ENABLE_MANUAL_TASKBAR_STASHING;
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_SHELL_DRAG_READY;
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_STASHED_TASKBAR_HEIGHT;
+import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_STASHED_TASKBAR_SCALE;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.SystemClock;
import android.view.MotionEvent;
+import android.view.ViewConfiguration;
import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.Condition;
+import androidx.test.uiautomator.UiDevice;
import com.android.launcher3.testing.shared.TestProtocol;
@@ -43,6 +47,18 @@
// More drag steps than Launchables to give the window manager time to register the drag.
private static final int DEFAULT_DRAG_STEPS = 35;
+ // UNSTASHED_TASKBAR_HANDLE_HINT_SCALE value from TaskbarStashController.
+ private static final float UNSTASHED_TASKBAR_HANDLE_HINT_SCALE = 1.1f;
+
+ private final Condition<UiDevice, Boolean> mStashedTaskbarHintScaleCondition =
+ device -> mLauncher.getTestInfo(REQUEST_STASHED_TASKBAR_SCALE).getFloat(
+ TestProtocol.TEST_INFO_RESPONSE_FIELD) - UNSTASHED_TASKBAR_HANDLE_HINT_SCALE
+ < 0.00001f;
+
+ private final Condition<UiDevice, Boolean> mStashedTaskbarDefaultScaleCondition =
+ device -> mLauncher.getTestInfo(REQUEST_STASHED_TASKBAR_SCALE).getFloat(
+ TestProtocol.TEST_INFO_RESPONSE_FIELD) - 1f < 0.00001f;
+
LaunchedAppState(LauncherInstrumentation launcher) {
super(launcher);
}
@@ -187,4 +203,86 @@
}
}
}
+
+ /**
+ * Emulate the cursor hovering the screen edge to unstash the taskbar.
+ *
+ * <p>This unstashing occurs when not actively hovering the taskbar.
+ */
+ public void hoverScreenBottomEdgeToUnstashTaskbar() {
+ try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+ LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "cursor hover entering screen edge to unstash taskbar")) {
+ mLauncher.getDevice().wait(mStashedTaskbarDefaultScaleCondition,
+ ViewConfiguration.DEFAULT_LONG_PRESS_TIMEOUT);
+
+ long downTime = SystemClock.uptimeMillis();
+ int leftEdge = 10;
+ Point taskbarUnstashArea = new Point(leftEdge, mLauncher.getRealDisplaySize().y - 1);
+ mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_ENTER,
+ new Point(taskbarUnstashArea.x, taskbarUnstashArea.y), null);
+
+ mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID);
+ }
+ }
+
+ /**
+ * Emulate the cursor hovering the taskbar to get unstash hint, then hovering below to unstash.
+ */
+ public void hoverBelowHintedTaskbarToUnstash() {
+ try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+ LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "cursor hover entering stashed taskbar")) {
+ long downTime = SystemClock.uptimeMillis();
+ Point stashedTaskbarHintArea = new Point(mLauncher.getRealDisplaySize().x / 2,
+ mLauncher.getRealDisplaySize().y - 1);
+ mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_ENTER,
+ new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y), null);
+
+ mLauncher.getDevice().wait(mStashedTaskbarHintScaleCondition,
+ LauncherInstrumentation.WAIT_TIME_MS);
+
+ try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
+ "cursor hover enter below taskbar to unstash")) {
+ downTime = SystemClock.uptimeMillis();
+ Point taskbarUnstashArea = new Point(mLauncher.getRealDisplaySize().x / 2,
+ mLauncher.getRealDisplaySize().y - 1);
+ mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_EXIT,
+ new Point(taskbarUnstashArea.x, taskbarUnstashArea.y), null);
+
+ mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID);
+ }
+ }
+ }
+
+ /**
+ * Emulate the cursor entering and exiting a hover over the taskbar.
+ */
+ public void hoverToShowTaskbarUnstashHint() {
+ try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+ LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "cursor hover entering stashed taskbar")) {
+ long downTime = SystemClock.uptimeMillis();
+ Point stashedTaskbarHintArea = new Point(mLauncher.getRealDisplaySize().x / 2,
+ mLauncher.getRealDisplaySize().y - 1);
+ mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_ENTER,
+ new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y), null);
+
+ mLauncher.getDevice().wait(mStashedTaskbarHintScaleCondition,
+ LauncherInstrumentation.WAIT_TIME_MS);
+
+ try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
+ "cursor hover exiting stashed taskbar")) {
+ Point outsideStashedTaskbarHintArea = new Point(
+ mLauncher.getRealDisplaySize().x / 2,
+ mLauncher.getRealDisplaySize().y - 500);
+ mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_EXIT,
+ new Point(outsideStashedTaskbarHintArea.x, outsideStashedTaskbarHintArea.y),
+ null);
+
+ mLauncher.getDevice().wait(mStashedTaskbarDefaultScaleCondition,
+ LauncherInstrumentation.WAIT_TIME_MS);
+ }
+ }
+ }
}