Show notification to promote window magnification mode available

The magnification mode is full-screen when the migrating deivce turns on
magnification settings.
We show a notification prompt the user that new window magnifier to
guide the user to take a look.

Bug: 168635084
Test: 1. adb shell settings put secure \
      accessibility_show_window_magnification_prompt 1
      2. use full-screen magnification to see if it works well.
      atest WindowMagnificationPromptControllerTest
      atest FullScreenMagnificationGestureHandlerTest
Change-Id: I40dfc49307d2dad380f1e662960d35f5cc5e7524
This commit is contained in:
ryanlwlin
2020-11-05 16:58:29 +08:00
parent 54e28edd2f
commit 3badad790d
9 changed files with 482 additions and 5 deletions

View File

@@ -57,6 +57,7 @@ public class SystemNotificationChannels {
public static String HEAVY_WEIGHT_APP = "HEAVY_WEIGHT_APP";
public static String SYSTEM_CHANGES = "SYSTEM_CHANGES";
public static String DO_NOT_DISTURB = "DO_NOT_DISTURB";
public static String ACCESSIBILITY_MAGNIFICATION = "ACCESSIBILITY_MAGNIFICATION";
public static void createAll(Context context) {
final NotificationManager nm = context.getSystemService(NotificationManager.class);
@@ -191,6 +192,13 @@ public class SystemNotificationChannels {
NotificationManager.IMPORTANCE_LOW);
channelsList.add(dndChanges);
final NotificationChannel newFeaturePrompt = new NotificationChannel(
ACCESSIBILITY_MAGNIFICATION,
context.getString(R.string.notification_channel_accessibility_magnification),
NotificationManager.IMPORTANCE_HIGH);
newFeaturePrompt.setBlockable(true);
channelsList.add(newFeaturePrompt);
nm.createNotificationChannels(channelsList);
}

View File

@@ -717,6 +717,10 @@
[CHAR LIMIT=NONE BACKUP_MESSAGE_ID=6665375982962336520] -->
<string name="notification_channel_foreground_service">Apps consuming battery</string>
<!-- Text shown when viewing channel settings for notifications related to accessibility
magnification. [CHAR_LIMIT=NONE]-->
<string name="notification_channel_accessibility_magnification">Magnification</string>
<!-- Label for foreground service notification when one app is running.
[CHAR LIMIT=NONE BACKUP_MESSAGE_ID=6826789589341671842] -->
<string name="foreground_service_app_in_background"><xliff:g id="app_name">%1$s</xliff:g> is
@@ -5767,4 +5771,16 @@ ul.</string>
<string name="config_pdp_reject_service_not_subscribed"></string>
<!-- pdp data reject dialog string for cause 55 (MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED) [CHAR LIMIT=100] -->
<string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed"></string>
<!-- Window magnification prompt related string. -->
<!-- Notification title to prompt the user that new magnification feature is available. [CHAR LIMIT=50] -->
<string name="window_magnification_prompt_title">New: Window Magnifier</string>
<!-- Notification content to prompt the user that new magnification feature is available. [CHAR LIMIT=50] -->
<string name="window_magnification_prompt_content">You can now magnify some or all of your screen</string>
<!-- Notification action to bring the user to magnification settings page. [CHAR LIMIT=50] -->
<string name="turn_on_magnification_settings_action">Turn on in Settings</string>
<!-- Notification action to dismiss. [CHAR LIMIT=50] -->
<string name="dismiss_action">Dismiss</string>
</resources>

View File

@@ -3460,6 +3460,7 @@
<java-symbol type="string" name="notification_channel_heavy_weight_app" />
<java-symbol type="string" name="notification_channel_system_changes" />
<java-symbol type="string" name="notification_channel_do_not_disturb" />
<java-symbol type="string" name="notification_channel_accessibility_magnification" />
<java-symbol type="string" name="config_defaultAutofillService" />
<java-symbol type="string" name="config_defaultTextClassifierPackage" />
<java-symbol type="string" name="config_defaultWellbeingPackage" />
@@ -4097,4 +4098,10 @@
<java-symbol type="dimen" name="config_taskLetterboxAspectRatio" />
<java-symbol type="bool" name="config_hideDisplayCutoutWithDisplayArea" />
<!-- Window magnification prompt -->
<java-symbol type="string" name="window_magnification_prompt_title" />
<java-symbol type="string" name="window_magnification_prompt_content" />
<java-symbol type="string" name="turn_on_magnification_settings_action" />
<java-symbol type="string" name="dismiss_action" />
</resources>

View File

@@ -332,5 +332,9 @@ message SystemMessage {
// Notify the user that the admin suspended personal apps on the device.
// Package: android
NOTE_PERSONAL_APPS_SUSPENDED = 1003;
// Notify the user that window magnification is available.
// package: android
NOTE_A11Y_WINDOW_MAGNIFICATION_FEATURE = 1004;
}
}

View File

@@ -37,6 +37,7 @@ import com.android.server.accessibility.gestures.TouchExplorer;
import com.android.server.accessibility.magnification.FullScreenMagnificationGestureHandler;
import com.android.server.accessibility.magnification.MagnificationGestureHandler;
import com.android.server.accessibility.magnification.WindowMagnificationGestureHandler;
import com.android.server.accessibility.magnification.WindowMagnificationPromptController;
import com.android.server.policy.WindowManagerPolicy;
import java.util.ArrayList;
@@ -561,8 +562,9 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
detectControlGestures, triggerable, displayId);
} else {
magnificationGestureHandler = new FullScreenMagnificationGestureHandler(displayContext,
mAms.getFullScreenMagnificationController(), mAms::onMagnificationScaleChanged,
detectControlGestures, triggerable, displayId);
mAms.getFullScreenMagnificationController(),
mAms::onMagnificationScaleChanged, detectControlGestures, triggerable,
new WindowMagnificationPromptController(displayContext, mUserId), displayId);
}
return magnificationGestureHandler;
}

View File

@@ -137,6 +137,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
@VisibleForTesting final ViewportDraggingState mViewportDraggingState;
private final ScreenStateReceiver mScreenStateReceiver;
private final WindowMagnificationPromptController mPromptController;
/**
* {@code true} if this detector should detect and respond to triple-tap
@@ -178,6 +179,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
ScaleChangedListener listener,
boolean detectTripleTap,
boolean detectShortcutTrigger,
@NonNull WindowMagnificationPromptController promptController,
int displayId) {
super(listener);
if (DEBUG_ALL) {
@@ -186,6 +188,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
+ ", detectShortcutTrigger = " + detectShortcutTrigger + ")");
}
mFullScreenMagnificationController = fullScreenMagnificationController;
mPromptController = promptController;
mDisplayId = displayId;
mDelegatingState = new DelegatingState();
@@ -195,7 +198,6 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
mDetectTripleTap = detectTripleTap;
mDetectShortcutTrigger = detectShortcutTrigger;
if (mDetectShortcutTrigger) {
mScreenStateReceiver = new ScreenStateReceiver(context, this);
mScreenStateReceiver.register();
@@ -264,6 +266,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
if (mScreenStateReceiver != null) {
mScreenStateReceiver.unregister();
}
mPromptController.onDestroy();
// Check if need to reset when MagnificationGestureHandler is the last magnifying service.
mFullScreenMagnificationController.resetAllIfNeeded(
AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
@@ -278,6 +281,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
if (wasMagnifying) {
clearAndTransitionToStateDetecting();
} else {
mPromptController.showNotificationIfNeeded();
mDetectingState.toggleShortcutTriggered();
}
}
@@ -950,6 +954,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
if (mFullScreenMagnificationController.isMagnifying(mDisplayId)) {
zoomOff();
} else {
mPromptController.showNotificationIfNeeded();
zoomOn(up.getX(), up.getY());
}
}

View File

@@ -0,0 +1,211 @@
/*
* Copyright (C) 2020 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.server.accessibility.magnification;
import static android.provider.Settings.Secure.ACCESSIBILITY_SHOW_WINDOW_MAGNIFICATION_PROMPT;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME;
import static com.android.internal.messages.nano.SystemMessageProto.SystemMessage.NOTE_A11Y_WINDOW_MAGNIFICATION_FEATURE;
import android.Manifest;
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.app.ActivityOptions;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Bundle;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.notification.SystemNotificationChannels;
/**
* A class to show notification to prompt the user that this feature is available.
*/
public class WindowMagnificationPromptController {
private static final Uri MAGNIFICATION_WINDOW_MODE_PROMPT_URI = Settings.Secure.getUriFor(
ACCESSIBILITY_SHOW_WINDOW_MAGNIFICATION_PROMPT);
@VisibleForTesting
static final String ACTION_DISMISS =
"com.android.server.accessibility.magnification.action.DISMISS";
@VisibleForTesting
static final String ACTION_TURN_ON_IN_SETTINGS =
"com.android.server.accessibility.magnification.action.TURN_ON_IN_SETTINGS";
private final Context mContext;
private final NotificationManager mNotificationManager;
private final ContentObserver mContentObserver;
private final int mUserId;
@VisibleForTesting
BroadcastReceiver mNotificationActionReceiver;
private boolean mNeedToShowNotification;
@MainThread
public WindowMagnificationPromptController(@NonNull Context context, int userId) {
mContext = context;
mNotificationManager = context.getSystemService(NotificationManager.class);
mUserId = userId;
mContentObserver = new ContentObserver(null) {
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
onPromptSettingsValueChanged();
}
};
context.getContentResolver().registerContentObserver(MAGNIFICATION_WINDOW_MODE_PROMPT_URI,
false, mContentObserver, mUserId);
mNeedToShowNotification = isWindowMagnificationPromptEnabled();
}
@VisibleForTesting
protected void onPromptSettingsValueChanged() {
final boolean needToShowNotification = isWindowMagnificationPromptEnabled();
if (mNeedToShowNotification == needToShowNotification) {
return;
}
mNeedToShowNotification = needToShowNotification;
if (!mNeedToShowNotification) {
unregisterReceiverIfNeeded();
mNotificationManager.cancel(NOTE_A11Y_WINDOW_MAGNIFICATION_FEATURE);
}
}
/**
* Shows the prompt notification that could bring users to magnification settings if necessary.
*/
@MainThread
void showNotificationIfNeeded() {
if (!mNeedToShowNotification) return;
final Notification.Builder notificationBuilder = new Notification.Builder(mContext,
SystemNotificationChannels.ACCESSIBILITY_MAGNIFICATION);
notificationBuilder.setSmallIcon(R.drawable.ic_settings_24dp)
.setContentTitle(mContext.getString(R.string.window_magnification_prompt_title))
.setContentText(mContext.getString(R.string.window_magnification_prompt_content))
.setLargeIcon(Icon.createWithResource(mContext,
R.drawable.ic_accessibility_magnification))
.setTicker(mContext.getString(R.string.window_magnification_prompt_title))
.setOnlyAlertOnce(true)
.setDeleteIntent(createPendingIntent(ACTION_DISMISS))
.setContentIntent(createPendingIntent(ACTION_TURN_ON_IN_SETTINGS))
.setActions(buildTurnOnAction(), buildDismissAction());
mNotificationManager.notify(NOTE_A11Y_WINDOW_MAGNIFICATION_FEATURE,
notificationBuilder.build());
registerReceiverIfNeeded();
}
/**
* Called when this object is not used anymore to release resources if necessary.
*/
@VisibleForTesting
@MainThread
public void onDestroy() {
dismissNotification();
mContext.getContentResolver().unregisterContentObserver(mContentObserver);
}
private boolean isWindowMagnificationPromptEnabled() {
return Settings.Secure.getIntForUser(mContext.getContentResolver(),
ACCESSIBILITY_SHOW_WINDOW_MAGNIFICATION_PROMPT, 0, mUserId) == 1;
}
private Notification.Action buildTurnOnAction() {
return new Notification.Action.Builder(null,
mContext.getString(R.string.turn_on_magnification_settings_action),
createPendingIntent(ACTION_TURN_ON_IN_SETTINGS)).build();
}
private Notification.Action buildDismissAction() {
return new Notification.Action.Builder(null, mContext.getString(R.string.dismiss_action),
createPendingIntent(ACTION_DISMISS)).build();
}
private PendingIntent createPendingIntent(String action) {
final Intent intent = new Intent(action);
intent.setPackage(mContext.getPackageName());
return PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_IMMUTABLE);
}
private void registerReceiverIfNeeded() {
if (mNotificationActionReceiver != null) {
return;
}
mNotificationActionReceiver = new NotificationActionReceiver();
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION_DISMISS);
intentFilter.addAction(ACTION_TURN_ON_IN_SETTINGS);
mContext.registerReceiver(mNotificationActionReceiver, intentFilter,
Manifest.permission.MANAGE_ACCESSIBILITY, null);
}
private void launchMagnificationSettings() {
final Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_DETAILS_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.putExtra(Intent.EXTRA_COMPONENT_NAME,
MAGNIFICATION_COMPONENT_NAME.flattenToShortString());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
final Bundle bundle = ActivityOptions.makeBasic().setLaunchDisplayId(
mContext.getDisplayId()).toBundle();
mContext.startActivityAsUser(intent, bundle, UserHandle.of(mUserId));
mContext.getSystemService(StatusBarManager.class).collapsePanels();
}
private void dismissNotification() {
unregisterReceiverIfNeeded();
mNotificationManager.cancel(NOTE_A11Y_WINDOW_MAGNIFICATION_FEATURE);
}
private void unregisterReceiverIfNeeded() {
if (mNotificationActionReceiver == null) {
return;
}
mContext.unregisterReceiver(mNotificationActionReceiver);
mNotificationActionReceiver = null;
}
private class NotificationActionReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (TextUtils.isEmpty(action)) return;
mNeedToShowNotification = false;
Settings.Secure.putIntForUser(mContext.getContentResolver(),
ACCESSIBILITY_SHOW_WINDOW_MAGNIFICATION_PROMPT, 0, mUserId);
if (ACTION_TURN_ON_IN_SETTINGS.equals(action)) {
launchMagnificationSettings();
dismissNotification();
} else if (ACTION_DISMISS.equals(action)) {
dismissNotification();
}
}
}
}

View File

@@ -66,7 +66,6 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.List;
import java.util.function.IntConsumer;
@@ -129,6 +128,8 @@ public class FullScreenMagnificationGestureHandlerTest {
ScaleChangedListener mMockScaleChangedListener;
@Mock
MagnificationRequestObserver mMagnificationRequestObserver;
@Mock
WindowMagnificationPromptController mWindowMagnificationPromptController;
private OffsettableClock mClock;
private FullScreenMagnificationGestureHandler mMgh;
@@ -170,7 +171,9 @@ public class FullScreenMagnificationGestureHandlerTest {
@After
public void tearDown() {
mMgh.onDestroy();
mFullScreenMagnificationController.unregister(DISPLAY_0);
verify(mWindowMagnificationPromptController).onDestroy();
}
@NonNull
@@ -178,7 +181,8 @@ public class FullScreenMagnificationGestureHandlerTest {
boolean detectShortcutTrigger) {
FullScreenMagnificationGestureHandler h = new FullScreenMagnificationGestureHandler(
mContext, mFullScreenMagnificationController, mMockScaleChangedListener,
detectTripleTap, detectShortcutTrigger, DISPLAY_0);
detectTripleTap, detectShortcutTrigger, mWindowMagnificationPromptController,
DISPLAY_0);
mHandler = new TestHandler(h.mDetectingState, mClock) {
@Override
protected String messageToString(Message m) {
@@ -434,6 +438,20 @@ public class FullScreenMagnificationGestureHandlerTest {
returnToNormalFrom(STATE_PANNING);
}
@Test
public void testZoomedWithTripleTap_invokeShowWindowPromptAction() {
goFromStateIdleTo(STATE_ZOOMED);
verify(mWindowMagnificationPromptController).showNotificationIfNeeded();
}
@Test
public void testShortcutTriggered_invokeShowWindowPromptAction() {
goFromStateIdleTo(STATE_SHORTCUT_TRIGGERED);
verify(mWindowMagnificationPromptController).showNotificationIfNeeded();
}
private void assertActionsInOrder(List<MotionEvent> actualEvents,
List<Integer> expectedActions) {
assertTrue(actualEvents.size() == expectedActions.size());

View File

@@ -0,0 +1,206 @@
/*
* Copyright (C) 2020 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.server.accessibility.magnification;
import static android.provider.Settings.Secure.ACCESSIBILITY_SHOW_WINDOW_MAGNIFICATION_PROMPT;
import static com.android.internal.messages.nano.SystemMessageProto.SystemMessage.NOTE_A11Y_WINDOW_MAGNIFICATION_FEATURE;
import static com.android.server.accessibility.magnification.WindowMagnificationPromptController.ACTION_TURN_ON_IN_SETTINGS;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
import android.testing.TestableContext;
import androidx.test.InstrumentationRegistry;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
/**
* Tests for {@link WindowMagnificationPromptController}.
*/
public class WindowMagnificationPromptControllerTest {
private static final int TEST_USER = 0;
@Mock
private NotificationManager mNotificationManager;
@Mock
private StatusBarManager mStatusBarManager;
@Rule
public A11yTestableContext mTestableContext = new A11yTestableContext(
InstrumentationRegistry.getContext());
private ContentResolver mResolver = mTestableContext.getContentResolver();
private WindowMagnificationPromptController mWindowMagnificationPromptController;
private BroadcastReceiver mReceiver;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mTestableContext.addMockSystemService(NotificationManager.class, mNotificationManager);
mTestableContext.addMockSystemService(StatusBarManager.class, mStatusBarManager);
setWindowMagnificationPromptSettings(true);
mWindowMagnificationPromptController = new WindowMagnificationPromptController(
mTestableContext, TEST_USER);
}
@After
public void tearDown() throws Exception {
mWindowMagnificationPromptController.onDestroy();
}
@Test
public void showNotificationIfNeeded_promptSettingsIsOn_showNotification() {
mWindowMagnificationPromptController.showNotificationIfNeeded();
verify(mNotificationManager).notify(eq(NOTE_A11Y_WINDOW_MAGNIFICATION_FEATURE), any(
Notification.class));
}
@Test
public void tapTurnOnAction_isShown_cancelNotificationAndLaunchMagnificationSettings() {
showNotificationAndAssert();
final Intent intent = new Intent(ACTION_TURN_ON_IN_SETTINGS);
mReceiver.onReceive(mTestableContext, intent);
verify(mNotificationManager).cancel(NOTE_A11Y_WINDOW_MAGNIFICATION_FEATURE);
verifyLaunchMagnificationSettings();
}
@Test
public void tapTurnOnAction_isShown_settingsValueIsFalseAndUnregisterReceiver() {
showNotificationAndAssert();
final Intent intent = new Intent(ACTION_TURN_ON_IN_SETTINGS);
mReceiver.onReceive(mTestableContext, intent);
assertThat(Settings.Secure.getInt(mResolver, ACCESSIBILITY_SHOW_WINDOW_MAGNIFICATION_PROMPT,
-1)).isEqualTo(0);
verify(mTestableContext.getSpyContext()).unregisterReceiver(mReceiver);
}
@Test
public void tapDismissAction_isShown_cancelNotificationAndUnregisterReceiver() {
showNotificationAndAssert();
final Intent intent = new Intent(WindowMagnificationPromptController.ACTION_DISMISS);
mReceiver.onReceive(mTestableContext, intent);
verify(mNotificationManager).cancel(NOTE_A11Y_WINDOW_MAGNIFICATION_FEATURE);
verify(mTestableContext.getSpyContext()).unregisterReceiver(mReceiver);
}
@Test
public void promptSettingsChangeToFalse_isShown_cancelNotificationAndUnregisterReceiver() {
showNotificationAndAssert();
setWindowMagnificationPromptSettings(false);
verify(mNotificationManager).cancel(NOTE_A11Y_WINDOW_MAGNIFICATION_FEATURE);
verify(mTestableContext.getSpyContext()).unregisterReceiver(mReceiver);
}
@Test
public void onDestroy_isShown_cancelNotificationAndUnregisterReceiver() {
showNotificationAndAssert();
mWindowMagnificationPromptController.onDestroy();
verify(mNotificationManager).cancel(NOTE_A11Y_WINDOW_MAGNIFICATION_FEATURE);
verify(mTestableContext.getSpyContext()).unregisterReceiver(mReceiver);
}
private void verifyLaunchMagnificationSettings() {
final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
final ArgumentCaptor<UserHandle> userHandleCaptor = ArgumentCaptor.forClass(
UserHandle.class);
verify(mTestableContext.getSpyContext()).startActivityAsUser(intentCaptor.capture(),
bundleCaptor.capture(), userHandleCaptor.capture());
assertThat(intentCaptor.getValue().getAction()).isEqualTo(
Settings.ACTION_ACCESSIBILITY_DETAILS_SETTINGS);
assertThat(userHandleCaptor.getValue().getIdentifier()).isEqualTo(TEST_USER);
verify(mStatusBarManager).collapsePanels();
}
private void showNotificationAndAssert() {
mWindowMagnificationPromptController.showNotificationIfNeeded();
mReceiver = mWindowMagnificationPromptController.mNotificationActionReceiver;
assertThat(mReceiver).isNotNull();
}
private void setWindowMagnificationPromptSettings(boolean enable) {
Settings.Secure.putIntForUser(mResolver, ACCESSIBILITY_SHOW_WINDOW_MAGNIFICATION_PROMPT,
enable ? 1 : 0, TEST_USER);
if (mWindowMagnificationPromptController != null) {
mWindowMagnificationPromptController.onPromptSettingsValueChanged();
}
}
private class A11yTestableContext extends TestableContext {
private Context mSpyContext;
A11yTestableContext(Context base) {
super(base);
mSpyContext = Mockito.mock(Context.class);
}
@Override
public void startActivityAsUser(Intent intent, Bundle options, UserHandle user) {
mSpyContext.startActivityAsUser(intent, options, user);
}
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler) {
return mSpyContext.registerReceiver(receiver, filter, broadcastPermission, scheduler);
}
@Override
public void unregisterReceiver(BroadcastReceiver receiver) {
mSpyContext.unregisterReceiver(receiver);
}
Context getSpyContext() {
return mSpyContext;
}
}
}