1 /* 2 * Copyright (C) 2024 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.auto; 18 19 import static android.Manifest.permission.ACCESS_COARSE_LOCATION; 20 import static android.Manifest.permission.ACCESS_FINE_LOCATION; 21 22 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.ALLOW_ALL_BUTTON; 23 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.ALLOW_ALWAYS_BUTTON; 24 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.ALLOW_BUTTON; 25 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.ALLOW_FOREGROUND_BUTTON; 26 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.ALLOW_ONE_TIME_BUTTON; 27 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.ALLOW_SELECTED_BUTTON; 28 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.COARSE_RADIO_BUTTON; 29 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.DENY_AND_DONT_ASK_AGAIN_BUTTON; 30 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.DENY_BUTTON; 31 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.DIALOG_WITH_BOTH_LOCATIONS; 32 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.DIALOG_WITH_COARSE_LOCATION_ONLY; 33 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.DIALOG_WITH_FINE_LOCATION_ONLY; 34 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.DONT_ALLOW_MORE_SELECTED_BUTTON; 35 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.FINE_RADIO_BUTTON; 36 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.LOCATION_ACCURACY_LAYOUT; 37 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.NEXT_BUTTON; 38 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.NEXT_LOCATION_DIALOG; 39 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON; 40 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.NO_UPGRADE_BUTTON; 41 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.NO_UPGRADE_OT_AND_DONT_ASK_AGAIN_BUTTON; 42 import static com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.NO_UPGRADE_OT_BUTTON; 43 import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.CANCELED; 44 import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.DENIED; 45 import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.DENIED_DO_NOT_ASK_AGAIN; 46 import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.DENIED_MORE; 47 import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.GRANTED_ALWAYS; 48 import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.GRANTED_FOREGROUND_ONLY; 49 import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.GRANTED_ONE_TIME; 50 import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.GRANTED_USER_SELECTED; 51 52 import android.app.Activity; 53 import android.content.Context; 54 import android.graphics.Typeface; 55 import android.graphics.drawable.Icon; 56 import android.text.method.LinkMovementMethod; 57 import android.transition.ChangeBounds; 58 import android.transition.TransitionManager; 59 import android.util.SparseIntArray; 60 import android.view.Gravity; 61 import android.view.LayoutInflater; 62 import android.view.View; 63 import android.view.ViewGroup; 64 import android.view.Window; 65 import android.view.accessibility.AccessibilityNodeInfo; 66 import android.view.animation.AnimationUtils; 67 import android.widget.Button; 68 import android.widget.ImageView; 69 import android.widget.RadioButton; 70 import android.widget.RadioGroup; 71 import android.widget.TextView; 72 73 import androidx.annotation.RawRes; 74 75 import com.android.permissioncontroller.R; 76 import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler; 77 78 import com.airbnb.lottie.LottieComposition; 79 import com.airbnb.lottie.LottieCompositionFactory; 80 import com.airbnb.lottie.LottieDrawable; 81 82 import java.util.ArrayList; 83 import java.util.HashMap; 84 import java.util.List; 85 import java.util.Map; 86 87 /** 88 * An extension of {@link GrantPermissionsAutoViewHandler} that updates the current auto location 89 * permission prompt with a custom view 90 */ 91 public class AutoLocationPermissionPromptView implements View.OnClickListener { 92 private static final int[] LOCATION_ACCURACY_DIALOGS = 93 { 94 DIALOG_WITH_BOTH_LOCATIONS, 95 DIALOG_WITH_FINE_LOCATION_ONLY, 96 DIALOG_WITH_COARSE_LOCATION_ONLY 97 }; 98 private static final long ANIMATION_DURATION_MILLIS = 200; 99 private static final float LOCATION_IMAGE_SIZE_MODIFIER = 2; 100 private final Context mContext; 101 private GrantPermissionsViewHandler.ResultListener mResultListener; 102 private String mGroupName; 103 private Icon mGroupIcon; 104 private CharSequence mGroupMessage; 105 private CharSequence mDetailMessage; 106 private boolean[] mButtonVisibilities; 107 private boolean[] mLocationVisibilities; 108 private SparseIntArray mButtonResIdToNum = new SparseIntArray(); 109 private SparseIntArray mLocationResIdToNum = new SparseIntArray(); 110 private boolean mIsLocationPermissionDialogActionClicked = false; 111 private LottieDrawable mCoarseOffDrawable = null; 112 private LottieDrawable mCoarseOnDrawable = null; 113 private LottieDrawable mFineOffDrawable = null; 114 private LottieDrawable mFineOnDrawable = null; 115 116 // Views 117 private ViewGroup mRootView = null; 118 private TextView mMessageView = null; 119 private TextView mDetailedMessageView = null; 120 private Button[] mButtons = new Button[NEXT_BUTTON]; 121 private View[] mLocationViews = new View[NEXT_LOCATION_DIALOG]; 122 123 // Dialog Config 124 private RadioButton mCoarseRadioButton = null; 125 private RadioButton mFineRadioButton = null; 126 private int mSelectedPrecision = 0; 127 private float mLocationAccuracyImageDiameter = 0; 128 129 /** 130 * Constructs a new AutoLocationPermissionPromptView. 131 * 132 * @param context the Context in which the view is created 133 */ AutoLocationPermissionPromptView(Context context)134 public AutoLocationPermissionPromptView(Context context) { 135 mContext = context; 136 generateResIdToButtonMap(); 137 mLocationAccuracyImageDiameter = 138 mContext.getResources().getDimension(R.dimen.location_accuracy_image_size) 139 + LOCATION_IMAGE_SIZE_MODIFIER; 140 } 141 142 /** 143 * Sets the ResultListener for this view. The ResultListener will be notified when 144 * the user makes a selection in the permission prompt. 145 * 146 * @param listener the ResultListener to set 147 */ setResultListener(GrantPermissionsViewHandler.ResultListener listener)148 public void setResultListener(GrantPermissionsViewHandler.ResultListener listener) { 149 mResultListener = listener; 150 } 151 152 /** 153 * Creates and initializes the custom view for the auto location permission prompt. 154 * This method inflates the layout, sets up various UI elements, and configures their behaviors 155 * such as click listeners and gravity adjustments. 156 */ createView()157 public View createView() { 158 ViewGroup rootView = (ViewGroup) LayoutInflater.from(mContext).inflate( 159 R.layout.auto_grant_permissions_material3, null); 160 161 this.mRootView = rootView; 162 163 int gravity = rootView.requireViewById(R.id.grant_singleton).getForegroundGravity(); 164 int verticalGravity = Gravity.VERTICAL_GRAVITY_MASK & gravity; 165 if (mContext instanceof Activity activity) { 166 Window window = activity.getWindow(); 167 window.setGravity(Gravity.CENTER_HORIZONTAL | verticalGravity); 168 } 169 170 rootView.requireViewById(R.id.grant_singleton).setOnClickListener(this); 171 rootView.requireViewById(R.id.grant_dialog).setOnClickListener(this); 172 173 mMessageView = rootView.requireViewById(R.id.permission_message); 174 mDetailedMessageView = rootView.requireViewById(R.id.detail_message); 175 mDetailedMessageView.setMovementMethod(LinkMovementMethod.getInstance()); 176 177 Button[] buttons = new Button[NEXT_BUTTON]; 178 int numButtons = mButtonResIdToNum.size(); 179 for (int i = 0; i < numButtons; i++) { 180 Button button = rootView.requireViewById(mButtonResIdToNum.keyAt(i)); 181 button.setOnClickListener(this); 182 buttons[mButtonResIdToNum.valueAt(i)] = button; 183 } 184 this.mButtons = buttons; 185 186 View[] locationViews = new View[NEXT_LOCATION_DIALOG]; 187 for (int i = 0; i < mLocationResIdToNum.size(); i++) { 188 View locationView = rootView.requireViewById(mLocationResIdToNum.keyAt(i)); 189 locationViews[mLocationResIdToNum.valueAt(i)] = locationView; 190 } 191 192 initializeAnimatedImages(); 193 194 mCoarseRadioButton = (RadioButton) locationViews[COARSE_RADIO_BUTTON]; 195 mFineRadioButton = (RadioButton) locationViews[FINE_RADIO_BUTTON]; 196 mCoarseRadioButton.setOnClickListener(this); 197 mFineRadioButton.setOnClickListener(this); 198 this.mLocationViews = locationViews; 199 200 if (mDetailMessage != null) { 201 updateAll(); 202 } 203 return rootView; 204 } 205 initializeAnimatedImages()206 private void initializeAnimatedImages() { 207 mCoarseOffDrawable = getLottieDrawable(R.raw.coarse_loc_off); 208 mCoarseOnDrawable = getLottieDrawable(R.raw.coarse_loc_on); 209 mFineOffDrawable = getLottieDrawable(R.raw.fine_loc_off); 210 mFineOnDrawable = getLottieDrawable(R.raw.fine_loc_on); 211 } 212 getLottieDrawable(@awRes int rawResId)213 private LottieDrawable getLottieDrawable(@RawRes int rawResId) { 214 LottieComposition composition = LottieCompositionFactory 215 .fromRawResSync(mContext, rawResId).getValue(); 216 if (composition == null) { 217 throw new NullPointerException(); 218 } 219 220 float scale = mLocationAccuracyImageDiameter / composition.getBounds().width(); 221 LottieDrawable drawable = new LottieDrawable() { 222 @Override 223 public int getIntrinsicHeight() { 224 return ((int) (super.getIntrinsicHeight() * scale)); 225 } 226 227 @Override 228 public int getIntrinsicWidth() { 229 return ((int) (super.getIntrinsicWidth() * scale)); 230 } 231 }; 232 drawable.setComposition(composition); 233 return drawable; 234 } 235 236 /** 237 * Updates the state of the view with the provided parameters. This method is called to refresh 238 * the UI elements with new data, ensuring that the view reflects the latest information. 239 */ updateState(String groupName, Icon icon, CharSequence message, CharSequence detailMessage, boolean[] buttonVisibilities, boolean[] locationVisibilities, int selectedPrecision)240 public void updateState(String groupName, Icon icon, 241 CharSequence message, CharSequence detailMessage, boolean[] buttonVisibilities, 242 boolean[] locationVisibilities, int selectedPrecision) { 243 244 mGroupName = groupName; 245 mGroupIcon = icon; 246 mGroupMessage = message; 247 mDetailMessage = detailMessage; 248 mSelectedPrecision = selectedPrecision; 249 setButtonVisibilities(buttonVisibilities); 250 setLocationVisibilities(locationVisibilities); 251 252 // If the iconView is null, it's likely other related views are also null. Attempting to 253 // update variables in this state could lead to a null object reference and crash the app. 254 if (mMessageView != null) { 255 updateAll(); 256 } 257 } 258 updateAll()259 private void updateAll() { 260 updateDescription(); 261 updateDetailDescription(); 262 updateButtons(); 263 updateLocationVisibilities(); 264 265 ChangeBounds growShrinkToNewContentSize = new ChangeBounds(); 266 growShrinkToNewContentSize.setDuration(ANIMATION_DURATION_MILLIS); 267 growShrinkToNewContentSize.setInterpolator( 268 AnimationUtils.loadInterpolator(mContext, android.R.interpolator.fast_out_slow_in)); 269 TransitionManager.beginDelayedTransition(mRootView, growShrinkToNewContentSize); 270 } 271 updateLocationVisibilities()272 private void updateLocationVisibilities() { 273 if (mLocationVisibilities[LOCATION_ACCURACY_LAYOUT]) { 274 if (mIsLocationPermissionDialogActionClicked) { 275 return; 276 } 277 mLocationViews[LOCATION_ACCURACY_LAYOUT].setVisibility(View.VISIBLE); 278 for (int i : LOCATION_ACCURACY_DIALOGS) { 279 if (mLocationVisibilities[i]) { 280 mLocationViews[i].setVisibility(View.VISIBLE); 281 } else { 282 mLocationViews[i].setVisibility(View.GONE); 283 } 284 } 285 286 if (mLocationVisibilities[DIALOG_WITH_BOTH_LOCATIONS]) { 287 mCoarseRadioButton.setVisibility(View.VISIBLE); 288 mFineRadioButton.setVisibility(View.VISIBLE); 289 if (mSelectedPrecision == 0) { 290 mFineRadioButton.setChecked(mLocationVisibilities[FINE_RADIO_BUTTON]); 291 mCoarseRadioButton.setChecked(mLocationVisibilities[COARSE_RADIO_BUTTON]); 292 } else { 293 mFineRadioButton.setChecked(mSelectedPrecision == FINE_RADIO_BUTTON); 294 mCoarseRadioButton.setChecked(mSelectedPrecision == COARSE_RADIO_BUTTON); 295 } 296 if (mCoarseRadioButton.isChecked()) { 297 runLocationAccuracyAnimation(false); 298 299 } else if (mFineRadioButton.isChecked()) { 300 runLocationAccuracyAnimation(true); 301 } 302 } else if (mLocationVisibilities[DIALOG_WITH_COARSE_LOCATION_ONLY]) { 303 ((ImageView) mLocationViews[DIALOG_WITH_COARSE_LOCATION_ONLY]) 304 .setImageDrawable(mCoarseOnDrawable); 305 mCoarseOnDrawable.start(); 306 } else if (mLocationVisibilities[DIALOG_WITH_FINE_LOCATION_ONLY]) { 307 ((ImageView) mLocationViews[DIALOG_WITH_FINE_LOCATION_ONLY]) 308 .setImageDrawable(mFineOnDrawable); 309 mFineOnDrawable.start(); 310 } 311 } else { 312 mLocationViews[LOCATION_ACCURACY_LAYOUT].setVisibility(View.GONE); 313 for (int i : LOCATION_ACCURACY_DIALOGS) { 314 mLocationVisibilities[i] = false; 315 mLocationViews[i].setVisibility(View.GONE); 316 } 317 } 318 } 319 runLocationAccuracyAnimation(boolean isFineSelected)320 private void runLocationAccuracyAnimation(boolean isFineSelected) { 321 if (isFineSelected) { 322 mCoarseOnDrawable.stop(); 323 mFineOffDrawable.stop(); 324 // Sets the drawable to appear to the left, top, right, or bottom of the text 325 mCoarseRadioButton.setCompoundDrawablesWithIntrinsicBounds( 326 /* left */ null, 327 /* top */ mCoarseOffDrawable, 328 /* right */ null, 329 /* bottom */ null 330 ); 331 mFineRadioButton.setCompoundDrawablesWithIntrinsicBounds( 332 /* left */ null, 333 /* top */ mFineOnDrawable, 334 /* right */ null, 335 /* bottom */ null 336 ); 337 mCoarseOffDrawable.start(); 338 mFineOnDrawable.start(); 339 mFineRadioButton.setTypeface(null, Typeface.BOLD); 340 mCoarseRadioButton.setTypeface(null, Typeface.NORMAL); 341 } else { 342 mCoarseOffDrawable.stop(); 343 mFineOnDrawable.stop(); 344 mCoarseRadioButton.setCompoundDrawablesWithIntrinsicBounds( 345 /* left */ null, 346 /* top */ mCoarseOnDrawable, 347 /* right */ null, 348 /* bottom */ null 349 ); 350 mFineRadioButton.setCompoundDrawablesWithIntrinsicBounds( 351 /* left */ null, 352 /* top */ mFineOffDrawable, 353 /* right */ null, 354 /* bottom */ null 355 ); 356 mFineOffDrawable.start(); 357 mCoarseOnDrawable.start(); 358 mCoarseRadioButton.setTypeface(null, Typeface.BOLD); 359 mFineRadioButton.setTypeface(null, Typeface.NORMAL); 360 } 361 } 362 updateButtons()363 private void updateButtons() { 364 for (int i = 0; i < mButtonResIdToNum.size(); i++) { 365 int pos = mButtonResIdToNum.valueAt(i); 366 if (pos < mButtonVisibilities.length && mButtonVisibilities[pos]) { 367 mButtons[pos].setVisibility(View.VISIBLE); 368 } else { 369 mButtons[pos].setVisibility(View.GONE); 370 } 371 if (pos == ALLOW_FOREGROUND_BUTTON && mButtonVisibilities[pos]) { 372 if (mLocationVisibilities[LOCATION_ACCURACY_LAYOUT] 373 && mLocationVisibilities[DIALOG_WITH_FINE_LOCATION_ONLY] 374 ) { 375 mButtons[pos].setText(mContext.getResources().getString( 376 R.string.grant_dialog_button_change_to_precise_location)); 377 } else { 378 mButtons[pos].setText(mContext.getResources().getString( 379 R.string.grant_dialog_button_allow_foreground)); 380 } 381 } 382 if ((pos == DENY_BUTTON || pos == DENY_AND_DONT_ASK_AGAIN_BUTTON)) { 383 if ( 384 mLocationVisibilities[LOCATION_ACCURACY_LAYOUT] 385 && mLocationVisibilities[DIALOG_WITH_FINE_LOCATION_ONLY] 386 ) { 387 mButtons[pos].setText(mContext.getResources().getString( 388 R.string.grant_dialog_button_keey_approximate_location)); 389 } else { 390 mButtons[pos].setText( 391 mContext.getResources().getString(R.string.grant_dialog_button_deny)); 392 } 393 } 394 mButtons[pos].requestLayout(); 395 } 396 } 397 updateDetailDescription()398 private void updateDetailDescription() { 399 if (mDetailMessage == null) { 400 mDetailedMessageView.setVisibility(View.GONE); 401 } else { 402 mDetailedMessageView.setText(mDetailMessage); 403 mDetailedMessageView.setVisibility(View.VISIBLE); 404 } 405 } 406 updateDescription()407 private void updateDescription() { 408 mMessageView.setText(mGroupMessage); 409 } 410 setButtonVisibilities(boolean[] visibilities)411 private void setButtonVisibilities(boolean[] visibilities) { 412 // If GrantPermissionsActivity sent the user directly to settings, button visibilities are 413 // not created. If the activity was then destroyed by the system, once the activity is 414 // recreated to perform onActivityResult, it will try to loadInstanceState in onCreate but 415 // the button visibilities were never set, so they will be null. 416 mButtonVisibilities = visibilities == null ? new boolean[0] : visibilities; 417 } 418 setLocationVisibilities(boolean[] visibilities)419 private void setLocationVisibilities(boolean[] visibilities) { 420 mLocationVisibilities = visibilities == null ? new boolean[0] : visibilities; 421 } 422 423 @Override onClick(View view)424 public void onClick(View view) { 425 int id = view.getId(); 426 427 if (id == R.id.permission_location_accuracy_radio_fine) { 428 if (mSelectedPrecision != FINE_RADIO_BUTTON) { 429 ((RadioButton) mLocationViews[FINE_RADIO_BUTTON]).setChecked(true); 430 mSelectedPrecision = FINE_RADIO_BUTTON; 431 runLocationAccuracyAnimation(true); 432 } 433 return; 434 } 435 436 if (id == R.id.permission_location_accuracy_radio_coarse) { 437 if (mSelectedPrecision != COARSE_RADIO_BUTTON) { 438 ((RadioButton) mLocationViews[COARSE_RADIO_BUTTON]).setChecked(true); 439 mSelectedPrecision = COARSE_RADIO_BUTTON; 440 runLocationAccuracyAnimation(false); 441 } 442 return; 443 } 444 445 if (mLocationVisibilities[LOCATION_ACCURACY_LAYOUT]) { 446 mIsLocationPermissionDialogActionClicked = true; 447 } 448 449 if (id == R.id.grant_singleton) { 450 mResultListener.onPermissionGrantResult(mGroupName, CANCELED); 451 return; 452 } 453 454 List<String> affectedForegroundPermissions = new ArrayList<>(); 455 if (mLocationVisibilities[DIALOG_WITH_BOTH_LOCATIONS]) { 456 if (((RadioGroup) mLocationViews[DIALOG_WITH_BOTH_LOCATIONS]) 457 .getCheckedRadioButtonId() == R.id.permission_location_accuracy_radio_coarse) { 458 459 affectedForegroundPermissions.add(ACCESS_COARSE_LOCATION); 460 } else if (((RadioGroup) mLocationViews[DIALOG_WITH_BOTH_LOCATIONS]) 461 .getCheckedRadioButtonId() == R.id.permission_location_accuracy_radio_fine) { 462 463 affectedForegroundPermissions.add(ACCESS_FINE_LOCATION); 464 affectedForegroundPermissions.add(ACCESS_COARSE_LOCATION); 465 } 466 } else if (mLocationVisibilities[DIALOG_WITH_FINE_LOCATION_ONLY]) { 467 affectedForegroundPermissions.add(ACCESS_FINE_LOCATION); 468 } else if (mLocationVisibilities[DIALOG_WITH_COARSE_LOCATION_ONLY]) { 469 affectedForegroundPermissions.add(ACCESS_COARSE_LOCATION); 470 } 471 472 473 Map<Integer, Integer> buttonToResultValueMap = initializeButtonToResultValueMap(); 474 int resultValue = buttonToResultValueMap.getOrDefault( 475 mButtonResIdToNum.get(id, -1), -1); 476 if (resultValue != -1) { 477 if (resultValue != DENIED_MORE) { 478 view.performAccessibilityAction( 479 AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null); 480 } 481 mResultListener.onPermissionGrantResult(mGroupName, affectedForegroundPermissions, 482 resultValue); 483 } 484 } 485 initializeButtonToResultValueMap()486 private Map<Integer, Integer> initializeButtonToResultValueMap() { 487 Map<Integer, Integer> map = new HashMap<>(); 488 map.put(ALLOW_ALL_BUTTON, GRANTED_ALWAYS); 489 map.put(ALLOW_BUTTON, GRANTED_ALWAYS); 490 map.put(ALLOW_FOREGROUND_BUTTON, GRANTED_FOREGROUND_ONLY); 491 map.put(ALLOW_ALWAYS_BUTTON, GRANTED_ALWAYS); 492 map.put(ALLOW_ONE_TIME_BUTTON, GRANTED_ONE_TIME); 493 map.put(ALLOW_SELECTED_BUTTON, GRANTED_USER_SELECTED); 494 map.put(DONT_ALLOW_MORE_SELECTED_BUTTON, DENIED_MORE); 495 map.put(DENY_BUTTON, DENIED); 496 map.put(NO_UPGRADE_BUTTON, DENIED); 497 map.put(NO_UPGRADE_OT_BUTTON, DENIED); 498 map.put(DENY_AND_DONT_ASK_AGAIN_BUTTON, DENIED_DO_NOT_ASK_AGAIN); 499 map.put(NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON, DENIED_DO_NOT_ASK_AGAIN); 500 map.put(NO_UPGRADE_OT_AND_DONT_ASK_AGAIN_BUTTON, DENIED_DO_NOT_ASK_AGAIN); 501 return map; 502 } 503 generateResIdToButtonMap()504 private void generateResIdToButtonMap() { 505 mButtonResIdToNum.put(R.id.permission_allow_button, ALLOW_BUTTON); 506 mButtonResIdToNum.put( 507 R.id.permission_allow_foreground_only_button, 508 ALLOW_FOREGROUND_BUTTON 509 ); 510 mButtonResIdToNum.put(R.id.permission_deny_button, DENY_BUTTON); 511 mButtonResIdToNum.put( 512 R.id.permission_deny_and_dont_ask_again_button, 513 DENY_AND_DONT_ASK_AGAIN_BUTTON 514 ); 515 mButtonResIdToNum.put(R.id.permission_allow_one_time_button, ALLOW_ONE_TIME_BUTTON); 516 mButtonResIdToNum.put(R.id.permission_no_upgrade_button, NO_UPGRADE_BUTTON); 517 mButtonResIdToNum.put( 518 R.id.permission_no_upgrade_and_dont_ask_again_button, 519 NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON 520 ); 521 mButtonResIdToNum.put( 522 R.id.permission_no_upgrade_one_time_button, 523 NO_UPGRADE_OT_BUTTON 524 ); 525 mButtonResIdToNum.put( 526 R.id.permission_no_upgrade_one_time_and_dont_ask_again_button, 527 NO_UPGRADE_OT_AND_DONT_ASK_AGAIN_BUTTON 528 ); 529 mButtonResIdToNum.put(R.id.permission_allow_all_button, ALLOW_ALL_BUTTON); 530 mButtonResIdToNum.put(R.id.permission_allow_selected_button, ALLOW_SELECTED_BUTTON); 531 mButtonResIdToNum.put( 532 R.id.permission_dont_allow_more_selected_button, 533 DONT_ALLOW_MORE_SELECTED_BUTTON 534 ); 535 536 mLocationResIdToNum.put(R.id.permission_location_accuracy, LOCATION_ACCURACY_LAYOUT); 537 mLocationResIdToNum.put( 538 R.id.permission_location_accuracy_radio_fine, 539 FINE_RADIO_BUTTON 540 ); 541 mLocationResIdToNum.put( 542 R.id.permission_location_accuracy_radio_coarse, 543 COARSE_RADIO_BUTTON 544 ); 545 mLocationResIdToNum.put( 546 R.id.permission_location_accuracy_radio_group, 547 DIALOG_WITH_BOTH_LOCATIONS 548 ); 549 mLocationResIdToNum.put( 550 R.id.permission_location_accuracy_fine_only, 551 DIALOG_WITH_FINE_LOCATION_ONLY 552 ); 553 mLocationResIdToNum.put( 554 R.id.permission_location_accuracy_coarse_only, 555 DIALOG_WITH_COARSE_LOCATION_ONLY 556 ); 557 } 558 } 559