Root cause: When Accessibility settings parse the application which is from google play store, the settings have no check if the resource is valid before delivery the parameter into the corresponding fragment. Solution: Check if the resource is valid before creating the image uri. Bug: 190716289 Test: manual test Change-Id: I56eba2232ddf6ed5b2e526d4698479465a012e52
188 lines
7.4 KiB
Java
188 lines
7.4 KiB
Java
/*
|
|
* Copyright (C) 2020 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.android.settings.accessibility;
|
|
|
|
import static com.android.settings.accessibility.AccessibilityStatsLogUtils.logAccessibilityServiceEnabled;
|
|
|
|
import android.accessibilityservice.AccessibilityShortcutInfo;
|
|
import android.app.ActivityOptions;
|
|
import android.content.ActivityNotFoundException;
|
|
import android.content.ComponentName;
|
|
import android.content.ContentResolver;
|
|
import android.content.Intent;
|
|
import android.content.pm.ActivityInfo;
|
|
import android.net.Uri;
|
|
import android.os.Bundle;
|
|
import android.os.UserHandle;
|
|
import android.text.TextUtils;
|
|
import android.util.Log;
|
|
import android.view.LayoutInflater;
|
|
import android.view.Menu;
|
|
import android.view.MenuInflater;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
import android.view.accessibility.AccessibilityManager;
|
|
|
|
import androidx.annotation.Nullable;
|
|
import androidx.preference.Preference;
|
|
|
|
import com.android.settings.R;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
/** Fragment for providing open activity button. */
|
|
public class LaunchAccessibilityActivityPreferenceFragment extends ToggleFeaturePreferenceFragment {
|
|
private static final String TAG = "LaunchA11yActivity";
|
|
private static final String EMPTY_STRING = "";
|
|
protected static final String KEY_LAUNCH_PREFERENCE = "launch_preference";
|
|
|
|
@Override
|
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
|
Bundle savedInstanceState) {
|
|
final View view = super.onCreateView(inflater, container, savedInstanceState);
|
|
|
|
// Init new preference to replace the switch preference instead.
|
|
initLaunchPreference();
|
|
removePreference(KEY_USE_SERVICE_PREFERENCE);
|
|
return view;
|
|
};
|
|
|
|
@Override
|
|
protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
|
|
// Do nothing.
|
|
}
|
|
|
|
@Override
|
|
protected void onProcessArguments(Bundle arguments) {
|
|
super.onProcessArguments(arguments);
|
|
|
|
mComponentName = arguments.getParcelable(AccessibilitySettings.EXTRA_COMPONENT_NAME);
|
|
final ActivityInfo info = getAccessibilityShortcutInfo().getActivityInfo();
|
|
mPackageName = info.loadLabel(getPackageManager()).toString();
|
|
|
|
// Settings animated image.
|
|
final int animatedImageRes = arguments.getInt(
|
|
AccessibilitySettings.EXTRA_ANIMATED_IMAGE_RES);
|
|
if (animatedImageRes > 0) {
|
|
mImageUri = new Uri.Builder().scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
|
|
.authority(mComponentName.getPackageName())
|
|
.appendPath(String.valueOf(animatedImageRes))
|
|
.build();
|
|
}
|
|
|
|
// Settings html description.
|
|
mHtmlDescription = arguments.getCharSequence(AccessibilitySettings.EXTRA_HTML_DESCRIPTION);
|
|
|
|
// Settings title and intent.
|
|
final String settingsTitle = arguments.getString(
|
|
AccessibilitySettings.EXTRA_SETTINGS_TITLE);
|
|
mSettingsIntent = TextUtils.isEmpty(settingsTitle) ? null : getSettingsIntent(arguments);
|
|
mSettingsTitle = (mSettingsIntent == null) ? null : settingsTitle;
|
|
}
|
|
|
|
@Override
|
|
int getUserShortcutTypes() {
|
|
return AccessibilityUtil.getUserShortcutTypesFromSettings(getPrefContext(),
|
|
mComponentName);
|
|
}
|
|
|
|
@Override
|
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
|
// Do not call super. We don't want to see the "Help & feedback" option on this page so as
|
|
// not to confuse users who think they might be able to send feedback about a specific
|
|
// accessibility service from this page.
|
|
}
|
|
|
|
// IMPORTANT: Refresh the info since there are dynamically changing capabilities.
|
|
private AccessibilityShortcutInfo getAccessibilityShortcutInfo() {
|
|
final List<AccessibilityShortcutInfo> infos = AccessibilityManager.getInstance(
|
|
getPrefContext()).getInstalledAccessibilityShortcutListAsUser(getPrefContext(),
|
|
UserHandle.myUserId());
|
|
|
|
for (int i = 0, count = infos.size(); i < count; i++) {
|
|
AccessibilityShortcutInfo shortcutInfo = infos.get(i);
|
|
ActivityInfo activityInfo = shortcutInfo.getActivityInfo();
|
|
if (mComponentName.getPackageName().equals(activityInfo.packageName)
|
|
&& mComponentName.getClassName().equals(activityInfo.name)) {
|
|
return shortcutInfo;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/** Customizes the order by preference key. */
|
|
protected List<String> getPreferenceOrderList() {
|
|
final List<String> lists = new ArrayList<>();
|
|
lists.add(KEY_ANIMATED_IMAGE);
|
|
lists.add(KEY_LAUNCH_PREFERENCE);
|
|
lists.add(KEY_GENERAL_CATEGORY);
|
|
lists.add(KEY_HTML_DESCRIPTION_PREFERENCE);
|
|
return lists;
|
|
}
|
|
|
|
private void initLaunchPreference() {
|
|
final Preference launchPreference = new Preference(getPrefContext());
|
|
launchPreference.setKey(KEY_LAUNCH_PREFERENCE);
|
|
|
|
final AccessibilityShortcutInfo info = getAccessibilityShortcutInfo();
|
|
final String switchBarText = (info == null) ? EMPTY_STRING : getString(
|
|
R.string.accessibility_service_primary_open_title,
|
|
info.getActivityInfo().loadLabel(getPackageManager()));
|
|
launchPreference.setTitle(switchBarText);
|
|
|
|
launchPreference.setOnPreferenceClickListener(preference -> {
|
|
logAccessibilityServiceEnabled(mComponentName, /* enabled= */ true);
|
|
launchShortcutTargetActivity(getPrefContext().getDisplayId(), mComponentName);
|
|
return true;
|
|
});
|
|
getPreferenceScreen().addPreference(launchPreference);
|
|
}
|
|
|
|
private void launchShortcutTargetActivity(int displayId, ComponentName name) {
|
|
final Intent intent = new Intent();
|
|
final Bundle bundle = ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle();
|
|
|
|
intent.setComponent(name);
|
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
try {
|
|
final int userId = UserHandle.myUserId();
|
|
getPrefContext().startActivityAsUser(intent, bundle, UserHandle.of(userId));
|
|
} catch (ActivityNotFoundException ignore) {
|
|
// ignore the exception
|
|
Log.w(TAG, "Target activity not found.");
|
|
}
|
|
}
|
|
|
|
@Nullable
|
|
private Intent getSettingsIntent(Bundle arguments) {
|
|
final String settingsComponentName = arguments.getString(
|
|
AccessibilitySettings.EXTRA_SETTINGS_COMPONENT_NAME);
|
|
if (TextUtils.isEmpty(settingsComponentName)) {
|
|
return null;
|
|
}
|
|
|
|
final Intent settingsIntent = new Intent(Intent.ACTION_MAIN).setComponent(
|
|
ComponentName.unflattenFromString(settingsComponentName));
|
|
if (getPackageManager().queryIntentActivities(settingsIntent, /* flags= */ 0).isEmpty()) {
|
|
return null;
|
|
}
|
|
|
|
return settingsIntent;
|
|
}
|
|
}
|