Launcher3: add support for hotseat qsb

and fix styles to support ListPreference

Change-Id: I571dfacf67a63872a8f7351ad9c6106397f79505

Launcher3: fix crash on taskbar usage

we use search_container_hotseat.xml for phone when using
qsb in hotseat. So add a new empty one for taskbar

Change-Id: I3df2c9ad432c51e06102b65282bcbc9c4848e6fa

Launcher3: fixup hardocded usages of QSB_ON_FIRST_SCREEN

Change-Id: Id8f6ca9c332f0c53bdf96c944f8daa361adeab1c

Launcher3: fix hotseat qsb widget width

we are not going beyond isScalableGrid in
recalculateHotseatWidthAndBorderSpace so hotseatQsbWidth is 0
in that case. To prevent any unwanted side effects add
a separate API for the width to use if not isQsbInline

Change-Id: I2d49127aa6ea3e10eab043f3f9a102154f1d8458
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 570221c..2bcb12f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -178,7 +178,7 @@
         }
 
         // TODO: Disable touch events on QSB otherwise it can crash.
-        mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false);
+        mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat_taskbar, this, false);
 
         // Default long press (touch) delay = 400ms
         mAllAppsButtonTouchDelayMs = ViewConfiguration.getLongPressTimeout();
diff --git a/res/layout/search_container_hotseat.xml b/res/layout/search_container_hotseat.xml
index 8f12ca0..3cbd402 100644
--- a/res/layout/search_container_hotseat.xml
+++ b/res/layout/search_container_hotseat.xml
@@ -14,7 +14,22 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<View
+<!--<View
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="0dp" />
\ No newline at end of file
+    android:layout_height="0dp" />-->
+
+<com.android.launcher3.qsb.QsbContainerView
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:id="@id/search_container_hotseat"
+        android:padding="0dp" >
+
+    <fragment
+        android:name="com.android.launcher3.qsb.QsbContainerView$QsbFragment"
+        android:layout_width="match_parent"
+        android:tag="qsb_view_hotseat"
+        android:layout_height="match_parent"/>
+</com.android.launcher3.qsb.QsbContainerView>
\ No newline at end of file
diff --git a/res/layout/search_container_hotseat_empty.xml b/res/layout/search_container_hotseat_empty.xml
new file mode 100644
index 0000000..8f12ca0
--- /dev/null
+++ b/res/layout/search_container_hotseat_empty.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+<View
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="0dp" />
\ No newline at end of file
diff --git a/res/layout/search_container_hotseat_taskbar.xml b/res/layout/search_container_hotseat_taskbar.xml
new file mode 100644
index 0000000..8f12ca0
--- /dev/null
+++ b/res/layout/search_container_hotseat_taskbar.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+<View
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="0dp" />
\ No newline at end of file
diff --git a/res/layout/search_container_workspace.xml b/res/layout/search_container_workspace.xml
index 1c617b1..3cf4f74 100644
--- a/res/layout/search_container_workspace.xml
+++ b/res/layout/search_container_workspace.xml
@@ -25,6 +25,6 @@
     <fragment
         android:name="com.android.launcher3.qsb.QsbContainerView$QsbFragment"
         android:layout_width="match_parent"
-        android:tag="qsb_view"
+        android:tag="qsb_view_workspace"
         android:layout_height="match_parent"/>
 </com.android.launcher3.qsb.QsbContainerView>
\ No newline at end of file
diff --git a/res/values/custom_arrays.xml b/res/values/custom_arrays.xml
new file mode 100644
index 0000000..37a0a19
--- /dev/null
+++ b/res/values/custom_arrays.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--  Copyright (C) 2018 The OmniROM Project
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string-array name="prefs_qsb_location_entries">
+        <item>@string/pref_qsb_location_hotseat</item>
+        <item>@string/pref_qsb_location_workspace</item>
+    </string-array>
+    <string-array name="prefs_qsb_location_values">
+        <item>"0"</item>
+        <item>"1"</item>
+    </string-array>
+</resources>
diff --git a/res/values/custom_strings.xml b/res/values/custom_strings.xml
index d68edfd..e161967 100644
--- a/res/values/custom_strings.xml
+++ b/res/values/custom_strings.xml
@@ -20,6 +20,11 @@
     <string name="state_loading">Applying\u2026</string>
     <string name="pref_qsb_show_summary"></string>
     <string name="pref_qsb_show_title">Show search widget</string>
+    <string name="pref_qsb_location_title">Search widget location</string>
+    <string name="pref_qsb_location_hotseat">Hotseat</string>
+    <string name="pref_qsb_location_hotseat_value" translatable="false">0</string>
+    <string name="pref_qsb_location_workspace">Workspace</string>
+    <string name="pref_qsb_location_workspace_value" translatable="false">1</string>
     <string name="pref_grid_title">Grid size</string>
 
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 562da3b..2da5a02 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -410,7 +410,7 @@
         @*android:dimen/rounded_corner_content_padding
     </dimen>
     <dimen name="taskbar_stashed_size">0dp</dimen>
-    <dimen name="qsb_widget_height">0dp</dimen>
+    <dimen name="qsb_widget_height">72dp</dimen>
     <dimen name="qsb_shadow_height">0dp</dimen>
     <dimen name="min_hotseat_icon_space">18dp</dimen>
     <dimen name="max_hotseat_icon_space">50dp</dimen>
diff --git a/res/xml/launcher_preferences.xml b/res/xml/launcher_preferences.xml
index 4f486b6..94617d1 100644
--- a/res/xml/launcher_preferences.xml
+++ b/res/xml/launcher_preferences.xml
@@ -57,6 +57,16 @@
         android:summary="@string/pref_qsb_show_summary"
         android:title="@string/pref_qsb_show_title"/>
 
+
+    <ListPreference
+        android:key="pref_qsb_location"
+        android:title="@string/pref_qsb_location_title"
+        android:persistent="true"
+        android:dependency="pref_qsb_show"
+        android:entries="@array/prefs_qsb_location_entries"
+        android:entryValues="@array/prefs_qsb_location_values"
+        android:defaultValue="@string/pref_qsb_location_workspace_value"/>
+
     <ListPreference
         android:key="pref_grid"
         android:title="@string/pref_grid_title"
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 00db3a3..a403544 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -71,6 +71,7 @@
 import com.android.launcher3.util.ResourceHelper;
 import com.android.launcher3.util.WindowBounds;
 import com.android.launcher3.util.window.WindowManagerProxy;
+import com.android.launcher3.Utilities;
 
 import java.io.PrintWriter;
 import java.util.Locale;
@@ -540,7 +541,7 @@
 
         workspaceCellPaddingXPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_padding_x);
 
-        hotseatQsbHeight = res.getDimensionPixelSize(R.dimen.qsb_widget_height);
+        hotseatQsbHeight = Utilities.showHotseatQsbWidget(context) ? res.getDimensionPixelSize(R.dimen.qsb_widget_height) : 0;
         hotseatQsbShadowHeight = res.getDimensionPixelSize(R.dimen.qsb_shadow_height);
         hotseatQsbVisualHeight = hotseatQsbHeight - 2 * hotseatQsbShadowHeight;
 
@@ -887,6 +888,13 @@
     }
 
     /**
+     * used in Hotseat only for !isQsbInline
+     */
+    public int getHostseatQsbWidth() {
+        return calculateQsbWidth(0);
+    }
+
+    /**
      * Calculates the width of the hotseat, changing spaces between the icons and removing icons if
      * necessary.
      */
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 8546454..117c281 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -33,6 +33,7 @@
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
+import com.android.launcher3.Utilities;
 import com.android.launcher3.util.HorizontalInsettableView;
 import com.android.launcher3.util.MultiTranslateDelegate;
 import com.android.launcher3.views.ActivityContext;
@@ -64,7 +65,11 @@
     public Hotseat(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
 
-        mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false);
+        if (Utilities.showHotseatQsbWidget(context)) {
+            mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false);
+        } else {
+            mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat_empty, this, false);
+        }
         addView(mQsb);
     }
 
@@ -248,7 +253,8 @@
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 
         DeviceProfile dp = mActivity.getDeviceProfile();
-        mQsb.measure(MeasureSpec.makeMeasureSpec(dp.hotseatQsbWidth, MeasureSpec.EXACTLY),
+        int hotseatQsbWidth = dp.isQsbInline ? dp.hotseatQsbWidth : dp.getHostseatQsbWidth();
+        mQsb.measure(MeasureSpec.makeMeasureSpec(hotseatQsbWidth, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(dp.hotseatQsbHeight, MeasureSpec.EXACTLY));
     }
 
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index c1ef4b4..b38db5d 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -24,6 +24,7 @@
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN;
+import static com.android.launcher3.settings.SettingsActivity.QSB_LOCATION_PREFERENCE_KEY;
 
 import android.annotation.SuppressLint;
 import android.app.ActivityManager;
@@ -195,6 +196,19 @@
                 context.getResources().getBoolean(R.bool.qsb_show_default));
     }
 
+    public static String qsbWidgtLocation(Context context) {
+         return LauncherPrefs.getPrefs(context).getString(QSB_LOCATION_PREFERENCE_KEY,
+                context.getResources().getString(R.string.pref_qsb_location_workspace_value));
+    }
+
+    public static boolean showHotseatQsbWidget(Context context) {
+         return showQsbWidget(context) && qsbWidgtLocation(context).equals(context.getResources().getString(R.string.pref_qsb_location_hotseat_value));
+    }
+
+    public static boolean showWorkspaceQsbWidget(Context context) {
+         return showQsbWidget(context) && qsbWidgtLocation(context).equals(context.getResources().getString(R.string.pref_qsb_location_workspace_value));
+    }
+
     /**
      * Given a coordinate relative to the descendant, find the coordinate in a parent view's
      * coordinates.
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 0676c05..460d175 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -597,7 +597,7 @@
      * Initializes and binds the first page
      */
     public void bindAndInitFirstWorkspaceScreen() {
-        if ((!Utilities.showQsbWidget(mContext)
+        if ((!Utilities.showWorkspaceQsbWidget(mContext)
                 || !mLauncher.getIsFirstPagePinnedItemEnabled())
                 || SHOULD_SHOW_FIRST_PAGE_WIDGET) {
             mFirstPagePinnedItem = null;
@@ -1038,7 +1038,7 @@
             int id = mWorkspaceScreens.keyAt(i);
             CellLayout cl = mWorkspaceScreens.valueAt(i);
             // FIRST_SCREEN_ID can never be removed.
-            if (((!Utilities.showQsbWidget(getContext())
+            if (((!Utilities.showWorkspaceQsbWidget(getContext())
                     || SHOULD_SHOW_FIRST_PAGE_WIDGET)
                     || id > FIRST_SCREEN_ID)
                     && cl.getShortcutsAndWidgets().getChildCount() == 0) {
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 82bf1ba..3117085 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -50,7 +50,7 @@
      */
     @Deprecated
     // NOTE: replaced by resource qsb_show_default
-    public static final boolean QSB_ON_FIRST_SCREEN = true;
+    public static final boolean QSB_ON_FIRST_SCREEN = BuildConfig.QSB_ON_FIRST_SCREEN;
 
     /**
      * Feature flag to handle define config changes dynamically instead of killing the process.
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 91deef1..9b51d74 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -504,7 +504,7 @@
         }
 
         // Add first page QSB
-        if (Utilities.showQsbWidget(mContext) && dataModel.isFirstPagePinnedItemEnabled
+        if (Utilities.showWorkspaceQsbWidget(mContext) && dataModel.isFirstPagePinnedItemEnabled
                 && !SHOULD_SHOW_FIRST_PAGE_WIDGET) {
             CellLayout firstScreen = mWorkspaceScreens.get(FIRST_SCREEN_ID);
             View qsb = mHomeElementInflater.inflate(R.layout.qsb_preview, firstScreen, false);
diff --git a/src/com/android/launcher3/model/DatabaseHelper.java b/src/com/android/launcher3/model/DatabaseHelper.java
index 8368256..8d20fb0 100644
--- a/src/com/android/launcher3/model/DatabaseHelper.java
+++ b/src/com/android/launcher3/model/DatabaseHelper.java
@@ -258,7 +258,7 @@
                         Favorites.SCREEN, IntArray.wrap(-777, -778)), null);
             }
             case 30: {
-                if (FeatureFlags.QSB_ON_FIRST_SCREEN
+                if (Utilities.showWorkspaceQsbWidget(mContext)
                         && !SHOULD_SHOW_FIRST_PAGE_WIDGET) {
                     // Clean up first row in screen 0 as it might contain junk data.
                     Log.d(TAG, "Cleaning up first row");
diff --git a/src/com/android/launcher3/model/GridSizeMigrationUtil.java b/src/com/android/launcher3/model/GridSizeMigrationUtil.java
index ad32fc2..b3a1544 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationUtil.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationUtil.java
@@ -347,7 +347,7 @@
         final GridOccupancy occupied = new GridOccupancy(trgX, trgY);
         final Point trg = new Point(trgX, trgY);
         final Point next = new Point(0, screenId == 0
-                && (FeatureFlags.QSB_ON_FIRST_SCREEN
+                && (Utilities.showWorkspaceQsbWidget(destReader.mContext)
                 && (!enableSmartspaceRemovalToggle() || LauncherPrefs.getPrefs(destReader.mContext)
                 .getBoolean(SMARTSPACE_ON_HOME_SCREEN, true))
                 && !SHOULD_SHOW_FIRST_PAGE_WIDGET)
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index b668b84..179cf3b 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -553,7 +553,7 @@
 
         if (!mOccupied.containsKey(item.screenId)) {
             GridOccupancy screen = new GridOccupancy(countX + 1, countY + 1);
-            if (item.screenId == Workspace.FIRST_SCREEN_ID && (FeatureFlags.QSB_ON_FIRST_SCREEN
+            if (item.screenId == Workspace.FIRST_SCREEN_ID && (Utilities.showWorkspaceQsbWidget(mContext)
                     && !SHOULD_SHOW_FIRST_PAGE_WIDGET
                     && isFirstPagePinnedItemEnabled)) {
                 // Mark the first X columns (X is width of the search container) in the first row as
@@ -561,7 +561,7 @@
                 // container.
                 int spanX = mIDP.numSearchContainerColumns;
                 int spanY = 1;
-                screen.markCells(0, 0, spanX, spanY, Utilities.showQsbWidget(mContext));
+                screen.markCells(0, 0, spanX, spanY, Utilities.showWorkspaceQsbWidget(mContext));
             }
             mOccupied.put(item.screenId, screen);
         }
diff --git a/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java b/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java
index 1a6d178..7e025ac 100644
--- a/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java
+++ b/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java
@@ -25,6 +25,7 @@
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.util.GridOccupancy;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
@@ -67,7 +68,7 @@
         int screenCount = workspaceScreens.size();
         // First check the preferred screen.
         IntSet screensToExclude = new IntSet();
-        if (FeatureFlags.QSB_ON_FIRST_SCREEN
+        if (Utilities.showWorkspaceQsbWidget(app.getContext())
                 && !SHOULD_SHOW_FIRST_PAGE_WIDGET) {
             screensToExclude.add(FIRST_SCREEN_ID);
         }
diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java
index 6379469..46995b2 100644
--- a/src/com/android/launcher3/settings/SettingsActivity.java
+++ b/src/com/android/launcher3/settings/SettingsActivity.java
@@ -83,6 +83,7 @@
 
     private static final String NOTIFICATION_DOTS_PREFERENCE_KEY = "pref_icon_badging";
     private static final String GRID_SIZE_PREFERENCE_KEY = "pref_grid";
+    public static final String QSB_LOCATION_PREFERENCE_KEY = "pref_qsb_location";
 
     public static final String EXTRA_FRAGMENT_ARGS = ":settings:fragment_args";
 
@@ -269,6 +270,16 @@
                     return true;
                 }
             });
+
+            final ListPreference qsbLocation = (ListPreference) findPreference(QSB_LOCATION_PREFERENCE_KEY);
+            valueIndex = qsbLocation.findIndexOfValue(qsbLocation.getValue());
+            qsbLocation.setSummary(qsbLocation.getEntries()[valueIndex]);
+            qsbLocation.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+                public boolean onPreferenceChange(Preference preference, Object newValue) {
+                    new Handler().postDelayed(() -> Utilities.restart(getActivity()), Utilities.WAIT_BEFORE_RESTART);
+                    return true;
+                }
+            });
         }
 
         @Override