Merge "Remove max displacement threshold in 2-zone model" into ub-launcher3-master
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
index da58817..5b01185 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
@@ -26,6 +26,7 @@
import androidx.core.app.NotificationCompat;
+import com.android.launcher3.ArrowTipView;
import com.android.launcher3.CellLayout;
import com.android.launcher3.FolderInfo;
import com.android.launcher3.Hotseat;
@@ -42,6 +43,7 @@
import com.android.launcher3.util.GridOccupancy;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.Themes;
+import com.android.launcher3.views.Snackbar;
import java.util.ArrayDeque;
import java.util.ArrayList;
@@ -56,7 +58,11 @@
private static final String NOTIFICATION_CHANNEL_ID = "launcher_onboarding";
private static final int ONBOARDING_NOTIFICATION_ID = 7641;
+ private static final String SETTINGS_ACTION =
+ "android.settings.ACTION_CONTENT_SUGGESTIONS_SETTINGS";
+
private final Launcher mLauncher;
+ private final Hotseat mHotseat;
private final NotificationManager mNotificationManager;
private final Notification mNotification;
private List<WorkspaceItemInfo> mPredictedApps;
@@ -68,6 +74,7 @@
HotseatEduController(Launcher launcher, Runnable runnable) {
mLauncher = launcher;
+ mHotseat = launcher.getHotseat();
mOnOnboardingComplete = runnable;
mNotificationManager = mLauncher.getSystemService(NotificationManager.class);
createNotificationChannel();
@@ -98,7 +105,7 @@
//separate folders and items that can get in folders
for (int i = 0; i < mLauncher.getDeviceProfile().inv.numHotseatIcons; i++) {
- View view = mLauncher.getHotseat().getChildAt(i, 0);
+ View view = mHotseat.getChildAt(i, 0);
if (view == null) continue;
ItemInfo info = (ItemInfo) view.getTag();
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
@@ -178,7 +185,6 @@
*/
private int migrateHotseatWhole() {
Workspace workspace = mLauncher.getWorkspace();
- Hotseat hotseatVG = mLauncher.getHotseat();
int pageId = -1;
int toRow = 0;
@@ -196,7 +202,7 @@
.getInt(LauncherSettings.Settings.EXTRA_VALUE);
}
for (int i = 0; i < mLauncher.getDeviceProfile().inv.numHotseatIcons; i++) {
- View child = hotseatVG.getChildAt(i, 0);
+ View child = mHotseat.getChildAt(i, 0);
if (child == null || child.getTag() == null) continue;
ItemInfo tag = (ItemInfo) child.getTag();
mLauncher.getModelWriter().moveItemInDatabase(tag,
@@ -211,8 +217,8 @@
mNotificationManager.cancel(ONBOARDING_NOTIFICATION_ID);
}
- void finishOnboarding() {
- mLauncher.getHotseat().removeAllViewsInLayout();
+ void moveHotseatItems() {
+ mHotseat.removeAllViewsInLayout();
if (!mNewItems.isEmpty()) {
int lastPage = mNewItems.get(mNewItems.size() - 1).screenId;
ArrayList<ItemInfo> animated = new ArrayList<>();
@@ -227,17 +233,34 @@
}
mLauncher.bindAppsAdded(mNewScreens, nonAnimated, animated);
}
+ }
+
+ void finishOnboarding() {
mOnOnboardingComplete.run();
destroy();
mLauncher.getSharedPrefs().edit().putBoolean(KEY_HOTSEAT_EDU_SEEN, true).apply();
}
+ void showDimissTip() {
+ if (mHotseat.getShortcutsAndWidgets().getChildCount()
+ < mLauncher.getDeviceProfile().inv.numHotseatIcons) {
+ Snackbar.show(mLauncher, R.string.hotseat_tip_gaps_filled, R.string.hotseat_turn_off,
+ null, () -> mLauncher.startActivity(new Intent(SETTINGS_ACTION)));
+ } else {
+ new ArrowTipView(mLauncher).show(
+ mLauncher.getString(R.string.hotseat_tip_no_empty_slots), mHotseat.getTop());
+ }
+ }
+
void setPredictedApps(List<WorkspaceItemInfo> predictedApps) {
mPredictedApps = predictedApps;
if (!mPredictedApps.isEmpty()
&& mLauncher.getOrientation() == Configuration.ORIENTATION_PORTRAIT) {
mNotificationManager.notify(ONBOARDING_NOTIFICATION_ID, mNotification);
}
+ else {
+ removeNotification();
+ }
}
private void createNotificationChannel() {
@@ -275,6 +298,17 @@
}
}
+ void showEdu() {
+ // hotseat is already empty and does not require migration. show edu tip
+ if (mHotseat.getShortcutsAndWidgets().getChildCount() == 0) {
+ new ArrowTipView(mLauncher).show(mLauncher.getString(R.string.hotseat_auto_enrolled),
+ mHotseat.getTop());
+ finishOnboarding();
+ } else {
+ showDialog();
+ }
+ }
+
void showDialog() {
if (mPredictedApps == null || mPredictedApps.isEmpty()) {
return;
@@ -291,7 +325,7 @@
ActivityTracker.SchedulerCallback<QuickstepLauncher> {
@Override
public boolean init(QuickstepLauncher activity, boolean alreadyOnHome) {
- activity.getHotseatPredictionController().showEduDialog();
+ activity.getHotseatPredictionController().showEdu();
return true;
}
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
index bcce168..8944088 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
@@ -16,7 +16,8 @@
package com.android.launcher3.hybridhotseat;
import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent;
-import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType.HYBRID_HOTSEAT_CANCELED;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType
+ .HYBRID_HOTSEAT_CANCELED;
import android.animation.PropertyValuesHolder;
import android.content.Context;
@@ -27,9 +28,7 @@
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
-import android.widget.Toast;
-import com.android.launcher3.ArrowTipView;
import com.android.launcher3.CellLayout;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
@@ -109,18 +108,16 @@
private void onAccept(View v) {
mHotseatEduController.migrate();
handleClose(true);
+
+ mHotseatEduController.moveHotseatItems();
mHotseatEduController.finishOnboarding();
//TODO: pass actual page index here.
// Temporarily we're passing 1 for folder migration and 2 for page migration
logUserAction(true, FeatureFlags.HOTSEAT_MIGRATE_TO_FOLDER.get() ? 1 : 2);
- int toastStringRes = !FeatureFlags.HOTSEAT_MIGRATE_TO_FOLDER.get()
- ? R.string.hotseat_items_migrated : R.string.hotseat_items_migrated_alt;
- Toast.makeText(mLauncher, toastStringRes, Toast.LENGTH_LONG).show();
}
private void onDismiss(View v) {
- int top = mLauncher.getHotseat().getTop();
- new ArrowTipView(mLauncher).show(mLauncher.getString(R.string.hotseat_no_migration), top);
+ mHotseatEduController.showDimissTip();
mHotseatEduController.finishOnboarding();
logUserAction(false, -1);
handleClose(true);
@@ -166,6 +163,7 @@
target.rank = MIGRATION_EXPERIMENT_IDENTIFIER;
// encoding migration type on pageIndex
target.pageIndex = pageIndex;
+ target.cardinality = HotseatPredictionController.MAX_ITEMS_FOR_MIGRATION;
LauncherLogProto.LauncherEvent event = newLauncherEvent(action, target);
UserEventDispatcher.newInstance(getContext()).dispatchUserEvent(event, null);
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
index 801408f..d3bb4f9 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
@@ -16,6 +16,9 @@
package com.android.launcher3.hybridhotseat;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.logging.LoggerUtils.newAction;
+import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
+import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent;
import android.animation.Animator;
import android.animation.AnimatorSet;
@@ -28,6 +31,7 @@
import android.app.prediction.AppTargetId;
import android.content.ComponentName;
import android.os.Bundle;
+import android.provider.DeviceConfig;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -59,9 +63,11 @@
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.logging.FileLog;
+import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.touch.ItemLongClickListener;
+import com.android.launcher3.uioverrides.DeviceFlag;
import com.android.launcher3.uioverrides.PredictedAppIcon;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.userevent.nano.LauncherLogProto;
@@ -85,6 +91,9 @@
private static final String TAG = "PredictiveHotseat";
private static final boolean DEBUG = false;
+ public static final int MAX_ITEMS_FOR_MIGRATION = DeviceConfig.getInt(
+ DeviceFlag.NAMESPACE_LAUNCHER, "max_homepage_items_for_migration", 5);
+
//TODO: replace this with AppTargetEvent.ACTION_UNPIN (b/144119543)
private static final int APPTARGET_ACTION_UNPIN = 4;
@@ -113,8 +122,8 @@
private HotseatEduController mHotseatEduController;
- private List<PredictedAppIcon.PredictedIconOutlineDrawing> mOutlineDrawings = new ArrayList<>();
+ private List<PredictedAppIcon.PredictedIconOutlineDrawing> mOutlineDrawings = new ArrayList<>();
private final View.OnLongClickListener mPredictionLongClickListener = v -> {
if (!ItemLongClickListener.canStartDrag(mLauncher)) return false;
@@ -147,12 +156,12 @@
}
/**
- * Transitions to NORMAL workspace mode and shows edu dialog
+ * Transitions to NORMAL workspace mode and shows edu
*/
- public void showEduDialog() {
+ public void showEdu() {
if (mHotseatEduController == null) return;
mLauncher.getStateManager().goToState(LauncherState.NORMAL, true,
- () -> mHotseatEduController.showDialog());
+ () -> mHotseatEduController.showEdu());
}
@Override
@@ -278,7 +287,7 @@
mAppPredictor.registerPredictionUpdates(mLauncher.getMainExecutor(),
this::setPredictedApps);
setPauseUIUpdate(false);
-
+ performBetaCheck();
if (!isReady()) {
mHotseatEduController = new HotseatEduController(mLauncher, this::createPredictor);
}
@@ -590,6 +599,39 @@
}
}
+ private void performBetaCheck() {
+ if (isReady()) return;
+ int hotseatItemsCount = mHotseat.getShortcutsAndWidgets().getChildCount();
+
+ // -1 to exclude smart space
+ int workspaceItemCount = mLauncher.getWorkspace().getScreenWithId(
+ Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets().getChildCount() - 1;
+
+ // opt user into the feature without onboarding tip or migration if they don't have any
+ // open spots in their hotseat and have more than maxItems in their hotseat + workspace
+
+ if (hotseatItemsCount == mHotSeatItemsCount && workspaceItemCount + hotseatItemsCount
+ > MAX_ITEMS_FOR_MIGRATION) {
+ mLauncher.getSharedPrefs().edit().putBoolean(HotseatEduController.KEY_HOTSEAT_EDU_SEEN,
+ true).apply();
+
+ LauncherLogProto.Action action = newAction(LauncherLogProto.Action.Type.TOUCH);
+ LauncherLogProto.Target target = newContainerTarget(LauncherLogProto.ContainerType.TIP);
+ action.touch = LauncherLogProto.Action.Touch.TAP;
+ target.tipType = LauncherLogProto.TipType.HYBRID_HOTSEAT;
+ target.controlType = LauncherLogProto.ControlType.HYBRID_HOTSEAT_CANCELED;
+
+ // temporarily encode details in log target (go/hotseat_migration)
+ target.rank = 2;
+ target.cardinality = MAX_ITEMS_FOR_MIGRATION;
+ target.pageIndex = (workspaceItemCount * 1000) + hotseatItemsCount;
+ LauncherLogProto.LauncherEvent event = newLauncherEvent(action, target);
+ UserEventDispatcher.newInstance(mLauncher).dispatchUserEvent(event, null);
+
+
+ }
+ }
+
/**
* Fill in predicted_rank field based on app prediction.
* Only applicable when {@link ItemInfo#itemType} is PREDICTED_HOTSEAT
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index d1a487a..a6eea0c 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -183,8 +183,8 @@
onStateOrResumeChanged();
}
- if ((changeBits & ACTIVITY_STATE_STARTED) != 0 && mHotseatPredictionController != null
- && (getActivityFlags() & ACTIVITY_STATE_USER_ACTIVE) == 0) {
+ if (mHotseatPredictionController != null && ((changeBits & ACTIVITY_STATE_STARTED) != 0
+ || (changeBits & getActivityFlags() & ACTIVITY_STATE_DEFERRED_RESUMED) != 0)) {
mHotseatPredictionController.setPauseUIUpdate(false);
}
}
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index b55b042..ab34f47 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -78,16 +78,21 @@
<string name="hotseat_edu_message_migrate">Easily access your most-used apps right on the Home screen. Suggestions will change based on your routines. Apps on the bottom row will move up to your Home screen. </string>
<string name="hotseat_edu_message_migrate_alt">Easily access your most-used apps, right on the Home screen. Suggestions will change based on your routines. Apps on the bottom row will move to a new folder.</string>
- <!-- Toast message user sees after opting into fully predicted hybrid hotseat -->
- <string name="hotseat_items_migrated">Your hotseat items have been moved up to your homescreen</string>
- <string name="hotseat_items_migrated_alt">Your hotseat items have been moved to a folder</string>
- <!-- Toast message user sees after opting into fully predicted hybrid hotseat -->
- <string name="hotseat_no_migration">Drag apps off the bottom row to see app suggestions</string>
<!-- Button text to opt in for fully predicted hotseat -->
<string name="hotseat_edu_accept">Get app suggestions</string>
<!-- Button text to dismiss opt in for fully predicted hotseat -->
<string name="hotseat_edu_dismiss">No thanks</string>
+ <!-- action shown to turn off predictions after onboarding -->
+ <string name="hotseat_turn_off">Settings</string>
+
+ <!-- tip shown if user has no items in hotseat to migrate -->
+ <string name="hotseat_auto_enrolled">Most-used apps appear here, and change based on routines</string>
+ <!-- tip shown if user declines migration and has no open spots for prediction -->
+ <string name="hotseat_tip_no_empty_slots">Drag apps off the bottom row to get app suggestions</string>
+ <!-- tip shown if user declines migration and has some open spots for prediction -->
+ <string name="hotseat_tip_gaps_filled">App suggestions added to empty space</string>
+
<!-- Title shown during interactive part of Back gesture tutorial for right edge. [CHAR LIMIT=30] -->
<string name="back_gesture_tutorial_playground_title_swipe_inward_right_edge" translatable="false">Try the back gesture</string>
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index ac5ba7a..573aa07 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -114,6 +114,7 @@
import com.android.launcher3.model.ModelWriter;
import com.android.launcher3.notification.NotificationListener;
import com.android.launcher3.pm.PinRequestHelper;
+import com.android.launcher3.pm.UserCache;
import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.popup.SystemShortcut;
@@ -137,6 +138,7 @@
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.PendingRequestArgs;
+import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.ShortcutUtil;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.Themes;
@@ -327,6 +329,8 @@
private long mLastTouchUpTime = -1;
private boolean mTouchInProgress;
+ private SafeCloseable mUserChangedCallbackCloseable;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
Object traceToken = TraceHelper.INSTANCE.beginSection(ON_CREATE_EVT,
@@ -445,6 +449,9 @@
});
TraceHelper.INSTANCE.endSection(traceToken);
+
+ mUserChangedCallbackCloseable = UserCache.INSTANCE.get(this).addUserChangeListener(
+ () -> getStateManager().goToState(NORMAL));
}
protected LauncherOverlayManager getDefaultOverlay() {
@@ -746,8 +753,8 @@
data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1) : -1;
if (resultCode == RESULT_CANCELED) {
completeTwoStageWidgetDrop(RESULT_CANCELED, appWidgetId, requestArgs);
- mWorkspace.removeExtraEmptyScreenDelayed(true, exitSpringLoaded,
- ON_ACTIVITY_RESULT_ANIMATION_DELAY, false);
+ mWorkspace.removeExtraEmptyScreenDelayed(
+ ON_ACTIVITY_RESULT_ANIMATION_DELAY, false, exitSpringLoaded);
} else if (resultCode == RESULT_OK) {
addAppWidgetImpl(
appWidgetId, requestArgs, null,
@@ -777,15 +784,9 @@
"returned from the widget configuration activity.");
result = RESULT_CANCELED;
completeTwoStageWidgetDrop(result, appWidgetId, requestArgs);
- final Runnable onComplete = new Runnable() {
- @Override
- public void run() {
- getStateManager().goToState(NORMAL);
- }
- };
-
- mWorkspace.removeExtraEmptyScreenDelayed(true, onComplete,
- ON_ACTIVITY_RESULT_ANIMATION_DELAY, false);
+ mWorkspace.removeExtraEmptyScreenDelayed(
+ ON_ACTIVITY_RESULT_ANIMATION_DELAY, false,
+ () -> getStateManager().goToState(NORMAL));
} else {
if (requestArgs.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
// When the screen id represents an actual screen (as opposed to a rank)
@@ -804,8 +805,8 @@
dropLayout.setDropPending(false);
}
};
- mWorkspace.removeExtraEmptyScreenDelayed(true, onComplete,
- ON_ACTIVITY_RESULT_ANIMATION_DELAY, false);
+ mWorkspace.removeExtraEmptyScreenDelayed(
+ ON_ACTIVITY_RESULT_ANIMATION_DELAY, false, onComplete);
}
return;
}
@@ -824,12 +825,12 @@
// Handle custom shortcuts created using ACTION_CREATE_SHORTCUT.
if (resultCode == RESULT_OK && requestArgs.container != ItemInfo.NO_ID) {
completeAdd(requestCode, data, -1, requestArgs);
- mWorkspace.removeExtraEmptyScreenDelayed(true, exitSpringLoaded,
- ON_ACTIVITY_RESULT_ANIMATION_DELAY, false);
+ mWorkspace.removeExtraEmptyScreenDelayed(
+ ON_ACTIVITY_RESULT_ANIMATION_DELAY, false, exitSpringLoaded);
} else if (resultCode == RESULT_CANCELED) {
- mWorkspace.removeExtraEmptyScreenDelayed(true, exitSpringLoaded,
- ON_ACTIVITY_RESULT_ANIMATION_DELAY, false);
+ mWorkspace.removeExtraEmptyScreenDelayed(
+ ON_ACTIVITY_RESULT_ANIMATION_DELAY, false, exitSpringLoaded);
}
}
@@ -1576,6 +1577,7 @@
mOverlayManager.onActivityDestroyed(this);
mAppTransitionManager.unregisterRemoteAnimations();
+ mUserChangedCallbackCloseable.close();
}
public LauncherAccessibilityDelegate getAccessibilityDelegate() {
@@ -1669,7 +1671,7 @@
};
completeAddAppWidget(appWidgetId, info, boundWidget,
addFlowHandler.getProviderInfo(this));
- mWorkspace.removeExtraEmptyScreenDelayed(true, onComplete, delay, false);
+ mWorkspace.removeExtraEmptyScreenDelayed(delay, false, onComplete);
}
}
@@ -2114,7 +2116,7 @@
}
// Remove the extra empty screen
- mWorkspace.removeExtraEmptyScreen(false, false);
+ mWorkspace.removeExtraEmptyScreen(false);
}
/**
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index ee08beb..ee9c099 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -29,7 +29,6 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.LayoutTransition;
-import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.SuppressLint;
@@ -124,9 +123,6 @@
private static final boolean ENFORCE_DRAG_EVENT_ORDER = false;
- private static final int SNAP_OFF_EMPTY_SCREEN_DURATION = 400;
- private static final int FADE_EMPTY_SCREEN_DURATION = 150;
-
private static final int ADJACENT_SCREEN_DROP_DURATION = 300;
private static final int DEFAULT_PAGE = 0;
@@ -139,7 +135,6 @@
@Thunk final IntSparseArrayMap<CellLayout> mWorkspaceScreens = new IntSparseArrayMap<>();
@Thunk final IntArray mScreenOrder = new IntArray();
- @Thunk Runnable mRemoveEmptyScreenRunnable;
@Thunk boolean mDeferRemoveExtraEmptyScreen = false;
/**
@@ -427,7 +422,7 @@
}
if (!mDeferRemoveExtraEmptyScreen) {
- removeExtraEmptyScreen(true, mDragSourceInternal != null);
+ removeExtraEmptyScreen(mDragSourceInternal != null);
}
updateChildrenLayersEnabled();
@@ -452,8 +447,16 @@
private void setupLayoutTransition() {
// We want to show layout transitions when pages are deleted, to close the gap.
mLayoutTransition = new LayoutTransition();
+
mLayoutTransition.enableTransitionType(LayoutTransition.DISAPPEARING);
mLayoutTransition.enableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
+ // Change the interpolators such that the fade animation plays before the move animation.
+ // This prevents empty adjacent pages to overlay during animation
+ mLayoutTransition.setInterpolator(LayoutTransition.DISAPPEARING,
+ Interpolators.clampToProgress(Interpolators.ACCEL_DEACCEL, 0, 0.5f));
+ mLayoutTransition.setInterpolator(LayoutTransition.CHANGE_DISAPPEARING,
+ Interpolators.clampToProgress(Interpolators.ACCEL_DEACCEL, 0.5f, 1));
+
mLayoutTransition.disableTransitionType(LayoutTransition.APPEARING);
mLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_APPEARING);
setLayoutTransition(mLayoutTransition);
@@ -570,9 +573,6 @@
boolean lastChildOnScreen = false;
boolean childOnFinalScreen = false;
- // Cancel any pending removal of empty screen
- mRemoveEmptyScreenRunnable = null;
-
if (mDragSourceInternal != null) {
if (mDragSourceInternal.getChildCount() == 1) {
lastChildOnScreen = true;
@@ -623,43 +623,34 @@
}
}
- public void removeExtraEmptyScreen(final boolean animate, boolean stripEmptyScreens) {
- removeExtraEmptyScreenDelayed(animate, null, 0, stripEmptyScreens);
+ public void removeExtraEmptyScreen(boolean stripEmptyScreens) {
+ removeExtraEmptyScreenDelayed(0, stripEmptyScreens, null);
}
- public void removeExtraEmptyScreenDelayed(final boolean animate, final Runnable onComplete,
- final int delay, final boolean stripEmptyScreens) {
+ public void removeExtraEmptyScreenDelayed(
+ int delay, boolean stripEmptyScreens, Runnable onComplete) {
if (mLauncher.isWorkspaceLoading()) {
// Don't strip empty screens if the workspace is still loading
return;
}
if (delay > 0) {
- postDelayed(new Runnable() {
- @Override
- public void run() {
- removeExtraEmptyScreenDelayed(animate, onComplete, 0, stripEmptyScreens);
- }
- }, delay);
+ postDelayed(
+ () -> removeExtraEmptyScreenDelayed(0, stripEmptyScreens, onComplete), delay);
return;
}
convertFinalScreenToEmptyScreenIfNecessary();
if (hasExtraEmptyScreen()) {
- int emptyIndex = mScreenOrder.indexOf(EXTRA_EMPTY_SCREEN_ID);
- if (getNextPage() == emptyIndex) {
- snapToPage(getNextPage() - 1, SNAP_OFF_EMPTY_SCREEN_DURATION);
- fadeAndRemoveEmptyScreen(SNAP_OFF_EMPTY_SCREEN_DURATION, FADE_EMPTY_SCREEN_DURATION,
- onComplete, stripEmptyScreens);
- } else {
- snapToPage(getNextPage(), 0);
- fadeAndRemoveEmptyScreen(0, FADE_EMPTY_SCREEN_DURATION,
- onComplete, stripEmptyScreens);
- }
- return;
- } else if (stripEmptyScreens) {
- // If we're not going to strip the empty screens after removing
- // the extra empty screen, do it right away.
+ removeView(mWorkspaceScreens.get(EXTRA_EMPTY_SCREEN_ID));
+ mWorkspaceScreens.remove(EXTRA_EMPTY_SCREEN_ID);
+ mScreenOrder.removeValue(EXTRA_EMPTY_SCREEN_ID);
+
+ // Update the page indicator to reflect the removed page.
+ showPageIndicatorAtCurrentScroll();
+ }
+
+ if (stripEmptyScreens) {
stripEmptyScreens();
}
@@ -668,44 +659,6 @@
}
}
- private void fadeAndRemoveEmptyScreen(int delay, int duration, final Runnable onComplete,
- final boolean stripEmptyScreens) {
- // XXX: Do we need to update LM workspace screens below?
- final CellLayout cl = mWorkspaceScreens.get(EXTRA_EMPTY_SCREEN_ID);
-
- mRemoveEmptyScreenRunnable = new Runnable() {
- @Override
- public void run() {
- if (hasExtraEmptyScreen()) {
- mWorkspaceScreens.remove(EXTRA_EMPTY_SCREEN_ID);
- mScreenOrder.removeValue(EXTRA_EMPTY_SCREEN_ID);
- removeView(cl);
- if (stripEmptyScreens) {
- stripEmptyScreens();
- }
- // Update the page indicator to reflect the removed page.
- showPageIndicatorAtCurrentScroll();
- }
- }
- };
-
- ObjectAnimator oa = ObjectAnimator.ofFloat(cl, ALPHA, 0f);
- oa.setDuration(duration);
- oa.setStartDelay(delay);
- oa.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- if (mRemoveEmptyScreenRunnable != null) {
- mRemoveEmptyScreenRunnable.run();
- }
- if (onComplete != null) {
- onComplete.run();
- }
- }
- });
- oa.start();
- }
-
public boolean hasExtraEmptyScreen() {
return mWorkspaceScreens.containsKey(EXTRA_EMPTY_SCREEN_ID) && getChildCount() > 1;
}
@@ -792,8 +745,6 @@
}
}
- boolean isInAccessibleDrag = mLauncher.getAccessibilityDelegate().isInAccessibleDrag();
-
// We enforce at least one page to add new items to. In the case that we remove the last
// such screen, we convert the last screen to the empty screen
int minScreens = 1;
@@ -812,7 +763,6 @@
removeView(cl);
} else {
// if this is the last screen, convert it to the empty screen
- mRemoveEmptyScreenRunnable = null;
mWorkspaceScreens.put(EXTRA_EMPTY_SCREEN_ID, cl);
mScreenOrder.add(EXTRA_EMPTY_SCREEN_ID);
}
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index dd0212a..8d1a102 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -406,6 +406,11 @@
setupWorkToggle();
mAH[AdapterHolder.MAIN].setup(mViewPager.getChildAt(0), mPersonalMatcher);
mAH[AdapterHolder.WORK].setup(mViewPager.getChildAt(1), mWorkMatcher);
+ mViewPager.getPageIndicator().setActiveMarker(AdapterHolder.MAIN);
+ findViewById(R.id.tab_personal)
+ .setOnClickListener((View view) -> mViewPager.snapToPage(AdapterHolder.MAIN));
+ findViewById(R.id.tab_work)
+ .setOnClickListener((View view) -> mViewPager.snapToPage(AdapterHolder.WORK));
onTabChanged(mViewPager.getNextPage());
} else {
mAH[AdapterHolder.MAIN].setup(findViewById(R.id.apps_list_view), null);
@@ -456,16 +461,10 @@
public void onTabChanged(int pos) {
mHeader.setMainActive(pos == 0);
- reset(true /* animate */);
- mViewPager.getPageIndicator().updateTabTextColor(pos);
if (mAH[pos].recyclerView != null) {
mAH[pos].recyclerView.bindFastScrollbar();
-
- findViewById(R.id.tab_personal)
- .setOnClickListener((View view) -> mViewPager.snapToPage(AdapterHolder.MAIN));
- findViewById(R.id.tab_work)
- .setOnClickListener((View view) -> mViewPager.snapToPage(AdapterHolder.WORK));
}
+ reset(true /* animate */);
if (mWorkModeSwitch != null) {
mWorkModeSwitch.setWorkTabVisible(pos == AdapterHolder.WORK);
}
diff --git a/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java b/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
index 3e40392..2515c24 100644
--- a/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
+++ b/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
@@ -135,6 +135,7 @@
@Override
public void setActiveMarker(int activePage) {
updateTabTextColor(activePage);
+ updateIndicatorPosition(activePage);
if (mContainerView != null && mLastActivePage != activePage) {
mContainerView.onTabChanged(activePage);
}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index b3f87f0..1cc8a98 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -154,7 +154,7 @@
"Replace Smartspace with a version rendered by System UI.");
public static final BooleanFlag ENABLE_LSQ_VELOCITY_PROVIDER = getDebugFlag(
- "ENABLE_LSQ_VELOCITY_PROVIDER", false,
+ "ENABLE_LSQ_VELOCITY_PROVIDER", true,
"Use Least Square algorithm for motion pause detection.");
public static final BooleanFlag ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS =
diff --git a/src/com/android/launcher3/pm/UserCache.java b/src/com/android/launcher3/pm/UserCache.java
index 678b647..f723256 100644
--- a/src/com/android/launcher3/pm/UserCache.java
+++ b/src/com/android/launcher3/pm/UserCache.java
@@ -95,7 +95,7 @@
private void removeUserChangeListener(Runnable command) {
synchronized (this) {
- mUserChangeListeners.add(command);
+ mUserChangeListeners.remove(command);
if (mUserChangeListeners.isEmpty()) {
// Disable cache and stop listening
mContext.unregisterReceiver(mUserChangeReceiver);