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);