Home | History | Annotate | Download | only in view
      1 /*
      2  * Copyright (C) 2013 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.view;
     18 
     19 import dalvik.system.CloseGuard;
     20 
     21 import android.os.Looper;
     22 import android.os.MessageQueue;
     23 import android.util.Log;
     24 
     25 import java.lang.ref.WeakReference;
     26 
     27 /**
     28  * Provides a low-level mechanism for an application to send input events.
     29  * @hide
     30  */
     31 public abstract class InputEventSender {
     32     private static final String TAG = "InputEventSender";
     33 
     34     private final CloseGuard mCloseGuard = CloseGuard.get();
     35 
     36     private long mSenderPtr;
     37 
     38     // We keep references to the input channel and message queue objects here so that
     39     // they are not GC'd while the native peer of the receiver is using them.
     40     private InputChannel mInputChannel;
     41     private MessageQueue mMessageQueue;
     42 
     43     private static native long nativeInit(WeakReference<InputEventSender> sender,
     44             InputChannel inputChannel, MessageQueue messageQueue);
     45     private static native void nativeDispose(long senderPtr);
     46     private static native boolean nativeSendKeyEvent(long senderPtr, int seq, KeyEvent event);
     47     private static native boolean nativeSendMotionEvent(long senderPtr, int seq, MotionEvent event);
     48 
     49     /**
     50      * Creates an input event sender bound to the specified input channel.
     51      *
     52      * @param inputChannel The input channel.
     53      * @param looper The looper to use when invoking callbacks.
     54      */
     55     public InputEventSender(InputChannel inputChannel, Looper looper) {
     56         if (inputChannel == null) {
     57             throw new IllegalArgumentException("inputChannel must not be null");
     58         }
     59         if (looper == null) {
     60             throw new IllegalArgumentException("looper must not be null");
     61         }
     62 
     63         mInputChannel = inputChannel;
     64         mMessageQueue = looper.getQueue();
     65         mSenderPtr = nativeInit(new WeakReference<InputEventSender>(this),
     66                 inputChannel, mMessageQueue);
     67 
     68         mCloseGuard.open("dispose");
     69     }
     70 
     71     @Override
     72     protected void finalize() throws Throwable {
     73         try {
     74             dispose(true);
     75         } finally {
     76             super.finalize();
     77         }
     78     }
     79 
     80     /**
     81      * Disposes the receiver.
     82      */
     83     public void dispose() {
     84         dispose(false);
     85     }
     86 
     87     private void dispose(boolean finalized) {
     88         if (mCloseGuard != null) {
     89             if (finalized) {
     90                 mCloseGuard.warnIfOpen();
     91             }
     92             mCloseGuard.close();
     93         }
     94 
     95         if (mSenderPtr != 0) {
     96             nativeDispose(mSenderPtr);
     97             mSenderPtr = 0;
     98         }
     99         mInputChannel = null;
    100         mMessageQueue = null;
    101     }
    102 
    103     /**
    104      * Called when an input event is finished.
    105      *
    106      * @param seq The input event sequence number.
    107      * @param handled True if the input event was handled.
    108      */
    109     public void onInputEventFinished(int seq, boolean handled) {
    110     }
    111 
    112     /**
    113      * Sends an input event.
    114      * Must be called on the same Looper thread to which the sender is attached.
    115      *
    116      * @param seq The input event sequence number.
    117      * @param event The input event to send.
    118      * @return True if the entire event was sent successfully.  May return false
    119      * if the input channel buffer filled before all samples were dispatched.
    120      */
    121     public final boolean sendInputEvent(int seq, InputEvent event) {
    122         if (event == null) {
    123             throw new IllegalArgumentException("event must not be null");
    124         }
    125         if (mSenderPtr == 0) {
    126             Log.w(TAG, "Attempted to send an input event but the input event "
    127                     + "sender has already been disposed.");
    128             return false;
    129         }
    130 
    131         if (event instanceof KeyEvent) {
    132             return nativeSendKeyEvent(mSenderPtr, seq, (KeyEvent)event);
    133         } else {
    134             return nativeSendMotionEvent(mSenderPtr, seq, (MotionEvent)event);
    135         }
    136     }
    137 
    138     // Called from native code.
    139     @SuppressWarnings("unused")
    140     private void dispatchInputEventFinished(int seq, boolean handled) {
    141         onInputEventFinished(seq, handled);
    142     }
    143 }
    144