Merge "Add support for device emulation in the Gallery app"
This commit is contained in:
committed by
Android (Google) Code Review
commit
1475e5f3dd
@@ -17,5 +17,6 @@
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.systemui.compose.gallery">
|
||||
|
||||
<!-- To emulate a display size and density. -->
|
||||
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
|
||||
</manifest>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.systemui.compose.gallery">
|
||||
package="com.android.systemui.compose.gallery.app">
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
@@ -25,7 +25,7 @@
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.SystemUIGallery">
|
||||
<activity
|
||||
android:name=".GalleryActivity"
|
||||
android:name="com.android.systemui.compose.gallery.GalleryActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
package com.android.systemui.compose.gallery
|
||||
|
||||
import android.graphics.Point
|
||||
import android.os.UserHandle
|
||||
import android.view.Display
|
||||
import android.view.WindowManagerGlobal
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
@@ -9,14 +14,25 @@ import androidx.compose.material.icons.filled.BrightnessLow
|
||||
import androidx.compose.material.icons.filled.FormatSize
|
||||
import androidx.compose.material.icons.filled.FormatTextdirectionLToR
|
||||
import androidx.compose.material.icons.filled.FormatTextdirectionRToL
|
||||
import androidx.compose.material.icons.filled.Smartphone
|
||||
import androidx.compose.material.icons.filled.Tablet
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
enum class FontScale(val scale: Float) {
|
||||
Small(0.85f),
|
||||
@@ -35,6 +51,39 @@ fun ConfigurationControls(
|
||||
onChangeLayoutDirection: () -> Unit,
|
||||
onChangeFontScale: () -> Unit,
|
||||
) {
|
||||
// The display we are emulating, if any.
|
||||
var emulatedDisplayName by rememberSaveable { mutableStateOf<String?>(null) }
|
||||
val emulatedDisplay =
|
||||
emulatedDisplayName?.let { name -> EmulatedDisplays.firstOrNull { it.name == name } }
|
||||
|
||||
LaunchedEffect(emulatedDisplay) {
|
||||
val wm = WindowManagerGlobal.getWindowManagerService()
|
||||
|
||||
val defaultDisplayId = Display.DEFAULT_DISPLAY
|
||||
if (emulatedDisplay == null) {
|
||||
wm.clearForcedDisplayDensityForUser(defaultDisplayId, UserHandle.myUserId())
|
||||
wm.clearForcedDisplaySize(defaultDisplayId)
|
||||
} else {
|
||||
val density = emulatedDisplay.densityDpi
|
||||
|
||||
// Emulate the display and make sure that we use the maximum available space possible.
|
||||
val initialSize = Point()
|
||||
wm.getInitialDisplaySize(defaultDisplayId, initialSize)
|
||||
val width = emulatedDisplay.width
|
||||
val height = emulatedDisplay.height
|
||||
val minOfSize = min(width, height)
|
||||
val maxOfSize = max(width, height)
|
||||
if (initialSize.x < initialSize.y) {
|
||||
wm.setForcedDisplaySize(defaultDisplayId, minOfSize, maxOfSize)
|
||||
} else {
|
||||
wm.setForcedDisplaySize(defaultDisplayId, maxOfSize, minOfSize)
|
||||
}
|
||||
wm.setForcedDisplayDensityForUser(defaultDisplayId, density, UserHandle.myUserId())
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(b/231131244): Fork FlowRow from Accompanist and use that instead to make sure that users
|
||||
// don't miss any available configuration.
|
||||
LazyRow {
|
||||
// Dark/light theme.
|
||||
item {
|
||||
@@ -82,5 +131,70 @@ fun ConfigurationControls(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Display emulation.
|
||||
EmulatedDisplays.forEach { display ->
|
||||
item {
|
||||
DisplayButton(
|
||||
display,
|
||||
emulatedDisplay == display,
|
||||
{ emulatedDisplayName = it?.name },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DisplayButton(
|
||||
display: EmulatedDisplay,
|
||||
selected: Boolean,
|
||||
onChangeEmulatedDisplay: (EmulatedDisplay?) -> Unit,
|
||||
) {
|
||||
val onClick = {
|
||||
if (selected) {
|
||||
onChangeEmulatedDisplay(null)
|
||||
} else {
|
||||
onChangeEmulatedDisplay(display)
|
||||
}
|
||||
}
|
||||
|
||||
val content: @Composable RowScope.() -> Unit = {
|
||||
Icon(display.icon, null)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text(display.name)
|
||||
}
|
||||
|
||||
if (selected) {
|
||||
Button(onClick, contentPadding = ButtonDefaults.TextButtonContentPadding, content = content)
|
||||
} else {
|
||||
TextButton(onClick, content = content)
|
||||
}
|
||||
}
|
||||
|
||||
/** The displays that can be emulated from this Gallery app. */
|
||||
private val EmulatedDisplays =
|
||||
listOf(
|
||||
EmulatedDisplay(
|
||||
"Phone",
|
||||
Icons.Default.Smartphone,
|
||||
width = 1440,
|
||||
height = 3120,
|
||||
densityDpi = 560,
|
||||
),
|
||||
EmulatedDisplay(
|
||||
"Tablet",
|
||||
Icons.Default.Tablet,
|
||||
width = 2560,
|
||||
height = 1600,
|
||||
densityDpi = 320,
|
||||
),
|
||||
)
|
||||
|
||||
private data class EmulatedDisplay(
|
||||
val name: String,
|
||||
val icon: ImageVector,
|
||||
val width: Int,
|
||||
val height: Int,
|
||||
val densityDpi: Int,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user