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

Commit 78826d1e authored by Nick Chameyev's avatar Nick Chameyev Committed by Android (Google) Code Review
Browse files

Merge "[Partial screensharing] Fix crash when having a recents app available...

Merge "[Partial screensharing] Fix crash when having a recents app available only in work profile" into tm-qpr-dev
parents 2fea6cf0 df18b672
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.systemui.mediaprojection.appselector
import android.app.Activity
import android.content.ComponentName
import android.content.Context
import com.android.launcher3.icons.IconFactory
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.media.MediaProjectionAppSelectorActivity
import com.android.systemui.mediaprojection.appselector.data.ActivityTaskManagerThumbnailLoader
@@ -91,6 +92,11 @@ interface MediaProjectionAppSelectorModule {
            activity: MediaProjectionAppSelectorActivity
        ): ConfigurationController = ConfigurationControllerImpl(activity)

        @Provides
        fun bindIconFactory(
            context: Context
        ): IconFactory = IconFactory.obtain(context)

        @Provides
        @MediaProjectionAppSelector
        @MediaProjectionAppSelectorScope
+10 −5
Original line number Diff line number Diff line
@@ -19,13 +19,14 @@ package com.android.systemui.mediaprojection.appselector.data
import android.content.ComponentName
import android.content.Context
import android.content.pm.PackageManager
import android.content.pm.PackageManager.ComponentInfoFlags
import android.graphics.drawable.Drawable
import android.os.UserHandle
import com.android.launcher3.icons.BaseIconFactory.IconOptions
import com.android.launcher3.icons.IconFactory
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.shared.system.PackageManagerWrapper
import javax.inject.Inject
import javax.inject.Provider
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext

@@ -38,14 +39,18 @@ class IconLoaderLibAppIconLoader
constructor(
    @Background private val backgroundDispatcher: CoroutineDispatcher,
    private val context: Context,
    private val packageManager: PackageManager
    // Use wrapper to access hidden API that allows to get ActivityInfo for any user id
    private val packageManagerWrapper: PackageManagerWrapper,
    private val packageManager: PackageManager,
    private val iconFactoryProvider: Provider<IconFactory>
) : AppIconLoader {

    override suspend fun loadIcon(userId: Int, component: ComponentName): Drawable? =
        withContext(backgroundDispatcher) {
            IconFactory.obtain(context).use<IconFactory, Drawable?> { iconFactory ->
                val activityInfo = packageManager
                        .getActivityInfo(component, ComponentInfoFlags.of(0))
            iconFactoryProvider.get().use<IconFactory, Drawable?> { iconFactory ->
                val activityInfo =
                    packageManagerWrapper.getActivityInfo(component, userId)
                        ?: return@withContext null
                val icon = activityInfo.loadIcon(packageManager) ?: return@withContext null
                val userHandler = UserHandle.of(userId)
                val options = IconOptions().apply { setUser(userHandler) }
+83 −0
Original line number Diff line number Diff line
/*
 * 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.mediaprojection.appselector.data

import android.content.ComponentName
import android.content.pm.ActivityInfo
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import androidx.test.filters.SmallTest
import com.android.launcher3.icons.BitmapInfo
import com.android.launcher3.icons.FastBitmapDrawable
import com.android.launcher3.icons.IconFactory
import com.android.systemui.SysuiTestCase
import com.android.systemui.shared.system.PackageManagerWrapper
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4

@SmallTest
@RunWith(JUnit4::class)
class IconLoaderLibAppIconLoaderTest : SysuiTestCase() {

    private val iconFactory: IconFactory = mock()
    private val packageManagerWrapper: PackageManagerWrapper = mock()
    private val packageManager: PackageManager = mock()
    private val dispatcher = Dispatchers.Unconfined

    private val appIconLoader =
        IconLoaderLibAppIconLoader(
            backgroundDispatcher = dispatcher,
            context = context,
            packageManagerWrapper = packageManagerWrapper,
            packageManager = packageManager,
            iconFactoryProvider = { iconFactory }
        )

    @Test
    fun loadIcon_loadsIconUsingTheSameUserId() {
        val icon = createIcon()
        val component = ComponentName("com.test", "TestApplication")
        givenIcon(component, userId = 123, icon = icon)

        val loadedIcon = runBlocking { appIconLoader.loadIcon(userId = 123, component = component) }

        assertThat(loadedIcon).isEqualTo(icon)
    }

    private fun givenIcon(component: ComponentName, userId: Int, icon: FastBitmapDrawable) {
        val activityInfo = mock<ActivityInfo>()
        whenever(packageManagerWrapper.getActivityInfo(component, userId)).thenReturn(activityInfo)
        val rawIcon = mock<Drawable>()
        whenever(activityInfo.loadIcon(packageManager)).thenReturn(rawIcon)

        val bitmapInfo = mock<BitmapInfo>()
        whenever(iconFactory.createBadgedIconBitmap(eq(rawIcon), any())).thenReturn(bitmapInfo)
        whenever(bitmapInfo.newIcon(context)).thenReturn(icon)
    }

    private fun createIcon(): FastBitmapDrawable =
        FastBitmapDrawable(Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888))
}