From dcd089d3e7ae4dd735ee13947740a1c5bda54b1e Mon Sep 17 00:00:00 2001 From: Jing Ji Date: Thu, 23 Jun 2022 20:43:36 -0700 Subject: [PATCH] Allow preventing unrestricted Apps from being Stopped This CL adds a flag to allow toggling the behavior on whether or not the foreground service task manager should show a stop button for unrestricted apps. Bug: 230449539 Test: Manual - device_config put systemui \ show_stop_button_for_user_allowlisted_apps true|false Test: atest FgsManagerControllerTest Change-Id: I4cfe54933d7c6807a7ffbac9ee709c7d8d6b83d3 Merged-In: I4cfe54933d7c6807a7ffbac9ee709c7d8d6b83d3 --- .../sysui/SystemUiDeviceConfigFlags.java | 6 +++ .../systemui/qs/FgsManagerController.kt | 33 +++++++++++++++++ .../systemui/qs/FgsManagerControllerTest.java | 37 +++++++++++++++++++ 3 files changed, 76 insertions(+) diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java index 7c08a7bbc8262..6c689ff2b7252 100644 --- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java @@ -548,6 +548,12 @@ public final class SystemUiDeviceConfigFlags { */ public static final String TASK_MANAGER_SHOW_FOOTER_DOT = "task_manager_show_footer_dot"; + /** + * (boolean) Whether the task manager should show a stop button if the app is allowlisted + * by the user. + */ + public static final String TASK_MANAGER_SHOW_STOP_BUTTON_FOR_USER_ALLOWLISTED_APPS = + "show_stop_button_for_user_allowlisted_apps"; /** * (boolean) Whether the clipboard overlay is enabled. diff --git a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt index 0288c9fce64ae..8f6c3737d6dae 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt @@ -40,11 +40,13 @@ import android.widget.Button import android.widget.ImageView import android.widget.TextView import androidx.annotation.GuardedBy +import androidx.annotation.VisibleForTesting import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.TASK_MANAGER_ENABLED import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.TASK_MANAGER_SHOW_FOOTER_DOT +import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.TASK_MANAGER_SHOW_STOP_BUTTON_FOR_USER_ALLOWLISTED_APPS import com.android.internal.jank.InteractionJankMonitor import com.android.systemui.Dumpable import com.android.systemui.R @@ -87,6 +89,7 @@ class FgsManagerController @Inject constructor( private val LOG_TAG = FgsManagerController::class.java.simpleName private const val DEFAULT_TASK_MANAGER_ENABLED = true private const val DEFAULT_TASK_MANAGER_SHOW_FOOTER_DOT = false + private const val DEFAULT_TASK_MANAGER_SHOW_STOP_BUTTON_FOR_USER_ALLOWLISTED_APPS = true } var changesSinceDialog = false @@ -96,6 +99,8 @@ class FgsManagerController @Inject constructor( private set var showFooterDot = false private set + var showStopBtnForUserAllowlistedApps = false + private set private val lock = Any() @@ -163,6 +168,9 @@ class FgsManagerController @Inject constructor( isAvailable = it.getBoolean(TASK_MANAGER_ENABLED, isAvailable) showFooterDot = it.getBoolean(TASK_MANAGER_SHOW_FOOTER_DOT, showFooterDot) + showStopBtnForUserAllowlistedApps = it.getBoolean( + TASK_MANAGER_SHOW_STOP_BUTTON_FOR_USER_ALLOWLISTED_APPS, + showStopBtnForUserAllowlistedApps) } isAvailable = deviceConfigProxy.getBoolean( @@ -173,6 +181,10 @@ class FgsManagerController @Inject constructor( NAMESPACE_SYSTEMUI, TASK_MANAGER_SHOW_FOOTER_DOT, DEFAULT_TASK_MANAGER_SHOW_FOOTER_DOT ) + showStopBtnForUserAllowlistedApps = deviceConfigProxy.getBoolean( + NAMESPACE_SYSTEMUI, + TASK_MANAGER_SHOW_STOP_BUTTON_FOR_USER_ALLOWLISTED_APPS, + DEFAULT_TASK_MANAGER_SHOW_STOP_BUTTON_FOR_USER_ALLOWLISTED_APPS) dumpManager.registerDumpable(this) @@ -275,6 +287,20 @@ class FgsManagerController @Inject constructor( } } + @VisibleForTesting + @JvmName("getNumVisibleButtons") + internal fun getNumVisibleButtons(): Int { + synchronized(lock) { + return getNumVisibleButtonsLocked() + } + } + + private fun getNumVisibleButtonsLocked(): Int { + return runningServiceTokens.keys.count { + it.uiControl != UIControl.HIDE_BUTTON && currentProfileIds.contains(it.userId) + } + } + fun shouldUpdateFooterVisibility() = dialog == null fun showDialog(viewLaunchedFrom: View?) { @@ -505,6 +531,13 @@ class FgsManagerController @Inject constructor( PowerExemptionManager.REASON_PROC_STATE_PERSISTENT_UI, PowerExemptionManager.REASON_ROLE_DIALER, PowerExemptionManager.REASON_SYSTEM_MODULE -> UIControl.HIDE_BUTTON + + PowerExemptionManager.REASON_ALLOWLISTED_PACKAGE -> + if (showStopBtnForUserAllowlistedApps) { + UIControl.NORMAL + } else { + UIControl.HIDE_BUTTON + } else -> UIControl.NORMAL } uiControlInitialized = true diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/FgsManagerControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/FgsManagerControllerTest.java index 2927669020c85..3dc10d0ac6cab 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/FgsManagerControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/FgsManagerControllerTest.java @@ -16,6 +16,8 @@ package com.android.systemui.qs; +import static android.os.PowerExemptionManager.REASON_ALLOWLISTED_PACKAGE; + import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; @@ -34,6 +36,7 @@ import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.os.Binder; import android.os.RemoteException; +import android.os.UserHandle; import android.provider.DeviceConfig; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -222,7 +225,41 @@ public class FgsManagerControllerTest extends SysuiTestCase { Assert.assertEquals(2, mFmc.getNumRunningPackages()); } + @Test + public void testButtonVisibilityOnShowAllowlistButtonFlagChange() throws Exception { + setUserProfiles(0); + setBackgroundRestrictionExemptionReason("pkg", 12345, REASON_ALLOWLISTED_PACKAGE); + final Binder binder = new Binder(); + setShowStopButtonForUserAllowlistedApps(true); + mIForegroundServiceObserver.onForegroundStateChanged(binder, "pkg", 0, true); + Assert.assertEquals(1, mFmc.getNumVisibleButtons()); + + mIForegroundServiceObserver.onForegroundStateChanged(binder, "pkg", 0, false); + Assert.assertEquals(0, mFmc.getNumVisibleButtons()); + + setShowStopButtonForUserAllowlistedApps(false); + mIForegroundServiceObserver.onForegroundStateChanged(binder, "pkg", 0, true); + Assert.assertEquals(0, mFmc.getNumVisibleButtons()); + } + + private void setShowStopButtonForUserAllowlistedApps(boolean enable) { + mDeviceConfigProxyFake.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags.TASK_MANAGER_SHOW_STOP_BUTTON_FOR_USER_ALLOWLISTED_APPS, + enable ? "true" : "false", false); + mBackgroundExecutor.advanceClockToLast(); + mBackgroundExecutor.runAllReady(); + } + + private void setBackgroundRestrictionExemptionReason(String pkgName, int uid, int reason) + throws Exception { + Mockito.doReturn(uid) + .when(mPackageManager) + .getPackageUidAsUser(pkgName, UserHandle.getUserId(uid)); + Mockito.doReturn(reason) + .when(mIActivityManager) + .getBackgroundRestrictionExemptionReason(uid); + } FgsManagerController createFgsManagerController() throws RemoteException { ArgumentCaptor iForegroundServiceObserverArgumentCaptor =