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