diff --git a/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java b/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java index aa21bc6b360ab..4f620f2b2b0c1 100644 --- a/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java +++ b/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java @@ -9,10 +9,13 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.AssetManager; +import android.hardware.display.DisplayManager; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.SystemClock; +import android.view.Display; import android.view.WindowManager; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -106,7 +109,6 @@ public FlutterLoader(@NonNull FlutterJNI flutterJNI, @NonNull ExecutorService ex private FlutterApplicationInfo flutterApplicationInfo; private FlutterJNI flutterJNI; private ExecutorService executorService; - private WindowManager windowManager; private static class InitResult { final String appStoragePath; @@ -158,8 +160,19 @@ public void startInitialization(@NonNull Context applicationContext, @NonNull Se initStartTimestampMillis = SystemClock.uptimeMillis(); flutterApplicationInfo = ApplicationInfoLoader.load(appContext); - VsyncWaiter.getInstance((WindowManager) appContext.getSystemService(Context.WINDOW_SERVICE)) - .init(); + + float fps; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + final DisplayManager dm = appContext.getSystemService(DisplayManager.class); + final Display primaryDisplay = dm.getDisplay(Display.DEFAULT_DISPLAY); + fps = primaryDisplay.getRefreshRate(); + } else { + fps = + ((WindowManager) appContext.getSystemService(Context.WINDOW_SERVICE)) + .getDefaultDisplay() + .getRefreshRate(); + } + VsyncWaiter.getInstance(fps).init(); // Use a background thread for initialization tasks that require disk access. Callable initTask = diff --git a/shell/platform/android/io/flutter/view/VsyncWaiter.java b/shell/platform/android/io/flutter/view/VsyncWaiter.java index 8e225f0ee548a..89ff20dbee951 100644 --- a/shell/platform/android/io/flutter/view/VsyncWaiter.java +++ b/shell/platform/android/io/flutter/view/VsyncWaiter.java @@ -5,7 +5,6 @@ package io.flutter.view; import android.view.Choreographer; -import android.view.WindowManager; import androidx.annotation.NonNull; import io.flutter.embedding.engine.FlutterJNI; @@ -14,14 +13,14 @@ public class VsyncWaiter { private static VsyncWaiter instance; @NonNull - public static VsyncWaiter getInstance(@NonNull WindowManager windowManager) { + public static VsyncWaiter getInstance(float fps) { if (instance == null) { - instance = new VsyncWaiter(windowManager); + instance = new VsyncWaiter(fps); } return instance; } - @NonNull private final WindowManager windowManager; + private final float fps; private final FlutterJNI.AsyncWaitForVsyncDelegate asyncWaitForVsyncDelegate = new FlutterJNI.AsyncWaitForVsyncDelegate() { @@ -32,7 +31,6 @@ public void asyncWaitForVsync(long cookie) { new Choreographer.FrameCallback() { @Override public void doFrame(long frameTimeNanos) { - float fps = windowManager.getDefaultDisplay().getRefreshRate(); long refreshPeriodNanos = (long) (1000000000.0 / fps); FlutterJNI.nativeOnVsync( frameTimeNanos, frameTimeNanos + refreshPeriodNanos, cookie); @@ -41,15 +39,14 @@ public void doFrame(long frameTimeNanos) { } }; - private VsyncWaiter(@NonNull WindowManager windowManager) { - this.windowManager = windowManager; + private VsyncWaiter(float fps) { + this.fps = fps; } public void init() { FlutterJNI.setAsyncWaitForVsyncDelegate(asyncWaitForVsyncDelegate); // TODO(mattcarroll): look into moving FPS reporting to a plugin - float fps = windowManager.getDefaultDisplay().getRefreshRate(); FlutterJNI.setRefreshRateFPS(fps); } } diff --git a/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java b/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java index 4b11863f5efb8..854a23182f7bb 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java @@ -12,10 +12,13 @@ import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.robolectric.Shadows.shadowOf; +import android.annotation.TargetApi; import android.app.ActivityManager; import android.content.Context; import io.flutter.embedding.engine.FlutterJNI; @@ -92,4 +95,18 @@ public void itUsesCorrectExecutorService() { flutterLoader.startInitialization(RuntimeEnvironment.application); verify(mockExecutorService, times(1)).submit(any(Callable.class)); } + + @Test + @TargetApi(23) + @Config(sdk = 23) + public void itReportsFpsToVsyncWaiterAndroidM() { + FlutterJNI mockFlutterJNI = mock(FlutterJNI.class); + FlutterLoader flutterLoader = new FlutterLoader(mockFlutterJNI); + + Context appContextSpy = spy(RuntimeEnvironment.application); + + assertFalse(flutterLoader.initialized()); + flutterLoader.startInitialization(appContextSpy); + verify(appContextSpy, never()).getSystemService(anyString()); + } }