diff --git a/lawnchair/res/color/hotseat_qsb_bg_color.xml b/lawnchair/res/color/hotseat_qsb_bg_color.xml
new file mode 100644
index 0000000000..ec3edc0eb8
--- /dev/null
+++ b/lawnchair/res/color/hotseat_qsb_bg_color.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/lawnchair/res/drawable/bg_google_qsb.xml b/lawnchair/res/drawable/bg_google_qsb.xml
new file mode 100644
index 0000000000..8e3425d32f
--- /dev/null
+++ b/lawnchair/res/drawable/bg_google_qsb.xml
@@ -0,0 +1,21 @@
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+
diff --git a/lawnchair/res/drawable/ic_lens_color.xml b/lawnchair/res/drawable/ic_lens_color.xml
new file mode 100644
index 0000000000..f03228b841
--- /dev/null
+++ b/lawnchair/res/drawable/ic_lens_color.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
diff --git a/lawnchair/res/drawable/ic_mic_color.xml b/lawnchair/res/drawable/ic_mic_color.xml
new file mode 100644
index 0000000000..e3da2cf218
--- /dev/null
+++ b/lawnchair/res/drawable/ic_mic_color.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
diff --git a/lawnchair/res/drawable/ic_super_g_color.xml b/lawnchair/res/drawable/ic_super_g_color.xml
new file mode 100644
index 0000000000..90d69ec322
--- /dev/null
+++ b/lawnchair/res/drawable/ic_super_g_color.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
diff --git a/lawnchair/res/layout/empty_view.xml b/lawnchair/res/layout/empty_view.xml
new file mode 100644
index 0000000000..a38d98dd03
--- /dev/null
+++ b/lawnchair/res/layout/empty_view.xml
@@ -0,0 +1,20 @@
+
+
+
diff --git a/lawnchair/res/layout/search_container_hotseat.xml b/lawnchair/res/layout/search_container_hotseat.xml
new file mode 100644
index 0000000000..9bb1199b11
--- /dev/null
+++ b/lawnchair/res/layout/search_container_hotseat.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lawnchair/res/values/attrs.xml b/lawnchair/res/values/attrs.xml
index 933bd1f6a1..dfb2a9dda0 100644
--- a/lawnchair/res/values/attrs.xml
+++ b/lawnchair/res/values/attrs.xml
@@ -20,6 +20,11 @@
+
+
+
+
+
diff --git a/lawnchair/res/values/dimens.xml b/lawnchair/res/values/dimens.xml
index 361c4ee371..9fb461fc16 100644
--- a/lawnchair/res/values/dimens.xml
+++ b/lawnchair/res/values/dimens.xml
@@ -16,12 +16,16 @@
-->
- 70dp
+
0dp
- 72dp
+ 62dp
+ 15dp
+ 24dp
8dp
2dp
+ 0dp
+ 34dp
16dp
56dp
@@ -29,7 +33,16 @@
24dp
30dp
+ 16dp
+ 4dp
+ 8dp
+ 48dp
20dp
+ 54dp
+ 124dp
+ 6dp
+ 63dp
+
60dp
52dp
1dp
diff --git a/lawnchair/res/values/strings.xml b/lawnchair/res/values/strings.xml
index 3763349147..7612829a65 100644
--- a/lawnchair/res/values/strings.xml
+++ b/lawnchair/res/values/strings.xml
@@ -138,8 +138,10 @@
Font
Reset
- Search
Clear search box
Search
Automatically show keyboard
+ Search
+ Google Lens
+ Voice search
diff --git a/lawnchair/res/values/styles.xml b/lawnchair/res/values/styles.xml
index 60af5e8a34..83a1f0dd30 100644
--- a/lawnchair/res/values/styles.xml
+++ b/lawnchair/res/values/styles.xml
@@ -14,6 +14,11 @@
- @color/dark_drawer_text_color
- @color/system_neutral1_0
- @color/surface_light
+ - #ffffffff
+ - #ff4285f4
+ - #ffea4335
+ - #ff34a853
+ - #fffbbc05
- @color/surface_variant_light
@@ -63,6 +78,11 @@
- ?android:textColorSecondary
- @color/system_neutral1_700
- @color/surface_dark
+ - #ff3c4043
+ - #ff4285f4
+ - #ffea4335
+ - #ff34a853
+ - #fffbbc05
- @color/system_neutral1_800
+
+
diff --git a/lawnchair/src/app/lawnchair/preferences/PreferenceManager.kt b/lawnchair/src/app/lawnchair/preferences/PreferenceManager.kt
index fbbfb76011..72594c43e2 100644
--- a/lawnchair/src/app/lawnchair/preferences/PreferenceManager.kt
+++ b/lawnchair/src/app/lawnchair/preferences/PreferenceManager.kt
@@ -30,6 +30,7 @@ class PreferenceManager private constructor(private val context: Context) : Base
private val idp get() = InvariantDeviceProfile.INSTANCE.get(context)
private val reloadIcons = { idp.onPreferencesChanged(context) }
private val reloadGrid: () -> Unit = {
+ idp.onPreferencesChanged(context)
/* TODO: fix this
val defaultGrid = idp.closestProfile
val numColumns = workspaceColumns.get(defaultGrid)
@@ -57,7 +58,10 @@ class PreferenceManager private constructor(private val context: Context) : Base
val allowRotation = BoolPref("pref_allowRotation", false)
val wrapAdaptiveIcons = BoolPref("prefs_wrapAdaptive", false, reloadIcons)
val addIconToHome = BoolPref("pref_add_icon_to_home", true)
- val enableHotseatQsb = BoolPref("pref_dockSearchBar", true, reloadGrid)
+ val enableHotseatQsb = BoolPref("pref_dockSearchBar", true) {
+ reloadGrid()
+ recreate()
+ }
val hotseatColumns = IdpIntPref("pref_hotseatColumns", { numHotseatIcons }, reloadGrid)
val workspaceColumns = IdpIntPref("pref_workspaceColumns", { numColumns }, reloadGrid)
val workspaceRows = IdpIntPref("pref_workspaceRows", { numRows }, reloadGrid)
diff --git a/lawnchair/src/app/lawnchair/qsb/AssistantIconView.kt b/lawnchair/src/app/lawnchair/qsb/AssistantIconView.kt
new file mode 100644
index 0000000000..3c549b1f05
--- /dev/null
+++ b/lawnchair/src/app/lawnchair/qsb/AssistantIconView.kt
@@ -0,0 +1,27 @@
+package app.lawnchair.qsb
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.content.Intent
+import android.util.AttributeSet
+import android.widget.ImageView
+import com.android.launcher3.R
+import com.android.launcher3.qsb.QsbContainerView
+
+@SuppressLint("AppCompatCustomView")
+class AssistantIconView(context: Context, attrs: AttributeSet?) : ImageView(context, attrs) {
+
+ init {
+ scaleType = ScaleType.CENTER
+ setOnClickListener {
+ val intent = Intent(Intent.ACTION_VOICE_COMMAND)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ .setPackage(QsbContainerView.getSearchWidgetPackageName(context))
+ context.startActivity(intent)
+ }
+ }
+
+ fun setIcon() {
+ setImageResource(R.drawable.ic_mic_color)
+ }
+}
diff --git a/lawnchair/src/app/lawnchair/qsb/QsbLayout.kt b/lawnchair/src/app/lawnchair/qsb/QsbLayout.kt
new file mode 100644
index 0000000000..0492b3af7a
--- /dev/null
+++ b/lawnchair/src/app/lawnchair/qsb/QsbLayout.kt
@@ -0,0 +1,78 @@
+package app.lawnchair.qsb
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.util.AttributeSet
+import android.widget.FrameLayout
+import android.widget.ImageView
+import androidx.core.view.ViewCompat
+import androidx.core.view.children
+import androidx.core.view.isVisible
+import com.android.launcher3.BaseActivity
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.R
+import com.android.launcher3.qsb.QsbContainerView
+import com.android.launcher3.views.ActivityContext
+
+class QsbLayout(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs) {
+
+ private val activity: ActivityContext = ActivityContext.lookupContext(context)
+ private lateinit var assistantIcon: AssistantIconView
+ private lateinit var lensIcon: ImageView
+
+ override fun onFinishInflate() {
+ super.onFinishInflate()
+ assistantIcon = ViewCompat.requireViewById(this, R.id.mic_icon)
+ assistantIcon.setIcon()
+ lensIcon = ViewCompat.requireViewById(this, R.id.lens_icon)
+
+ val searchPackage = QsbContainerView.getSearchWidgetPackageName(context)
+ setOnClickListener {
+ val intent = Intent("android.search.action.GLOBAL_SEARCH")
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ .setPackage(searchPackage)
+ context.startActivity(intent)
+ }
+ if (searchPackage == GOOGLE_PACKAGE) {
+ setupLensIcon()
+ }
+ }
+
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ val requestedWidth = MeasureSpec.getSize(widthMeasureSpec)
+ val height = MeasureSpec.getSize(heightMeasureSpec)
+
+ val dp = activity.deviceProfile
+ val cellWidth = DeviceProfile.calculateCellWidth(
+ requestedWidth,
+ dp.cellLayoutBorderSpacingPx,
+ dp.numShownHotseatIcons
+ )
+ val iconSize = (dp.iconSizePx * 0.92f).toInt()
+ val width = requestedWidth - (cellWidth - iconSize)
+ setMeasuredDimension(width, height)
+
+ children.forEach { child ->
+ measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0)
+ }
+ }
+
+ private fun setupLensIcon() {
+ val lensIntent = Intent.makeMainActivity(ComponentName(LENS_PACKAGE, LENS_ACTIVITY))
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
+ if (context.packageManager.resolveActivity(lensIntent, 0) == null) return
+
+ lensIcon.isVisible = true
+ lensIcon.setImageResource(R.drawable.ic_lens_color)
+ lensIcon.setOnClickListener {
+ context.startActivity(lensIntent)
+ }
+ }
+
+ companion object {
+ private const val GOOGLE_PACKAGE = "com.google.android.googlequicksearchbox"
+ private const val LENS_PACKAGE = "com.google.ar.lens"
+ private const val LENS_ACTIVITY = "com.google.vr.apps.ornament.app.lens.LensLauncherActivity"
+ }
+}
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/FontSelectionPreference.kt b/lawnchair/src/app/lawnchair/ui/preferences/FontSelectionPreference.kt
index 60bfb40d5f..af588633d0 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/FontSelectionPreference.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/FontSelectionPreference.kt
@@ -71,7 +71,7 @@ fun FontSelection(fontPref: BasePreferenceManager.FontPref) {
onValueChange = { searchQuery = it },
modifier = Modifier
.fillMaxSize(),
- placeholder = { Text(text = stringResource(id = R.string.search_bar_placeholder)) },
+ placeholder = { Text(text = stringResource(id = R.string.label_search)) },
trailingIcon = {
if (searchQuery.isNotEmpty()) {
ClickableIcon(
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 9b9f46f5cf..0d93c707b0 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -335,12 +335,18 @@ public class DeviceProfile {
int hotseatTopPaddingRes;
int hotseatBottomPaddingRes;
+ int hotseatBottomNonTallPaddingRes;
+ int hotseatExtraVerticalSizeRes;
if (prefs.getEnableHotseatQsb().get()) {
hotseatTopPaddingRes = R.dimen.dynamic_grid_hotseat_top_padding;
hotseatBottomPaddingRes = R.dimen.dynamic_grid_hotseat_bottom_padding;
+ hotseatBottomNonTallPaddingRes = R.dimen.dynamic_grid_hotseat_bottom_non_tall_padding;
+ hotseatExtraVerticalSizeRes = R.dimen.dynamic_grid_hotseat_extra_vertical_size;
} else {
hotseatTopPaddingRes = R.dimen.noqsb_hotseat_top_padding;
hotseatBottomPaddingRes = R.dimen.noqsb_hotseat_bottom_padding;
+ hotseatBottomNonTallPaddingRes = R.dimen.noqsb_hotseat_bottom_non_tall_padding;
+ hotseatExtraVerticalSizeRes = R.dimen.noqsb_hotseat_extra_vertical_size;
}
numShownHotseatIcons =
@@ -351,14 +357,13 @@ public class DeviceProfile {
hotseatBarTopPaddingPx =
res.getDimensionPixelSize(hotseatTopPaddingRes);
hotseatBarBottomPaddingPx = (isTallDevice ? 0
- : res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_bottom_non_tall_padding))
+ : res.getDimensionPixelSize(hotseatBottomNonTallPaddingRes))
+ res.getDimensionPixelSize(hotseatBottomPaddingRes);
hotseatBarSidePaddingEndPx =
res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_side_padding);
// Add a bit of space between nav bar and hotseat in vertical bar layout.
hotseatBarSidePaddingStartPx = isVerticalBarLayout() ? workspacePageIndicatorHeight : 0;
- hotseatExtraVerticalSize =
- res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_extra_vertical_size);
+ hotseatExtraVerticalSize = res.getDimensionPixelSize(hotseatExtraVerticalSizeRes);
updateHotseatIconSize(pxFromDp(inv.iconSize, mMetrics, 1f));
qsbBottomMarginOriginalPx = isScalableGrid
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index eaca162e82..e0cc4c796e 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -31,6 +31,8 @@ import androidx.annotation.Nullable;
import java.util.function.Consumer;
+import app.lawnchair.preferences.PreferenceManager;
+
/**
* View class that represents the bottom row of the home screen.
*/
@@ -62,7 +64,9 @@ public class Hotseat extends CellLayout implements Insettable {
public Hotseat(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false);
+ boolean enableQsb = PreferenceManager.getInstance(context).getEnableHotseatQsb().get();
+ int layoutId = enableQsb ? R.layout.search_container_hotseat : R.layout.empty_view;
+ mQsb = LayoutInflater.from(context).inflate(layoutId, this, false);
mQsbHeight = mQsb.getLayoutParams().height;
addView(mQsb);