Skip to content
Snippets Groups Projects
Commit f7bfbc34 authored by Chaohui Wang's avatar Chaohui Wang
Browse files

New PermissionsChangedFlow

Also also clean up LiveDataTestUtil.

Bug: 321163306
Test: unit test
Change-Id: Id2d77f53569619654036e782285cab8931fd5bfc
parent 4846e39b
No related branches found
No related tags found
No related merge requests found
/*
* Copyright (C) 2022 The Android Open Source Project
* 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.
......@@ -14,37 +14,33 @@
* limitations under the License.
*/
package com.android.settingslib.spa.testutils
package com.android.settingslib.spaprivileged.model.app
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
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
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()
/**
* 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
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)
val onPermissionsChangedListener = PackageManager.OnPermissionsChangedListener { uid ->
if (uid == app.uid) trySend(Unit)
}
userPackageManager.addOnPermissionsChangeListener(onPermissionsChangedListener)
trySend(Unit)
return data
}
awaitClose {
userPackageManager.removeOnPermissionsChangeListener(onPermissionsChangedListener)
}
}.conflate().flowOn(Dispatchers.Default)
/*
* 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
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment