summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Yalan Yiue <yyalan@google.com> 2022-11-09 11:30:26 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2022-11-09 11:30:26 +0000
commitdccb3586684b1a7f11dfbfc1715d6cf09373523c (patch)
tree6f64f0e404e3ff9eb3bbeef042f2f69ea736063d
parentabee62b65c510c4ca289d94992a233fd49bd41a0 (diff)
parentc3b0b68436ce16dd6102c542df6781f4c14d7b24 (diff)
Merge "[Partial Screensharing] Permission Dialog initial version" into tm-qpr-dev
-rw-r--r--packages/SystemUI/res/layout/screen_record_options.xml86
-rw-r--r--packages/SystemUI/res/layout/screen_share_dialog.xml94
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java49
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/BaseScreenSharePermissionDialog.kt110
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/MediaProjectionPermissionDialog.kt56
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt173
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/ScreenShareOption.kt33
9 files changed, 597 insertions, 26 deletions
diff --git a/packages/SystemUI/res/layout/screen_record_options.xml b/packages/SystemUI/res/layout/screen_record_options.xml
new file mode 100644
index 000000000000..a93691434bc0
--- /dev/null
+++ b/packages/SystemUI/res/layout/screen_record_options.xml
@@ -0,0 +1,86 @@
+<!--
+ 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.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <ImageView
+ android:layout_width="@dimen/screenrecord_option_icon_size"
+ android:layout_height="@dimen/screenrecord_option_icon_size"
+ android:src="@drawable/ic_mic_26dp"
+ android:tint="?android:attr/textColorSecondary"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="0"
+ android:layout_marginRight="@dimen/screenrecord_option_padding"
+ android:importantForAccessibility="no"/>
+ <Spinner
+ android:id="@+id/screen_recording_options"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:minHeight="48dp"
+ android:layout_weight="1"
+ android:popupBackground="@drawable/screenrecord_spinner_background"
+ android:dropDownWidth="274dp"
+ android:importantForAccessibility="yes"/>
+ <Switch
+ android:layout_width="wrap_content"
+ android:minWidth="48dp"
+ android:layout_height="48dp"
+ android:layout_weight="0"
+ android:layout_gravity="end"
+ android:id="@+id/screenrecord_audio_switch"
+ style="@style/ScreenRecord.Switch"
+ android:importantForAccessibility="yes"/>
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_marginTop="@dimen/screenrecord_option_padding">
+ <ImageView
+ android:layout_width="@dimen/screenrecord_option_icon_size"
+ android:layout_height="@dimen/screenrecord_option_icon_size"
+ android:layout_weight="0"
+ android:src="@drawable/ic_touch"
+ android:tint="?android:attr/textColorSecondary"
+ android:layout_gravity="center_vertical"
+ android:layout_marginRight="@dimen/screenrecord_option_padding"
+ android:importantForAccessibility="no"/>
+ <TextView
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:minHeight="48dp"
+ android:layout_weight="1"
+ android:gravity="center_vertical"
+ android:text="@string/screenrecord_taps_label"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:fontFamily="@*android:string/config_headlineFontFamily"
+ android:textColor="?android:attr/textColorPrimary"
+ android:contentDescription="@string/screenrecord_taps_label"/>
+ <Switch
+ android:layout_width="wrap_content"
+ android:minWidth="48dp"
+ android:layout_height="48dp"
+ android:layout_weight="0"
+ android:id="@+id/screenrecord_taps_switch"
+ style="@style/ScreenRecord.Switch"
+ android:importantForAccessibility="yes"/>
+ </LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/screen_share_dialog.xml b/packages/SystemUI/res/layout/screen_share_dialog.xml
new file mode 100644
index 000000000000..ac46cdb1be24
--- /dev/null
+++ b/packages/SystemUI/res/layout/screen_share_dialog.xml
@@ -0,0 +1,94 @@
+<!--
+ 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.
+ -->
+
+<!-- Scrollview is necessary to fit everything in landscape layout -->
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/screen_share_permission_dialog"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="@dimen/dialog_side_padding"
+ android:paddingEnd="@dimen/dialog_side_padding"
+ android:paddingTop="@dimen/dialog_top_padding"
+ android:paddingBottom="@dimen/dialog_bottom_padding"
+ android:orientation="vertical"
+ android:gravity="center_horizontal">
+
+ <ImageView
+ android:layout_width="@dimen/screenrecord_logo_size"
+ android:layout_height="@dimen/screenrecord_logo_size"
+ android:src="@drawable/ic_screenrecord"
+ android:tint="@color/screenrecord_icon_color"
+ android:importantForAccessibility="no"/>
+ <TextView
+ android:id="@+id/screen_share_dialog_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:fontFamily="@*android:string/config_headlineFontFamily"
+ android:layout_marginTop="22dp"
+ android:layout_marginBottom="15dp"/>
+ <Spinner
+ android:id="@+id/screen_share_mode_spinner"
+ android:layout_width="320dp"
+ android:layout_height="72dp"
+ android:layout_marginTop="24dp"
+ android:layout_marginBottom="24dp" />
+ <ViewStub
+ android:id="@+id/options_stub"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+ <TextView
+ android:id="@+id/text_warning"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/screenrecord_description"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:textColorSecondary"
+ android:gravity="start"
+ android:layout_marginBottom="20dp"/>
+
+ <!-- Buttons -->
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_marginTop="36dp">
+ <TextView
+ android:id="@+id/button_cancel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:text="@string/cancel"
+ style="@style/Widget.Dialog.Button.BorderButton" />
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"/>
+ <TextView
+ android:id="@+id/button_start"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:text="@string/screenrecord_start"
+ style="@style/Widget.Dialog.Button" />
+ </LinearLayout>
+ </LinearLayout>
+</ScrollView> \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
index 397bffcaa64c..22f91f359de8 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
@@ -18,6 +18,9 @@ package com.android.systemui.media;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+import static com.android.systemui.screenrecord.ScreenShareOptionKt.ENTIRE_SCREEN;
+import static com.android.systemui.screenrecord.ScreenShareOptionKt.SINGLE_APP;
+
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
@@ -44,6 +47,8 @@ import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
+import com.android.systemui.screenrecord.MediaProjectionPermissionDialog;
+import com.android.systemui.screenrecord.ScreenShareOption;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.util.Utils;
@@ -102,7 +107,9 @@ public class MediaProjectionPermissionActivity extends Activity
CharSequence dialogText = null;
CharSequence dialogTitle = null;
+ String appName = null;
if (Utils.isHeadlessRemoteDisplayProvider(packageManager, mPackageName)) {
+ // TODO(b/253438807): handle special app name
dialogText = getString(R.string.media_projection_dialog_service_text);
dialogTitle = getString(R.string.media_projection_dialog_service_title);
} else {
@@ -132,7 +139,7 @@ public class MediaProjectionPermissionActivity extends Activity
String unsanitizedAppName = TextUtils.ellipsize(label,
paint, MAX_APP_NAME_SIZE_PX, TextUtils.TruncateAt.END).toString();
- String appName = BidiFormatter.getInstance().unicodeWrap(unsanitizedAppName);
+ appName = BidiFormatter.getInstance().unicodeWrap(unsanitizedAppName);
String actionText = getString(R.string.media_projection_dialog_text, appName);
SpannableString message = new SpannableString(actionText);
@@ -146,27 +153,28 @@ public class MediaProjectionPermissionActivity extends Activity
dialogTitle = getString(R.string.media_projection_dialog_title, appName);
}
- AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this,
- R.style.Theme_SystemUI_Dialog)
- .setTitle(dialogTitle)
- .setIcon(R.drawable.ic_media_projection_permission)
- .setMessage(dialogText)
- .setPositiveButton(R.string.media_projection_action_text, this)
- .setNeutralButton(android.R.string.cancel, this)
- .setOnCancelListener(this);
-
if (isPartialScreenSharingEnabled()) {
- // This is a temporary entry point before we have a new permission dialog
- // TODO(b/233183090): this activity should be redesigned to have a dropdown selector
- dialogBuilder.setNegativeButton("App", this);
+ mDialog = new MediaProjectionPermissionDialog(this, () -> {
+ ScreenShareOption selectedOption =
+ ((MediaProjectionPermissionDialog) mDialog).getSelectedScreenShareOption();
+ grantMediaProjectionPermission(selectedOption.getMode());
+ }, appName);
+ } else {
+ AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this,
+ R.style.Theme_SystemUI_Dialog)
+ .setTitle(dialogTitle)
+ .setIcon(R.drawable.ic_media_projection_permission)
+ .setMessage(dialogText)
+ .setPositiveButton(R.string.media_projection_action_text, this)
+ .setNeutralButton(android.R.string.cancel, this);
+ mDialog = dialogBuilder.create();
}
- mDialog = dialogBuilder.create();
-
SystemUIDialog.registerDismissListener(mDialog);
SystemUIDialog.applyFlags(mDialog);
SystemUIDialog.setDialogSize(mDialog);
+ mDialog.setOnCancelListener(this);
mDialog.create();
mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setFilterTouchesWhenObscured(true);
@@ -186,12 +194,17 @@ public class MediaProjectionPermissionActivity extends Activity
@Override
public void onClick(DialogInterface dialog, int which) {
+ if (which == AlertDialog.BUTTON_POSITIVE) {
+ grantMediaProjectionPermission(ENTIRE_SCREEN);
+ }
+ }
+
+ private void grantMediaProjectionPermission(int screenShareMode) {
try {
- if (which == AlertDialog.BUTTON_POSITIVE) {
+ if (screenShareMode == ENTIRE_SCREEN) {
setResult(RESULT_OK, getMediaProjectionIntent(mUid, mPackageName));
}
-
- if (isPartialScreenSharingEnabled() && which == AlertDialog.BUTTON_NEGATIVE) {
+ if (isPartialScreenSharingEnabled() && screenShareMode == SINGLE_APP) {
IMediaProjection projection = createProjection(mUid, mPackageName);
final Intent intent = new Intent(this, MediaProjectionAppSelectorActivity.class);
intent.putExtra(MediaProjectionManager.EXTRA_MEDIA_PROJECTION,
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 f63f0444210b..64a8a146031b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles;
+import android.app.Dialog;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
@@ -43,7 +44,6 @@ import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.screenrecord.RecordingController;
-import com.android.systemui.screenrecord.ScreenRecordDialog;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -170,9 +170,9 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState>
mDialogLaunchAnimator.disableAllCurrentDialogsExitAnimations();
getHost().collapsePanels();
};
- ScreenRecordDialog dialog = mController.createScreenRecordDialog(mContext, mFlags,
- mDialogLaunchAnimator, mActivityStarter, onStartRecordingClicked);
+ Dialog dialog = mController.createScreenRecordDialog(mContext, mFlags,
+ mDialogLaunchAnimator, mActivityStarter, onStartRecordingClicked);
ActivityStarter.OnDismissAction dismissAction = () -> {
if (shouldAnimateFromView) {
mDialogLaunchAnimator.showFromView(dialog, view, new DialogCuj(
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/BaseScreenSharePermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/BaseScreenSharePermissionDialog.kt
new file mode 100644
index 000000000000..f4d59a8dd6a6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/BaseScreenSharePermissionDialog.kt
@@ -0,0 +1,110 @@
+/*
+ * 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.content.Context
+import android.os.Bundle
+import android.view.Gravity
+import android.view.View
+import android.view.ViewStub
+import android.view.WindowManager
+import android.widget.AdapterView
+import android.widget.ArrayAdapter
+import android.widget.Spinner
+import android.widget.TextView
+import androidx.annotation.LayoutRes
+import androidx.annotation.StringRes
+import com.android.systemui.R
+import com.android.systemui.statusbar.phone.SystemUIDialog
+
+/** Base permission dialog for screen share and recording */
+open class BaseScreenSharePermissionDialog(
+ context: Context?,
+ private val screenShareOptions: List<ScreenShareOption>,
+ private val appName: String?
+) : SystemUIDialog(context), AdapterView.OnItemSelectedListener {
+ private lateinit var dialogTitle: TextView
+ private lateinit var startButton: TextView
+ private lateinit var warning: TextView
+ private lateinit var screenShareModeSpinner: Spinner
+ var selectedScreenShareOption: ScreenShareOption = screenShareOptions.first()
+
+ public override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ window.apply {
+ addPrivateFlags(WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS)
+ setGravity(Gravity.CENTER)
+ }
+ setContentView(R.layout.screen_share_dialog)
+ dialogTitle = findViewById(R.id.screen_share_dialog_title)
+ warning = findViewById(R.id.text_warning)
+ startButton = findViewById(R.id.button_start)
+ findViewById<TextView>(R.id.button_cancel).setOnClickListener { dismiss() }
+ initScreenShareOptions()
+ createOptionsView(getOptionsViewLayoutId())
+ }
+
+ protected fun initScreenShareOptions() {
+ selectedScreenShareOption = screenShareOptions.first()
+ warning.text = warningText
+ initScreenShareSpinner()
+ }
+
+ private val warningText: String
+ get() = context.getString(selectedScreenShareOption.warningText, appName)
+
+ private fun initScreenShareSpinner() {
+ val options = screenShareOptions.map { context.getString(it.spinnerText) }.toTypedArray()
+ val adapter =
+ ArrayAdapter(context.applicationContext, android.R.layout.simple_spinner_item, options)
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
+ screenShareModeSpinner = findViewById(R.id.screen_share_mode_spinner)
+ screenShareModeSpinner.adapter = adapter
+ screenShareModeSpinner.onItemSelectedListener = this
+ }
+
+ override fun onItemSelected(adapterView: AdapterView<*>?, view: View, pos: Int, id: Long) {
+ selectedScreenShareOption = screenShareOptions[pos]
+ warning.text = warningText
+ }
+
+ override fun onNothingSelected(parent: AdapterView<*>?) {}
+
+ /** Protected methods for the text updates & functionality */
+ protected fun setDialogTitle(@StringRes stringId: Int) {
+ val title = context.getString(stringId, appName)
+ dialogTitle.text = title
+ }
+
+ protected fun setStartButtonText(@StringRes stringId: Int) {
+ startButton.setText(stringId)
+ }
+
+ protected fun setStartButtonOnClickListener(listener: View.OnClickListener?) {
+ startButton.setOnClickListener(listener)
+ }
+
+ // Create additional options that is shown under the share mode spinner
+ // Eg. the audio and tap toggles in SysUI Recorder
+ @LayoutRes protected open fun getOptionsViewLayoutId(): Int? = null
+
+ private fun createOptionsView(@LayoutRes layoutId: Int?) {
+ if (layoutId == null) return
+ val stub = findViewById<View>(R.id.options_stub) as ViewStub
+ stub.layoutResource = layoutId
+ stub.inflate()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/MediaProjectionPermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/MediaProjectionPermissionDialog.kt
new file mode 100644
index 000000000000..15b0bc4a356a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/MediaProjectionPermissionDialog.kt
@@ -0,0 +1,56 @@
+/*
+ * 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.content.Context
+import android.os.Bundle
+import com.android.systemui.R
+
+/** Dialog to select screen recording options */
+class MediaProjectionPermissionDialog(
+ context: Context?,
+ private val onStartRecordingClicked: Runnable,
+ appName: String?
+) : BaseScreenSharePermissionDialog(context, createOptionList(), appName) {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setDialogTitle(R.string.media_projection_permission_dialog_title)
+ setStartButtonText(R.string.media_projection_permission_dialog_continue)
+ setStartButtonOnClickListener {
+ // Note that it is important to run this callback before dismissing, so that the
+ // callback can disable the dialog exit animation if it wants to.
+ onStartRecordingClicked.run()
+ dismiss()
+ }
+ }
+
+ companion object {
+ private fun createOptionList(): List<ScreenShareOption> {
+ return listOf(
+ ScreenShareOption(
+ SINGLE_APP,
+ R.string.media_projection_permission_dialog_option_single_app,
+ R.string.media_projection_permission_dialog_warning_single_app
+ ),
+ ScreenShareOption(
+ ENTIRE_SCREEN,
+ R.string.media_projection_permission_dialog_option_entire_screen,
+ R.string.media_projection_permission_dialog_warning_entire_screen
+ )
+ )
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
index 1083f22164d9..ce4e0ecee914 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
@@ -16,6 +16,7 @@
package com.android.systemui.screenrecord;
+import android.app.Dialog;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -33,6 +34,7 @@ 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.flags.Flags;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.statusbar.policy.CallbackController;
@@ -97,11 +99,15 @@ public class RecordingController
}
/** Create a dialog to show screen recording options to the user. */
- public ScreenRecordDialog createScreenRecordDialog(Context context, FeatureFlags flags,
- DialogLaunchAnimator dialogLaunchAnimator, ActivityStarter activityStarter,
- @Nullable Runnable onStartRecordingClicked) {
- return new ScreenRecordDialog(context, this, activityStarter, mUserContextProvider,
- flags, dialogLaunchAnimator, onStartRecordingClicked);
+ public Dialog createScreenRecordDialog(Context context, FeatureFlags flags,
+ DialogLaunchAnimator dialogLaunchAnimator,
+ ActivityStarter activityStarter,
+ @Nullable Runnable onStartRecordingClicked) {
+ return flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING)
+ ? new ScreenRecordPermissionDialog(context, this, activityStarter,
+ dialogLaunchAnimator, mUserContextProvider, onStartRecordingClicked)
+ : new ScreenRecordDialog(context, this, activityStarter,
+ mUserContextProvider, flags, dialogLaunchAnimator, onStartRecordingClicked);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
new file mode 100644
index 000000000000..cffd28f9fc96
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
@@ -0,0 +1,173 @@
+/*
+ * 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.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.View
+import android.widget.AdapterView
+import android.widget.AdapterView.OnItemClickListener
+import android.widget.ArrayAdapter
+import android.widget.Spinner
+import android.widget.Switch
+import androidx.annotation.LayoutRes
+import com.android.systemui.R
+import com.android.systemui.animation.DialogLaunchAnimator
+import com.android.systemui.media.MediaProjectionAppSelectorActivity
+import com.android.systemui.media.MediaProjectionCaptureTarget
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.settings.UserContextProvider
+
+/** Dialog to select screen recording options */
+class ScreenRecordPermissionDialog(
+ context: Context?,
+ private val controller: RecordingController,
+ private val activityStarter: ActivityStarter,
+ private val dialogLaunchAnimator: DialogLaunchAnimator,
+ private val userContextProvider: UserContextProvider,
+ private val onStartRecordingClicked: Runnable?
+) : BaseScreenSharePermissionDialog(context, createOptionList(), null) {
+ private lateinit var tapsSwitch: Switch
+ private lateinit var audioSwitch: Switch
+ private lateinit var options: Spinner
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setDialogTitle(R.string.screenrecord_start_label)
+ setStartButtonText(R.string.screenrecord_start_recording)
+ setStartButtonOnClickListener { v: View? ->
+ onStartRecordingClicked?.run()
+ if (selectedScreenShareOption.mode == ENTIRE_SCREEN) {
+ requestScreenCapture(/* captureTarget= */ null)
+ }
+ if (selectedScreenShareOption.mode == SINGLE_APP) {
+ val intent = Intent(context, MediaProjectionAppSelectorActivity::class.java)
+ 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(
+ MediaProjectionAppSelectorActivity.EXTRA_CAPTURE_REGION_RESULT_RECEIVER,
+ CaptureTargetResultReceiver()
+ )
+ val animationController = dialogLaunchAnimator.createActivityLaunchController(v!!)
+ if (animationController == null) {
+ dismiss()
+ }
+ activityStarter.startActivity(intent, /* dismissShade= */ true, animationController)
+ }
+ dismiss()
+ }
+ initRecordOptionsView()
+ }
+
+ @LayoutRes override fun getOptionsViewLayoutId(): Int = R.layout.screen_record_options
+
+ private fun initRecordOptionsView() {
+ audioSwitch = findViewById(R.id.screenrecord_audio_switch)
+ tapsSwitch = findViewById(R.id.screenrecord_taps_switch)
+ options = findViewById(R.id.screen_recording_options)
+ val a: ArrayAdapter<*> =
+ ScreenRecordingAdapter(context, android.R.layout.simple_spinner_dropdown_item, MODES)
+ a.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
+ options.adapter = a
+ options.setOnItemClickListenerInt(
+ OnItemClickListener { _: AdapterView<*>?, _: View?, _: Int, _: Long ->
+ audioSwitch.isChecked = true
+ }
+ )
+ }
+
+ /**
+ * 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 fun requestScreenCapture(captureTarget: MediaProjectionCaptureTarget?) {
+ val userContext = userContextProvider.userContext
+ val showTaps = tapsSwitch.isChecked
+ val audioMode =
+ if (audioSwitch.isChecked) options.selectedItem as ScreenRecordingAudioSource
+ else ScreenRecordingAudioSource.NONE
+ val startIntent =
+ PendingIntent.getForegroundService(
+ userContext,
+ RecordingService.REQUEST_CODE,
+ RecordingService.getStartIntent(
+ userContext,
+ Activity.RESULT_OK,
+ audioMode.ordinal,
+ showTaps,
+ captureTarget
+ ),
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
+ )
+ val stopIntent =
+ PendingIntent.getService(
+ userContext,
+ RecordingService.REQUEST_CODE,
+ RecordingService.getStopIntent(userContext),
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
+ )
+ controller.startCountdown(DELAY_MS, INTERVAL_MS, startIntent, stopIntent)
+ }
+
+ private inner class CaptureTargetResultReceiver() :
+ ResultReceiver(Handler(Looper.getMainLooper())) {
+ override fun onReceiveResult(resultCode: Int, resultData: Bundle) {
+ if (resultCode == Activity.RESULT_OK) {
+ val captureTarget =
+ resultData.getParcelable(
+ MediaProjectionAppSelectorActivity.KEY_CAPTURE_TARGET,
+ MediaProjectionCaptureTarget::class.java
+ )
+
+ // Start recording of the selected target
+ requestScreenCapture(captureTarget)
+ }
+ }
+ }
+
+ companion object {
+ private val MODES =
+ listOf(
+ ScreenRecordingAudioSource.INTERNAL,
+ ScreenRecordingAudioSource.MIC,
+ ScreenRecordingAudioSource.MIC_AND_INTERNAL
+ )
+ private const val DELAY_MS: Long = 3000
+ private const val INTERVAL_MS: Long = 1000
+ private fun createOptionList(): List<ScreenShareOption> {
+ return listOf(
+ ScreenShareOption(
+ SINGLE_APP,
+ R.string.screenrecord_option_single_app,
+ R.string.screenrecord_warning_single_app
+ ),
+ ScreenShareOption(
+ ENTIRE_SCREEN,
+ R.string.screenrecord_option_entire_screen,
+ R.string.screenrecord_warning_entire_screen
+ )
+ )
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenShareOption.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenShareOption.kt
new file mode 100644
index 000000000000..914d29a52b53
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenShareOption.kt
@@ -0,0 +1,33 @@
+/*
+ * 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 androidx.annotation.IntDef
+import androidx.annotation.StringRes
+import kotlin.annotation.Retention
+
+@Retention(AnnotationRetention.SOURCE)
+@IntDef(SINGLE_APP, ENTIRE_SCREEN)
+annotation class ScreenShareMode
+
+const val SINGLE_APP = 0
+const val ENTIRE_SCREEN = 1
+
+class ScreenShareOption(
+ @ScreenShareMode val mode: Int,
+ @StringRes val spinnerText: Int,
+ @StringRes val warningText: Int
+)