1 package com.android.packageinstaller.permission.ui; 2 3 import android.app.AlertDialog; 4 import android.app.Dialog; 5 import android.content.Context; 6 import android.content.DialogInterface; 7 import android.content.res.TypedArray; 8 import android.graphics.drawable.Drawable; 9 import android.graphics.drawable.Icon; 10 import android.graphics.PixelFormat; 11 import android.graphics.PorterDuff; 12 import android.os.Bundle; 13 import android.support.wearable.view.AcceptDenyDialog; 14 import android.support.wearable.view.WearableDialogHelper; 15 import android.text.SpannableStringBuilder; 16 import android.text.Spanned; 17 import android.text.style.ImageSpan; 18 import android.text.style.TextAppearanceSpan; 19 import android.text.TextUtils; 20 import android.util.Log; 21 import android.view.LayoutInflater; 22 import android.view.View; 23 import android.view.WindowManager; 24 import android.widget.Space; 25 26 import com.android.packageinstaller.R; 27 28 /** 29 * Watch-specific view handler for the grant permissions activity. 30 */ 31 final class GrantPermissionsWatchViewHandler implements GrantPermissionsViewHandler, 32 DialogInterface.OnClickListener { 33 private static final String TAG = "GrantPermsWatchViewH"; 34 35 private static final String WATCH_HANDLER_BUNDLE = "watch_handler_bundle"; 36 private static final String DIALOG_BUNDLE = "dialog_bundle"; 37 private static final String GROUP_NAME = "group_name"; 38 private static final String SHOW_DO_NOT_ASK = "show_do_not_ask"; 39 private static final String ICON = "icon"; 40 private static final String MESSAGE = "message"; 41 private static final String CURRENT_PAGE_TEXT = "current_page_text"; 42 43 private final Context mContext; 44 45 private ResultListener mResultListener; 46 47 private Dialog mDialog; 48 49 private String mGroupName; 50 private boolean mShowDoNotAsk; 51 52 private CharSequence mMessage; 53 private String mCurrentPageText; 54 private Icon mIcon; 55 56 GrantPermissionsWatchViewHandler(Context context) { 57 mContext = context; 58 } 59 60 @Override 61 public GrantPermissionsWatchViewHandler setResultListener(ResultListener listener) { 62 mResultListener = listener; 63 return this; 64 } 65 66 @Override 67 public View createView() { 68 return new Space(mContext); 69 } 70 71 @Override 72 public void updateWindowAttributes(WindowManager.LayoutParams outLayoutParams) { 73 outLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; 74 outLayoutParams.height = WindowManager.LayoutParams.MATCH_PARENT; 75 outLayoutParams.format = PixelFormat.OPAQUE; 76 outLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; 77 outLayoutParams.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; 78 } 79 80 @Override 81 public void updateUi(String groupName, int groupCount, int groupIndex, Icon icon, 82 CharSequence message, boolean showDoNotAsk) { 83 if (Log.isLoggable(TAG, Log.DEBUG)) { 84 Log.d(TAG, "updateUi() - groupName: " + groupName 85 + ", groupCount: " + groupCount 86 + ", groupIndex: " + groupIndex 87 + ", icon: " + icon 88 + ", message: " + message 89 + ", showDoNotAsk: " + showDoNotAsk); 90 } 91 92 mGroupName = groupName; 93 mShowDoNotAsk = showDoNotAsk; 94 mMessage = message; 95 mIcon = icon; 96 mCurrentPageText = groupCount > 1 97 ? mContext.getString(R.string.current_permission_template, 98 groupIndex + 1, groupCount) 99 : null; 100 showDialog(null); 101 } 102 103 private void showDialog(Bundle savedInstanceState) { 104 TypedArray a = mContext.obtainStyledAttributes( 105 new int[] { android.R.attr.textColorPrimary }); 106 int color = a.getColor(0, mContext.getColor(android.R.color.white)); 107 a.recycle(); 108 Drawable drawable = mIcon == null ? null : mIcon.setTint(color).loadDrawable(mContext); 109 110 SpannableStringBuilder ssb = new SpannableStringBuilder(); 111 if (!TextUtils.isEmpty(mCurrentPageText)) { 112 ssb.append(mCurrentPageText, new TextAppearanceSpan(mContext, R.style.BreadcrumbText), 113 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 114 ssb.append('\n'); 115 } 116 if (!TextUtils.isEmpty(mMessage)) { 117 ssb.append(mMessage, new TextAppearanceSpan(mContext, R.style.TitleText), 118 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 119 } 120 121 if (mDialog != null) { 122 mDialog.dismiss(); 123 mDialog = null; 124 } 125 126 if (mShowDoNotAsk) { 127 AlertDialog alertDialog = new WearableDialogHelper.DialogBuilder(mContext) 128 .setPositiveIcon(R.drawable.confirm_button) 129 .setNeutralIcon(R.drawable.cancel_button) 130 .setNegativeIcon(R.drawable.deny_button) 131 .setTitle(ssb) 132 .setIcon(drawable) 133 .setPositiveButton(R.string.grant_dialog_button_allow, this) 134 .setNeutralButton(R.string.grant_dialog_button_deny, this) 135 .setNegativeButton(R.string.grant_dialog_button_deny_dont_ask_again, this) 136 .show(); 137 alertDialog.getButton(DialogInterface.BUTTON_POSITIVE) 138 .setId(R.id.permission_allow_button); 139 alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL) 140 .setId(R.id.permission_deny_button); 141 alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE) 142 .setId(R.id.permission_deny_dont_ask_again_button); 143 144 mDialog = alertDialog; 145 } else { 146 AcceptDenyDialog acceptDenyDialog = new AcceptDenyDialog(mContext); 147 acceptDenyDialog.setTitle(ssb); 148 acceptDenyDialog.setIcon(drawable); 149 acceptDenyDialog.setPositiveButton(this); 150 acceptDenyDialog.setNegativeButton(this); 151 acceptDenyDialog.show(); 152 acceptDenyDialog.getButton(DialogInterface.BUTTON_POSITIVE) 153 .setId(R.id.permission_allow_button); 154 acceptDenyDialog.getButton(DialogInterface.BUTTON_NEGATIVE) 155 .setId(R.id.permission_deny_button); 156 157 mDialog = acceptDenyDialog; 158 } 159 mDialog.setCancelable(false); 160 161 if (savedInstanceState != null) { 162 mDialog.onRestoreInstanceState(savedInstanceState); 163 } 164 } 165 166 @Override 167 public void saveInstanceState(Bundle outState) { 168 Bundle b = new Bundle(); 169 b.putByte(SHOW_DO_NOT_ASK, (byte) (mShowDoNotAsk ? 1 : 0)); 170 b.putString(GROUP_NAME, mGroupName); 171 b.putBundle(DIALOG_BUNDLE, mDialog.onSaveInstanceState()); 172 173 outState.putBundle(WATCH_HANDLER_BUNDLE, b); 174 } 175 176 @Override 177 public void loadInstanceState(Bundle savedInstanceState) { 178 Bundle b = savedInstanceState.getBundle(WATCH_HANDLER_BUNDLE); 179 mShowDoNotAsk = b.getByte(SHOW_DO_NOT_ASK) == 1; 180 mGroupName = b.getString(GROUP_NAME); 181 showDialog(b.getBundle(DIALOG_BUNDLE)); 182 } 183 184 @Override 185 public void onBackPressed() { 186 notifyListener(false, false); 187 } 188 189 @Override 190 public void onClick(DialogInterface dialog, int which) { 191 switch (which) { 192 case DialogInterface.BUTTON_POSITIVE: 193 notifyListener(true, false); 194 break; 195 case DialogInterface.BUTTON_NEUTRAL: 196 notifyListener(false, false); 197 break; 198 case DialogInterface.BUTTON_NEGATIVE: 199 notifyListener(false, 200 /* In AlertDialog, the negative button is also a don't ask again button. */ 201 dialog instanceof AlertDialog); 202 break; 203 } 204 } 205 206 private void notifyListener(boolean granted, boolean doNotAskAgain) { 207 if (mResultListener != null) { 208 mResultListener.onPermissionGrantResult(mGroupName, granted, doNotAskAgain); 209 } 210 } 211 } 212