Merge "Add work profile support to chooser selector" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
978d953c71
@@ -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
|
||||||
}
|
}
|
||||||
try {
|
userTracker.userProfiles.forEach {
|
||||||
packageManager.setComponentEnabledSetting(chooserComponent, newState, /* flags = */ 0)
|
try {
|
||||||
} catch (e: IllegalArgumentException) {
|
context.createContextAsUser(it.userHandle, /* flags = */ 0).packageManager
|
||||||
Log.w("ChooserSelector", "Unable to set IntentResolver enabled=" + enabled, e)
|
.setComponentEnabledSetting(chooserComponent, newState, /* flags = */ 0)
|
||||||
|
} catch (e: IllegalArgumentException) {
|
||||||
|
Log.w(
|
||||||
|
"ChooserSelector",
|
||||||
|
"Unable to set IntentResolver enabled=$enabled for user ${it.id}",
|
||||||
|
e,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user