Files
app_Settings/src/com/android/settings/accessibility/LaunchAccessibilityActivityPreferenceFragment.java
Peter_Liang 652c425acb Fixing the crash when tapping the "Downloaded apps" in Accessibility page.
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
2021-06-11 03:24:06 +00:00

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;
}
}