From f9ea202f424646f75543afbb1b3c9f7dda262150 Mon Sep 17 00:00:00 2001 From: Nick Chameyev Date: Mon, 25 Jul 2022 13:46:25 +0000 Subject: [PATCH] [Partial Screensharing] Add a temporary entrypoint in SysUI screen recorder Adds a button that allows to start app selection flow in SystemUI screen recorder dialog (see screenshot in the bug). This button is needed for teamfood testing of partial screensharing and will be shown only when the feature flag is enabled. It will be removed when redesigned dialog with a dropdown will be implemented. Bug: 239422418 Test: turn on feature flag and start partial screen recording Test: atest com.android.systemui.screenrecord.ScreenRecordDialogTest Change-Id: I9caa913ef52eeb2203dca32e94e0b10d71fc4b83 --- .../res/layout/screen_record_dialog.xml | 14 +++ .../MediaProjectionAppSelectorActivity.kt | 40 +++++-- .../media/MediaProjectionCaptureTarget.kt | 49 ++++++++ .../systemui/qs/tiles/ScreenRecordTile.java | 8 +- .../screenrecord/RecordingController.java | 9 +- .../screenrecord/RecordingService.java | 15 ++- .../screenrecord/ScreenMediaRecorder.java | 12 +- .../screenrecord/ScreenRecordDialog.java | 81 ++++++++++++- .../qs/tiles/ScreenRecordTileTest.java | 8 +- .../screenrecord/RecordingServiceTest.java | 17 ++- .../screenrecord/ScreenRecordDialogTest.kt | 111 ++++++++++++++++++ 11 files changed, 340 insertions(+), 24 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/media/MediaProjectionCaptureTarget.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordDialogTest.kt diff --git a/packages/SystemUI/res/layout/screen_record_dialog.xml b/packages/SystemUI/res/layout/screen_record_dialog.xml index f57d65aef8afe..ab38dd2aebba8 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"/> + + + + + { + override fun createFromParcel(parcel: Parcel): MediaProjectionCaptureTarget { + return MediaProjectionCaptureTarget(parcel) + } + + override fun newArray(size: Int): Array { + 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 02d30c5224a0c..75fb393d84b56 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.DialogCuj; 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 @@ public class ScreenRecordTile extends QSTileImpl 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 @@ public class ScreenRecordTile extends QSTileImpl @Main Handler mainHandler, FalsingManager falsingManager, MetricsLogger metricsLogger, + FeatureFlags flags, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger, @@ -83,6 +86,7 @@ public class ScreenRecordTile extends QSTileImpl statusBarStateController, activityStarter, qsLogger); mController = controller; mController.observe(this, mCallback); + mFlags = flags; mKeyguardDismissUtil = keyguardDismissUtil; mKeyguardStateController = keyguardStateController; mDialogLaunchAnimator = dialogLaunchAnimator; @@ -164,8 +168,8 @@ public class ScreenRecordTile extends QSTileImpl 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 1a08878cecfe3..1083f22164d9f 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.NonNull; 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 @@ public class RecordingController } /** 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 a837cbb8a50e1..047762662aab7 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.internal.logging.UiEventLogger; 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 @@ public class RecordingService extends Service implements ScreenMediaRecorderList 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 @@ public class RecordingService extends Service implements ScreenMediaRecorderList * @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 @@ public class RecordingService extends Service implements ScreenMediaRecorderList .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 @@ public class RecordingService extends Service implements ScreenMediaRecorderList 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 d098b4b3442ae..b8d96f774e028 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.util.Size; 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 @@ public class ScreenMediaRecorder extends MediaProjection.Callback { 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 class ScreenMediaRecorder extends MediaProjection.Callback { 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 @@ public class ScreenMediaRecorder extends MediaProjection.Callback { 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 1fb88dfe9b523..efa45a4c4723b 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 static com.android.systemui.screenrecord.ScreenRecordingAudioSource.NONE; 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 android.widget.TextView; 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 @@ public class ScreenRecordDialog extends SystemUIDialog { 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 @@ public class ScreenRecordDialog extends SystemUIDialog { 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 @@ public class ScreenRecordDialog extends SystemUIDialog { }); } - 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 @@ public class ScreenRecordDialog extends SystemUIDialog { 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 @@ public class ScreenRecordDialog extends SystemUIDialog { 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 e4c5299a0cc52..e6bd396ebc6ce 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 junit.framework.Assert.assertTrue; 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.R; 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 @@ public class ScreenRecordTileTest extends SysuiTestCase { @Mock private QSLogger mQSLogger; @Mock + private FeatureFlags mFeatureFlags; + @Mock private KeyguardStateController mKeyguardStateController; @Mock private DialogLaunchAnimator mDialogLaunchAnimator; @@ -94,6 +98,7 @@ public class ScreenRecordTileTest extends SysuiTestCase { new Handler(mTestableLooper.getLooper()), new FalsingManagerFake(), mMetricsLogger, + mFeatureFlags, mStatusBarStateController, mActivityStarter, mQSLogger, @@ -125,7 +130,8 @@ public class ScreenRecordTileTest extends SysuiTestCase { mTestableLooper.processAllMessages(); ArgumentCaptor 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 b05d9a31b475e..a1d78cbba7f9c 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 static org.mockito.Mockito.verify; 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 androidx.test.filters.SmallTest; 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 @@ public class RecordingServiceTest extends SysuiTestCase { } @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 @@ public class RecordingServiceTest extends SysuiTestCase { // 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 0000000000000..03d944475da81 --- /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) +@TestableLooper.RunWithLooper(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(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(R.id.button_app).visibility + assertThat(visibility).isEqualTo(View.VISIBLE) + } +}