Home | History | Annotate | Download | only in delegate
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.accessibilityservice.delegate;
     18 
     19 import android.accessibilityservice.AccessibilityService;
     20 import android.accessibilityservice.AccessibilityServiceInfo;
     21 import android.accessibilityservice.IAccessibilityServiceDelegate;
     22 import android.accessibilityservice.IAccessibilityServiceDelegateConnection;
     23 import android.app.Service;
     24 import android.content.Intent;
     25 import android.os.Bundle;
     26 import android.os.IBinder;
     27 import android.os.RemoteException;
     28 import android.util.Log;
     29 import android.view.accessibility.AccessibilityEvent;
     30 import android.view.accessibility.AccessibilityNodeInfo;
     31 
     32 import java.util.List;
     33 
     34 /**
     35  * This class is an accessibility service mock to which the system is bound and
     36  * exposes a mock interface to the CTS accessibility tests.
     37  * </p>
     38  * Note: The end-to-end test is composed of two APKs, one with a mock accessibility
     39  * service, another with the instrumented activity and test cases. The
     40  * motivation for two APKs design is that CTS tests cannot access the secure
     41  * settings which is required for enabling accessibility and accessibility
     42  * services. Therefore, manual installation of this package is required. Once
     43  * the package has been installed accessibility must be enabled (Settings ->
     44  * Accessibility), the mock service must be enabled (Settings -> Accessibility
     45  * -> Mock Accessibility Service), and then the CTS tests in this package
     46  * <strong>CtsAccessibilityServiceTestCases.apk</strong> located in
     47  * <strong>cts/tests/tests/accessibility</strong> can be successfully run.
     48  * Further, the mock and tests run in separate processes since the
     49  * instrumentation restarts the process in which it is running and this breaks
     50  * the binding between the mock accessibility service and the system.
     51  */
     52 public class DelegatingAccessibilityService extends AccessibilityService {
     53 
     54     /**
     55      * Tag used for logging.
     56      */
     57     private static final String LOG_TAG = "AccessibilityServiceDelegate";
     58 
     59     /**
     60      * Handle to the instance used by the accessibility service connection.
     61      */
     62     static DelegatingAccessibilityService sServiceDelegate;
     63 
     64     /**
     65      * Interface for delegating events and interrupt requests.
     66      */
     67     private IAccessibilityServiceDelegate mDelegateInterface;
     68 
     69     @Override
     70     protected void onServiceConnected() {
     71         // the service is ready to be used only
     72         // after the system has bound to it
     73         sServiceDelegate = this;
     74     }
     75 
     76     @Override
     77     public void onAccessibilityEvent(AccessibilityEvent event) {
     78         if (mDelegateInterface == null) {
     79             return;
     80         }
     81 
     82         try {
     83             mDelegateInterface.onAccessibilityEvent(event);
     84         } catch (RemoteException re) {
     85             Log.i(LOG_TAG, "Dead: " + mDelegateInterface.toString() + " cleaning up.");
     86             mDelegateInterface = null;
     87         }
     88     }
     89 
     90     @Override
     91     public void onInterrupt() {
     92         if (mDelegateInterface == null) {
     93             return;
     94         }
     95 
     96         try {
     97             mDelegateInterface.onInterrupt();
     98         } catch (RemoteException re) {
     99             Log.i(LOG_TAG, "Dead: " + mDelegateInterface.toString() + " cleaning up.");
    100             mDelegateInterface = null;
    101         }
    102     }
    103 
    104     /**
    105      * Sets the interface to which to delegate.
    106      *
    107      * @param delegateInterface The delegate interface.
    108      */
    109     private void setDelegateInterface(IAccessibilityServiceDelegate delegateInterface) {
    110         mDelegateInterface = delegateInterface;
    111     }
    112 
    113     /**
    114      * This is a service to which the end-to-end CTS test connects to pass a
    115      * delegate interface to which the {@link DelegatingAccessibilityService}
    116      * to delegate.
    117      */
    118     public static class DelegatingConnectionService extends Service {
    119 
    120         @Override
    121         public IBinder onBind(Intent intent) {
    122             if (sServiceDelegate == null) {
    123                 return null;
    124             }
    125             return new AccessibilityServiceDelegateConnection();
    126         }
    127 
    128         /**
    129          * This class is the connection wrapper passed to the end-to-end CTS
    130          * test, so the latter can pass a delegating interface.
    131          */
    132         private class AccessibilityServiceDelegateConnection extends
    133                 IAccessibilityServiceDelegateConnection.Stub {
    134 
    135             @Override
    136             public void setAccessibilityServiceDelegate(IBinder binder) {
    137                 sServiceDelegate.setDelegateInterface(IAccessibilityServiceDelegate.Stub
    138                         .asInterface(binder));
    139             }
    140 
    141             @Override
    142             public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(
    143                     AccessibilityNodeInfo root, String text) {
    144                 return root.findAccessibilityNodeInfosByText(text);
    145             }
    146 
    147             @Override
    148             public AccessibilityNodeInfo getChild(AccessibilityNodeInfo parent, int index) {
    149                 return parent.getChild(index);
    150             }
    151 
    152             @Override
    153             public AccessibilityNodeInfo getParent(AccessibilityNodeInfo child) {
    154                 return child.getParent();
    155             }
    156 
    157             @Override
    158             public AccessibilityNodeInfo findFocus(AccessibilityNodeInfo root, int focusType) {
    159                 return root.findFocus(focusType);
    160             }
    161 
    162             @Override
    163             public AccessibilityNodeInfo focusSearch(AccessibilityNodeInfo current, int direction) {
    164                 return current.focusSearch(direction);
    165             }
    166 
    167             @Override
    168             public AccessibilityNodeInfo getSource(AccessibilityEvent event) {
    169                 return event.getSource();
    170             }
    171 
    172             @Override
    173             public boolean performAccessibilityAction(AccessibilityNodeInfo target, int action,
    174                     Bundle arguments) {
    175                 return target.performAction(action, arguments);
    176             }
    177 
    178             @Override
    179             public void setFetchViewsNotExposedForAccessibility(boolean fetch) {
    180                 AccessibilityServiceInfo info = sServiceDelegate.getServiceInfo();
    181                 if (fetch) {
    182                     info.flags |= AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
    183                 } else {
    184                     info.flags &= ~AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
    185                 }
    186                 sServiceDelegate.setServiceInfo(info);
    187             }
    188 
    189             @Override
    190             public boolean performGlobalAction(int action) {
    191                 return sServiceDelegate.performGlobalAction(action);
    192             }
    193 
    194             @Override
    195             public AccessibilityNodeInfo getRootInActiveWindow() {
    196                 return sServiceDelegate.getRootInActiveWindow();
    197             }
    198         }
    199     }
    200 }
    201