AccessibilityMenuService test class setup & initial test.
Bug: 265173123 Test: atest AccessibilityMenuServiceTests Change-Id: I388e02b58bf582ae6b481804c5f34883e8692e5f
This commit is contained in:
committed by
Riley Jones
parent
5c6c582940
commit
abdfd6f63b
@@ -18,6 +18,15 @@ package {
|
||||
default_applicable_licenses: ["Android-Apache-2.0"],
|
||||
}
|
||||
|
||||
// This filegroup is used by menu tests.
|
||||
filegroup {
|
||||
name: "AccessibilityMenuSource",
|
||||
srcs: [
|
||||
"src/**/AccessibilityMenuService.java",
|
||||
"src/**/A11yMenuShortcut.java",
|
||||
],
|
||||
}
|
||||
|
||||
android_app {
|
||||
name: "AccessibilityMenu",
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/shortcutItem"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingTop="@dimen/grid_item_padding"
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.systemui.accessibility.accessibilitymenu;
|
||||
|
||||
import android.Manifest;
|
||||
import android.accessibilityservice.AccessibilityButtonController;
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.content.BroadcastReceiver;
|
||||
@@ -51,8 +52,12 @@ import java.util.List;
|
||||
/** @hide */
|
||||
public class AccessibilityMenuService extends AccessibilityService
|
||||
implements View.OnTouchListener {
|
||||
private static final String TAG = "A11yMenuService";
|
||||
|
||||
public static final String PACKAGE_NAME = AccessibilityMenuService.class.getPackageName();
|
||||
public static final String INTENT_TOGGLE_MENU = ".toggle_menu";
|
||||
public static final String INTENT_HIDE_MENU = ".hide_menu";
|
||||
|
||||
private static final String TAG = "A11yMenuService";
|
||||
private static final long BUFFER_MILLISECONDS_TO_PREVENT_UPDATE_FAILURE = 100L;
|
||||
|
||||
private static final int BRIGHTNESS_UP_INCREMENT_GAMMA =
|
||||
@@ -74,7 +79,8 @@ public class AccessibilityMenuService extends AccessibilityService
|
||||
|
||||
// TODO(b/136716947): Support multi-display once a11y framework side is ready.
|
||||
private DisplayManager mDisplayManager;
|
||||
final DisplayManager.DisplayListener mDisplayListener = new DisplayManager.DisplayListener() {
|
||||
private final DisplayManager.DisplayListener mDisplayListener =
|
||||
new DisplayManager.DisplayListener() {
|
||||
int mRotation;
|
||||
|
||||
@Override
|
||||
@@ -95,13 +101,20 @@ public class AccessibilityMenuService extends AccessibilityService
|
||||
}
|
||||
};
|
||||
|
||||
final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
|
||||
private final BroadcastReceiver mHideMenuReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
mA11yMenuLayout.hideMenu();
|
||||
}
|
||||
};
|
||||
|
||||
private final BroadcastReceiver mToggleMenuReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
mA11yMenuLayout.toggleVisibility();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Update a11y menu layout when large button setting is changed.
|
||||
*/
|
||||
@@ -172,7 +185,19 @@ public class AccessibilityMenuService extends AccessibilityService
|
||||
protected void onServiceConnected() {
|
||||
mA11yMenuLayout = new A11yMenuOverlayLayout(this);
|
||||
|
||||
registerReceiver(mBroadcastReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
|
||||
IntentFilter hideMenuFilter = new IntentFilter();
|
||||
hideMenuFilter.addAction(Intent.ACTION_SCREEN_OFF);
|
||||
hideMenuFilter.addAction(PACKAGE_NAME + INTENT_HIDE_MENU);
|
||||
|
||||
// Including WRITE_SECURE_SETTINGS enforces that we only listen to apps
|
||||
// with the restricted WRITE_SECURE_SETTINGS permission who broadcast this intent.
|
||||
registerReceiver(mHideMenuReceiver, hideMenuFilter,
|
||||
Manifest.permission.WRITE_SECURE_SETTINGS, null,
|
||||
Context.RECEIVER_EXPORTED);
|
||||
registerReceiver(mToggleMenuReceiver,
|
||||
new IntentFilter(PACKAGE_NAME + INTENT_TOGGLE_MENU),
|
||||
Manifest.permission.WRITE_SECURE_SETTINGS, null,
|
||||
Context.RECEIVER_EXPORTED);
|
||||
|
||||
mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
mPrefs.registerOnSharedPreferenceChangeListener(mSharedPreferenceChangeListener);
|
||||
@@ -260,7 +285,8 @@ public class AccessibilityMenuService extends AccessibilityService
|
||||
* @param increment The increment amount in gamma-space
|
||||
*/
|
||||
private void adjustBrightness(int increment) {
|
||||
BrightnessInfo info = getDisplay().getBrightnessInfo();
|
||||
Display display = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
|
||||
BrightnessInfo info = display.getBrightnessInfo();
|
||||
int gamma = BrightnessUtils.convertLinearToGammaFloat(
|
||||
info.brightness,
|
||||
info.brightnessMinimum,
|
||||
@@ -275,7 +301,7 @@ public class AccessibilityMenuService extends AccessibilityService
|
||||
info.brightnessMinimum,
|
||||
info.brightnessMaximum
|
||||
);
|
||||
mDisplayManager.setBrightness(getDisplayId(), brightness);
|
||||
mDisplayManager.setBrightness(display.getDisplayId(), brightness);
|
||||
mA11yMenuLayout.showSnackbar(
|
||||
getString(R.string.brightness_percentage_label,
|
||||
(gamma / (BrightnessUtils.GAMMA_SPACE_MAX / 100))));
|
||||
@@ -310,7 +336,8 @@ public class AccessibilityMenuService extends AccessibilityService
|
||||
|
||||
@Override
|
||||
public boolean onUnbind(Intent intent) {
|
||||
unregisterReceiver(mBroadcastReceiver);
|
||||
unregisterReceiver(mHideMenuReceiver);
|
||||
unregisterReceiver(mToggleMenuReceiver);
|
||||
mPrefs.unregisterOnSharedPreferenceChangeListener(mSharedPreferenceChangeListener);
|
||||
sInitialized = false;
|
||||
return super.onUnbind(intent);
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.view.LayoutInflater;
|
||||
import android.view.TouchDelegate;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.TextView;
|
||||
@@ -146,6 +147,15 @@ public class A11yMenuAdapter extends BaseAdapter {
|
||||
|
||||
shortcutIconButton.setBackground(
|
||||
mShortcutDrawableUtils.createAdaptiveIconDrawable(shortcutItem.imageColor));
|
||||
|
||||
shortcutIconButton.setAccessibilityDelegate(new View.AccessibilityDelegate() {
|
||||
@Override
|
||||
public void onInitializeAccessibilityNodeInfo(
|
||||
View host, AccessibilityNodeInfo info) {
|
||||
super.onInitializeAccessibilityNodeInfo(host, info);
|
||||
info.setUniqueId(host.getTag().toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// Copyright (C) 2023 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package {
|
||||
default_applicable_licenses: ["Android-Apache-2.0"],
|
||||
}
|
||||
|
||||
android_test {
|
||||
name: "AccessibilityMenuServiceTests",
|
||||
certificate: "platform",
|
||||
libs: [
|
||||
"android.test.runner",
|
||||
"android.test.base",
|
||||
],
|
||||
static_libs: [
|
||||
"androidx.test.core",
|
||||
"androidx.test.runner",
|
||||
"androidx.test.ext.junit",
|
||||
"compatibility-device-util-axt",
|
||||
"platform-test-annotations",
|
||||
"truth-prebuilt",
|
||||
],
|
||||
srcs: [
|
||||
"src/**/*.java",
|
||||
":AccessibilityMenuSource",
|
||||
],
|
||||
platform_apis: true,
|
||||
test_suites: ["device-tests"],
|
||||
instrumentation_for: "AccessibilityMenu",
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2023 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.android.systemui.accessibility.accessibilitymenu.tests">
|
||||
|
||||
<!-- Needed to write to Settings.Secure to enable and disable the service under test. -->
|
||||
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS"/>
|
||||
|
||||
<application android:debuggable="true">
|
||||
<uses-library android:name="android.test.runner" />
|
||||
</application>
|
||||
|
||||
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
|
||||
android:targetPackage="com.android.systemui.accessibility.accessibilitymenu.tests"
|
||||
android:label="AccessibilityMenu Test Cases">
|
||||
</instrumentation>
|
||||
</manifest>
|
||||
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2023 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<configuration description="Runs AccessibilityMenu Test Cases.">
|
||||
<option name="test-tag" value="AccessibilityMenuServiceTests" />
|
||||
|
||||
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
|
||||
<option name="cleanup-apks" value="true" />
|
||||
<option name="test-file-name" value="AccessibilityMenuServiceTests.apk" />
|
||||
<option name="aapt-version" value="AAPT2" />
|
||||
</target_preparer>
|
||||
|
||||
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
|
||||
<option name="package" value="com.android.systemui.accessibility.accessibilitymenu.tests" />
|
||||
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
|
||||
</test>
|
||||
</configuration>
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"presubmit": [
|
||||
{
|
||||
"name": "AccessibilityMenuServiceTests",
|
||||
"options": [
|
||||
{
|
||||
"include-annotation": "android.platform.test.annotations.Presubmit"
|
||||
},
|
||||
{
|
||||
"exclude-annotation": "android.support.test.filters.FlakyTest"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.accessibility.accessibilitymenu.tests;
|
||||
|
||||
import static com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService.INTENT_HIDE_MENU;
|
||||
import static com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService.INTENT_TOGGLE_MENU;
|
||||
import static com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService.PACKAGE_NAME;
|
||||
|
||||
import android.accessibilityservice.AccessibilityServiceInfo;
|
||||
import android.app.Instrumentation;
|
||||
import android.app.UiAutomation;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.hardware.display.BrightnessInfo;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.provider.Settings;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.android.compatibility.common.util.TestUtils;
|
||||
import com.android.systemui.accessibility.accessibilitymenu.model.A11yMenuShortcut.ShortcutId;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AccessibilityMenuServiceTest {
|
||||
private static final String TAG = "A11yMenuServiceTest";
|
||||
|
||||
private static final int TIMEOUT_SERVICE_STATUS_CHANGE_S = 5;
|
||||
private static final int TIMEOUT_UI_CHANGE_S = 5;
|
||||
|
||||
private static Instrumentation sInstrumentation;
|
||||
private static UiAutomation sUiAutomation;
|
||||
|
||||
private static AccessibilityManager sAccessibilityManager;
|
||||
|
||||
@BeforeClass
|
||||
public static void classSetup() throws Throwable {
|
||||
final String serviceName = PACKAGE_NAME + "/.AccessibilityMenuService";
|
||||
sInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
sUiAutomation = sInstrumentation.getUiAutomation(
|
||||
UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
|
||||
final Context context = sInstrumentation.getContext();
|
||||
sAccessibilityManager = context.getSystemService(AccessibilityManager.class);
|
||||
|
||||
// Disable all a11yServices if any are active.
|
||||
if (!sAccessibilityManager.getEnabledAccessibilityServiceList(
|
||||
AccessibilityServiceInfo.FEEDBACK_ALL_MASK).isEmpty()) {
|
||||
Settings.Secure.putString(context.getContentResolver(),
|
||||
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, "");
|
||||
TestUtils.waitUntil("Failed to disable all services",
|
||||
TIMEOUT_SERVICE_STATUS_CHANGE_S,
|
||||
() -> sAccessibilityManager.getEnabledAccessibilityServiceList(
|
||||
AccessibilityServiceInfo.FEEDBACK_ALL_MASK).isEmpty());
|
||||
}
|
||||
|
||||
// Enable a11yMenu service.
|
||||
Settings.Secure.putString(context.getContentResolver(),
|
||||
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, serviceName);
|
||||
|
||||
TestUtils.waitUntil("Failed to enable service",
|
||||
TIMEOUT_SERVICE_STATUS_CHANGE_S,
|
||||
() -> sAccessibilityManager.getEnabledAccessibilityServiceList(
|
||||
AccessibilityServiceInfo.FEEDBACK_ALL_MASK).stream().filter(
|
||||
info -> info.getId().contains(serviceName)).count() == 1);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void classTeardown() throws Throwable {
|
||||
Settings.Secure.putString(sInstrumentation.getTargetContext().getContentResolver(),
|
||||
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, "");
|
||||
}
|
||||
|
||||
private boolean isMenuVisible() {
|
||||
return sUiAutomation.getRootInActiveWindow() != null
|
||||
&& sUiAutomation.getRootInActiveWindow().getPackageName().toString().equals(
|
||||
PACKAGE_NAME);
|
||||
}
|
||||
|
||||
private void openMenu() throws Throwable {
|
||||
if (isMenuVisible()) {
|
||||
return;
|
||||
}
|
||||
Intent intent = new Intent(PACKAGE_NAME + INTENT_TOGGLE_MENU);
|
||||
sInstrumentation.getContext().sendBroadcast(intent);
|
||||
TestUtils.waitUntil("Timed out before menu could appear.",
|
||||
TIMEOUT_UI_CHANGE_S, () -> isMenuVisible());
|
||||
}
|
||||
|
||||
private void closeMenu() throws Throwable {
|
||||
if (!isMenuVisible()) {
|
||||
return;
|
||||
}
|
||||
Intent intent = new Intent(PACKAGE_NAME + INTENT_HIDE_MENU);
|
||||
sInstrumentation.getContext().sendBroadcast(intent);
|
||||
TestUtils.waitUntil("Timed out before menu could close.",
|
||||
TIMEOUT_UI_CHANGE_S, () -> !isMenuVisible());
|
||||
}
|
||||
|
||||
private List<AccessibilityNodeInfo> getGridButtonList() {
|
||||
return sUiAutomation.getRootInActiveWindow()
|
||||
.findAccessibilityNodeInfosByViewId(PACKAGE_NAME + ":id/shortcutIconBtn");
|
||||
}
|
||||
|
||||
private AccessibilityNodeInfo findGridButtonInfo(
|
||||
List<AccessibilityNodeInfo> buttons, String text) {
|
||||
for (AccessibilityNodeInfo button: buttons) {
|
||||
if (button.getUniqueId().equals(text)) {
|
||||
return button;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAdjustBrightness() throws Throwable {
|
||||
openMenu();
|
||||
|
||||
Context context = sInstrumentation.getTargetContext();
|
||||
DisplayManager displayManager = context.getSystemService(
|
||||
DisplayManager.class);
|
||||
float resetBrightness = displayManager.getBrightness(context.getDisplayId());
|
||||
|
||||
List<AccessibilityNodeInfo> buttons = getGridButtonList();
|
||||
AccessibilityNodeInfo brightnessUpButton = findGridButtonInfo(buttons,
|
||||
String.valueOf(ShortcutId.ID_BRIGHTNESS_UP_VALUE.ordinal()));
|
||||
AccessibilityNodeInfo brightnessDownButton = findGridButtonInfo(buttons,
|
||||
String.valueOf(ShortcutId.ID_BRIGHTNESS_DOWN_VALUE.ordinal()));
|
||||
|
||||
int clickId = AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.getId();
|
||||
BrightnessInfo brightnessInfo = displayManager.getDisplay(
|
||||
context.getDisplayId()).getBrightnessInfo();
|
||||
|
||||
try {
|
||||
displayManager.setBrightness(context.getDisplayId(), brightnessInfo.brightnessMinimum);
|
||||
TestUtils.waitUntil("Could not change to minimum brightness",
|
||||
TIMEOUT_UI_CHANGE_S,
|
||||
() -> displayManager.getBrightness(context.getDisplayId())
|
||||
== brightnessInfo.brightnessMinimum);
|
||||
brightnessUpButton.performAction(clickId);
|
||||
TestUtils.waitUntil("Did not detect an increase in brightness.",
|
||||
TIMEOUT_UI_CHANGE_S,
|
||||
() -> displayManager.getBrightness(context.getDisplayId())
|
||||
> brightnessInfo.brightnessMinimum);
|
||||
|
||||
displayManager.setBrightness(context.getDisplayId(), brightnessInfo.brightnessMaximum);
|
||||
TestUtils.waitUntil("Could not change to maximum brightness",
|
||||
TIMEOUT_UI_CHANGE_S,
|
||||
() -> displayManager.getBrightness(context.getDisplayId())
|
||||
== brightnessInfo.brightnessMaximum);
|
||||
brightnessDownButton.performAction(clickId);
|
||||
TestUtils.waitUntil("Did not detect a decrease in brightness.",
|
||||
TIMEOUT_UI_CHANGE_S,
|
||||
() -> displayManager.getBrightness(context.getDisplayId())
|
||||
< brightnessInfo.brightnessMaximum);
|
||||
} finally {
|
||||
displayManager.setBrightness(context.getDisplayId(), resetBrightness);
|
||||
closeMenu();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user