Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 516503df authored by Chaohui Wang's avatar Chaohui Wang Committed by Automerger Merge Worker
Browse files

Merge "Fix crash of PictureInPicture" into udc-dev am: 5b042e2f am: a9a22966

parents 810659f8 a9a22966
Loading
Loading
Loading
Loading
+39 −20
Original line number Original line Diff line number Diff line
@@ -23,6 +23,7 @@ import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo
import android.content.pm.PackageInfo
import android.content.pm.PackageManager.GET_ACTIVITIES
import android.content.pm.PackageManager.GET_ACTIVITIES
import android.content.pm.PackageManager.PackageInfoFlags
import android.content.pm.PackageManager.PackageInfoFlags
import android.util.Log
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Composable
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.livedata.observeAsState
import com.android.settings.R
import com.android.settings.R
@@ -56,9 +57,8 @@ class PictureInPictureListModel(private val context: Context) :
    private val packageManager = context.packageManager
    private val packageManager = context.packageManager


    override fun transform(userIdFlow: Flow<Int>, appListFlow: Flow<List<ApplicationInfo>>) =
    override fun transform(userIdFlow: Flow<Int>, appListFlow: Flow<List<ApplicationInfo>>) =
        userIdFlow.map(::getPictureInPicturePackages).combine(appListFlow) {
        userIdFlow.map(::getPictureInPicturePackages)
            pictureInPicturePackages,
            .combine(appListFlow) { pictureInPicturePackages, appList ->
            appList ->
                appList.map { app ->
                appList.map { app ->
                    createPictureInPictureRecord(
                    createPictureInPictureRecord(
                        app = app,
                        app = app,
@@ -67,15 +67,11 @@ class PictureInPictureListModel(private val context: Context) :
                }
                }
            }
            }


    override fun transformItem(app: ApplicationInfo): PictureInPictureRecord {
    override fun transformItem(app: ApplicationInfo) = createPictureInPictureRecord(
        return createPictureInPictureRecord(
        app = app,
        app = app,
        isSupport = app.installed &&
        isSupport = app.installed &&
                packageManager
            getPackageAndActivityInfo(app)?.supportsPictureInPicture() == true,
                    .getPackageInfoAsUser(app.packageName, GET_ACTIVITIES_FLAGS, app.userId)
                    .supportsPictureInPicture(),
    )
    )
    }


    private fun createPictureInPictureRecord(app: ApplicationInfo, isSupport: Boolean) =
    private fun createPictureInPictureRecord(app: ApplicationInfo, isSupport: Boolean) =
        PictureInPictureRecord(
        PictureInPictureRecord(
@@ -103,13 +99,36 @@ class PictureInPictureListModel(private val context: Context) :
    }
    }


    private fun getPictureInPicturePackages(userId: Int): Set<String> =
    private fun getPictureInPicturePackages(userId: Int): Set<String> =
        packageManager
        getPackageAndActivityInfoList(userId)
            .getInstalledPackagesAsUser(GET_ACTIVITIES_FLAGS, userId)
            .filter { it.supportsPictureInPicture() }
            .filter { it.supportsPictureInPicture() }
            .map { it.packageName }
            .map { it.packageName }
            .toSet()
            .toSet()


    private fun getPackageAndActivityInfo(app: ApplicationInfo): PackageInfo? = try {
        packageManager.getPackageInfoAsUser(app.packageName, GET_ACTIVITIES_FLAGS, app.userId)
    } catch (e: Exception) {
        // Query PackageManager.getPackageInfoAsUser() with GET_ACTIVITIES_FLAGS could cause
        // exception sometimes. Since we reply on this flag to retrieve the Picture In Picture
        // packages, we need to catch the exception to alleviate the impact before PackageManager
        // fixing this issue or provide a better api.
        Log.e(TAG, "Exception while getPackageInfoAsUser", e)
        null
    }

    private fun getPackageAndActivityInfoList(userId: Int): List<PackageInfo> = try {
        packageManager.getInstalledPackagesAsUser(GET_ACTIVITIES_FLAGS, userId)
    } catch (e: Exception) {
        // Query PackageManager.getPackageInfoAsUser() with GET_ACTIVITIES_FLAGS could cause
        // exception sometimes. Since we reply on this flag to retrieve the Picture In Picture
        // packages, we need to catch the exception to alleviate the impact before PackageManager
        // fixing this issue or provide a better api.
        Log.e(TAG, "Exception while getInstalledPackagesAsUser", e)
        emptyList()
    }

    companion object {
    companion object {
        private const val TAG = "PictureInPictureListModel"

        private fun PackageInfo.supportsPictureInPicture() =
        private fun PackageInfo.supportsPictureInPicture() =
            activities?.any(ActivityInfo::supportsPictureInPicture) ?: false
            activities?.any(ActivityInfo::supportsPictureInPicture) ?: false


+32 −0
Original line number Original line Diff line number Diff line
@@ -23,6 +23,7 @@ import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.PackageManager
import android.content.pm.PackageManager.PackageInfoFlags
import android.content.pm.PackageManager.PackageInfoFlags
import android.os.DeadSystemRuntimeException
import androidx.test.core.app.ApplicationProvider
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R
import com.android.settings.R
@@ -100,6 +101,23 @@ class PictureInPictureTest {
        assertThat(record.isSupport).isTrue()
        assertThat(record.isSupport).isTrue()
    }
    }


    @Test
    fun transform_getInstalledPackagesAsUserThrowsException_treatAsNotSupported() = runTest {
        whenever(packageManager.getInstalledPackagesAsUser(any<PackageInfoFlags>(), anyInt()))
            .thenThrow(DeadSystemRuntimeException())

        val recordListFlow = listModel.transform(
            userIdFlow = flowOf(USER_ID),
            appListFlow = flowOf(listOf(PICTURE_IN_PICTURE_APP)),
        )

        val recordList = recordListFlow.first()
        assertThat(recordList).hasSize(1)
        val record = recordList[0]
        assertThat(record.app).isSameInstanceAs(PICTURE_IN_PICTURE_APP)
        assertThat(record.isSupport).isFalse()
    }

    @Test
    @Test
    fun transformItem() {
    fun transformItem() {
        whenever(
        whenever(
@@ -114,6 +132,20 @@ class PictureInPictureTest {
        assertThat(record.isSupport).isTrue()
        assertThat(record.isSupport).isTrue()
    }
    }


    @Test
    fun transformItem_getPackageInfoAsUserThrowsException_treatAsNotSupported() {
        whenever(
            packageManager.getPackageInfoAsUser(
                eq(PICTURE_IN_PICTURE_PACKAGE_NAME), any<PackageInfoFlags>(), eq(USER_ID)
            )
        ).thenThrow(DeadSystemRuntimeException())

        val record = listModel.transformItem(PICTURE_IN_PICTURE_APP)

        assertThat(record.app).isSameInstanceAs(PICTURE_IN_PICTURE_APP)
        assertThat(record.isSupport).isFalse()
    }

    @Test
    @Test
    fun filter_isSupport() = runTest {
    fun filter_isSupport() = runTest {
        val record = createRecord(isSupport = true)
        val record = createRecord(isSupport = true)