1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
2  * This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 package org.mozilla.gecko.gfx;
7 
8 import android.content.Context;
9 import android.hardware.display.DisplayManager;
10 import android.os.Build;
11 import android.os.Handler;
12 import android.os.Looper;
13 import android.view.Choreographer;
14 import android.view.Display;
15 import androidx.annotation.RequiresApi;
16 import org.mozilla.gecko.GeckoAppShell;
17 import org.mozilla.gecko.annotation.WrapForJNI;
18 import org.mozilla.gecko.mozglue.JNIObject;
19 
20 /** This class receives HW vsync events through a {@link Choreographer}. */
21 @WrapForJNI
22 /* package */ final class AndroidVsync extends JNIObject implements Choreographer.FrameCallback {
23   @WrapForJNI
24   @Override // JNIObject
disposeNative()25   protected native void disposeNative();
26 
27   private static final String LOGTAG = "AndroidVsync";
28 
29   /* package */ Choreographer mChoreographer;
30   private volatile boolean mObservingVsync;
31 
AndroidVsync()32   public AndroidVsync() {
33     final Handler mainHandler = new Handler(Looper.getMainLooper());
34     mainHandler.post(
35         new Runnable() {
36           @Override
37           public void run() {
38             mChoreographer = Choreographer.getInstance();
39             if (mObservingVsync) {
40               mChoreographer.postFrameCallback(AndroidVsync.this);
41             }
42           }
43         });
44   }
45 
46   @WrapForJNI(stubName = "NotifyVsync")
nativeNotifyVsync(final long frameTimeNanos)47   private native void nativeNotifyVsync(final long frameTimeNanos);
48 
49   // Choreographer callback implementation.
doFrame(final long frameTimeNanos)50   public void doFrame(final long frameTimeNanos) {
51     if (mObservingVsync) {
52       mChoreographer.postFrameCallback(this);
53       nativeNotifyVsync(frameTimeNanos);
54     }
55   }
56 
57   /**
58    * Start/stop observing Vsync event.
59    *
60    * @param enable true to start observing; false to stop.
61    * @return true if observing and false if not.
62    */
63   @WrapForJNI
observeVsync(final boolean enable)64   public synchronized boolean observeVsync(final boolean enable) {
65     if (mObservingVsync != enable) {
66       mObservingVsync = enable;
67 
68       if (mChoreographer != null) {
69         if (enable) {
70           mChoreographer.postFrameCallback(this);
71         } else {
72           mChoreographer.removeFrameCallback(this);
73         }
74       }
75     }
76     return mObservingVsync;
77   }
78 
79   /**
80    * Gets the refresh rate of default display in frames per second.
81    *
82    * <p>The {@link DisplayManager} used by this method to determine the refresh rate was introduced
83    * in API level 17.
84    *
85    * @return the refresh rate of default display in frames per second.
86    */
87   @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
88   @WrapForJNI
getRefreshRate()89   public float getRefreshRate() {
90     final DisplayManager dm =
91         (DisplayManager)
92             GeckoAppShell.getApplicationContext().getSystemService(Context.DISPLAY_SERVICE);
93     return dm.getDisplay(Display.DEFAULT_DISPLAY).getRefreshRate();
94   }
95 }
96