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

Commit bc76112e authored by Hongming Jin's avatar Hongming Jin
Browse files

System action registration API for SystemUI

Bug: 136286274
Test: atest AccessibilityManagerTest
      atest AccessibilityManagerServiceTest
Change-Id: I6bbdf3627bfc9b39551cc7809dda1cf43d1d6ea4
parent 82825a24
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -11495,6 +11495,8 @@ package android.view.accessibility {
  public final class AccessibilityManager {
    method public int getAccessibilityWindowId(@Nullable android.os.IBinder);
    method @RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY) public void performAccessibilityShortcut();
    method @RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY) public void registerSystemAction(@NonNull android.app.RemoteAction, int);
    method @RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY) public void unregisterSystemAction(int);
  }
}
+56 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.annotation.UserIdInt;
import android.app.RemoteAction;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
@@ -1208,6 +1209,61 @@ public final class AccessibilityManager {
        }
    }

    /**
     * Register the provided {@link RemoteAction} with the given actionId
     *
     * @param action The remote action to be registered with the given actionId as system action.
     * @param actionId The id uniquely identify the system action.
     * @hide
     */
    @SystemApi
    @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
    public void registerSystemAction(@NonNull RemoteAction action, int actionId) {
        final IAccessibilityManager service;
        synchronized (mLock) {
            service = getServiceLocked();
            if (service == null) {
                return;
            }
        }
        try {
            service.registerSystemAction(action, actionId);

            if (DEBUG) {
                Log.i(LOG_TAG, "System action " + action.getTitle() + " is registered.");
            }
        } catch (RemoteException re) {
            Log.e(LOG_TAG, "Error registering system action " + action.getTitle() + " ", re);
        }
    }

   /**
     * Unregister a system action with the given actionId
     *
     * @param actionId The id uniquely identify the system action to be unregistered.
     * @hide
     */
    @SystemApi
    @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
    public void unregisterSystemAction(int actionId) {
        final IAccessibilityManager service;
        synchronized (mLock) {
            service = getServiceLocked();
            if (service == null) {
                return;
            }
        }
        try {
            service.unregisterSystemAction(actionId);

            if (DEBUG) {
                Log.i(LOG_TAG, "System action with actionId " + actionId + " is unregistered.");
            }
        } catch (RemoteException re) {
            Log.e(LOG_TAG, "Error unregistering system action with actionId " + actionId + " ", re);
        }
    }

    /**
     * Notifies that the accessibility button in the system's navigation area has been clicked
     *
+4 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.view.accessibility;

import android.app.RemoteAction;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.IAccessibilityServiceConnection;
import android.accessibilityservice.IAccessibilityServiceClient;
@@ -82,4 +83,7 @@ interface IAccessibilityManager {
    int getAccessibilityWindowId(IBinder windowToken);

    long getRecommendedTimeoutMillis();

    oneway void registerSystemAction(in RemoteAction action, int actionId);
    oneway void unregisterSystemAction(int actionId);
}
+39 −5
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@
 * limitations under the License.
 */

package com.android.server.accessibility;
package android.view.accessibility;

import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertSame;
@@ -29,16 +29,17 @@ import static org.mockito.Mockito.when;

import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.Instrumentation;
import android.app.PendingIntent;
import android.app.RemoteAction;
import android.content.Intent;
import android.graphics.drawable.Icon;
import android.os.UserHandle;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager;
import android.view.accessibility.IAccessibilityManagerClient;

import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;

import com.android.internal.util.IntPair;
import com.android.server.accessibility.test.MessageCapturingHandler;

import org.junit.After;
import org.junit.Before;
@@ -57,6 +58,16 @@ import java.util.List;
public class AccessibilityManagerTest {
    private static final boolean WITH_A11Y_ENABLED = true;
    private static final boolean WITH_A11Y_DISABLED = false;
    private static final String LABEL = "label";
    private static final String INTENT_ACTION = "TESTACTION";
    private static final String DESCRIPTION = "description";
    private static final PendingIntent TEST_PENDING_INTENT = PendingIntent.getBroadcast(
            InstrumentationRegistry.getTargetContext(), 0, new Intent(INTENT_ACTION), 0);
    private static final RemoteAction TEST_ACTION = new RemoteAction(
            Icon.createWithContentUri("content://test"),
            LABEL,
            DESCRIPTION,
            TEST_PENDING_INTENT);

    @Mock private IAccessibilityManager mMockService;
    private MessageCapturingHandler mHandler;
@@ -121,6 +132,29 @@ public class AccessibilityManagerTest {
        verify(mMockService).interrupt(UserHandle.USER_CURRENT);
    }

    @Test
    public void testRegisterSystemAction() throws Exception {
        AccessibilityManager manager = createManager(WITH_A11Y_ENABLED);
        RemoteAction action = new RemoteAction(
                Icon.createWithContentUri("content://test"),
                LABEL,
                DESCRIPTION,
                TEST_PENDING_INTENT);
        final int actionId = 0;
        manager.registerSystemAction(TEST_ACTION, actionId);

        verify(mMockService).registerSystemAction(TEST_ACTION, actionId);
    }

    @Test
    public void testUnregisterSystemAction() throws Exception {
        AccessibilityManager manager = createManager(WITH_A11Y_ENABLED);
        final int actionId = 0;
        manager.unregisterSystemAction(actionId);

        verify(mMockService).unregisterSystemAction(actionId);
    }

    @Test
    public void testIsEnabled() throws Exception {
        // Create manager with a11y enabled
+57 −6
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.app.RemoteAction;
import android.appwidget.AppWidgetManagerInternal;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
@@ -148,6 +149,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
    //       their capabilities are ready.
    private static final int WAIT_MOTION_INJECTOR_TIMEOUT_MILLIS = 1000;

    static final String FUNCTION_REGISTER_SYSTEM_ACTION = "registerSystemAction";
    static final String FUNCTION_UNREGISTER_SYSTEM_ACTION = "unregisterSystemAction";
    private static final String FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE =
        "registerUiTestAutomationService";

@@ -253,6 +256,27 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
        }
    }

    @VisibleForTesting
    AccessibilityManagerService(
            Context context,
            PackageManager packageManager,
            AccessibilitySecurityPolicy securityPolicy,
            SystemActionPerformer systemActionPerformer,
            AccessibilityWindowManager a11yWindowManager,
            AccessibilityDisplayListener a11yDisplayListener) {
        mContext = context;
        mPowerManager =  (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
        mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
        mMainHandler = new MainHandler(mContext.getMainLooper());
        mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class);
        mPackageManager = packageManager;
        mSecurityPolicy = securityPolicy;
        mSystemActionPerformer = systemActionPerformer;
        mA11yWindowManager = a11yWindowManager;
        mA11yDisplayListener = a11yDisplayListener;
        init();
    }

    /**
     * Creates a new instance.
     *
@@ -260,21 +284,24 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
     */
    public AccessibilityManagerService(Context context) {
        mContext = context;
        mPackageManager = mContext.getPackageManager();
        mPowerManager =  (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
        mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
        mSecurityPolicy = new AccessibilitySecurityPolicy(mContext, this);
        mMainHandler = new MainHandler(mContext.getMainLooper());
        mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class);
        mPackageManager = mContext.getPackageManager();
        mSecurityPolicy = new AccessibilitySecurityPolicy(mContext, this);
        mSystemActionPerformer = new SystemActionPerformer(mContext, mWindowManagerService);
        mA11yWindowManager = new AccessibilityWindowManager(mLock, mMainHandler,
                mWindowManagerService, this, mSecurityPolicy, this);
        mA11yDisplayListener = new AccessibilityDisplayListener(mContext, mMainHandler);
        mSecurityPolicy.setAccessibilityWindowManager(mA11yWindowManager);
        mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class);
        init();
    }

    private void init() {
        mSecurityPolicy.setAccessibilityWindowManager(mA11yWindowManager);
        registerBroadcastReceivers();
        new AccessibilityContentObserver(mMainHandler).register(
                context.getContentResolver());
                mContext.getContentResolver());
    }

    @Override
@@ -623,6 +650,30 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
        event.recycle();
    }

    /**
     * This is the implementation of AccessibilityManager system API.
     * System UI calls into this method through AccessibilityManager system API to register a
     * system action.
     */
    @Override
    public void registerSystemAction(RemoteAction action, int actionId) {
        mSecurityPolicy.enforceCallingPermission(Manifest.permission.MANAGE_ACCESSIBILITY,
                FUNCTION_REGISTER_SYSTEM_ACTION);
        mSystemActionPerformer.registerSystemAction(actionId, action);
    }

    /**
     * This is the implementation of AccessibilityManager system API.
     * System UI calls into this method through AccessibilityManager system API to unregister a
     * system action.
     */
    @Override
    public void unregisterSystemAction(int actionId) {
        mSecurityPolicy.enforceCallingPermission(Manifest.permission.MANAGE_ACCESSIBILITY,
                FUNCTION_UNREGISTER_SYSTEM_ACTION);
        mSystemActionPerformer.unregisterSystemAction(actionId);
    }

    @Override
    public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) {
        synchronized (mLock) {
Loading