Merge "[Partial Screensharing] Add a temporary entrypoint in SysUI screen recorder" into tm-qpr-dev
diff --git a/packages/SystemUI/res/layout/screen_record_dialog.xml b/packages/SystemUI/res/layout/screen_record_dialog.xml
index f57d65a..ab38dd2 100644
--- a/packages/SystemUI/res/layout/screen_record_dialog.xml
+++ b/packages/SystemUI/res/layout/screen_record_dialog.xml
@@ -148,6 +148,20 @@
                     android:layout_width="0dp"
                     android:layout_height="match_parent"
                     android:layout_weight="1"/>
+
+                <!-- Temporary entrypoint for the partial screensharing used for teamfooding -->
+                <!-- TODO(b/236838395) remove this and use redesigned dialog -->
+                <TextView
+                    android:id="@+id/button_app"
+                    android:visibility="gone"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="0"
+                    android:layout_gravity="end"
+                    android:layout_marginEnd="8dp"
+                    android:text="App"
+                    style="@style/Widget.Dialog.Button.BorderButton" />
+
                 <TextView
                     android:id="@+id/button_start"
                     android:layout_width="wrap_content"
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
index 6802da3..53abd99 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
@@ -22,6 +22,7 @@
 import android.os.Binder
 import android.os.Bundle
 import android.os.IBinder
+import android.os.ResultReceiver
 import android.view.View
 import com.android.internal.app.ChooserActivity
 import com.android.internal.app.chooser.NotSelectableTargetInfo
@@ -103,17 +104,42 @@
     }
 
     private fun onTargetActivityLaunched(launchToken: IBinder) {
-        val mediaProjectionBinder = intent.getIBinderExtra(EXTRA_MEDIA_PROJECTION)
-        val projection = IMediaProjection.Stub.asInterface(mediaProjectionBinder)
+        if (intent.hasExtra(EXTRA_CAPTURE_REGION_RESULT_RECEIVER)) {
+            // The client requested to return the result in the result receiver instead of
+            // activity result, let's send the media projection to the result receiver
+            val resultReceiver = intent
+                .getParcelableExtra(EXTRA_CAPTURE_REGION_RESULT_RECEIVER,
+                    ResultReceiver::class.java) as ResultReceiver
+            val captureRegion = MediaProjectionCaptureTarget(launchToken)
+            val data = Bundle().apply {
+                putParcelable(KEY_CAPTURE_TARGET, captureRegion)
+            }
+            resultReceiver.send(RESULT_OK, data)
+        } else {
+            // Return the media projection instance as activity result
+            val mediaProjectionBinder = intent.getIBinderExtra(EXTRA_MEDIA_PROJECTION)
+            val projection = IMediaProjection.Stub.asInterface(mediaProjectionBinder)
 
-        projection.launchCookie = launchToken
+            projection.launchCookie = launchToken
 
-        val intent = Intent()
-        intent.putExtra(EXTRA_MEDIA_PROJECTION, projection.asBinder())
-        setResult(RESULT_OK, intent)
-        setForceSendResultForMediaProjection()
+            val intent = Intent()
+            intent.putExtra(EXTRA_MEDIA_PROJECTION, projection.asBinder())
+            setResult(RESULT_OK, intent)
+            setForceSendResultForMediaProjection()
+        }
+
         finish()
     }
 
     override fun shouldGetOnlyDefaultActivities() = false
+
+    companion object {
+        /**
+         * When EXTRA_CAPTURE_REGION_RESULT_RECEIVER is passed as intent extra
+         * the activity will send the [CaptureRegion] to the result receiver
+         * instead of returning media projection instance through activity result.
+         */
+        const val EXTRA_CAPTURE_REGION_RESULT_RECEIVER = "capture_region_result_receiver"
+        const val KEY_CAPTURE_TARGET = "capture_region"
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionCaptureTarget.kt b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionCaptureTarget.kt
new file mode 100644
index 0000000..fbf9294
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionCaptureTarget.kt
@@ -0,0 +1,49 @@
+/*
+ * 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.media
+
+import android.os.IBinder
+import android.os.Parcel
+import android.os.Parcelable
+
+/**
+ * Class that represents an area that should be captured.
+ * Currently it has only a launch cookie that represents a task but
+ * we potentially could add more identifiers e.g. for a pair of tasks.
+ */
+data class MediaProjectionCaptureTarget(
+    val launchCookie: IBinder?
+): Parcelable {
+
+    constructor(parcel: Parcel) : this(parcel.readStrongBinder())
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeStrongBinder(launchCookie)
+    }
+
+    override fun describeContents(): Int = 0
+
+    companion object CREATOR : Parcelable.Creator<MediaProjectionCaptureTarget> {
+        override fun createFromParcel(parcel: Parcel): MediaProjectionCaptureTarget {
+            return MediaProjectionCaptureTarget(parcel)
+        }
+
+        override fun newArray(size: Int): Array<MediaProjectionCaptureTarget?> {
+            return arrayOfNulls(size)
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
index 02d30c52..75fb393 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
@@ -34,6 +34,7 @@
 import com.android.systemui.animation.DialogLaunchAnimator;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QSTile;
@@ -61,6 +62,7 @@
     private final KeyguardStateController mKeyguardStateController;
     private final Callback mCallback = new Callback();
     private final DialogLaunchAnimator mDialogLaunchAnimator;
+    private final FeatureFlags mFlags;
 
     private long mMillisUntilFinished = 0;
 
@@ -71,6 +73,7 @@
             @Main Handler mainHandler,
             FalsingManager falsingManager,
             MetricsLogger metricsLogger,
+            FeatureFlags flags,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
             QSLogger qsLogger,
@@ -83,6 +86,7 @@
                 statusBarStateController, activityStarter, qsLogger);
         mController = controller;
         mController.observe(this, mCallback);
+        mFlags = flags;
         mKeyguardDismissUtil = keyguardDismissUtil;
         mKeyguardStateController = keyguardStateController;
         mDialogLaunchAnimator = dialogLaunchAnimator;
@@ -164,8 +168,8 @@
             mDialogLaunchAnimator.disableAllCurrentDialogsExitAnimations();
             getHost().collapsePanels();
         };
-        ScreenRecordDialog dialog = mController.createScreenRecordDialog(mContext,
-                onStartRecordingClicked);
+        ScreenRecordDialog dialog = mController.createScreenRecordDialog(mContext, mFlags,
+                mDialogLaunchAnimator, mActivityStarter, onStartRecordingClicked);
 
         ActivityStarter.OnDismissAction dismissAction = () -> {
             if (shouldAnimateFromView) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
index 1a08878..1083f22 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
@@ -29,8 +29,11 @@
 import androidx.annotation.Nullable;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.animation.DialogLaunchAnimator;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.settings.UserContextProvider;
 import com.android.systemui.statusbar.policy.CallbackController;
 
@@ -94,9 +97,11 @@
     }
 
     /** Create a dialog to show screen recording options to the user. */
-    public ScreenRecordDialog createScreenRecordDialog(Context context,
+    public ScreenRecordDialog createScreenRecordDialog(Context context, FeatureFlags flags,
+            DialogLaunchAnimator dialogLaunchAnimator, ActivityStarter activityStarter,
             @Nullable Runnable onStartRecordingClicked) {
-        return new ScreenRecordDialog(context, this, mUserContextProvider, onStartRecordingClicked);
+        return new ScreenRecordDialog(context, this, activityStarter, mUserContextProvider,
+                flags, dialogLaunchAnimator, onStartRecordingClicked);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index a837cbb..0477626 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.screenrecord;
 
+import android.annotation.Nullable;
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
@@ -42,6 +43,7 @@
 import com.android.systemui.R;
 import com.android.systemui.dagger.qualifiers.LongRunning;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.media.MediaProjectionCaptureTarget;
 import com.android.systemui.screenrecord.ScreenMediaRecorder.ScreenMediaRecorderListener;
 import com.android.systemui.settings.UserContextProvider;
 import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
@@ -67,6 +69,7 @@
     private static final String EXTRA_PATH = "extra_path";
     private static final String EXTRA_AUDIO_SOURCE = "extra_useAudio";
     private static final String EXTRA_SHOW_TAPS = "extra_showTaps";
+    private static final String EXTRA_CAPTURE_TARGET = "extra_captureTarget";
 
     private static final String ACTION_START = "com.android.systemui.screenrecord.START";
     private static final String ACTION_STOP = "com.android.systemui.screenrecord.STOP";
@@ -110,14 +113,18 @@
      * @param audioSource   The ordinal value of the audio source
      *                      {@link com.android.systemui.screenrecord.ScreenRecordingAudioSource}
      * @param showTaps   True to make touches visible while recording
+     * @param captureTarget   pass this parameter to capture a specific part instead
+     *                        of the full screen
      */
     public static Intent getStartIntent(Context context, int resultCode,
-            int audioSource, boolean showTaps) {
+            int audioSource, boolean showTaps,
+            @Nullable MediaProjectionCaptureTarget captureTarget) {
         return new Intent(context, RecordingService.class)
                 .setAction(ACTION_START)
                 .putExtra(EXTRA_RESULT_CODE, resultCode)
                 .putExtra(EXTRA_AUDIO_SOURCE, audioSource)
-                .putExtra(EXTRA_SHOW_TAPS, showTaps);
+                .putExtra(EXTRA_SHOW_TAPS, showTaps)
+                .putExtra(EXTRA_CAPTURE_TARGET, captureTarget);
     }
 
     @Override
@@ -136,6 +143,9 @@
                         .values()[intent.getIntExtra(EXTRA_AUDIO_SOURCE, 0)];
                 Log.d(TAG, "recording with audio source" + mAudioSource);
                 mShowTaps = intent.getBooleanExtra(EXTRA_SHOW_TAPS, false);
+                MediaProjectionCaptureTarget captureTarget =
+                        intent.getParcelableExtra(EXTRA_CAPTURE_TARGET,
+                                MediaProjectionCaptureTarget.class);
 
                 mOriginalShowTaps = Settings.System.getInt(
                         getApplicationContext().getContentResolver(),
@@ -148,6 +158,7 @@
                         mMainHandler,
                         currentUserId,
                         mAudioSource,
+                        captureTarget,
                         this
                 );
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
index d098b4b..b8d96f7 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
@@ -51,6 +51,7 @@
 import android.view.Surface;
 import android.view.WindowManager;
 
+import com.android.systemui.media.MediaProjectionCaptureTarget;
 import java.io.File;
 import java.io.Closeable;
 import java.io.IOException;
@@ -85,6 +86,7 @@
     private ScreenRecordingMuxer mMuxer;
     private ScreenInternalAudioRecorder mAudio;
     private ScreenRecordingAudioSource mAudioSource;
+    private final MediaProjectionCaptureTarget mCaptureRegion;
     private final Handler mHandler;
 
     private Context mContext;
@@ -92,10 +94,12 @@
 
     public ScreenMediaRecorder(Context context, Handler handler,
             int user, ScreenRecordingAudioSource audioSource,
+            MediaProjectionCaptureTarget captureRegion,
             ScreenMediaRecorderListener listener) {
         mContext = context;
         mHandler = handler;
         mUser = user;
+        mCaptureRegion = captureRegion;
         mListener = listener;
         mAudioSource = audioSource;
     }
@@ -108,9 +112,11 @@
         IMediaProjection proj = null;
         proj = mediaService.createProjection(mUser, mContext.getPackageName(),
                     MediaProjectionManager.TYPE_SCREEN_CAPTURE, false);
-        IBinder projection = proj.asBinder();
-        mMediaProjection = new MediaProjection(mContext,
-                IMediaProjection.Stub.asInterface(projection));
+        IMediaProjection projection = IMediaProjection.Stub.asInterface(proj.asBinder());
+        if (mCaptureRegion != null) {
+            projection.setLaunchCookie(mCaptureRegion.getLaunchCookie());
+        }
+        mMediaProjection = new MediaProjection(mContext, projection);
         mMediaProjection.registerCallback(this, mHandler);
 
         File cacheDir = mContext.getCacheDir();
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
index 1fb88df..efa45a4 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
@@ -16,6 +16,10 @@
 
 package com.android.systemui.screenrecord;
 
+import static android.app.Activity.RESULT_OK;
+
+import static com.android.systemui.media.MediaProjectionAppSelectorActivity.EXTRA_CAPTURE_REGION_RESULT_RECEIVER;
+import static com.android.systemui.media.MediaProjectionAppSelectorActivity.KEY_CAPTURE_TARGET;
 import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.INTERNAL;
 import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.MIC;
 import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.MIC_AND_INTERNAL;
@@ -24,8 +28,13 @@
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.Context;
+import android.content.Intent;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.ResultReceiver;
 import android.view.Gravity;
+import android.view.View;
 import android.view.Window;
 import android.view.WindowManager;
 import android.widget.ArrayAdapter;
@@ -36,6 +45,13 @@
 import androidx.annotation.Nullable;
 
 import com.android.systemui.R;
+import com.android.systemui.animation.ActivityLaunchAnimator;
+import com.android.systemui.animation.DialogLaunchAnimator;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
+import com.android.systemui.media.MediaProjectionAppSelectorActivity;
+import com.android.systemui.media.MediaProjectionCaptureTarget;
+import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.settings.UserContextProvider;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 
@@ -55,15 +71,23 @@
     private final UserContextProvider mUserContextProvider;
     @Nullable
     private final Runnable mOnStartRecordingClicked;
+    private final ActivityStarter mActivityStarter;
+    private final FeatureFlags mFlags;
+    private final DialogLaunchAnimator mDialogLaunchAnimator;
     private Switch mTapsSwitch;
     private Switch mAudioSwitch;
     private Spinner mOptions;
 
     public ScreenRecordDialog(Context context, RecordingController controller,
-            UserContextProvider userContextProvider, @Nullable Runnable onStartRecordingClicked) {
+            ActivityStarter activityStarter, UserContextProvider userContextProvider,
+            FeatureFlags flags, DialogLaunchAnimator dialogLaunchAnimator,
+            @Nullable Runnable onStartRecordingClicked) {
         super(context);
         mController = controller;
         mUserContextProvider = userContextProvider;
+        mActivityStarter = activityStarter;
+        mDialogLaunchAnimator = dialogLaunchAnimator;
+        mFlags = flags;
         mOnStartRecordingClicked = onStartRecordingClicked;
     }
 
@@ -91,10 +115,36 @@
                 mOnStartRecordingClicked.run();
             }
 
-            requestScreenCapture();
+            // Start full-screen recording
+            requestScreenCapture(/* captureTarget= */ null);
             dismiss();
         });
 
+        if (mFlags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING)) {
+            TextView appBtn = findViewById(R.id.button_app);
+
+            appBtn.setVisibility(View.VISIBLE);
+            appBtn.setOnClickListener(v -> {
+                Intent intent = new Intent(getContext(), MediaProjectionAppSelectorActivity.class);
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+                // We can't start activity for result here so we use result receiver to get
+                // the selected target to capture
+                intent.putExtra(EXTRA_CAPTURE_REGION_RESULT_RECEIVER,
+                        new CaptureTargetResultReceiver());
+
+                ActivityLaunchAnimator.Controller animationController =
+                        mDialogLaunchAnimator.createActivityLaunchController(appBtn);
+
+                if (animationController == null) {
+                    dismiss();
+                }
+
+                mActivityStarter.startActivity(intent, /* dismissShade= */ true,
+                        animationController);
+            });
+        }
+
         mAudioSwitch = findViewById(R.id.screenrecord_audio_switch);
         mTapsSwitch = findViewById(R.id.screenrecord_taps_switch);
         mOptions = findViewById(R.id.screen_recording_options);
@@ -108,7 +158,12 @@
         });
     }
 
-    private void requestScreenCapture() {
+    /**
+     * Starts screen capture after some countdown
+     * @param captureTarget target to capture (could be e.g. a task) or
+     *                      null to record the whole screen
+     */
+    private void requestScreenCapture(@Nullable MediaProjectionCaptureTarget captureTarget) {
         Context userContext = mUserContextProvider.getUserContext();
         boolean showTaps = mTapsSwitch.isChecked();
         ScreenRecordingAudioSource audioMode = mAudioSwitch.isChecked()
@@ -118,7 +173,7 @@
                 RecordingService.REQUEST_CODE,
                 RecordingService.getStartIntent(
                         userContext, Activity.RESULT_OK,
-                        audioMode.ordinal(), showTaps),
+                        audioMode.ordinal(), showTaps, captureTarget),
                 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
         PendingIntent stopIntent = PendingIntent.getService(userContext,
                 RecordingService.REQUEST_CODE,
@@ -126,4 +181,22 @@
                 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
         mController.startCountdown(DELAY_MS, INTERVAL_MS, startIntent, stopIntent);
     }
+
+    private class CaptureTargetResultReceiver extends ResultReceiver {
+
+        CaptureTargetResultReceiver() {
+            super(new Handler(Looper.getMainLooper()));
+        }
+
+        @Override
+        protected void onReceiveResult(int resultCode, Bundle resultData) {
+            if (resultCode == RESULT_OK) {
+                MediaProjectionCaptureTarget captureTarget = resultData
+                        .getParcelable(KEY_CAPTURE_TARGET, MediaProjectionCaptureTarget.class);
+
+                // Start recording of the selected target
+                requestScreenCapture(captureTarget);
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
index e4c5299..e6bd396 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
@@ -22,6 +22,7 @@
 
 import static org.junit.Assert.assertFalse;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -38,6 +39,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.animation.DialogLaunchAnimator;
 import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSTileHost;
@@ -73,6 +75,8 @@
     @Mock
     private QSLogger mQSLogger;
     @Mock
+    private FeatureFlags mFeatureFlags;
+    @Mock
     private KeyguardStateController mKeyguardStateController;
     @Mock
     private DialogLaunchAnimator mDialogLaunchAnimator;
@@ -94,6 +98,7 @@
                 new Handler(mTestableLooper.getLooper()),
                 new FalsingManagerFake(),
                 mMetricsLogger,
+                mFeatureFlags,
                 mStatusBarStateController,
                 mActivityStarter,
                 mQSLogger,
@@ -125,7 +130,8 @@
         mTestableLooper.processAllMessages();
 
         ArgumentCaptor<Runnable> onStartRecordingClicked = ArgumentCaptor.forClass(Runnable.class);
-        verify(mController).createScreenRecordDialog(any(), onStartRecordingClicked.capture());
+        verify(mController).createScreenRecordDialog(any(), eq(mFeatureFlags),
+                eq(mDialogLaunchAnimator), eq(mActivityStarter), onStartRecordingClicked.capture());
 
         // When starting the recording, we collapse the shade and disable the dialog animation.
         assertNotNull(onStartRecordingClicked.getValue());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
index b05d9a3..a1d78cb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
@@ -30,6 +30,7 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.content.Intent;
+import android.os.Binder;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.testing.AndroidTestingRunner;
@@ -38,6 +39,7 @@
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.media.MediaProjectionCaptureTarget;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.settings.UserContextProvider;
 import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
@@ -108,8 +110,17 @@
     }
 
     @Test
-    public void testLogStartRecording() {
-        Intent startIntent = RecordingService.getStartIntent(mContext, 0, 0, false);
+    public void testLogStartFullScreenRecording() {
+        Intent startIntent = RecordingService.getStartIntent(mContext, 0, 0, false, null);
+        mRecordingService.onStartCommand(startIntent, 0, 0);
+
+        verify(mUiEventLogger, times(1)).log(Events.ScreenRecordEvent.SCREEN_RECORD_START);
+    }
+
+    @Test
+    public void testLogStartPartialRecording() {
+        MediaProjectionCaptureTarget target = new MediaProjectionCaptureTarget(new Binder());
+        Intent startIntent = RecordingService.getStartIntent(mContext, 0, 0, false, target);
         mRecordingService.onStartCommand(startIntent, 0, 0);
 
         verify(mUiEventLogger, times(1)).log(Events.ScreenRecordEvent.SCREEN_RECORD_START);
@@ -142,7 +153,7 @@
         // When the screen recording does not start properly
         doThrow(new RuntimeException("fail")).when(mScreenMediaRecorder).start();
 
-        Intent startIntent = RecordingService.getStartIntent(mContext, 0, 0, false);
+        Intent startIntent = RecordingService.getStartIntent(mContext, 0, 0, false, null);
         mRecordingService.onStartCommand(startIntent, 0, 0);
 
         // Then the state is set to not recording
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordDialogTest.kt
new file mode 100644
index 0000000..03d9444
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordDialogTest.kt
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+/*
+ * 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.screenrecord
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.DialogLaunchAnimator
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.settings.UserContextProvider
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.`when` as whenever
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
[email protected](setAsMainLooper = true)
+class ScreenRecordDialogTest : SysuiTestCase() {
+
+    @Mock
+    private lateinit var starter: ActivityStarter
+    @Mock
+    private lateinit var controller: RecordingController
+    @Mock
+    private lateinit var userContextProvider: UserContextProvider
+    @Mock
+    private lateinit var flags: FeatureFlags
+    @Mock
+    private lateinit var dialogLaunchAnimator: DialogLaunchAnimator
+    @Mock
+    private lateinit var onStartRecordingClicked: Runnable
+
+    private lateinit var dialog: ScreenRecordDialog
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        dialog = ScreenRecordDialog(
+            context, controller, starter, userContextProvider, flags, dialogLaunchAnimator,
+            onStartRecordingClicked
+        )
+    }
+
+    @After
+    fun teardown() {
+        if (::dialog.isInitialized) {
+            dialog.dismiss()
+        }
+    }
+
+    @Test
+    fun testShowDialog_partialScreenSharingDisabled_appButtonIsNotVisible() {
+        whenever(flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING)).thenReturn(false)
+
+        dialog.show()
+
+        val visibility = dialog.requireViewById<View>(R.id.button_app).visibility
+        assertThat(visibility).isEqualTo(View.GONE)
+    }
+
+    @Test
+    fun testShowDialog_partialScreenSharingEnabled_appButtonIsVisible() {
+        whenever(flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING)).thenReturn(true)
+
+        dialog.show()
+
+        val visibility = dialog.requireViewById<View>(R.id.button_app).visibility
+        assertThat(visibility).isEqualTo(View.VISIBLE)
+    }
+}