• 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.settings.accessibility;
18 
19 import static com.android.settings.accessibility.AccessibilityStatsLogUtils.logAccessibilityServiceEnabled;
20 
21 import android.accessibilityservice.AccessibilityShortcutInfo;
22 import android.app.ActivityOptions;
23 import android.content.ActivityNotFoundException;
24 import android.content.ComponentName;
25 import android.content.ContentResolver;
26 import android.content.Intent;
27 import android.content.pm.ActivityInfo;
28 import android.net.Uri;
29 import android.os.Bundle;
30 import android.os.UserHandle;
31 import android.text.TextUtils;
32 import android.util.Log;
33 import android.view.LayoutInflater;
34 import android.view.Menu;
35 import android.view.MenuInflater;
36 import android.view.View;
37 import android.view.ViewGroup;
38 import android.view.accessibility.AccessibilityManager;
39 
40 import androidx.annotation.Nullable;
41 import androidx.preference.Preference;
42 
43 import com.android.settings.R;
44 
45 import java.util.ArrayList;
46 import java.util.List;
47 
48 /** Fragment for providing open activity button. */
49 public class LaunchAccessibilityActivityPreferenceFragment extends ToggleFeaturePreferenceFragment {
50     private static final String TAG = "LaunchA11yActivity";
51     private static final String EMPTY_STRING = "";
52     protected static final String KEY_LAUNCH_PREFERENCE = "launch_preference";
53 
54     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)55     public View onCreateView(LayoutInflater inflater, ViewGroup container,
56             Bundle savedInstanceState) {
57         final View view = super.onCreateView(inflater, container, savedInstanceState);
58 
59         // Init new preference to replace the switch preference instead.
60         initLaunchPreference();
61         removePreference(KEY_USE_SERVICE_PREFERENCE);
62         return view;
63     };
64 
65     @Override
onPreferenceToggled(String preferenceKey, boolean enabled)66     protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
67         // Do nothing.
68     }
69 
70     @Override
onProcessArguments(Bundle arguments)71     protected void onProcessArguments(Bundle arguments) {
72         super.onProcessArguments(arguments);
73 
74         mComponentName = arguments.getParcelable(AccessibilitySettings.EXTRA_COMPONENT_NAME);
75         final ActivityInfo info = getAccessibilityShortcutInfo().getActivityInfo();
76         mPackageName = info.loadLabel(getPackageManager()).toString();
77 
78         // Settings animated image.
79         final int animatedImageRes = arguments.getInt(
80                 AccessibilitySettings.EXTRA_ANIMATED_IMAGE_RES);
81         if (animatedImageRes > 0) {
82             mImageUri = new Uri.Builder().scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
83                     .authority(mComponentName.getPackageName())
84                     .appendPath(String.valueOf(animatedImageRes))
85                     .build();
86         }
87 
88         // Settings html description.
89         mHtmlDescription = arguments.getCharSequence(AccessibilitySettings.EXTRA_HTML_DESCRIPTION);
90 
91         // Settings title and intent.
92         final String settingsTitle = arguments.getString(
93                 AccessibilitySettings.EXTRA_SETTINGS_TITLE);
94         mSettingsIntent = TextUtils.isEmpty(settingsTitle) ? null : getSettingsIntent(arguments);
95         mSettingsTitle = (mSettingsIntent == null) ? null : settingsTitle;
96     }
97 
98     @Override
getUserShortcutTypes()99     int getUserShortcutTypes() {
100         return AccessibilityUtil.getUserShortcutTypesFromSettings(getPrefContext(),
101                 mComponentName);
102     }
103 
104     @Override
onCreateOptionsMenu(Menu menu, MenuInflater inflater)105     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
106         // Do not call super. We don't want to see the "Help & feedback" option on this page so as
107         // not to confuse users who think they might be able to send feedback about a specific
108         // accessibility service from this page.
109     }
110 
111     // IMPORTANT: Refresh the info since there are dynamically changing capabilities.
getAccessibilityShortcutInfo()112     private AccessibilityShortcutInfo getAccessibilityShortcutInfo() {
113         final List<AccessibilityShortcutInfo> infos = AccessibilityManager.getInstance(
114                 getPrefContext()).getInstalledAccessibilityShortcutListAsUser(getPrefContext(),
115                 UserHandle.myUserId());
116 
117         for (int i = 0, count = infos.size(); i < count; i++) {
118             AccessibilityShortcutInfo shortcutInfo = infos.get(i);
119             ActivityInfo activityInfo = shortcutInfo.getActivityInfo();
120             if (mComponentName.getPackageName().equals(activityInfo.packageName)
121                     && mComponentName.getClassName().equals(activityInfo.name)) {
122                 return shortcutInfo;
123             }
124         }
125         return null;
126     }
127 
128     /** Customizes the order by preference key. */
getPreferenceOrderList()129     protected List<String> getPreferenceOrderList() {
130         final List<String> lists = new ArrayList<>();
131         lists.add(KEY_ANIMATED_IMAGE);
132         lists.add(KEY_LAUNCH_PREFERENCE);
133         lists.add(KEY_GENERAL_CATEGORY);
134         lists.add(KEY_HTML_DESCRIPTION_PREFERENCE);
135         return lists;
136     }
137 
initLaunchPreference()138     private void initLaunchPreference() {
139         final Preference launchPreference = new Preference(getPrefContext());
140         launchPreference.setKey(KEY_LAUNCH_PREFERENCE);
141 
142         final AccessibilityShortcutInfo info = getAccessibilityShortcutInfo();
143         final String switchBarText = (info == null) ? EMPTY_STRING : getString(
144                 R.string.accessibility_service_primary_open_title,
145                 info.getActivityInfo().loadLabel(getPackageManager()));
146         launchPreference.setTitle(switchBarText);
147 
148         launchPreference.setOnPreferenceClickListener(preference -> {
149             logAccessibilityServiceEnabled(mComponentName, /* enabled= */ true);
150             launchShortcutTargetActivity(getPrefContext().getDisplayId(), mComponentName);
151             return true;
152         });
153         getPreferenceScreen().addPreference(launchPreference);
154     }
155 
launchShortcutTargetActivity(int displayId, ComponentName name)156     private void launchShortcutTargetActivity(int displayId, ComponentName name) {
157         final Intent intent = new Intent();
158         final Bundle bundle = ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle();
159 
160         intent.setComponent(name);
161         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
162         try {
163             final int userId = UserHandle.myUserId();
164             getPrefContext().startActivityAsUser(intent, bundle, UserHandle.of(userId));
165         } catch (ActivityNotFoundException ignore) {
166             // ignore the exception
167             Log.w(TAG, "Target activity not found.");
168         }
169     }
170 
171     @Nullable
getSettingsIntent(Bundle arguments)172     private Intent getSettingsIntent(Bundle arguments) {
173         final String settingsComponentName = arguments.getString(
174                 AccessibilitySettings.EXTRA_SETTINGS_COMPONENT_NAME);
175         if (TextUtils.isEmpty(settingsComponentName)) {
176             return null;
177         }
178 
179         final Intent settingsIntent = new Intent(Intent.ACTION_MAIN).setComponent(
180                 ComponentName.unflattenFromString(settingsComponentName));
181         if (getPackageManager().queryIntentActivities(settingsIntent, /* flags= */ 0).isEmpty()) {
182             return null;
183         }
184 
185         return settingsIntent;
186     }
187 }
188