1c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright/* 2c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * Copyright (C) 2014 The Android Open Source Project 3c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * 4c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * Licensed under the Apache License, Version 2.0 (the "License"); 5c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * you may not use this file except in compliance with the License. 6c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * You may obtain a copy of the License at 7c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * 8c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * http://www.apache.org/licenses/LICENSE-2.0 9c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * 10c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * Unless required by applicable law or agreed to in writing, software 11c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * distributed under the License is distributed on an "AS IS" BASIS, 12c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * See the License for the specific language governing permissions and 14c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * limitations under the License. 15c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright */ 16c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright 17c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightpackage com.android.systemui.media; 18c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright 19752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roosimport android.app.Activity; 20c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.app.AlertDialog; 21c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.content.DialogInterface; 22c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.content.Intent; 23c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.content.pm.ApplicationInfo; 24c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.content.pm.PackageManager; 2558950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wrightimport android.graphics.Typeface; 26c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.media.projection.IMediaProjection; 27c0d7058b14c24cd07912f5629c26b39b7b4673d5Winsonimport android.media.projection.IMediaProjectionManager; 28c0d7058b14c24cd07912f5629c26b39b7b4673d5Winsonimport android.media.projection.MediaProjectionManager; 29c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.os.Bundle; 30c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.os.IBinder; 31c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.os.RemoteException; 32c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.os.ServiceManager; 3358950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wrightimport android.text.BidiFormatter; 3458950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wrightimport android.text.SpannableString; 3558950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wrightimport android.text.TextPaint; 3658950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wrightimport android.text.TextUtils; 3758950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wrightimport android.text.style.StyleSpan; 38c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.util.Log; 39752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roosimport android.view.WindowManager; 40c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.widget.CheckBox; 41c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.widget.CompoundButton; 42c0d7058b14c24cd07912f5629c26b39b7b4673d5Winson 43c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport com.android.systemui.R; 44c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright 45752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roospublic class MediaProjectionPermissionActivity extends Activity 46752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos implements DialogInterface.OnClickListener, CheckBox.OnCheckedChangeListener, 47752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos DialogInterface.OnCancelListener { 48c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright private static final String TAG = "MediaProjectionPermissionActivity"; 4958950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright private static final float MAX_APP_NAME_SIZE_PX = 500f; 5058950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright private static final String ELLIPSIS = "\u2026"; 51c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright 52c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright private boolean mPermanentGrant; 53c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright private String mPackageName; 54c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright private int mUid; 55c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright private IMediaProjectionManager mService; 56c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright 57752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos private AlertDialog mDialog; 58752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos 59c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright @Override 60c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright public void onCreate(Bundle icicle) { 61c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright super.onCreate(icicle); 62c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright 63c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright mPackageName = getCallingPackage(); 64c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright IBinder b = ServiceManager.getService(MEDIA_PROJECTION_SERVICE); 65c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright mService = IMediaProjectionManager.Stub.asInterface(b); 66c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright 67c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright if (mPackageName == null) { 68c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright finish(); 69c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright return; 70c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright } 71c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright 72c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright PackageManager packageManager = getPackageManager(); 73c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright ApplicationInfo aInfo; 74c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright try { 75c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright aInfo = packageManager.getApplicationInfo(mPackageName, 0); 76c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright mUid = aInfo.uid; 77c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright } catch (PackageManager.NameNotFoundException e) { 78c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright Log.e(TAG, "unable to look up package name", e); 79c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright finish(); 80c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright return; 81c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright } 82c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright 83c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright try { 84c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright if (mService.hasProjectionPermission(mUid, mPackageName)) { 85c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright setResult(RESULT_OK, getMediaProjectionIntent(mUid, mPackageName, 86c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright false /*permanentGrant*/)); 87c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright finish(); 88c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright return; 89c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright } 90c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright } catch (RemoteException e) { 91c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright Log.e(TAG, "Error checking projection permissions", e); 92c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright finish(); 93c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright return; 94c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright } 95c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright 9658950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright TextPaint paint = new TextPaint(); 9758950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright paint.setTextSize(42); 9858950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright 9958950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright String label = aInfo.loadLabel(packageManager).toString(); 10058950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright 10158950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright // If the label contains new line characters it may push the security 10258950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright // message below the fold of the dialog. Labels shouldn't have new line 10358950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright // characters anyways, so just truncate the message the first time one 10458950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright // is seen. 10558950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright final int labelLength = label.length(); 10658950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright int offset = 0; 10758950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright while (offset < labelLength) { 10858950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright final int codePoint = label.codePointAt(offset); 10958950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright final int type = Character.getType(codePoint); 11058950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright if (type == Character.LINE_SEPARATOR 11158950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright || type == Character.CONTROL 11258950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright || type == Character.PARAGRAPH_SEPARATOR) { 11358950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright label = label.substring(0, offset) + ELLIPSIS; 11458950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright break; 11558950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright } 11658950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright offset += Character.charCount(codePoint); 11758950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright } 11858950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright 11958950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright if (label.isEmpty()) { 12058950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright label = mPackageName; 12158950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright } 12258950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright 12358950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright String unsanitizedAppName = TextUtils.ellipsize(label, 12458950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright paint, MAX_APP_NAME_SIZE_PX, TextUtils.TruncateAt.END).toString(); 12558950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright String appName = BidiFormatter.getInstance().unicodeWrap(unsanitizedAppName); 12658950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright 12758950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright String actionText = getString(R.string.media_projection_dialog_text, appName); 12858950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright SpannableString message = new SpannableString(actionText); 12958950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright 13058950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright int appNameIndex = actionText.indexOf(appName); 13158950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright if (appNameIndex >= 0) { 13258950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright message.setSpan(new StyleSpan(Typeface.BOLD), 13358950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright appNameIndex, appNameIndex + appName.length(), 0); 13458950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright } 135c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright 136752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos mDialog = new AlertDialog.Builder(this) 137752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos .setIcon(aInfo.loadIcon(packageManager)) 13858950a9476070b47bc0f2ae93e7a24ab0444c3f3Michael Wright .setMessage(message) 139752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos .setPositiveButton(R.string.media_projection_action_text, this) 140752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos .setNegativeButton(android.R.string.cancel, this) 141752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos .setView(R.layout.remember_permission_checkbox) 142752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos .setOnCancelListener(this) 143752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos .create(); 144752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos 145752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos mDialog.create(); 146b0cf7ea65df8aad45556d2336e9ebae7d6da94b4Dongwon Kang mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setFilterTouchesWhenObscured(true); 147752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos 148752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos ((CheckBox) mDialog.findViewById(R.id.remember)).setOnCheckedChangeListener(this); 149752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 150752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos 151752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos mDialog.show(); 152752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos } 153752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos 154752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos @Override 155752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos protected void onDestroy() { 156752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos super.onDestroy(); 1573d332f4e67a484abe597576bf329d89655afe720John Spurlock if (mDialog != null) { 1583d332f4e67a484abe597576bf329d89655afe720John Spurlock mDialog.dismiss(); 1593d332f4e67a484abe597576bf329d89655afe720John Spurlock } 160c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright } 161c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright 162c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright @Override 163c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright public void onClick(DialogInterface dialog, int which) { 164c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright try { 165c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright if (which == AlertDialog.BUTTON_POSITIVE) { 166c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright setResult(RESULT_OK, getMediaProjectionIntent( 167c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright mUid, mPackageName, mPermanentGrant)); 168c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright } 169c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright } catch (RemoteException e) { 170c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright Log.e(TAG, "Error granting projection permission", e); 171c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright setResult(RESULT_CANCELED); 172c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright } finally { 1733d332f4e67a484abe597576bf329d89655afe720John Spurlock if (mDialog != null) { 1743d332f4e67a484abe597576bf329d89655afe720John Spurlock mDialog.dismiss(); 1753d332f4e67a484abe597576bf329d89655afe720John Spurlock } 176c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright finish(); 177c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright } 178c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright } 179c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright 180c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright @Override 181c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 182c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright mPermanentGrant = isChecked; 183c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright } 184c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright 185c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright private Intent getMediaProjectionIntent(int uid, String packageName, boolean permanentGrant) 186c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright throws RemoteException { 187c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright IMediaProjection projection = mService.createProjection(uid, packageName, 188c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright MediaProjectionManager.TYPE_SCREEN_CAPTURE, permanentGrant); 189c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright Intent intent = new Intent(); 190c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright intent.putExtra(MediaProjectionManager.EXTRA_MEDIA_PROJECTION, projection.asBinder()); 191c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright return intent; 192c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright } 193752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos 194752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos @Override 195752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos public void onCancel(DialogInterface dialog) { 196752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos finish(); 197752aee8a6f868011dea1d1bb4f582a2531d76d47Adrian Roos } 198c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright} 199