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

Commit 6b04dc93 authored by Govinda Wasserman's avatar Govinda Wasserman
Browse files

Updates common repositories to match the rest of the framework

Test: atest SystemUITests:com.android.systemui.screencapture.common.data.repository
BUG: 398934067
Flag: com.android.systemui.large_screen_sharing
Change-Id: I1eb1953493447093a7c611928631f5ac26da313b
parent aed1a7f1
Loading
Loading
Loading
Loading
+5 −110
Original line number Diff line number Diff line
@@ -33,12 +33,9 @@ import com.android.launcher3.icons.FastBitmapDrawable
import com.android.launcher3.icons.IconFactory
import com.android.launcher3.util.UserIconInfo
import com.android.systemui.SysuiTestCase
import com.android.systemui.kosmos.backgroundScope
import com.android.systemui.kosmos.currentValue
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.testKosmosNew
import com.android.systemui.unfold.util.fakeDeviceStateManager
import com.google.common.truth.Truth.assertThat
import javax.inject.Provider
import org.junit.Test
@@ -96,7 +93,6 @@ class ScreenCaptureIconRepositoryImplTest : SysuiTestCase() {
            // Arrange
            val iconRepository =
                ScreenCaptureIconRepositoryImpl(
                    scope = backgroundScope,
                    bgContext = testDispatcher,
                    context = testableContext,
                    userManager = userManager,
@@ -117,7 +113,8 @@ class ScreenCaptureIconRepositoryImplTest : SysuiTestCase() {
                .getActivityInfo(eq(ComponentName("TestPackage", "TestClass")), eq(123))
            verify(mockIconFactory).createBadgedIconBitmap(same(fakeDrawable), any())
            verify(mockIconFactory).close()
            assertThat(result?.sameAs(fakeBadgedBitmap)).isTrue()
            assertThat(result.isSuccess).isTrue()
            assertThat(result.getOrNull()?.sameAs(fakeBadgedBitmap)).isTrue()
        }

    @Test
@@ -126,7 +123,6 @@ class ScreenCaptureIconRepositoryImplTest : SysuiTestCase() {
            // Arrange
            val iconRepository =
                ScreenCaptureIconRepositoryImpl(
                    scope = backgroundScope,
                    bgContext = testDispatcher,
                    context = testableContext,
                    userManager = userManager,
@@ -147,7 +143,8 @@ class ScreenCaptureIconRepositoryImplTest : SysuiTestCase() {
            verify(packageManagerWrapper)
                .getActivityInfo(eq(ComponentName("TestPackage", "TestClass")), eq(123))
            verifyNoInteractions(mockIconFactory)
            assertThat(result?.sameAs(fakeUnbadgedBitmap)).isTrue()
            assertThat(result.isSuccess).isTrue()
            assertThat(result.getOrNull()?.sameAs(fakeUnbadgedBitmap)).isTrue()
        }

    @Test
@@ -157,7 +154,6 @@ class ScreenCaptureIconRepositoryImplTest : SysuiTestCase() {
            packageManagerWrapper.stub { on { getActivityInfo(any(), any()) } doReturn null }
            val iconRepository =
                ScreenCaptureIconRepositoryImpl(
                    scope = backgroundScope,
                    bgContext = testDispatcher,
                    context = testableContext,
                    userManager = userManager,
@@ -177,104 +173,7 @@ class ScreenCaptureIconRepositoryImplTest : SysuiTestCase() {
            verify(packageManagerWrapper)
                .getActivityInfo(eq(ComponentName("TestPackage", "TestClass")), eq(123))
            verifyNoInteractions(mockIconFactory)
            assertThat(result).isNull()
        }

    @Test
    fun iconFor_flowEmitsBadgedIcon() =
        kosmos.runTest {
            // Arrange
            val iconRepository =
                ScreenCaptureIconRepositoryImpl(
                    scope = backgroundScope,
                    bgContext = testDispatcher,
                    context = testableContext,
                    userManager = userManager,
                    packageManagerWrapper = packageManagerWrapper,
                    packageManager = packageManager,
                    iconFactoryProvider = testIconFactoryProvider,
                )

            // Act
            val flow =
                iconRepository.iconFor(
                    component = ComponentName("TestPackage", "TestClass"),
                    userId = 123,
                )
            val result = currentValue(flow)

            // Assert
            verify(packageManagerWrapper)
                .getActivityInfo(eq(ComponentName("TestPackage", "TestClass")), eq(123))
            verify(mockIconFactory).createBadgedIconBitmap(same(fakeDrawable), any())
            verify(mockIconFactory).close()
            assertThat(result?.isSuccess).isTrue()
            assertThat(result?.getOrNull()?.sameAs(fakeBadgedBitmap)).isTrue()
        }

    @Test
    fun iconFor_unbadged_flowEmitsUnbadgedIcon() =
        kosmos.runTest {
            // Arrange
            val iconRepository =
                ScreenCaptureIconRepositoryImpl(
                    scope = backgroundScope,
                    bgContext = testDispatcher,
                    context = testableContext,
                    userManager = userManager,
                    packageManagerWrapper = packageManagerWrapper,
                    packageManager = packageManager,
                    iconFactoryProvider = testIconFactoryProvider,
                )

            // Act
            val flow =
                iconRepository.iconFor(
                    component = ComponentName("TestPackage", "TestClass"),
                    userId = 123,
                    badged = false,
                )
            val result = currentValue(flow)

            // Assert
            verify(packageManagerWrapper)
                .getActivityInfo(eq(ComponentName("TestPackage", "TestClass")), eq(123))
            verifyNoInteractions(mockIconFactory)
            assertThat(result?.isSuccess).isTrue()
            assertThat(result?.getOrNull()?.sameAs(fakeUnbadgedBitmap)).isTrue()
        }

    @Test
    fun iconFor_couldNotFindActivity_flowEmitsFailure() =
        kosmos.runTest {
            // Arrange
            packageManagerWrapper.stub { on { getActivityInfo(any(), any()) } doReturn null }
            val iconRepository =
                ScreenCaptureIconRepositoryImpl(
                    scope = backgroundScope,
                    bgContext = testDispatcher,
                    context = testableContext,
                    userManager = userManager,
                    packageManagerWrapper = packageManagerWrapper,
                    packageManager = packageManager,
                    iconFactoryProvider = testIconFactoryProvider,
                )

            this.fakeDeviceStateManager

            // Act
            val flow =
                iconRepository.iconFor(
                    component = ComponentName("TestPackage", "TestClass"),
                    userId = 123,
                )
            val result = currentValue(flow)

            // Assert
            verify(packageManagerWrapper)
                .getActivityInfo(eq(ComponentName("TestPackage", "TestClass")), eq(123))
            verifyNoInteractions(mockIconFactory)
            assertThat(result?.isFailure).isTrue()
            assertThat(result.isFailure).isTrue()
        }

    @Test
@@ -293,7 +192,6 @@ class ScreenCaptureIconRepositoryImplTest : SysuiTestCase() {
            }
            val iconRepository =
                ScreenCaptureIconRepositoryImpl(
                    scope = backgroundScope,
                    bgContext = testDispatcher,
                    context = testableContext,
                    userManager = userManager,
@@ -325,7 +223,6 @@ class ScreenCaptureIconRepositoryImplTest : SysuiTestCase() {
            }
            val iconRepository =
                ScreenCaptureIconRepositoryImpl(
                    scope = backgroundScope,
                    bgContext = testDispatcher,
                    context = testableContext,
                    userManager = userManager,
@@ -357,7 +254,6 @@ class ScreenCaptureIconRepositoryImplTest : SysuiTestCase() {
            }
            val iconRepository =
                ScreenCaptureIconRepositoryImpl(
                    scope = backgroundScope,
                    bgContext = testDispatcher,
                    context = testableContext,
                    userManager = userManager,
@@ -389,7 +285,6 @@ class ScreenCaptureIconRepositoryImplTest : SysuiTestCase() {
            }
            val iconRepository =
                ScreenCaptureIconRepositoryImpl(
                    scope = backgroundScope,
                    bgContext = testDispatcher,
                    context = testableContext,
                    userManager = userManager,
+5 −103
Original line number Diff line number Diff line
@@ -24,8 +24,6 @@ import android.os.UserHandle
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.kosmos.backgroundScope
import com.android.systemui.kosmos.currentValue
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.testKosmosNew
@@ -66,7 +64,6 @@ class ScreenCaptureLabelRepositoryImplTest : SysuiTestCase() {
            // Arrange
            val labelRepository =
                ScreenCaptureLabelRepositoryImpl(
                    scope = backgroundScope,
                    bgContext = testDispatcher,
                    packageManager = packageManager,
                )
@@ -86,7 +83,8 @@ class ScreenCaptureLabelRepositoryImplTest : SysuiTestCase() {
                    eq(123),
                )
            verify(packageManager).getUserBadgedLabel(any(), eq(UserHandle(123)))
            assertThat(result).isEqualTo("TestBadgedLabel")
            assertThat(result.isSuccess).isTrue()
            assertThat(result.getOrNull()).isEqualTo("TestBadgedLabel")
        }

    @Test
@@ -95,7 +93,6 @@ class ScreenCaptureLabelRepositoryImplTest : SysuiTestCase() {
            // Arrange
            val labelRepository =
                ScreenCaptureLabelRepositoryImpl(
                    scope = backgroundScope,
                    bgContext = testDispatcher,
                    packageManager = packageManager,
                )
@@ -116,7 +113,8 @@ class ScreenCaptureLabelRepositoryImplTest : SysuiTestCase() {
                    eq(123),
                )
            verify(packageManager, never()).getUserBadgedLabel(any(), any())
            assertThat(result).isEqualTo("TestUnbadgedLabel")
            assertThat(result.isSuccess).isTrue()
            assertThat(result.getOrNull()).isEqualTo("TestUnbadgedLabel")
        }

    @Test
@@ -125,7 +123,6 @@ class ScreenCaptureLabelRepositoryImplTest : SysuiTestCase() {
            // Arrange
            val labelRepository =
                ScreenCaptureLabelRepositoryImpl(
                    scope = backgroundScope,
                    bgContext = testDispatcher,
                    packageManager =
                        packageManager.stub {
@@ -147,101 +144,6 @@ class ScreenCaptureLabelRepositoryImplTest : SysuiTestCase() {
                )

            // Assert
            assertThat(result).isNull()
        }

    @Test
    fun LabelFor_flowEmitsBadgedLabel() =
        kosmos.runTest {
            // Arrange
            val labelRepository =
                ScreenCaptureLabelRepositoryImpl(
                    scope = backgroundScope,
                    bgContext = testDispatcher,
                    packageManager = packageManager,
                )

            // Act
            val flow =
                labelRepository.labelFor(
                    component = ComponentName("TestPackage", "TestClass"),
                    userId = 123,
                )
            val result = currentValue(flow)

            // Assert
            verify(packageManager)
                .getApplicationInfoAsUser(
                    eq("TestPackage"),
                    argThat<PackageManager.ApplicationInfoFlags> { value == 0L },
                    eq(123),
                )
            verify(packageManager).getUserBadgedLabel(any(), eq(UserHandle(123)))
            assertThat(result?.isSuccess).isTrue()
            assertThat(result?.getOrNull()).isEqualTo("TestBadgedLabel")
        }

    @Test
    fun LabelFor_unbadged_flowEmitsUnbadgedLabel() =
        kosmos.runTest {
            // Arrange
            val labelRepository =
                ScreenCaptureLabelRepositoryImpl(
                    scope = backgroundScope,
                    bgContext = testDispatcher,
                    packageManager = packageManager,
                )

            // Act
            val flow =
                labelRepository.labelFor(
                    component = ComponentName("TestPackage", "TestClass"),
                    userId = 123,
                    badged = false,
                )
            val result = currentValue(flow)

            // Assert
            verify(packageManager)
                .getApplicationInfoAsUser(
                    eq("TestPackage"),
                    argThat<PackageManager.ApplicationInfoFlags> { value == 0L },
                    eq(123),
                )
            verify(packageManager, never()).getUserBadgedLabel(any(), any())
            assertThat(result?.isSuccess).isTrue()
            assertThat(result?.getOrNull()).isEqualTo("TestUnbadgedLabel")
        }

    @Test
    fun LabelFor_appNotFound_flowEmitsFailure() =
        kosmos.runTest {
            // Arrange
            val labelRepository =
                ScreenCaptureLabelRepositoryImpl(
                    scope = backgroundScope,
                    bgContext = testDispatcher,
                    packageManager =
                        packageManager.stub {
                            on {
                                getApplicationInfoAsUser(
                                    any<String>(),
                                    any<PackageManager.ApplicationInfoFlags>(),
                                    any<Int>(),
                                )
                            } doThrow PackageManager.NameNotFoundException()
                        },
                )

            // Act
            val flow =
                labelRepository.labelFor(
                    component = ComponentName("TestPackage", "TestClass"),
                    userId = 123,
                )
            val result = currentValue(flow)

            // Assert
            assertThat(result?.isFailure).isTrue()
            assertThat(result.isFailure).isTrue()
        }
}
+3 −54
Original line number Diff line number Diff line
@@ -20,8 +20,6 @@ import androidx.core.graphics.createBitmap
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.kosmos.backgroundScope
import com.android.systemui.kosmos.currentValue
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.shared.recents.model.ThumbnailData
@@ -50,7 +48,6 @@ class ScreenCaptureThumbnailRepositoryImplTest : SysuiTestCase() {
            // Arrange
            val thumbnailRepository =
                ScreenCaptureThumbnailRepositoryImpl(
                    scope = backgroundScope,
                    bgContext = testDispatcher,
                    activityManager =
                        activityManagerWrapper.stub {
@@ -64,7 +61,8 @@ class ScreenCaptureThumbnailRepositoryImplTest : SysuiTestCase() {

            // Assert
            verify(activityManagerWrapper).takeTaskThumbnail(eq(123))
            assertThat(result?.sameAs(fakeThumbnail)).isTrue()
            assertThat(result.isSuccess).isTrue()
            assertThat(result.getOrNull()?.sameAs(fakeThumbnail)).isTrue()
        }

    @Test
@@ -73,7 +71,6 @@ class ScreenCaptureThumbnailRepositoryImplTest : SysuiTestCase() {
            // Arrange
            val thumbnailRepository =
                ScreenCaptureThumbnailRepositoryImpl(
                    scope = backgroundScope,
                    bgContext = testDispatcher,
                    activityManager =
                        activityManagerWrapper.stub {
@@ -86,54 +83,6 @@ class ScreenCaptureThumbnailRepositoryImplTest : SysuiTestCase() {

            // Assert
            verify(activityManagerWrapper).takeTaskThumbnail(eq(123))
            assertThat(result).isNull()
        }

    @Test
    fun thumbnailFor_flowEmitsNewThumbnail() =
        kosmos.runTest {
            // Arrange
            val thumbnailRepository =
                ScreenCaptureThumbnailRepositoryImpl(
                    scope = backgroundScope,
                    bgContext = testDispatcher,
                    activityManager =
                        activityManagerWrapper.stub {
                            on { takeTaskThumbnail(any()) } doReturn
                                ThumbnailData(thumbnail = fakeThumbnail)
                        },
                )

            // Act
            val flow = thumbnailRepository.thumbnailFor(123)
            val result = currentValue(flow)

            // Assert
            verify(activityManagerWrapper).takeTaskThumbnail(eq(123))
            assertThat(result?.isSuccess).isTrue()
            assertThat(result?.getOrNull()?.sameAs(fakeThumbnail)).isTrue()
        }

    @Test
    fun thumbnailFor_failsToTakeThumbnail_flowEmitsFailure() =
        kosmos.runTest {
            // Arrange
            val thumbnailRepository =
                ScreenCaptureThumbnailRepositoryImpl(
                    scope = backgroundScope,
                    bgContext = testDispatcher,
                    activityManager =
                        activityManagerWrapper.stub {
                            on { takeTaskThumbnail(any()) } doReturn ThumbnailData(thumbnail = null)
                        },
                )

            // Act
            val flow = thumbnailRepository.thumbnailFor(123)
            val result = currentValue(flow)

            // Assert
            verify(activityManagerWrapper).takeTaskThumbnail(eq(123))
            assertThat(result?.isFailure).isTrue()
            assertThat(result.isFailure).isTrue()
        }
}
+17 −43
Original line number Diff line number Diff line
@@ -32,41 +32,29 @@ import com.android.launcher3.icons.IconFactory
import com.android.launcher3.util.UserIconInfo
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.screencapture.common.ScreenCapture
import com.android.systemui.screencapture.common.ScreenCaptureScope
import com.android.systemui.shared.system.PackageManagerWrapper
import javax.inject.Inject
import javax.inject.Provider
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext

/** Repository for app icons. */
interface ScreenCaptureIconRepository {

    /** Returns a flow that fetches an app icon. */
    fun iconFor(
        component: ComponentName,
        @UserIdInt userId: Int,
        badged: Boolean = true,
    ): StateFlow<Result<Bitmap>?>

    /** Fetch app icon on background dispatcher. */
    suspend fun loadIcon(
        component: ComponentName,
        @UserIdInt userId: Int,
        badged: Boolean = true,
    ): Bitmap?
    ): Result<Bitmap>
}

/** Default implementation of [ScreenCaptureIconRepository]. */
@ScreenCaptureScope
class ScreenCaptureIconRepositoryImpl
@Inject
constructor(
    @ScreenCapture private val scope: CoroutineScope,
    @Background private val bgContext: CoroutineContext,
    private val context: Context,
    private val userManager: UserManager,
@@ -75,44 +63,30 @@ constructor(
    @ScreenCapture private val iconFactoryProvider: Provider<IconFactory>,
) : ScreenCaptureIconRepository {

    override fun iconFor(
        component: ComponentName,
        userId: Int,
        badged: Boolean,
    ): StateFlow<Result<Bitmap>?> =
        flow {
                val icon = loadIcon(component, userId, badged)
                if (icon == null) {
                    emit(
                        Result.failure(
                            Exception(
                                "Could not find icon for ${component.flattenToString()}, user $userId"
                            )
                        )
                    )
                } else {
                    emit(Result.success(icon))
                }
            }
            .stateIn(scope, SharingStarted.Eagerly, null)

    override suspend fun loadIcon(
        component: ComponentName,
        @UserIdInt userId: Int,
        badged: Boolean,
    ): Bitmap? =
    ): Result<Bitmap> =
        withContext(bgContext) {
            packageManagerWrapper
                .getActivityInfo(component, userId)
                ?.loadIcon(packageManager)
                ?.let {
                    Result.success(
                        if (badged) {
                                badgeIcon(it, userId)
                            } else {
                                it
                            }
                            .toBitmap()
                    )
                }
                ?: Result.failure(
                    IllegalStateException(
                        "Could not find icon for ${component.flattenToString()}, user $userId"
                    )
                )
        }

    private suspend fun badgeIcon(icon: Drawable, @UserIdInt userId: Int): Drawable {
+12 −44
Original line number Diff line number Diff line
@@ -22,69 +22,35 @@ import android.content.pm.PackageManager
import android.os.UserHandle
import android.util.Log
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.screencapture.common.ScreenCapture
import com.android.systemui.screencapture.common.ScreenCaptureScope
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext

/** Repository for fetching app labels */
interface ScreenCaptureLabelRepository {

    /** Returns a flow that fetches an app label. */
    fun labelFor(
        component: ComponentName,
        @UserIdInt userId: Int,
        badged: Boolean = true,
    ): StateFlow<Result<CharSequence>?>

    /** Fetch app label on background dispatcher. */
    suspend fun loadLabel(
        component: ComponentName,
        @UserIdInt userId: Int,
        badged: Boolean = true,
    ): CharSequence?
    ): Result<CharSequence>
}

/** Default implementation of [ScreenCaptureLabelRepository]. */
@ScreenCaptureScope
class ScreenCaptureLabelRepositoryImpl
@Inject
constructor(
    @ScreenCapture private val scope: CoroutineScope,
    @Background private val bgContext: CoroutineContext,
    private val packageManager: PackageManager,
) : ScreenCaptureLabelRepository {

    override fun labelFor(
        component: ComponentName,
        userId: Int,
        badged: Boolean,
    ): StateFlow<Result<CharSequence>?> =
        flow {
                val label = loadLabel(component, userId, badged)
                if (label == null) {
                    emit(
                        Result.failure(
                            Exception(
                                "Could not find label for ${component.flattenToString()}, user $userId"
                            )
                        )
                    )
                } else {
                    emit(Result.success(label))
                }
            }
            .stateIn(scope, SharingStarted.Eagerly, null)

    override suspend fun loadLabel(
        component: ComponentName,
        @UserIdInt userId: Int,
        badged: Boolean,
    ): CharSequence? =
    ): Result<CharSequence> =
        withContext(bgContext) {
            try {
                val label =
@@ -95,14 +61,16 @@ constructor(
                            userId,
                        )
                        .let { appInfo -> packageManager.getApplicationLabel(appInfo) }
                Result.success(
                    if (badged) {
                        packageManager.getUserBadgedLabel(label, UserHandle(userId))
                    } else {
                        label
                    }
                )
            } catch (e: PackageManager.NameNotFoundException) {
                Log.e(TAG, "Unable to get application info", e)
                null
                Result.failure(e)
            }
        }
}
Loading