Merge "Create state strings for every stock tile" into sc-dev

This commit is contained in:
TreeHugger Robot
2021-06-01 20:25:47 +00:00
committed by Android (Google) Code Review
9 changed files with 404 additions and 17 deletions

View File

@@ -305,6 +305,7 @@ This section describes necessary and recommended steps when implementing a Quick
* Inject a `Provider` for the tile created before.
* Add a case to the `switch` with a unique String spec for the chosen tile.
5. In [SystemUI/res/values/config.xml](/packages/SystemUI/res/values/config.xml), modify `quick_settings_tiles_stock` and add the spec defined in the previous step. If necessary, add it also to `quick_settings_tiles_default`. The first one contains a list of all the tiles that SystemUI knows how to create (to show to the user in the customization screen). The second one contains only the default tiles that the user will experience on a fresh boot or after they reset their tiles.
6. In [SystemUI/res/values/tiles_states_strings.xml](/packages/SystemUI/res/values/tiles_states_strings.xml), add a new array for your tile. The name has to be `tile_states_<spec>`. Use a good description to help the translators.
#### Abstract methods in QSTileImpl

View File

@@ -166,11 +166,13 @@ public interface QSTile {
public boolean handlesLongClick = true;
public boolean showRippleEffect = true;
public Drawable sideViewCustomDrawable;
public String spec;
public boolean copyTo(State other) {
if (other == null) throw new IllegalArgumentException();
if (!other.getClass().equals(getClass())) throw new IllegalArgumentException();
final boolean changed = !Objects.equals(other.icon, icon)
final boolean changed = !Objects.equals(other.spec, spec)
|| !Objects.equals(other.icon, icon)
|| !Objects.equals(other.iconSupplier, iconSupplier)
|| !Objects.equals(other.label, label)
|| !Objects.equals(other.secondaryLabel, secondaryLabel)
@@ -188,6 +190,7 @@ public interface QSTile {
|| !Objects.equals(other.handlesLongClick, handlesLongClick)
|| !Objects.equals(other.showRippleEffect, showRippleEffect)
|| !Objects.equals(other.sideViewCustomDrawable, sideViewCustomDrawable);
other.spec = spec;
other.icon = icon;
other.iconSupplier = iconSupplier;
other.label = label;
@@ -216,6 +219,7 @@ public interface QSTile {
// This string may be used for CTS testing of tiles, so removing elements is discouraged.
protected StringBuilder toStringBuilder() {
final StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('[');
sb.append("spec=").append(spec);
sb.append(",icon=").append(icon);
sb.append(",iconSupplier=").append(iconSupplier);
sb.append(",label=").append(label);

View File

@@ -0,0 +1,284 @@
<!--
~ 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.
-->
<!-- This resources set the default subtitle for tiles. This way, each tile can be translated
separately.
The indices in the array correspond to the state values in QSTile:
* STATE_UNAVAILABLE
* STATE_INACTIVE
* STATE_ACTIVE
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as if
they could appear.
-->
<resources>
<!-- Default names for tiles states: unavailable, off, on.
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as
if they could appear. [CHAR LIMIT=32] -->
<string-array name="tile_states_default">
<item>@string/tile_unavailable</item>
<item>@string/switch_bar_off</item>
<item>@string/switch_bar_on</item>
</string-array>
<!-- State names for internet tile: unavailable, off, on.
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as
if they could appear. [CHAR LIMIT=32] -->
<string-array name="tile_states_internet">
<item>@string/tile_unavailable</item>
<item>@string/switch_bar_off</item>
<item>@string/switch_bar_on</item>
</string-array>
<!-- State names for wifi tile: unavailable, off, on.
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as
if they could appear. [CHAR LIMIT=32] -->
<string-array name="tile_states_wifi">
<item>@string/tile_unavailable</item>
<item>@string/switch_bar_off</item>
<item>@string/switch_bar_on</item>
</string-array>
<!-- State names for cell (data) tile: unavailable, off, on.
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as
if they could appear.[CHAR LIMIT=32] -->
<string-array name="tile_states_cell">
<item>@string/tile_unavailable</item>
<item>@string/switch_bar_off</item>
<item>@string/switch_bar_on</item>
</string-array>
<!-- State names for battery (saver) tile: unavailable, off, on.
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as
if they could appear. [CHAR LIMIT=32] -->
<string-array name="tile_states_battery">
<item>@string/tile_unavailable</item>
<item>@string/switch_bar_off</item>
<item>@string/switch_bar_on</item>
</string-array>
<!-- State names for dnd (Do not disturb) tile: unavailable, off, on.
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as
if they could appear. [CHAR LIMIT=32] -->
<string-array name="tile_states_dnd">
<item>@string/tile_unavailable</item>
<item>@string/switch_bar_off</item>
<item>@string/switch_bar_on</item>
</string-array>
<!-- State names for flashlight tile: unavailable, off, on.
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as
if they could appear. [CHAR LIMIT=32] -->
<string-array name="tile_states_flashlight">
<item>@string/tile_unavailable</item>
<item>@string/switch_bar_off</item>
<item>@string/switch_bar_on</item>
</string-array>
<!-- State names for rotation (lock) tile: unavailable, off, on.
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as
if they could appear. [CHAR LIMIT=32] -->
<string-array name="tile_states_rotation">
<item>@string/tile_unavailable</item>
<item>@string/switch_bar_off</item>
<item>@string/switch_bar_on</item>
</string-array>
<!-- State names for bt (bluetooth) tile: unavailable, off, on.
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as
if they could appear. [CHAR LIMIT=32] -->
<string-array name="tile_states_bt">
<item>@string/tile_unavailable</item>
<item>@string/switch_bar_off</item>
<item>@string/switch_bar_on</item>
</string-array>
<!-- State names for airplane tile: unavailable, off, on [CHAR LIMIT=32] -->
<string-array name="tile_states_airplane">
<item>@string/tile_unavailable</item>
<item>@string/switch_bar_off</item>
<item>@string/switch_bar_on</item>
</string-array>
<!-- State names for location tile: unavailable, off, on.
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as
if they could appear. [CHAR LIMIT=32] -->
<string-array name="tile_states_location">
<item>@string/tile_unavailable</item>
<item>@string/switch_bar_off</item>
<item>@string/switch_bar_on</item>
</string-array>
<!-- State names for hotspot tile: unavailable, off, on.
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as
if they could appear. [CHAR LIMIT=32] -->
<string-array name="tile_states_hotspot">
<item>@string/tile_unavailable</item>
<item>@string/switch_bar_off</item>
<item>@string/switch_bar_on</item>
</string-array>
<!-- State names for (color) inversion tile: unavailable, off, on.
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as
if they could appear. [CHAR LIMIT=32] -->
<string-array name="tile_states_inversion">
<item>@string/tile_unavailable</item>
<item>@string/switch_bar_off</item>
<item>@string/switch_bar_on</item>
</string-array>
<!-- State names for (data) saver tile: unavailable, off, on.
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as
if they could appear. [CHAR LIMIT=32] -->
<string-array name="tile_states_saver">
<item>@string/tile_unavailable</item>
<item>@string/switch_bar_off</item>
<item>@string/switch_bar_on</item>
</string-array>
<!-- State names for dark (mode) tile: unavailable, off, on.
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as
if they could appear. [CHAR LIMIT=32] -->
<string-array name="tile_states_dark">
<item>@string/tile_unavailable</item>
<item>@string/switch_bar_off</item>
<item>@string/switch_bar_on</item>
</string-array>
<!-- State names for work (mode) tile: unavailable, off, on.
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as
if they could appear. [CHAR LIMIT=32] -->
<string-array name="tile_states_work">
<item>@string/tile_unavailable</item>
<item>@string/switch_bar_off</item>
<item>@string/switch_bar_on</item>
</string-array>
<!-- State names for cast tile: unavailable, off, on.
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as
if they could appear. [CHAR LIMIT=32] -->
<string-array name="tile_states_cast">
<item>@string/tile_unavailable</item>
<item>@string/switch_bar_off</item>
<item>@string/switch_bar_on</item>
</string-array>
<!-- State names for night (light) tile: unavailable, off, on.
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as
if they could appear. [CHAR LIMIT=32] -->
<string-array name="tile_states_night">
<item>@string/tile_unavailable</item>
<item>@string/switch_bar_off</item>
<item>@string/switch_bar_on</item>
</string-array>
<!-- State names for screenrecord tile: unavailable, off, on.
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as
if they could appear. [CHAR LIMIT=32] -->
<string-array name="tile_states_screenrecord">
<item>@string/tile_unavailable</item>
<item>@string/switch_bar_off</item>
<item>@string/switch_bar_on</item>
</string-array>
<!-- State names for reverse (charging) tile: unavailable, off, on.
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as
if they could appear. [CHAR LIMIT=32] -->
<string-array name="tile_states_reverse">
<item>@string/tile_unavailable</item>
<item>@string/switch_bar_off</item>
<item>@string/switch_bar_on</item>
</string-array>
<!-- State names for reduce_brightness tile: unavailable, off, on.
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as
if they could appear. [CHAR LIMIT=32] -->
<string-array name="tile_states_reduce_brightness">
<item>@string/tile_unavailable</item>
<item>@string/switch_bar_off</item>
<item>@string/switch_bar_on</item>
</string-array>
<!-- State names for cameratoggle tile: unavailable, off, on.
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as
if they could appear.[CHAR LIMIT=32] -->
<string-array name="tile_states_cameratoggle">
<item>@string/tile_unavailable</item>
<item>@string/switch_bar_off</item>
<item>@string/switch_bar_on</item>
</string-array>
<!-- State names for mictoggle tile: unavailable, off, on.
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as
if they could appear. [CHAR LIMIT=32] -->
<string-array name="tile_states_mictoggle">
<item>@string/tile_unavailable</item>
<item>@string/switch_bar_off</item>
<item>@string/switch_bar_on</item>
</string-array>
<!-- State names for (home) controls tile: unavailable, off, on.
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as
if they could appear. [CHAR LIMIT=32] -->
<string-array name="tile_states_controls">
<item>@string/tile_unavailable</item>
<item>@string/switch_bar_off</item>
<item>@string/switch_bar_on</item>
</string-array>
<!-- State names for (quick access) wallet tile: unavailable, off, on.
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as
if they could appear. [CHAR LIMIT=32] -->
<string-array name="tile_states_wallet">
<item>@string/tile_unavailable</item>
<item>@string/switch_bar_off</item>
<item>@string/switch_bar_on</item>
</string-array>
<!-- State names for alarm tile: unavailable, off, on.
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as
if they could appear. [CHAR LIMIT=32] -->
<string-array name="tile_states_alarm">
<item>@string/tile_unavailable</item>
<item>@string/switch_bar_off</item>
<item>@string/switch_bar_on</item>
</string-array>
</resources>

View File

@@ -181,14 +181,15 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy
mStatusBarStateController = statusBarStateController;
mActivityStarter = activityStarter;
mState = newTileState();
mTmpState = newTileState();
resetStates();
mUiHandler.post(() -> mLifecycle.setCurrentState(CREATED));
}
protected final void resetStates() {
mState = newTileState();
mTmpState = newTileState();
mState.spec = mTileSpec;
mTmpState.spec = mTileSpec;
}
@NonNull
@@ -225,6 +226,8 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy
public void setTileSpec(String tileSpec) {
mTileSpec = tileSpec;
mState.spec = tileSpec;
mTmpState.spec = tileSpec;
}
public QSHost getHost() {

View File

@@ -38,6 +38,7 @@ import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.Switch
import android.widget.TextView
import androidx.annotation.VisibleForTesting
import com.android.settingslib.Utils
import com.android.systemui.FontSizeUtils
import com.android.systemui.R
@@ -62,6 +63,8 @@ open class QSTileViewImpl @JvmOverloads constructor(
private const val SECONDARY_LABEL_NAME = "secondaryLabel"
private const val CHEVRON_NAME = "chevron"
const val UNAVAILABLE_ALPHA = 0.3f
@VisibleForTesting
internal const val TILE_STATE_RES_PREFIX = "tile_states_"
}
override var heightOverride: Int = HeightOverrideable.NO_OVERRIDE
@@ -484,16 +487,18 @@ open class QSTileViewImpl @JvmOverloads constructor(
}
private fun getStateText(state: QSTile.State): String {
return if (state.disabledByPolicy) {
context.getString(R.string.tile_disabled)
} else if (state.state == Tile.STATE_UNAVAILABLE) {
context.getString(R.string.tile_unavailable)
} else if (state is BooleanState) {
if (state.state == Tile.STATE_INACTIVE) {
context.getString(R.string.switch_bar_off)
} else {
context.getString(R.string.switch_bar_on)
if (state.disabledByPolicy) {
return context.getString(R.string.tile_disabled)
}
return if (state.state == Tile.STATE_UNAVAILABLE || state is BooleanState) {
val resName = "$TILE_STATE_RES_PREFIX${state.spec}"
var arrayResId = resources.getIdentifier(resName, "array", context.packageName)
if (arrayResId == 0) {
arrayResId = R.array.tile_states_default
}
val array = resources.getStringArray(arrayResId)
array[state.state]
} else {
""
}

View File

@@ -45,7 +45,6 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QSIconView;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTile.SignalState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.AlphaControlledSignalTileView;
@@ -72,7 +71,6 @@ public class InternetTile extends QSTileImpl<SignalState> {
protected final NetworkController mController;
private final DataUsageController mDataController;
private final QSTile.SignalState mStateBeforeClick = newTileState();
// The last updated tile state, 0: mobile, 1: wifi, 2: ethernet.
private int mLastTileState = -1;

View File

@@ -94,6 +94,7 @@ public class WifiTile extends QSTileImpl<SignalState> {
mWifiController = accessPointController;
mDetailAdapter = (WifiDetailAdapter) createDetailAdapter();
mController.observe(getLifecycle(), mSignalCallback);
mStateBeforeClick.spec = "wifi";
}
@Override

View File

@@ -23,6 +23,7 @@ import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.text.TextUtils
import android.view.View
import android.widget.TextView
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
@@ -52,6 +53,7 @@ class QSTileViewImplTest : SysuiTestCase() {
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
context.ensureTestableResources()
tileView = FakeTileView(context, iconView, false)
customDrawableView = tileView.requireViewById(R.id.customDrawable)
@@ -117,7 +119,7 @@ class QSTileViewImplTest : SysuiTestCase() {
}
@Test
fun testSecondaryLabelDescription_unavailable() {
fun testSecondaryLabelDescription_unavailable_default() {
val state = QSTile.State()
state.state = Tile.STATE_UNAVAILABLE
state.secondaryLabel = ""
@@ -130,7 +132,7 @@ class QSTileViewImplTest : SysuiTestCase() {
}
@Test
fun testSecondaryLabelDescription_booleanInactive() {
fun testSecondaryLabelDescription_booleanInactive_default() {
val state = QSTile.BooleanState()
state.state = Tile.STATE_INACTIVE
state.secondaryLabel = ""
@@ -143,7 +145,7 @@ class QSTileViewImplTest : SysuiTestCase() {
}
@Test
fun testSecondaryLabelDescription_booleanActive() {
fun testSecondaryLabelDescription_booleanActive_default() {
val state = QSTile.BooleanState()
state.state = Tile.STATE_ACTIVE
state.secondaryLabel = ""
@@ -220,6 +222,41 @@ class QSTileViewImplTest : SysuiTestCase() {
assertThat(chevronView.visibility).isEqualTo(View.GONE)
}
@Test
fun testUseStateStringsForKnownSpec_Boolean() {
val state = QSTile.BooleanState()
val spec = "internet"
state.spec = spec
val unavailableString = "${spec}_unavailable"
val offString = "${spec}_off"
val onString = "${spec}_on"
context.orCreateTestableResources.addOverride(R.array.tile_states_internet, arrayOf(
unavailableString,
offString,
onString
))
// State UNAVAILABLE
state.secondaryLabel = ""
state.state = Tile.STATE_UNAVAILABLE
tileView.changeState(state)
assertThat((tileView.secondaryLabel as TextView).text).isEqualTo(unavailableString)
// State INACTIVE
state.secondaryLabel = ""
state.state = Tile.STATE_INACTIVE
tileView.changeState(state)
assertThat((tileView.secondaryLabel as TextView).text).isEqualTo(offString)
// State ACTIVE
state.secondaryLabel = ""
state.state = Tile.STATE_ACTIVE
tileView.changeState(state)
assertThat((tileView.secondaryLabel as TextView).text).isEqualTo(onString)
}
class FakeTileView(
context: Context,
icon: QSIconView,

View File

@@ -0,0 +1,54 @@
/*
* 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.systemui.qs.tileimpl
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotEquals
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidTestingRunner::class)
@SmallTest
class TilesStatesTextTest : SysuiTestCase() {
@Test
fun testStockTilesHaveStatesArray() {
val tiles = mContext.getString(R.string.quick_settings_tiles_stock).split(",")
tiles.forEach { spec ->
val resName = "${QSTileViewImpl.TILE_STATE_RES_PREFIX}$spec"
val resId = mContext.resources.getIdentifier(resName, "array", mContext.packageName)
assertNotEquals("Missing resource for $resName", 0, resId)
val array = mContext.resources.getStringArray(resId)
assertEquals("Array for $spec is of wrong size", 3, array.size)
}
}
@Test
fun testDefaultArray() {
val array = mContext.resources.getStringArray(R.array.tile_states_default)
assertThat(array.size).isEqualTo(3)
}
}