• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 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.settings.accessibility;
18 
19 import static com.android.settings.accessibility.AccessibilityDialogUtils.DialogEnums;
20 import static com.android.settings.accessibility.AccessibilityStatsLogUtils.logAccessibilityServiceEnabled;
21 import static com.android.settings.accessibility.PreferredShortcuts.retrieveUserShortcutType;
22 
23 import android.accessibilityservice.AccessibilityServiceInfo;
24 import android.app.Activity;
25 import android.app.Dialog;
26 import android.app.admin.DevicePolicyManager;
27 import android.app.settings.SettingsEnums;
28 import android.content.BroadcastReceiver;
29 import android.content.ComponentName;
30 import android.content.ContentResolver;
31 import android.content.Context;
32 import android.content.DialogInterface;
33 import android.content.Intent;
34 import android.content.IntentFilter;
35 import android.content.pm.ApplicationInfo;
36 import android.content.pm.ResolveInfo;
37 import android.content.pm.ServiceInfo;
38 import android.net.Uri;
39 import android.os.Bundle;
40 import android.os.Handler;
41 import android.os.UserHandle;
42 import android.os.storage.StorageManager;
43 import android.provider.Settings;
44 import android.text.TextUtils;
45 import android.util.Log;
46 import android.view.Menu;
47 import android.view.MenuInflater;
48 import android.view.View;
49 import android.view.accessibility.AccessibilityManager;
50 import android.widget.Switch;
51 
52 import androidx.annotation.Nullable;
53 
54 import com.android.internal.widget.LockPatternUtils;
55 import com.android.settings.R;
56 import com.android.settings.accessibility.AccessibilityUtil.UserShortcutType;
57 import com.android.settings.password.ConfirmDeviceCredentialActivity;
58 import com.android.settings.widget.SettingsMainSwitchPreference;
59 import com.android.settingslib.accessibility.AccessibilityUtils;
60 
61 import java.util.List;
62 import java.util.concurrent.atomic.AtomicBoolean;
63 
64 /** Fragment for providing toggle bar and basic accessibility service setup. */
65 public class ToggleAccessibilityServicePreferenceFragment extends
66         ToggleFeaturePreferenceFragment {
67 
68     private static final String TAG = "ToggleAccessibilityServicePreferenceFragment";
69     private static final int ACTIVITY_REQUEST_CONFIRM_CREDENTIAL_FOR_WEAKER_ENCRYPTION = 1;
70     private LockPatternUtils mLockPatternUtils;
71     private AtomicBoolean mIsDialogShown = new AtomicBoolean(/* initialValue= */ false);
72 
73     private static final String EMPTY_STRING = "";
74 
75     private final SettingsContentObserver mSettingsContentObserver =
76             new SettingsContentObserver(new Handler()) {
77                 @Override
78                 public void onChange(boolean selfChange, Uri uri) {
79                     updateSwitchBarToggleSwitch();
80                 }
81             };
82 
83     private Dialog mDialog;
84     private BroadcastReceiver mPackageRemovedReceiver;
85 
86     @Override
getMetricsCategory()87     public int getMetricsCategory() {
88         return SettingsEnums.ACCESSIBILITY_SERVICE;
89     }
90 
91     @Override
onCreateOptionsMenu(Menu menu, MenuInflater infalter)92     public void onCreateOptionsMenu(Menu menu, MenuInflater infalter) {
93         // Do not call super. We don't want to see the "Help & feedback" option on this page so as
94         // not to confuse users who think they might be able to send feedback about a specific
95         // accessibility service from this page.
96     }
97 
98     @Override
onCreate(Bundle savedInstanceState)99     public void onCreate(Bundle savedInstanceState) {
100         super.onCreate(savedInstanceState);
101         mLockPatternUtils = new LockPatternUtils(getPrefContext());
102     }
103 
104     @Override
onStart()105     public void onStart() {
106         super.onStart();
107         final AccessibilityServiceInfo serviceInfo = getAccessibilityServiceInfo();
108         if (serviceInfo == null) {
109             getActivity().finishAndRemoveTask();
110         } else if (!AccessibilityUtil.isSystemApp(serviceInfo)) {
111             registerPackageRemoveReceiver();
112         }
113     }
114 
115     @Override
onResume()116     public void onResume() {
117         super.onResume();
118         updateSwitchBarToggleSwitch();
119         mSettingsContentObserver.register(getContentResolver());
120     }
121 
122     @Override
onPreferenceToggled(String preferenceKey, boolean enabled)123     public void onPreferenceToggled(String preferenceKey, boolean enabled) {
124         ComponentName toggledService = ComponentName.unflattenFromString(preferenceKey);
125         logAccessibilityServiceEnabled(toggledService, enabled);
126         AccessibilityUtils.setAccessibilityServiceState(getPrefContext(), toggledService, enabled);
127     }
128 
129     // IMPORTANT: Refresh the info since there are dynamically changing
130     // capabilities. For
131     // example, before JellyBean MR2 the user was granting the explore by touch
132     // one.
133     @Nullable
getAccessibilityServiceInfo()134     AccessibilityServiceInfo getAccessibilityServiceInfo() {
135         final List<AccessibilityServiceInfo> infos = AccessibilityManager.getInstance(
136                 getPrefContext()).getInstalledAccessibilityServiceList();
137 
138         for (int i = 0, count = infos.size(); i < count; i++) {
139             AccessibilityServiceInfo serviceInfo = infos.get(i);
140             ResolveInfo resolveInfo = serviceInfo.getResolveInfo();
141             if (mComponentName.getPackageName().equals(resolveInfo.serviceInfo.packageName)
142                     && mComponentName.getClassName().equals(resolveInfo.serviceInfo.name)) {
143                 return serviceInfo;
144             }
145         }
146         return null;
147     }
148 
149     @Override
onCreateDialog(int dialogId)150     public Dialog onCreateDialog(int dialogId) {
151         switch (dialogId) {
152             case DialogEnums.ENABLE_WARNING_FROM_TOGGLE: {
153                 final AccessibilityServiceInfo info = getAccessibilityServiceInfo();
154                 if (info == null) {
155                     return null;
156                 }
157                 mDialog = AccessibilityServiceWarning
158                         .createCapabilitiesDialog(getPrefContext(), info,
159                                 this::onDialogButtonFromEnableToggleClicked,
160                                 this::onDialogButtonFromUninstallClicked);
161                 break;
162             }
163             case DialogEnums.ENABLE_WARNING_FROM_SHORTCUT_TOGGLE: {
164                 final AccessibilityServiceInfo info = getAccessibilityServiceInfo();
165                 if (info == null) {
166                     return null;
167                 }
168                 mDialog = AccessibilityServiceWarning
169                         .createCapabilitiesDialog(getPrefContext(), info,
170                                 this::onDialogButtonFromShortcutToggleClicked,
171                                 this::onDialogButtonFromUninstallClicked);
172                 break;
173             }
174             case DialogEnums.ENABLE_WARNING_FROM_SHORTCUT: {
175                 final AccessibilityServiceInfo info = getAccessibilityServiceInfo();
176                 if (info == null) {
177                     return null;
178                 }
179                 mDialog = AccessibilityServiceWarning
180                         .createCapabilitiesDialog(getPrefContext(), info,
181                                 this::onDialogButtonFromShortcutClicked,
182                                 this::onDialogButtonFromUninstallClicked);
183                 break;
184             }
185             case DialogEnums.DISABLE_WARNING_FROM_TOGGLE: {
186                 final AccessibilityServiceInfo info = getAccessibilityServiceInfo();
187                 if (info == null) {
188                     return null;
189                 }
190                 mDialog = AccessibilityServiceWarning
191                         .createDisableDialog(getPrefContext(), info,
192                                 this::onDialogButtonFromDisableToggleClicked);
193                 break;
194             }
195             default: {
196                 mDialog = super.onCreateDialog(dialogId);
197             }
198         }
199         return mDialog;
200     }
201 
202     @Override
getDialogMetricsCategory(int dialogId)203     public int getDialogMetricsCategory(int dialogId) {
204         switch (dialogId) {
205             case DialogEnums.ENABLE_WARNING_FROM_TOGGLE:
206             case DialogEnums.ENABLE_WARNING_FROM_SHORTCUT:
207             case DialogEnums.ENABLE_WARNING_FROM_SHORTCUT_TOGGLE:
208                 return SettingsEnums.DIALOG_ACCESSIBILITY_SERVICE_ENABLE;
209             case DialogEnums.DISABLE_WARNING_FROM_TOGGLE:
210                 return SettingsEnums.DIALOG_ACCESSIBILITY_SERVICE_DISABLE;
211             case DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL:
212                 return SettingsEnums.DIALOG_ACCESSIBILITY_TUTORIAL;
213             default:
214                 return super.getDialogMetricsCategory(dialogId);
215         }
216     }
217 
218     @Override
getUserShortcutTypes()219     int getUserShortcutTypes() {
220         return AccessibilityUtil.getUserShortcutTypesFromSettings(getPrefContext(),
221                 mComponentName);
222     }
223 
224     @Override
updateToggleServiceTitle(SettingsMainSwitchPreference switchPreference)225     protected void updateToggleServiceTitle(SettingsMainSwitchPreference switchPreference) {
226         final AccessibilityServiceInfo info = getAccessibilityServiceInfo();
227         final String switchBarText = (info == null) ? "" :
228                 getString(R.string.accessibility_service_primary_switch_title,
229                         info.getResolveInfo().loadLabel(getPackageManager()));
230         switchPreference.setTitle(switchBarText);
231     }
232 
233     @Override
updateSwitchBarToggleSwitch()234     protected void updateSwitchBarToggleSwitch() {
235         final boolean checked = isAccessibilityServiceEnabled();
236         if (mToggleServiceSwitchPreference.isChecked() == checked) {
237             return;
238         }
239         mToggleServiceSwitchPreference.setChecked(checked);
240     }
241 
isAccessibilityServiceEnabled()242     private boolean isAccessibilityServiceEnabled() {
243         return AccessibilityUtils.getEnabledServicesFromSettings(getPrefContext())
244                 .contains(mComponentName);
245     }
246 
247     /**
248      * Return whether the device is encrypted with legacy full disk encryption. Newer devices
249      * should be using File Based Encryption.
250      *
251      * @return true if device is encrypted
252      */
isFullDiskEncrypted()253     private boolean isFullDiskEncrypted() {
254         return StorageManager.isNonDefaultBlockEncrypted();
255     }
256 
257     @Override
onActivityResult(int requestCode, int resultCode, Intent data)258     public void onActivityResult(int requestCode, int resultCode, Intent data) {
259         if (requestCode == ACTIVITY_REQUEST_CONFIRM_CREDENTIAL_FOR_WEAKER_ENCRYPTION) {
260             if (resultCode == Activity.RESULT_OK) {
261                 handleConfirmServiceEnabled(/* confirmed= */ true);
262                 // The user confirmed that they accept weaker encryption when
263                 // enabling the accessibility service, so change encryption.
264                 // Since we came here asynchronously, check encryption again.
265                 if (isFullDiskEncrypted()) {
266                     mLockPatternUtils.clearEncryptionPassword();
267                     Settings.Global.putInt(getContentResolver(),
268                             Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, 0);
269                 }
270             } else {
271                 handleConfirmServiceEnabled(/* confirmed= */ false);
272             }
273         }
274     }
275 
registerPackageRemoveReceiver()276     private void registerPackageRemoveReceiver() {
277         if (mPackageRemovedReceiver != null || getContext() == null) {
278             return;
279         }
280         mPackageRemovedReceiver = new BroadcastReceiver() {
281             @Override
282             public void onReceive(Context context, Intent intent) {
283                 final String packageName = intent.getData().getSchemeSpecificPart();
284                 if (TextUtils.equals(mComponentName.getPackageName(), packageName)) {
285                     getActivity().finishAndRemoveTask();
286                 }
287             }
288         };
289         final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
290         filter.addDataScheme("package");
291         getContext().registerReceiver(mPackageRemovedReceiver, filter);
292     }
293 
unregisterPackageRemoveReceiver()294     private void unregisterPackageRemoveReceiver() {
295         if (mPackageRemovedReceiver == null || getContext() == null) {
296             return;
297         }
298         getContext().unregisterReceiver(mPackageRemovedReceiver);
299         mPackageRemovedReceiver = null;
300     }
301 
isServiceSupportAccessibilityButton()302     private boolean isServiceSupportAccessibilityButton() {
303         final AccessibilityManager ams = getPrefContext().getSystemService(
304                 AccessibilityManager.class);
305         final List<AccessibilityServiceInfo> services = ams.getInstalledAccessibilityServiceList();
306 
307         for (AccessibilityServiceInfo info : services) {
308             if ((info.flags & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0) {
309                 ServiceInfo serviceInfo = info.getResolveInfo().serviceInfo;
310                 if (serviceInfo != null && TextUtils.equals(serviceInfo.name,
311                         getAccessibilityServiceInfo().getResolveInfo().serviceInfo.name)) {
312                     return true;
313                 }
314             }
315         }
316 
317         return false;
318     }
319 
handleConfirmServiceEnabled(boolean confirmed)320     private void handleConfirmServiceEnabled(boolean confirmed) {
321         getArguments().putBoolean(AccessibilitySettings.EXTRA_CHECKED, confirmed);
322         onPreferenceToggled(mPreferenceKey, confirmed);
323     }
324 
createConfirmCredentialReasonMessage()325     private String createConfirmCredentialReasonMessage() {
326         int resId = R.string.enable_service_password_reason;
327         switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(UserHandle.myUserId())) {
328             case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: {
329                 resId = R.string.enable_service_pattern_reason;
330             }
331             break;
332             case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
333             case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: {
334                 resId = R.string.enable_service_pin_reason;
335             }
336             break;
337         }
338         return getString(resId, getAccessibilityServiceInfo().getResolveInfo()
339                 .loadLabel(getPackageManager()));
340     }
341 
342     @Override
onSwitchChanged(Switch switchView, boolean isChecked)343     public void onSwitchChanged(Switch switchView, boolean isChecked) {
344         if (isChecked != isAccessibilityServiceEnabled()) {
345             onPreferenceClick(isChecked);
346         }
347     }
348 
349     @Override
onToggleClicked(ShortcutPreference preference)350     public void onToggleClicked(ShortcutPreference preference) {
351         final int shortcutTypes = retrieveUserShortcutType(getPrefContext(),
352                 mComponentName.flattenToString(), UserShortcutType.SOFTWARE);
353         if (preference.isChecked()) {
354             if (!mToggleServiceSwitchPreference.isChecked()) {
355                 preference.setChecked(false);
356                 showPopupDialog(DialogEnums.ENABLE_WARNING_FROM_SHORTCUT_TOGGLE);
357             } else {
358                 AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), shortcutTypes,
359                         mComponentName);
360                 showPopupDialog(DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL);
361             }
362         } else {
363             AccessibilityUtil.optOutAllValuesFromSettings(getPrefContext(), shortcutTypes,
364                     mComponentName);
365         }
366         mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext()));
367     }
368 
369     @Override
onSettingsClicked(ShortcutPreference preference)370     public void onSettingsClicked(ShortcutPreference preference) {
371         final boolean isServiceOnOrShortcutAdded = mShortcutPreference.isChecked()
372                 || mToggleServiceSwitchPreference.isChecked();
373         showPopupDialog(isServiceOnOrShortcutAdded ? DialogEnums.EDIT_SHORTCUT
374                 : DialogEnums.ENABLE_WARNING_FROM_SHORTCUT);
375     }
376 
377     @Override
onProcessArguments(Bundle arguments)378     protected void onProcessArguments(Bundle arguments) {
379         super.onProcessArguments(arguments);
380         // Settings title and intent.
381         String settingsTitle = arguments.getString(AccessibilitySettings.EXTRA_SETTINGS_TITLE);
382         String settingsComponentName = arguments.getString(
383                 AccessibilitySettings.EXTRA_SETTINGS_COMPONENT_NAME);
384         if (!TextUtils.isEmpty(settingsTitle) && !TextUtils.isEmpty(settingsComponentName)) {
385             Intent settingsIntent = new Intent(Intent.ACTION_MAIN).setComponent(
386                     ComponentName.unflattenFromString(settingsComponentName.toString()));
387             if (!getPackageManager().queryIntentActivities(settingsIntent, 0).isEmpty()) {
388                 mSettingsTitle = settingsTitle;
389                 mSettingsIntent = settingsIntent;
390                 setHasOptionsMenu(true);
391             }
392         }
393 
394         mComponentName = arguments.getParcelable(AccessibilitySettings.EXTRA_COMPONENT_NAME);
395 
396         // Settings animated image.
397         final int animatedImageRes = arguments.getInt(
398                 AccessibilitySettings.EXTRA_ANIMATED_IMAGE_RES);
399         if (animatedImageRes > 0) {
400             mImageUri = new Uri.Builder().scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
401                     .authority(mComponentName.getPackageName())
402                     .appendPath(String.valueOf(animatedImageRes))
403                     .build();
404         }
405 
406         // Get Accessibility service name.
407         mPackageName = getAccessibilityServiceInfo().getResolveInfo().loadLabel(
408                 getPackageManager());
409     }
410 
onDialogButtonFromDisableToggleClicked(DialogInterface dialog, int which)411     private void onDialogButtonFromDisableToggleClicked(DialogInterface dialog, int which) {
412         switch (which) {
413             case DialogInterface.BUTTON_POSITIVE:
414                 handleConfirmServiceEnabled(/* confirmed= */ false);
415                 break;
416             case DialogInterface.BUTTON_NEGATIVE:
417                 handleConfirmServiceEnabled(/* confirmed= */ true);
418                 break;
419             default:
420                 throw new IllegalArgumentException("Unexpected button identifier");
421         }
422     }
423 
onDialogButtonFromEnableToggleClicked(View view)424     private void onDialogButtonFromEnableToggleClicked(View view) {
425         final int viewId = view.getId();
426         if (viewId == R.id.permission_enable_allow_button) {
427             onAllowButtonFromEnableToggleClicked();
428         } else if (viewId == R.id.permission_enable_deny_button) {
429             onDenyButtonFromEnableToggleClicked();
430         } else {
431             throw new IllegalArgumentException("Unexpected view id");
432         }
433     }
434 
onDialogButtonFromUninstallClicked()435     private void onDialogButtonFromUninstallClicked() {
436         mDialog.dismiss();
437         final Intent uninstallIntent = createUninstallPackageActivityIntent();
438         if (uninstallIntent == null) {
439             return;
440         }
441         startActivity(uninstallIntent);
442     }
443 
444     @Nullable
createUninstallPackageActivityIntent()445     private Intent createUninstallPackageActivityIntent() {
446         final AccessibilityServiceInfo a11yServiceInfo = getAccessibilityServiceInfo();
447         if (a11yServiceInfo == null) {
448             Log.w(TAG, "createUnInstallIntent -- invalid a11yServiceInfo");
449             return null;
450         }
451         final ApplicationInfo appInfo =
452                 a11yServiceInfo.getResolveInfo().serviceInfo.applicationInfo;
453         final Uri packageUri = Uri.parse("package:" + appInfo.packageName);
454         final Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri);
455         return uninstallIntent;
456     }
457 
458     @Override
onStop()459     public void onStop() {
460         super.onStop();
461         unregisterPackageRemoveReceiver();
462     }
463 
onAllowButtonFromEnableToggleClicked()464     private void onAllowButtonFromEnableToggleClicked() {
465         if (isFullDiskEncrypted()) {
466             final String title = createConfirmCredentialReasonMessage();
467             final Intent intent = ConfirmDeviceCredentialActivity.createIntent(title, /* details= */
468                     null);
469             startActivityForResult(intent,
470                     ACTIVITY_REQUEST_CONFIRM_CREDENTIAL_FOR_WEAKER_ENCRYPTION);
471         } else {
472             handleConfirmServiceEnabled(/* confirmed= */ true);
473             if (isServiceSupportAccessibilityButton()) {
474                 mIsDialogShown.set(false);
475                 showPopupDialog(DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL);
476             }
477         }
478 
479         mDialog.dismiss();
480     }
481 
onDenyButtonFromEnableToggleClicked()482     private void onDenyButtonFromEnableToggleClicked() {
483         handleConfirmServiceEnabled(/* confirmed= */ false);
484         mDialog.dismiss();
485     }
486 
onDialogButtonFromShortcutToggleClicked(View view)487     void onDialogButtonFromShortcutToggleClicked(View view) {
488         final int viewId = view.getId();
489         if (viewId == R.id.permission_enable_allow_button) {
490             onAllowButtonFromShortcutToggleClicked();
491         } else if (viewId == R.id.permission_enable_deny_button) {
492             onDenyButtonFromShortcutToggleClicked();
493         } else {
494             throw new IllegalArgumentException("Unexpected view id");
495         }
496     }
497 
onAllowButtonFromShortcutToggleClicked()498     private void onAllowButtonFromShortcutToggleClicked() {
499         mShortcutPreference.setChecked(true);
500 
501         final int shortcutTypes = retrieveUserShortcutType(getPrefContext(),
502                 mComponentName.flattenToString(), UserShortcutType.SOFTWARE);
503         AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), shortcutTypes, mComponentName);
504 
505         mIsDialogShown.set(false);
506         showPopupDialog(DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL);
507 
508         mDialog.dismiss();
509 
510         mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext()));
511     }
512 
onDenyButtonFromShortcutToggleClicked()513     private void onDenyButtonFromShortcutToggleClicked() {
514         mShortcutPreference.setChecked(false);
515 
516         mDialog.dismiss();
517     }
518 
onDialogButtonFromShortcutClicked(View view)519     void onDialogButtonFromShortcutClicked(View view) {
520         final int viewId = view.getId();
521         if (viewId == R.id.permission_enable_allow_button) {
522             onAllowButtonFromShortcutClicked();
523         } else if (viewId == R.id.permission_enable_deny_button) {
524             onDenyButtonFromShortcutClicked();
525         } else {
526             throw new IllegalArgumentException("Unexpected view id");
527         }
528     }
529 
onAllowButtonFromShortcutClicked()530     private void onAllowButtonFromShortcutClicked() {
531         mIsDialogShown.set(false);
532         showPopupDialog(DialogEnums.EDIT_SHORTCUT);
533 
534         mDialog.dismiss();
535     }
536 
onDenyButtonFromShortcutClicked()537     private void onDenyButtonFromShortcutClicked() {
538         mDialog.dismiss();
539     }
540 
onPreferenceClick(boolean isChecked)541     private boolean onPreferenceClick(boolean isChecked) {
542         if (isChecked) {
543             mToggleServiceSwitchPreference.setChecked(false);
544             getArguments().putBoolean(AccessibilitySettings.EXTRA_CHECKED,
545                     /* disableService */ false);
546             if (!mShortcutPreference.isChecked()) {
547                 showPopupDialog(DialogEnums.ENABLE_WARNING_FROM_TOGGLE);
548             } else {
549                 handleConfirmServiceEnabled(/* confirmed= */ true);
550                 if (isServiceSupportAccessibilityButton()) {
551                     showPopupDialog(DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL);
552                 }
553             }
554         } else {
555             mToggleServiceSwitchPreference.setChecked(true);
556             getArguments().putBoolean(AccessibilitySettings.EXTRA_CHECKED,
557                     /* enableService */ true);
558             showDialog(DialogEnums.DISABLE_WARNING_FROM_TOGGLE);
559         }
560         return true;
561     }
562 
showPopupDialog(int dialogId)563     private void showPopupDialog(int dialogId) {
564         if (mIsDialogShown.compareAndSet(/* expect= */ false, /* update= */ true)) {
565             showDialog(dialogId);
566             setOnDismissListener(
567                     dialog -> mIsDialogShown.compareAndSet(/* expect= */ true, /* update= */
568                             false));
569         }
570     }
571 }
572