Add haptic feedback for a11y shortcut

Bug: 35036259
Test: Activated shortcut, felt the vibration. Also added unit test.
Change-Id: I3070620d9152ce9b9bb084ee4f01d26020f125d0
This commit is contained in:
Phil Weaver
2017-03-13 11:32:01 -07:00
parent 7219795ffb
commit 32ea37255d
2 changed files with 46 additions and 1 deletions

View File

@@ -29,6 +29,7 @@ import android.media.Ringtone;
import android.media.RingtoneManager;
import android.os.Handler;
import android.os.UserHandle;
import android.os.Vibrator;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Slog;
@@ -48,6 +49,11 @@ import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
*/
public class AccessibilityShortcutController {
private static final String TAG = "AccessibilityShortcutController";
private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY)
.build();
private final Context mContext;
private AlertDialog mAlertDialog;
@@ -100,6 +106,8 @@ public class AccessibilityShortcutController {
final int userId = ActivityManager.getCurrentUser();
final int dialogAlreadyShown = Settings.Secure.getIntForUser(
cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0, userId);
// Play a notification tone
final Ringtone tone =
RingtoneManager.getRingtone(mContext, Settings.System.DEFAULT_NOTIFICATION_URI);
if (tone != null) {
@@ -108,6 +116,18 @@ public class AccessibilityShortcutController {
.build());
tone.play();
}
// Play a notification vibration
Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
if ((vibrator != null) && vibrator.hasVibrator()) {
// Don't check if haptics are disabled, as we need to alert the user that their
// way of interacting with the phone may change if they activate the shortcut
long[] vibePattern = PhoneWindowManager.getLongIntArray(mContext.getResources(),
R.array.config_safeModeDisabledVibePattern);
vibrator.vibrate(vibePattern, -1, VIBRATION_ATTRIBUTES);
}
if (dialogAlreadyShown == 0) {
// The first time, we show a warning rather than toggle the service to give the user a
// chance to turn off this feature before stuff gets enabled.

View File

@@ -21,9 +21,11 @@ import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.os.Handler;
import android.os.Vibrator;
import android.provider.Settings;
import android.support.test.runner.AndroidJUnit4;
@@ -54,6 +56,7 @@ import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SER
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.mockito.AdditionalMatchers.aryEq;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyObject;
@@ -67,6 +70,11 @@ import static org.mockito.Mockito.when;
@RunWith(AndroidJUnit4.class)
public class AccessibilityShortcutControllerTest {
private static final String SERVICE_NAME_STRING = "fake.package/fake.service.name";
private static final long VIBRATOR_PATTERN_1 = 100L;
private static final long VIBRATOR_PATTERN_2 = 150L;
private static final int[] VIBRATOR_PATTERN_INT = {(int) VIBRATOR_PATTERN_1,
(int) VIBRATOR_PATTERN_2};
private static final long[] VIBRATOR_PATTERN_LONG = {VIBRATOR_PATTERN_1, VIBRATOR_PATTERN_2};
private @Mock Context mContext;
private @Mock FrameworkObjectProvider mFrameworkObjectProvider;
@@ -77,6 +85,8 @@ public class AccessibilityShortcutControllerTest {
private @Mock AccessibilityServiceInfo mServiceInfo;
private @Mock Resources mResources;
private @Mock Toast mToast;
private @Mock Vibrator mVibrator;
private @Mock ApplicationInfo mApplicationInfo;
private MockContentResolver mContentResolver;
private WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams();
@@ -85,10 +95,15 @@ public class AccessibilityShortcutControllerTest {
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mVibrator.hasVibrator()).thenReturn(true);
when(mContext.getResources()).thenReturn(mResources);
when(mContext.getApplicationInfo()).thenReturn(mApplicationInfo);
when(mContext.getSystemService(Context.VIBRATOR_SERVICE)).thenReturn(mVibrator);
mContentResolver = new MockContentResolver(mContext);
mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
when(mContext.getContentResolver()).thenReturn(mContentResolver);
when(mContext.getResources()).thenReturn(mResources);
when(mAccessibilityManagerService.getInstalledAccessibilityServiceList(anyInt()))
.thenReturn(Collections.singletonList(mServiceInfo));
@@ -104,6 +119,8 @@ public class AccessibilityShortcutControllerTest {
.thenReturn(mToast);
when(mResources.getString(anyInt())).thenReturn("Howdy %s");
when(mResources.getIntArray(anyInt())).thenReturn(VIBRATOR_PATTERN_INT);
ResolveInfo resolveInfo = mock(ResolveInfo.class);
when(resolveInfo.loadLabel(anyObject())).thenReturn("Service name");
when(mServiceInfo.getResolveInfo()).thenReturn(resolveInfo);
@@ -162,6 +179,14 @@ public class AccessibilityShortcutControllerTest {
assertTrue(accessibilityShortcutController.isAccessibilityShortcutAvailable());
}
@Test
public void testOnAccessibilityShortcut_vibrates() {
configureShortcutEnabled();
AccessibilityShortcutController accessibilityShortcutController = getController();
accessibilityShortcutController.performAccessibilityShortcut();
verify(mVibrator).vibrate(aryEq(VIBRATOR_PATTERN_LONG), eq(-1), anyObject());
}
@Test
public void testOnAccessibilityShortcut_firstTime_showsWarningDialog()
throws Exception {