• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE;
20 import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE;
21 import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE;
22 
23 import android.annotation.NonNull;
24 import android.annotation.Nullable;
25 import android.annotation.SuppressLint;
26 import android.content.ComponentName;
27 import android.content.Context;
28 import android.graphics.drawable.Drawable;
29 import android.os.UserHandle;
30 import android.view.View;
31 import android.view.accessibility.AccessibilityManager;
32 
33 import com.android.internal.accessibility.common.ShortcutConstants;
34 import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType;
35 import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
36 import com.android.internal.accessibility.dialog.TargetAdapter.ViewHolder;
37 import com.android.internal.accessibility.util.ShortcutUtils;
38 import com.android.internal.annotations.VisibleForTesting;
39 
40 import java.util.Set;
41 
42 /**
43  * Abstract base class for creating various target related to accessibility service, accessibility
44  * activity, and allowlisting features.
45  *
46  * <p> Disables accessibility features that are not permitted in adding a restricted padlock icon
47  * and showing admin support message dialog.
48  */
49 public abstract class AccessibilityTarget implements TargetOperations, OnTargetSelectedListener,
50         OnTargetCheckedChangeListener {
51     private Context mContext;
52     @UserShortcutType
53     private int mShortcutType;
54     @AccessibilityFragmentType
55     private int mFragmentType;
56     private boolean mShortcutEnabled;
57     private String mId;
58     private int mUid;
59     private ComponentName mComponentName;
60     private CharSequence mLabel;
61     private Drawable mIcon;
62     private String mKey;
63     private CharSequence mStateDescription;
64 
65     @VisibleForTesting
AccessibilityTarget(Context context, @UserShortcutType int shortcutType, @AccessibilityFragmentType int fragmentType, boolean isShortcutSwitched, String id, int uid, CharSequence label, Drawable icon, String key)66     public AccessibilityTarget(Context context, @UserShortcutType int shortcutType,
67             @AccessibilityFragmentType int fragmentType, boolean isShortcutSwitched, String id,
68             int uid, CharSequence label, Drawable icon, String key) {
69         if (!isRecognizedShortcutType(shortcutType)) {
70             throw new IllegalArgumentException(
71                     "Unexpected shortcut type " + ShortcutUtils.convertToKey(shortcutType));
72         }
73         mContext = context;
74         mShortcutType = shortcutType;
75         mFragmentType = fragmentType;
76         mShortcutEnabled = isShortcutSwitched;
77         mId = id;
78         mUid = uid;
79         mComponentName = ComponentName.unflattenFromString(id);
80         mLabel = label;
81         mIcon = icon;
82         mKey = key;
83     }
84 
85     @Override
updateActionItem(@onNull ViewHolder holder, @ShortcutConstants.ShortcutMenuMode int shortcutMenuMode)86     public void updateActionItem(@NonNull ViewHolder holder,
87             @ShortcutConstants.ShortcutMenuMode int shortcutMenuMode) {
88         // Resetting the enable state of the item to avoid the previous wrong state of RecyclerView.
89         holder.mCheckBoxView.setEnabled(true);
90         holder.mIconView.setEnabled(true);
91         holder.mLabelView.setEnabled(true);
92         holder.mStatusView.setEnabled(true);
93 
94         final boolean isEditMenuMode =
95                 shortcutMenuMode == ShortcutConstants.ShortcutMenuMode.EDIT;
96         holder.mCheckBoxView.setChecked(isEditMenuMode && isShortcutEnabled());
97         holder.mCheckBoxView.setVisibility(isEditMenuMode ? View.VISIBLE : View.GONE);
98         holder.mIconView.setImageDrawable(getIcon());
99         holder.mLabelView.setText(getLabel());
100         holder.mStatusView.setVisibility(View.GONE);
101     }
102 
103     @SuppressLint("MissingPermission")
104     @Override
onSelected()105     public void onSelected() {
106         final AccessibilityManager am =
107                 getContext().getSystemService(AccessibilityManager.class);
108         if (am == null) {
109             return;
110         }
111         am.performAccessibilityShortcut(getContext().getDisplayId(), mShortcutType, getId());
112     }
113 
114     @SuppressLint("MissingPermission")
115     @Override
onCheckedChanged(boolean isChecked)116     public void onCheckedChanged(boolean isChecked) {
117         setShortcutEnabled(isChecked);
118         final AccessibilityManager am = getContext().getSystemService(AccessibilityManager.class);
119         am.enableShortcutsForTargets(
120                 isChecked, getShortcutType(), Set.of(mId), UserHandle.myUserId());
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 @UserShortcutType 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     /**
182      * Determines if the provided shortcut type is valid for use with AccessibilityTargets.
183      * @param shortcutType shortcut type to check.
184      * @return {@code true} if the shortcut type can be used, {@code false} otherwise.
185      */
186     @VisibleForTesting
isRecognizedShortcutType(@serShortcutType int shortcutType)187     public static boolean isRecognizedShortcutType(@UserShortcutType int shortcutType) {
188         int mask = SOFTWARE | HARDWARE;
189         if (android.provider.Flags.a11yStandaloneGestureEnabled()) {
190             mask = mask | GESTURE;
191         }
192         return (shortcutType != 0 && (shortcutType & mask) == shortcutType);
193     }
194 }
195