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

Commit bd56c6d7 authored by Govinda Wasserman's avatar Govinda Wasserman Committed by Android (Google) Code Review
Browse files

Merge "Updates common repositories to match the rest of the framework" into main

parents 49129bcd 6b04dc93
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