Merge "Cache hotseat predictions" into ub-launcher3-rvc-dev
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 f907089..78cc2dc 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
@@ -200,6 +200,7 @@
pageId = LauncherSettings.Settings.call(mLauncher.getContentResolver(),
LauncherSettings.Settings.METHOD_NEW_SCREEN_ID)
.getInt(LauncherSettings.Settings.EXTRA_VALUE);
+ mNewScreens = IntArray.wrap(pageId);
}
for (int i = 0; i < mLauncher.getDeviceProfile().inv.numHotseatIcons; i++) {
View child = mHotseat.getChildAt(i, 0);
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 4213740..fa137f8 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
@@ -33,6 +33,7 @@
import com.android.launcher3.Insettable;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
+import com.android.launcher3.Workspace;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.UserEventDispatcher;
@@ -153,6 +154,12 @@
private void logUserAction(boolean migrated, int pageIndex) {
LauncherLogProto.Action action = new LauncherLogProto.Action();
LauncherLogProto.Target target = new LauncherLogProto.Target();
+
+ int hotseatItemsCount = mLauncher.getHotseat().getShortcutsAndWidgets().getChildCount();
+ // -1 to exclude smart space
+ int workspaceItemCount = mLauncher.getWorkspace().getScreenWithId(
+ Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets().getChildCount() - 1;
+
action.type = LauncherLogProto.Action.Type.TOUCH;
action.touch = LauncherLogProto.Action.Touch.TAP;
target.containerType = LauncherLogProto.ContainerType.TIP;
@@ -162,7 +169,7 @@
target.rank = MIGRATION_EXPERIMENT_IDENTIFIER;
// encoding migration type on pageIndex
target.pageIndex = pageIndex;
- target.cardinality = HotseatPredictionController.MAX_ITEMS_FOR_MIGRATION;
+ target.cardinality = (workspaceItemCount * 1000) + hotseatItemsCount;
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 e7398ab..1aff8e9 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
@@ -31,6 +31,7 @@
import android.app.prediction.AppTargetId;
import android.content.ComponentName;
import android.os.Bundle;
+import android.os.Process;
import android.provider.DeviceConfig;
import android.util.Log;
import android.view.View;
@@ -40,6 +41,7 @@
import androidx.annotation.Nullable;
import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.CellLayout;
import com.android.launcher3.DragSource;
import com.android.launcher3.DropTarget;
import com.android.launcher3.Hotseat;
@@ -63,6 +65,7 @@
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
+import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.shortcuts.ShortcutKey;
@@ -76,6 +79,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Locale;
import java.util.OptionalInt;
import java.util.stream.IntStream;
@@ -91,9 +95,6 @@
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;
@@ -105,6 +106,8 @@
private static final String BUNDLE_KEY_HOTSEAT = "hotseat_apps";
private static final String BUNDLE_KEY_WORKSPACE = "workspace_apps";
+ private static final String BUNDLE_KEY_PIN_EVENTS = "pin_events";
+
private static final String PREDICTION_CLIENT = "hotseat";
private DropTarget.DragObject mDragObject;
private int mHotSeatItemsCount;
@@ -310,15 +313,45 @@
private Bundle getAppPredictionContextExtra() {
Bundle bundle = new Bundle();
+
+ //TODO: remove this way of reporting items
bundle.putParcelableArrayList(BUNDLE_KEY_HOTSEAT,
getPinnedAppTargetsInViewGroup((mHotseat.getShortcutsAndWidgets())));
bundle.putParcelableArrayList(BUNDLE_KEY_WORKSPACE, getPinnedAppTargetsInViewGroup(
mLauncher.getWorkspace().getScreenWithId(
Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets()));
+ ArrayList<AppTargetEvent> pinEvents = new ArrayList<>();
+ getPinEventsForViewGroup(pinEvents, mHotseat.getShortcutsAndWidgets(),
+ APP_LOCATION_HOTSEAT);
+ getPinEventsForViewGroup(pinEvents, mLauncher.getWorkspace().getScreenWithId(
+ Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets(), APP_LOCATION_WORKSPACE);
+ bundle.putParcelableArrayList(BUNDLE_KEY_PIN_EVENTS, pinEvents);
+
return bundle;
}
+ private ArrayList<AppTargetEvent> getPinEventsForViewGroup(ArrayList<AppTargetEvent> pinEvents,
+ ViewGroup views, String root) {
+ for (int i = 0; i < views.getChildCount(); i++) {
+ View child = views.getChildAt(i);
+ final AppTargetEvent event;
+ if (child.getTag() instanceof ItemInfo && getAppTargetFromInfo(
+ (ItemInfo) child.getTag()) != null) {
+ ItemInfo info = (ItemInfo) child.getTag();
+ event = wrapAppTargetWithLocation(getAppTargetFromInfo(info),
+ AppTargetEvent.ACTION_PIN, info);
+ } else {
+ CellLayout.LayoutParams params = (CellLayout.LayoutParams) views.getLayoutParams();
+ event = wrapAppTargetWithLocation(getBlockAppTarget(), AppTargetEvent.ACTION_PIN,
+ root, 0, params.cellX, params.cellY, params.cellHSpan, params.cellVSpan);
+ }
+ pinEvents.add(event);
+ }
+ return pinEvents;
+ }
+
+
private ArrayList<AppTarget> getPinnedAppTargetsInViewGroup(ViewGroup viewGroup) {
ArrayList<AppTarget> pinnedApps = new ArrayList<>();
for (int i = 0; i < viewGroup.getChildCount(); i++) {
@@ -653,6 +686,9 @@
if (isReady()) return;
int hotseatItemsCount = mHotseat.getShortcutsAndWidgets().getChildCount();
+ int maxItems = DeviceConfig.getInt(
+ DeviceFlag.NAMESPACE_LAUNCHER, "max_homepage_items_for_migration", 5);
+
// -1 to exclude smart space
int workspaceItemCount = mLauncher.getWorkspace().getScreenWithId(
Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets().getChildCount() - 1;
@@ -661,7 +697,7 @@
// open spots in their hotseat and have more than maxItems in their hotseat + workspace
if (hotseatItemsCount == mHotSeatItemsCount && workspaceItemCount + hotseatItemsCount
- > MAX_ITEMS_FOR_MIGRATION) {
+ > maxItems) {
mLauncher.getSharedPrefs().edit().putBoolean(HotseatEduController.KEY_HOTSEAT_EDU_SEEN,
true).apply();
@@ -673,8 +709,8 @@
// temporarily encode details in log target (go/hotseat_migration)
target.rank = 2;
- target.cardinality = MAX_ITEMS_FOR_MIGRATION;
- target.pageIndex = (workspaceItemCount * 1000) + hotseatItemsCount;
+ target.cardinality = (workspaceItemCount * 1000) + hotseatItemsCount;
+ target.pageIndex = maxItems;
LauncherLogProto.LauncherEvent event = newLauncherEvent(action, target);
UserEventDispatcher.newInstance(mLauncher).dispatchUserEvent(event, null);
@@ -736,4 +772,52 @@
return new AppTarget.Builder(new AppTargetId("app:" + cn.getPackageName()),
cn.getPackageName(), info.user).setClassName(cn.getClassName()).build();
}
+
+ private AppTarget getAppTargetFromInfo(ItemInfo info) {
+ if (info == null) return null;
+ if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
+ && info instanceof LauncherAppWidgetInfo
+ && ((LauncherAppWidgetInfo) info).providerName != null) {
+ ComponentName cn = ((LauncherAppWidgetInfo) info).providerName;
+ return new AppTarget.Builder(new AppTargetId("widget:" + cn.getPackageName()),
+ cn.getPackageName(), info.user).setClassName(cn.getClassName()).build();
+ } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
+ && info.getTargetComponent() != null) {
+ ComponentName cn = info.getTargetComponent();
+ return new AppTarget.Builder(new AppTargetId("app:" + cn.getPackageName()),
+ cn.getPackageName(), info.user).setClassName(cn.getClassName()).build();
+ } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
+ && info instanceof WorkspaceItemInfo) {
+ ShortcutKey shortcutKey = ShortcutKey.fromItemInfo(info);
+ //TODO: switch to using full shortcut info
+ return new AppTarget.Builder(new AppTargetId("shortcut:" + shortcutKey.getId()),
+ shortcutKey.componentName.getPackageName(), shortcutKey.user).build();
+ } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
+ return new AppTarget.Builder(new AppTargetId("folder:" + info.id),
+ mLauncher.getPackageName(), info.user).build();
+ }
+ return null;
+ }
+
+ private AppTargetEvent wrapAppTargetWithLocation(AppTarget target, int action, ItemInfo info) {
+ return wrapAppTargetWithLocation(target, action,
+ info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT
+ ? APP_LOCATION_HOTSEAT : APP_LOCATION_WORKSPACE, info.screenId, info.cellX,
+ info.cellY, info.spanX, info.spanY);
+ }
+
+ private AppTargetEvent wrapAppTargetWithLocation(AppTarget target, int action, String root,
+ int screenId, int x, int y, int spanX, int spanY) {
+ return new AppTargetEvent.Builder(target, action).setLaunchLocation(
+ String.format(Locale.ENGLISH, "%s/%d/[%d,%d]/[%d,%d]", root, screenId, x, y, spanX,
+ spanY)).build();
+ }
+
+ /**
+ * A helper method to generate an AppTarget that's used to communicate workspace layout
+ */
+ private AppTarget getBlockAppTarget() {
+ return new AppTarget.Builder(new AppTargetId("block"),
+ mLauncher.getPackageName(), Process.myUserHandle()).build();
+ }
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
index 70880eb..8af26c6 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
@@ -136,9 +136,11 @@
@Override
public void addSupportedAccessibilityActions(AccessibilityNodeInfo accessibilityNodeInfo) {
- accessibilityNodeInfo.addAction(
- new AccessibilityNodeInfo.AccessibilityAction(PIN_PREDICTION,
- getContext().getText(R.string.pin_prediction)));
+ if (!mIsPinned) {
+ accessibilityNodeInfo.addAction(
+ new AccessibilityNodeInfo.AccessibilityAction(PIN_PREDICTION,
+ getContext().getText(R.string.pin_prediction)));
+ }
}
@Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
index 70b139d..fadde37 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
@@ -204,27 +204,23 @@
true /* freezeTaskList */);
} else {
int taskId = mRecentsView.getNextPageTaskView().getTask().key.id;
- mFinishingRecentsAnimationForNewTaskId = taskId;
- mRecentsAnimationController.finish(true /* toRecents */, () -> {
- if (!mCanceled) {
- TaskView nextTask = mRecentsView.getTaskView(taskId);
- if (nextTask != null) {
- nextTask.launchTask(false /* animate */, true /* freezeTaskList */,
- success -> {
- resultCallback.accept(success);
- if (!success) {
- mActivityInterface.onLaunchTaskFailed();
- nextTask.notifyTaskLaunchFailed(TAG);
- } else {
- mActivityInterface.onLaunchTaskSuccess();
- }
- }, MAIN_EXECUTOR.getHandler());
- }
- mStateCallback.setStateOnUiThread(successStateFlag);
+ if (!mCanceled) {
+ TaskView nextTask = mRecentsView.getTaskView(taskId);
+ if (nextTask != null) {
+ nextTask.launchTask(false /* animate */, true /* freezeTaskList */,
+ success -> {
+ resultCallback.accept(success);
+ if (!success) {
+ mActivityInterface.onLaunchTaskFailed();
+ nextTask.notifyTaskLaunchFailed(TAG);
+ } else {
+ mActivityInterface.onLaunchTaskSuccess();
+ }
+ }, MAIN_EXECUTOR.getHandler());
}
- mCanceled = false;
- mFinishingRecentsAnimationForNewTaskId = -1;
- });
+ mStateCallback.setStateOnUiThread(successStateFlag);
+ }
+ mCanceled = false;
}
ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", true);
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
index 8574cf1..31a2814 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
@@ -30,6 +30,7 @@
import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
import static com.android.quickstep.GestureState.STATE_END_TARGET_ANIMATION_FINISHED;
import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHED;
+import static com.android.quickstep.GestureState.STATE_TASK_APPEARED_DURING_SWITCH;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.HIDE;
@@ -253,6 +254,8 @@
| STATE_RECENTS_SCROLLING_FINISHED,
this::onSettledOnEndTarget);
+ mGestureState.runOnceAtState(STATE_TASK_APPEARED_DURING_SWITCH, this::onTaskAppeared);
+
mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED, this::invalidateHandler);
mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
this::invalidateHandlerWithLauncher);
@@ -727,6 +730,22 @@
}
}
+ private void onTaskAppeared() {
+ RemoteAnimationTargetCompat app = mGestureState.getAnimationTarget();
+ if (mRecentsAnimationController != null && app != null) {
+
+ // TODO(b/152480470): Update Task target animation after onTaskAppeared holistically.
+ /* android.util.Log.d("LauncherSwipeHandler", "onTaskAppeared");
+
+ final boolean result = mRecentsAnimationController.removeTaskTarget(app);
+ mGestureState.setAnimationTarget(null);
+ android.util.Log.d("LauncherSwipeHandler", "removeTask, result=" + result); */
+
+ mRecentsAnimationController.finish(false /* toRecents */,
+ null /* onFinishComplete */);
+ }
+ }
+
private GestureEndTarget calculateEndTarget(PointF velocity, float endVelocity, boolean isFling,
boolean isCancel) {
final GestureEndTarget endTarget;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
index 7979601..2c2feb2 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -58,7 +58,6 @@
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.model.AppLaunchTracker;
@@ -68,6 +67,7 @@
import com.android.launcher3.tracing.nano.LauncherTraceProto;
import com.android.launcher3.tracing.nano.TouchInteractionServiceProto;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
+import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.TraceHelper;
import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
import com.android.quickstep.inputconsumers.AssistantInputConsumer;
@@ -378,7 +378,7 @@
if (!sharedPrefs.getBoolean(HAS_ENABLED_QUICKSTEP_ONCE, true)) {
sharedPrefs.edit()
.putBoolean(HAS_ENABLED_QUICKSTEP_ONCE, true)
- .putBoolean(DiscoveryBounce.HOME_BOUNCE_SEEN, false)
+ .putBoolean(OnboardingPrefs.HOME_BOUNCE_SEEN, false)
.apply();
}
}
@@ -539,6 +539,8 @@
boolean canStartSystemGesture = mDeviceState.canStartSystemGesture();
if (!mDeviceState.isUserUnlocked()) {
+ Log.d(TAG, "User locked. Can start system gesture? " + canStartSystemGesture
+ + " sysUiFlags: " + mDeviceState.getSystemUiStateFlags());
if (canStartSystemGesture) {
// This handles apps launched in direct boot mode (e.g. dialer) as well as apps
// launched while device is locked even after exiting direct boot mode (e.g. camera).
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 69400b3..48e25bd 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -17,14 +17,7 @@
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
import static com.android.launcher3.AbstractFloatingView.TYPE_HIDE_BACK_BUTTON;
-import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.allapps.DiscoveryBounce.BOUNCE_MAX_COUNT;
-import static com.android.launcher3.allapps.DiscoveryBounce.HOME_BOUNCE_COUNT;
-import static com.android.launcher3.allapps.DiscoveryBounce.HOME_BOUNCE_SEEN;
-import static com.android.launcher3.allapps.DiscoveryBounce.SHELF_BOUNCE_COUNT;
-import static com.android.launcher3.allapps.DiscoveryBounce.SHELF_BOUNCE_SEEN;
import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
@@ -32,6 +25,7 @@
import android.animation.ValueAnimator;
import android.content.Intent;
import android.content.IntentSender;
+import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.view.View;
@@ -47,12 +41,14 @@
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.uioverrides.RecentsViewStateController;
+import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.UiThreadHelper;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.util.QuickstepOnboardingPrefs;
import com.android.quickstep.util.RemoteAnimationProvider;
import com.android.quickstep.util.RemoteFadeOutAnimationListener;
import com.android.quickstep.util.ShelfPeekAnim;
@@ -86,45 +82,6 @@
super.onCreate(savedInstanceState);
SysUINavigationMode.INSTANCE.get(this).addModeChangeListener(this);
-
- if (!getSharedPrefs().getBoolean(HOME_BOUNCE_SEEN, false)) {
- getStateManager().addStateListener(new LauncherStateManager.StateListener() {
- @Override
- public void onStateTransitionStart(LauncherState toState) { }
-
- @Override
- public void onStateTransitionComplete(LauncherState finalState) {
- boolean swipeUpEnabled = SysUINavigationMode.INSTANCE
- .get(BaseQuickstepLauncher.this).getMode().hasGestures;
- LauncherState prevState = getStateManager().getLastState();
-
- if (((swipeUpEnabled && finalState == OVERVIEW) || (!swipeUpEnabled
- && finalState == ALL_APPS && prevState == NORMAL) || BOUNCE_MAX_COUNT
- <= getSharedPrefs().getInt(HOME_BOUNCE_COUNT, 0))) {
- getSharedPrefs().edit().putBoolean(HOME_BOUNCE_SEEN, true).apply();
- getStateManager().removeStateListener(this);
- }
- }
- });
- }
-
- if (!getSharedPrefs().getBoolean(SHELF_BOUNCE_SEEN, false)) {
- getStateManager().addStateListener(new LauncherStateManager.StateListener() {
- @Override
- public void onStateTransitionStart(LauncherState toState) { }
-
- @Override
- public void onStateTransitionComplete(LauncherState finalState) {
- LauncherState prevState = getStateManager().getLastState();
-
- if ((finalState == ALL_APPS && prevState == OVERVIEW) || BOUNCE_MAX_COUNT
- <= getSharedPrefs().getInt(SHELF_BOUNCE_COUNT, 0)) {
- getSharedPrefs().edit().putBoolean(SHELF_BOUNCE_SEEN, true).apply();
- getStateManager().removeStateListener(this);
- }
- }
- });
- }
}
@Override
@@ -244,6 +201,12 @@
}
@Override
+ protected OnboardingPrefs createOnboardingPrefs(SharedPreferences sharedPrefs,
+ LauncherStateManager stateManager) {
+ return new QuickstepOnboardingPrefs(this, sharedPrefs, stateManager);
+ }
+
+ @Override
protected ScaleAndTranslation getOverviewScaleAndTranslationForNormalState() {
if (SysUINavigationMode.getMode(this) == Mode.NO_BUTTON) {
PagedOrientationHandler layoutVertical =
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index 123c988..0f45196 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -62,10 +62,13 @@
@Override
public void setState(@NonNull LauncherState state) {
- ScaleAndTranslation scaleAndTranslation = state
- .getOverviewScaleAndTranslation(mLauncher);
+ ScaleAndTranslation scaleAndTranslation = state.getOverviewScaleAndTranslation(mLauncher);
+ float translationX = scaleAndTranslation.translationX;
+ if (mRecentsView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
+ translationX = -translationX;
+ }
SCALE_PROPERTY.set(mRecentsView, scaleAndTranslation.scale);
- mRecentsView.setTranslationX(scaleAndTranslation.translationX);
+ mRecentsView.setTranslationX(translationX);
mRecentsView.setTranslationY(scaleAndTranslation.translationY);
getContentAlphaProperty().set(mRecentsView, state.overviewUi ? 1f : 0);
@@ -96,9 +99,13 @@
void setStateWithAnimationInternal(@NonNull final LauncherState toState,
@NonNull StateAnimationConfig config, @NonNull PendingAnimation setter) {
ScaleAndTranslation scaleAndTranslation = toState.getOverviewScaleAndTranslation(mLauncher);
+ float translationX = scaleAndTranslation.translationX;
+ if (mRecentsView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
+ translationX = -translationX;
+ }
setter.setFloat(mRecentsView, SCALE_PROPERTY, scaleAndTranslation.scale,
config.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR));
- setter.setFloat(mRecentsView, VIEW_TRANSLATE_X, scaleAndTranslation.translationX,
+ setter.setFloat(mRecentsView, VIEW_TRANSLATE_X, translationX,
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_X, LINEAR));
setter.setFloat(mRecentsView, VIEW_TRANSLATE_Y, scaleAndTranslation.translationY,
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR));
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index 5118906..544f420 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -23,6 +23,7 @@
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -109,6 +110,9 @@
public static final int STATE_RECENTS_SCROLLING_FINISHED =
getFlagForIndex("STATE_RECENTS_SCROLLING_FINISHED");
+ // Called when the new task appeared from quick switching.
+ public static final int STATE_TASK_APPEARED_DURING_SWITCH =
+ getFlagForIndex("STATE_TASK_APPEARED_DURING_SWITCH");
// Needed to interact with the current activity
private final Intent mHomeIntent;
@@ -119,6 +123,7 @@
private ActivityManager.RunningTaskInfo mRunningTask;
private GestureEndTarget mEndTarget;
+ private RemoteAnimationTargetCompat mAnimationTarget;
// TODO: This can be removed once we stop finishing the animation when starting a new task
private int mFinishingRecentsAnimationTaskId = -1;
@@ -227,6 +232,14 @@
return mEndTarget;
}
+ public void setAnimationTarget(RemoteAnimationTargetCompat target) {
+ mAnimationTarget = target;
+ }
+
+ public RemoteAnimationTargetCompat getAnimationTarget() {
+ return mAnimationTarget;
+ }
+
/**
* Sets the end target of this gesture and immediately notifies the state changes.
*/
@@ -301,6 +314,12 @@
mStateCallback.setState(STATE_RECENTS_ANIMATION_ENDED);
}
+ @Override
+ public void onTaskAppeared(RemoteAnimationTargetCompat app) {
+ mAnimationTarget = app;
+ mStateCallback.setState(STATE_TASK_APPEARED_DURING_SWITCH);
+ }
+
public void dump(PrintWriter pw) {
pw.println("GestureState:");
pw.println(" gestureID=" + mGestureId);
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index 10f9feb..b0ce8e6 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -124,6 +124,17 @@
}
@Override
+ public void onRecentTaskListUpdated() {
+ // In some cases immediately after booting, the tasks in the system recent task list may be
+ // loaded, but not in the active task hierarchy in the system. These tasks are displayed in
+ // overview, but removing them don't result in a onTaskStackChanged() nor a onTaskRemoved()
+ // callback (those are for changes to the active tasks), but the task list is still updated,
+ // so we should also invalidate the change id to ensure we load a new list instead of
+ // reusing a stale list.
+ mChangeId++;
+ }
+
+ @Override
public void onTaskRemoved(int taskId) {
mTasks = loadTasksInBackground(Integer.MAX_VALUE, false);
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index d1dbcfb..7d568a4 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -118,6 +118,16 @@
});
}
+ @BinderThread
+ @Override
+ public void onTaskAppeared(RemoteAnimationTargetCompat app) {
+ Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
+ for (RecentsAnimationListener listener : getListeners()) {
+ listener.onTaskAppeared(app);
+ }
+ });
+ }
+
private final void onAnimationFinished(RecentsAnimationController controller) {
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
for (RecentsAnimationListener listener : getListeners()) {
@@ -147,5 +157,10 @@
* Callback made whenever the recents animation is finished.
*/
default void onRecentsAnimationFinished(RecentsAnimationController controller) {}
+
+ /**
+ * Callback made when a task started from the recents is ready for an app transition.
+ */
+ default void onTaskAppeared(RemoteAnimationTargetCompat app) {}
}
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index 8dd4aa4..5ece2d7 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -28,12 +28,14 @@
import android.view.KeyEvent;
import android.view.MotionEvent;
+import androidx.annotation.NonNull;
import androidx.annotation.UiThread;
import com.android.launcher3.util.Preconditions;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import java.util.function.Consumer;
import java.util.function.Supplier;
@@ -107,6 +109,15 @@
UI_HELPER_EXECUTOR.execute(() -> mController.cleanupScreenshot());
}
+ /**
+ * Remove task remote animation target from
+ * {@link RecentsAnimationCallbacks#onTaskAppeared(RemoteAnimationTargetCompat)}}.
+ */
+ @UiThread
+ public boolean removeTaskTarget(@NonNull RemoteAnimationTargetCompat target) {
+ return mController.removeTask(target.taskId);
+ }
+
@UiThread
public void finishAnimationToHome() {
finishAndClear(true /* toRecents */, null, false /* sendUserLeaveHint */);
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 8cb27a3..6dbf2b0 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -74,6 +74,8 @@
NavigationModeChangeListener,
DefaultDisplay.DisplayInfoChangeListener {
+ private static final String TAG = "RecentsAnimationDeviceState";
+
private final Context mContext;
private final SysUINavigationMode mSysUiNavMode;
private final DefaultDisplay mDefaultDisplay;
@@ -96,6 +98,7 @@
@Override
public void onReceive(Context context, Intent intent) {
if (ACTION_USER_UNLOCKED.equals(intent.getAction())) {
+ Log.d(TAG, "User Unlocked Broadcast Received");
mIsUserUnlocked = true;
notifyUserUnlocked();
}
diff --git a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
new file mode 100644
index 0000000..ab2484d
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+
+import android.content.SharedPreferences;
+
+import com.android.launcher3.BaseQuickstepLauncher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.LauncherStateManager;
+import com.android.launcher3.LauncherStateManager.StateListener;
+import com.android.launcher3.util.OnboardingPrefs;
+import com.android.quickstep.SysUINavigationMode;
+
+/**
+ * Extends {@link OnboardingPrefs} for quickstep-specific onboarding data.
+ */
+public class QuickstepOnboardingPrefs extends OnboardingPrefs<BaseQuickstepLauncher> {
+
+ public QuickstepOnboardingPrefs(BaseQuickstepLauncher launcher, SharedPreferences sharedPrefs,
+ LauncherStateManager stateManager) {
+ super(launcher, sharedPrefs, stateManager);
+
+ if (!getBoolean(HOME_BOUNCE_SEEN)) {
+ mStateManager.addStateListener(new StateListener() {
+ @Override
+ public void onStateTransitionStart(LauncherState toState) { }
+
+ @Override
+ public void onStateTransitionComplete(LauncherState finalState) {
+ boolean swipeUpEnabled = SysUINavigationMode.INSTANCE
+ .get(mLauncher).getMode().hasGestures;
+ LauncherState prevState = mStateManager.getLastState();
+
+ if (((swipeUpEnabled && finalState == OVERVIEW) || (!swipeUpEnabled
+ && finalState == ALL_APPS && prevState == NORMAL) ||
+ hasReachedMaxCount(HOME_BOUNCE_COUNT))) {
+ mSharedPrefs.edit().putBoolean(HOME_BOUNCE_SEEN, true).apply();
+ mStateManager.removeStateListener(this);
+ }
+ }
+ });
+ }
+
+ if (!getBoolean(SHELF_BOUNCE_SEEN)) {
+ mStateManager.addStateListener(new StateListener() {
+ @Override
+ public void onStateTransitionStart(LauncherState toState) { }
+
+ @Override
+ public void onStateTransitionComplete(LauncherState finalState) {
+ LauncherState prevState = mStateManager.getLastState();
+
+ if ((finalState == ALL_APPS && prevState == OVERVIEW) ||
+ hasReachedMaxCount(SHELF_BOUNCE_COUNT)) {
+ mSharedPrefs.edit().putBoolean(SHELF_BOUNCE_SEEN, true).apply();
+ mStateManager.removeStateListener(this);
+ }
+ }
+ });
+ }
+
+ if (!hasReachedMaxCount(ALL_APPS_COUNT)) {
+ mStateManager.addStateListener(new StateListener() {
+ @Override
+ public void onStateTransitionStart(LauncherState toState) { }
+
+ @Override
+ public void onStateTransitionComplete(LauncherState finalState) {
+ if (finalState == ALL_APPS) {
+ if (incrementEventCount(ALL_APPS_COUNT)) {
+ mStateManager.removeStateListener(this);
+ mLauncher.getScrimView().updateDragHandleVisibility();
+ }
+ }
+ }
+ });
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
index c2ccd90..f5498c9 100644
--- a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
+++ b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
@@ -43,6 +43,7 @@
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.uioverrides.states.OverviewState;
+import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ScrimView;
import com.android.quickstep.SysUINavigationMode;
@@ -75,6 +76,7 @@
private final float mRadius;
private final int mMaxScrimAlpha;
private final Paint mPaint;
+ private final OnboardingPrefs mOnboardingPrefs;
// Mid point where the alpha changes
private int mMidAlpha;
@@ -100,6 +102,7 @@
private boolean mRemainingScreenPathValid = false;
private Mode mSysUINavigationMode;
+ private boolean mIsTwoZoneSwipeModel;
public ShelfScrimView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -108,6 +111,7 @@
mEndAlpha = Color.alpha(mEndScrim);
mRadius = BOTTOM_CORNER_RADIUS_RATIO * Themes.getDialogCornerRadius(context);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mOnboardingPrefs = mLauncher.getOnboardingPrefs();
// Just assume the easiest UI for now, until we have the proper layout information.
mDrawingFlatColor = true;
@@ -140,9 +144,11 @@
// Show the shelf more quickly before reaching overview progress.
mBeforeMidProgressColorInterpolator = ACCEL_2;
mAfterMidProgressColorInterpolator = ACCEL;
+ mIsTwoZoneSwipeModel = FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get();
} else {
mBeforeMidProgressColorInterpolator = ACCEL;
mAfterMidProgressColorInterpolator = Interpolators.clampToProgress(ACCEL, 0.5f, 1f);
+ mIsTwoZoneSwipeModel = false;
}
}
@@ -236,9 +242,9 @@
@Override
protected boolean shouldDragHandleBeVisible() {
- boolean twoZoneSwipeModel = FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get()
- && SysUINavigationMode.removeShelfFromOverview(mLauncher);
- return twoZoneSwipeModel || super.shouldDragHandleBeVisible();
+ boolean needsAllAppsEdu = mIsTwoZoneSwipeModel
+ && !mOnboardingPrefs.hasReachedMaxCount(OnboardingPrefs.ALL_APPS_COUNT);
+ return needsAllAppsEdu || super.shouldDragHandleBeVisible();
}
@Override
diff --git a/res/layout/work_apps_paused.xml b/res/layout/work_apps_paused.xml
index f64b2d9..08e1c98 100644
--- a/res/layout/work_apps_paused.xml
+++ b/res/layout/work_apps_paused.xml
@@ -20,7 +20,7 @@
android:gravity="center">
<TextView
- style="@style/PrimaryMediumText"
+ style="@style/PrimaryHeadline"
android:textColor="?attr/workProfileOverlayTextColor"
android:id="@+id/work_apps_paused_title"
android:layout_width="wrap_content"
diff --git a/res/values/styles.xml b/res/values/styles.xml
index bc6ab45..fcc651b 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -226,6 +226,9 @@
<style name="TextHeadline" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle" />
<style name="PrimaryMediumText" parent="@android:style/TextAppearance.DeviceDefault.Medium"/>
+ <style name="PrimaryHeadline" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle">
+ <item name="android:textStyle">bold</item>
+ </style>
<style name="TextTitle" parent="@android:style/TextAppearance.DeviceDefault" />
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 48db5ea..f69940b 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -139,6 +139,7 @@
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
+import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.PendingRequestArgs;
@@ -300,6 +301,7 @@
// We only want to get the SharedPreferences once since it does an FS stat each time we get
// it from the context.
private SharedPreferences mSharedPrefs;
+ private OnboardingPrefs mOnboardingPrefs;
// Activity result which needs to be processed after workspace has loaded.
private ActivityResultInfo mPendingActivityResult;
@@ -367,6 +369,8 @@
mAllAppsController = new AllAppsTransitionController(this);
mStateManager = new LauncherStateManager(this);
+ mOnboardingPrefs = createOnboardingPrefs(mSharedPrefs, mStateManager);
+
mAppWidgetManager = new WidgetManagerHelper(this);
mAppWidgetHost = new LauncherAppWidgetHost(this,
appWidgetId -> getWorkspace().removeWidget(appWidgetId));
@@ -458,6 +462,15 @@
return new LauncherOverlayManager() { };
}
+ protected OnboardingPrefs createOnboardingPrefs(SharedPreferences sharedPrefs,
+ LauncherStateManager stateManager) {
+ return new OnboardingPrefs<>(this, sharedPrefs, stateManager);
+ }
+
+ public OnboardingPrefs getOnboardingPrefs() {
+ return mOnboardingPrefs;
+ }
+
@Override
public void onPluginConnected(OverlayPlugin overlayManager, Context context) {
switchOverlay(() -> overlayManager.createOverlayManager(this, this));
diff --git a/src/com/android/launcher3/allapps/DiscoveryBounce.java b/src/com/android/launcher3/allapps/DiscoveryBounce.java
index 0f0fc3a..fc29a30 100644
--- a/src/com/android/launcher3/allapps/DiscoveryBounce.java
+++ b/src/com/android/launcher3/allapps/DiscoveryBounce.java
@@ -24,7 +24,6 @@
import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.animation.AnimatorListenerAdapter;
-import android.content.SharedPreferences;
import android.os.Handler;
import android.os.UserManager;
import android.view.MotionEvent;
@@ -35,6 +34,7 @@
import com.android.launcher3.LauncherStateManager.StateListener;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.util.OnboardingPrefs;
/**
* Abstract base class of floating view responsible for showing discovery bounce animation
@@ -43,13 +43,6 @@
private static final long DELAY_MS = 450;
- public static final String HOME_BOUNCE_SEEN = "launcher.apps_view_shown";
- public static final String SHELF_BOUNCE_SEEN = "launcher.shelf_bounce_seen";
- public static final String HOME_BOUNCE_COUNT = "launcher.home_bounce_count";
- public static final String SHELF_BOUNCE_COUNT = "launcher.shelf_bounce_count";
-
- public static final int BOUNCE_MAX_COUNT = 3;
-
private final Launcher mLauncher;
private final Animator mDiscoBounceAnimation;
@@ -142,8 +135,9 @@
}
private static void showForHomeIfNeeded(Launcher launcher, boolean withDelay) {
+ OnboardingPrefs onboardingPrefs = launcher.getOnboardingPrefs();
if (!launcher.isInState(NORMAL)
- || launcher.getSharedPrefs().getBoolean(HOME_BOUNCE_SEEN, false)
+ || onboardingPrefs.getBoolean(OnboardingPrefs.HOME_BOUNCE_SEEN)
|| AbstractFloatingView.getTopOpenView(launcher) != null
|| launcher.getSystemService(UserManager.class).isDemoUser()
|| Utilities.IS_RUNNING_IN_TEST_HARNESS) {
@@ -154,7 +148,7 @@
new Handler().postDelayed(() -> showForHomeIfNeeded(launcher, false), DELAY_MS);
return;
}
- incrementHomeBounceCount(launcher);
+ onboardingPrefs.incrementEventCount(OnboardingPrefs.HOME_BOUNCE_COUNT);
new DiscoveryBounce(launcher, 0).show(HOTSEAT);
}
@@ -164,11 +158,12 @@
}
private static void showForOverviewIfNeeded(Launcher launcher, boolean withDelay) {
+ OnboardingPrefs onboardingPrefs = launcher.getOnboardingPrefs();
if (!launcher.isInState(OVERVIEW)
|| !launcher.hasBeenResumed()
|| launcher.isForceInvisible()
|| launcher.getDeviceProfile().isVerticalBarLayout()
- || launcher.getSharedPrefs().getBoolean(SHELF_BOUNCE_SEEN, false)
+ || onboardingPrefs.getBoolean(OnboardingPrefs.SHELF_BOUNCE_SEEN)
|| launcher.getSystemService(UserManager.class).isDemoUser()
|| Utilities.IS_RUNNING_IN_TEST_HARNESS) {
return;
@@ -182,7 +177,7 @@
// TODO: Move these checks to the top and call this method after invalidate handler.
return;
}
- incrementShelfBounceCount(launcher);
+ onboardingPrefs.incrementEventCount(OnboardingPrefs.SHELF_BOUNCE_COUNT);
new DiscoveryBounce(launcher, (1 - OVERVIEW.getVerticalProgress(launcher)))
.show(PREDICTION);
@@ -209,22 +204,4 @@
mController.setProgress(progress - mDelta);
}
}
-
- private static void incrementShelfBounceCount(Launcher launcher) {
- SharedPreferences sharedPrefs = launcher.getSharedPrefs();
- int count = sharedPrefs.getInt(SHELF_BOUNCE_COUNT, 0);
- if (count > BOUNCE_MAX_COUNT) {
- return;
- }
- sharedPrefs.edit().putInt(SHELF_BOUNCE_COUNT, count + 1).apply();
- }
-
- private static void incrementHomeBounceCount(Launcher launcher) {
- SharedPreferences sharedPrefs = launcher.getSharedPrefs();
- int count = sharedPrefs.getInt(HOME_BOUNCE_COUNT, 0);
- if (count > BOUNCE_MAX_COUNT) {
- return;
- }
- sharedPrefs.edit().putInt(HOME_BOUNCE_COUNT, count + 1).apply();
- }
}
diff --git a/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java b/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
index 2515c24..2de425e 100644
--- a/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
+++ b/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
@@ -135,8 +135,8 @@
@Override
public void setActiveMarker(int activePage) {
updateTabTextColor(activePage);
- updateIndicatorPosition(activePage);
if (mContainerView != null && mLastActivePage != activePage) {
+ updateIndicatorPosition(activePage);
mContainerView.onTabChanged(activePage);
}
mLastActivePage = activePage;
diff --git a/src/com/android/launcher3/allapps/WorkModeSwitch.java b/src/com/android/launcher3/allapps/WorkModeSwitch.java
index c1621b0..33262b6 100644
--- a/src/com/android/launcher3/allapps/WorkModeSwitch.java
+++ b/src/com/android/launcher3/allapps/WorkModeSwitch.java
@@ -25,6 +25,8 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
import android.widget.Switch;
import com.android.launcher3.Insettable;
@@ -46,16 +48,28 @@
private Rect mInsets = new Rect();
+ private final float[] mTouch = new float[2];
+ private int mTouchSlop;
+
public WorkModeSwitch(Context context) {
super(context);
+ init();
}
public WorkModeSwitch(Context context, AttributeSet attrs) {
super(context, attrs);
+ init();
+
}
public WorkModeSwitch(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
+ init();
+ }
+
+ private void init() {
+ ViewConfiguration viewConfiguration = ViewConfiguration.get(getContext());
+ mTouchSlop = viewConfiguration.getScaledTouchSlop();
}
@Override
@@ -84,6 +98,25 @@
setEnabled(true);
}
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ mTouch[0] = ev.getX();
+ mTouch[1] = ev.getY();
+ } else if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) {
+ if (Math.abs(mTouch[0] - ev.getX()) > mTouchSlop
+ || Math.abs(mTouch[1] - ev.getY()) > mTouchSlop) {
+ int action = ev.getAction();
+ ev.setAction(MotionEvent.ACTION_CANCEL);
+ super.onTouchEvent(ev);
+ ev.setAction(action);
+ return false;
+ }
+ }
+ return super.onTouchEvent(ev);
+ }
+
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index 96ddd57..32531c0 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -153,6 +153,7 @@
CellLayout page = (CellLayout) getChildAt(i);
ShortcutAndWidgetContainer container = page.getShortcutsAndWidgets();
for (int j = container.getChildCount() - 1; j >= 0; j--) {
+ container.getChildAt(j).setVisibility(View.VISIBLE);
mViewCache.recycleView(R.layout.folder_application, container.getChildAt(j));
}
page.removeAllViews();
diff --git a/src/com/android/launcher3/util/OnboardingPrefs.java b/src/com/android/launcher3/util/OnboardingPrefs.java
new file mode 100644
index 0000000..baa1eee
--- /dev/null
+++ b/src/com/android/launcher3/util/OnboardingPrefs.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.util;
+
+import android.content.SharedPreferences;
+import android.util.ArrayMap;
+
+import androidx.annotation.StringDef;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherStateManager;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * Stores and retrieves onboarding-related data via SharedPreferences.
+ */
+public class OnboardingPrefs<T extends Launcher> {
+
+ public static final String HOME_BOUNCE_SEEN = "launcher.apps_view_shown";
+ public static final String SHELF_BOUNCE_SEEN = "launcher.shelf_bounce_seen";
+ public static final String HOME_BOUNCE_COUNT = "launcher.home_bounce_count";
+ public static final String SHELF_BOUNCE_COUNT = "launcher.shelf_bounce_count";
+ public static final String ALL_APPS_COUNT = "launcher.all_apps_count";
+
+ /**
+ * Events that either have happened or have not (booleans).
+ */
+ @StringDef(value = {
+ HOME_BOUNCE_SEEN,
+ SHELF_BOUNCE_SEEN,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface EventBoolKey {}
+
+ /**
+ * Events that occur multiple times, which we count up to a max defined in {@link #MAX_COUNTS}.
+ */
+ @StringDef(value = {
+ HOME_BOUNCE_COUNT,
+ SHELF_BOUNCE_COUNT,
+ ALL_APPS_COUNT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface EventCountKey {}
+
+ private static final Map<String, Integer> MAX_COUNTS;
+ static {
+ Map<String, Integer> maxCounts = new ArrayMap<>(3);
+ maxCounts.put(HOME_BOUNCE_COUNT, 3);
+ maxCounts.put(SHELF_BOUNCE_COUNT, 3);
+ maxCounts.put(ALL_APPS_COUNT, 5);
+ MAX_COUNTS = Collections.unmodifiableMap(maxCounts);
+ }
+
+ protected final T mLauncher;
+ protected final SharedPreferences mSharedPrefs;
+ protected final LauncherStateManager mStateManager;
+
+ public OnboardingPrefs(T launcher, SharedPreferences sharedPrefs,
+ LauncherStateManager stateManager) {
+ mLauncher = launcher;
+ mSharedPrefs = sharedPrefs;
+ mStateManager = stateManager;
+ }
+
+ /** @return The number of times we have seen the given event. */
+ public int getCount(@EventCountKey String key) {
+ return mSharedPrefs.getInt(key, 0);
+ }
+
+ /** @return Whether we have seen this event enough times, as defined by {@link #MAX_COUNTS}. */
+ public boolean hasReachedMaxCount(@EventCountKey String eventKey) {
+ return hasReachedMaxCount(getCount(eventKey), eventKey);
+ }
+
+ private boolean hasReachedMaxCount(int count, @EventCountKey String eventKey) {
+ return count >= MAX_COUNTS.get(eventKey);
+ }
+
+ /** @return Whether we have seen the given event. */
+ public boolean getBoolean(@EventBoolKey String key) {
+ return mSharedPrefs.getBoolean(key, false);
+ }
+
+ /**
+ * Add 1 to the given event count, if we haven't already reached the max count.
+ * @return Whether we have now reached the max count.
+ */
+ public boolean incrementEventCount(@EventCountKey String eventKey) {
+ int count = getCount(eventKey);
+ if (hasReachedMaxCount(count, eventKey)) {
+ return true;
+ }
+ count++;
+ mSharedPrefs.edit().putInt(eventKey, count).apply();
+ return hasReachedMaxCount(count, eventKey);
+ }
+}
diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java
index 39e1eac..442c5fd 100644
--- a/src/com/android/launcher3/views/ScrimView.java
+++ b/src/com/android/launcher3/views/ScrimView.java
@@ -82,7 +82,7 @@
* Simple scrim which draws a flat color
*/
public class ScrimView<T extends Launcher> extends View implements Insettable, OnChangeListener,
- AccessibilityStateChangeListener, StateListener {
+ AccessibilityStateChangeListener {
public static final IntProperty<ScrimView> DRAG_HANDLE_ALPHA =
new IntProperty<ScrimView>("dragHandleAlpha") {
@@ -116,6 +116,18 @@
private final AccessibilityManager mAM;
protected final int mEndScrim;
+ private final StateListener mAccessibilityLauncherStateListener = new StateListener() {
+ @Override
+ public void onStateTransitionStart(LauncherState toState) {}
+
+ @Override
+ public void onStateTransitionComplete(LauncherState finalState) {
+ setImportantForAccessibility(finalState == ALL_APPS
+ ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
+ : IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+ }
+ };
+
protected float mMaxScrimAlpha;
protected float mProgress = 1;
@@ -177,7 +189,7 @@
@Override
public void setInsets(Rect insets) {
updateDragHandleBounds();
- updateDragHandleVisibility(null);
+ updateDragHandleVisibility();
}
@Override
@@ -375,18 +387,22 @@
@Override
public void onAccessibilityStateChanged(boolean enabled) {
LauncherStateManager stateManager = mLauncher.getStateManager();
- stateManager.removeStateListener(this);
+ stateManager.removeStateListener(mAccessibilityLauncherStateListener);
if (enabled) {
- stateManager.addStateListener(this);
- handleStateChangedComplete(stateManager.getState());
+ stateManager.addStateListener(mAccessibilityLauncherStateListener);
+ mAccessibilityLauncherStateListener.onStateTransitionComplete(stateManager.getState());
} else {
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
}
+ updateDragHandleVisibility();
+ }
+
+ public void updateDragHandleVisibility() {
updateDragHandleVisibility(null);
}
- private void updateDragHandleVisibility(Drawable recycle) {
+ private void updateDragHandleVisibility(@Nullable Drawable recycle) {
boolean visible = shouldDragHandleBeVisible();
boolean wasVisible = mDragHandle != null;
if (visible != wasVisible) {
@@ -424,20 +440,6 @@
mAccessibilityHelper.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
}
- @Override
- public void onStateTransitionStart(LauncherState toState) {}
-
- @Override
- public void onStateTransitionComplete(LauncherState finalState) {
- handleStateChangedComplete(finalState);
- }
-
- private void handleStateChangedComplete(LauncherState finalState) {
- setImportantForAccessibility(finalState == ALL_APPS
- ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
- : IMPORTANT_FOR_ACCESSIBILITY_AUTO);
- }
-
protected class AccessibilityHelper extends ExploreByTouchHelper {
private static final int DRAG_HANDLE_ID = 1;
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java b/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
index a56801f..313ea05 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -15,8 +15,8 @@
*/
package com.android.launcher3.uioverrides.states;
-import static com.android.launcher3.allapps.DiscoveryBounce.HOME_BOUNCE_SEEN;
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
+import static com.android.launcher3.util.OnboardingPrefs.HOME_BOUNCE_SEEN;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index a7089fe..86faddb 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -162,7 +162,6 @@
mLauncher.enableDebugTracing();
// Avoid double-reporting of Launcher crashes.
mLauncher.setOnLauncherCrashed(() -> mLauncherPid = 0);
- mLauncher.disableSensorRotation();
}
protected final LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
@@ -278,7 +277,6 @@
clearPackageData(mDevice.getLauncherPackageName());
mLauncher.enableDebugTracing();
mLauncherPid = mLauncher.getPid();
- mLauncher.disableSensorRotation();
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 710ce9e..af22704 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -247,6 +247,8 @@
}
}
}
+
+ disableSensorRotation();
}
public void enableCheckEventsForSuccessfulGestures() {
@@ -1263,7 +1265,7 @@
TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
- public void disableSensorRotation() {
+ private void disableSensorRotation() {
getTestInfo(TestProtocol.REQUEST_MOCK_SENSOR_ROTATION);
}