Fix clickjacking again for accessibility services
Turns out that the flag for the window being obscured does not imply that it is also partially obscured. Also blocking system alerts and toast windows over the accessibility service preference screen (and its associated warning dialog) as well as the warning dialog shown when a service is made available with the accessibiity shortcut. Bug: 62104030 Test: Manually verified that I can't enable Select to Speak when switch access is highlighting the button. I am able to do that without this fix. Also started a service that displayed a system overlay and confirmed that the overlay disappears on a11y service preference screens and when a new service is configured for the a11y shortcut. Merged-In: Ie00bafa736c837881a258c9de10891b27c5baefd Change-Id: Iabbded1a12dbc33d76e51c0bac710280a88080f3
This commit is contained in:
@@ -81,6 +81,7 @@
|
|||||||
<uses-permission android:name="android.permission.PEERS_MAC_ADDRESS"/>
|
<uses-permission android:name="android.permission.PEERS_MAC_ADDRESS"/>
|
||||||
<uses-permission android:name="android.permission.MANAGE_NOTIFICATIONS"/>
|
<uses-permission android:name="android.permission.MANAGE_NOTIFICATIONS"/>
|
||||||
<uses-permission android:name="android.permission.DELETE_PACKAGES"/>
|
<uses-permission android:name="android.permission.DELETE_PACKAGES"/>
|
||||||
|
<uses-permission android:name="android.permission.MANAGE_APP_OPS_RESTRICTIONS"/>
|
||||||
|
|
||||||
<application android:label="@string/settings_label"
|
<application android:label="@string/settings_label"
|
||||||
android:icon="@drawable/ic_launcher_settings"
|
android:icon="@drawable/ic_launcher_settings"
|
||||||
|
@@ -25,6 +25,7 @@ import android.annotation.Nullable;
|
|||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.AppGlobals;
|
import android.app.AppGlobals;
|
||||||
|
import android.app.AppOpsManager;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
import android.app.IActivityManager;
|
import android.app.IActivityManager;
|
||||||
@@ -1272,6 +1273,22 @@ public final class Utils extends com.android.settingslib.Utils {
|
|||||||
return info.enabled ? R.string.installed : R.string.disabled;
|
return info.enabled ? R.string.installed : R.string.disabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control if other apps can display overlays. By default this is allowed. Be sure to
|
||||||
|
* re-enable overlays, as the effect is system-wide.
|
||||||
|
*/
|
||||||
|
public static void setOverlayAllowed(Context context, IBinder token, boolean allowed) {
|
||||||
|
AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
|
||||||
|
if (appOpsManager != null) {
|
||||||
|
appOpsManager.setUserRestriction(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
|
||||||
|
!allowed, token);
|
||||||
|
appOpsManager.setUserRestriction(AppOpsManager.OP_TOAST_WINDOW,
|
||||||
|
!allowed, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static boolean isVolumeValid(VolumeInfo volume) {
|
private static boolean isVolumeValid(VolumeInfo volume) {
|
||||||
return (volume != null) && (volume.getType() == VolumeInfo.TYPE_PRIVATE)
|
return (volume != null) && (volume.getType() == VolumeInfo.TYPE_PRIVATE)
|
||||||
&& volume.isMountedReadable();
|
&& volume.isMountedReadable();
|
||||||
|
@@ -48,14 +48,14 @@ public class AccessibilityServiceWarning {
|
|||||||
.setTitle(parentActivity.getString(R.string.enable_service_title,
|
.setTitle(parentActivity.getString(R.string.enable_service_title,
|
||||||
getServiceName(parentActivity, info)))
|
getServiceName(parentActivity, info)))
|
||||||
.setView(createEnableDialogContentView(parentActivity, info))
|
.setView(createEnableDialogContentView(parentActivity, info))
|
||||||
.setCancelable(true)
|
|
||||||
.setPositiveButton(android.R.string.ok, listener)
|
.setPositiveButton(android.R.string.ok, listener)
|
||||||
.setNegativeButton(android.R.string.cancel, listener)
|
.setNegativeButton(android.R.string.cancel, listener)
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
final View.OnTouchListener filterTouchListener = (View v, MotionEvent event) -> {
|
final View.OnTouchListener filterTouchListener = (View v, MotionEvent event) -> {
|
||||||
// Filter obscured touches by consuming them.
|
// Filter obscured touches by consuming them.
|
||||||
if ((event.getFlags() & MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED) != 0) {
|
if (((event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0)
|
||||||
|
|| ((event.getFlags() & MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED) != 0)) {
|
||||||
if (event.getAction() == MotionEvent.ACTION_UP) {
|
if (event.getAction() == MotionEvent.ACTION_UP) {
|
||||||
Toast.makeText(v.getContext(), R.string.touch_filtered_warning,
|
Toast.makeText(v.getContext(), R.string.touch_filtered_warning,
|
||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
@@ -67,6 +67,8 @@ public class AccessibilityServiceWarning {
|
|||||||
|
|
||||||
ad.create();
|
ad.create();
|
||||||
ad.getButton(AlertDialog.BUTTON_POSITIVE).setOnTouchListener(filterTouchListener);
|
ad.getButton(AlertDialog.BUTTON_POSITIVE).setOnTouchListener(filterTouchListener);
|
||||||
|
ad.setCanceledOnTouchOutside(true);
|
||||||
|
|
||||||
return ad;
|
return ad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -17,25 +17,24 @@ package com.android.settings.accessibility;
|
|||||||
|
|
||||||
import static android.content.DialogInterface.BUTTON_POSITIVE;
|
import static android.content.DialogInterface.BUTTON_POSITIVE;
|
||||||
|
|
||||||
|
import static com.android.settings.Utils.setOverlayAllowed;
|
||||||
|
|
||||||
import android.accessibilityservice.AccessibilityServiceInfo;
|
import android.accessibilityservice.AccessibilityServiceInfo;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.DialogFragment;
|
import android.app.DialogFragment;
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.pm.PackageManager;
|
import android.os.Binder;
|
||||||
import android.content.pm.PackageParser;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.IBinder;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.support.v7.preference.Preference;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.accessibility.AccessibilityManager;
|
import android.view.accessibility.AccessibilityManager;
|
||||||
|
|
||||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||||
import com.android.settings.DialogCreatable;
|
|
||||||
import com.android.settings.applications.defaultapps.DefaultAppInfo;
|
import com.android.settings.applications.defaultapps.DefaultAppInfo;
|
||||||
import com.android.settings.applications.defaultapps.DefaultAppPickerFragment;
|
import com.android.settings.applications.defaultapps.DefaultAppPickerFragment;
|
||||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||||
@@ -118,6 +117,7 @@ public class ShortcutServicePickerFragment extends DefaultAppPickerFragment {
|
|||||||
implements DialogInterface.OnClickListener {
|
implements DialogInterface.OnClickListener {
|
||||||
private static final String EXTRA_KEY = "extra_key";
|
private static final String EXTRA_KEY = "extra_key";
|
||||||
private static final String TAG = "ConfirmationDialogFragment";
|
private static final String TAG = "ConfirmationDialogFragment";
|
||||||
|
private IBinder mToken;
|
||||||
|
|
||||||
public static ConfirmationDialogFragment newInstance(ShortcutServicePickerFragment parent,
|
public static ConfirmationDialogFragment newInstance(ShortcutServicePickerFragment parent,
|
||||||
String key) {
|
String key) {
|
||||||
@@ -126,6 +126,7 @@ public class ShortcutServicePickerFragment extends DefaultAppPickerFragment {
|
|||||||
argument.putString(EXTRA_KEY, key);
|
argument.putString(EXTRA_KEY, key);
|
||||||
fragment.setArguments(argument);
|
fragment.setArguments(argument);
|
||||||
fragment.setTargetFragment(parent, 0);
|
fragment.setTargetFragment(parent, 0);
|
||||||
|
fragment.mToken = new Binder();
|
||||||
return fragment;
|
return fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,6 +147,22 @@ public class ShortcutServicePickerFragment extends DefaultAppPickerFragment {
|
|||||||
return AccessibilityServiceWarning.createCapabilitiesDialog(getActivity(), info, this);
|
return AccessibilityServiceWarning.createCapabilitiesDialog(getActivity(), info, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
if (mToken != null) {
|
||||||
|
setOverlayAllowed(getActivity(), mToken, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
if (mToken != null) {
|
||||||
|
setOverlayAllowed(getActivity(), mToken, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
final Fragment fragment = getTargetFragment();
|
final Fragment fragment = getTargetFragment();
|
||||||
|
@@ -16,34 +16,30 @@
|
|||||||
|
|
||||||
package com.android.settings.accessibility;
|
package com.android.settings.accessibility;
|
||||||
|
|
||||||
|
import static com.android.settings.Utils.setOverlayAllowed;
|
||||||
|
|
||||||
import android.accessibilityservice.AccessibilityServiceInfo;
|
import android.accessibilityservice.AccessibilityServiceInfo;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.admin.DevicePolicyManager;
|
import android.app.admin.DevicePolicyManager;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.ResolveInfo;
|
import android.content.pm.ResolveInfo;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Binder;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.os.IBinder;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.storage.StorageManager;
|
import android.os.storage.StorageManager;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.accessibility.AccessibilityManager;
|
import android.view.accessibility.AccessibilityManager;
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||||
import com.android.internal.widget.LockPatternUtils;
|
import com.android.internal.widget.LockPatternUtils;
|
||||||
@@ -77,6 +73,8 @@ public class ToggleAccessibilityServicePreferenceFragment
|
|||||||
|
|
||||||
private int mShownDialogId;
|
private int mShownDialogId;
|
||||||
|
|
||||||
|
private final IBinder mToken = new Binder();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMetricsCategory() {
|
public int getMetricsCategory() {
|
||||||
return MetricsEvent.ACCESSIBILITY_SERVICE;
|
return MetricsEvent.ACCESSIBILITY_SERVICE;
|
||||||
@@ -107,12 +105,18 @@ public class ToggleAccessibilityServicePreferenceFragment
|
|||||||
public void onResume() {
|
public void onResume() {
|
||||||
mSettingsContentObserver.register(getContentResolver());
|
mSettingsContentObserver.register(getContentResolver());
|
||||||
updateSwitchBarToggleSwitch();
|
updateSwitchBarToggleSwitch();
|
||||||
|
if (mToken != null) {
|
||||||
|
setOverlayAllowed(getActivity(), mToken, false);
|
||||||
|
}
|
||||||
super.onResume();
|
super.onResume();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
mSettingsContentObserver.unregister(getContentResolver());
|
mSettingsContentObserver.unregister(getContentResolver());
|
||||||
|
if (mToken != null) {
|
||||||
|
setOverlayAllowed(getActivity(), mToken, true);
|
||||||
|
}
|
||||||
super.onPause();
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user