summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Chaohui Wang <chaohuiw@google.com> 2024-01-19 14:44:52 +0800
committer Chaohui Wang <chaohuiw@google.com> 2024-01-19 13:53:21 +0000
commitf7bfbc3490bf66fd8c4dce7cad7de0fd7c6cca70 (patch)
treec20bee6c0f5d717ee5c03f7e59569dd235e80cdd
parent4846e39bce4c3955c53ba9256e84705eebe218de (diff)
New PermissionsChangedFlow
Also also clean up LiveDataTestUtil. Bug: 321163306 Test: unit test Change-Id: Id2d77f53569619654036e782285cab8931fd5bfc
-rw-r--r--packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/LiveDataTestUtil.kt50
-rw-r--r--packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/PermissionsChangedFlow.kt46
-rw-r--r--packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/PermissionsChangedFlowTest.kt81
3 files changed, 127 insertions, 50 deletions
diff --git a/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/LiveDataTestUtil.kt b/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/LiveDataTestUtil.kt
deleted file mode 100644
index dddda5511c7b..000000000000
--- a/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/LiveDataTestUtil.kt
+++ /dev/null
@@ -1,50 +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.settingslib.spa.testutils
-
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.Observer
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
-import java.util.concurrent.TimeoutException
-
-fun <T> LiveData<T>.getOrAwaitValue(
- timeout: Long = 1,
- timeUnit: TimeUnit = TimeUnit.SECONDS,
- afterObserve: () -> Unit = {},
-): T? {
- var data: T? = null
- val latch = CountDownLatch(1)
- val observer = Observer<T> { newData ->
- data = newData
- latch.countDown()
- }
- this.observeForever(observer)
-
- afterObserve()
-
- try {
- // Don't wait indefinitely if the LiveData is not set.
- if (!latch.await(timeout, timeUnit)) {
- throw TimeoutException("LiveData value was never set.")
- }
- } finally {
- this.removeObserver(observer)
- }
-
- return data
-}
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/PermissionsChangedFlow.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/PermissionsChangedFlow.kt
new file mode 100644
index 000000000000..367244aa2cfe
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/PermissionsChangedFlow.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 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.settingslib.spaprivileged.model.app
+
+import android.content.Context
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
+import com.android.settingslib.spaprivileged.framework.common.asUser
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.conflate
+import kotlinx.coroutines.flow.flowOn
+
+/**
+ * Creates an instance of a cold Flow for permissions changed callback of given [app].
+ *
+ * An initial element will be always sent.
+ */
+fun Context.permissionsChangedFlow(app: ApplicationInfo) = callbackFlow {
+ val userPackageManager = asUser(app.userHandle).packageManager
+
+ val onPermissionsChangedListener = PackageManager.OnPermissionsChangedListener { uid ->
+ if (uid == app.uid) trySend(Unit)
+ }
+ userPackageManager.addOnPermissionsChangeListener(onPermissionsChangedListener)
+ trySend(Unit)
+
+ awaitClose {
+ userPackageManager.removeOnPermissionsChangeListener(onPermissionsChangedListener)
+ }
+}.conflate().flowOn(Dispatchers.Default)
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/PermissionsChangedFlowTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/PermissionsChangedFlowTest.kt
new file mode 100644
index 000000000000..31522c1209f7
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/PermissionsChangedFlowTest.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2024 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.settingslib.spaprivileged.model.app
+
+import android.content.Context
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
+import com.android.settingslib.spa.testutils.toListWithTimeout
+import com.android.settingslib.spaprivileged.framework.common.asUser
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.async
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.runBlocking
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.doAnswer
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+
+@RunWith(AndroidJUnit4::class)
+class PermissionsChangedFlowTest {
+
+ private var onPermissionsChangedListener: PackageManager.OnPermissionsChangedListener? = null
+
+ private val mockPackageManager = mock<PackageManager> {
+ on { addOnPermissionsChangeListener(any()) } doAnswer {
+ onPermissionsChangedListener =
+ it.arguments[0] as PackageManager.OnPermissionsChangedListener
+ }
+ }
+
+ private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
+ on { asUser(APP.userHandle) } doReturn mock
+ on { packageManager } doReturn mockPackageManager
+ }
+
+ @Test
+ fun permissionsChangedFlow_sendInitialValueTrue() = runBlocking {
+ val flow = context.permissionsChangedFlow(APP)
+
+ assertThat(flow.firstWithTimeoutOrNull()).isNotNull()
+ }
+
+ @Test
+ fun permissionsChangedFlow_collectChanged_getTwo() = runBlocking {
+ val listDeferred = async {
+ context.permissionsChangedFlow(APP).toListWithTimeout()
+ }
+ delay(100)
+
+ onPermissionsChangedListener?.onPermissionsChanged(APP.uid)
+
+ assertThat(listDeferred.await()).hasSize(2)
+ }
+
+ private companion object {
+ val APP = ApplicationInfo().apply {
+ packageName = "package.name"
+ uid = 10000
+ }
+ }
+}