1 package org.robolectric.shadows; 2 3 import static android.os.Build.VERSION_CODES.KITKAT; 4 import static org.robolectric.RuntimeEnvironment.getApiLevel; 5 6 import android.accessibilityservice.AccessibilityServiceInfo; 7 import android.content.Context; 8 import android.content.pm.ServiceInfo; 9 import android.os.Handler; 10 import android.os.Looper; 11 import android.os.Message; 12 import android.util.Log; 13 import android.view.accessibility.AccessibilityManager; 14 import android.view.accessibility.IAccessibilityManager; 15 import java.util.List; 16 import org.robolectric.annotation.HiddenApi; 17 import org.robolectric.annotation.Implementation; 18 import org.robolectric.annotation.Implements; 19 import org.robolectric.annotation.RealObject; 20 import org.robolectric.annotation.Resetter; 21 import org.robolectric.shadow.api.Shadow; 22 import org.robolectric.util.ReflectionHelpers; 23 import org.robolectric.util.ReflectionHelpers.ClassParameter; 24 25 @Implements(AccessibilityManager.class) 26 public class ShadowAccessibilityManager { 27 private static AccessibilityManager sInstance; 28 private static final Object sInstanceSync = new Object(); 29 30 @RealObject AccessibilityManager realAccessibilityManager; 31 private boolean enabled; 32 private List<AccessibilityServiceInfo> installedAccessibilityServiceList; 33 private List<AccessibilityServiceInfo> enabledAccessibilityServiceList; 34 private List<ServiceInfo> accessibilityServiceList; 35 private boolean touchExplorationEnabled; 36 37 @Resetter 38 public static void reset() { 39 synchronized (sInstanceSync) { 40 sInstance = null; 41 } 42 } 43 44 @HiddenApi 45 @Implementation 46 public static AccessibilityManager getInstance(Context context) throws Exception { 47 synchronized (sInstanceSync) { 48 if (sInstance == null) { 49 sInstance = createInstance(context); 50 } 51 } 52 return sInstance; 53 } 54 55 private static AccessibilityManager createInstance(Context context) throws Exception { 56 if (getApiLevel() >= KITKAT) { 57 AccessibilityManager accessibilityManager = Shadow.newInstance(AccessibilityManager.class, 58 new Class[]{Context.class, IAccessibilityManager.class, int.class}, 59 new Object[]{context, ReflectionHelpers.createNullProxy(IAccessibilityManager.class), 0}); 60 ReflectionHelpers.setField(accessibilityManager, "mHandler", new MyHandler(context.getMainLooper(), accessibilityManager)); 61 return accessibilityManager; 62 } else { 63 AccessibilityManager accessibilityManager = Shadow.newInstance(AccessibilityManager.class, new Class[0], new Object[0]); 64 ReflectionHelpers.setField(accessibilityManager, "mHandler", new MyHandler(context.getMainLooper(), accessibilityManager)); 65 return accessibilityManager; 66 } 67 } 68 69 @Implementation 70 public boolean addAccessibilityStateChangeListener(AccessibilityManager.AccessibilityStateChangeListener listener) { 71 return true; 72 } 73 74 @Implementation 75 public boolean removeAccessibilityStateChangeListener(AccessibilityManager.AccessibilityStateChangeListener listener) { 76 return true; 77 } 78 79 @Implementation 80 public List<ServiceInfo> getAccessibilityServiceList () { 81 return accessibilityServiceList; 82 } 83 84 public void setAccessibilityServiceList(List<ServiceInfo> accessibilityServiceList) { 85 this.accessibilityServiceList = accessibilityServiceList; 86 } 87 88 @Implementation 89 public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList (int feedbackTypeFlags) { 90 return enabledAccessibilityServiceList; 91 } 92 93 public void setEnabledAccessibilityServiceList(List<AccessibilityServiceInfo> enabledAccessibilityServiceList) { 94 this.enabledAccessibilityServiceList = enabledAccessibilityServiceList; 95 } 96 97 @Implementation 98 public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList () { 99 return installedAccessibilityServiceList; 100 } 101 102 public void setInstalledAccessibilityServiceList(List<AccessibilityServiceInfo> installedAccessibilityServiceList) { 103 this.installedAccessibilityServiceList = installedAccessibilityServiceList; 104 } 105 106 @Implementation 107 public boolean isEnabled () { 108 return enabled; 109 } 110 111 public void setEnabled(boolean enabled) { 112 this.enabled = enabled; 113 ReflectionHelpers.setField(realAccessibilityManager, "mIsEnabled", enabled); 114 } 115 116 @Implementation 117 public boolean isTouchExplorationEnabled () { 118 return touchExplorationEnabled; 119 } 120 121 public void setTouchExplorationEnabled(boolean touchExplorationEnabled) { 122 this.touchExplorationEnabled = touchExplorationEnabled; 123 } 124 125 static class MyHandler extends Handler { 126 private static final int DO_SET_STATE = 10; 127 private final AccessibilityManager accessibilityManager; 128 129 MyHandler(Looper mainLooper, AccessibilityManager accessibilityManager) { 130 super(mainLooper); 131 this.accessibilityManager = accessibilityManager; 132 } 133 134 @Override 135 public void handleMessage(Message message) { 136 switch (message.what) { 137 case DO_SET_STATE: 138 ReflectionHelpers.callInstanceMethod(accessibilityManager, "setState", ClassParameter.from(int.class, message.arg1)); 139 return; 140 default: 141 Log.w("AccessibilityManager", "Unknown message type: " + message.what); 142 } 143 } 144 } 145 } 146