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