Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ android {
}
}

androidComponents {
finalizeDsl { extension ->
extension.sourceSets.getByName("benchmarkRelease").manifest.srcFile(
"src/benchmarkRelease/AndroidManifest.xml",
)
}
}

dependencies {
implementation(projects.core.common)
implementation(projects.core.analytics)
Expand Down
11 changes: 11 additions & 0 deletions app/src/benchmarkRelease/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<application>
<activity
android:name="com.yapp.orbit.benchmark.BenchmarkHostActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.Orbit" />
</application>
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.yapp.orbit.benchmark

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.ReportDrawnWhen
import androidx.activity.compose.setContent
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
import com.yapp.designsystem.theme.OrbitTheme

internal const val EXTRA_BENCHMARK_SCREEN = "benchmark_screen_key"
internal const val BENCHMARK_SCREEN_ORBIT_PICKER = "orbit_picker"
internal const val BENCHMARK_UNKNOWN_SCREEN_ROOT = "benchmark_unknown_screen"

class BenchmarkHostActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val screenKey = intent?.getStringExtra(EXTRA_BENCHMARK_SCREEN)
setContent {
OrbitTheme {
BenchmarkScreenContainer(screenKey)
}
}
}
}

@Composable
private fun BenchmarkScreenContainer(screenKey: String?) {
when (screenKey) {
BENCHMARK_SCREEN_ORBIT_PICKER -> OrbitPickerBenchmarkScreen()
else -> BenchmarkScreenMissing(screenKey)
}
}

@Composable
private fun BenchmarkScreenMissing(requestedKey: String?) {
ReportDrawnWhen { true }
Box(
modifier = Modifier
.fillMaxSize()
.background(OrbitTheme.colors.gray_900)
.semantics { contentDescription = BENCHMARK_UNKNOWN_SCREEN_ROOT },
contentAlignment = Alignment.Center,
) {
Text(
text = "Benchmark screen '${requestedKey ?: "unknown"}' not registered.",
color = OrbitTheme.colors.white,
fontSize = 16.sp,
fontWeight = FontWeight.SemiBold,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.yapp.orbit.benchmark

import androidx.activity.compose.ReportDrawnWhen
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.yapp.designsystem.theme.OrbitTheme
import com.yapp.ui.component.timepicker.OrbitPicker
import java.time.LocalTime

internal const val ORBIT_PICKER_BENCHMARK_ROOT = "orbit_picker_root"

@Composable
internal fun OrbitPickerBenchmarkScreen(
modifier: Modifier = Modifier,
initialTime: LocalTime = LocalTime.of(8, 30),
) {
var selectedTime by remember { mutableStateOf(initialTime) }
var isDrawn by remember { mutableStateOf(false) }

ReportDrawnWhen { isDrawn }

LaunchedEffect(Unit) {
isDrawn = true
}

Box(
modifier = modifier
.fillMaxSize()
.background(OrbitTheme.colors.gray_900)
.semantics { contentDescription = ORBIT_PICKER_BENCHMARK_ROOT },
contentAlignment = Alignment.Center,
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
modifier = Modifier.padding(horizontal = 24.dp),
) {
OrbitPicker(
initialTime = selectedTime,
onValueChange = { selectedTime = it },
)
}
}
}

@Preview
@Composable
private fun OrbitPickerBenchmarkPreview() {
OrbitTheme {
OrbitPickerBenchmarkScreen()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.dongchyeon.baselineprofile

import android.content.ComponentName
import android.content.Intent
import androidx.benchmark.macro.CompilationMode
import androidx.benchmark.macro.FrameTimingMetric
import androidx.benchmark.macro.StartupMode
import androidx.benchmark.macro.junit4.MacrobenchmarkRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
@LargeTest
class OrbitPickerBenchmarks {

@get:Rule
val rule = MacrobenchmarkRule()

@Test
fun orbitPickerScrollCompilationNone() = benchmark(CompilationMode.None())

@Test
fun orbitPickerScrollCompilationBaselineProfile() = benchmark(CompilationMode.Partial())

private fun benchmark(compilationMode: CompilationMode) {
val targetPackage = InstrumentationRegistry.getArguments().getString("targetAppId")
?: throw IllegalStateException("targetAppId not passed as instrumentation runner arg")

rule.measureRepeated(
packageName = targetPackage,
metrics = listOf(FrameTimingMetric()),
compilationMode = compilationMode,
startupMode = StartupMode.COLD,
iterations = 10,
setupBlock = {
killProcess()
pressHome()
},
measureBlock = {
val intent = Intent().apply {
component = ComponentName(targetPackage, BENCHMARK_ACTIVITY_NAME)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
putExtra(BENCHMARK_SCREEN_EXTRA, ORBIT_PICKER_SCREEN_KEY)
}

startActivityAndWait(intent)

device.wait(Until.hasObject(By.desc(ORBIT_PICKER_SEMANTICS)), 5_000)
val picker = device.findObject(By.desc(ORBIT_PICKER_SEMANTICS))
?: error("OrbitPicker root not found")

val bounds = picker.visibleBounds
val x = bounds.centerX() + bounds.width() / 4
val startY = bounds.centerY() + bounds.height() / 4
val endY = bounds.centerY() - bounds.height() / 4

device.swipe(x, startY, x, endY, 30)
device.waitForIdle()
},
)
}

private companion object {
private const val BENCHMARK_ACTIVITY_NAME =
"com.yapp.orbit.benchmark.BenchmarkHostActivity"
private const val BENCHMARK_SCREEN_EXTRA = "benchmark_screen_key"
private const val ORBIT_PICKER_SCREEN_KEY = "orbit_picker"
private const val ORBIT_PICKER_SEMANTICS = "orbit_picker_root"
}
}