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