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

Commit d261711e authored by Hongming Jin's avatar Hongming Jin Committed by Android (Google) Code Review
Browse files

Merge "System action registration API for SystemUI"

parents 3df3e3b0 bc76112e
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -11833,6 +11833,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