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 17 package android.view; 18 19 import android.os.Looper; 20 import android.os.MessageQueue; 21 import android.util.Log; 22 23 import dalvik.annotation.optimization.FastNative; 24 import dalvik.system.CloseGuard; 25 26 import java.lang.ref.WeakReference; 27 28 /** 29 * Provides a low-level mechanism for an application to receive display events 30 * such as vertical sync. 31 * 32 * The display event receive is NOT thread safe. Moreover, its methods must only 33 * be called on the Looper thread to which it is attached. 34 * 35 * @hide 36 */ 37 public abstract class DisplayEventReceiver { 38 39 /** 40 * When retrieving vsync events, this specifies that the vsync event should happen at the normal 41 * vsync-app tick. 42 * <p> 43 * Needs to be kept in sync with frameworks/native/include/gui/ISurfaceComposer.h 44 */ 45 public static final int VSYNC_SOURCE_APP = 0; 46 47 /** 48 * When retrieving vsync events, this specifies that the vsync event should happen whenever 49 * Surface Flinger is processing a frame. 50 * <p> 51 * Needs to be kept in sync with frameworks/native/include/gui/ISurfaceComposer.h 52 */ 53 public static final int VSYNC_SOURCE_SURFACE_FLINGER = 1; 54 55 private static final String TAG = "DisplayEventReceiver"; 56 57 private final CloseGuard mCloseGuard = CloseGuard.get(); 58 59 private long mReceiverPtr; 60 61 // We keep a reference message queue object here so that it is not 62 // GC'd while the native peer of the receiver is using them. 63 private MessageQueue mMessageQueue; 64 nativeInit(WeakReference<DisplayEventReceiver> receiver, MessageQueue messageQueue, int vsyncSource)65 private static native long nativeInit(WeakReference<DisplayEventReceiver> receiver, 66 MessageQueue messageQueue, int vsyncSource); nativeDispose(long receiverPtr)67 private static native void nativeDispose(long receiverPtr); 68 @FastNative nativeScheduleVsync(long receiverPtr)69 private static native void nativeScheduleVsync(long receiverPtr); 70 71 /** 72 * Creates a display event receiver. 73 * 74 * @param looper The looper to use when invoking callbacks. 75 */ DisplayEventReceiver(Looper looper)76 public DisplayEventReceiver(Looper looper) { 77 this(looper, VSYNC_SOURCE_APP); 78 } 79 80 /** 81 * Creates a display event receiver. 82 * 83 * @param looper The looper to use when invoking callbacks. 84 * @param vsyncSource The source of the vsync tick. Must be on of the VSYNC_SOURCE_* values. 85 */ DisplayEventReceiver(Looper looper, int vsyncSource)86 public DisplayEventReceiver(Looper looper, int vsyncSource) { 87 if (looper == null) { 88 throw new IllegalArgumentException("looper must not be null"); 89 } 90 91 mMessageQueue = looper.getQueue(); 92 mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue, 93 vsyncSource); 94 95 mCloseGuard.open("dispose"); 96 } 97 98 @Override finalize()99 protected void finalize() throws Throwable { 100 try { 101 dispose(true); 102 } finally { 103 super.finalize(); 104 } 105 } 106 107 /** 108 * Disposes the receiver. 109 */ dispose()110 public void dispose() { 111 dispose(false); 112 } 113 dispose(boolean finalized)114 private void dispose(boolean finalized) { 115 if (mCloseGuard != null) { 116 if (finalized) { 117 mCloseGuard.warnIfOpen(); 118 } 119 mCloseGuard.close(); 120 } 121 122 if (mReceiverPtr != 0) { 123 nativeDispose(mReceiverPtr); 124 mReceiverPtr = 0; 125 } 126 mMessageQueue = null; 127 } 128 129 /** 130 * Called when a vertical sync pulse is received. 131 * The recipient should render a frame and then call {@link #scheduleVsync} 132 * to schedule the next vertical sync pulse. 133 * 134 * @param timestampNanos The timestamp of the pulse, in the {@link System#nanoTime()} 135 * timebase. 136 * @param builtInDisplayId The surface flinger built-in display id such as 137 * {@link SurfaceControl#BUILT_IN_DISPLAY_ID_MAIN}. 138 * @param frame The frame number. Increases by one for each vertical sync interval. 139 */ onVsync(long timestampNanos, int builtInDisplayId, int frame)140 public void onVsync(long timestampNanos, int builtInDisplayId, int frame) { 141 } 142 143 /** 144 * Called when a display hotplug event is received. 145 * 146 * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()} 147 * timebase. 148 * @param builtInDisplayId The surface flinger built-in display id such as 149 * {@link SurfaceControl#BUILT_IN_DISPLAY_ID_HDMI}. 150 * @param connected True if the display is connected, false if it disconnected. 151 */ onHotplug(long timestampNanos, int builtInDisplayId, boolean connected)152 public void onHotplug(long timestampNanos, int builtInDisplayId, boolean connected) { 153 } 154 155 /** 156 * Schedules a single vertical sync pulse to be delivered when the next 157 * display frame begins. 158 */ scheduleVsync()159 public void scheduleVsync() { 160 if (mReceiverPtr == 0) { 161 Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event " 162 + "receiver has already been disposed."); 163 } else { 164 nativeScheduleVsync(mReceiverPtr); 165 } 166 } 167 168 // Called from native code. 169 @SuppressWarnings("unused") dispatchVsync(long timestampNanos, int builtInDisplayId, int frame)170 private void dispatchVsync(long timestampNanos, int builtInDisplayId, int frame) { 171 onVsync(timestampNanos, builtInDisplayId, frame); 172 } 173 174 // Called from native code. 175 @SuppressWarnings("unused") dispatchHotplug(long timestampNanos, int builtInDisplayId, boolean connected)176 private void dispatchHotplug(long timestampNanos, int builtInDisplayId, boolean connected) { 177 onHotplug(timestampNanos, builtInDisplayId, connected); 178 } 179 } 180