package foo.bar.testback; import android.accessibilityservice.AccessibilityService; import android.accessibilityservice.AccessibilityServiceInfo; import android.content.Context; import android.util.ArraySet; import android.util.Log; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityWindowInfo; import android.widget.Button; import java.util.List; import java.util.Set; public class TestBackService extends AccessibilityService { private static final String LOG_TAG = TestBackService.class.getSimpleName(); private Button mButton; @Override public void onCreate() { super.onCreate(); mButton = new Button(this); mButton.setText("Button 1"); } @Override public void onAccessibilityEvent(AccessibilityEvent event) { // if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { // Log.i(LOG_TAG, event.getText().toString()); // //dumpWindows(); // } if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_HOVER_ENTER) { // Log.i(LOG_TAG, "Click event.isChecked()=" + event.isChecked() // + ((event.getSource() != null) ? " node.isChecked()=" // + event.getSource().isChecked() : " node=null")); AccessibilityNodeInfo source = event.getSource(); dumpWindow(source); // AccessibilityNodeInfo node = event.getSource(); // if (node != null) { // node.refresh(); // Log.i(LOG_TAG, "Clicked: " + node.getClassName() + " clicked:" + node.isChecked()); // } } } @Override protected boolean onGesture(int gestureId) { switch (gestureId) { case AccessibilityService.GESTURE_SWIPE_DOWN: { showAccessibilityOverlay(); } break; case AccessibilityService.GESTURE_SWIPE_UP: { hideAccessibilityOverlay(); } break; } return super.onGesture(gestureId); } private void showAccessibilityOverlay() { WindowManager.LayoutParams params = new WindowManager.LayoutParams(); params.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; params.type = WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY; WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); windowManager.addView(mButton, params); } private void hideAccessibilityOverlay() { WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); windowManager.removeView(mButton); } private void dumpWindows() { List windows = getWindows(); final int windowCount = windows.size(); for (int i = 0; i < windowCount; i++) { AccessibilityWindowInfo window = windows.get(i); Log.i(LOG_TAG, "============================="); Log.i(LOG_TAG, window.toString()); } } private void dumpWindow(AccessibilityNodeInfo source) { AccessibilityNodeInfo root = source; while (true) { AccessibilityNodeInfo parent = root.getParent(); if (parent == null) { break; } else if (parent.equals(root)) { Log.i(LOG_TAG, "Node is own parent:" + root); } root = parent; } dumpTree(root, new ArraySet()); } private void dumpTree(AccessibilityNodeInfo root, Set visited) { if (root == null) { return; } if (!visited.add(root)) { Log.i(LOG_TAG, "Cycle detected to node:" + root); } final int childCount = root.getChildCount(); for (int i = 0; i < childCount; i++) { AccessibilityNodeInfo child = root.getChild(i); if (child != null) { AccessibilityNodeInfo parent = child.getParent(); if (parent == null) { Log.e(LOG_TAG, "Child of a node has no parent"); } else if (!parent.equals(root)) { Log.e(LOG_TAG, "Child of a node has wrong parent"); } Log.i(LOG_TAG, child.toString()); } } for (int i = 0; i < childCount; i++) { AccessibilityNodeInfo child = root.getChild(i); dumpTree(child, visited); } } @Override public void onInterrupt() { /* ignore */ } @Override public void onServiceConnected() { AccessibilityServiceInfo info = getServiceInfo(); info.flags |= AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS; info.flags |= AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE; info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS; setServiceInfo(info); } }