Home | History | Annotate | Download | only in view
      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 
     47     private static native long nativeInit(WeakReference<DisplayEventReceiver> receiver,
     48             MessageQueue messageQueue);
     49     private static native void nativeDispose(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      */
     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
     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      */
     80     public void dispose() {
     81         dispose(false);
     82     }
     83 
     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      */
    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      */
    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      */
    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")
    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")
    146     private void dispatchHotplug(long timestampNanos, int builtInDisplayId, boolean connected) {
    147         onHotplug(timestampNanos, builtInDisplayId, connected);
    148     }
    149 }
    150