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

Commit f7209d15 authored by Matt Casey's avatar Matt Casey
Browse files

Move package manager lookup to background thread.

Bug: 391401141
Flag: com.android.systemui.shared.use_preferred_image_editor
Test: atest ActionIntentCreatorTest
Change-Id: I8aebfec5e4e19fcc25a32deff361f43b4427df15
parent a51d95a4
Loading
Loading
Loading
Loading
+14 −1
Original line number Diff line number Diff line
@@ -30,6 +30,9 @@ import com.android.systemui.shared.Flags
import com.google.common.truth.Truth.assertThat
import java.util.UUID
import kotlin.test.Test
import kotlinx.coroutines.test.TestCoroutineScheduler
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import org.junit.runner.RunWith
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.kotlin.any
@@ -43,10 +46,19 @@ import org.mockito.kotlin.verify

@RunWith(AndroidJUnit4::class)
class DefaultScreenshotActionsProviderTest : SysuiTestCase() {
    private val scheduler = TestCoroutineScheduler()
    private val mainDispatcher = UnconfinedTestDispatcher(scheduler)
    private val testScope = TestScope(mainDispatcher)
    private val actionExecutor = mock<ActionExecutor>()
    private val uiEventLogger = mock<UiEventLogger>()
    private val actionsCallback = mock<ScreenshotActionsController.ActionsCallback>()
    private val actionIntentCreator = ActionIntentCreator(context, context.packageManager)
    private val actionIntentCreator =
        ActionIntentCreator(
            context,
            context.packageManager,
            testScope.backgroundScope,
            mainDispatcher,
        )

    private val request = ScreenshotData.forTesting(userHandle = UserHandle.OWNER)
    private val validResult = ScreenshotSavedResult(Uri.EMPTY, Process.myUserHandle(), 0)
@@ -198,6 +210,7 @@ class DefaultScreenshotActionsProviderTest : SysuiTestCase() {
            context,
            uiEventLogger,
            actionIntentCreator,
            testScope,
            UUID.randomUUID(),
            request,
            actionExecutor,
+34 −8
Original line number Diff line number Diff line
@@ -23,18 +23,31 @@ import android.content.ContentProvider
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.PackageManager.NameNotFoundException
import android.net.Uri
import android.os.UserHandle
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.res.R
import com.android.systemui.screenshot.scroll.LongScreenshotActivity
import com.android.systemui.shared.Flags.usePreferredImageEditor
import java.util.function.Consumer
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

@SysUISingleton
class ActionIntentCreator
@Inject
constructor(private val context: Context, private val packageManager: PackageManager) {
constructor(
    private val context: Context,
    private val packageManager: PackageManager,
    @Application private val applicationScope: CoroutineScope,
    @Background private val backgroundDispatcher: CoroutineDispatcher,
) {
    /** @return a chooser intent to share the given URI. */
    fun createShare(uri: Uri): Intent = createShare(uri, subject = null, text = null)

@@ -76,11 +89,16 @@ constructor(private val context: Context, private val packageManager: PackageMan
            .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
    }

    // Non-suspend version for java compat
    fun createEdit(rawUri: Uri, consumer: Consumer<Intent>) {
        applicationScope.launch { consumer.accept(createEdit(rawUri)) }
    }

    /**
     * @return an ACTION_EDIT intent for the given URI, directed to config_preferredScreenshotEditor
     *   if enabled, falling back to config_screenshotEditor if that's non-empty.
     */
    fun createEdit(rawUri: Uri): Intent {
    suspend fun createEdit(rawUri: Uri): Intent {
        val uri = uriWithoutUserId(rawUri)
        val editIntent = Intent(Intent.ACTION_EDIT)

@@ -112,22 +130,30 @@ constructor(private val context: Context, private val packageManager: PackageMan
            .addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)
    }

    private fun preferredEditor(): ComponentName? =
    private suspend fun preferredEditor(): ComponentName? =
        runCatching {
                val preferredEditor = context.getString(R.string.config_preferredScreenshotEditor)
                val component = ComponentName.unflattenFromString(preferredEditor) ?: return null

                return if (isComponentAvailable(component)) component else null
            }
            .getOrNull()

    private suspend fun isComponentAvailable(component: ComponentName): Boolean =
        withContext(backgroundDispatcher) {
            try {
                val info =
                    packageManager.getPackageInfo(
                        component.packageName,
                        PackageManager.GET_ACTIVITIES,
                    )

                return info.activities
                    ?.firstOrNull { it.componentName.className.equals(component.className) }
                    ?.componentName
                info.activities?.firstOrNull {
                    it.componentName.className == component.className
                } != null
            } catch (e: NameNotFoundException) {
                false
            }
        }
            .getOrNull()

    private fun defaultEditor(): ComponentName? =
        runCatching {
+10 −5
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.net.Uri
import android.util.Log
import androidx.appcompat.content.res.AppCompatResources
import com.android.internal.logging.UiEventLogger
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.log.DebugLogger.debugLog
import com.android.systemui.res.R
import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_EDIT_TAPPED
@@ -34,6 +35,8 @@ import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import java.util.UUID
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch

/**
 * Provides actions for screenshots. This class can be overridden by a vendor-specific SysUI
@@ -68,6 +71,7 @@ constructor(
    private val context: Context,
    private val uiEventLogger: UiEventLogger,
    private val actionIntentCreator: ActionIntentCreator,
    @Application private val applicationScope: CoroutineScope,
    @Assisted val requestId: UUID,
    @Assisted val request: ScreenshotData,
    @Assisted val actionExecutor: ActionExecutor,
@@ -75,7 +79,7 @@ constructor(
) : ScreenshotActionsProvider {
    private var addedScrollChip = false
    private var onScrollClick: Runnable? = null
    private var pendingAction: ((ScreenshotSavedResult) -> Unit)? = null
    private var pendingAction: (suspend (ScreenshotSavedResult) -> Unit)? = null
    private var result: ScreenshotSavedResult? = null
    private var webUri: Uri? = null

@@ -166,15 +170,16 @@ constructor(
            return
        }
        this.result = result
        pendingAction?.invoke(result)
        pendingAction?.also { applicationScope.launch { it.invoke(result) } }
    }

    override fun onAssistContent(assistContent: AssistContent?) {
        webUri = assistContent?.webUri
    }

    private fun onDeferrableActionTapped(onResult: (ScreenshotSavedResult) -> Unit) {
        result?.let { onResult.invoke(it) } ?: run { pendingAction = onResult }
    private fun onDeferrableActionTapped(onResult: suspend (ScreenshotSavedResult) -> Unit) {
        result?.let { applicationScope.launch { onResult.invoke(it) } }
            ?: run { pendingAction = onResult }
    }

    @AssistedFactory
@@ -188,6 +193,6 @@ constructor(
    }

    companion object {
        private const val TAG = "ScreenshotActionsProvider"
        private const val TAG = "ScreenshotActionsPrvdr"
    }
}
+26 −21
Original line number Diff line number Diff line
@@ -352,13 +352,16 @@ public class LongScreenshotActivity extends Activity {
    private void doEdit(Uri uri) {
        if (mScreenshotUserHandle != Process.myUserHandle()) {
            // TODO: Fix transition for work profile. Omitting it in the meantime.
            mActionIntentCreator.createEdit(uri, intent -> {
                mActionExecutor.launchIntentAsync(
                    mActionIntentCreator.createEdit(uri),
                        intent,
                        mScreenshotUserHandle, false,
                        /* activityOptions */ null, /* transitionCoordinator */ null);
            });

        } else {
            if (usePreferredImageEditor()) {
                Intent intent = mActionIntentCreator.createEdit(uri);
                mActionIntentCreator.createEdit(uri, intent -> {
                    Bundle options = null;

                    if (intent.getComponent() != null) {
@@ -369,13 +372,15 @@ public class LongScreenshotActivity extends Activity {
                        mTransitionView.setVisibility(View.VISIBLE);
                        mTransitionView.setTransitionName(
                                ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME);
                    options = ActivityOptions.makeSceneTransitionAnimation(this, mTransitionView,
                        options = ActivityOptions.makeSceneTransitionAnimation(this,
                                mTransitionView,
                                ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME).toBundle();
                        // TODO: listen for transition completing instead of finishing onStop
                        mTransitionStarted = true;
                    }

                    startActivity(intent, options);
                });
            } else {
                String editorPackage = getString(R.string.config_screenshotEditor);
                Intent intent = new Intent(Intent.ACTION_EDIT);
+17 −9
Original line number Diff line number Diff line
@@ -35,6 +35,10 @@ import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import kotlinx.coroutines.test.TestCoroutineScheduler
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyInt
@@ -43,9 +47,13 @@ import org.mockito.Mockito.`when` as whenever
@SmallTest
@RunWith(AndroidJUnit4::class)
class ActionIntentCreatorTest : SysuiTestCase() {
    private val scheduler = TestCoroutineScheduler()
    private val mainDispatcher = UnconfinedTestDispatcher(scheduler)
    private val testScope = TestScope(mainDispatcher)
    val context = mock<Context>()
    val packageManager = mock<PackageManager>()
    private val actionIntentCreator = ActionIntentCreator(context, packageManager)
    private val actionIntentCreator =
        ActionIntentCreator(context, packageManager, testScope.backgroundScope, mainDispatcher)

    @Test
    fun testCreateShare() {
@@ -132,7 +140,7 @@ class ActionIntentCreatorTest : SysuiTestCase() {

    @Test
    @DisableFlags(Flags.FLAG_USE_PREFERRED_IMAGE_EDITOR)
    fun testCreateEditLegacy() {
    fun testCreateEditLegacy() = runTest {
        val uri = Uri.parse("content://fake")

        whenever(context.getString(eq(R.string.config_screenshotEditor))).thenReturn("")
@@ -155,7 +163,7 @@ class ActionIntentCreatorTest : SysuiTestCase() {

    @Test
    @DisableFlags(Flags.FLAG_USE_PREFERRED_IMAGE_EDITOR)
    fun testCreateEditLegacy_embeddedUserIdRemoved() {
    fun testCreateEditLegacy_embeddedUserIdRemoved() = runTest {
        val uri = Uri.parse("content://555@fake")
        whenever(context.getString(eq(R.string.config_screenshotEditor))).thenReturn("")

@@ -166,7 +174,7 @@ class ActionIntentCreatorTest : SysuiTestCase() {

    @Test
    @DisableFlags(Flags.FLAG_USE_PREFERRED_IMAGE_EDITOR)
    fun testCreateEditLegacy_withEditor() {
    fun testCreateEditLegacy_withEditor() = runTest {
        val uri = Uri.parse("content://fake")
        val component = ComponentName("com.android.foo", "com.android.foo.Something")

@@ -180,7 +188,7 @@ class ActionIntentCreatorTest : SysuiTestCase() {

    @Test
    @EnableFlags(Flags.FLAG_USE_PREFERRED_IMAGE_EDITOR)
    fun testCreateEdit() {
    fun testCreateEdit() = runTest {
        val uri = Uri.parse("content://fake")

        whenever(context.getString(eq(R.string.config_screenshotEditor))).thenReturn("")
@@ -203,7 +211,7 @@ class ActionIntentCreatorTest : SysuiTestCase() {

    @Test
    @EnableFlags(Flags.FLAG_USE_PREFERRED_IMAGE_EDITOR)
    fun testCreateEdit_embeddedUserIdRemoved() {
    fun testCreateEdit_embeddedUserIdRemoved() = runTest {
        val uri = Uri.parse("content://555@fake")
        whenever(context.getString(eq(R.string.config_screenshotEditor))).thenReturn("")

@@ -214,7 +222,7 @@ class ActionIntentCreatorTest : SysuiTestCase() {

    @Test
    @EnableFlags(Flags.FLAG_USE_PREFERRED_IMAGE_EDITOR)
    fun testCreateEdit_withPreferredEditorEnabled() {
    fun testCreateEdit_withPreferredEditorEnabled() = runTest {
        val uri = Uri.parse("content://fake")
        val fallbackComponent = ComponentName("com.android.foo", "com.android.foo.Something")
        val preferredComponent = ComponentName("com.android.bar", "com.android.bar.Something")
@@ -243,7 +251,7 @@ class ActionIntentCreatorTest : SysuiTestCase() {

    @Test
    @EnableFlags(Flags.FLAG_USE_PREFERRED_IMAGE_EDITOR)
    fun testCreateEdit_withPreferredEditorDisabled() {
    fun testCreateEdit_withPreferredEditorDisabled() = runTest {
        val uri = Uri.parse("content://fake")
        val fallbackComponent = ComponentName("com.android.foo", "com.android.foo.Something")
        val preferredComponent = ComponentName("com.android.bar", "com.android.bar.Something")
@@ -266,7 +274,7 @@ class ActionIntentCreatorTest : SysuiTestCase() {

    @Test
    @EnableFlags(Flags.FLAG_USE_PREFERRED_IMAGE_EDITOR)
    fun testCreateEdit_withFallbackEditor() {
    fun testCreateEdit_withFallbackEditor() = runTest {
        val uri = Uri.parse("content://fake")
        val component = ComponentName("com.android.foo", "com.android.foo.Something")