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

Commit e018b5c7 authored by Mark Renouf's avatar Mark Renouf
Browse files

Minor cleanups and fixes for ActionIntentCreator

Makes parameters for text and subject non-nullable
Don't add null values to the output intent
Shorten function names by removing 'Intent' suffix
Tests use IntentSubject (Truth) where possible

Bug: 291706486
Fixes: 294241612
Test: atest ActionIntentCreatorTest
Change-Id: I39a4f70d61a8c57c01d8cf0e98ad64e66f7be217
parent 6e83117b
Loading
Loading
Loading
Loading
+11 −16
Original line number Original line Diff line number Diff line
@@ -26,21 +26,17 @@ import com.android.systemui.R


object ActionIntentCreator {
object ActionIntentCreator {
    /** @return a chooser intent to share the given URI. */
    /** @return a chooser intent to share the given URI. */
    fun createShareIntent(uri: Uri) = createShareIntent(uri, null, null)
    fun createShare(uri: Uri): Intent = createShare(uri, subject = null, text = null)


    /** @return a chooser intent to share the given URI with the optional provided subject. */
    /** @return a chooser intent to share the given URI with the optional provided subject. */
    fun createShareIntentWithSubject(uri: Uri, subject: String?) =
    fun createShareWithSubject(uri: Uri, subject: String): Intent =
        createShareIntent(uri, subject = subject)
        createShare(uri, subject = subject)


    /** @return a chooser intent to share the given URI with the optional provided extra text. */
    /** @return a chooser intent to share the given URI with the optional provided extra text. */
    fun createShareIntentWithExtraText(uri: Uri, extraText: String?) =
    fun createShareWithText(uri: Uri, extraText: String): Intent =
        createShareIntent(uri, extraText = extraText)
        createShare(uri, text = extraText)


    private fun createShareIntent(
    private fun createShare(uri: Uri, subject: String? = null, text: String? = null): Intent {
        uri: Uri,
        subject: String? = null,
        extraText: String? = null
    ): Intent {
        // Create a share intent, this will always go through the chooser activity first
        // Create a share intent, this will always go through the chooser activity first
        // which should not trigger auto-enter PiP
        // which should not trigger auto-enter PiP
        val sharingIntent =
        val sharingIntent =
@@ -56,8 +52,8 @@ object ActionIntentCreator {
                        ClipData.Item(uri)
                        ClipData.Item(uri)
                    )
                    )


                putExtra(Intent.EXTRA_SUBJECT, subject)
                subject?.let { putExtra(Intent.EXTRA_SUBJECT, subject) }
                putExtra(Intent.EXTRA_TEXT, extraText)
                text?.let { putExtra(Intent.EXTRA_TEXT, text) }
                addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
                addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
            }
            }
@@ -75,10 +71,9 @@ object ActionIntentCreator {
    fun createEditIntent(uri: Uri, context: Context): Intent {
    fun createEditIntent(uri: Uri, context: Context): Intent {
        val editIntent = Intent(Intent.ACTION_EDIT)
        val editIntent = Intent(Intent.ACTION_EDIT)


        context.getString(R.string.config_screenshotEditor)?.let {
        val editor = context.getString(R.string.config_screenshotEditor)
            if (it.isNotEmpty()) {
        if (editor.isNotEmpty()) {
                editIntent.component = ComponentName.unflattenFromString(it)
            editIntent.component = ComponentName.unflattenFromString(editor)
            }
        }
        }


        return editIntent
        return editIntent
+19 −14
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.systemui.screenshot
import android.content.Context
import android.content.Context
import android.content.Intent
import android.content.Intent
import android.os.Bundle
import android.os.Bundle
import android.os.Process.myUserHandle
import android.os.RemoteException
import android.os.RemoteException
import android.os.UserHandle
import android.os.UserHandle
import android.util.Log
import android.util.Log
@@ -44,10 +45,10 @@ import kotlinx.coroutines.withContext
class ActionIntentExecutor
class ActionIntentExecutor
@Inject
@Inject
constructor(
constructor(
    private val context: Context,
    @Application private val applicationScope: CoroutineScope,
    @Application private val applicationScope: CoroutineScope,
    @Main private val mainDispatcher: CoroutineDispatcher,
    @Main private val mainDispatcher: CoroutineDispatcher,
    private val context: Context,
    private val displayTracker: DisplayTracker,
    private val displayTracker: DisplayTracker
) {
) {
    /**
    /**
     * Execute the given intent with startActivity while performing operations for screenshot action
     * Execute the given intent with startActivity while performing operations for screenshot action
@@ -58,25 +59,25 @@ constructor(
     */
     */
    fun launchIntentAsync(
    fun launchIntentAsync(
        intent: Intent,
        intent: Intent,
        bundle: Bundle,
        options: Bundle?,
        userId: Int,
        user: UserHandle,
        overrideTransition: Boolean,
        overrideTransition: Boolean,
    ) {
    ) {
        applicationScope.launch { launchIntent(intent, bundle, userId, overrideTransition) }
        applicationScope.launch { launchIntent(intent, options, user, overrideTransition) }
    }
    }


    suspend fun launchIntent(
    suspend fun launchIntent(
        intent: Intent,
        intent: Intent,
        bundle: Bundle,
        options: Bundle?,
        userId: Int,
        user: UserHandle,
        overrideTransition: Boolean,
        overrideTransition: Boolean,
    ) {
    ) {
        dismissKeyguard()
        dismissKeyguard()


        if (userId == UserHandle.myUserId()) {
        if (user == myUserHandle()) {
            withContext(mainDispatcher) { context.startActivity(intent, bundle) }
            withContext(mainDispatcher) { context.startActivity(intent, options) }
        } else {
        } else {
            launchCrossProfileIntent(userId, intent, bundle)
            launchCrossProfileIntent(user, intent, options)
        }
        }


        if (overrideTransition) {
        if (overrideTransition) {
@@ -111,17 +112,21 @@ constructor(
        completion.await()
        completion.await()
    }
    }


    private fun getCrossProfileConnector(userId: Int): ServiceConnector<ICrossProfileService> =
    private fun getCrossProfileConnector(user: UserHandle): ServiceConnector<ICrossProfileService> =
        ServiceConnector.Impl<ICrossProfileService>(
        ServiceConnector.Impl<ICrossProfileService>(
            context,
            context,
            Intent(context, ScreenshotCrossProfileService::class.java),
            Intent(context, ScreenshotCrossProfileService::class.java),
            Context.BIND_AUTO_CREATE or Context.BIND_WAIVE_PRIORITY or Context.BIND_NOT_VISIBLE,
            Context.BIND_AUTO_CREATE or Context.BIND_WAIVE_PRIORITY or Context.BIND_NOT_VISIBLE,
            userId,
            user.identifier,
            ICrossProfileService.Stub::asInterface,
            ICrossProfileService.Stub::asInterface,
        )
        )


    private suspend fun launchCrossProfileIntent(userId: Int, intent: Intent, bundle: Bundle) {
    private suspend fun launchCrossProfileIntent(
        val connector = getCrossProfileConnector(userId)
        user: UserHandle,
        intent: Intent,
        bundle: Bundle?
    ) {
        val connector = getCrossProfileConnector(user)
        val completion = CompletableDeferred<Unit>()
        val completion = CompletableDeferred<Unit>()
        connector.post {
        connector.post {
            it.launchIntent(intent, bundle)
            it.launchIntent(intent, bundle)
+3 −4
Original line number Original line Diff line number Diff line
@@ -336,7 +336,7 @@ public class LongScreenshotActivity extends Activity {
            mActionExecutor.launchIntentAsync(
            mActionExecutor.launchIntentAsync(
                    ActionIntentCreator.INSTANCE.createEditIntent(uri, this),
                    ActionIntentCreator.INSTANCE.createEditIntent(uri, this),
                    null,
                    null,
                    mScreenshotUserHandle.getIdentifier(), false);
                    mScreenshotUserHandle, false);
        } else {
        } else {
            String editorPackage = getString(R.string.config_screenshotEditor);
            String editorPackage = getString(R.string.config_screenshotEditor);
            Intent intent = new Intent(Intent.ACTION_EDIT);
            Intent intent = new Intent(Intent.ACTION_EDIT);
@@ -362,9 +362,8 @@ public class LongScreenshotActivity extends Activity {
    }
    }


    private void doShare(Uri uri) {
    private void doShare(Uri uri) {
        Intent shareIntent = ActionIntentCreator.INSTANCE.createShareIntent(uri);
        Intent shareIntent = ActionIntentCreator.INSTANCE.createShare(uri);
        mActionExecutor.launchIntentAsync(shareIntent, null,
        mActionExecutor.launchIntentAsync(shareIntent, null, mScreenshotUserHandle, false);
                mScreenshotUserHandle.getIdentifier(), false);
    }
    }


    private void onClicked(View v) {
    private void onClicked(View v) {
+5 −5
Original line number Original line Diff line number Diff line
@@ -801,15 +801,15 @@ public class ScreenshotView extends FrameLayout implements
            Intent shareIntent;
            Intent shareIntent;
            if (mFlags.isEnabled(Flags.SCREENSHOT_METADATA) && mScreenshotData != null
            if (mFlags.isEnabled(Flags.SCREENSHOT_METADATA) && mScreenshotData != null
                    && mScreenshotData.getContextUrl() != null) {
                    && mScreenshotData.getContextUrl() != null) {
                shareIntent = ActionIntentCreator.INSTANCE.createShareIntentWithExtraText(
                shareIntent = ActionIntentCreator.INSTANCE.createShareWithText(
                        imageData.uri, mScreenshotData.getContextUrl().toString());
                        imageData.uri, mScreenshotData.getContextUrl().toString());
            } else {
            } else {
                shareIntent = ActionIntentCreator.INSTANCE.createShareIntentWithSubject(
                shareIntent = ActionIntentCreator.INSTANCE.createShareWithSubject(
                        imageData.uri, imageData.subject);
                        imageData.uri, imageData.subject);
            }
            }
            mActionExecutor.launchIntentAsync(shareIntent,
            mActionExecutor.launchIntentAsync(shareIntent,
                    imageData.shareTransition.get().bundle,
                    imageData.shareTransition.get().bundle,
                    imageData.owner.getIdentifier(), false);
                    imageData.owner, false);
        });
        });
        mEditChip.setOnClickListener(v -> {
        mEditChip.setOnClickListener(v -> {
            mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_EDIT_TAPPED, 0, mPackageName);
            mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_EDIT_TAPPED, 0, mPackageName);
@@ -817,7 +817,7 @@ public class ScreenshotView extends FrameLayout implements
            mActionExecutor.launchIntentAsync(
            mActionExecutor.launchIntentAsync(
                    ActionIntentCreator.INSTANCE.createEditIntent(imageData.uri, mContext),
                    ActionIntentCreator.INSTANCE.createEditIntent(imageData.uri, mContext),
                    imageData.editTransition.get().bundle,
                    imageData.editTransition.get().bundle,
                    imageData.owner.getIdentifier(), true);
                    imageData.owner, true);
        });
        });
        mScreenshotPreview.setOnClickListener(v -> {
        mScreenshotPreview.setOnClickListener(v -> {
            mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED, 0, mPackageName);
            mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED, 0, mPackageName);
@@ -825,7 +825,7 @@ public class ScreenshotView extends FrameLayout implements
            mActionExecutor.launchIntentAsync(
            mActionExecutor.launchIntentAsync(
                    ActionIntentCreator.INSTANCE.createEditIntent(imageData.uri, mContext),
                    ActionIntentCreator.INSTANCE.createEditIntent(imageData.uri, mContext),
                    imageData.editTransition.get().bundle,
                    imageData.editTransition.get().bundle,
                    imageData.owner.getIdentifier(), true);
                    imageData.owner, true);
        });
        });
        if (mQuickShareChip != null) {
        if (mQuickShareChip != null) {
            if (imageData.quickShareAction != null) {
            if (imageData.quickShareAction != null) {
+61 −62
Original line number Original line Diff line number Diff line
@@ -20,12 +20,13 @@ import android.content.ComponentName
import android.content.Context
import android.content.Context
import android.content.Intent
import android.content.Intent
import android.net.Uri
import android.net.Uri
import androidx.test.ext.truth.content.IntentSubject.assertThat
import androidx.test.filters.SmallTest
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import org.junit.Test
import org.junit.Test
import org.mockito.Mockito.`when` as whenever
import org.mockito.Mockito.`when` as whenever


@@ -36,24 +37,25 @@ class ActionIntentCreatorTest : SysuiTestCase() {
    fun testCreateShareIntent() {
    fun testCreateShareIntent() {
        val uri = Uri.parse("content://fake")
        val uri = Uri.parse("content://fake")


        val output = ActionIntentCreator.createShareIntent(uri)
        val output = ActionIntentCreator.createShare(uri)


        assertThat(output.action).isEqualTo(Intent.ACTION_CHOOSER)
        assertThat(output).hasAction(Intent.ACTION_CHOOSER)
        assertFlagsSet(
        assertThat(output)
            .hasFlags(
                Intent.FLAG_ACTIVITY_NEW_TASK or
                Intent.FLAG_ACTIVITY_NEW_TASK or
                    Intent.FLAG_ACTIVITY_CLEAR_TASK or
                    Intent.FLAG_ACTIVITY_CLEAR_TASK or
                Intent.FLAG_GRANT_READ_URI_PERMISSION,
                    Intent.FLAG_GRANT_READ_URI_PERMISSION
            output.flags
            )
            )


        assertThat(output).extras().parcelable<Intent>(Intent.EXTRA_INTENT).isNotNull()
        val wrappedIntent = output.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java)
        val wrappedIntent = output.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java)
        assertThat(wrappedIntent?.action).isEqualTo(Intent.ACTION_SEND)

        assertThat(wrappedIntent?.data).isEqualTo(uri)
        assertThat(wrappedIntent).hasAction(Intent.ACTION_SEND)
        assertThat(wrappedIntent?.type).isEqualTo("image/png")
        assertThat(wrappedIntent).hasData(uri)
        assertThat(wrappedIntent?.getStringExtra(Intent.EXTRA_SUBJECT)).isNull()
        assertThat(wrappedIntent).hasType("image/png")
        assertThat(wrappedIntent?.getStringExtra(Intent.EXTRA_TEXT)).isNull()
        assertThat(wrappedIntent).extras().doesNotContainKey(Intent.EXTRA_SUBJECT)
        assertThat(wrappedIntent?.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java))
        assertThat(wrappedIntent).extras().doesNotContainKey(Intent.EXTRA_TEXT)
            .isEqualTo(uri)
        assertThat(wrappedIntent).extras().parcelable<Uri>(Intent.EXTRA_STREAM).isEqualTo(uri)
    }
    }


    @Test
    @Test
@@ -61,24 +63,23 @@ class ActionIntentCreatorTest : SysuiTestCase() {
        val uri = Uri.parse("content://fake")
        val uri = Uri.parse("content://fake")
        val subject = "Example subject"
        val subject = "Example subject"


        val output = ActionIntentCreator.createShareIntentWithSubject(uri, subject)
        val output = ActionIntentCreator.createShareWithSubject(uri, subject)


        assertThat(output.action).isEqualTo(Intent.ACTION_CHOOSER)
        assertThat(output).hasAction(Intent.ACTION_CHOOSER)
        assertFlagsSet(
        assertThat(output)
            .hasFlags(
                Intent.FLAG_ACTIVITY_NEW_TASK or
                Intent.FLAG_ACTIVITY_NEW_TASK or
                    Intent.FLAG_ACTIVITY_CLEAR_TASK or
                    Intent.FLAG_ACTIVITY_CLEAR_TASK or
                Intent.FLAG_GRANT_READ_URI_PERMISSION,
                    Intent.FLAG_GRANT_READ_URI_PERMISSION
            output.flags
            )
            )


        val wrappedIntent = output.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java)
        val wrappedIntent = output.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java)
        assertThat(wrappedIntent?.action).isEqualTo(Intent.ACTION_SEND)
        assertThat(wrappedIntent).hasAction(Intent.ACTION_SEND)
        assertThat(wrappedIntent?.data).isEqualTo(uri)
        assertThat(wrappedIntent).hasData(uri)
        assertThat(wrappedIntent?.type).isEqualTo("image/png")
        assertThat(wrappedIntent).hasType("image/png")
        assertThat(wrappedIntent?.getStringExtra(Intent.EXTRA_SUBJECT)).isEqualTo(subject)
        assertThat(wrappedIntent).extras().string(Intent.EXTRA_SUBJECT).isEqualTo(subject)
        assertThat(wrappedIntent?.getStringExtra(Intent.EXTRA_TEXT)).isNull()
        assertThat(wrappedIntent).extras().doesNotContainKey(Intent.EXTRA_TEXT)
        assertThat(wrappedIntent?.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java))
        assertThat(wrappedIntent).extras().parcelable<Uri>(Intent.EXTRA_STREAM).isEqualTo(uri)
            .isEqualTo(uri)
    }
    }


    @Test
    @Test
@@ -86,24 +87,23 @@ class ActionIntentCreatorTest : SysuiTestCase() {
        val uri = Uri.parse("content://fake")
        val uri = Uri.parse("content://fake")
        val extraText = "Extra text"
        val extraText = "Extra text"


        val output = ActionIntentCreator.createShareIntentWithExtraText(uri, extraText)
        val output = ActionIntentCreator.createShareWithText(uri, extraText)


        assertThat(output.action).isEqualTo(Intent.ACTION_CHOOSER)
        assertThat(output).hasAction(Intent.ACTION_CHOOSER)
        assertFlagsSet(
        assertThat(output)
            .hasFlags(
                Intent.FLAG_ACTIVITY_NEW_TASK or
                Intent.FLAG_ACTIVITY_NEW_TASK or
                    Intent.FLAG_ACTIVITY_CLEAR_TASK or
                    Intent.FLAG_ACTIVITY_CLEAR_TASK or
                Intent.FLAG_GRANT_READ_URI_PERMISSION,
                    Intent.FLAG_GRANT_READ_URI_PERMISSION
            output.flags
            )
            )


        val wrappedIntent = output.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java)
        val wrappedIntent = output.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java)
        assertThat(wrappedIntent?.action).isEqualTo(Intent.ACTION_SEND)
        assertThat(wrappedIntent).hasAction(Intent.ACTION_SEND)
        assertThat(wrappedIntent?.data).isEqualTo(uri)
        assertThat(wrappedIntent).hasData(uri)
        assertThat(wrappedIntent?.type).isEqualTo("image/png")
        assertThat(wrappedIntent).hasType("image/png")
        assertThat(wrappedIntent?.getStringExtra(Intent.EXTRA_SUBJECT)).isNull()
        assertThat(wrappedIntent).extras().doesNotContainKey(Intent.EXTRA_SUBJECT)
        assertThat(wrappedIntent?.getStringExtra(Intent.EXTRA_TEXT)).isEqualTo(extraText)
        assertThat(wrappedIntent).extras().string(Intent.EXTRA_TEXT).isEqualTo(extraText)
        assertThat(wrappedIntent?.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java))
        assertThat(wrappedIntent).extras().parcelable<Uri>(Intent.EXTRA_STREAM).isEqualTo(uri)
            .isEqualTo(uri)
    }
    }


    @Test
    @Test
@@ -111,35 +111,34 @@ class ActionIntentCreatorTest : SysuiTestCase() {
        val uri = Uri.parse("content://fake")
        val uri = Uri.parse("content://fake")
        val context = mock<Context>()
        val context = mock<Context>()


        whenever(context.getString(eq(R.string.config_screenshotEditor))).thenReturn("")

        val output = ActionIntentCreator.createEditIntent(uri, context)
        val output = ActionIntentCreator.createEditIntent(uri, context)


        assertThat(output.action).isEqualTo(Intent.ACTION_EDIT)
        assertThat(output).hasAction(Intent.ACTION_EDIT)
        assertThat(output.data).isEqualTo(uri)
        assertThat(output).hasData(uri)
        assertThat(output.type).isEqualTo("image/png")
        assertThat(output).hasType("image/png")
        assertThat(output.component).isNull()
        assertWithMessage("getComponent()").that(output.component).isNull()
        val expectedFlags =
        assertThat(output)
            .hasFlags(
                Intent.FLAG_GRANT_READ_URI_PERMISSION or
                Intent.FLAG_GRANT_READ_URI_PERMISSION or
                    Intent.FLAG_GRANT_WRITE_URI_PERMISSION or
                    Intent.FLAG_GRANT_WRITE_URI_PERMISSION or
                    Intent.FLAG_ACTIVITY_NEW_TASK or
                    Intent.FLAG_ACTIVITY_NEW_TASK or
                    Intent.FLAG_ACTIVITY_CLEAR_TASK
                    Intent.FLAG_ACTIVITY_CLEAR_TASK
        assertFlagsSet(expectedFlags, output.flags)
            )
    }
    }


    @Test
    @Test
    fun testCreateEditIntent_withEditor() {
    fun testCreateEditIntent_withEditor() {
        val uri = Uri.parse("content://fake")
        val uri = Uri.parse("content://fake")
        val context = mock<Context>()
        val context = mock<Context>()
        var component = ComponentName("com.android.foo", "com.android.foo.Something")
        val component = ComponentName("com.android.foo", "com.android.foo.Something")


        whenever(context.getString(eq(R.string.config_screenshotEditor)))
        whenever(context.getString(eq(R.string.config_screenshotEditor)))
            .thenReturn(component.flattenToString())
            .thenReturn(component.flattenToString())


        val output = ActionIntentCreator.createEditIntent(uri, context)
        val output = ActionIntentCreator.createEditIntent(uri, context)


        assertThat(output.component).isEqualTo(component)
        assertThat(output).hasComponent(component)
    }

    private fun assertFlagsSet(expected: Int, observed: Int) {
        assertThat(observed and expected).isEqualTo(expected)
    }
    }
}
}