1 /*
2  * Copyright (C) 2020 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.internal.accessibility.dialog;
18 
19 import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
20 import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
21 
22 import static com.android.internal.accessibility.util.ShortcutUtils.convertToUserType;
23 import static com.android.internal.accessibility.util.ShortcutUtils.optInValueToSettings;
24 import static com.android.internal.accessibility.util.ShortcutUtils.optOutValueFromSettings;
25 
26 import android.annotation.NonNull;
27 import android.annotation.Nullable;
28 import android.content.ComponentName;
29 import android.content.Context;
30 import android.graphics.drawable.Drawable;
31 import android.view.View;
32 import android.view.accessibility.AccessibilityManager;
33 import android.view.accessibility.AccessibilityManager.ShortcutType;
34 
35 import com.android.internal.accessibility.common.ShortcutConstants;
36 import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType;
37 import com.android.internal.accessibility.dialog.TargetAdapter.ViewHolder;
38 import com.android.internal.annotations.VisibleForTesting;
39 
40 /**
41  * Abstract base class for creating various target related to accessibility service, accessibility
42  * activity, and allowlisting features.
43  *
44  * <p> Disables accessibility features that are not permitted in adding a restricted padlock icon
45  * and showing admin support message dialog.
46  */
47 public abstract class AccessibilityTarget implements TargetOperations, OnTargetSelectedListener,
48         OnTargetCheckedChangeListener {
49     private Context mContext;
50     @ShortcutType
51     private int mShortcutType;
52     @AccessibilityFragmentType
53     private int mFragmentType;
54     private boolean mShortcutEnabled;
55     private String mId;
56     private int mUid;
57     private ComponentName mComponentName;
58     private CharSequence mLabel;
59     private Drawable mIcon;
60     private String mKey;
61     private CharSequence mStateDescription;
62 
63     @VisibleForTesting
AccessibilityTarget(Context context, @ShortcutType int shortcutType, @AccessibilityFragmentType int fragmentType, boolean isShortcutSwitched, String id, int uid, CharSequence label, Drawable icon, String key)64     public AccessibilityTarget(Context context, @ShortcutType int shortcutType,
65             @AccessibilityFragmentType int fragmentType, boolean isShortcutSwitched, String id,
66             int uid, CharSequence label, Drawable icon, String key) {
67         mContext = context;
68         mShortcutType = shortcutType;
69         mFragmentType = fragmentType;
70         mShortcutEnabled = isShortcutSwitched;
71         mId = id;
72         mUid = uid;
73         mComponentName = ComponentName.unflattenFromString(id);
74         mLabel = label;
75         mIcon = icon;
76         mKey = key;
77     }
78 
79     @Override
updateActionItem(@onNull ViewHolder holder, @ShortcutConstants.ShortcutMenuMode int shortcutMenuMode)80     public void updateActionItem(@NonNull ViewHolder holder,
81             @ShortcutConstants.ShortcutMenuMode int shortcutMenuMode) {
82         // Resetting the enable state of the item to avoid the previous wrong state of RecyclerView.
83         holder.mCheckBoxView.setEnabled(true);
84         holder.mIconView.setEnabled(true);
85         holder.mLabelView.setEnabled(true);
86         holder.mStatusView.setEnabled(true);
87 
88         final boolean isEditMenuMode =
89                 shortcutMenuMode == ShortcutConstants.ShortcutMenuMode.EDIT;
90         holder.mCheckBoxView.setChecked(isEditMenuMode && isShortcutEnabled());
91         holder.mCheckBoxView.setVisibility(isEditMenuMode ? View.VISIBLE : View.GONE);
92         holder.mIconView.setImageDrawable(getIcon());
93         holder.mLabelView.setText(getLabel());
94         holder.mStatusView.setVisibility(View.GONE);
95     }
96 
97     @Override
onSelected()98     public void onSelected() {
99         final AccessibilityManager am =
100                 getContext().getSystemService(AccessibilityManager.class);
101         switch (getShortcutType()) {
102             case ACCESSIBILITY_BUTTON:
103                 am.notifyAccessibilityButtonClicked(getContext().getDisplayId(), getId());
104                 return;
105             case ACCESSIBILITY_SHORTCUT_KEY:
106                 am.performAccessibilityShortcut(getId());
107                 return;
108             default:
109                 throw new IllegalStateException("Unexpected shortcut type");
110         }
111     }
112 
113     @Override
onCheckedChanged(boolean isChecked)114     public void onCheckedChanged(boolean isChecked) {
115         setShortcutEnabled(isChecked);
116         if (isChecked) {
117             optInValueToSettings(getContext(), convertToUserType(getShortcutType()), getId());
118         } else {
119             optOutValueFromSettings(getContext(), convertToUserType(getShortcutType()), getId());
120         }
121     }
122 
setStateDescription(CharSequence stateDescription)123     public void setStateDescription(CharSequence stateDescription) {
124         mStateDescription = stateDescription;
125     }
126 
127     /**
128      * Gets the state description of this feature target.
129      *
130      * @return the state description
131      */
132     @Nullable
getStateDescription()133     public CharSequence getStateDescription() {
134         return mStateDescription;
135     }
136 
setShortcutEnabled(boolean enabled)137     public void setShortcutEnabled(boolean enabled) {
138         mShortcutEnabled = enabled;
139     }
140 
getContext()141     public Context getContext() {
142         return mContext;
143     }
144 
getShortcutType()145     public @ShortcutType int getShortcutType() {
146         return mShortcutType;
147     }
148 
getFragmentType()149     public @AccessibilityFragmentType int getFragmentType() {
150         return mFragmentType;
151     }
152 
isShortcutEnabled()153     public boolean isShortcutEnabled() {
154         return mShortcutEnabled;
155     }
156 
getId()157     public String getId() {
158         return mId;
159     }
160 
getUid()161     public int getUid() {
162         return mUid;
163     }
164 
getComponentName()165     public ComponentName getComponentName() {
166         return mComponentName;
167     }
168 
getLabel()169     public CharSequence getLabel() {
170         return mLabel;
171     }
172 
getIcon()173     public Drawable getIcon() {
174         return mIcon;
175     }
176 
getKey()177     public String getKey() {
178         return mKey;
179     }
180 }
181