• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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