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.annotation.UnsupportedAppUsage;
     20 import android.os.Looper;
     21 import android.os.MessageQueue;
     22 import android.util.Log;
     23 
     24 import dalvik.annotation.optimization.FastNative;
     25 import dalvik.system.CloseGuard;
     26 
     27 import java.lang.ref.WeakReference;
     28 
     29 /**
     30  * Provides a low-level mechanism for an application to receive display events
     31  * such as vertical sync.
     32  *
     33  * The display event receive is NOT thread safe.  Moreover, its methods must only
     34  * be called on the Looper thread to which it is attached.
     35  *
     36  * @hide
     37  */
     38 public abstract class DisplayEventReceiver {
     39 
     40     /**
     41      * When retrieving vsync events, this specifies that the vsync event should happen at the normal
     42      * vsync-app tick.
     43      * <p>
     44      * Needs to be kept in sync with frameworks/native/include/gui/ISurfaceComposer.h
     45      */
     46     public static final int VSYNC_SOURCE_APP = 0;
     47 
     48     /**
     49      * When retrieving vsync events, this specifies that the vsync event should happen whenever
     50      * Surface Flinger is processing a frame.
     51      * <p>
     52      * Needs to be kept in sync with frameworks/native/include/gui/ISurfaceComposer.h
     53      */
     54     public static final int VSYNC_SOURCE_SURFACE_FLINGER = 1;
     55 
     56     private static final String TAG = "DisplayEventReceiver";
     57 
     58     private final CloseGuard mCloseGuard = CloseGuard.get();
     59 
     60     @UnsupportedAppUsage
     61     private long mReceiverPtr;
     62 
     63     // We keep a reference message queue object here so that it is not
     64     // GC'd while the native peer of the receiver is using them.
     65     private MessageQueue mMessageQueue;
     66 
     67     private static native long nativeInit(WeakReference<DisplayEventReceiver> receiver,
     68             MessageQueue messageQueue, int vsyncSource);
     69     private static native void nativeDispose(long receiverPtr);
     70     @FastNative
     71     private static native void nativeScheduleVsync(long receiverPtr);
     72 
     73     /**
     74      * Creates a display event receiver.
     75      *
     76      * @param looper The looper to use when invoking callbacks.
     77      */
     78     @UnsupportedAppUsage
     79     public DisplayEventReceiver(Looper looper) {
     80         this(looper, VSYNC_SOURCE_APP);
     81     }
     82 
     83     /**
     84      * Creates a display event receiver.
     85      *
     86      * @param looper The looper to use when invoking callbacks.
     87      * @param vsyncSource The source of the vsync tick. Must be on of the VSYNC_SOURCE_* values.
     88      */
     89     public DisplayEventReceiver(Looper looper, int vsyncSource) {
     90         if (looper == null) {
     91             throw new IllegalArgumentException("looper must not be null");
     92         }
     93 
     94         mMessageQueue = looper.getQueue();
     95         mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,
     96                 vsyncSource);
     97 
     98         mCloseGuard.open("dispose");
     99     }
    100 
    101     @Override
    102     protected void finalize() throws Throwable {
    103         try {
    104             dispose(true);
    105         } finally {
    106             super.finalize();
    107         }
    108     }
    109 
    110     /**
    111      * Disposes the receiver.
    112      */
    113     public void dispose() {
    114         dispose(false);
    115     }
    116 
    117     private void dispose(boolean finalized) {
    118         if (mCloseGuard != null) {
    119             if (finalized) {
    120                 mCloseGuard.warnIfOpen();
    121             }
    122             mCloseGuard.close();
    123         }
    124 
    125         if (mReceiverPtr != 0) {
    126             nativeDispose(mReceiverPtr);
    127             mReceiverPtr = 0;
    128         }
    129         mMessageQueue = null;
    130     }
    131 
    132     /**
    133      * Called when a vertical sync pulse is received.
    134      * The recipient should render a frame and then call {@link #scheduleVsync}
    135      * to schedule the next vertical sync pulse.
    136      *
    137      * @param timestampNanos The timestamp of the pulse, in the {@link System#nanoTime()}
    138      * timebase.
    139      * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair.
    140      * @param frame The frame number.  Increases by one for each vertical sync interval.
    141      */
    142     @UnsupportedAppUsage
    143     public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
    144     }
    145 
    146     /**
    147      * Called when a display hotplug event is received.
    148      *
    149      * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()}
    150      * timebase.
    151      * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair.
    152      * @param connected True if the display is connected, false if it disconnected.
    153      */
    154     @UnsupportedAppUsage
    155     public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) {
    156     }
    157 
    158     /**
    159      * Called when a display config changed event is received.
    160      *
    161      * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()}
    162      * timebase.
    163      * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair.
    164      * @param configId The new config Id
    165      */
    166     public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) {
    167     }
    168 
    169     /**
    170      * Schedules a single vertical sync pulse to be delivered when the next
    171      * display frame begins.
    172      */
    173     @UnsupportedAppUsage
    174     public void scheduleVsync() {
    175         if (mReceiverPtr == 0) {
    176             Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event "
    177                     + "receiver has already been disposed.");
    178         } else {
    179             nativeScheduleVsync(mReceiverPtr);
    180         }
    181     }
    182 
    183     // Called from native code.
    184     @SuppressWarnings("unused")
    185     @UnsupportedAppUsage
    186     private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame) {
    187         onVsync(timestampNanos, physicalDisplayId, frame);
    188     }
    189 
    190     // Called from native code.
    191     @SuppressWarnings("unused")
    192     @UnsupportedAppUsage
    193     private void dispatchHotplug(long timestampNanos, long physicalDisplayId, boolean connected) {
    194         onHotplug(timestampNanos, physicalDisplayId, connected);
    195     }
    196 
    197     // Called from native code.
    198     @SuppressWarnings("unused")
    199     private void dispatchConfigChanged(long timestampNanos, long physicalDisplayId, int configId) {
    200         onConfigChanged(timestampNanos, physicalDisplayId, configId);
    201     }
    202 
    203 }
    204