Home | History | Annotate | Download | only in remoteprovider
      1 /*
      2  * Copyright (C) 2016 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 com.android.media.tv.remoteprovider;
     18 
     19 import android.content.Context;
     20 import android.media.tv.ITvRemoteProvider;
     21 import android.media.tv.ITvRemoteServiceInput;
     22 import android.os.Handler;
     23 import android.os.IBinder;
     24 import android.os.Looper;
     25 import android.os.Message;
     26 import android.os.RemoteException;
     27 import android.util.Log;
     28 
     29 /**
     30  * Base class for emote providers implemented in unbundled service.
     31  * <p/>
     32  * This object is not thread safe.  It is only intended to be accessed on the
     33  * {@link Context#getMainLooper main looper thread} of an application.
     34  * </p><p>
     35  * IMPORTANT: This class is effectively a system API for unbundled emote service, and
     36  * must remain API stable. See README.txt in the root of this package for more information.
     37  * </p>
     38  */
     39 
     40 
     41 public abstract class TvRemoteProvider {
     42 
     43     /**
     44      * The {@link Intent} that must be declared as handled by the service.
     45      * The service must also require the {@link android.Manifest.permission#BIND_TV_REMOTE_SERVICE}
     46      * permission so that other applications cannot abuse it.
     47      */
     48     public static final String SERVICE_INTERFACE =
     49             "com.android.media.tv.remoteprovider.TvRemoteProvider";
     50 
     51     private static final String TAG = "TvRemoteProvider";
     52     private static final boolean DEBUG_KEYS = false;
     53     private static final int MSG_SET_SERVICE_INPUT = 1;
     54     private static final int MSG_SEND_INPUTBRIDGE_CONNECTED = 2;
     55     private final Context mContext;
     56     private final ProviderStub mStub;
     57     private final ProviderHandler mHandler;
     58     private ITvRemoteServiceInput mRemoteServiceInput;
     59 
     60     /**
     61      * Creates a provider for an unbundled emote controller
     62      * service allowing it to interface with the tv remote controller
     63      * system service.
     64      *
     65      * @param context The application context for the remote provider.
     66      */
     67     public TvRemoteProvider(Context context) {
     68         mContext = context.getApplicationContext();
     69         mStub = new ProviderStub();
     70         mHandler = new ProviderHandler(mContext.getMainLooper());
     71     }
     72 
     73     /**
     74      * Gets the context of the remote service provider.
     75      */
     76     public final Context getContext() {
     77         return mContext;
     78     }
     79 
     80 
     81     /**
     82      * Gets the Binder associated with the provider.
     83      * <p>
     84      * This is intended to be used for the onBind() method of a service that implements
     85      * a remote provider service.
     86      * </p>
     87      *
     88      * @return The IBinder instance associated with the provider.
     89      */
     90     public IBinder getBinder() {
     91         return mStub;
     92     }
     93 
     94     /**
     95      * Information about the InputBridge connected status.
     96      *
     97      * @param token Identifier for the connection. Null, if failed.
     98      */
     99     public void onInputBridgeConnected(IBinder token) {
    100     }
    101 
    102     /**
    103      * Set a sink for sending events to framework service.
    104      *
    105      * @param tvServiceInput sink defined in framework service
    106      */
    107     private void setRemoteServiceInputSink(ITvRemoteServiceInput tvServiceInput) {
    108         mRemoteServiceInput = tvServiceInput;
    109     }
    110 
    111     /**
    112      * openRemoteInputBridge : Open an input bridge for a particular device.
    113      * Clients should pass in a token that can be used to match this request with a token that
    114      * will be returned by {@link TvRemoteProvider#onInputBridgeConnected(IBinder token)}
    115      * <p>
    116      * The token should be used for subsequent calls.
    117      * </p>
    118      *
    119      * @param name        Device name
    120      * @param token       Identifier for this connection
    121      * @param width       Width of the device's virtual touchpad
    122      * @param height      Height of the device's virtual touchpad
    123      * @param maxPointers Maximum supported pointers
    124      * @throws RuntimeException
    125      */
    126     public void openRemoteInputBridge(IBinder token, String name, int width, int height,
    127                                       int maxPointers) throws RuntimeException {
    128         try {
    129             mRemoteServiceInput.openInputBridge(token, name, width, height, maxPointers);
    130         } catch (RemoteException re) {
    131             throw re.rethrowFromSystemServer();
    132         }
    133     }
    134 
    135     /**
    136      * closeInputBridge : Close input bridge for a device
    137      *
    138      * @param token identifier for this connection
    139      * @throws RuntimeException
    140      */
    141     public void closeInputBridge(IBinder token) throws RuntimeException {
    142         try {
    143             mRemoteServiceInput.closeInputBridge(token);
    144         } catch (RemoteException re) {
    145             throw re.rethrowFromSystemServer();
    146         }
    147     }
    148 
    149     /**
    150      * clearInputBridge : Clear out any existing key or pointer events in queue for this device by
    151      *                    dropping them on the floor and sending an UP to all keys and pointer
    152      *                    slots.
    153      *
    154      * @param token identifier for this connection
    155      * @throws RuntimeException
    156      */
    157     public void clearInputBridge(IBinder token) throws RuntimeException {
    158         if (DEBUG_KEYS) Log.d(TAG, "clearInputBridge() token " + token);
    159         try {
    160             mRemoteServiceInput.clearInputBridge(token);
    161         } catch (RemoteException re) {
    162             throw re.rethrowFromSystemServer();
    163         }
    164     }
    165 
    166     /**
    167      * sendTimestamp : Send a timestamp for a set of pointer events
    168      *
    169      * @param token     identifier for the device
    170      * @param timestamp Timestamp to be used in
    171      *                  {@link android.os.SystemClock#uptimeMillis} time base
    172      * @throws RuntimeException
    173      */
    174     public void sendTimestamp(IBinder token, long timestamp) throws RuntimeException {
    175         if (DEBUG_KEYS) Log.d(TAG, "sendTimestamp() token: " + token +
    176                 ", timestamp: " + timestamp);
    177         try {
    178             mRemoteServiceInput.sendTimestamp(token, timestamp);
    179         } catch (RemoteException re) {
    180             throw re.rethrowFromSystemServer();
    181         }
    182     }
    183 
    184     /**
    185      * sendKeyUp : Send key up event for a device
    186      *
    187      * @param token   identifier for this connection
    188      * @param keyCode Key code to be sent
    189      * @throws RuntimeException
    190      */
    191     public void sendKeyUp(IBinder token, int keyCode) throws RuntimeException {
    192         if (DEBUG_KEYS) Log.d(TAG, "sendKeyUp() token: " + token + ", keyCode: " + keyCode);
    193         try {
    194             mRemoteServiceInput.sendKeyUp(token, keyCode);
    195         } catch (RemoteException re) {
    196             throw re.rethrowFromSystemServer();
    197         }
    198     }
    199 
    200     /**
    201      * sendKeyDown : Send key down event for a device
    202      *
    203      * @param token   identifier for this connection
    204      * @param keyCode Key code to be sent
    205      * @throws RuntimeException
    206      */
    207     public void sendKeyDown(IBinder token, int keyCode) throws RuntimeException {
    208         if (DEBUG_KEYS) Log.d(TAG, "sendKeyDown() token: " + token +
    209                 ", keyCode: " + keyCode);
    210         try {
    211             mRemoteServiceInput.sendKeyDown(token, keyCode);
    212         } catch (RemoteException re) {
    213             throw re.rethrowFromSystemServer();
    214         }
    215     }
    216 
    217     /**
    218      * sendPointerUp : Send pointer up event for a device
    219      *
    220      * @param token     identifier for the device
    221      * @param pointerId Pointer id to be used. Value may be from 0
    222      *                  to {@link MotionEvent#getPointerCount()} -1
    223      * @throws RuntimeException
    224      */
    225     public void sendPointerUp(IBinder token, int pointerId) throws RuntimeException {
    226         if (DEBUG_KEYS) Log.d(TAG, "sendPointerUp() token: " + token +
    227                 ", pointerId: " + pointerId);
    228         try {
    229             mRemoteServiceInput.sendPointerUp(token, pointerId);
    230         } catch (RemoteException re) {
    231             throw re.rethrowFromSystemServer();
    232         }
    233     }
    234 
    235     /**
    236      * sendPointerDown : Send pointer down event for a device
    237      *
    238      * @param token     identifier for the device
    239      * @param pointerId Pointer id to be used. Value may be from 0
    240      *                  to {@link MotionEvent#getPointerCount()} -1
    241      * @param x         X co-ordinates in display pixels
    242      * @param y         Y co-ordinates in display pixels
    243      * @throws RuntimeException
    244      */
    245     public void sendPointerDown(IBinder token, int pointerId, int x, int y)
    246             throws RuntimeException {
    247         if (DEBUG_KEYS) Log.d(TAG, "sendPointerDown() token: " + token +
    248                 ", pointerId: " + pointerId);
    249         try {
    250             mRemoteServiceInput.sendPointerDown(token, pointerId, x, y);
    251         } catch (RemoteException re) {
    252             throw re.rethrowFromSystemServer();
    253         }
    254     }
    255 
    256     /**
    257      * sendPointerSync : Send pointer sync event for a device
    258      *
    259      * @param token identifier for the device
    260      * @throws RuntimeException
    261      */
    262     public void sendPointerSync(IBinder token) throws RuntimeException {
    263         if (DEBUG_KEYS) Log.d(TAG, "sendPointerSync() token: " + token);
    264         try {
    265             mRemoteServiceInput.sendPointerSync(token);
    266         } catch (RemoteException re) {
    267             throw re.rethrowFromSystemServer();
    268         }
    269     }
    270 
    271     private final class ProviderStub extends ITvRemoteProvider.Stub {
    272         @Override
    273         public void setRemoteServiceInputSink(ITvRemoteServiceInput tvServiceInput) {
    274             mHandler.obtainMessage(MSG_SET_SERVICE_INPUT, tvServiceInput).sendToTarget();
    275         }
    276 
    277         @Override
    278         public void onInputBridgeConnected(IBinder token) {
    279             mHandler.obtainMessage(MSG_SEND_INPUTBRIDGE_CONNECTED, 0, 0,
    280                     (IBinder) token).sendToTarget();
    281         }
    282     }
    283 
    284     private final class ProviderHandler extends Handler {
    285         public ProviderHandler(Looper looper) {
    286             super(looper, null, true);
    287         }
    288 
    289         @Override
    290         public void handleMessage(Message msg) {
    291             switch (msg.what) {
    292                 case MSG_SET_SERVICE_INPUT: {
    293                     setRemoteServiceInputSink((ITvRemoteServiceInput) msg.obj);
    294                     break;
    295                 }
    296                 case MSG_SEND_INPUTBRIDGE_CONNECTED: {
    297                     onInputBridgeConnected((IBinder) msg.obj);
    298                     break;
    299                 }
    300             }
    301         }
    302     }
    303 }
    304