1 /*
2  * Copyright (C) 2023 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.shortcuts;
18 
19 import android.content.Context;
20 import android.os.UserHandle;
21 import android.view.accessibility.AccessibilityManager;
22 import android.view.accessibility.Flags;
23 
24 import androidx.annotation.NonNull;
25 import androidx.preference.Preference;
26 
27 import com.android.internal.accessibility.common.ShortcutConstants;
28 import com.android.internal.accessibility.util.ShortcutUtils;
29 import com.android.internal.util.Preconditions;
30 import com.android.settings.core.BasePreferenceController;
31 
32 import java.util.Collections;
33 import java.util.Set;
34 
35 /**
36  * A base preference controller for {@link ShortcutOptionPreference}
37  */
38 public abstract class ShortcutOptionPreferenceController extends BasePreferenceController
39         implements Preference.OnPreferenceChangeListener {
40     private Set<String> mShortcutTargets = Collections.emptySet();
41     private boolean mIsInSetupWizard;
42 
ShortcutOptionPreferenceController(Context context, String preferenceKey)43     public ShortcutOptionPreferenceController(Context context, String preferenceKey) {
44         super(context, preferenceKey);
45     }
46 
47     @Override
updateState(Preference preference)48     public void updateState(Preference preference) {
49         super.updateState(preference);
50         if (getPreferenceKey().equals(preference.getKey())
51                 && preference instanceof ShortcutOptionPreference) {
52             ((ShortcutOptionPreference) preference).setChecked(isChecked());
53         }
54     }
55 
56     @Override
getAvailabilityStatus()57     public int getAvailabilityStatus() {
58         if (isShortcutAvailable()) {
59             return AVAILABLE_UNSEARCHABLE;
60         }
61         return CONDITIONALLY_UNAVAILABLE;
62     }
63 
64     /**
65      * Set the targets (i.e. a11y features) to be configured with the a11y shortcut option.
66      * <p>
67      * Note: the shortcutTargets cannot be empty, since the edit a11y shortcut option
68      * is meant to configure the shortcut options for an a11y feature.
69      * </>
70      *
71      * @param shortcutTargets the a11y features, like color correction, Talkback, etc.
72      * @throws NullPointerException     if the {@code shortcutTargets} was {@code null}
73      * @throws IllegalArgumentException if the {@code shortcutTargets} was empty
74      */
setShortcutTargets(Set<String> shortcutTargets)75     public void setShortcutTargets(Set<String> shortcutTargets) {
76         Preconditions.checkCollectionNotEmpty(shortcutTargets, /* valueName= */ "a11y targets");
77 
78         this.mShortcutTargets = shortcutTargets;
79     }
80 
setInSetupWizard(boolean isInSetupWizard)81     public void setInSetupWizard(boolean isInSetupWizard) {
82         this.mIsInSetupWizard = isInSetupWizard;
83     }
84 
getShortcutTargets()85     protected Set<String> getShortcutTargets() {
86         return mShortcutTargets;
87     }
88 
isInSetupWizard()89     protected boolean isInSetupWizard() {
90         return mIsInSetupWizard;
91     }
92 
93     @Override
onPreferenceChange(@onNull Preference preference, Object newValue)94     public final boolean onPreferenceChange(@NonNull Preference preference, Object newValue) {
95         enableShortcutForTargets((Boolean) newValue);
96         return false;
97     }
98 
99     @ShortcutConstants.UserShortcutType
getShortcutType()100     protected int getShortcutType() {
101         return ShortcutConstants.UserShortcutType.DEFAULT;
102     }
103 
104     /**
105      * Returns true if the shortcut is associated to the targets
106      */
isChecked()107     protected boolean isChecked() {
108         Set<String> targets = ShortcutUtils.getShortcutTargetsFromSettings(
109                 mContext, getShortcutType(), UserHandle.myUserId());
110 
111         return !targets.isEmpty() && targets.containsAll(getShortcutTargets());
112     }
113 
114     /**
115      * Enable or disable the shortcut for the given accessibility features.
116      */
enableShortcutForTargets(boolean enable)117     protected void enableShortcutForTargets(boolean enable) {
118         Set<String> shortcutTargets = getShortcutTargets();
119         @ShortcutConstants.UserShortcutType int shortcutType = getShortcutType();
120 
121         if (Flags.a11yQsShortcut()) {
122             AccessibilityManager a11yManager = mContext.getSystemService(
123                     AccessibilityManager.class);
124             if (a11yManager != null) {
125                 a11yManager.enableShortcutsForTargets(enable, shortcutType, shortcutTargets,
126                         UserHandle.myUserId());
127             }
128             return;
129         }
130 
131         if (enable) {
132             for (String target : shortcutTargets) {
133                 ShortcutUtils.optInValueToSettings(mContext, shortcutType, target);
134             }
135         } else {
136             for (String target : shortcutTargets) {
137                 ShortcutUtils.optOutValueFromSettings(mContext, shortcutType, target);
138             }
139         }
140         ShortcutUtils.updateInvisibleToggleAccessibilityServiceEnableState(
141                 mContext, shortcutTargets, UserHandle.myUserId());
142     }
143 
144     /**
145      * Returns true when the user can associate a shortcut to the targets
146      */
isShortcutAvailable()147     protected abstract boolean isShortcutAvailable();
148 }
149