1/* 2 * Copyright (C) 2011 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 17package android.view; 18 19import dalvik.system.CloseGuard; 20 21import android.os.Looper; 22import android.os.MessageQueue; 23import android.util.Log; 24 25/** 26 * Provides a low-level mechanism for an application to receive display events 27 * such as vertical sync. 28 * 29 * The display event receive is NOT thread safe. Moreover, its methods must only 30 * be called on the Looper thread to which it is attached. 31 * 32 * @hide 33 */ 34public abstract class DisplayEventReceiver { 35 private static final String TAG = "DisplayEventReceiver"; 36 37 private final CloseGuard mCloseGuard = CloseGuard.get(); 38 39 private int mReceiverPtr; 40 41 // We keep a reference message queue object here so that it is not 42 // GC'd while the native peer of the receiver is using them. 43 private MessageQueue mMessageQueue; 44 45 private static native int nativeInit(DisplayEventReceiver receiver, 46 MessageQueue messageQueue); 47 private static native void nativeDispose(int receiverPtr); 48 private static native void nativeScheduleVsync(int receiverPtr); 49 50 /** 51 * Creates a display event receiver. 52 * 53 * @param looper The looper to use when invoking callbacks. 54 */ 55 public DisplayEventReceiver(Looper looper) { 56 if (looper == null) { 57 throw new IllegalArgumentException("looper must not be null"); 58 } 59 60 mMessageQueue = looper.getQueue(); 61 mReceiverPtr = nativeInit(this, mMessageQueue); 62 63 mCloseGuard.open("dispose"); 64 } 65 66 @Override 67 protected void finalize() throws Throwable { 68 try { 69 dispose(); 70 } finally { 71 super.finalize(); 72 } 73 } 74 75 /** 76 * Disposes the receiver. 77 */ 78 public void dispose() { 79 if (mCloseGuard != null) { 80 mCloseGuard.close(); 81 } 82 if (mReceiverPtr != 0) { 83 nativeDispose(mReceiverPtr); 84 mReceiverPtr = 0; 85 } 86 mMessageQueue = null; 87 } 88 89 /** 90 * Called when a vertical sync pulse is received. 91 * The recipient should render a frame and then call {@link #scheduleVsync} 92 * to schedule the next vertical sync pulse. 93 * 94 * @param timestampNanos The timestamp of the pulse, in the {@link System#nanoTime()} 95 * timebase. 96 * @param frame The frame number. Increases by one for each vertical sync interval. 97 */ 98 public void onVsync(long timestampNanos, int frame) { 99 } 100 101 /** 102 * Schedules a single vertical sync pulse to be delivered when the next 103 * display frame begins. 104 */ 105 public void scheduleVsync() { 106 if (mReceiverPtr == 0) { 107 Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event " 108 + "receiver has already been disposed."); 109 } else { 110 nativeScheduleVsync(mReceiverPtr); 111 } 112 } 113 114 // Called from native code. 115 @SuppressWarnings("unused") 116 private void dispatchVsync(long timestampNanos, int frame) { 117 onVsync(timestampNanos, frame); 118 } 119} 120