Merge changes I01790ce5,I938e23af into ub-launcher3-rvc-dev

* changes:
  Remove all apps arrow after getting to all apps 5 times
  Refactor some onboarding-related shared prefs into a class
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 3bb5b12..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();
         }
     }
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/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/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/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;