Merge "Add work profile support to chooser selector" into tm-qpr-dev

This commit is contained in:
TreeHugger Robot
2022-11-08 22:53:44 +00:00
committed by Android (Google) Code Review
3 changed files with 75 additions and 66 deletions

View File

@@ -4,30 +4,32 @@ import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.util.Log import android.util.Log
import com.android.internal.R
import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.FlagListenable import com.android.systemui.flags.FlagListenable
import com.android.systemui.flags.Flags import com.android.systemui.flags.Flags
import javax.inject.Inject import com.android.systemui.settings.UserTracker
import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import javax.inject.Inject
@SysUISingleton @SysUISingleton
class ChooserSelector @Inject constructor( class ChooserSelector @Inject constructor(
private val context: Context, private val context: Context,
private val userTracker: UserTracker,
private val featureFlags: FeatureFlags, private val featureFlags: FeatureFlags,
@Application private val coroutineScope: CoroutineScope, @Application private val coroutineScope: CoroutineScope,
@Background private val bgDispatcher: CoroutineDispatcher @Background private val bgDispatcher: CoroutineDispatcher,
) : CoreStartable { ) : CoreStartable {
private val packageManager = context.packageManager
private val chooserComponent = ComponentName.unflattenFromString( private val chooserComponent = ComponentName.unflattenFromString(
context.resources.getString(ChooserSelectorResourceHelper.CONFIG_CHOOSER_ACTIVITY)) context.resources.getString(R.string.config_chooserActivity))
override fun start() { override fun start() {
coroutineScope.launch { coroutineScope.launch {
@@ -56,10 +58,17 @@ class ChooserSelector @Inject constructor(
} else { } else {
PackageManager.COMPONENT_ENABLED_STATE_DISABLED PackageManager.COMPONENT_ENABLED_STATE_DISABLED
} }
userTracker.userProfiles.forEach {
try { try {
packageManager.setComponentEnabledSetting(chooserComponent, newState, /* flags = */ 0) context.createContextAsUser(it.userHandle, /* flags = */ 0).packageManager
.setComponentEnabledSetting(chooserComponent, newState, /* flags = */ 0)
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
Log.w("ChooserSelector", "Unable to set IntentResolver enabled=" + enabled, e) Log.w(
"ChooserSelector",
"Unable to set IntentResolver enabled=$enabled for user ${it.id}",
e,
)
}
} }
} }

View File

@@ -1,31 +0,0 @@
/*
* Copyright (C) 2022 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;
import androidx.annotation.StringRes;
import com.android.internal.R;
/** Helper class for referencing resources */
class ChooserSelectorResourceHelper {
private ChooserSelectorResourceHelper() {
}
@StringRes
static final int CONFIG_CHOOSER_ACTIVITY = R.string.config_chooserActivity;
}

View File

@@ -3,6 +3,7 @@ package com.android.systemui
import android.content.ComponentName import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.pm.UserInfo
import android.content.res.Resources import android.content.res.Resources
import android.testing.AndroidTestingRunner import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
@@ -11,9 +12,11 @@ import com.android.systemui.flags.Flag
import com.android.systemui.flags.FlagListenable import com.android.systemui.flags.FlagListenable
import com.android.systemui.flags.Flags import com.android.systemui.flags.Flags
import com.android.systemui.flags.UnreleasedFlag import com.android.systemui.flags.UnreleasedFlag
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.kotlinArgumentCaptor import com.android.systemui.util.mockito.kotlinArgumentCaptor
import com.android.systemui.util.mockito.whenever
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.cancel import kotlinx.coroutines.cancel
@@ -26,9 +29,9 @@ import org.mockito.Mock
import org.mockito.Mockito.anyInt import org.mockito.Mockito.anyInt
import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.never import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyZeroInteractions import org.mockito.Mockito.verifyZeroInteractions
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations import org.mockito.MockitoAnnotations
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
@@ -44,6 +47,8 @@ class ChooserSelectorTest : SysuiTestCase() {
private lateinit var chooserSelector: ChooserSelector private lateinit var chooserSelector: ChooserSelector
@Mock private lateinit var mockContext: Context @Mock private lateinit var mockContext: Context
@Mock private lateinit var mockProfileContext: Context
@Mock private lateinit var mockUserTracker: UserTracker
@Mock private lateinit var mockPackageManager: PackageManager @Mock private lateinit var mockPackageManager: PackageManager
@Mock private lateinit var mockResources: Resources @Mock private lateinit var mockResources: Resources
@Mock private lateinit var mockFeatureFlags: FeatureFlags @Mock private lateinit var mockFeatureFlags: FeatureFlags
@@ -52,12 +57,20 @@ class ChooserSelectorTest : SysuiTestCase() {
fun setup() { fun setup() {
MockitoAnnotations.initMocks(this) MockitoAnnotations.initMocks(this)
`when`(mockContext.packageManager).thenReturn(mockPackageManager) whenever(mockContext.createContextAsUser(any(), anyInt())).thenReturn(mockProfileContext)
`when`(mockContext.resources).thenReturn(mockResources) whenever(mockContext.resources).thenReturn(mockResources)
`when`(mockResources.getString(anyInt())).thenReturn( whenever(mockProfileContext.packageManager).thenReturn(mockPackageManager)
whenever(mockResources.getString(anyInt())).thenReturn(
ComponentName("TestPackage", "TestClass").flattenToString()) ComponentName("TestPackage", "TestClass").flattenToString())
whenever(mockUserTracker.userProfiles).thenReturn(listOf(UserInfo(), UserInfo()))
chooserSelector = ChooserSelector(mockContext, mockFeatureFlags, testScope, testDispatcher) chooserSelector = ChooserSelector(
mockContext,
mockUserTracker,
mockFeatureFlags,
testScope,
testDispatcher,
)
} }
@After @After
@@ -74,7 +87,9 @@ class ChooserSelectorTest : SysuiTestCase() {
// Assert // Assert
verify(mockFeatureFlags).addListener( verify(mockFeatureFlags).addListener(
eq<Flag<*>>(Flags.CHOOSER_UNBUNDLED), flagListener.capture()) eq<Flag<*>>(Flags.CHOOSER_UNBUNDLED),
flagListener.capture(),
)
verify(mockFeatureFlags, never()).removeListener(any()) verify(mockFeatureFlags, never()).removeListener(any())
// Act // Act
@@ -87,86 +102,102 @@ class ChooserSelectorTest : SysuiTestCase() {
@Test @Test
fun initialize_enablesUnbundledChooser_whenFlagEnabled() { fun initialize_enablesUnbundledChooser_whenFlagEnabled() {
// Arrange // Arrange
`when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(true) whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(true)
// Act // Act
chooserSelector.start() chooserSelector.start()
// Assert // Assert
verify(mockPackageManager).setComponentEnabledSetting( verify(mockPackageManager, times(2)).setComponentEnabledSetting(
eq(ComponentName("TestPackage", "TestClass")), eq(ComponentName("TestPackage", "TestClass")),
eq(PackageManager.COMPONENT_ENABLED_STATE_ENABLED), eq(PackageManager.COMPONENT_ENABLED_STATE_ENABLED),
anyInt()) anyInt(),
)
} }
@Test @Test
fun initialize_disablesUnbundledChooser_whenFlagDisabled() { fun initialize_disablesUnbundledChooser_whenFlagDisabled() {
// Arrange // Arrange
`when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false) whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false)
// Act // Act
chooserSelector.start() chooserSelector.start()
// Assert // Assert
verify(mockPackageManager).setComponentEnabledSetting( verify(mockPackageManager, times(2)).setComponentEnabledSetting(
eq(ComponentName("TestPackage", "TestClass")), eq(ComponentName("TestPackage", "TestClass")),
eq(PackageManager.COMPONENT_ENABLED_STATE_DISABLED), eq(PackageManager.COMPONENT_ENABLED_STATE_DISABLED),
anyInt()) anyInt(),
)
} }
@Test @Test
fun enablesUnbundledChooser_whenFlagBecomesEnabled() { fun enablesUnbundledChooser_whenFlagBecomesEnabled() {
// Arrange // Arrange
`when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false) whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false)
chooserSelector.start() chooserSelector.start()
verify(mockFeatureFlags).addListener( verify(mockFeatureFlags).addListener(
eq<Flag<*>>(Flags.CHOOSER_UNBUNDLED), flagListener.capture()) eq<Flag<*>>(Flags.CHOOSER_UNBUNDLED),
flagListener.capture(),
)
verify(mockPackageManager, never()).setComponentEnabledSetting( verify(mockPackageManager, never()).setComponentEnabledSetting(
any(), eq(PackageManager.COMPONENT_ENABLED_STATE_ENABLED), anyInt()) any(),
eq(PackageManager.COMPONENT_ENABLED_STATE_ENABLED),
anyInt(),
)
// Act // Act
`when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(true) whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(true)
flagListener.value.onFlagChanged(TestFlagEvent(Flags.CHOOSER_UNBUNDLED.id)) flagListener.value.onFlagChanged(TestFlagEvent(Flags.CHOOSER_UNBUNDLED.id))
// Assert // Assert
verify(mockPackageManager).setComponentEnabledSetting( verify(mockPackageManager, times(2)).setComponentEnabledSetting(
eq(ComponentName("TestPackage", "TestClass")), eq(ComponentName("TestPackage", "TestClass")),
eq(PackageManager.COMPONENT_ENABLED_STATE_ENABLED), eq(PackageManager.COMPONENT_ENABLED_STATE_ENABLED),
anyInt()) anyInt(),
)
} }
@Test @Test
fun disablesUnbundledChooser_whenFlagBecomesDisabled() { fun disablesUnbundledChooser_whenFlagBecomesDisabled() {
// Arrange // Arrange
`when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(true) whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(true)
chooserSelector.start() chooserSelector.start()
verify(mockFeatureFlags).addListener( verify(mockFeatureFlags).addListener(
eq<Flag<*>>(Flags.CHOOSER_UNBUNDLED), flagListener.capture()) eq<Flag<*>>(Flags.CHOOSER_UNBUNDLED),
flagListener.capture(),
)
verify(mockPackageManager, never()).setComponentEnabledSetting( verify(mockPackageManager, never()).setComponentEnabledSetting(
any(), eq(PackageManager.COMPONENT_ENABLED_STATE_DISABLED), anyInt()) any(),
eq(PackageManager.COMPONENT_ENABLED_STATE_DISABLED),
anyInt(),
)
// Act // Act
`when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false) whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false)
flagListener.value.onFlagChanged(TestFlagEvent(Flags.CHOOSER_UNBUNDLED.id)) flagListener.value.onFlagChanged(TestFlagEvent(Flags.CHOOSER_UNBUNDLED.id))
// Assert // Assert
verify(mockPackageManager).setComponentEnabledSetting( verify(mockPackageManager, times(2)).setComponentEnabledSetting(
eq(ComponentName("TestPackage", "TestClass")), eq(ComponentName("TestPackage", "TestClass")),
eq(PackageManager.COMPONENT_ENABLED_STATE_DISABLED), eq(PackageManager.COMPONENT_ENABLED_STATE_DISABLED),
anyInt()) anyInt(),
)
} }
@Test @Test
fun doesNothing_whenAnotherFlagChanges() { fun doesNothing_whenAnotherFlagChanges() {
// Arrange // Arrange
`when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false) whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false)
chooserSelector.start() chooserSelector.start()
verify(mockFeatureFlags).addListener( verify(mockFeatureFlags).addListener(
eq<Flag<*>>(Flags.CHOOSER_UNBUNDLED), flagListener.capture()) eq<Flag<*>>(Flags.CHOOSER_UNBUNDLED),
flagListener.capture(),
)
clearInvocations(mockPackageManager) clearInvocations(mockPackageManager)
// Act // Act
`when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false) whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false)
flagListener.value.onFlagChanged(TestFlagEvent(Flags.CHOOSER_UNBUNDLED.id + 1)) flagListener.value.onFlagChanged(TestFlagEvent(Flags.CHOOSER_UNBUNDLED.id + 1))
// Assert // Assert