From 618876c6c9b4394498f14c92459e2879564c092b Mon Sep 17 00:00:00 2001 From: Ats Jenk Date: Thu, 22 Sep 2022 16:44:51 -0700 Subject: [PATCH] Add support to hide developer tile based on a flag Define new meta-data option for development tiles that can be used to specify a sysprop flag. If this meta-data is present, the value will be used as the flag name that has to be enabled for the preference to show up. Bug: 248363970 Test: atest SettingsRoboTests:DevelopmentTilePreferenceControllerTest Change-Id: I66d56777a6290d7fee739492bd2871f637791d75 --- AndroidManifest.xml | 2 + .../DevelopmentTilePreferenceController.java | 17 +++++- .../development/qstile/DevelopmentTiles.java | 16 ++++++ ...velopmentTilePreferenceControllerTest.java | 55 +++++++++++++++++-- 4 files changed, 84 insertions(+), 6 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index ee7b1f90a92..f51719b4dd3 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -4067,6 +4067,8 @@ + 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 diff --git a/src/com/android/settings/development/qstile/DevelopmentTiles.java b/src/com/android/settings/development/qstile/DevelopmentTiles.java index 343ed24e0a1..bb5216cb8d0 100644 --- a/src/com/android/settings/development/qstile/DevelopmentTiles.java +++ b/src/com/android/settings/development/qstile/DevelopmentTiles.java @@ -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. + *
+     * {@literal
+     * 
+     * }
+     * 
+ */ + 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(); diff --git a/tests/robotests/src/com/android/settings/development/qstile/DevelopmentTilePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/qstile/DevelopmentTilePreferenceControllerTest.java index dc466dff80d..8a94aee07c1 100644 --- a/tests/robotests/src/com/android/settings/development/qstile/DevelopmentTilePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/development/qstile/DevelopmentTilePreferenceControllerTest.java @@ -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; @@ -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; @@ -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; @@ -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); @@ -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); @@ -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) {