Loading packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt +2 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ class DefaultScreenshotActionsProviderTest : SysuiTestCase() { 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 request = ScreenshotData.forTesting(userHandle = UserHandle.OWNER) private val validResult = ScreenshotSavedResult(Uri.EMPTY, Process.myUserHandle(), 0) Loading Loading @@ -196,6 +197,7 @@ class DefaultScreenshotActionsProviderTest : SysuiTestCase() { return DefaultScreenshotActionsProvider( context, uiEventLogger, actionIntentCreator, UUID.randomUUID(), request, actionExecutor, Loading packages/SystemUI/res/values/config.xml +10 −1 Original line number Diff line number Diff line Loading @@ -501,7 +501,16 @@ <!-- Smartspace trampoline activity that is used when the user taps smartspace. --> <string name="config_smartspaceTrampolineActivityComponent" translatable="false">com.google.android.apps.gsa.staticplugins.opa.smartspace.ExportedSmartspaceTrampolineActivity</string> <!-- Screenshot editing default activity. Must handle ACTION_EDIT image/png intents. <!-- Screenshot editing default activity. Will only be used if the provided component exists and is enabled. Must handle ACTION_EDIT image/png intents. Blank falls back to config_screenshotEditor. This name is in the ComponentName flattened format (package/class) --> <string name="config_preferredScreenshotEditor" translatable="false"></string> <!-- Screenshot editing activity used if config_preferredScreenshotEditor is not available. Must handle ACTION_EDIT image/png intents. Blank sends the user to the Chooser first. This name is in the ComponentName flattened format (package/class) --> <string name="config_screenshotEditor" translatable="false"></string> Loading packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt +50 −11 Original line number Diff line number Diff line Loading @@ -22,12 +22,19 @@ import android.content.ComponentName import android.content.ContentProvider import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.net.Uri import android.os.UserHandle import com.android.systemui.dagger.SysUISingleton import com.android.systemui.res.R import com.android.systemui.screenshot.scroll.LongScreenshotActivity import com.android.systemui.shared.Flags.usePreferredImageEditor import javax.inject.Inject object ActionIntentCreator { @SysUISingleton class ActionIntentCreator @Inject constructor(private val context: Context, private val packageManager: PackageManager) { /** @return a chooser intent to share the given URI. */ fun createShare(uri: Uri): Intent = createShare(uri, subject = null, text = null) Loading @@ -54,7 +61,7 @@ object ActionIntentCreator { clipData = ClipData( ClipDescription("content", arrayOf(ClipDescription.MIMETYPE_TEXT_PLAIN)), ClipData.Item(uri) ClipData.Item(uri), ) subject?.let { putExtra(Intent.EXTRA_SUBJECT, subject) } Loading @@ -70,17 +77,22 @@ object ActionIntentCreator { } /** * @return an ACTION_EDIT intent for the given URI, directed to config_screenshotEditor if * available. * @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, context: Context): Intent { fun createEdit(rawUri: Uri): Intent { val uri = uriWithoutUserId(rawUri) val editIntent = Intent(Intent.ACTION_EDIT) if (usePreferredImageEditor()) { // Use the preferred editor if it's available, otherwise fall back to the default editor editIntent.component = preferredEditor() ?: defaultEditor() } else { val editor = context.getString(R.string.config_screenshotEditor) if (editor.isNotEmpty()) { editIntent.component = ComponentName.unflattenFromString(editor) } } return editIntent .setDataAndType(uri, "image/png") Loading @@ -92,7 +104,7 @@ object ActionIntentCreator { } /** @return an Intent to start the LongScreenshotActivity */ fun createLongScreenshotIntent(owner: UserHandle, context: Context): Intent { fun createLongScreenshotIntent(owner: UserHandle): Intent { return Intent(context, LongScreenshotActivity::class.java) .putExtra(LongScreenshotActivity.EXTRA_SCREENSHOT_USER_HANDLE, owner) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) Loading @@ -100,9 +112,36 @@ object ActionIntentCreator { .addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION) } private fun preferredEditor(): ComponentName? = runCatching { val preferredEditor = context.getString(R.string.config_preferredScreenshotEditor) val component = ComponentName.unflattenFromString(preferredEditor) ?: return null val info = packageManager.getPackageInfo( component.packageName, PackageManager.GET_ACTIVITIES, ) return info.activities ?.firstOrNull { it.componentName.className.equals(component.className) } ?.componentName } .getOrNull() private fun defaultEditor(): ComponentName? = runCatching { context.getString(R.string.config_screenshotEditor).let { ComponentName.unflattenFromString(it) } } .getOrNull() companion object { private const val EXTRA_EDIT_SOURCE = "edit_source" private const val EDIT_SOURCE_SCREENSHOT = "screenshot" } } /** * URIs here are passed only via Intent which are sent to the target user via Intent. Because of Loading packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotController.java +4 −2 Original line number Diff line number Diff line Loading @@ -139,6 +139,7 @@ public class LegacyScreenshotController implements InteractiveScreenshotHandler private RequestCallback mCurrentRequestCallback; private String mPackageName = ""; private final BroadcastReceiver mCopyBroadcastReceiver; private final ActionIntentCreator mActionIntentCreator; /** Tracks config changes that require re-creating UI */ private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges( Loading Loading @@ -174,6 +175,7 @@ public class LegacyScreenshotController implements InteractiveScreenshotHandler MessageContainerController messageContainerController, Provider<ScreenshotSoundController> screenshotSoundController, AnnouncementResolver announcementResolver, ActionIntentCreator actionIntentCreator, @Assisted Display display ) { mScreenshotSmartActions = screenshotSmartActions; Loading Loading @@ -201,6 +203,7 @@ public class LegacyScreenshotController implements InteractiveScreenshotHandler mMessageContainerController = messageContainerController; mAssistContentRequester = assistContentRequester; mAnnouncementResolver = announcementResolver; mActionIntentCreator = actionIntentCreator; mViewProxy = viewProxyFactory.getProxy(mContext, mDisplay.getDisplayId()); Loading Loading @@ -509,8 +512,7 @@ public class LegacyScreenshotController implements InteractiveScreenshotHandler private void executeBatchScrollCapture(ScrollCaptureResponse response, UserHandle owner) { mScrollCaptureExecutor.executeBatchScrollCapture(response, () -> { final Intent intent = ActionIntentCreator.INSTANCE.createLongScreenshotIntent( owner, mContext); final Intent intent = mActionIntentCreator.createLongScreenshotIntent(owner); mContext.startActivity(intent); }, mViewProxy::restoreNonScrollingUi, Loading packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt +8 −7 Original line number Diff line number Diff line Loading @@ -24,9 +24,6 @@ import androidx.appcompat.content.res.AppCompatResources import com.android.internal.logging.UiEventLogger import com.android.systemui.log.DebugLogger.debugLog import com.android.systemui.res.R import com.android.systemui.screenshot.ActionIntentCreator.createEdit import com.android.systemui.screenshot.ActionIntentCreator.createShareWithSubject import com.android.systemui.screenshot.ActionIntentCreator.createShareWithText import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_EDIT_TAPPED import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_SHARE_TAPPED Loading Loading @@ -70,6 +67,7 @@ class DefaultScreenshotActionsProvider constructor( private val context: Context, private val uiEventLogger: UiEventLogger, private val actionIntentCreator: ActionIntentCreator, @Assisted val requestId: UUID, @Assisted val request: ScreenshotData, @Assisted val actionExecutor: ActionExecutor, Loading @@ -88,7 +86,7 @@ constructor( uiEventLogger.log(SCREENSHOT_PREVIEW_TAPPED, 0, request.packageNameString) onDeferrableActionTapped { result -> actionExecutor.startSharedTransition( createEdit(result.uri, context), actionIntentCreator.createEdit(result.uri), result.user, true, ) Loading @@ -110,9 +108,12 @@ constructor( val uri = webUri val shareIntent = if (screenshotContextUrl() && uri != null) { createShareWithText(result.uri, extraText = uri.toString()) actionIntentCreator.createShareWithText( result.uri, extraText = uri.toString(), ) } else { createShareWithSubject(result.uri, result.subject) actionIntentCreator.createShareWithSubject(result.uri, result.subject) } actionExecutor.startSharedTransition(shareIntent, result.user, false) } Loading @@ -130,7 +131,7 @@ constructor( uiEventLogger.log(SCREENSHOT_EDIT_TAPPED, 0, request.packageNameString) onDeferrableActionTapped { result -> actionExecutor.startSharedTransition( createEdit(result.uri, context), actionIntentCreator.createEdit(result.uri), result.user, true, ) Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt +2 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ class DefaultScreenshotActionsProviderTest : SysuiTestCase() { 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 request = ScreenshotData.forTesting(userHandle = UserHandle.OWNER) private val validResult = ScreenshotSavedResult(Uri.EMPTY, Process.myUserHandle(), 0) Loading Loading @@ -196,6 +197,7 @@ class DefaultScreenshotActionsProviderTest : SysuiTestCase() { return DefaultScreenshotActionsProvider( context, uiEventLogger, actionIntentCreator, UUID.randomUUID(), request, actionExecutor, Loading
packages/SystemUI/res/values/config.xml +10 −1 Original line number Diff line number Diff line Loading @@ -501,7 +501,16 @@ <!-- Smartspace trampoline activity that is used when the user taps smartspace. --> <string name="config_smartspaceTrampolineActivityComponent" translatable="false">com.google.android.apps.gsa.staticplugins.opa.smartspace.ExportedSmartspaceTrampolineActivity</string> <!-- Screenshot editing default activity. Must handle ACTION_EDIT image/png intents. <!-- Screenshot editing default activity. Will only be used if the provided component exists and is enabled. Must handle ACTION_EDIT image/png intents. Blank falls back to config_screenshotEditor. This name is in the ComponentName flattened format (package/class) --> <string name="config_preferredScreenshotEditor" translatable="false"></string> <!-- Screenshot editing activity used if config_preferredScreenshotEditor is not available. Must handle ACTION_EDIT image/png intents. Blank sends the user to the Chooser first. This name is in the ComponentName flattened format (package/class) --> <string name="config_screenshotEditor" translatable="false"></string> Loading
packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt +50 −11 Original line number Diff line number Diff line Loading @@ -22,12 +22,19 @@ import android.content.ComponentName import android.content.ContentProvider import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.net.Uri import android.os.UserHandle import com.android.systemui.dagger.SysUISingleton import com.android.systemui.res.R import com.android.systemui.screenshot.scroll.LongScreenshotActivity import com.android.systemui.shared.Flags.usePreferredImageEditor import javax.inject.Inject object ActionIntentCreator { @SysUISingleton class ActionIntentCreator @Inject constructor(private val context: Context, private val packageManager: PackageManager) { /** @return a chooser intent to share the given URI. */ fun createShare(uri: Uri): Intent = createShare(uri, subject = null, text = null) Loading @@ -54,7 +61,7 @@ object ActionIntentCreator { clipData = ClipData( ClipDescription("content", arrayOf(ClipDescription.MIMETYPE_TEXT_PLAIN)), ClipData.Item(uri) ClipData.Item(uri), ) subject?.let { putExtra(Intent.EXTRA_SUBJECT, subject) } Loading @@ -70,17 +77,22 @@ object ActionIntentCreator { } /** * @return an ACTION_EDIT intent for the given URI, directed to config_screenshotEditor if * available. * @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, context: Context): Intent { fun createEdit(rawUri: Uri): Intent { val uri = uriWithoutUserId(rawUri) val editIntent = Intent(Intent.ACTION_EDIT) if (usePreferredImageEditor()) { // Use the preferred editor if it's available, otherwise fall back to the default editor editIntent.component = preferredEditor() ?: defaultEditor() } else { val editor = context.getString(R.string.config_screenshotEditor) if (editor.isNotEmpty()) { editIntent.component = ComponentName.unflattenFromString(editor) } } return editIntent .setDataAndType(uri, "image/png") Loading @@ -92,7 +104,7 @@ object ActionIntentCreator { } /** @return an Intent to start the LongScreenshotActivity */ fun createLongScreenshotIntent(owner: UserHandle, context: Context): Intent { fun createLongScreenshotIntent(owner: UserHandle): Intent { return Intent(context, LongScreenshotActivity::class.java) .putExtra(LongScreenshotActivity.EXTRA_SCREENSHOT_USER_HANDLE, owner) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) Loading @@ -100,9 +112,36 @@ object ActionIntentCreator { .addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION) } private fun preferredEditor(): ComponentName? = runCatching { val preferredEditor = context.getString(R.string.config_preferredScreenshotEditor) val component = ComponentName.unflattenFromString(preferredEditor) ?: return null val info = packageManager.getPackageInfo( component.packageName, PackageManager.GET_ACTIVITIES, ) return info.activities ?.firstOrNull { it.componentName.className.equals(component.className) } ?.componentName } .getOrNull() private fun defaultEditor(): ComponentName? = runCatching { context.getString(R.string.config_screenshotEditor).let { ComponentName.unflattenFromString(it) } } .getOrNull() companion object { private const val EXTRA_EDIT_SOURCE = "edit_source" private const val EDIT_SOURCE_SCREENSHOT = "screenshot" } } /** * URIs here are passed only via Intent which are sent to the target user via Intent. Because of Loading
packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotController.java +4 −2 Original line number Diff line number Diff line Loading @@ -139,6 +139,7 @@ public class LegacyScreenshotController implements InteractiveScreenshotHandler private RequestCallback mCurrentRequestCallback; private String mPackageName = ""; private final BroadcastReceiver mCopyBroadcastReceiver; private final ActionIntentCreator mActionIntentCreator; /** Tracks config changes that require re-creating UI */ private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges( Loading Loading @@ -174,6 +175,7 @@ public class LegacyScreenshotController implements InteractiveScreenshotHandler MessageContainerController messageContainerController, Provider<ScreenshotSoundController> screenshotSoundController, AnnouncementResolver announcementResolver, ActionIntentCreator actionIntentCreator, @Assisted Display display ) { mScreenshotSmartActions = screenshotSmartActions; Loading Loading @@ -201,6 +203,7 @@ public class LegacyScreenshotController implements InteractiveScreenshotHandler mMessageContainerController = messageContainerController; mAssistContentRequester = assistContentRequester; mAnnouncementResolver = announcementResolver; mActionIntentCreator = actionIntentCreator; mViewProxy = viewProxyFactory.getProxy(mContext, mDisplay.getDisplayId()); Loading Loading @@ -509,8 +512,7 @@ public class LegacyScreenshotController implements InteractiveScreenshotHandler private void executeBatchScrollCapture(ScrollCaptureResponse response, UserHandle owner) { mScrollCaptureExecutor.executeBatchScrollCapture(response, () -> { final Intent intent = ActionIntentCreator.INSTANCE.createLongScreenshotIntent( owner, mContext); final Intent intent = mActionIntentCreator.createLongScreenshotIntent(owner); mContext.startActivity(intent); }, mViewProxy::restoreNonScrollingUi, Loading
packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt +8 −7 Original line number Diff line number Diff line Loading @@ -24,9 +24,6 @@ import androidx.appcompat.content.res.AppCompatResources import com.android.internal.logging.UiEventLogger import com.android.systemui.log.DebugLogger.debugLog import com.android.systemui.res.R import com.android.systemui.screenshot.ActionIntentCreator.createEdit import com.android.systemui.screenshot.ActionIntentCreator.createShareWithSubject import com.android.systemui.screenshot.ActionIntentCreator.createShareWithText import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_EDIT_TAPPED import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_SHARE_TAPPED Loading Loading @@ -70,6 +67,7 @@ class DefaultScreenshotActionsProvider constructor( private val context: Context, private val uiEventLogger: UiEventLogger, private val actionIntentCreator: ActionIntentCreator, @Assisted val requestId: UUID, @Assisted val request: ScreenshotData, @Assisted val actionExecutor: ActionExecutor, Loading @@ -88,7 +86,7 @@ constructor( uiEventLogger.log(SCREENSHOT_PREVIEW_TAPPED, 0, request.packageNameString) onDeferrableActionTapped { result -> actionExecutor.startSharedTransition( createEdit(result.uri, context), actionIntentCreator.createEdit(result.uri), result.user, true, ) Loading @@ -110,9 +108,12 @@ constructor( val uri = webUri val shareIntent = if (screenshotContextUrl() && uri != null) { createShareWithText(result.uri, extraText = uri.toString()) actionIntentCreator.createShareWithText( result.uri, extraText = uri.toString(), ) } else { createShareWithSubject(result.uri, result.subject) actionIntentCreator.createShareWithSubject(result.uri, result.subject) } actionExecutor.startSharedTransition(shareIntent, result.user, false) } Loading @@ -130,7 +131,7 @@ constructor( uiEventLogger.log(SCREENSHOT_EDIT_TAPPED, 0, request.packageNameString) onDeferrableActionTapped { result -> actionExecutor.startSharedTransition( createEdit(result.uri, context), actionIntentCreator.createEdit(result.uri), result.user, true, ) Loading