Merge " Introduce feature education for AllApps Search"
diff --git a/quickstep/res/layout/fallback_search_input.xml b/quickstep/res/layout/fallback_search_input.xml
new file mode 100644
index 0000000..0fb2924
--- /dev/null
+++ b/quickstep/res/layout/fallback_search_input.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+<com.android.launcher3.search.FallbackSearchInputView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_gravity="center_vertical"
+    android:layout_marginLeft="48dp"
+    android:layout_marginRight="48dp"
+    android:background="@android:color/transparent"
+    android:focusableInTouchMode="true"
+    android:gravity="start|center_vertical"
+    android:inputType="textNoSuggestions"
+    android:imeOptions="actionSearch|flagNoExtractUi"
+    android:maxLines="1"
+    android:privateImeOptions="bc_search"
+    android:scrollHorizontally="true"
+    android:singleLine="true"
+    android:textColor="?android:attr/textColorSecondary"
+    android:textColorHint="?android:attr/textColorTertiary"
+    android:textSize="16sp" />
\ No newline at end of file
diff --git a/quickstep/res/layout/search_edu_view.xml b/quickstep/res/layout/search_edu_view.xml
new file mode 100644
index 0000000..d89f5c7
--- /dev/null
+++ b/quickstep/res/layout/search_edu_view.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2008 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.
+-->
+<com.android.launcher3.search.DeviceSearchEdu
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_gravity="center_horizontal"
+    android:orientation="vertical">
+
+
+    <FrameLayout
+        android:layout_height="wrap_content"
+        android:id="@+id/search_box_wrapper"
+        android:layout_width="match_parent">
+
+        <include
+            layout="@layout/fallback_search_input"
+            android:id="@+id/mock_search_box" />
+    </FrameLayout>
+
+    <LinearLayout
+        android:layout_height="wrap_content"
+        android:id="@+id/edu_wrapper"
+        android:padding="24dp"
+        android:layout_marginTop="40dp"
+        android:orientation="vertical"
+        android:layout_width="match_parent">
+
+        <TextView
+            style="@style/TextHeadline"
+            android:layout_width="match_parent"
+            android:gravity="center"
+            android:textSize="24sp"
+            android:textColor="?android:attr/textColorPrimary"
+            android:layout_height="wrap_content"
+            android:text="@string/search_edu_primary" />
+
+        <TextView
+            style="@style/TextHeadline"
+            android:layout_width="match_parent"
+            android:gravity="center"
+            android:textSize="18sp"
+            android:layout_marginTop="30dp"
+            android:textColor="?android:attr/textColorPrimary"
+            android:layout_height="wrap_content"
+            android:text="@string/search_edu_secondary" />
+
+        <Button
+            android:id="@+id/dismiss_edu"
+            android:layout_width="wrap_content"
+            android:layout_marginTop="@dimen/dynamic_grid_edge_margin"
+            android:background="?android:attr/selectableItemBackground"
+            android:layout_height="wrap_content"
+            android:textColor="?android:attr/textColorPrimary"
+            android:gravity="center"
+            android:layout_gravity="center"
+            android:text="@string/search_edu_dismiss" />
+
+    </LinearLayout>
+
+</com.android.launcher3.search.DeviceSearchEdu>
\ No newline at end of file
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 4b45b10..9a4487c 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -93,6 +93,15 @@
     <!-- content description for hotseat items -->
     <string name="hotseat_prediction_content_description">Predicted app: <xliff:g id="title" example="Chrome">%1$s</xliff:g></string>
 
+    <!-- primary educational text shown for first time search users -->
+    <string name="search_edu_primary">Search your phone for apps, people, settings and more!</string>
+    <!-- secondary educational text shown for first time search users -->
+    <string name="search_edu_secondary">Tap keyboard search button to launch the first search
+        result.</string>
+
+    <!-- Dismiss button string for search education view -->
+    <string name="search_edu_dismiss">Got it.</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>
     <!-- Subtitle shown during interactive parts of Back gesture tutorial for right edge. [CHAR LIMIT=60] -->
diff --git a/quickstep/src/com/android/launcher3/search/DeviceSearchEdu.java b/quickstep/src/com/android/launcher3/search/DeviceSearchEdu.java
new file mode 100644
index 0000000..425e557
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/search/DeviceSearchEdu.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2021 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.search;
+
+import static com.android.launcher3.util.OnboardingPrefs.SEARCH_EDU_SEEN;
+
+import android.animation.PropertyValuesHolder;
+import android.content.Context;
+import android.graphics.Rect;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import androidx.core.graphics.ColorUtils;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Insettable;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.R;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.util.Themes;
+import com.android.launcher3.views.AbstractSlideInView;
+
+/**
+ * Feature education for on-device Search. Shown the first time user opens AllApps Search
+ */
+public class DeviceSearchEdu extends AbstractSlideInView implements
+        StateManager.StateListener<LauncherState>, TextWatcher, Insettable,
+        TextView.OnEditorActionListener {
+
+    private static final long ANIMATION_DURATION = 350;
+    private static final int ANIMATION_CONTENT_TRANSLATION = 200;
+
+    private EditText mEduInput;
+
+    private View mInputWrapper;
+    private EditText mSearchInput;
+
+    private boolean mSwitchFocusOnDismiss;
+
+
+    public DeviceSearchEdu(Context context) {
+        this(context, null, 0);
+    }
+
+    public DeviceSearchEdu(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public DeviceSearchEdu(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+
+    private void close(boolean animate, boolean markAsSeen) {
+        handleClose(animate);
+        if (markAsSeen) {
+            mLauncher.getOnboardingPrefs().markChecked(SEARCH_EDU_SEEN);
+        }
+    }
+
+    @Override
+    protected void handleClose(boolean animate) {
+        handleClose(animate, ANIMATION_DURATION);
+        mLauncher.getStateManager().removeStateListener(this);
+    }
+
+    @Override
+    protected boolean isOfType(int type) {
+        return false;
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mSearchInput = mLauncher.getAppsView().getSearchUiManager().getEditText();
+        mInputWrapper = findViewById(R.id.search_box_wrapper);
+        mContent = findViewById(R.id.edu_wrapper);
+
+        mEduInput = findViewById(R.id.mock_search_box);
+        mEduInput.setHint(R.string.all_apps_on_device_search_bar_hint);
+        mEduInput.addTextChangedListener(this);
+        if (mSearchInput != null) {
+            mEduInput.getLayoutParams().height = mSearchInput.getHeight();
+            mEduInput.setOnEditorActionListener(this);
+        } else {
+            mEduInput.setVisibility(INVISIBLE);
+        }
+
+        findViewById(R.id.dismiss_edu).setOnClickListener((view) -> {
+            mSwitchFocusOnDismiss = true;
+            close(true, true);
+        });
+    }
+
+    private void showInternal() {
+        mLauncher.getStateManager().addStateListener(this);
+        AbstractFloatingView.closeAllOpenViews(mLauncher);
+        attachToContainer();
+        if (mSearchInput != null) {
+            Rect r = mLauncher.getViewBounds(mSearchInput);
+            mEduInput.requestFocus();
+            InputMethodManager imm = mLauncher.getSystemService(InputMethodManager.class);
+            imm.showSoftInput(mEduInput, InputMethodManager.SHOW_IMPLICIT);
+            ((LayoutParams) mInputWrapper.getLayoutParams()).setMargins(0, r.top, 0, 0);
+        }
+        animateOpen();
+    }
+
+    @Override
+    protected int getScrimColor(Context context) {
+        return ColorUtils.setAlphaComponent(Themes.getAttrColor(context, R.attr.allAppsScrimColor),
+                230);
+    }
+
+    protected void setTranslationShift(float translationShift) {
+        mTranslationShift = translationShift;
+        mContent.setAlpha(getBoxedProgress(1 - mTranslationShift, .25f, 1));
+        mContent.setTranslationY(ANIMATION_CONTENT_TRANSLATION * translationShift);
+        if (mColorScrim != null) {
+            mColorScrim.setAlpha(getBoxedProgress(1 - mTranslationShift, 0, .75f));
+        }
+    }
+
+    /**
+     * Given input [0-1], returns progress within bounds [min,max] allowing for staged animations
+     */
+    private float getBoxedProgress(float input, float min, float max) {
+        if (input < min) return 0;
+        if (input > max) return 1;
+        return (input - min) / (max - min);
+    }
+
+    private void animateOpen() {
+        if (mIsOpen || mOpenCloseAnimator.isRunning()) {
+            return;
+        }
+        mIsOpen = true;
+        mOpenCloseAnimator.setValues(
+                PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
+        mOpenCloseAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+        mOpenCloseAnimator.setDuration(ANIMATION_DURATION);
+        mOpenCloseAnimator.start();
+    }
+
+    /**
+     * Show On-device search education view.
+     */
+    public static void show(Launcher launcher) {
+        LayoutInflater layoutInflater = LayoutInflater.from(launcher);
+        ((DeviceSearchEdu) layoutInflater.inflate(
+                R.layout.search_edu_view, launcher.getDragLayer(),
+                false)).showInternal();
+    }
+
+    @Override
+    public void onStateTransitionStart(LauncherState toState) {
+        close(true, false);
+    }
+
+    @Override
+    protected void onCloseComplete() {
+        super.onCloseComplete();
+        if (mSearchInput != null && mSwitchFocusOnDismiss) {
+            mSearchInput.requestFocus();
+            mSearchInput.setSelection(mSearchInput.getText().length());
+        }
+    }
+
+    @Override
+    public void afterTextChanged(Editable editable) {
+        //Does nothing
+    }
+
+    @Override
+    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+        //Does nothing
+    }
+
+    @Override
+    public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+        if (mSearchInput != null) {
+            mSearchInput.setText(charSequence.toString());
+            mSwitchFocusOnDismiss = true;
+            close(true, true);
+        }
+    }
+
+    @Override
+    public void setInsets(Rect insets) {
+
+    }
+
+    @Override
+    public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) {
+        mSearchInput.onEditorAction(i);
+        close(true, true);
+        return true;
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/search/FallbackSearchInputView.java b/quickstep/src/com/android/launcher3/search/FallbackSearchInputView.java
new file mode 100644
index 0000000..7b10622
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/search/FallbackSearchInputView.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2021 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.search;
+
+import static com.android.launcher3.LauncherState.ALL_APPS;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+
+import com.android.launcher3.ExtendedEditText;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.allapps.AllAppsContainerView;
+import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem;
+import com.android.launcher3.allapps.AllAppsStore;
+import com.android.launcher3.allapps.AlphabeticalAppsList;
+import com.android.launcher3.allapps.FloatingHeaderView;
+import com.android.launcher3.allapps.search.AllAppsSearchBarController;
+import com.android.launcher3.allapps.search.SearchAlgorithm;
+
+import java.util.ArrayList;
+
+/**
+ * A search view shown in all apps for on device search
+ */
+public class FallbackSearchInputView extends ExtendedEditText
+        implements AllAppsSearchBarController.Callbacks, AllAppsStore.OnUpdateListener {
+
+    private final AllAppsSearchBarController mSearchBarController;
+
+    private AlphabeticalAppsList mApps;
+    private Runnable mOnResultsChanged;
+    private AllAppsContainerView mAppsView;
+
+    public FallbackSearchInputView(Context context) {
+        this(context, null);
+    }
+
+    public FallbackSearchInputView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public FallbackSearchInputView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mSearchBarController = new AllAppsSearchBarController();
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        Launcher.getLauncher(getContext()).getAppsView().getAppsStore().addUpdateListener(this);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        Launcher.getLauncher(getContext()).getAppsView().getAppsStore().removeUpdateListener(this);
+    }
+
+    /**
+     * Initializes SearchInput
+     */
+    public void initialize(AllAppsContainerView appsView, SearchAlgorithm algo, Runnable changed) {
+        mOnResultsChanged = changed;
+        mApps = appsView.getApps();
+        mAppsView = appsView;
+        mSearchBarController.initialize(algo, this, Launcher.getLauncher(getContext()), this);
+    }
+
+    @Override
+    public void onSearchResult(String query, ArrayList<AdapterItem> items) {
+        if (mApps != null && getParent() != null) {
+            mApps.setSearchResults(items);
+            notifyResultChanged();
+            collapseAppsViewHeader(true);
+            mAppsView.setLastSearchQuery(query);
+        }
+    }
+
+    @Override
+    public void onAppendSearchResult(String query, ArrayList<AdapterItem> items) {
+        if (mApps != null && getParent() != null) {
+            mApps.appendSearchResults(items);
+            notifyResultChanged();
+        }
+    }
+
+    @Override
+    public void clearSearchResult() {
+        if (getParent() != null && mApps != null) {
+            mApps.setSearchResults(null);
+            notifyResultChanged();
+            collapseAppsViewHeader(false);
+            mAppsView.onClearSearchResult();
+        }
+    }
+
+    @Override
+    public void onAppsUpdated() {
+        mSearchBarController.refreshSearchResult();
+    }
+
+    private void collapseAppsViewHeader(boolean collapse) {
+        FloatingHeaderView header = mAppsView.getFloatingHeaderView();
+        if (header != null) {
+            header.setCollapsed(collapse);
+        }
+    }
+
+    private void notifyResultChanged() {
+        if (mOnResultsChanged != null) {
+            mOnResultsChanged.run();
+        }
+        mAppsView.onSearchResultsChanged();
+    }
+
+    @Override
+    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
+        // TODO: Consider animating the state transition here
+        if (focused) {
+            // Getting focus will open the keyboard. Go to the all-apps state, so that the input
+            // box is at the top and there is enough space below to show search results.
+            Launcher.getLauncher(getContext()).getStateManager().goToState(ALL_APPS, false);
+        }
+        super.onFocusChanged(focused, direction, previouslyFocusedRect);
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
index a85f0d2..9ee9f00 100644
--- a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
+++ b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
@@ -29,6 +29,7 @@
 import com.android.launcher3.Workspace;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.hybridhotseat.HotseatPredictionController;
+import com.android.launcher3.search.DeviceSearchEdu;
 import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.statemanager.StateManager.StateListener;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
@@ -41,6 +42,7 @@
  */
 public class QuickstepOnboardingPrefs extends OnboardingPrefs<QuickstepLauncher> {
 
+
     public QuickstepOnboardingPrefs(QuickstepLauncher launcher, SharedPreferences sharedPrefs) {
         super(launcher, sharedPrefs);
 
@@ -131,5 +133,18 @@
                 }
             });
         }
+
+        if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && !getBoolean(SEARCH_EDU_SEEN)) {
+            stateManager.addStateListener(new StateListener<LauncherState>() {
+                @Override
+                public void onStateTransitionStart(LauncherState toState) {
+                    if (toState == ALL_APPS) {
+                        mLauncher.getAllAppsController().getInsetController().setSearchEduRunnable(
+                                () -> DeviceSearchEdu.show(launcher));
+                        stateManager.removeStateListener(this);
+                    }
+                }
+            });
+        }
     }
 }
diff --git a/src/com/android/launcher3/allapps/AllAppsInsetTransitionController.java b/src/com/android/launcher3/allapps/AllAppsInsetTransitionController.java
index 93da1c0..1cf98e1 100644
--- a/src/com/android/launcher3/allapps/AllAppsInsetTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsInsetTransitionController.java
@@ -44,6 +44,8 @@
     private WindowInsetsAnimationController mAnimationController;
     private WindowInsetsAnimationControlListener mCurrentRequest;
 
+    private Runnable mSearchEduRunnable;
+
     private float mAllAppsHeight;
 
     private int mDownInsetBottom;
@@ -55,12 +57,28 @@
     private float mDown, mCurrent;
     private View mApps;
 
+    /**
+     *
+     */
+    public boolean showSearchEduIfNecessary() {
+        if (mSearchEduRunnable == null) {
+            return false;
+        }
+        mSearchEduRunnable.run();
+        return true;
+    }
+
+    public void setSearchEduRunnable(Runnable eduRunnable) {
+        mSearchEduRunnable = eduRunnable;
+    }
+
     // Only purpose of these states is to keep track of fast fling transition
     enum State {
         RESET, DRAG_START_BOTTOM, DRAG_START_BOTTOM_IME_CANCELLED,
         FLING_END_TOP, FLING_END_TOP_IME_CANCELLED,
         DRAG_START_TOP, FLING_END_BOTTOM
     }
+
     private State mState;
 
     public AllAppsInsetTransitionController(float allAppsHeight, View appsView) {
@@ -77,7 +95,7 @@
         boolean imeVisible = insets.isVisible(WindowInsets.Type.ime());
 
         if (DEBUG) {
-            Log.d(TAG, "\nhide imeVisible=" +  imeVisible);
+            Log.d(TAG, "\nhide imeVisible=" + imeVisible);
         }
         if (insets.isVisible(WindowInsets.Type.ime())) {
             mApps.getWindowInsetsController().hide(WindowInsets.Type.ime());
@@ -107,7 +125,7 @@
         // mShownAtDown = mApps.getRootWindowInsets().isVisible(WindowInsets.Type.ime());
 
         if (DEBUG) {
-            Log.d(TAG, "\nonDragStart progress=" +  progress
+            Log.d(TAG, "\nonDragStart progress=" + progress
                     + " mDownInsets=" + mDownInsetBottom
                     + " mShownAtDown=" + mShownAtDown);
         }
@@ -123,7 +141,7 @@
                         }
                         if (controller != null) {
                             if (mCurrentRequest == this && !handleFinishOnFling(controller)) {
-                                    mAnimationController = controller;
+                                mAnimationController = controller;
                             } else {
                                 controller.finish(false /* just don't show */);
                             }
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index c03619e..2f805fd 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -270,11 +270,10 @@
             if (Float.compare(mProgress, 0f) == 0) {
                 mLauncher.getLiveSearchManager().start();
                 EditText editText = mAppsView.getSearchUiManager().getEditText();
-                if (editText != null) {
+                if (editText != null && !mInsetController.showSearchEduIfNecessary()) {
                     editText.requestFocus();
                 }
-            }
-            else {
+            } else {
                 mLauncher.getLiveSearchManager().stop();
             }
             // TODO: should make the controller hide synchronously
diff --git a/src/com/android/launcher3/util/OnboardingPrefs.java b/src/com/android/launcher3/util/OnboardingPrefs.java
index 14df0f3..2e279fa 100644
--- a/src/com/android/launcher3/util/OnboardingPrefs.java
+++ b/src/com/android/launcher3/util/OnboardingPrefs.java
@@ -36,13 +36,15 @@
     public static final String HOME_BOUNCE_COUNT = "launcher.home_bounce_count";
     public static final String HOTSEAT_DISCOVERY_TIP_COUNT = "launcher.hotseat_discovery_tip_count";
     public static final String HOTSEAT_LONGPRESS_TIP_SEEN = "launcher.hotseat_longpress_tip_seen";
+    public static final String SEARCH_EDU_SEEN = "launcher.search_edu";
 
     /**
      * Events that either have happened or have not (booleans).
      */
     @StringDef(value = {
             HOME_BOUNCE_SEEN,
-            HOTSEAT_LONGPRESS_TIP_SEEN
+            HOTSEAT_LONGPRESS_TIP_SEEN,
+            SEARCH_EDU_SEEN
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface EventBoolKey {}
diff --git a/src/com/android/launcher3/views/AbstractSlideInView.java b/src/com/android/launcher3/views/AbstractSlideInView.java
index 11c1029..e08f881 100644
--- a/src/com/android/launcher3/views/AbstractSlideInView.java
+++ b/src/com/android/launcher3/views/AbstractSlideInView.java
@@ -64,7 +64,7 @@
     protected final ObjectAnimator mOpenCloseAnimator;
 
     protected View mContent;
-    private final View mColorScrim;
+    protected final View mColorScrim;
     protected Interpolator mScrollInterpolator;
 
     // range [0, 1], 0=> completely open, 1=> completely closed
@@ -216,7 +216,6 @@
         return mLauncher.getDragLayer();
     }
 
-
     protected static View createColorScrim(Context context, int bgColor) {
         View view = new View(context);
         view.forceHasOverlappingRendering(false);