blob: eaf297cc05d80fd785b7d35fea1a74a866e1d2de [file] [log] [blame]
Jeff Brown0a0a1242011-12-02 02:25:22 -08001/*
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
Artur Satayevad9254c2019-12-10 17:47:54 +000019import android.compat.annotation.UnsupportedAppUsage;
Jeff Brown0a0a1242011-12-02 02:25:22 -080020import android.os.Looper;
21import android.os.MessageQueue;
22import android.util.Log;
23
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070024import dalvik.annotation.optimization.FastNative;
25import dalvik.system.CloseGuard;
26
Jeff Brown3b4049e2015-04-17 15:22:27 -070027import java.lang.ref.WeakReference;
28
Jeff Brown0a0a1242011-12-02 02:25:22 -080029/**
30 * Provides a low-level mechanism for an application to receive display events
31 * such as vertical sync.
Jeff Brown58aedbc2012-02-13 20:15:01 -080032 *
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 *
Jeff Brown0a0a1242011-12-02 02:25:22 -080036 * @hide
37 */
38public abstract class DisplayEventReceiver {
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -070039
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
Ady Abraham9c501aa2019-06-04 16:07:44 -070056 /**
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
Jeff Brown0a0a1242011-12-02 02:25:22 -080070 private static final String TAG = "DisplayEventReceiver";
71
72 private final CloseGuard mCloseGuard = CloseGuard.get();
73
Mathew Inwooda570dee2018-08-17 14:56:00 +010074 @UnsupportedAppUsage
Ashok Bhat27285822013-12-18 18:00:05 +000075 private long mReceiverPtr;
Jeff Brown0a0a1242011-12-02 02:25:22 -080076
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
Jeff Brown3b4049e2015-04-17 15:22:27 -070081 private static native long nativeInit(WeakReference<DisplayEventReceiver> receiver,
Ady Abraham9c501aa2019-06-04 16:07:44 -070082 MessageQueue messageQueue, int vsyncSource, int configChanged);
Ashok Bhat27285822013-12-18 18:00:05 +000083 private static native void nativeDispose(long receiverPtr);
John Recke46af372016-10-03 16:21:30 -070084 @FastNative
Ashok Bhat27285822013-12-18 18:00:05 +000085 private static native void nativeScheduleVsync(long receiverPtr);
Jeff Brown0a0a1242011-12-02 02:25:22 -080086
87 /**
88 * Creates a display event receiver.
89 *
90 * @param looper The looper to use when invoking callbacks.
Wale Ogunwale71f30992017-06-19 13:53:32 -070091 */
Mathew Inwooda570dee2018-08-17 14:56:00 +010092 @UnsupportedAppUsage
Wale Ogunwale71f30992017-06-19 13:53:32 -070093 public DisplayEventReceiver(Looper looper) {
Ady Abraham9c501aa2019-06-04 16:07:44 -070094 this(looper, VSYNC_SOURCE_APP, CONFIG_CHANGED_EVENT_SUPPRESS);
Wale Ogunwale71f30992017-06-19 13:53:32 -070095 }
96
97 /**
98 * Creates a display event receiver.
99 *
100 * @param looper The looper to use when invoking callbacks.
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -0700101 * @param vsyncSource The source of the vsync tick. Must be on of the VSYNC_SOURCE_* values.
Ady Abraham9c501aa2019-06-04 16:07:44 -0700102 * @param configChanged Whether to dispatch config changed events. Must be one of the
103 * CONFIG_CHANGED_EVENT_* values.
Jeff Brown0a0a1242011-12-02 02:25:22 -0800104 */
Ady Abraham9c501aa2019-06-04 16:07:44 -0700105 public DisplayEventReceiver(Looper looper, int vsyncSource, int configChanged) {
Jeff Brown0a0a1242011-12-02 02:25:22 -0800106 if (looper == null) {
107 throw new IllegalArgumentException("looper must not be null");
108 }
109
110 mMessageQueue = looper.getQueue();
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -0700111 mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,
Ady Abraham9c501aa2019-06-04 16:07:44 -0700112 vsyncSource, configChanged);
Jeff Brown0a0a1242011-12-02 02:25:22 -0800113
114 mCloseGuard.open("dispose");
115 }
116
117 @Override
118 protected void finalize() throws Throwable {
119 try {
Jeff Brown3e7e7f02012-08-27 14:33:53 -0700120 dispose(true);
Jeff Brown0a0a1242011-12-02 02:25:22 -0800121 } finally {
122 super.finalize();
123 }
124 }
125
126 /**
127 * Disposes the receiver.
128 */
129 public void dispose() {
Jeff Brown3e7e7f02012-08-27 14:33:53 -0700130 dispose(false);
131 }
132
133 private void dispose(boolean finalized) {
Jeff Brown0a0a1242011-12-02 02:25:22 -0800134 if (mCloseGuard != null) {
Jeff Brown3e7e7f02012-08-27 14:33:53 -0700135 if (finalized) {
136 mCloseGuard.warnIfOpen();
137 }
Jeff Brown0a0a1242011-12-02 02:25:22 -0800138 mCloseGuard.close();
139 }
Jeff Brown3e7e7f02012-08-27 14:33:53 -0700140
Jeff Brown0a0a1242011-12-02 02:25:22 -0800141 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.
Dominik Laskowski3316a0a2019-01-25 02:56:41 -0800155 * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair.
Jeff Brown0a0a1242011-12-02 02:25:22 -0800156 * @param frame The frame number. Increases by one for each vertical sync interval.
157 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100158 @UnsupportedAppUsage
Dominik Laskowski3316a0a2019-01-25 02:56:41 -0800159 public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
Jeff Browne87bf032012-09-20 18:30:13 -0700160 }
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.
Dominik Laskowski3316a0a2019-01-25 02:56:41 -0800167 * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair.
Jeff Browne87bf032012-09-20 18:30:13 -0700168 * @param connected True if the display is connected, false if it disconnected.
169 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100170 @UnsupportedAppUsage
Dominik Laskowski3316a0a2019-01-25 02:56:41 -0800171 public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) {
Jeff Brown0a0a1242011-12-02 02:25:22 -0800172 }
173
174 /**
Ady Abrahama5a21f72019-02-13 16:41:59 -0800175 * 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 */
182 public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) {
183 }
184
185 /**
Jeff Brown0a0a1242011-12-02 02:25:22 -0800186 * Schedules a single vertical sync pulse to be delivered when the next
187 * display frame begins.
188 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100189 @UnsupportedAppUsage
Jeff Brown0a0a1242011-12-02 02:25:22 -0800190 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")
Mathew Inwooda570dee2018-08-17 14:56:00 +0100201 @UnsupportedAppUsage
Dominik Laskowski3316a0a2019-01-25 02:56:41 -0800202 private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame) {
203 onVsync(timestampNanos, physicalDisplayId, frame);
Jeff Browne87bf032012-09-20 18:30:13 -0700204 }
205
206 // Called from native code.
207 @SuppressWarnings("unused")
Mathew Inwooda570dee2018-08-17 14:56:00 +0100208 @UnsupportedAppUsage
Dominik Laskowski3316a0a2019-01-25 02:56:41 -0800209 private void dispatchHotplug(long timestampNanos, long physicalDisplayId, boolean connected) {
210 onHotplug(timestampNanos, physicalDisplayId, connected);
Jeff Brown0a0a1242011-12-02 02:25:22 -0800211 }
Ady Abrahama5a21f72019-02-13 16:41:59 -0800212
213 // Called from native code.
214 @SuppressWarnings("unused")
215 private void dispatchConfigChanged(long timestampNanos, long physicalDisplayId, int configId) {
216 onConfigChanged(timestampNanos, physicalDisplayId, configId);
217 }
218
Jeff Brown0a0a1242011-12-02 02:25:22 -0800219}