summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt1
-rw-r--r--core/java/android/service/quicksettings/TileService.java22
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt128
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java6
9 files changed, 205 insertions, 4 deletions
diff --git a/api/current.txt b/api/current.txt
index 40106b3a5724..4174b6a53cc9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -41917,6 +41917,7 @@ package android.service.quicksettings {
field public static final String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
field public static final String ACTION_QS_TILE_PREFERENCES = "android.service.quicksettings.action.QS_TILE_PREFERENCES";
field public static final String META_DATA_ACTIVE_TILE = "android.service.quicksettings.ACTIVE_TILE";
+ field public static final String META_DATA_BOOLEAN_TILE = "android.service.quicksettings.BOOLEAN_TILE";
}
}
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index f1c870d96065..dd2586cd58ad 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -126,11 +126,29 @@ public class TileService extends Service {
= "android.service.quicksettings.ACTIVE_TILE";
/**
+ * Meta-data for a tile to support {@code BooleanState}.
+ * <p>
+ * BooleanState is for tiles that should support switch tile behavior in accessibility. This is
+ * the behavior of most of the framework tiles.
+ *
+ * To make a TileService support BooleanState, set this meta-data to true on the TileService's
+ * manifest declaration.
+ * <pre class="prettyprint">
+ * {@literal
+ * <meta-data android:name="android.service.quicksettings.BOOLEAN_TILE"
+ * android:value="true" />
+ * }
+ * </pre>
+ */
+ public static final String META_DATA_BOOLEAN_TILE =
+ "android.service.quicksettings.BOOLEAN_TILE";
+
+ /**
* Used to notify SysUI that Listening has be requested.
* @hide
*/
- public static final String ACTION_REQUEST_LISTENING
- = "android.service.quicksettings.action.REQUEST_LISTENING";
+ public static final String ACTION_REQUEST_LISTENING =
+ "android.service.quicksettings.action.REQUEST_LISTENING";
/**
* @hide
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
index db026cad6ef5..6518924ca0c2 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
@@ -186,6 +186,8 @@ public interface QSTile {
return toStringBuilder().toString();
}
+ // Used in dumps to determine current state of a tile.
+ // 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(",icon=").append(icon);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 466c8082f0b9..411980b399bd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -39,6 +39,7 @@ import android.text.format.DateUtils;
import android.util.Log;
import android.view.IWindowManager;
import android.view.WindowManagerGlobal;
+import android.widget.Switch;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Dependency;
@@ -82,6 +83,11 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
mTile = new Tile();
updateDefaultTileAndIcon();
mServiceManager = host.getTileServices().getTileWrapper(this);
+ if (mServiceManager.isBooleanTile()) {
+ // Replace states with BooleanState
+ resetStates();
+ }
+
mService = mServiceManager.getTileService();
mServiceManager.setTileChangeListener(this);
mUser = ActivityManager.getCurrentUser();
@@ -246,8 +252,10 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
@Override
public State newTileState() {
- State state = new State();
- return state;
+ if (mServiceManager != null && mServiceManager.isBooleanTile()) {
+ return new BooleanState();
+ }
+ return new State();
}
@Override
@@ -336,6 +344,12 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
} else {
state.contentDescription = state.label;
}
+
+ if (state instanceof BooleanState) {
+ state.expandedAccessibilityClassName = Switch.class.getName();
+ ((BooleanState) state).value = (state.state == Tile.STATE_ACTIVE);
+ }
+
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
index effea6a877b8..f59e0c2d9bc2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -131,6 +131,24 @@ public class TileLifecycleManager extends BroadcastReceiver implements
}
/**
+ * Determines whether the associated TileService is a Boolean Tile.
+ *
+ * @return true if {@link TileService#META_DATA_BOOLEAN_TILE} is set to {@code true} for this
+ * tile
+ * @see TileService#META_DATA_BOOLEAN_TILE
+ */
+ public boolean isBooleanTile() {
+ try {
+ ServiceInfo info = mPackageManagerAdapter.getServiceInfo(mIntent.getComponent(),
+ PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_META_DATA);
+ return info.metaData != null
+ && info.metaData.getBoolean(TileService.META_DATA_BOOLEAN_TILE, false);
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ /**
* Binds just long enough to send any queued messages, then unbinds.
*/
public void flushMessagesAndUnbind() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
index 2a7e55fe6f8f..0b4e6485551c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
@@ -123,6 +123,10 @@ public class TileServiceManager {
return mStateManager.isActiveTile();
}
+ public boolean isBooleanTile() {
+ return mStateManager.isBooleanTile();
+ }
+
public void setShowingDialog(boolean dialog) {
mShowingDialog = dialog;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 681de378ff57..e0f26cd1a267 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -139,6 +139,11 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy
mQSSettingsPanelOption = QSSettingsControllerKt.getQSSettingsPanelOption();
}
+ protected final void resetStates() {
+ mState = newTileState();
+ mTmpState = newTileState();
+ }
+
@NonNull
@Override
public Lifecycle getLifecycle() {
@@ -629,6 +634,11 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy
}
}
+ /**
+ * Dumps the state of this tile along with its name.
+ *
+ * This may be used for CTS testing of tiles.
+ */
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println(this.getClass().getSimpleName() + ":");
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
new file mode 100644
index 000000000000..4becd522ebd6
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2019 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.external
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
+import android.content.pm.ServiceInfo
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.Icon
+import android.service.quicksettings.IQSTileService
+import android.service.quicksettings.Tile
+import android.test.suitebuilder.annotation.SmallTest
+import android.view.IWindowManager
+import androidx.test.runner.AndroidJUnit4
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.qs.QSTileHost
+import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.anyString
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.any
+import org.mockito.Mockito.mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CustomTileTest : SysuiTestCase() {
+
+ companion object {
+ const val packageName = "test_package"
+ const val className = "test_class"
+ val componentName = ComponentName(packageName, className)
+ val TILE_SPEC = CustomTile.toSpec(componentName)
+ }
+
+ @Mock private lateinit var mTileHost: QSTileHost
+ @Mock private lateinit var mTileService: IQSTileService
+ @Mock private lateinit var mTileServices: TileServices
+ @Mock private lateinit var mTileServiceManager: TileServiceManager
+ @Mock private lateinit var mWindowService: IWindowManager
+ @Mock private lateinit var mPackageManager: PackageManager
+ @Mock private lateinit var mApplicationInfo: ApplicationInfo
+ @Mock private lateinit var mServiceInfo: ServiceInfo
+
+ private lateinit var customTile: CustomTile
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ mContext.addMockSystemService("window", mWindowService)
+ mContext.setMockPackageManager(mPackageManager)
+ `when`(mTileHost.tileServices).thenReturn(mTileServices)
+ `when`(mTileHost.context).thenReturn(mContext)
+ `when`(mTileServices.getTileWrapper(any(CustomTile::class.java)))
+ .thenReturn(mTileServiceManager)
+ `when`(mTileServiceManager.tileService).thenReturn(mTileService)
+ `when`(mPackageManager.getApplicationInfo(anyString(), anyInt()))
+ .thenReturn(mApplicationInfo)
+
+ `when`(mPackageManager.getServiceInfo(any(ComponentName::class.java), anyInt()))
+ .thenReturn(mServiceInfo)
+ mServiceInfo.applicationInfo = mApplicationInfo
+
+ customTile = CustomTile.create(mTileHost, TILE_SPEC)
+ }
+
+ @Test
+ fun testBooleanTileHasBooleanState() {
+ `when`(mTileServiceManager.isBooleanTile).thenReturn(true)
+ customTile = CustomTile.create(mTileHost, TILE_SPEC)
+
+ assertTrue(customTile.state is QSTile.BooleanState)
+ assertTrue(customTile.newTileState() is QSTile.BooleanState)
+ }
+
+ @Test
+ fun testRegularTileHasNotBooleanState() {
+ assertFalse(customTile.state is QSTile.BooleanState)
+ assertFalse(customTile.newTileState() is QSTile.BooleanState)
+ }
+
+ @Test
+ fun testValueUpdatedInBooleanTile() {
+ `when`(mTileServiceManager.isBooleanTile).thenReturn(true)
+ customTile = CustomTile.create(mTileHost, TILE_SPEC)
+ customTile.qsTile.icon = mock(Icon::class.java)
+ `when`(customTile.qsTile.icon.loadDrawable(any(Context::class.java)))
+ .thenReturn(mock(Drawable::class.java))
+
+ val state = customTile.newTileState()
+ assertTrue(state is QSTile.BooleanState)
+
+ customTile.qsTile.state = Tile.STATE_INACTIVE
+ customTile.handleUpdateState(state, null)
+ assertFalse((state as QSTile.BooleanState).value)
+
+ customTile.qsTile.state = Tile.STATE_ACTIVE
+ customTile.handleUpdateState(state, null)
+ assertTrue(state.value)
+
+ customTile.qsTile.state = Tile.STATE_UNAVAILABLE
+ customTile.handleUpdateState(state, null)
+ assertFalse(state.value)
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
index f35295cf6f99..11b0c69e8a41 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
@@ -101,6 +101,7 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
defaultServiceInfo = new ServiceInfo();
defaultServiceInfo.metaData = new Bundle();
defaultServiceInfo.metaData.putBoolean(TileService.META_DATA_ACTIVE_TILE, true);
+ defaultServiceInfo.metaData.putBoolean(TileService.META_DATA_BOOLEAN_TILE, true);
}
when(mMockPackageManagerAdapter.getServiceInfo(any(), anyInt(), anyInt()))
.thenReturn(defaultServiceInfo);
@@ -237,4 +238,9 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
verifyBind(2);
verify(mMockTileService, times(2)).onStartListening();
}
+
+ @Test
+ public void testBooleanTile() throws Exception {
+ assertTrue(mStateManager.isBooleanTile());
+ }
}