1package com.android.packageinstaller.permission.ui;
2
3import android.app.AlertDialog;
4import android.app.Dialog;
5import android.content.Context;
6import android.content.DialogInterface;
7import android.content.res.TypedArray;
8import android.graphics.drawable.Drawable;
9import android.graphics.drawable.Icon;
10import android.graphics.PixelFormat;
11import android.graphics.PorterDuff;
12import android.os.Bundle;
13import android.support.wearable.view.AcceptDenyDialog;
14import android.support.wearable.view.WearableDialogHelper;
15import android.text.SpannableStringBuilder;
16import android.text.Spanned;
17import android.text.style.ImageSpan;
18import android.text.style.TextAppearanceSpan;
19import android.text.TextUtils;
20import android.util.Log;
21import android.view.LayoutInflater;
22import android.view.View;
23import android.view.WindowManager;
24import android.widget.Space;
25
26import com.android.packageinstaller.R;
27
28/**
29 * Watch-specific view handler for the grant permissions activity.
30 */
31final 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