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