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 import static com.android.settingslib.widget.ButtonPreference.SIZE_EXTRA_LARGE; 21 import static com.android.settingslib.widget.ButtonPreference.TYPE_TONAL; 22 23 import android.accessibilityservice.AccessibilityShortcutInfo; 24 import android.app.ActivityOptions; 25 import android.content.ActivityNotFoundException; 26 import android.content.ComponentName; 27 import android.content.ContentResolver; 28 import android.content.Intent; 29 import android.content.pm.ActivityInfo; 30 import android.net.Uri; 31 import android.os.Bundle; 32 import android.os.UserHandle; 33 import android.text.TextUtils; 34 import android.util.Log; 35 import android.view.LayoutInflater; 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 import com.android.settingslib.widget.ButtonPreference; 45 import com.android.settingslib.widget.SettingsThemeHelper; 46 47 import java.util.ArrayList; 48 import java.util.List; 49 50 /** Fragment for providing open activity button. */ 51 public class LaunchAccessibilityActivityPreferenceFragment extends ToggleFeaturePreferenceFragment { 52 53 private static final String TAG = "LaunchAccessibilityActivityPreferenceFragment"; 54 private static final String EMPTY_STRING = ""; 55 protected static final String KEY_LAUNCH_PREFERENCE = "launch_preference"; 56 57 private ComponentName mTileComponentName; 58 59 @Override getMetricsCategory()60 public int getMetricsCategory() { 61 return getArguments().getInt(AccessibilitySettings.EXTRA_METRICS_CATEGORY); 62 } 63 64 @Override getFeedbackCategory()65 public int getFeedbackCategory() { 66 return getArguments().getInt(AccessibilitySettings.EXTRA_FEEDBACK_CATEGORY); 67 } 68 69 @Override onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)70 public View onCreateView(LayoutInflater inflater, ViewGroup container, 71 Bundle savedInstanceState) { 72 // Init new preference to replace the switch preference instead. 73 initLaunchPreference(); 74 75 final View view = super.onCreateView(inflater, container, savedInstanceState); 76 removePreference(getUseServicePreferenceKey()); 77 return view; 78 } 79 80 @Override onProcessArguments(Bundle arguments)81 protected void onProcessArguments(Bundle arguments) { 82 super.onProcessArguments(arguments); 83 mComponentName = arguments.getParcelable(AccessibilitySettings.EXTRA_COMPONENT_NAME); 84 final ActivityInfo info = getAccessibilityShortcutInfo().getActivityInfo(); 85 mFeatureName = info.loadLabel(getPackageManager()); 86 87 // Settings animated image. 88 final int animatedImageRes = arguments.getInt( 89 AccessibilitySettings.EXTRA_ANIMATED_IMAGE_RES); 90 if (animatedImageRes > 0) { 91 mImageUri = new Uri.Builder().scheme(ContentResolver.SCHEME_ANDROID_RESOURCE) 92 .authority(mComponentName.getPackageName()) 93 .appendPath(String.valueOf(animatedImageRes)) 94 .build(); 95 } 96 97 // Settings html description. 98 mHtmlDescription = arguments.getCharSequence(AccessibilitySettings.EXTRA_HTML_DESCRIPTION); 99 100 // Settings title and intent. 101 final String settingsTitle = arguments.getString( 102 AccessibilitySettings.EXTRA_SETTINGS_TITLE); 103 mSettingsIntent = TextUtils.isEmpty(settingsTitle) ? null : getSettingsIntent(arguments); 104 mSettingsTitle = (mSettingsIntent == null) ? null : settingsTitle; 105 106 // Tile service. 107 if (arguments.containsKey(AccessibilitySettings.EXTRA_TILE_SERVICE_COMPONENT_NAME)) { 108 final String tileServiceComponentName = arguments.getString( 109 AccessibilitySettings.EXTRA_TILE_SERVICE_COMPONENT_NAME); 110 mTileComponentName = ComponentName.unflattenFromString(tileServiceComponentName); 111 } 112 } 113 114 @Override getUserShortcutTypes()115 int getUserShortcutTypes() { 116 return AccessibilityUtil.getUserShortcutTypesFromSettings(getPrefContext(), 117 mComponentName); 118 } 119 120 @Override getTileComponentName()121 ComponentName getTileComponentName() { 122 return mTileComponentName; 123 } 124 125 // IMPORTANT: Refresh the info since there are dynamically changing capabilities. getAccessibilityShortcutInfo()126 private AccessibilityShortcutInfo getAccessibilityShortcutInfo() { 127 final List<AccessibilityShortcutInfo> infos = AccessibilityManager.getInstance( 128 getPrefContext()).getInstalledAccessibilityShortcutListAsUser(getPrefContext(), 129 UserHandle.myUserId()); 130 131 for (int i = 0, count = infos.size(); i < count; i++) { 132 AccessibilityShortcutInfo shortcutInfo = infos.get(i); 133 ActivityInfo activityInfo = shortcutInfo.getActivityInfo(); 134 if (mComponentName.getPackageName().equals(activityInfo.packageName) 135 && mComponentName.getClassName().equals(activityInfo.name)) { 136 return shortcutInfo; 137 } 138 } 139 return null; 140 } 141 142 /** Customizes the order by preference key. */ getPreferenceOrderList()143 protected List<String> getPreferenceOrderList() { 144 final List<String> lists = new ArrayList<>(); 145 lists.add(KEY_TOP_INTRO_PREFERENCE); 146 lists.add(KEY_ANIMATED_IMAGE); 147 lists.add(KEY_LAUNCH_PREFERENCE); 148 lists.add(KEY_GENERAL_CATEGORY); 149 lists.add(KEY_HTML_DESCRIPTION_PREFERENCE); 150 return lists; 151 } 152 initLaunchPreference()153 private void initLaunchPreference() { 154 final Preference launchPreference; 155 if (SettingsThemeHelper.isExpressiveTheme(getPrefContext())) { 156 launchPreference = new ButtonPreference(getPrefContext()); 157 ((ButtonPreference) launchPreference).setButtonStyle(TYPE_TONAL, SIZE_EXTRA_LARGE); 158 } else { 159 launchPreference = new Preference(getPrefContext()); 160 launchPreference.setLayoutResource(R.layout.accessibility_launch_activity_preference); 161 } 162 launchPreference.setKey(KEY_LAUNCH_PREFERENCE); 163 164 final AccessibilityShortcutInfo info = getAccessibilityShortcutInfo(); 165 final String switchBarText = (info == null) ? EMPTY_STRING : getString( 166 R.string.accessibility_service_primary_open_title, 167 info.getActivityInfo().loadLabel(getPackageManager())); 168 launchPreference.setTitle(switchBarText); 169 170 launchPreference.setOnPreferenceClickListener(preference -> { 171 logAccessibilityServiceEnabled(mComponentName, /* enabled= */ true); 172 launchShortcutTargetActivity(getPrefContext().getDisplayId(), mComponentName); 173 return true; 174 }); 175 getPreferenceScreen().addPreference(launchPreference); 176 } 177 launchShortcutTargetActivity(int displayId, ComponentName name)178 private void launchShortcutTargetActivity(int displayId, ComponentName name) { 179 final Intent intent = new Intent(); 180 final Bundle bundle = ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle(); 181 182 intent.setComponent(name); 183 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 184 try { 185 final int userId = UserHandle.myUserId(); 186 getPrefContext().startActivityAsUser(intent, bundle, UserHandle.of(userId)); 187 } catch (ActivityNotFoundException ignore) { 188 // ignore the exception 189 Log.w(TAG, "Target activity not found."); 190 } 191 } 192 193 @Nullable getSettingsIntent(Bundle arguments)194 private Intent getSettingsIntent(Bundle arguments) { 195 final String settingsComponentName = arguments.getString( 196 AccessibilitySettings.EXTRA_SETTINGS_COMPONENT_NAME); 197 if (TextUtils.isEmpty(settingsComponentName)) { 198 return null; 199 } 200 201 final Intent settingsIntent = new Intent(Intent.ACTION_MAIN).setComponent( 202 ComponentName.unflattenFromString(settingsComponentName)); 203 if (getPackageManager().queryIntentActivities(settingsIntent, /* flags= */ 0).isEmpty()) { 204 return null; 205 } 206 207 return settingsIntent; 208 } 209 210 @Override getPreferenceScreenResId()211 protected int getPreferenceScreenResId() { 212 // TODO(b/171272809): Add back when controllers move to static type 213 return 0; 214 } 215 216 @Override getLogTag()217 protected String getLogTag() { 218 return TAG; 219 } 220 }