blob: 9f0f53e0d50886086b3af8693042d700ed8e5067 [file] [log] [blame]
Michael Wrightc39d47a2014-07-08 18:07:36 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui.media;
18
Philip P. Moltmann66ce2382018-10-09 13:46:11 -070019import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
Wale Ogunwaled6bb8e92018-05-16 16:42:29 -070020
Adrian Roos752aee82014-11-25 21:11:19 +010021import android.app.Activity;
Michael Wrightc39d47a2014-07-08 18:07:36 -070022import android.app.AlertDialog;
Michael Wrightc39d47a2014-07-08 18:07:36 -070023import android.content.DialogInterface;
24import android.content.Intent;
25import android.content.pm.ApplicationInfo;
26import android.content.pm.PackageManager;
Michael Wright58950a92015-08-25 00:00:05 +010027import android.graphics.Typeface;
Michael Wrightc39d47a2014-07-08 18:07:36 -070028import android.media.projection.IMediaProjection;
Winsonc0d70582016-01-29 10:24:39 -080029import android.media.projection.IMediaProjectionManager;
30import android.media.projection.MediaProjectionManager;
Michael Wrightc39d47a2014-07-08 18:07:36 -070031import android.os.Bundle;
32import android.os.IBinder;
33import android.os.RemoteException;
34import android.os.ServiceManager;
Michael Wright58950a92015-08-25 00:00:05 +010035import android.text.BidiFormatter;
Michael Wright58950a92015-08-25 00:00:05 +010036import android.text.SpannableString;
37import android.text.TextPaint;
38import android.text.TextUtils;
39import android.text.style.StyleSpan;
Michael Wrightc39d47a2014-07-08 18:07:36 -070040import android.util.Log;
Wale Ogunwaled6bb8e92018-05-16 16:42:29 -070041import android.view.Window;
Adrian Roos752aee82014-11-25 21:11:19 +010042import android.view.WindowManager;
Winsonc0d70582016-01-29 10:24:39 -080043
Michael Wrightc39d47a2014-07-08 18:07:36 -070044import com.android.systemui.R;
45
Adrian Roos752aee82014-11-25 21:11:19 +010046public class MediaProjectionPermissionActivity extends Activity
Narayan Kamathcc52e822019-02-19 18:42:56 +000047 implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
Michael Wrightc39d47a2014-07-08 18:07:36 -070048 private static final String TAG = "MediaProjectionPermissionActivity";
Michael Wright58950a92015-08-25 00:00:05 +010049 private static final float MAX_APP_NAME_SIZE_PX = 500f;
50 private static final String ELLIPSIS = "\u2026";
Michael Wrightc39d47a2014-07-08 18:07:36 -070051
Michael Wrightc39d47a2014-07-08 18:07:36 -070052 private String mPackageName;
53 private int mUid;
54 private IMediaProjectionManager mService;
55
Adrian Roos752aee82014-11-25 21:11:19 +010056 private AlertDialog mDialog;
57
Michael Wrightc39d47a2014-07-08 18:07:36 -070058 @Override
59 public void onCreate(Bundle icicle) {
60 super.onCreate(icicle);
61
Michael Wrightc39d47a2014-07-08 18:07:36 -070062 mPackageName = getCallingPackage();
63 IBinder b = ServiceManager.getService(MEDIA_PROJECTION_SERVICE);
64 mService = IMediaProjectionManager.Stub.asInterface(b);
65
66 if (mPackageName == null) {
67 finish();
68 return;
69 }
70
71 PackageManager packageManager = getPackageManager();
72 ApplicationInfo aInfo;
73 try {
74 aInfo = packageManager.getApplicationInfo(mPackageName, 0);
75 mUid = aInfo.uid;
76 } catch (PackageManager.NameNotFoundException e) {
77 Log.e(TAG, "unable to look up package name", e);
78 finish();
79 return;
80 }
81
82 try {
83 if (mService.hasProjectionPermission(mUid, mPackageName)) {
Narayan Kamathcc52e822019-02-19 18:42:56 +000084 setResult(RESULT_OK, getMediaProjectionIntent(mUid, mPackageName));
Michael Wrightc39d47a2014-07-08 18:07:36 -070085 finish();
86 return;
87 }
88 } catch (RemoteException e) {
89 Log.e(TAG, "Error checking projection permissions", e);
90 finish();
91 return;
92 }
93
Michael Wright58950a92015-08-25 00:00:05 +010094 TextPaint paint = new TextPaint();
95 paint.setTextSize(42);
96
97 String label = aInfo.loadLabel(packageManager).toString();
98
99 // If the label contains new line characters it may push the security
100 // message below the fold of the dialog. Labels shouldn't have new line
101 // characters anyways, so just truncate the message the first time one
102 // is seen.
103 final int labelLength = label.length();
104 int offset = 0;
105 while (offset < labelLength) {
106 final int codePoint = label.codePointAt(offset);
107 final int type = Character.getType(codePoint);
108 if (type == Character.LINE_SEPARATOR
109 || type == Character.CONTROL
110 || type == Character.PARAGRAPH_SEPARATOR) {
111 label = label.substring(0, offset) + ELLIPSIS;
112 break;
113 }
114 offset += Character.charCount(codePoint);
115 }
116
117 if (label.isEmpty()) {
118 label = mPackageName;
119 }
120
121 String unsanitizedAppName = TextUtils.ellipsize(label,
122 paint, MAX_APP_NAME_SIZE_PX, TextUtils.TruncateAt.END).toString();
123 String appName = BidiFormatter.getInstance().unicodeWrap(unsanitizedAppName);
124
125 String actionText = getString(R.string.media_projection_dialog_text, appName);
126 SpannableString message = new SpannableString(actionText);
127
128 int appNameIndex = actionText.indexOf(appName);
129 if (appNameIndex >= 0) {
130 message.setSpan(new StyleSpan(Typeface.BOLD),
131 appNameIndex, appNameIndex + appName.length(), 0);
132 }
Michael Wrightc39d47a2014-07-08 18:07:36 -0700133
Narayan Kamathcc52e822019-02-19 18:42:56 +0000134 String dialogTitle = getString(R.string.media_projection_dialog_title, appName);
135
Adrian Roos752aee82014-11-25 21:11:19 +0100136 mDialog = new AlertDialog.Builder(this)
Narayan Kamathcc52e822019-02-19 18:42:56 +0000137 .setTitle(dialogTitle)
Narayan Kamathac3af3d2019-03-04 14:28:27 +0000138 .setIcon(R.drawable.ic_media_projection_permission)
Michael Wright58950a92015-08-25 00:00:05 +0100139 .setMessage(message)
Adrian Roos752aee82014-11-25 21:11:19 +0100140 .setPositiveButton(R.string.media_projection_action_text, this)
141 .setNegativeButton(android.R.string.cancel, this)
Adrian Roos752aee82014-11-25 21:11:19 +0100142 .setOnCancelListener(this)
143 .create();
Michael Wrightc39d47a2014-07-08 18:07:36 -0700144
Adrian Roos752aee82014-11-25 21:11:19 +0100145 mDialog.create();
Dongwon Kangb0cf7ea2015-06-08 13:43:07 -0700146 mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setFilterTouchesWhenObscured(true);
Michael Wrightc39d47a2014-07-08 18:07:36 -0700147
Wale Ogunwaled6bb8e92018-05-16 16:42:29 -0700148 final Window w = mDialog.getWindow();
149 w.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
Philip P. Moltmann66ce2382018-10-09 13:46:11 -0700150 w.addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
Adrian Roos752aee82014-11-25 21:11:19 +0100151
152 mDialog.show();
153 }
154
155 @Override
156 protected void onDestroy() {
157 super.onDestroy();
John Spurlock3d332f42015-02-24 12:14:06 -0500158 if (mDialog != null) {
159 mDialog.dismiss();
160 }
Michael Wrightc39d47a2014-07-08 18:07:36 -0700161 }
162
163 @Override
164 public void onClick(DialogInterface dialog, int which) {
165 try {
166 if (which == AlertDialog.BUTTON_POSITIVE) {
Narayan Kamathcc52e822019-02-19 18:42:56 +0000167 setResult(RESULT_OK, getMediaProjectionIntent(mUid, mPackageName));
Michael Wrightc39d47a2014-07-08 18:07:36 -0700168 }
169 } catch (RemoteException e) {
170 Log.e(TAG, "Error granting projection permission", e);
171 setResult(RESULT_CANCELED);
172 } finally {
John Spurlock3d332f42015-02-24 12:14:06 -0500173 if (mDialog != null) {
174 mDialog.dismiss();
175 }
Michael Wrightc39d47a2014-07-08 18:07:36 -0700176 finish();
177 }
178 }
179
Narayan Kamathcc52e822019-02-19 18:42:56 +0000180 private Intent getMediaProjectionIntent(int uid, String packageName)
Michael Wrightc39d47a2014-07-08 18:07:36 -0700181 throws RemoteException {
182 IMediaProjection projection = mService.createProjection(uid, packageName,
Narayan Kamathcc52e822019-02-19 18:42:56 +0000183 MediaProjectionManager.TYPE_SCREEN_CAPTURE, false /* permanentGrant */);
Michael Wrightc39d47a2014-07-08 18:07:36 -0700184 Intent intent = new Intent();
185 intent.putExtra(MediaProjectionManager.EXTRA_MEDIA_PROJECTION, projection.asBinder());
186 return intent;
187 }
Adrian Roos752aee82014-11-25 21:11:19 +0100188
189 @Override
190 public void onCancel(DialogInterface dialog) {
191 finish();
192 }
Michael Wrightc39d47a2014-07-08 18:07:36 -0700193}