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