Loading AndroidManifest.xml +2 −0 Original line number Diff line number Diff line Loading @@ -4067,6 +4067,8 @@ </intent-filter> <meta-data android:name="android.service.quicksettings.TOGGLEABLE_TILE" android:value="true"/> <meta-data android:name="com.android.settings.development.qstile.REQUIRES_SYSTEM_PROPERTY" android:value="persist.wm.debug.desktop_mode" /> </service> <activity Loading src/com/android/settings/development/qstile/DevelopmentTilePreferenceController.java +16 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; import android.service.quicksettings.TileService; import android.util.Log; Loading Loading @@ -61,9 +62,23 @@ public class DevelopmentTilePreferenceController extends BasePreferenceControlle final Intent intent = new Intent(TileService.ACTION_QS_TILE) .setPackage(context.getPackageName()); final List<ResolveInfo> resolveInfos = mPackageManager.queryIntentServices(intent, PackageManager.MATCH_DISABLED_COMPONENTS); PackageManager.MATCH_DISABLED_COMPONENTS | PackageManager.GET_META_DATA); for (ResolveInfo info : resolveInfos) { ServiceInfo sInfo = info.serviceInfo; // Check if the tile requires a flag. If it does, hide tile if flag is off. if (sInfo.metaData != null) { String flag = sInfo.metaData.getString( DevelopmentTiles.META_DATA_REQUIRES_SYSTEM_PROPERTY); if (flag != null) { boolean enabled = SystemProperties.getBoolean(flag, false); if (!enabled) { // Flagged tile, flag is not enabled continue; } } } final int enabledSetting = mPackageManager.getComponentEnabledSetting( new ComponentName(sInfo.packageName, sInfo.name)); boolean checked = enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_ENABLED Loading src/com/android/settings/development/qstile/DevelopmentTiles.java +16 −0 Original line number Diff line number Diff line Loading @@ -58,6 +58,22 @@ import com.android.settingslib.development.DevelopmentSettingsEnabler; import com.android.settingslib.development.SystemPropPoker; public abstract class DevelopmentTiles extends TileService { /** * Meta-data for a development tile to declare a sysprop flag that needs to be enabled for * the tile to be available. * * To define the flag, set this meta-data on the tile's manifest declaration. * <pre class="prettyprint"> * {@literal * <meta-data android:name="com.android.settings.development.qstile.REQUIRES_SYSTEM_PROPERTY" * android:value="persist.debug.flag_name_here" /> * } * </pre> */ public static final String META_DATA_REQUIRES_SYSTEM_PROPERTY = "com.android.settings.development.qstile.REQUIRES_SYSTEM_PROPERTY"; private static final String TAG = "DevelopmentTiles"; protected abstract boolean isEnabled(); Loading tests/robotests/src/com/android/settings/development/qstile/DevelopmentTilePreferenceControllerTest.java +50 −5 Original line number Diff line number Diff line Loading @@ -19,7 +19,9 @@ package com.android.settings.development.qstile; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; Loading @@ -30,6 +32,7 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.os.Bundle; import android.os.RemoteException; import android.service.quicksettings.TileService; Loading @@ -50,6 +53,7 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.Shadows; import org.robolectric.shadows.ShadowPackageManager; import org.robolectric.shadows.ShadowSystemProperties; import org.robolectric.util.ReflectionHelpers; import java.util.Arrays; Loading Loading @@ -88,11 +92,7 @@ public class DevelopmentTilePreferenceControllerTest { public void display_hasTileService_shouldDisplay() { final Intent tileProbe = new Intent(TileService.ACTION_QS_TILE) .setPackage(mContext.getPackageName()); final ResolveInfo info = new ResolveInfo(); info.serviceInfo = new FakeServiceInfo(); info.serviceInfo.name = "abc"; info.serviceInfo.icon = R.drawable.ic_settings_24dp; info.serviceInfo.packageName = mContext.getPackageName(); final ResolveInfo info = createFakeInfo("abc"); mShadowPackageManager.setResolveInfosForIntent(tileProbe, Arrays.asList(info)); mController.displayPreference(mScreen); Loading @@ -100,6 +100,36 @@ public class DevelopmentTilePreferenceControllerTest { verify(mScreen, atLeastOnce()).addPreference(any(Preference.class)); } @Test public void display_flagDefinedAndOn_shouldDisplay() { ShadowSystemProperties.override("tile_flag", "1"); final Intent tileProbe = new Intent(TileService.ACTION_QS_TILE) .setPackage(mContext.getPackageName()); final ResolveInfo info = createFakeInfo("abc"); info.serviceInfo.metaData = createFlagMetadata("tile_flag"); mShadowPackageManager.setResolveInfosForIntent(tileProbe, Arrays.asList(info)); mController.displayPreference(mScreen); verify(mScreen, atLeastOnce()).addPreference(argThat(pref -> pref.getKey().equals("abc"))); } @Test public void display_flagDefinedAndOff_shouldHide() { ShadowSystemProperties.override("tile_flag" , "0"); final Intent tileProbe = new Intent(TileService.ACTION_QS_TILE) .setPackage(mContext.getPackageName()); final ResolveInfo info = createFakeInfo("abc"); info.serviceInfo.metaData = createFlagMetadata("tile_flag"); mShadowPackageManager.setResolveInfosForIntent(tileProbe, Arrays.asList(info)); mController.displayPreference(mScreen); verify(mScreen, never()).addPreference(argThat(pref -> pref.getKey().equals("abc"))); } @Test public void preferenceChecked_shouldAddTile() throws RemoteException { SwitchPreference preference = createPreference(/* defaultCheckedState = */ false); Loading Loading @@ -132,6 +162,21 @@ public class DevelopmentTilePreferenceControllerTest { return preference; } private ResolveInfo createFakeInfo(String name) { final ResolveInfo info = new ResolveInfo(); info.serviceInfo = new FakeServiceInfo(); info.serviceInfo.name = name; info.serviceInfo.icon = R.drawable.ic_settings_24dp; info.serviceInfo.packageName = mContext.getPackageName(); return info; } private Bundle createFlagMetadata(String flag) { Bundle metaData = new Bundle(); metaData.putString(DevelopmentTiles.META_DATA_REQUIRES_SYSTEM_PROPERTY, flag); return metaData; } private static class FakeServiceInfo extends ServiceInfo { public String loadLabel(PackageManager mgr) { Loading Loading
AndroidManifest.xml +2 −0 Original line number Diff line number Diff line Loading @@ -4067,6 +4067,8 @@ </intent-filter> <meta-data android:name="android.service.quicksettings.TOGGLEABLE_TILE" android:value="true"/> <meta-data android:name="com.android.settings.development.qstile.REQUIRES_SYSTEM_PROPERTY" android:value="persist.wm.debug.desktop_mode" /> </service> <activity Loading
src/com/android/settings/development/qstile/DevelopmentTilePreferenceController.java +16 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; import android.service.quicksettings.TileService; import android.util.Log; Loading Loading @@ -61,9 +62,23 @@ public class DevelopmentTilePreferenceController extends BasePreferenceControlle final Intent intent = new Intent(TileService.ACTION_QS_TILE) .setPackage(context.getPackageName()); final List<ResolveInfo> resolveInfos = mPackageManager.queryIntentServices(intent, PackageManager.MATCH_DISABLED_COMPONENTS); PackageManager.MATCH_DISABLED_COMPONENTS | PackageManager.GET_META_DATA); for (ResolveInfo info : resolveInfos) { ServiceInfo sInfo = info.serviceInfo; // Check if the tile requires a flag. If it does, hide tile if flag is off. if (sInfo.metaData != null) { String flag = sInfo.metaData.getString( DevelopmentTiles.META_DATA_REQUIRES_SYSTEM_PROPERTY); if (flag != null) { boolean enabled = SystemProperties.getBoolean(flag, false); if (!enabled) { // Flagged tile, flag is not enabled continue; } } } final int enabledSetting = mPackageManager.getComponentEnabledSetting( new ComponentName(sInfo.packageName, sInfo.name)); boolean checked = enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_ENABLED Loading
src/com/android/settings/development/qstile/DevelopmentTiles.java +16 −0 Original line number Diff line number Diff line Loading @@ -58,6 +58,22 @@ import com.android.settingslib.development.DevelopmentSettingsEnabler; import com.android.settingslib.development.SystemPropPoker; public abstract class DevelopmentTiles extends TileService { /** * Meta-data for a development tile to declare a sysprop flag that needs to be enabled for * the tile to be available. * * To define the flag, set this meta-data on the tile's manifest declaration. * <pre class="prettyprint"> * {@literal * <meta-data android:name="com.android.settings.development.qstile.REQUIRES_SYSTEM_PROPERTY" * android:value="persist.debug.flag_name_here" /> * } * </pre> */ public static final String META_DATA_REQUIRES_SYSTEM_PROPERTY = "com.android.settings.development.qstile.REQUIRES_SYSTEM_PROPERTY"; private static final String TAG = "DevelopmentTiles"; protected abstract boolean isEnabled(); Loading
tests/robotests/src/com/android/settings/development/qstile/DevelopmentTilePreferenceControllerTest.java +50 −5 Original line number Diff line number Diff line Loading @@ -19,7 +19,9 @@ package com.android.settings.development.qstile; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; Loading @@ -30,6 +32,7 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.os.Bundle; import android.os.RemoteException; import android.service.quicksettings.TileService; Loading @@ -50,6 +53,7 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.Shadows; import org.robolectric.shadows.ShadowPackageManager; import org.robolectric.shadows.ShadowSystemProperties; import org.robolectric.util.ReflectionHelpers; import java.util.Arrays; Loading Loading @@ -88,11 +92,7 @@ public class DevelopmentTilePreferenceControllerTest { public void display_hasTileService_shouldDisplay() { final Intent tileProbe = new Intent(TileService.ACTION_QS_TILE) .setPackage(mContext.getPackageName()); final ResolveInfo info = new ResolveInfo(); info.serviceInfo = new FakeServiceInfo(); info.serviceInfo.name = "abc"; info.serviceInfo.icon = R.drawable.ic_settings_24dp; info.serviceInfo.packageName = mContext.getPackageName(); final ResolveInfo info = createFakeInfo("abc"); mShadowPackageManager.setResolveInfosForIntent(tileProbe, Arrays.asList(info)); mController.displayPreference(mScreen); Loading @@ -100,6 +100,36 @@ public class DevelopmentTilePreferenceControllerTest { verify(mScreen, atLeastOnce()).addPreference(any(Preference.class)); } @Test public void display_flagDefinedAndOn_shouldDisplay() { ShadowSystemProperties.override("tile_flag", "1"); final Intent tileProbe = new Intent(TileService.ACTION_QS_TILE) .setPackage(mContext.getPackageName()); final ResolveInfo info = createFakeInfo("abc"); info.serviceInfo.metaData = createFlagMetadata("tile_flag"); mShadowPackageManager.setResolveInfosForIntent(tileProbe, Arrays.asList(info)); mController.displayPreference(mScreen); verify(mScreen, atLeastOnce()).addPreference(argThat(pref -> pref.getKey().equals("abc"))); } @Test public void display_flagDefinedAndOff_shouldHide() { ShadowSystemProperties.override("tile_flag" , "0"); final Intent tileProbe = new Intent(TileService.ACTION_QS_TILE) .setPackage(mContext.getPackageName()); final ResolveInfo info = createFakeInfo("abc"); info.serviceInfo.metaData = createFlagMetadata("tile_flag"); mShadowPackageManager.setResolveInfosForIntent(tileProbe, Arrays.asList(info)); mController.displayPreference(mScreen); verify(mScreen, never()).addPreference(argThat(pref -> pref.getKey().equals("abc"))); } @Test public void preferenceChecked_shouldAddTile() throws RemoteException { SwitchPreference preference = createPreference(/* defaultCheckedState = */ false); Loading Loading @@ -132,6 +162,21 @@ public class DevelopmentTilePreferenceControllerTest { return preference; } private ResolveInfo createFakeInfo(String name) { final ResolveInfo info = new ResolveInfo(); info.serviceInfo = new FakeServiceInfo(); info.serviceInfo.name = name; info.serviceInfo.icon = R.drawable.ic_settings_24dp; info.serviceInfo.packageName = mContext.getPackageName(); return info; } private Bundle createFlagMetadata(String flag) { Bundle metaData = new Bundle(); metaData.putString(DevelopmentTiles.META_DATA_REQUIRES_SYSTEM_PROPERTY, flag); return metaData; } private static class FakeServiceInfo extends ServiceInfo { public String loadLabel(PackageManager mgr) { Loading