• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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 
17 package com.android.permissioncontroller.permission.ui.handheld;
18 
19 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.ALLOW_ALWAYS_BUTTON;
20 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.ALLOW_BUTTON;
21 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.ALLOW_FOREGROUND_BUTTON;
22 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.ALLOW_ONE_TIME_BUTTON;
23 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.DENY_AND_DONT_ASK_AGAIN_BUTTON;
24 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.DENY_BUTTON;
25 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON;
26 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.NO_UPGRADE_BUTTON;
27 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.NO_UPGRADE_OT_AND_DONT_ASK_AGAIN_BUTTON;
28 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.NO_UPGRADE_OT_BUTTON;
29 
30 import android.app.Activity;
31 import android.graphics.drawable.Icon;
32 import android.os.Bundle;
33 import android.os.UserHandle;
34 import android.text.method.LinkMovementMethod;
35 import android.transition.ChangeBounds;
36 import android.transition.TransitionManager;
37 import android.util.SparseArray;
38 import android.view.LayoutInflater;
39 import android.view.View;
40 import android.view.View.OnClickListener;
41 import android.view.ViewGroup;
42 import android.view.WindowManager.LayoutParams;
43 import android.view.accessibility.AccessibilityNodeInfo;
44 import android.view.animation.AnimationUtils;
45 import android.widget.Button;
46 import android.widget.ImageView;
47 import android.widget.TextView;
48 
49 import androidx.annotation.NonNull;
50 
51 import com.android.permissioncontroller.R;
52 import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity;
53 import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler;
54 
55 public class GrantPermissionsViewHandlerImpl implements GrantPermissionsViewHandler,
56         OnClickListener {
57 
58     public static final String ARG_GROUP_NAME = "ARG_GROUP_NAME";
59     public static final String ARG_GROUP_COUNT = "ARG_GROUP_COUNT";
60     public static final String ARG_GROUP_INDEX = "ARG_GROUP_INDEX";
61     public static final String ARG_GROUP_ICON = "ARG_GROUP_ICON";
62     public static final String ARG_GROUP_MESSAGE = "ARG_GROUP_MESSAGE";
63     private static final String ARG_GROUP_DETAIL_MESSAGE = "ARG_GROUP_DETAIL_MESSAGE";
64     private static final String ARG_DIALOG_BUTTON_VISIBILITIES = "ARG_DIALOG_BUTTON_VISIBILITIES";
65 
66     // Animation parameters.
67     private static final long SWITCH_TIME_MILLIS = 75;
68     private static final long ANIMATION_DURATION_MILLIS = 200;
69 
70     private static final SparseArray<Integer> BUTTON_RES_ID_TO_NUM = new SparseArray<>();
71     static {
BUTTON_RES_ID_TO_NUM.put(R.id.permission_allow_button, ALLOW_BUTTON)72         BUTTON_RES_ID_TO_NUM.put(R.id.permission_allow_button, ALLOW_BUTTON);
BUTTON_RES_ID_TO_NUM.put(R.id.permission_allow_always_button, ALLOW_ALWAYS_BUTTON)73         BUTTON_RES_ID_TO_NUM.put(R.id.permission_allow_always_button,
74                 ALLOW_ALWAYS_BUTTON);
BUTTON_RES_ID_TO_NUM.put(R.id.permission_allow_foreground_only_button, ALLOW_FOREGROUND_BUTTON)75         BUTTON_RES_ID_TO_NUM.put(R.id.permission_allow_foreground_only_button,
76                 ALLOW_FOREGROUND_BUTTON);
BUTTON_RES_ID_TO_NUM.put(R.id.permission_deny_button, DENY_BUTTON)77         BUTTON_RES_ID_TO_NUM.put(R.id.permission_deny_button, DENY_BUTTON);
BUTTON_RES_ID_TO_NUM.put(R.id.permission_deny_and_dont_ask_again_button, DENY_AND_DONT_ASK_AGAIN_BUTTON)78         BUTTON_RES_ID_TO_NUM.put(R.id.permission_deny_and_dont_ask_again_button,
79                 DENY_AND_DONT_ASK_AGAIN_BUTTON);
BUTTON_RES_ID_TO_NUM.put(R.id.permission_allow_one_time_button, ALLOW_ONE_TIME_BUTTON)80         BUTTON_RES_ID_TO_NUM.put(R.id.permission_allow_one_time_button, ALLOW_ONE_TIME_BUTTON);
BUTTON_RES_ID_TO_NUM.put(R.id.permission_no_upgrade_button, NO_UPGRADE_BUTTON)81         BUTTON_RES_ID_TO_NUM.put(R.id.permission_no_upgrade_button, NO_UPGRADE_BUTTON);
BUTTON_RES_ID_TO_NUM.put(R.id.permission_no_upgrade_and_dont_ask_again_button, NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON)82         BUTTON_RES_ID_TO_NUM.put(R.id.permission_no_upgrade_and_dont_ask_again_button,
83                 NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON);
BUTTON_RES_ID_TO_NUM.put(R.id.permission_no_upgrade_one_time_button, NO_UPGRADE_OT_BUTTON)84         BUTTON_RES_ID_TO_NUM.put(R.id.permission_no_upgrade_one_time_button, NO_UPGRADE_OT_BUTTON);
BUTTON_RES_ID_TO_NUM.put(R.id.permission_no_upgrade_one_time_and_dont_ask_again_button, NO_UPGRADE_OT_AND_DONT_ASK_AGAIN_BUTTON)85         BUTTON_RES_ID_TO_NUM.put(R.id.permission_no_upgrade_one_time_and_dont_ask_again_button,
86                 NO_UPGRADE_OT_AND_DONT_ASK_AGAIN_BUTTON);
87     }
88 
89     private final Activity mActivity;
90     private final String mAppPackageName;
91     private final UserHandle mUserHandle;
92 
93     private ResultListener mResultListener;
94 
95     // Configuration of the current dialog
96     private String mGroupName;
97     private int mGroupCount;
98     private int mGroupIndex;
99     private Icon mGroupIcon;
100     private CharSequence mGroupMessage;
101     private CharSequence mDetailMessage;
102     private boolean[] mButtonVisibilities;
103 
104     // Views
105     private ImageView mIconView;
106     private TextView mMessageView;
107     private TextView mDetailMessageView;
108     private Button[] mButtons;
109     private ViewGroup mRootView;
110 
GrantPermissionsViewHandlerImpl(Activity activity, String appPackageName, @NonNull UserHandle userHandle)111     public GrantPermissionsViewHandlerImpl(Activity activity, String appPackageName,
112             @NonNull UserHandle userHandle) {
113         mActivity = activity;
114         mAppPackageName = appPackageName;
115         mUserHandle = userHandle;
116     }
117 
118     @Override
setResultListener(ResultListener listener)119     public GrantPermissionsViewHandlerImpl setResultListener(ResultListener listener) {
120         mResultListener = listener;
121         return this;
122     }
123 
124     @Override
saveInstanceState(Bundle arguments)125     public void saveInstanceState(Bundle arguments) {
126         arguments.putString(ARG_GROUP_NAME, mGroupName);
127         arguments.putInt(ARG_GROUP_COUNT, mGroupCount);
128         arguments.putInt(ARG_GROUP_INDEX, mGroupIndex);
129         arguments.putParcelable(ARG_GROUP_ICON, mGroupIcon);
130         arguments.putCharSequence(ARG_GROUP_MESSAGE, mGroupMessage);
131         arguments.putCharSequence(ARG_GROUP_DETAIL_MESSAGE, mDetailMessage);
132         arguments.putBooleanArray(ARG_DIALOG_BUTTON_VISIBILITIES, mButtonVisibilities);
133     }
134 
135     @Override
loadInstanceState(Bundle savedInstanceState)136     public void loadInstanceState(Bundle savedInstanceState) {
137         mGroupName = savedInstanceState.getString(ARG_GROUP_NAME);
138         mGroupMessage = savedInstanceState.getCharSequence(ARG_GROUP_MESSAGE);
139         mGroupIcon = savedInstanceState.getParcelable(ARG_GROUP_ICON);
140         mGroupCount = savedInstanceState.getInt(ARG_GROUP_COUNT);
141         mGroupIndex = savedInstanceState.getInt(ARG_GROUP_INDEX);
142         mDetailMessage = savedInstanceState.getCharSequence(ARG_GROUP_DETAIL_MESSAGE);
143         mButtonVisibilities = savedInstanceState.getBooleanArray(ARG_DIALOG_BUTTON_VISIBILITIES);
144 
145         updateAll();
146     }
147 
148     @Override
updateUi(String groupName, int groupCount, int groupIndex, Icon icon, CharSequence message, CharSequence detailMessage, boolean[] buttonVisibilities)149     public void updateUi(String groupName, int groupCount, int groupIndex, Icon icon,
150             CharSequence message, CharSequence detailMessage, boolean[] buttonVisibilities) {
151         boolean isNewGroup = mGroupIndex != groupIndex;
152 
153         mGroupName = groupName;
154         mGroupCount = groupCount;
155         mGroupIndex = groupIndex;
156         mGroupIcon = icon;
157         mGroupMessage = message;
158         mDetailMessage = detailMessage;
159         mButtonVisibilities = buttonVisibilities;
160 
161         // If this is a second (or later) permission and the views exist, then animate.
162         if (mIconView != null) {
163             updateAll();
164         }
165     }
166 
updateAll()167     private void updateAll() {
168         updateDescription();
169         updateDetailDescription();
170         updateButtons();
171 
172 //      Animate change in size
173 //      Grow or shrink the content container to size of new content
174         ChangeBounds growShrinkToNewContentSize = new ChangeBounds();
175         growShrinkToNewContentSize.setDuration(ANIMATION_DURATION_MILLIS);
176         growShrinkToNewContentSize.setInterpolator(AnimationUtils.loadInterpolator(mActivity,
177                 android.R.interpolator.fast_out_slow_in));
178         TransitionManager.beginDelayedTransition(mRootView, growShrinkToNewContentSize);
179     }
180 
181     @Override
createView()182     public View createView() {
183         mRootView = (ViewGroup) LayoutInflater.from(mActivity)
184                 .inflate(R.layout.grant_permissions, null);
185 
186         int h = mActivity.getResources().getDisplayMetrics().heightPixels;
187         mRootView.setMinimumHeight(h);
188         mRootView.findViewById(R.id.grant_singleton).setOnClickListener(this); // Cancel dialog
189         mRootView.findViewById(R.id.grant_dialog).setOnClickListener(this); // Swallow click event
190 
191         mMessageView = mRootView.findViewById(R.id.permission_message);
192         mDetailMessageView = mRootView.findViewById(R.id.detail_message);
193         mDetailMessageView.setMovementMethod(LinkMovementMethod.getInstance());
194         mIconView = mRootView.findViewById(R.id.permission_icon);
195 
196         mButtons = new Button[GrantPermissionsActivity.NEXT_BUTTON];
197 
198         int numButtons = BUTTON_RES_ID_TO_NUM.size();
199         for (int i = 0; i < numButtons; i++) {
200             Button button = mRootView.findViewById(BUTTON_RES_ID_TO_NUM.keyAt(i));
201             button.setOnClickListener(this);
202             mButtons[BUTTON_RES_ID_TO_NUM.valueAt(i)] = button;
203         }
204 
205         if (mGroupName != null) {
206             updateAll();
207         }
208 
209         return mRootView;
210     }
211 
212     @Override
updateWindowAttributes(LayoutParams outLayoutParams)213     public void updateWindowAttributes(LayoutParams outLayoutParams) {
214         // No-op
215     }
216 
updateDescription()217     private void updateDescription() {
218         if (mGroupIcon != null) {
219             mIconView.setImageDrawable(mGroupIcon.loadDrawable(mActivity));
220         }
221         mMessageView.setText(mGroupMessage);
222     }
223 
updateDetailDescription()224     private void updateDetailDescription() {
225         if (mDetailMessage == null) {
226             mDetailMessageView.setVisibility(View.GONE);
227         } else {
228             mDetailMessageView.setText(mDetailMessage);
229             mDetailMessageView.setVisibility(View.VISIBLE);
230         }
231     }
232 
updateButtons()233     private void updateButtons() {
234         int numButtons = BUTTON_RES_ID_TO_NUM.size();
235         for (int i = 0; i < numButtons; i++) {
236             int pos = BUTTON_RES_ID_TO_NUM.valueAt(i);
237             mButtons[pos].setVisibility(mButtonVisibilities[pos] ? View.VISIBLE : View.GONE);
238         }
239     }
240 
241     @Override
onClick(View view)242     public void onClick(View view) {
243         int id = view.getId();
244         if (id == R.id.grant_singleton) {
245             if (mResultListener != null) {
246                 mResultListener.onPermissionGrantResult(mGroupName, CANCELED);
247             } else {
248                 mActivity.finish();
249             }
250             return;
251         }
252         int button = -1;
253         try {
254             button = BUTTON_RES_ID_TO_NUM.get(id);
255         } catch (NullPointerException e) {
256             // Clicked a view which is not one of the defined buttons
257             return;
258         }
259         switch (button) {
260             case ALLOW_BUTTON:
261                 if (mResultListener != null) {
262                     view.performAccessibilityAction(
263                             AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
264                     mResultListener.onPermissionGrantResult(mGroupName, GRANTED_ALWAYS);
265                 }
266                 break;
267             case ALLOW_FOREGROUND_BUTTON:
268                 if (mResultListener != null) {
269                     view.performAccessibilityAction(
270                             AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
271                     mResultListener.onPermissionGrantResult(mGroupName,
272                             GRANTED_FOREGROUND_ONLY);
273                 }
274                 break;
275             case ALLOW_ALWAYS_BUTTON:
276                 if (mResultListener != null) {
277                     view.performAccessibilityAction(
278                             AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
279                     mResultListener.onPermissionGrantResult(mGroupName,
280                             GRANTED_ALWAYS);
281                 }
282                 break;
283             case ALLOW_ONE_TIME_BUTTON:
284                 if (mResultListener != null) {
285                     view.performAccessibilityAction(
286                             AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
287                     mResultListener.onPermissionGrantResult(mGroupName, GRANTED_ONE_TIME);
288                 }
289                 break;
290             case DENY_BUTTON:
291             case NO_UPGRADE_BUTTON:
292             case NO_UPGRADE_OT_BUTTON:
293                 if (mResultListener != null) {
294                     view.performAccessibilityAction(
295                             AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
296                     mResultListener.onPermissionGrantResult(mGroupName, DENIED);
297                 }
298                 break;
299             case DENY_AND_DONT_ASK_AGAIN_BUTTON:
300             case NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON:
301             case NO_UPGRADE_OT_AND_DONT_ASK_AGAIN_BUTTON:
302                 if (mResultListener != null) {
303                     view.performAccessibilityAction(
304                             AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
305                     mResultListener.onPermissionGrantResult(mGroupName,
306                             DENIED_DO_NOT_ASK_AGAIN);
307                 }
308                 break;
309         }
310 
311     }
312 
313     @Override
onBackPressed()314     public void onBackPressed() {
315         if (mResultListener != null) {
316             mResultListener.onPermissionGrantResult(mGroupName, CANCELED);
317         } else {
318             mActivity.finish();
319         }
320     }
321 
322 }
323