Using Choreographer for getting refreshrate instead of display manager
Bug: 404582684 Flag: EXEMPT bugfix Test: Manually verified that values are same as before even after changing refresh rate `adb shell settings put system peak_refresh_rate [30/60/90/120]` Change-Id: I5d5468d8ab81a9a5e8d8cd67a9097423b750edb3
This commit is contained in:
@@ -21,8 +21,10 @@ import com.android.launcher3.uioverrides.SystemApiWrapper
|
||||
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapperImpl
|
||||
import com.android.launcher3.util.ApiWrapper
|
||||
import com.android.launcher3.util.PluginManagerWrapper
|
||||
import com.android.launcher3.util.window.RefreshRateTracker
|
||||
import com.android.launcher3.util.window.WindowManagerProxy
|
||||
import com.android.launcher3.widget.LauncherWidgetHolder.WidgetHolderFactory
|
||||
import com.android.quickstep.util.ChoreographerFrameRateTracker
|
||||
import com.android.quickstep.util.GestureExclusionManager
|
||||
import com.android.quickstep.util.SystemWindowManagerProxy
|
||||
import dagger.Binds
|
||||
@@ -60,4 +62,8 @@ object StaticObjectModule {
|
||||
@Provides
|
||||
@JvmStatic
|
||||
fun provideGestureExclusionManager(): GestureExclusionManager = GestureExclusionManager.INSTANCE
|
||||
|
||||
@Provides
|
||||
@JvmStatic
|
||||
fun provideRefreshRateTracker(): RefreshRateTracker = ChoreographerFrameRateTracker
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.quickstep.util
|
||||
|
||||
import android.util.TimeUtils
|
||||
import android.view.Choreographer
|
||||
import com.android.launcher3.util.window.RefreshRateTracker
|
||||
|
||||
/** [RefreshRateTracker] using main thread [Choreographer] */
|
||||
object ChoreographerFrameRateTracker : RefreshRateTracker {
|
||||
|
||||
override val singleFrameMs: Int
|
||||
get() =
|
||||
Choreographer.getMainThreadInstance()?.let {
|
||||
(it.frameIntervalNanos / TimeUtils.NANOS_PER_MS).toInt().coerceAtLeast(1)
|
||||
} ?: 1
|
||||
}
|
||||
@@ -91,6 +91,7 @@ public interface LauncherBaseAppComponent {
|
||||
|
||||
LoaderCursorFactory getLoaderCursorFactory();
|
||||
WidgetHolderFactory getWidgetHolderFactory();
|
||||
RefreshRateTracker getFrameRateProvider();
|
||||
|
||||
/** Builder for LauncherBaseAppComponent. */
|
||||
interface Builder {
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.launcher3.util.window;
|
||||
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.hardware.display.DisplayManager.DisplayListener;
|
||||
import android.view.Display;
|
||||
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import com.android.launcher3.dagger.ApplicationContext;
|
||||
import com.android.launcher3.dagger.LauncherAppComponent;
|
||||
import com.android.launcher3.dagger.LauncherAppSingleton;
|
||||
import com.android.launcher3.util.DaggerSingletonObject;
|
||||
import com.android.launcher3.util.DaggerSingletonTracker;
|
||||
import com.android.launcher3.util.SafeCloseable;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* Utility class to track refresh rate of the current device
|
||||
*/
|
||||
@LauncherAppSingleton
|
||||
public class RefreshRateTracker implements DisplayListener, SafeCloseable {
|
||||
|
||||
private static final DaggerSingletonObject<RefreshRateTracker> INSTANCE =
|
||||
new DaggerSingletonObject<>(LauncherAppComponent::getRefreshRateTracker);
|
||||
|
||||
private int mSingleFrameMs = 1;
|
||||
|
||||
private final DisplayManager mDM;
|
||||
|
||||
@Inject
|
||||
RefreshRateTracker(@ApplicationContext Context context, DaggerSingletonTracker tracker) {
|
||||
mDM = context.getSystemService(DisplayManager.class);
|
||||
updateSingleFrameMs();
|
||||
mDM.registerDisplayListener(this, UI_HELPER_EXECUTOR.getHandler());
|
||||
tracker.addCloseable(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the single frame time in ms
|
||||
*/
|
||||
public static int getSingleFrameMs(Context context) {
|
||||
return INSTANCE.get(context).mSingleFrameMs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onDisplayAdded(int displayId) { }
|
||||
|
||||
@Override
|
||||
public final void onDisplayRemoved(int displayId) { }
|
||||
|
||||
@WorkerThread
|
||||
@Override
|
||||
public final void onDisplayChanged(int displayId) {
|
||||
if (displayId == DEFAULT_DISPLAY) {
|
||||
updateSingleFrameMs();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSingleFrameMs() {
|
||||
Display display = mDM.getDisplay(DEFAULT_DISPLAY);
|
||||
if (display != null) {
|
||||
float refreshRate = display.getRefreshRate();
|
||||
mSingleFrameMs = refreshRate > 0 ? (int) (1000 / refreshRate) : 16;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
mDM.unregisterDisplayListener(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.launcher3.util.window
|
||||
|
||||
import android.content.Context
|
||||
import android.hardware.display.DisplayManager
|
||||
import android.hardware.display.DisplayManager.DisplayListener
|
||||
import android.view.Display.DEFAULT_DISPLAY
|
||||
import com.android.launcher3.dagger.ApplicationContext
|
||||
import com.android.launcher3.dagger.LauncherAppSingleton
|
||||
import com.android.launcher3.dagger.LauncherComponentProvider.appComponent
|
||||
import com.android.launcher3.util.DaggerSingletonTracker
|
||||
import com.android.launcher3.util.Executors
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Utility class to track refresh rate of the current device */
|
||||
interface RefreshRateTracker {
|
||||
|
||||
val singleFrameMs: Int
|
||||
|
||||
@LauncherAppSingleton
|
||||
class RefreshRateTrackerImpl
|
||||
@Inject
|
||||
constructor(@ApplicationContext ctx: Context, tracker: DaggerSingletonTracker) :
|
||||
RefreshRateTracker, DisplayListener {
|
||||
|
||||
private val displayManager: DisplayManager =
|
||||
ctx.getSystemService(DisplayManager::class.java)!!.also {
|
||||
it.registerDisplayListener(this, Executors.UI_HELPER_EXECUTOR.handler)
|
||||
tracker.addCloseable { it.unregisterDisplayListener(this) }
|
||||
}
|
||||
|
||||
override var singleFrameMs: Int = updateSingleFrameMs()
|
||||
|
||||
private fun updateSingleFrameMs(): Int {
|
||||
val refreshRate = displayManager.getDisplay(DEFAULT_DISPLAY)?.refreshRate
|
||||
return if (refreshRate != null && refreshRate > 0) (1000 / refreshRate).toInt() else 16
|
||||
}
|
||||
|
||||
override fun onDisplayChanged(displayId: Int) {
|
||||
if (displayId == DEFAULT_DISPLAY) {
|
||||
singleFrameMs = updateSingleFrameMs()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDisplayAdded(displayId: Int) {}
|
||||
|
||||
override fun onDisplayRemoved(displayId: Int) {}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
/** Returns the single frame time in ms */
|
||||
@JvmStatic fun Context.getSingleFrameMs() = appComponent.frameRateProvider.singleFrameMs
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.launcher3.dagger
|
||||
|
||||
import com.android.launcher3.util.window.RefreshRateTracker
|
||||
import com.android.launcher3.util.window.RefreshRateTracker.RefreshRateTrackerImpl
|
||||
import com.android.launcher3.widget.LauncherWidgetHolder.WidgetHolderFactory
|
||||
import com.android.launcher3.widget.LauncherWidgetHolder.WidgetHolderFactoryImpl
|
||||
import dagger.Binds
|
||||
@@ -35,7 +37,10 @@ abstract class WidgetModule {
|
||||
|
||||
@Module abstract class PluginManagerWrapperModule {}
|
||||
|
||||
@Module object StaticObjectModule {}
|
||||
@Module
|
||||
abstract class StaticObjectModule {
|
||||
@Binds abstract fun bindRefreshRateTracker(tracker: RefreshRateTrackerImpl): RefreshRateTracker
|
||||
}
|
||||
|
||||
// Module containing bindings for the final derivative app
|
||||
@Module abstract class AppModule {}
|
||||
|
||||
Reference in New Issue
Block a user