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