Home | History | Annotate | Download | only in testback
      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
     24     public void onCreate() {
     25         super.onCreate();
     26         mButton = new Button(this);
     27         mButton.setText("Button 1");
     28     }
     29 
     30     @Override
     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
     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 
     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 
     76     private void hideAccessibilityOverlay() {
     77         WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
     78         windowManager.removeView(mButton);
     79     }
     80 
     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 
     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 
    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
    136     public void onInterrupt() {
    137         /* ignore */
    138     }
    139 
    140     @Override
    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