Loading res/layout/enable_accessibility_service_dialog_content.xml +5 −0 Original line number Diff line number Diff line Loading @@ -134,6 +134,11 @@ android:text="@string/accessibility_dialog_button_deny" style="@style/AccessibilityDialogButton" /> <Button android:id="@+id/permission_enable_uninstall_button" android:text="@string/uninstall_text" android:visibility="gone" style="@style/AccessibilityDialogButton" /> </LinearLayout> </LinearLayout> Loading src/com/android/settings/accessibility/AccessibilityServiceWarning.java +22 −4 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.core.content.ContextCompat; Loading @@ -60,11 +61,19 @@ public class AccessibilityServiceWarning { return false; }; /** * The interface to execute the uninstallation action. */ interface UninstallActionPerformer { void uninstallPackage(); } /** Returns a {@link Dialog} to be shown to confirm that they want to enable a service. */ public static Dialog createCapabilitiesDialog(Context context, AccessibilityServiceInfo info, View.OnClickListener listener) { public static Dialog createCapabilitiesDialog(@NonNull Context context, @NonNull AccessibilityServiceInfo info, @NonNull View.OnClickListener listener, @NonNull UninstallActionPerformer performer) { final AlertDialog ad = new AlertDialog.Builder(context) .setView(createEnableDialogContentView(context, info, listener)) .setView(createEnableDialogContentView(context, info, listener, performer)) .create(); Window window = ad.getWindow(); Loading @@ -88,7 +97,8 @@ public class AccessibilityServiceWarning { } private static View createEnableDialogContentView(Context context, AccessibilityServiceInfo info, View.OnClickListener listener) { @NonNull AccessibilityServiceInfo info, View.OnClickListener listener, UninstallActionPerformer performer) { LayoutInflater inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE); Loading Loading @@ -129,6 +139,14 @@ public class AccessibilityServiceWarning { permissionAllowButton.setOnTouchListener(filterTouchListener); permissionDenyButton.setOnClickListener(listener); final Button uninstallButton = content.findViewById( R.id.permission_enable_uninstall_button); // Shows an uninstall button to help users quickly remove the non-system App due to the // required permissions. if (!AccessibilityUtil.isSystemApp(info)) { uninstallButton.setVisibility(View.VISIBLE); uninstallButton.setOnClickListener(v -> performer.uninstallPackage()); } return content; } Loading src/com/android/settings/accessibility/AccessibilityUtil.java +9 −0 Original line number Diff line number Diff line Loading @@ -381,4 +381,13 @@ final class AccessibilityUtil { return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, screenHeightDp, resources.getDisplayMetrics())); } /** * Indicates if the accessibility service belongs to a system App. * @param info AccessibilityServiceInfo * @return {@code true} if the App is a system App. */ public static boolean isSystemApp(@NonNull AccessibilityServiceInfo info) { return info.getResolveInfo().serviceInfo.applicationInfo.isSystemApp(); } } src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java +82 −4 Original line number Diff line number Diff line Loading @@ -24,10 +24,14 @@ import android.app.Activity; import android.app.Dialog; import android.app.admin.DevicePolicyManager; import android.app.settings.SettingsEnums; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.net.Uri; Loading @@ -37,12 +41,14 @@ import android.os.UserHandle; import android.os.storage.StorageManager; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.View; import android.view.accessibility.AccessibilityManager; import android.widget.Switch; import androidx.annotation.Nullable; import androidx.preference.Preference; import com.android.internal.widget.LockPatternUtils; Loading @@ -59,7 +65,8 @@ import java.util.concurrent.atomic.AtomicBoolean; public class ToggleAccessibilityServicePreferenceFragment extends ToggleFeaturePreferenceFragment { public static final int ACTIVITY_REQUEST_CONFIRM_CREDENTIAL_FOR_WEAKER_ENCRYPTION = 1; private static final String TAG = "ToggleAccessibilityServicePreferenceFragment"; private static final int ACTIVITY_REQUEST_CONFIRM_CREDENTIAL_FOR_WEAKER_ENCRYPTION = 1; private LockPatternUtils mLockPatternUtils; private AtomicBoolean mIsDialogShown = new AtomicBoolean(/* initialValue= */ false); Loading @@ -74,6 +81,7 @@ public class ToggleAccessibilityServicePreferenceFragment extends }; private Dialog mDialog; private BroadcastReceiver mPackageRemovedReceiver; @Override public int getMetricsCategory() { Loading @@ -93,6 +101,17 @@ public class ToggleAccessibilityServicePreferenceFragment extends mLockPatternUtils = new LockPatternUtils(getPrefContext()); } @Override public void onStart() { super.onStart(); final AccessibilityServiceInfo serviceInfo = getAccessibilityServiceInfo(); if (serviceInfo == null) { getActivity().finishAndRemoveTask(); } else if (!AccessibilityUtil.isSystemApp(serviceInfo)) { registerPackageRemoveReceiver(); } } @Override public void onResume() { super.onResume(); Loading @@ -111,6 +130,7 @@ public class ToggleAccessibilityServicePreferenceFragment extends // capabilities. For // example, before JellyBean MR2 the user was granting the explore by touch // one. @Nullable AccessibilityServiceInfo getAccessibilityServiceInfo() { final List<AccessibilityServiceInfo> infos = AccessibilityManager.getInstance( getPrefContext()).getInstalledAccessibilityServiceList(); Loading @@ -136,7 +156,8 @@ public class ToggleAccessibilityServicePreferenceFragment extends } mDialog = AccessibilityServiceWarning .createCapabilitiesDialog(getPrefContext(), info, this::onDialogButtonFromEnableToggleClicked); this::onDialogButtonFromEnableToggleClicked, this::onDialogButtonFromUninstallClicked); break; } case DialogEnums.ENABLE_WARNING_FROM_SHORTCUT_TOGGLE: { Loading @@ -146,7 +167,8 @@ public class ToggleAccessibilityServicePreferenceFragment extends } mDialog = AccessibilityServiceWarning .createCapabilitiesDialog(getPrefContext(), info, this::onDialogButtonFromShortcutToggleClicked); this::onDialogButtonFromShortcutToggleClicked, this::onDialogButtonFromUninstallClicked); break; } case DialogEnums.ENABLE_WARNING_FROM_SHORTCUT: { Loading @@ -156,7 +178,8 @@ public class ToggleAccessibilityServicePreferenceFragment extends } mDialog = AccessibilityServiceWarning .createCapabilitiesDialog(getPrefContext(), info, this::onDialogButtonFromShortcutClicked); this::onDialogButtonFromShortcutClicked, this::onDialogButtonFromUninstallClicked); break; } case DialogEnums.DISABLE_WARNING_FROM_TOGGLE: { Loading Loading @@ -246,6 +269,32 @@ public class ToggleAccessibilityServicePreferenceFragment extends } } private void registerPackageRemoveReceiver() { if (mPackageRemovedReceiver != null || getContext() == null) { return; } mPackageRemovedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final String packageName = intent.getData().getSchemeSpecificPart(); if (TextUtils.equals(mComponentName.getPackageName(), packageName)) { getActivity().finishAndRemoveTask(); } } }; final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED); filter.addDataScheme("package"); getContext().registerReceiver(mPackageRemovedReceiver, filter); } private void unregisterPackageRemoveReceiver() { if (mPackageRemovedReceiver == null || getContext() == null) { return; } getContext().unregisterReceiver(mPackageRemovedReceiver); mPackageRemovedReceiver = null; } private boolean isServiceSupportAccessibilityButton() { final AccessibilityManager ams = getPrefContext().getSystemService( AccessibilityManager.class); Loading Loading @@ -378,6 +427,35 @@ public class ToggleAccessibilityServicePreferenceFragment extends } } private void onDialogButtonFromUninstallClicked() { mDialog.dismiss(); final Intent uninstallIntent = createUninstallPackageActivityIntent(); if (uninstallIntent == null) { return; } startActivity(uninstallIntent); } @Nullable private Intent createUninstallPackageActivityIntent() { final AccessibilityServiceInfo a11yServiceInfo = getAccessibilityServiceInfo(); if (a11yServiceInfo == null) { Log.w(TAG, "createUnInstallIntent -- invalid a11yServiceInfo"); return null; } final ApplicationInfo appInfo = a11yServiceInfo.getResolveInfo().serviceInfo.applicationInfo; final Uri packageUri = Uri.parse("package:" + appInfo.packageName); final Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri); return uninstallIntent; } @Override public void onStop() { super.onStop(); unregisterPackageRemoveReceiver(); } private void onAllowButtonFromEnableToggleClicked() { if (isFullDiskEncrypted()) { final String title = createConfirmCredentialReasonMessage(); Loading Loading
res/layout/enable_accessibility_service_dialog_content.xml +5 −0 Original line number Diff line number Diff line Loading @@ -134,6 +134,11 @@ android:text="@string/accessibility_dialog_button_deny" style="@style/AccessibilityDialogButton" /> <Button android:id="@+id/permission_enable_uninstall_button" android:text="@string/uninstall_text" android:visibility="gone" style="@style/AccessibilityDialogButton" /> </LinearLayout> </LinearLayout> Loading
src/com/android/settings/accessibility/AccessibilityServiceWarning.java +22 −4 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.core.content.ContextCompat; Loading @@ -60,11 +61,19 @@ public class AccessibilityServiceWarning { return false; }; /** * The interface to execute the uninstallation action. */ interface UninstallActionPerformer { void uninstallPackage(); } /** Returns a {@link Dialog} to be shown to confirm that they want to enable a service. */ public static Dialog createCapabilitiesDialog(Context context, AccessibilityServiceInfo info, View.OnClickListener listener) { public static Dialog createCapabilitiesDialog(@NonNull Context context, @NonNull AccessibilityServiceInfo info, @NonNull View.OnClickListener listener, @NonNull UninstallActionPerformer performer) { final AlertDialog ad = new AlertDialog.Builder(context) .setView(createEnableDialogContentView(context, info, listener)) .setView(createEnableDialogContentView(context, info, listener, performer)) .create(); Window window = ad.getWindow(); Loading @@ -88,7 +97,8 @@ public class AccessibilityServiceWarning { } private static View createEnableDialogContentView(Context context, AccessibilityServiceInfo info, View.OnClickListener listener) { @NonNull AccessibilityServiceInfo info, View.OnClickListener listener, UninstallActionPerformer performer) { LayoutInflater inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE); Loading Loading @@ -129,6 +139,14 @@ public class AccessibilityServiceWarning { permissionAllowButton.setOnTouchListener(filterTouchListener); permissionDenyButton.setOnClickListener(listener); final Button uninstallButton = content.findViewById( R.id.permission_enable_uninstall_button); // Shows an uninstall button to help users quickly remove the non-system App due to the // required permissions. if (!AccessibilityUtil.isSystemApp(info)) { uninstallButton.setVisibility(View.VISIBLE); uninstallButton.setOnClickListener(v -> performer.uninstallPackage()); } return content; } Loading
src/com/android/settings/accessibility/AccessibilityUtil.java +9 −0 Original line number Diff line number Diff line Loading @@ -381,4 +381,13 @@ final class AccessibilityUtil { return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, screenHeightDp, resources.getDisplayMetrics())); } /** * Indicates if the accessibility service belongs to a system App. * @param info AccessibilityServiceInfo * @return {@code true} if the App is a system App. */ public static boolean isSystemApp(@NonNull AccessibilityServiceInfo info) { return info.getResolveInfo().serviceInfo.applicationInfo.isSystemApp(); } }
src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java +82 −4 Original line number Diff line number Diff line Loading @@ -24,10 +24,14 @@ import android.app.Activity; import android.app.Dialog; import android.app.admin.DevicePolicyManager; import android.app.settings.SettingsEnums; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.net.Uri; Loading @@ -37,12 +41,14 @@ import android.os.UserHandle; import android.os.storage.StorageManager; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.View; import android.view.accessibility.AccessibilityManager; import android.widget.Switch; import androidx.annotation.Nullable; import androidx.preference.Preference; import com.android.internal.widget.LockPatternUtils; Loading @@ -59,7 +65,8 @@ import java.util.concurrent.atomic.AtomicBoolean; public class ToggleAccessibilityServicePreferenceFragment extends ToggleFeaturePreferenceFragment { public static final int ACTIVITY_REQUEST_CONFIRM_CREDENTIAL_FOR_WEAKER_ENCRYPTION = 1; private static final String TAG = "ToggleAccessibilityServicePreferenceFragment"; private static final int ACTIVITY_REQUEST_CONFIRM_CREDENTIAL_FOR_WEAKER_ENCRYPTION = 1; private LockPatternUtils mLockPatternUtils; private AtomicBoolean mIsDialogShown = new AtomicBoolean(/* initialValue= */ false); Loading @@ -74,6 +81,7 @@ public class ToggleAccessibilityServicePreferenceFragment extends }; private Dialog mDialog; private BroadcastReceiver mPackageRemovedReceiver; @Override public int getMetricsCategory() { Loading @@ -93,6 +101,17 @@ public class ToggleAccessibilityServicePreferenceFragment extends mLockPatternUtils = new LockPatternUtils(getPrefContext()); } @Override public void onStart() { super.onStart(); final AccessibilityServiceInfo serviceInfo = getAccessibilityServiceInfo(); if (serviceInfo == null) { getActivity().finishAndRemoveTask(); } else if (!AccessibilityUtil.isSystemApp(serviceInfo)) { registerPackageRemoveReceiver(); } } @Override public void onResume() { super.onResume(); Loading @@ -111,6 +130,7 @@ public class ToggleAccessibilityServicePreferenceFragment extends // capabilities. For // example, before JellyBean MR2 the user was granting the explore by touch // one. @Nullable AccessibilityServiceInfo getAccessibilityServiceInfo() { final List<AccessibilityServiceInfo> infos = AccessibilityManager.getInstance( getPrefContext()).getInstalledAccessibilityServiceList(); Loading @@ -136,7 +156,8 @@ public class ToggleAccessibilityServicePreferenceFragment extends } mDialog = AccessibilityServiceWarning .createCapabilitiesDialog(getPrefContext(), info, this::onDialogButtonFromEnableToggleClicked); this::onDialogButtonFromEnableToggleClicked, this::onDialogButtonFromUninstallClicked); break; } case DialogEnums.ENABLE_WARNING_FROM_SHORTCUT_TOGGLE: { Loading @@ -146,7 +167,8 @@ public class ToggleAccessibilityServicePreferenceFragment extends } mDialog = AccessibilityServiceWarning .createCapabilitiesDialog(getPrefContext(), info, this::onDialogButtonFromShortcutToggleClicked); this::onDialogButtonFromShortcutToggleClicked, this::onDialogButtonFromUninstallClicked); break; } case DialogEnums.ENABLE_WARNING_FROM_SHORTCUT: { Loading @@ -156,7 +178,8 @@ public class ToggleAccessibilityServicePreferenceFragment extends } mDialog = AccessibilityServiceWarning .createCapabilitiesDialog(getPrefContext(), info, this::onDialogButtonFromShortcutClicked); this::onDialogButtonFromShortcutClicked, this::onDialogButtonFromUninstallClicked); break; } case DialogEnums.DISABLE_WARNING_FROM_TOGGLE: { Loading Loading @@ -246,6 +269,32 @@ public class ToggleAccessibilityServicePreferenceFragment extends } } private void registerPackageRemoveReceiver() { if (mPackageRemovedReceiver != null || getContext() == null) { return; } mPackageRemovedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final String packageName = intent.getData().getSchemeSpecificPart(); if (TextUtils.equals(mComponentName.getPackageName(), packageName)) { getActivity().finishAndRemoveTask(); } } }; final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED); filter.addDataScheme("package"); getContext().registerReceiver(mPackageRemovedReceiver, filter); } private void unregisterPackageRemoveReceiver() { if (mPackageRemovedReceiver == null || getContext() == null) { return; } getContext().unregisterReceiver(mPackageRemovedReceiver); mPackageRemovedReceiver = null; } private boolean isServiceSupportAccessibilityButton() { final AccessibilityManager ams = getPrefContext().getSystemService( AccessibilityManager.class); Loading Loading @@ -378,6 +427,35 @@ public class ToggleAccessibilityServicePreferenceFragment extends } } private void onDialogButtonFromUninstallClicked() { mDialog.dismiss(); final Intent uninstallIntent = createUninstallPackageActivityIntent(); if (uninstallIntent == null) { return; } startActivity(uninstallIntent); } @Nullable private Intent createUninstallPackageActivityIntent() { final AccessibilityServiceInfo a11yServiceInfo = getAccessibilityServiceInfo(); if (a11yServiceInfo == null) { Log.w(TAG, "createUnInstallIntent -- invalid a11yServiceInfo"); return null; } final ApplicationInfo appInfo = a11yServiceInfo.getResolveInfo().serviceInfo.applicationInfo; final Uri packageUri = Uri.parse("package:" + appInfo.packageName); final Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri); return uninstallIntent; } @Override public void onStop() { super.onStop(); unregisterPackageRemoveReceiver(); } private void onAllowButtonFromEnableToggleClicked() { if (isFullDiskEncrypted()) { final String title = createConfirmCredentialReasonMessage(); Loading