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