[CS] Define DisplayMetricsRepo and use it for QsFrameTranslateImpl.

CentralSurfacesImpl updated the display metrics on configuration change
(see #updateDisplaySize), so the new repo does the same.

Removing QsFrameTranslateImpl's usage of CentralSurfaces is necessary to
make NotificationPanelViewController a singleton.

Bug: 277762009
Bug: 277764509
Test: atest DisplayMetricsRepositoryTest
Test: `adb shell dumpsys activity service
com.android.systemui/.SystemUIService DisplayMetricsRepo` -> dumps the
display metric changes. Notably, the widthPixels and heightPixels change
when the device is rotated.

Change-Id: Ibef256bab38db5a7226d29a8b68546f093b78dd8
This commit is contained in:
Caitlin Shkuratov
2023-06-22 17:19:49 +00:00
parent 59d74fa26c
commit d7abdd7204
8 changed files with 221 additions and 7 deletions

View File

@@ -0,0 +1,74 @@
/*
* Copyright (C) 2023 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.systemui.display.data.repository
import android.content.Context
import android.content.res.Configuration
import android.util.DisplayMetrics
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.DisplayMetricsRepoLog
import com.android.systemui.statusbar.policy.ConfigurationController
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
/** Repository tracking display-related metrics like display height and width. */
@SysUISingleton
class DisplayMetricsRepository
@Inject
constructor(
@Application scope: CoroutineScope,
configurationController: ConfigurationController,
displayMetricsHolder: DisplayMetrics,
context: Context,
@DisplayMetricsRepoLog logBuffer: LogBuffer,
) {
private val displayMetrics: StateFlow<DisplayMetrics> =
conflatedCallbackFlow {
val callback =
object : ConfigurationController.ConfigurationListener {
override fun onConfigChanged(newConfig: Configuration?) {
context.display.getMetrics(displayMetricsHolder)
trySend(displayMetricsHolder)
}
}
configurationController.addCallback(callback)
awaitClose { configurationController.removeCallback(callback) }
}
.onEach {
logBuffer.log(
"DisplayMetrics",
LogLevel.INFO,
{ str1 = it.toString() },
{ "New metrics: $str1" },
)
}
.stateIn(scope, SharingStarted.Eagerly, displayMetricsHolder)
/** Returns the current display height in pixels. */
val heightPixels: Int
get() = displayMetrics.value.heightPixels
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2023 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.systemui.log.dagger
import javax.inject.Qualifier
/** A [com.android.systemui.log.LogBuffer] for display metrics related logging. */
@Qualifier
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class DisplayMetricsRepoLog

View File

@@ -488,4 +488,12 @@ public class LogModule {
public static LogBuffer provideDreamLogBuffer(LogBufferFactory factory) {
return factory.create("DreamLog", 250);
}
/** Provides a {@link LogBuffer} for display metrics related logs. */
@Provides
@SysUISingleton
@DisplayMetricsRepoLog
public static LogBuffer provideDisplayMetricsRepoLogBuffer(LogBufferFactory factory) {
return factory.create("DisplayMetricsRepo", 50);
}
}

View File

@@ -18,19 +18,19 @@ package com.android.systemui.statusbar;
import android.view.View;
import com.android.systemui.display.data.repository.DisplayMetricsRepository;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.phone.CentralSurfaces;
/**
* Calculates and moves the QS frame vertically.
*/
public abstract class QsFrameTranslateController {
protected CentralSurfaces mCentralSurfaces;
protected DisplayMetricsRepository mDisplayMetricsRepository;
public QsFrameTranslateController(CentralSurfaces centralSurfaces) {
mCentralSurfaces = centralSurfaces;
public QsFrameTranslateController(DisplayMetricsRepository displayMetricsRepository) {
mDisplayMetricsRepository = displayMetricsRepository;
}
/**

View File

@@ -19,9 +19,9 @@ package com.android.systemui.statusbar;
import android.view.View;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.display.data.repository.DisplayMetricsRepository;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.phone.CentralSurfaces;
import javax.inject.Inject;
@@ -34,8 +34,8 @@ import javax.inject.Inject;
public class QsFrameTranslateImpl extends QsFrameTranslateController {
@Inject
public QsFrameTranslateImpl(CentralSurfaces centralSurfaces) {
super(centralSurfaces);
public QsFrameTranslateImpl(DisplayMetricsRepository displayMetricsRepository) {
super(displayMetricsRepository);
}
@Override

View File

@@ -40,6 +40,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.AuthKeyguardMessageArea;
import com.android.systemui.Dumpable;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.display.data.repository.DisplayMetricsRepository;
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.qs.QSPanelController;
@@ -250,8 +251,12 @@ public interface CentralSurfaces extends Dumpable, LifecycleOwner {
@Override
void dump(PrintWriter pwOriginal, String[] args);
/** @deprecated Use {@link DisplayMetricsRepository} instead. */
@Deprecated
float getDisplayWidth();
/** @deprecated Use {@link DisplayMetricsRepository} instead. */
@Deprecated
float getDisplayHeight();
void readyForKeyguardDone();
@@ -394,6 +399,9 @@ public interface CentralSurfaces extends Dumpable, LifecycleOwner {
void setLaunchEmergencyActionOnFinishedWaking(boolean launch);
QSPanelController getQSPanelController();
/** @deprecated Use {@link DisplayMetricsRepository} instead. */
@Deprecated
float getDisplayDensity();
void extendDozePulse();

View File

@@ -2114,16 +2114,19 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
}
@Override
@Deprecated
public float getDisplayDensity() {
return mDisplayMetrics.density;
}
@Override
@Deprecated
public float getDisplayWidth() {
return mDisplayMetrics.widthPixels;
}
@Override
@Deprecated
public float getDisplayHeight() {
return mDisplayMetrics.heightPixels;
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright (C) 2023 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.systemui.display.data.repository
import android.content.Context
import android.util.DisplayMetrics
import android.view.Display
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.LogBuffer
import com.android.systemui.statusbar.policy.FakeConfigurationController
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@SmallTest
@OptIn(ExperimentalCoroutinesApi::class)
class DisplayMetricsRepositoryTest : SysuiTestCase() {
private lateinit var underTest: DisplayMetricsRepository
private val testScope = TestScope(StandardTestDispatcher())
private val configurationController = FakeConfigurationController()
private val displayMetrics =
DisplayMetrics().apply { this.heightPixels = INITIAL_HEIGHT_PIXELS }
private val mockContext: Context = mock()
private val mockDisplay: Display = mock()
@Before
fun setUp() {
underTest =
DisplayMetricsRepository(
testScope.backgroundScope,
configurationController,
displayMetrics,
mockContext,
LogBuffer("TestBuffer", maxSize = 10, logcatEchoTracker = mock())
)
whenever(mockContext.display).thenReturn(mockDisplay)
}
@Test
fun heightPixels_getsInitialValue() {
assertThat(underTest.heightPixels).isEqualTo(INITIAL_HEIGHT_PIXELS)
}
@Test
fun heightPixels_configChanged_heightUpdated() =
testScope.runTest {
runCurrent()
updateDisplayMetrics(456)
configurationController.notifyConfigurationChanged()
runCurrent()
assertThat(underTest.heightPixels).isEqualTo(456)
updateDisplayMetrics(23)
configurationController.notifyConfigurationChanged()
runCurrent()
assertThat(underTest.heightPixels).isEqualTo(23)
}
private fun updateDisplayMetrics(newHeight: Int) {
whenever(mockDisplay.getMetrics(displayMetrics)).thenAnswer {
it.getArgument<DisplayMetrics>(0).heightPixels = newHeight
Unit
}
}
private companion object {
const val INITIAL_HEIGHT_PIXELS = 345
}
}