Controls UI - Marquee + dynamic column count
Make the controls more legible across different displays. 1. Support marquee in the status field to support long strings 2. Adjust margins for different dp devices 3. Dynamically adjust the max number of columns based on fontScale and screen width in dp Bug: 152765942 Test: visual, use different display/font sizes Change-Id: I72665f1164ff30e0a5746adb9fdc89f00edd35d4
This commit is contained in:
@@ -40,29 +40,20 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/status"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/TextAppearance.Control.Status"
|
||||
android:paddingTop="@dimen/control_padding_adjustment"
|
||||
android:paddingStart="@dimen/control_status_padding"
|
||||
android:clickable="false"
|
||||
android:clickable="true"
|
||||
android:focusable="false"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="marquee"
|
||||
android:marqueeRepeatLimit = "marquee_forever"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/icon"
|
||||
app:layout_constraintStart_toEndOf="@+id/icon" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/status_extra"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/TextAppearance.Control.Status"
|
||||
android:paddingTop="@dimen/control_padding_adjustment"
|
||||
android:paddingStart="@dimen/control_status_padding"
|
||||
android:clickable="false"
|
||||
android:focusable="false"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/icon"
|
||||
app:layout_constraintStart_toEndOf="@+id/status" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -67,9 +67,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginRight="@dimen/global_actions_grid_horizontal_padding"
|
||||
android:layout_marginLeft="@dimen/global_actions_grid_horizontal_padding"
|
||||
/>
|
||||
</LinearLayout>
|
||||
</com.android.systemui.globalactions.MinHeightScrollView>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
@@ -31,4 +31,7 @@
|
||||
|
||||
<!-- orientation of the dead zone when touches have recently occurred elsewhere on screen -->
|
||||
<integer name="navigation_bar_deadzone_orientation">1</integer>
|
||||
|
||||
<!-- Max number of columns for quick controls area -->
|
||||
<integer name="controls_max_columns">4</integer>
|
||||
</resources>
|
||||
|
||||
@@ -30,5 +30,7 @@
|
||||
<dimen name="global_actions_grid_item_icon_side_margin">22dp</dimen>
|
||||
<dimen name="global_actions_grid_item_icon_bottom_margin">4dp</dimen>
|
||||
|
||||
<!-- Home Controls -->
|
||||
<dimen name="controls_list_side_margin">10dp</dimen>
|
||||
</resources>
|
||||
|
||||
|
||||
@@ -26,5 +26,7 @@
|
||||
navigation_extra_key_width -->
|
||||
<dimen name="navigation_side_padding">40dip</dimen>
|
||||
|
||||
<!-- Home Controls -->
|
||||
<dimen name="controls_list_side_margin">12dp</dimen>
|
||||
</resources>
|
||||
|
||||
|
||||
@@ -30,5 +30,7 @@
|
||||
<dimen name="global_actions_grid_item_icon_side_margin">22dp</dimen>
|
||||
<dimen name="global_actions_grid_item_icon_bottom_margin">4dp</dimen>
|
||||
|
||||
<!-- Home Controls -->
|
||||
<dimen name="controls_list_side_margin">16dp</dimen>
|
||||
</resources>
|
||||
|
||||
|
||||
@@ -533,4 +533,12 @@
|
||||
This config value should contain the package name of that preferred application.
|
||||
-->
|
||||
<string translatable="false" name="config_controlsPreferredPackage"></string>
|
||||
|
||||
<!-- Max number of columns for quick controls area -->
|
||||
<integer name="controls_max_columns">2</integer>
|
||||
<!-- If the dp width of the available space is <= this value, potentially adjust the number
|
||||
of columns-->
|
||||
<integer name="controls_max_columns_adjust_below_width_dp">320</integer>
|
||||
<!-- If the config font scale is >= this value, potentially adjust the number of columns-->
|
||||
<item name="controls_max_columns_adjust_above_font_scale" translatable="false" format="float" type="dimen">1.25</item>
|
||||
</resources>
|
||||
|
||||
@@ -51,7 +51,6 @@ class ControlViewHolder(
|
||||
) {
|
||||
val icon: ImageView = layout.requireViewById(R.id.icon)
|
||||
val status: TextView = layout.requireViewById(R.id.status)
|
||||
val statusExtra: TextView = layout.requireViewById(R.id.status_extra)
|
||||
val title: TextView = layout.requireViewById(R.id.title)
|
||||
val subtitle: TextView = layout.requireViewById(R.id.subtitle)
|
||||
val context: Context = layout.getContext()
|
||||
@@ -65,6 +64,8 @@ class ControlViewHolder(
|
||||
val ld = layout.getBackground() as LayerDrawable
|
||||
ld.mutate()
|
||||
clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) as ClipDrawable
|
||||
// needed for marquee to start
|
||||
status.setSelected(true)
|
||||
}
|
||||
|
||||
fun bindData(cws: ControlWithState) {
|
||||
@@ -103,8 +104,7 @@ class ControlViewHolder(
|
||||
|
||||
behavior?.bind(cws)
|
||||
|
||||
layout.setContentDescription(
|
||||
"${title.text} ${subtitle.text} ${status.text} ${statusExtra.text}")
|
||||
layout.setContentDescription("${title.text} ${subtitle.text} ${status.text}")
|
||||
}
|
||||
|
||||
fun actionResponse(@ControlAction.ResponseResult response: Int) {
|
||||
@@ -113,15 +113,12 @@ class ControlViewHolder(
|
||||
|
||||
fun setTransientStatus(tempStatus: String) {
|
||||
val previousText = status.getText()
|
||||
val previousTextExtra = statusExtra.getText()
|
||||
|
||||
cancelUpdate = uiExecutor.executeDelayed({
|
||||
status.setText(previousText)
|
||||
statusExtra.setText(previousTextExtra)
|
||||
}, UPDATE_DELAY_IN_MILLIS)
|
||||
|
||||
status.setText(tempStatus)
|
||||
statusExtra.setText("")
|
||||
}
|
||||
|
||||
fun action(action: ControlAction) {
|
||||
@@ -154,7 +151,6 @@ class ControlViewHolder(
|
||||
}
|
||||
|
||||
status.setTextColor(fg)
|
||||
statusExtra.setTextColor(fg)
|
||||
|
||||
icon.setImageDrawable(ri.icon)
|
||||
|
||||
|
||||
@@ -21,10 +21,12 @@ import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.LayerDrawable
|
||||
import android.service.controls.Control
|
||||
import android.service.controls.actions.ControlAction
|
||||
import android.util.TypedValue
|
||||
import android.util.Log
|
||||
import android.view.ContextThemeWrapper
|
||||
import android.view.LayoutInflater
|
||||
@@ -345,10 +347,12 @@ class ControlsUiControllerImpl @Inject constructor (
|
||||
val inflater = LayoutInflater.from(context)
|
||||
inflater.inflate(R.layout.controls_with_favorites, parent, true)
|
||||
|
||||
val maxColumns = findMaxColumns()
|
||||
|
||||
val listView = parent.requireViewById(R.id.global_actions_controls_list) as ViewGroup
|
||||
var lastRow: ViewGroup = createRow(inflater, listView)
|
||||
selectedStructure.controls.forEach {
|
||||
if (lastRow.getChildCount() == 2) {
|
||||
if (lastRow.getChildCount() == maxColumns) {
|
||||
lastRow = createRow(inflater, listView)
|
||||
}
|
||||
val baseLayout = inflater.inflate(
|
||||
@@ -365,12 +369,40 @@ class ControlsUiControllerImpl @Inject constructor (
|
||||
controlViewsById.put(key, cvh)
|
||||
}
|
||||
|
||||
// add spacer if necessary to keep control size consistent
|
||||
if ((selectedStructure.controls.size % 2) == 1) {
|
||||
// add spacers if necessary to keep control size consistent
|
||||
var spacersToAdd = selectedStructure.controls.size % maxColumns
|
||||
while (spacersToAdd > 0) {
|
||||
lastRow.addView(Space(context), LinearLayout.LayoutParams(0, 0, 1f))
|
||||
spacersToAdd--
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For low-dp width screens that also employ an increased font scale, adjust the
|
||||
* number of columns. This helps prevent text truncation on these devices.
|
||||
*/
|
||||
private fun findMaxColumns(): Int {
|
||||
val res = context.resources
|
||||
var maxColumns = res.getInteger(R.integer.controls_max_columns)
|
||||
val maxColumnsAdjustWidth =
|
||||
res.getInteger(R.integer.controls_max_columns_adjust_below_width_dp)
|
||||
|
||||
val outValue = TypedValue()
|
||||
res.getValue(R.dimen.controls_max_columns_adjust_above_font_scale, outValue, true)
|
||||
val maxColumnsAdjustFontScale = outValue.getFloat()
|
||||
|
||||
val config = res.configuration
|
||||
val isPortrait = config.orientation == Configuration.ORIENTATION_PORTRAIT
|
||||
if (isPortrait &&
|
||||
config.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED &&
|
||||
config.screenWidthDp <= maxColumnsAdjustWidth &&
|
||||
config.fontScale >= maxColumnsAdjustFontScale) {
|
||||
maxColumns--
|
||||
}
|
||||
|
||||
return maxColumns
|
||||
}
|
||||
|
||||
private fun loadPreference(structures: List<StructureInfo>): StructureInfo {
|
||||
if (structures.isEmpty()) return EMPTY_STRUCTURE
|
||||
|
||||
|
||||
@@ -47,9 +47,10 @@ class ToggleRangeBehavior : Behavior {
|
||||
lateinit var control: Control
|
||||
lateinit var cvh: ControlViewHolder
|
||||
lateinit var rangeTemplate: RangeTemplate
|
||||
lateinit var statusExtra: TextView
|
||||
lateinit var status: TextView
|
||||
lateinit var context: Context
|
||||
var currentStatusText: CharSequence = ""
|
||||
var currentRangeValue: String = ""
|
||||
|
||||
companion object {
|
||||
private const val DEFAULT_FORMAT = "%.1f"
|
||||
@@ -83,8 +84,8 @@ class ToggleRangeBehavior : Behavior {
|
||||
override fun bind(cws: ControlWithState) {
|
||||
this.control = cws.control!!
|
||||
|
||||
statusExtra = cvh.statusExtra
|
||||
status.setText(control.getStatusText())
|
||||
currentStatusText = control.getStatusText()
|
||||
status.setText(currentStatusText)
|
||||
|
||||
val ld = cvh.layout.getBackground() as LayerDrawable
|
||||
clipLayer = ld.findDrawableByLayerId(R.id.clip_layer)
|
||||
@@ -96,7 +97,7 @@ class ToggleRangeBehavior : Behavior {
|
||||
val checked = template.isChecked()
|
||||
val currentRatio = rangeTemplate.getCurrentValue() /
|
||||
(rangeTemplate.getMaxValue() - rangeTemplate.getMinValue())
|
||||
updateRange(currentRatio, checked)
|
||||
updateRange(currentRatio, checked, /* isDragging */ false)
|
||||
|
||||
cvh.applyRenderInfo(checked)
|
||||
|
||||
@@ -147,7 +148,7 @@ class ToggleRangeBehavior : Behavior {
|
||||
AccessibilityNodeInfo.ACTION_ARGUMENT_PROGRESS_VALUE)
|
||||
val ratioDiff = (value - rangeTemplate.getCurrentValue()) /
|
||||
(rangeTemplate.getMaxValue() - rangeTemplate.getMinValue())
|
||||
updateRange(ratioDiff, template.isChecked())
|
||||
updateRange(ratioDiff, template.isChecked(), /* isDragging */ false)
|
||||
endUpdateRange()
|
||||
true
|
||||
}
|
||||
@@ -167,26 +168,27 @@ class ToggleRangeBehavior : Behavior {
|
||||
}
|
||||
|
||||
fun beginUpdateRange() {
|
||||
status.setVisibility(View.GONE)
|
||||
statusExtra.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources()
|
||||
status.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources()
|
||||
.getDimensionPixelSize(R.dimen.control_status_expanded).toFloat())
|
||||
}
|
||||
|
||||
fun updateRange(ratioDiff: Float, checked: Boolean) {
|
||||
fun updateRange(ratioDiff: Float, checked: Boolean, isDragging: Boolean) {
|
||||
val changeAmount = if (checked) (MAX_LEVEL * ratioDiff).toInt() else MIN_LEVEL
|
||||
val newLevel = Math.max(MIN_LEVEL, Math.min(MAX_LEVEL, clipLayer.getLevel() + changeAmount))
|
||||
clipLayer.setLevel(newLevel)
|
||||
|
||||
if (checked) {
|
||||
val newValue = levelToRangeValue(clipLayer.getLevel())
|
||||
val formattedNewValue = format(rangeTemplate.getFormatString().toString(),
|
||||
currentRangeValue = format(rangeTemplate.getFormatString().toString(),
|
||||
DEFAULT_FORMAT, newValue)
|
||||
|
||||
statusExtra.setText(formattedNewValue)
|
||||
statusExtra.setVisibility(View.VISIBLE)
|
||||
val text = if (isDragging) {
|
||||
currentRangeValue
|
||||
} else {
|
||||
"$currentStatusText $currentRangeValue"
|
||||
}
|
||||
status.setText(text)
|
||||
} else {
|
||||
statusExtra.setText("")
|
||||
statusExtra.setVisibility(View.GONE)
|
||||
status.setText(currentStatusText)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,9 +212,9 @@ class ToggleRangeBehavior : Behavior {
|
||||
}
|
||||
|
||||
fun endUpdateRange() {
|
||||
statusExtra.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources()
|
||||
status.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources()
|
||||
.getDimensionPixelSize(R.dimen.control_status_normal).toFloat())
|
||||
status.setVisibility(View.VISIBLE)
|
||||
status.setText("$currentStatusText $currentRangeValue")
|
||||
cvh.action(FloatAction(rangeTemplate.getTemplateId(),
|
||||
findNearestStep(levelToRangeValue(clipLayer.getLevel()))))
|
||||
}
|
||||
@@ -260,7 +262,8 @@ class ToggleRangeBehavior : Behavior {
|
||||
isDragging = true
|
||||
}
|
||||
|
||||
this@ToggleRangeBehavior.updateRange(-xDiff / v.getWidth(), true)
|
||||
this@ToggleRangeBehavior.updateRange(-xDiff / v.getWidth(),
|
||||
/* checked */ true, /* isDragging */ true)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user