Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1542b344 authored by menghanli's avatar menghanli
Browse files

Fix A11y features blocked by IT admin can be bypassed using a11y shortcuts

Root cause: Setting preference uses RestrictedPreferenceHelper to block the non-approved service by RestrictedLockInternal.checkIfRestrictionEnforced. The volume keys shortcut editor mode does not apply the way in AccessibilityShortcutChooserActivity.
Solution: Add RestrictedLockUtils.checkIfRestrictionEnforced into AccessibilityTarget to disable the non-approved service. Show IT admin dialog to align the setting preference experience.

Bug: 254223085
Test: atest AccessibilityShortcutChooserActivityTest
Change-Id: I2c1a8379a230ab6b21e72ba8751e880fb6654650
parent 5987bdf4
Loading
Loading
Loading
Loading
+52 −0
Original line number Diff line number Diff line
@@ -2210,6 +2210,58 @@ public final class AccessibilityManager {
        }
    }

    /**
     * Determines if the accessibility target is allowed.
     *
     * @param packageName The name of the application attempting to perform the operation.
     * @param uid The user id of the application attempting to perform the operation.
     * @param userId The id of the user for whom to perform the operation.
     * @return {@code true} the accessibility target is allowed.
     * @hide
     */
    public boolean isAccessibilityTargetAllowed(String packageName, int uid, int userId) {
        final IAccessibilityManager service;
        synchronized (mLock) {
            service = getServiceLocked();
            if (service == null) {
                return false;
            }
        }

        try {
            return service.isAccessibilityTargetAllowed(packageName, uid, userId);
        } catch (RemoteException re) {
            Log.e(LOG_TAG, "Error while check accessibility target status", re);
            return false;
        }
    }

    /**
     * Sends restricted dialog intent if the accessibility target is disallowed.
     *
     * @param packageName The name of the application attempting to perform the operation.
     * @param uid The user id of the application attempting to perform the operation.
     * @param userId The id of the user for whom to perform the operation.
     * @return {@code true} if the restricted dialog is shown.
     * @hide
     */
    public boolean sendRestrictedDialogIntent(String packageName, int uid, int userId) {
        final IAccessibilityManager service;
        synchronized (mLock) {
            service = getServiceLocked();
            if (service == null) {
                return false;
            }
        }

        try {
            return service.sendRestrictedDialogIntent(packageName, uid, userId);
        } catch (RemoteException re) {
            Log.e(LOG_TAG, "Error while show restricted dialog", re);
            return false;
        }
    }

    private IAccessibilityManager getServiceLocked() {
        if (mService == null) {
            tryConnectToServiceLocked(null);
+3 −0
Original line number Diff line number Diff line
@@ -126,6 +126,9 @@ interface IAccessibilityManager {
    boolean stopFlashNotificationSequence(String opPkg);
    boolean startFlashNotificationEvent(String opPkg, int reason, String reasonPkg);

    boolean isAccessibilityTargetAllowed(String packageName, int uid, int userId);
    boolean sendRestrictedDialogIntent(String packageName, int uid, int userId);

    parcelable WindowTransformationSpec {
        float[] transformationMatrix;
        MagnificationSpec magnificationSpec;
+18 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.content.Context;
import android.view.accessibility.AccessibilityManager.ShortcutType;

import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType;
import com.android.internal.accessibility.common.ShortcutConstants.ShortcutMenuMode;

/**
 * Base class for creating accessibility activity target.
@@ -40,8 +41,25 @@ class AccessibilityActivityTarget extends AccessibilityTarget {
                isShortcutContained(context, shortcutType,
                        shortcutInfo.getComponentName().flattenToString()),
                shortcutInfo.getComponentName().flattenToString(),
                shortcutInfo.getActivityInfo().applicationInfo.uid,
                shortcutInfo.getActivityInfo().loadLabel(context.getPackageManager()),
                shortcutInfo.getActivityInfo().loadIcon(context.getPackageManager()),
                convertToKey(convertToUserType(shortcutType)));
    }

    @Override
    public void updateActionItem(@NonNull TargetAdapter.ViewHolder holder,
            @ShortcutMenuMode int shortcutMenuMode) {
        super.updateActionItem(holder, shortcutMenuMode);

        final boolean isAllowed = AccessibilityTargetHelper.isAccessibilityTargetAllowed(
                getContext(), getComponentName().getPackageName(), getUid());
        final boolean isEditMenuMode =
                shortcutMenuMode == ShortcutMenuMode.EDIT;
        final boolean enabled = isAllowed || (isEditMenuMode && isShortcutEnabled());
        holder.mCheckBoxView.setEnabled(enabled);
        holder.mIconView.setEnabled(enabled);
        holder.mLabelView.setEnabled(enabled);
        holder.mStatusView.setEnabled(enabled);
    }
}
+18 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.content.Context;
import android.view.accessibility.AccessibilityManager.ShortcutType;

import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType;
import com.android.internal.accessibility.common.ShortcutConstants.ShortcutMenuMode;

/**
 * Base class for creating accessibility service target with various fragment types related to
@@ -42,8 +43,25 @@ class AccessibilityServiceTarget extends AccessibilityTarget {
                isShortcutContained(context, shortcutType,
                        serviceInfo.getComponentName().flattenToString()),
                serviceInfo.getComponentName().flattenToString(),
                serviceInfo.getResolveInfo().serviceInfo.applicationInfo.uid,
                serviceInfo.getResolveInfo().loadLabel(context.getPackageManager()),
                serviceInfo.getResolveInfo().loadIcon(context.getPackageManager()),
                convertToKey(convertToUserType(shortcutType)));
    }

    @Override
    public void updateActionItem(@NonNull TargetAdapter.ViewHolder holder,
            @ShortcutMenuMode int shortcutMenuMode) {
        super.updateActionItem(holder, shortcutMenuMode);

        final boolean isAllowed = AccessibilityTargetHelper.isAccessibilityTargetAllowed(
                getContext(), getComponentName().getPackageName(), getUid());
        final boolean isEditMenuMode =
                shortcutMenuMode == ShortcutMenuMode.EDIT;
        final boolean enabled = isAllowed || (isEditMenuMode && isShortcutEnabled());
        holder.mCheckBoxView.setEnabled(enabled);
        holder.mIconView.setEnabled(enabled);
        holder.mLabelView.setEnabled(enabled);
        holder.mStatusView.setEnabled(enabled);
    }
}
+36 −3
Original line number Diff line number Diff line
@@ -95,6 +95,13 @@ public class AccessibilityShortcutChooserActivity extends Activity {

    private void onTargetSelected(AdapterView<?> parent, View view, int position, long id) {
        final AccessibilityTarget target = mTargets.get(position);
        if (target instanceof AccessibilityServiceTarget
                || target instanceof AccessibilityActivityTarget) {
            if (sendRestrictedDialogIntentIfNeeded(target)) {
                return;
            }
        }

        target.onSelected();
        mMenuDialog.dismiss();
    }
@@ -102,15 +109,41 @@ public class AccessibilityShortcutChooserActivity extends Activity {
    private void onTargetChecked(AdapterView<?> parent, View view, int position, long id) {
        final AccessibilityTarget target = mTargets.get(position);

        if ((target instanceof AccessibilityServiceTarget) && !target.isShortcutEnabled()) {
            showPermissionDialogIfNeeded(this, (AccessibilityServiceTarget) target, mTargetAdapter);
        if (!target.isShortcutEnabled()) {
            if (target instanceof AccessibilityServiceTarget
                    || target instanceof AccessibilityActivityTarget) {
                if (sendRestrictedDialogIntentIfNeeded(target)) {
                    return;
                }
            }

            if (target instanceof AccessibilityServiceTarget) {
                showPermissionDialogIfNeeded(this, (AccessibilityServiceTarget) target,
                        mTargetAdapter);
                return;
            }
        }

        target.onCheckedChanged(!target.isShortcutEnabled());
        mTargetAdapter.notifyDataSetChanged();
    }

    /**
     * Sends restricted dialog intent if the accessibility target is disallowed.
     *
     * @return true if sends restricted dialog intent, otherwise false.
     */
    private boolean sendRestrictedDialogIntentIfNeeded(AccessibilityTarget target) {
        if (AccessibilityTargetHelper.isAccessibilityTargetAllowed(this,
                target.getComponentName().getPackageName(), target.getUid())) {
            return false;
        }

        AccessibilityTargetHelper.sendRestrictedDialogIntent(this,
                target.getComponentName().getPackageName(), target.getUid());
        return true;
    }

    private void showPermissionDialogIfNeeded(Context context,
            AccessibilityServiceTarget serviceTarget, ShortcutTargetAdapter targetAdapter) {
        if (mPermissionDialog != null) {
Loading