Merge "Fix share/edit actions for work profile." into tm-qpr-dev
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 2737ecf..b5145f9 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -402,6 +402,9 @@
                  android:permission="com.android.systemui.permission.SELF"
                  android:exported="false" />
 
+        <service android:name=".screenshot.ScreenshotCrossProfileService"
+                 android:permission="com.android.systemui.permission.SELF"
+                 android:exported="false" />
 
         <service android:name=".screenrecord.RecordingService" />
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt
new file mode 100644
index 0000000..017e57f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot
+
+import android.content.ClipData
+import android.content.ClipDescription
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import com.android.systemui.R
+
+object ActionIntentCreator {
+    /** @return a chooser intent to share the given URI with the optional provided subject. */
+    fun createShareIntent(uri: Uri, subject: String?): Intent {
+        // Create a share intent, this will always go through the chooser activity first
+        // which should not trigger auto-enter PiP
+        val sharingIntent =
+            Intent(Intent.ACTION_SEND).apply {
+                setDataAndType(uri, "image/png")
+                putExtra(Intent.EXTRA_STREAM, uri)
+
+                // Include URI in ClipData also, so that grantPermission picks it up.
+                // We don't use setData here because some apps interpret this as "to:".
+                clipData =
+                    ClipData(
+                        ClipDescription("content", arrayOf(ClipDescription.MIMETYPE_TEXT_PLAIN)),
+                        ClipData.Item(uri)
+                    )
+
+                putExtra(Intent.EXTRA_SUBJECT, subject)
+                addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+                addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
+            }
+
+        return Intent.createChooser(sharingIntent, null)
+            .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+            .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+    }
+
+    /**
+     * @return an ACTION_EDIT intent for the given URI, directed to config_screenshotEditor if
+     * available.
+     */
+    fun createEditIntent(uri: Uri, context: Context): Intent {
+        val editIntent = Intent(Intent.ACTION_EDIT)
+
+        context.getString(R.string.config_screenshotEditor)?.let {
+            if (it.isNotEmpty()) {
+                editIntent.component = ComponentName.unflattenFromString(it)
+            }
+        }
+
+        return editIntent
+            .setDataAndType(uri, "image/png")
+            .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+            .addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
+            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+            .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
new file mode 100644
index 0000000..5961635
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.os.RemoteException
+import android.os.UserHandle
+import android.util.Log
+import android.view.Display
+import android.view.IRemoteAnimationFinishedCallback
+import android.view.IRemoteAnimationRunner
+import android.view.RemoteAnimationAdapter
+import android.view.RemoteAnimationTarget
+import android.view.WindowManager
+import android.view.WindowManagerGlobal
+import com.android.internal.infra.ServiceConnector
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import javax.inject.Inject
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+@SysUISingleton
+class ActionIntentExecutor
+@Inject
+constructor(
+    @Application private val applicationScope: CoroutineScope,
+    @Background private val bgDispatcher: CoroutineDispatcher,
+    private val context: Context,
+) {
+    /**
+     * Execute the given intent with startActivity while performing operations for screenshot action
+     * launching.
+     * - Dismiss the keyguard first
+     * - If the userId is not the current user, proxy to a service running as that user to execute
+     * - After startActivity, optionally override the pending app transition.
+     */
+    fun launchIntentAsync(
+        intent: Intent,
+        bundle: Bundle,
+        userId: Int,
+        overrideTransition: Boolean,
+    ) {
+        applicationScope.launch { launchIntent(intent, bundle, userId, overrideTransition) }
+    }
+
+    suspend fun launchIntent(
+        intent: Intent,
+        bundle: Bundle,
+        userId: Int,
+        overrideTransition: Boolean,
+    ) {
+        withContext(bgDispatcher) {
+            dismissKeyguard()
+
+            if (userId == UserHandle.myUserId()) {
+                context.startActivity(intent, bundle)
+            } else {
+                launchCrossProfileIntent(userId, intent, bundle)
+            }
+
+            if (overrideTransition) {
+                val runner = RemoteAnimationAdapter(SCREENSHOT_REMOTE_RUNNER, 0, 0)
+                try {
+                    WindowManagerGlobal.getWindowManagerService()
+                        .overridePendingAppTransitionRemote(runner, Display.DEFAULT_DISPLAY)
+                } catch (e: Exception) {
+                    Log.e(TAG, "Error overriding screenshot app transition", e)
+                }
+            }
+        }
+    }
+
+    private val proxyConnector: ServiceConnector<IScreenshotProxy> =
+        ServiceConnector.Impl(
+            context,
+            Intent(context, ScreenshotProxyService::class.java),
+            Context.BIND_AUTO_CREATE or Context.BIND_WAIVE_PRIORITY or Context.BIND_NOT_VISIBLE,
+            context.userId,
+            IScreenshotProxy.Stub::asInterface,
+        )
+
+    private suspend fun dismissKeyguard() {
+        val completion = CompletableDeferred<Unit>()
+        val onDoneBinder =
+            object : IOnDoneCallback.Stub() {
+                override fun onDone(success: Boolean) {
+                    completion.complete(Unit)
+                }
+            }
+        proxyConnector.post { it.dismissKeyguard(onDoneBinder) }
+        completion.await()
+    }
+
+    private fun getCrossProfileConnector(userId: Int): ServiceConnector<ICrossProfileService> =
+        ServiceConnector.Impl<ICrossProfileService>(
+            context,
+            Intent(context, ScreenshotCrossProfileService::class.java),
+            Context.BIND_AUTO_CREATE or Context.BIND_WAIVE_PRIORITY or Context.BIND_NOT_VISIBLE,
+            userId,
+            ICrossProfileService.Stub::asInterface,
+        )
+
+    private suspend fun launchCrossProfileIntent(userId: Int, intent: Intent, bundle: Bundle) {
+        val connector = getCrossProfileConnector(userId)
+        val completion = CompletableDeferred<Unit>()
+        connector.post {
+            it.launchIntent(intent, bundle)
+            completion.complete(Unit)
+        }
+        completion.await()
+    }
+}
+
+private const val TAG: String = "ActionIntentExecutor"
+private const val SCREENSHOT_SHARE_SUBJECT_TEMPLATE = "Screenshot (%s)"
+
+/**
+ * This is effectively a no-op, but we need something non-null to pass in, in order to successfully
+ * override the pending activity entrance animation.
+ */
+private val SCREENSHOT_REMOTE_RUNNER: IRemoteAnimationRunner.Stub =
+    object : IRemoteAnimationRunner.Stub() {
+        override fun onAnimationStart(
+            @WindowManager.TransitionOldType transit: Int,
+            apps: Array<RemoteAnimationTarget>,
+            wallpapers: Array<RemoteAnimationTarget>,
+            nonApps: Array<RemoteAnimationTarget>,
+            finishedCallback: IRemoteAnimationFinishedCallback,
+        ) {
+            try {
+                finishedCallback.onAnimationFinished()
+            } catch (e: RemoteException) {
+                Log.e(TAG, "Error finishing screenshot remote animation", e)
+            }
+        }
+
+        override fun onAnimationCancelled(isKeyguardOccluded: Boolean) {}
+    }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ICrossProfileService.aidl b/packages/SystemUI/src/com/android/systemui/screenshot/ICrossProfileService.aidl
new file mode 100644
index 0000000..da83472
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ICrossProfileService.aidl
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot;
+
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.os.Bundle;
+
+/** Interface implemented by ScreenshotCrossProfileService */
+interface ICrossProfileService {
+
+    void launchIntent(in Intent intent, in Bundle bundle);
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/IOnDoneCallback.aidl b/packages/SystemUI/src/com/android/systemui/screenshot/IOnDoneCallback.aidl
new file mode 100644
index 0000000..e15030f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/IOnDoneCallback.aidl
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot;
+
+interface IOnDoneCallback {
+  void onDone(boolean success);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/IScreenshotProxy.aidl b/packages/SystemUI/src/com/android/systemui/screenshot/IScreenshotProxy.aidl
index f7c4dad..d2e3fbd 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/IScreenshotProxy.aidl
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/IScreenshotProxy.aidl
@@ -16,9 +16,14 @@
 
 package com.android.systemui.screenshot;
 
+import com.android.systemui.screenshot.IOnDoneCallback;
+
 /** Interface implemented by ScreenshotProxyService */
 interface IScreenshotProxy {
 
     /** Is the notification shade currently exanded? */
     boolean isNotificationShadeExpanded();
-}
\ No newline at end of file
+
+    /** Attempts to dismiss the keyguard. */
+    void dismissKeyguard(IOnDoneCallback callback);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
index 077ad35..7143ba2 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
@@ -173,6 +173,7 @@
             mImageData.deleteAction = createDeleteAction(mContext, mContext.getResources(), uri);
             mImageData.quickShareAction = createQuickShareAction(mContext,
                     mQuickShareData.quickShareAction, uri);
+            mImageData.subject = getSubjectString();
 
             mParams.mActionsReadyListener.onActionsReady(mImageData);
             if (DEBUG_CALLBACK) {
@@ -237,8 +238,6 @@
 
             // Create a share intent, this will always go through the chooser activity first
             // which should not trigger auto-enter PiP
-            String subjectDate = DateFormat.getDateTimeInstance().format(new Date(mImageTime));
-            String subject = String.format(SCREENSHOT_SHARE_SUBJECT_TEMPLATE, subjectDate);
             Intent sharingIntent = new Intent(Intent.ACTION_SEND);
             sharingIntent.setDataAndType(uri, "image/png");
             sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
@@ -248,7 +247,7 @@
                     new String[]{ClipDescription.MIMETYPE_TEXT_PLAIN}),
                     new ClipData.Item(uri));
             sharingIntent.setClipData(clipdata);
-            sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
+            sharingIntent.putExtra(Intent.EXTRA_SUBJECT, getSubjectString());
             sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                     .addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
 
@@ -318,7 +317,7 @@
             // by setting the (otherwise unused) request code to the current user id.
             int requestCode = mContext.getUserId();
 
-            // Create a edit action
+            // Create an edit action
             PendingIntent editAction = PendingIntent.getBroadcastAsUser(context, requestCode,
                     new Intent(context, ActionProxyReceiver.class)
                             .putExtra(ScreenshotController.EXTRA_ACTION_INTENT, pendingIntent)
@@ -479,4 +478,9 @@
             mParams.mQuickShareActionsReadyListener.onActionsReady(mQuickShareData);
         }
     }
+
+    private String getSubjectString() {
+        String subjectDate = DateFormat.getDateTimeInstance().format(new Date(mImageTime));
+        return String.format(SCREENSHOT_SHARE_SUBJECT_TEMPLATE, subjectDate);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 6d5121a..231e415 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -174,7 +174,7 @@
         public List<Notification.Action> smartActions;
         public Notification.Action quickShareAction;
         public UserHandle owner;
-
+        public String subject;  // Title for sharing
 
         /**
          * POD for shared element transition.
@@ -195,6 +195,7 @@
             deleteAction = null;
             smartActions = null;
             quickShareAction = null;
+            subject = null;
         }
     }
 
@@ -273,6 +274,7 @@
     private final ScreenshotNotificationSmartActionsProvider
             mScreenshotNotificationSmartActionsProvider;
     private final TimeoutHandler mScreenshotHandler;
+    private final ActionIntentExecutor mActionExecutor;
 
     private ScreenshotView mScreenshotView;
     private Bitmap mScreenBitmap;
@@ -310,7 +312,8 @@
             ActivityManager activityManager,
             TimeoutHandler timeoutHandler,
             BroadcastSender broadcastSender,
-            ScreenshotNotificationSmartActionsProvider screenshotNotificationSmartActionsProvider
+            ScreenshotNotificationSmartActionsProvider screenshotNotificationSmartActionsProvider,
+            ActionIntentExecutor actionExecutor
     ) {
         mScreenshotSmartActions = screenshotSmartActions;
         mNotificationsController = screenshotNotificationsController;
@@ -340,6 +343,7 @@
         mContext = (WindowContext) displayContext.createWindowContext(TYPE_SCREENSHOT, null);
         mWindowManager = mContext.getSystemService(WindowManager.class);
         mFlags = flags;
+        mActionExecutor = actionExecutor;
 
         mAccessibilityManager = AccessibilityManager.getInstance(mContext);
 
@@ -486,7 +490,7 @@
                 // TODO(159460485): Remove this when focus is handled properly in the system
                 setWindowFocusable(false);
             }
-        });
+        }, mActionExecutor, mFlags);
         mScreenshotView.setDefaultTimeoutMillis(mScreenshotHandler.getDefaultTimeoutMillis());
 
         mScreenshotView.setOnKeyListener((v, keyCode, event) -> {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotCrossProfileService.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotCrossProfileService.kt
new file mode 100644
index 0000000..2e6c756
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotCrossProfileService.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot
+
+import android.app.Service
+import android.content.Intent
+import android.os.Bundle
+import android.os.IBinder
+import android.util.Log
+
+/**
+ * If a screenshot is saved to the work profile, any intents that grant access to the screenshot
+ * must come from a service running as the work profile user. This service is meant to be started as
+ * the desired user and just startActivity for the given intent.
+ */
+class ScreenshotCrossProfileService : Service() {
+
+    private val mBinder: IBinder =
+        object : ICrossProfileService.Stub() {
+            override fun launchIntent(intent: Intent, bundle: Bundle) {
+                startActivity(intent, bundle)
+            }
+        }
+
+    override fun onBind(intent: Intent): IBinder? {
+        Log.d(TAG, "onBind: $intent")
+        return mBinder
+    }
+
+    companion object {
+        const val TAG = "ScreenshotProxyService"
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt
index 793085a..c41e2bc 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt
@@ -20,13 +20,16 @@
 import android.os.IBinder
 import android.util.Log
 import com.android.systemui.shade.ShadeExpansionStateManager
+import com.android.systemui.statusbar.phone.CentralSurfaces
+import java.util.Optional
 import javax.inject.Inject
 
 /**
  * Provides state from the main SystemUI process on behalf of the Screenshot process.
  */
 internal class ScreenshotProxyService @Inject constructor(
-    private val mExpansionMgr: ShadeExpansionStateManager
+    private val mExpansionMgr: ShadeExpansionStateManager,
+    private val mCentralSurfacesOptional: Optional<CentralSurfaces>,
 ) : Service() {
 
     private val mBinder: IBinder = object : IScreenshotProxy.Stub() {
@@ -38,6 +41,20 @@
             Log.d(TAG, "isNotificationShadeExpanded(): $expanded")
             return expanded
         }
+
+        override fun dismissKeyguard(callback: IOnDoneCallback) {
+            if (mCentralSurfacesOptional.isPresent) {
+                mCentralSurfacesOptional.get().executeRunnableDismissingKeyguard(
+                    Runnable {
+                        callback.onDone(true)
+                    }, null,
+                    true /* dismissShade */, true /* afterKeyguardGone */,
+                    true /* deferred */
+                )
+            } else {
+                callback.onDone(false)
+            }
+        }
     }
 
     override fun onBind(intent: Intent): IBinder? {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index be41a6b..26cbcbf 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -87,6 +87,8 @@
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.R;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition;
 import com.android.systemui.shared.system.InputChannelCompat;
 import com.android.systemui.shared.system.InputMonitorCompat;
@@ -168,6 +170,8 @@
 
     private final InteractionJankMonitor mInteractionJankMonitor;
     private long mDefaultTimeoutOfTimeoutHandler;
+    private ActionIntentExecutor mActionExecutor;
+    private FeatureFlags mFlags;
 
     private enum PendingInteraction {
         PREVIEW,
@@ -422,9 +426,12 @@
      * Note: must be called before any other (non-constructor) method or null pointer exceptions
      * may occur.
      */
-    void init(UiEventLogger uiEventLogger, ScreenshotViewCallback callbacks) {
+    void init(UiEventLogger uiEventLogger, ScreenshotViewCallback callbacks,
+            ActionIntentExecutor actionExecutor, FeatureFlags flags) {
         mUiEventLogger = uiEventLogger;
         mCallbacks = callbacks;
+        mActionExecutor = actionExecutor;
+        mFlags = flags;
     }
 
     void setScreenshot(Bitmap bitmap, Insets screenInsets) {
@@ -759,18 +766,37 @@
     void setChipIntents(ScreenshotController.SavedImageData imageData) {
         mShareChip.setOnClickListener(v -> {
             mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SHARE_TAPPED, 0, mPackageName);
-            startSharedTransition(
-                    imageData.shareTransition.get());
+            if (mFlags.isEnabled(Flags.SCREENSHOT_WORK_PROFILE_POLICY)) {
+                mActionExecutor.launchIntentAsync(ActionIntentCreator.INSTANCE.createShareIntent(
+                                imageData.uri, imageData.subject),
+                        imageData.shareTransition.get().bundle,
+                        imageData.owner.getIdentifier(), false);
+            } else {
+                startSharedTransition(imageData.shareTransition.get());
+            }
         });
         mEditChip.setOnClickListener(v -> {
             mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_EDIT_TAPPED, 0, mPackageName);
-            startSharedTransition(
-                    imageData.editTransition.get());
+            if (mFlags.isEnabled(Flags.SCREENSHOT_WORK_PROFILE_POLICY)) {
+                mActionExecutor.launchIntentAsync(
+                        ActionIntentCreator.INSTANCE.createEditIntent(imageData.uri, mContext),
+                        imageData.editTransition.get().bundle,
+                        imageData.owner.getIdentifier(), true);
+            } else {
+                startSharedTransition(imageData.editTransition.get());
+            }
         });
         mScreenshotPreview.setOnClickListener(v -> {
             mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED, 0, mPackageName);
-            startSharedTransition(
-                    imageData.editTransition.get());
+            if (mFlags.isEnabled(Flags.SCREENSHOT_WORK_PROFILE_POLICY)) {
+                mActionExecutor.launchIntentAsync(
+                        ActionIntentCreator.INSTANCE.createEditIntent(imageData.uri, mContext),
+                        imageData.editTransition.get().bundle,
+                        imageData.owner.getIdentifier(), true);
+            } else {
+                startSharedTransition(
+                        imageData.editTransition.get());
+            }
         });
         if (mQuickShareChip != null) {
             mQuickShareChip.setPendingIntent(imageData.quickShareAction.actionIntent,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentCreatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentCreatorTest.kt
new file mode 100644
index 0000000..b6a595b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentCreatorTest.kt
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.mockito.Mockito.`when` as whenever
+
+@SmallTest
+class ActionIntentCreatorTest : SysuiTestCase() {
+
+    @Test
+    fun testCreateShareIntent() {
+        val uri = Uri.parse("content://fake")
+        val subject = "Example subject"
+
+        val output = ActionIntentCreator.createShareIntent(uri, subject)
+
+        assertThat(output.action).isEqualTo(Intent.ACTION_CHOOSER)
+        assertFlagsSet(
+            Intent.FLAG_ACTIVITY_NEW_TASK or
+                Intent.FLAG_ACTIVITY_CLEAR_TASK or
+                Intent.FLAG_GRANT_READ_URI_PERMISSION,
+            output.flags
+        )
+
+        val wrappedIntent = output.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java)
+        assertThat(wrappedIntent?.action).isEqualTo(Intent.ACTION_SEND)
+        assertThat(wrappedIntent?.data).isEqualTo(uri)
+        assertThat(wrappedIntent?.type).isEqualTo("image/png")
+        assertThat(wrappedIntent?.getStringExtra(Intent.EXTRA_SUBJECT)).isEqualTo(subject)
+        assertThat(wrappedIntent?.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java))
+            .isEqualTo(uri)
+    }
+
+    @Test
+    fun testCreateShareIntent_noSubject() {
+        val uri = Uri.parse("content://fake")
+        val output = ActionIntentCreator.createShareIntent(uri, null)
+        val wrappedIntent = output.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java)
+        assertThat(wrappedIntent?.getStringExtra(Intent.EXTRA_SUBJECT)).isNull()
+    }
+
+    @Test
+    fun testCreateEditIntent() {
+        val uri = Uri.parse("content://fake")
+        val context = mock<Context>()
+
+        val output = ActionIntentCreator.createEditIntent(uri, context)
+
+        assertThat(output.action).isEqualTo(Intent.ACTION_EDIT)
+        assertThat(output.data).isEqualTo(uri)
+        assertThat(output.type).isEqualTo("image/png")
+        assertThat(output.component).isNull()
+        val expectedFlags =
+            Intent.FLAG_GRANT_READ_URI_PERMISSION or
+                Intent.FLAG_GRANT_WRITE_URI_PERMISSION or
+                Intent.FLAG_ACTIVITY_NEW_TASK or
+                Intent.FLAG_ACTIVITY_CLEAR_TASK
+        assertFlagsSet(expectedFlags, output.flags)
+    }
+
+    @Test
+    fun testCreateEditIntent_withEditor() {
+        val uri = Uri.parse("content://fake")
+        val context = mock<Context>()
+        var component = ComponentName("com.android.foo", "com.android.foo.Something")
+
+        whenever(context.getString(eq(R.string.config_screenshotEditor)))
+            .thenReturn(component.flattenToString())
+
+        val output = ActionIntentCreator.createEditIntent(uri, context)
+
+        assertThat(output.component).isEqualTo(component)
+    }
+
+    private fun assertFlagsSet(expected: Int, observed: Int) {
+        assertThat(observed and expected).isEqualTo(expected)
+    }
+}