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

Commit d0429743 authored by Phil Weaver's avatar Phil Weaver
Browse files

Add a11y action to take screenshot

Bug: 70392997
Test: Adding unit test for functionality, cts test
for presence of api.

Change-Id: Ib5bc2217e1d29f527db0f0fadb69fd8249d6c279
parent e2861da8
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -2792,6 +2792,7 @@ package android.accessibilityservice {
    field public static final int GLOBAL_ACTION_POWER_DIALOG = 6; // 0x6
    field public static final int GLOBAL_ACTION_QUICK_SETTINGS = 5; // 0x5
    field public static final int GLOBAL_ACTION_RECENTS = 3; // 0x3
    field public static final int GLOBAL_ACTION_TAKE_SCREENSHOT = 9; // 0x9
    field public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7; // 0x7
    field public static final java.lang.String SERVICE_INTERFACE = "android.accessibilityservice.AccessibilityService";
    field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice";
+5 −0
Original line number Diff line number Diff line
@@ -363,6 +363,11 @@ public abstract class AccessibilityService extends Service {
     */
    public static final int GLOBAL_ACTION_LOCK_SCREEN = 8;

    /**
     * Action to take a screenshot
     */
    public static final int GLOBAL_ACTION_TAKE_SCREENSHOT = 9;

    private static final String LOG_TAG = "AccessibilityService";

    /**
+12 −1
Original line number Diff line number Diff line
package com.android.internal.util;

import android.annotation.NonNull;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -32,8 +33,18 @@ public class ScreenshotHelper {
        mContext = context;
    }

    /**
     * Request a screenshot be taken.
     *
     * @param screenshotType The type of screenshot, for example either
     *                       {@link android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN}
     *                       or {@link android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION}
     * @param hasStatus {@code true} if the status bar is currently showing. {@code false} if not.
     * @param hasNav {@code true} if the navigation bar is currently showing. {@code false} if not.
     * @param handler A handler used in case the screenshot times out
     */
    public void takeScreenshot(final int screenshotType, final boolean hasStatus,
            final boolean hasNav, Handler handler) {
            final boolean hasNav, @NonNull Handler handler) {
        synchronized (mScreenshotLock) {
            if (mScreenshotConnection != null) {
                return;
+27 −0
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ import android.app.StatusBarManager;
import android.content.Context;
import android.hardware.input.InputManager;
import android.os.Binder;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -30,20 +32,34 @@ import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ScreenshotHelper;
import com.android.server.LocalServices;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.wm.WindowManagerInternal;

import java.util.function.Supplier;

/**
 * Handle the back-end of AccessibilityService#performGlobalAction
 */
public class GlobalActionPerformer {
    private final WindowManagerInternal mWindowManagerService;
    private final Context mContext;
    private Supplier<ScreenshotHelper> mScreenshotHelperSupplier;

    public GlobalActionPerformer(Context context, WindowManagerInternal windowManagerInternal) {
        mContext = context;
        mWindowManagerService = windowManagerInternal;
        mScreenshotHelperSupplier = null;
    }

    // Used to mock ScreenshotHelper
    @VisibleForTesting
    public GlobalActionPerformer(Context context, WindowManagerInternal windowManagerInternal,
            Supplier<ScreenshotHelper> screenshotHelperSupplier) {
        this(context, windowManagerInternal);
        mScreenshotHelperSupplier = screenshotHelperSupplier;
    }

    public boolean performGlobalAction(int action) {
@@ -79,6 +95,9 @@ public class GlobalActionPerformer {
                case AccessibilityService.GLOBAL_ACTION_LOCK_SCREEN: {
                    return lockScreen();
                }
                case AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT: {
                    return takeScreenshot();
                }
            }
            return false;
        } finally {
@@ -167,4 +186,12 @@ public class GlobalActionPerformer {
        mWindowManagerService.lockNow();
        return true;
    }

    private boolean takeScreenshot() {
        ScreenshotHelper screenshotHelper = (mScreenshotHelperSupplier != null)
                ? mScreenshotHelperSupplier.get() : new ScreenshotHelper(mContext);
        screenshotHelper.takeScreenshot(android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN,
                true, true, new Handler(Looper.getMainLooper()));
        return true;
    }
}
+17 −1
Original line number Diff line number Diff line
@@ -16,13 +16,18 @@

package com.android.server.accessibility;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.accessibilityservice.AccessibilityService;
import android.app.StatusBarManager;
import android.content.Context;
import android.os.Handler;

import com.android.internal.util.ScreenshotHelper;
import com.android.server.wm.WindowManagerInternal;

import org.junit.Before;
@@ -39,6 +44,7 @@ public class GlobalActionPerformerTest {
    @Mock Context mMockContext;
    @Mock WindowManagerInternal mMockWindowManagerInternal;
    @Mock StatusBarManager mMockStatusBarManager;
    @Mock ScreenshotHelper mMockScreenshotHelper;

    @Before
    public void setup() {
@@ -48,7 +54,8 @@ public class GlobalActionPerformerTest {
                .thenReturn(mMockStatusBarManager);

        mGlobalActionPerformer =
                new GlobalActionPerformer(mMockContext, mMockWindowManagerInternal);
                new GlobalActionPerformer(mMockContext, mMockWindowManagerInternal,
                        () -> mMockScreenshotHelper);
    }

    @Test
@@ -70,4 +77,13 @@ public class GlobalActionPerformerTest {
        mGlobalActionPerformer.performGlobalAction(AccessibilityService.GLOBAL_ACTION_POWER_DIALOG);
        verify(mMockWindowManagerInternal).showGlobalActions();
    }

    @Test
    public void testScreenshot_requestsFromScreenshotHelper() {
        mGlobalActionPerformer.performGlobalAction(
                AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT);
        verify(mMockScreenshotHelper).takeScreenshot(
                eq(android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN), anyBoolean(),
                anyBoolean(), any(Handler.class));
    }
}