Merge "Add broadcast receiver to listen for safety center flag changes" into tm-dev
This commit is contained in:
commit
3795120659
@ -79,5 +79,6 @@
|
||||
<permission name="android.permission.LOG_COMPAT_CHANGE" />
|
||||
<permission name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
|
||||
<permission name="android.permission.READ_DEVICE_CONFIG" />
|
||||
<permission name="android.permission.READ_SAFETY_CENTER_STATUS" />
|
||||
</privapp-permissions>
|
||||
</permissions>
|
||||
|
@ -319,6 +319,9 @@
|
||||
<uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
|
||||
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
|
||||
|
||||
<!-- To read safety center status -->
|
||||
<uses-permission android:name="android.permission.READ_SAFETY_CENTER_STATUS" />
|
||||
|
||||
<protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" />
|
||||
<protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" />
|
||||
<protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" />
|
||||
|
@ -61,6 +61,7 @@ import android.os.ServiceManager;
|
||||
import android.os.UserManager;
|
||||
import android.os.Vibrator;
|
||||
import android.permission.PermissionManager;
|
||||
import android.safetycenter.SafetyCenterManager;
|
||||
import android.service.dreams.DreamService;
|
||||
import android.service.dreams.IDreamManager;
|
||||
import android.telecom.TelecomManager;
|
||||
@ -476,4 +477,11 @@ public class FrameworkServicesModule {
|
||||
static SmartspaceManager provideSmartspaceManager(Context context) {
|
||||
return context.getSystemService(SmartspaceManager.class);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static SafetyCenterManager provideSafetyCenterManager(Context context) {
|
||||
return context.getSystemService(SafetyCenterManager.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,15 +1,19 @@
|
||||
package com.android.systemui.qs
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.permission.PermissionGroupUsage
|
||||
import android.permission.PermissionManager
|
||||
import android.provider.DeviceConfig
|
||||
import android.safetycenter.SafetyCenterManager
|
||||
import android.view.View
|
||||
import androidx.annotation.WorkerThread
|
||||
import com.android.internal.R
|
||||
import com.android.internal.logging.UiEventLogger
|
||||
import com.android.systemui.animation.ActivityLaunchAnimator
|
||||
import com.android.systemui.appops.AppOpsController
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher
|
||||
import com.android.systemui.plugins.ActivityStarter
|
||||
import com.android.systemui.privacy.OngoingPrivacyChip
|
||||
import com.android.systemui.privacy.PrivacyChipEvent
|
||||
@ -18,7 +22,6 @@ import com.android.systemui.privacy.PrivacyItem
|
||||
import com.android.systemui.privacy.PrivacyItemController
|
||||
import com.android.systemui.privacy.logging.PrivacyLogger
|
||||
import com.android.systemui.statusbar.phone.StatusIconContainer
|
||||
import com.android.systemui.util.DeviceConfigProxy
|
||||
import java.util.concurrent.Executor
|
||||
import javax.inject.Inject
|
||||
import com.android.systemui.dagger.qualifiers.Background
|
||||
@ -50,15 +53,11 @@ class HeaderPrivacyIconsController @Inject constructor(
|
||||
@Main private val uiExecutor: Executor,
|
||||
private val activityStarter: ActivityStarter,
|
||||
private val appOpsController: AppOpsController,
|
||||
private val deviceConfigProxy: DeviceConfigProxy
|
||||
private val broadcastDispatcher: BroadcastDispatcher,
|
||||
private val safetyCenterManager: SafetyCenterManager
|
||||
) {
|
||||
|
||||
companion object {
|
||||
const val SAFETY_CENTER_ENABLED = "safety_center_is_enabled"
|
||||
}
|
||||
|
||||
var chipVisibilityListener: ChipVisibilityListener? = null
|
||||
|
||||
private var listening = false
|
||||
private var micCameraIndicatorsEnabled = false
|
||||
private var locationIndicatorsEnabled = false
|
||||
@ -68,20 +67,40 @@ class HeaderPrivacyIconsController @Inject constructor(
|
||||
private val micSlot = privacyChip.resources.getString(R.string.status_bar_microphone)
|
||||
private val locationSlot = privacyChip.resources.getString(R.string.status_bar_location)
|
||||
|
||||
private val devicePropertiesChangedListener =
|
||||
object : DeviceConfig.OnPropertiesChangedListener {
|
||||
override fun onPropertiesChanged(properties: DeviceConfig.Properties) {
|
||||
safetyCenterEnabled = properties.getBoolean(SAFETY_CENTER_ENABLED, false)
|
||||
}
|
||||
private val safetyCenterReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
safetyCenterEnabled = safetyCenterManager.isSafetyCenterEnabled()
|
||||
}
|
||||
}
|
||||
|
||||
val attachStateChangeListener = object : View.OnAttachStateChangeListener {
|
||||
override fun onViewAttachedToWindow(v: View) {
|
||||
broadcastDispatcher.registerReceiver(
|
||||
safetyCenterReceiver,
|
||||
IntentFilter(SafetyCenterManager.ACTION_SAFETY_CENTER_ENABLED_CHANGED),
|
||||
executor = backgroundExecutor
|
||||
)
|
||||
}
|
||||
|
||||
override fun onViewDetachedFromWindow(v: View) {
|
||||
broadcastDispatcher.unregisterReceiver(safetyCenterReceiver)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
safetyCenterEnabled = deviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
|
||||
SAFETY_CENTER_ENABLED, false)
|
||||
deviceConfigProxy.addOnPropertiesChangedListener(
|
||||
DeviceConfig.NAMESPACE_PRIVACY,
|
||||
uiExecutor,
|
||||
devicePropertiesChangedListener)
|
||||
backgroundExecutor.execute {
|
||||
safetyCenterEnabled = safetyCenterManager.isSafetyCenterEnabled()
|
||||
}
|
||||
|
||||
if (privacyChip.isAttachedToWindow()) {
|
||||
broadcastDispatcher.registerReceiver(
|
||||
safetyCenterReceiver,
|
||||
IntentFilter(SafetyCenterManager.ACTION_SAFETY_CENTER_ENABLED_CHANGED),
|
||||
executor = backgroundExecutor
|
||||
)
|
||||
}
|
||||
|
||||
privacyChip.addOnAttachStateChangeListener(attachStateChangeListener)
|
||||
}
|
||||
|
||||
private val picCallback: PrivacyItemController.Callback =
|
||||
|
@ -1,14 +1,18 @@
|
||||
package com.android.systemui.qs
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.permission.PermissionManager
|
||||
import android.provider.DeviceConfig
|
||||
import android.safetycenter.SafetyCenterManager
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.view.View
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.internal.logging.UiEventLogger
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.appops.AppOpsController
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher
|
||||
import com.android.systemui.plugins.ActivityStarter
|
||||
import com.android.systemui.privacy.OngoingPrivacyChip
|
||||
import com.android.systemui.privacy.PrivacyDialogController
|
||||
@ -16,30 +20,30 @@ import com.android.systemui.privacy.PrivacyItemController
|
||||
import com.android.systemui.privacy.logging.PrivacyLogger
|
||||
import com.android.systemui.statusbar.phone.StatusIconContainer
|
||||
import com.android.systemui.util.concurrency.FakeExecutor
|
||||
import com.android.systemui.util.DeviceConfigProxy
|
||||
import com.android.systemui.util.DeviceConfigProxyFake
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.android.systemui.util.mockito.argumentCaptor
|
||||
import com.android.systemui.util.mockito.capture
|
||||
import com.android.systemui.util.mockito.nullable
|
||||
import com.android.systemui.util.time.FakeSystemClock
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentMatchers.anyInt
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.Mockito.never
|
||||
import org.mockito.Mockito.times
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.MockitoAnnotations
|
||||
import java.util.concurrent.Executor
|
||||
import org.mockito.Mockito.`when` as whenever
|
||||
|
||||
private fun <T> eq(value: T): T = Mockito.eq(value) ?: value
|
||||
private fun <T> any(): T = Mockito.any<T>()
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
class HeaderPrivacyIconsControllerTest : SysuiTestCase() {
|
||||
|
||||
companion object {
|
||||
const val SAFETY_CENTER_ENABLED = "safety_center_is_enabled"
|
||||
}
|
||||
|
||||
@Mock
|
||||
private lateinit var privacyItemController: PrivacyItemController
|
||||
@Mock
|
||||
@ -55,14 +59,16 @@ class HeaderPrivacyIconsControllerTest : SysuiTestCase() {
|
||||
@Mock
|
||||
private lateinit var permissionManager: PermissionManager
|
||||
@Mock
|
||||
private lateinit var backgroundExecutor: Executor
|
||||
@Mock
|
||||
private lateinit var activityStarter: ActivityStarter
|
||||
@Mock
|
||||
private lateinit var appOpsController: AppOpsController
|
||||
@Mock
|
||||
private lateinit var broadcastDispatcher: BroadcastDispatcher
|
||||
@Mock
|
||||
private lateinit var safetyCenterManager: SafetyCenterManager
|
||||
|
||||
private val uiExecutor = FakeExecutor(FakeSystemClock())
|
||||
private lateinit var deviceConfigProxy: DeviceConfigProxy
|
||||
private val backgroundExecutor = FakeExecutor(FakeSystemClock())
|
||||
private lateinit var cameraSlotName: String
|
||||
private lateinit var microphoneSlotName: String
|
||||
private lateinit var locationSlotName: String
|
||||
@ -73,11 +79,11 @@ class HeaderPrivacyIconsControllerTest : SysuiTestCase() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
whenever(privacyChip.context).thenReturn(context)
|
||||
whenever(privacyChip.resources).thenReturn(context.resources)
|
||||
whenever(privacyChip.isAttachedToWindow).thenReturn(true)
|
||||
|
||||
cameraSlotName = context.getString(com.android.internal.R.string.status_bar_camera)
|
||||
microphoneSlotName = context.getString(com.android.internal.R.string.status_bar_microphone)
|
||||
locationSlotName = context.getString(com.android.internal.R.string.status_bar_location)
|
||||
deviceConfigProxy = DeviceConfigProxyFake()
|
||||
|
||||
controller = HeaderPrivacyIconsController(
|
||||
privacyItemController,
|
||||
@ -91,8 +97,11 @@ class HeaderPrivacyIconsControllerTest : SysuiTestCase() {
|
||||
uiExecutor,
|
||||
activityStarter,
|
||||
appOpsController,
|
||||
deviceConfigProxy
|
||||
broadcastDispatcher,
|
||||
safetyCenterManager
|
||||
)
|
||||
|
||||
backgroundExecutor.runAllReady()
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -141,19 +150,25 @@ class HeaderPrivacyIconsControllerTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun testPrivacyChipClicked() {
|
||||
changeProperty(SAFETY_CENTER_ENABLED, false)
|
||||
whenever(safetyCenterManager.isSafetyCenterEnabled).thenReturn(false)
|
||||
controller.onParentVisible()
|
||||
|
||||
val captor = argumentCaptor<View.OnClickListener>()
|
||||
verify(privacyChip).setOnClickListener(capture(captor))
|
||||
captor.value.onClick(privacyChip)
|
||||
|
||||
verify(privacyDialogController).showDialog(any(Context::class.java))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSafetyCenterFlag() {
|
||||
changeProperty(SAFETY_CENTER_ENABLED, true)
|
||||
val receiverCaptor = argumentCaptor<BroadcastReceiver>()
|
||||
whenever(safetyCenterManager.isSafetyCenterEnabled).thenReturn(true)
|
||||
verify(broadcastDispatcher).registerReceiver(capture(receiverCaptor),
|
||||
any(), any(), nullable(), anyInt())
|
||||
receiverCaptor.value.onReceive(
|
||||
context,
|
||||
Intent(SafetyCenterManager.ACTION_SAFETY_CENTER_ENABLED_CHANGED)
|
||||
)
|
||||
backgroundExecutor.runAllReady()
|
||||
controller.onParentVisible()
|
||||
val captor = argumentCaptor<View.OnClickListener>()
|
||||
verify(privacyChip).setOnClickListener(capture(captor))
|
||||
@ -161,18 +176,29 @@ class HeaderPrivacyIconsControllerTest : SysuiTestCase() {
|
||||
verify(privacyDialogController, never()).showDialog(any(Context::class.java))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBroadcastReceiverUnregisteredWhenChipDetached() {
|
||||
whenever(safetyCenterManager.isSafetyCenterEnabled).thenReturn(false)
|
||||
controller.attachStateChangeListener.onViewDetachedFromWindow(privacyChip)
|
||||
backgroundExecutor.runAllReady()
|
||||
val broadcastReceiverCaptor = argumentCaptor<BroadcastReceiver>()
|
||||
verify(broadcastDispatcher).unregisterReceiver(capture(broadcastReceiverCaptor))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBroadcastReceiverRegisteredWhenChipAttached() {
|
||||
whenever(safetyCenterManager.isSafetyCenterEnabled).thenReturn(false)
|
||||
controller.attachStateChangeListener.onViewAttachedToWindow(privacyChip)
|
||||
backgroundExecutor.runAllReady()
|
||||
val broadcastReceiverCaptor = argumentCaptor<BroadcastReceiver>()
|
||||
val intentFilterCaptor = argumentCaptor<IntentFilter>()
|
||||
// Broadcast receiver is registered on init and when privacy chip is attached
|
||||
verify(broadcastDispatcher, times(2)).registerReceiver(capture(broadcastReceiverCaptor),
|
||||
capture(intentFilterCaptor), any(), nullable(), anyInt())
|
||||
}
|
||||
|
||||
private fun setPrivacyController(micCamera: Boolean, location: Boolean) {
|
||||
whenever(privacyItemController.micCameraAvailable).thenReturn(micCamera)
|
||||
whenever(privacyItemController.locationAvailable).thenReturn(location)
|
||||
}
|
||||
|
||||
private fun changeProperty(name: String, value: Boolean?) {
|
||||
deviceConfigProxy.setProperty(
|
||||
DeviceConfig.NAMESPACE_PRIVACY,
|
||||
name,
|
||||
value?.toString(),
|
||||
false
|
||||
)
|
||||
uiExecutor.runAllReady()
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user