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 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 
     65     private static native long nativeInit(WeakReference<DisplayEventReceiver> receiver,
     66             MessageQueue messageQueue, int vsyncSource);
     67     private static native void nativeDispose(long receiverPtr);
     68     @FastNative
     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      */
     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      */
     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
     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      */
    110     public void dispose() {
    111         dispose(false);
    112     }
    113 
    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      */
    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      */
    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      */
    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")
    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")
    176     private void dispatchHotplug(long timestampNanos, int builtInDisplayId, boolean connected) {
    177         onHotplug(timestampNanos, builtInDisplayId, connected);
    178     }
    179 }
    180