1 package foo.bar.testback; 2 3 import android.accessibilityservice.AccessibilityService; 4 import android.accessibilityservice.AccessibilityServiceInfo; 5 import android.content.Context; 6 import android.util.ArraySet; 7 import android.util.Log; 8 import android.view.WindowManager; 9 import android.view.accessibility.AccessibilityEvent; 10 import android.view.accessibility.AccessibilityNodeInfo; 11 import android.view.accessibility.AccessibilityWindowInfo; 12 import android.widget.Button; 13 14 import java.util.List; 15 import java.util.Set; 16 17 public class TestBackService extends AccessibilityService { 18 19 private static final String LOG_TAG = TestBackService.class.getSimpleName(); 20 21 private Button mButton; 22 23 @Override onCreate()24 public void onCreate() { 25 super.onCreate(); 26 mButton = new Button(this); 27 mButton.setText("Button 1"); 28 } 29 30 @Override onAccessibilityEvent(AccessibilityEvent event)31 public void onAccessibilityEvent(AccessibilityEvent event) { 32 // if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { 33 // Log.i(LOG_TAG, event.getText().toString()); 34 // //dumpWindows(); 35 // } 36 if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_HOVER_ENTER) { 37 // Log.i(LOG_TAG, "Click event.isChecked()=" + event.isChecked() 38 // + ((event.getSource() != null) ? " node.isChecked()=" 39 // + event.getSource().isChecked() : " node=null")); 40 41 AccessibilityNodeInfo source = event.getSource(); 42 dumpWindow(source); 43 // AccessibilityNodeInfo node = event.getSource(); 44 // if (node != null) { 45 // node.refresh(); 46 // Log.i(LOG_TAG, "Clicked: " + node.getClassName() + " clicked:" + node.isChecked()); 47 // } 48 } 49 } 50 51 @Override onGesture(int gestureId)52 protected boolean onGesture(int gestureId) { 53 switch (gestureId) { 54 case AccessibilityService.GESTURE_SWIPE_DOWN: { 55 showAccessibilityOverlay(); 56 } break; 57 case AccessibilityService.GESTURE_SWIPE_UP: { 58 hideAccessibilityOverlay(); 59 } break; 60 } 61 return super.onGesture(gestureId); 62 } 63 showAccessibilityOverlay()64 private void showAccessibilityOverlay() { 65 WindowManager.LayoutParams params = new WindowManager.LayoutParams(); 66 params.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 67 | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR 68 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 69 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; 70 params.type = WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY; 71 72 WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); 73 windowManager.addView(mButton, params); 74 } 75 hideAccessibilityOverlay()76 private void hideAccessibilityOverlay() { 77 WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); 78 windowManager.removeView(mButton); 79 } 80 dumpWindows()81 private void dumpWindows() { 82 List<AccessibilityWindowInfo> windows = getWindows(); 83 final int windowCount = windows.size(); 84 for (int i = 0; i < windowCount; i++) { 85 AccessibilityWindowInfo window = windows.get(i); 86 Log.i(LOG_TAG, "============================="); 87 Log.i(LOG_TAG, window.toString()); 88 89 } 90 } 91 dumpWindow(AccessibilityNodeInfo source)92 private void dumpWindow(AccessibilityNodeInfo source) { 93 AccessibilityNodeInfo root = source; 94 while (true) { 95 AccessibilityNodeInfo parent = root.getParent(); 96 if (parent == null) { 97 break; 98 } else if (parent.equals(root)) { 99 Log.i(LOG_TAG, "Node is own parent:" + root); 100 } 101 root = parent; 102 } 103 dumpTree(root, new ArraySet<AccessibilityNodeInfo>()); 104 } 105 dumpTree(AccessibilityNodeInfo root, Set<AccessibilityNodeInfo> visited)106 private void dumpTree(AccessibilityNodeInfo root, Set<AccessibilityNodeInfo> visited) { 107 if (root == null) { 108 return; 109 } 110 111 if (!visited.add(root)) { 112 Log.i(LOG_TAG, "Cycle detected to node:" + root); 113 } 114 115 final int childCount = root.getChildCount(); 116 for (int i = 0; i < childCount; i++) { 117 AccessibilityNodeInfo child = root.getChild(i); 118 if (child != null) { 119 AccessibilityNodeInfo parent = child.getParent(); 120 if (parent == null) { 121 Log.e(LOG_TAG, "Child of a node has no parent"); 122 } else if (!parent.equals(root)) { 123 Log.e(LOG_TAG, "Child of a node has wrong parent"); 124 } 125 Log.i(LOG_TAG, child.toString()); 126 } 127 } 128 129 for (int i = 0; i < childCount; i++) { 130 AccessibilityNodeInfo child = root.getChild(i); 131 dumpTree(child, visited); 132 } 133 } 134 135 @Override onInterrupt()136 public void onInterrupt() { 137 /* ignore */ 138 } 139 140 @Override onServiceConnected()141 public void onServiceConnected() { 142 AccessibilityServiceInfo info = getServiceInfo(); 143 info.flags |= AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS; 144 info.flags |= AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE; 145 info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS; 146 setServiceInfo(info); 147 } 148 } 149