Skip to content
Open
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
29 changes: 15 additions & 14 deletions JankStatsSample/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,20 @@ plugins {
id("com.android.application")
alias(libs.plugins.kotlin)
alias(libs.plugins.compose.compiler)
alias(libs.plugins.kotlin.serialization)
}

android {
compileSdk = 35
compileSdk = 36

buildFeatures {
viewBinding = true
compose = true
}

defaultConfig {
applicationId = "com.example.jankstats"
minSdk = 21
targetSdk = 35
minSdk = 23
targetSdk = 36
versionCode = 1
versionName = "1.0"

Expand All @@ -40,17 +40,16 @@ android {

buildTypes {
getByName("release") {
isMinifyEnabled = false
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"))
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}

composeOptions {
kotlinCompilerExtensionVersion = "1.5.15"
}
Expand All @@ -62,13 +61,15 @@ dependencies {
implementation(composeBom)
implementation(libs.activity)
implementation(libs.appcompat)
implementation(libs.compose.material)
implementation(libs.compose.activity)
implementation(libs.material.icons.core)
implementation(libs.material3)
implementation(libs.compose.ui)
implementation(libs.compose.ui.tooling)
implementation(libs.constraintlayout)
implementation(libs.jankstats)
implementation(libs.material)
implementation(libs.navigation.fragment)
implementation(libs.navigation.ui)
implementation(libs.navigation3.runtime)
implementation(libs.navigation3.ui)
implementation(libs.kotlinx.serialization.json)
implementation(libs.tracing)
}
6 changes: 4 additions & 2 deletions JankStatsSample/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,17 @@

<activity
android:name=".JankLoggingActivity"
android:exported="true">
android:exported="true"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".JankAggregatorActivity"
android:exported="true">
android:exported="true"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,30 @@ package com.example.jankstats

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.metrics.performance.PerformanceMetricsState
import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.navigateUp
import androidx.navigation.ui.setupActionBarWithNavController
import com.example.jankstats.databinding.ActivityJankLoggingBinding
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Modifier
import androidx.lifecycle.compose.LifecycleResumeEffect
import androidx.navigation3.runtime.NavKey
import androidx.navigation3.runtime.entryProvider
import androidx.navigation3.ui.NavDisplay
import com.example.jankstats.compose.JankStatsScaffold
import com.example.jankstats.compose.JankStatsTheme
import com.example.jankstats.compose.MessageContentScreen
import com.example.jankstats.compose.MessageList
import com.example.jankstats.compose.rememberMetricsStateHolder
import com.example.jankstats.navigation.ComposeListRoute
import com.example.jankstats.navigation.MessageContentRoute
import com.example.jankstats.navigation.MessageListRoute
import com.example.jankstats.navigation.Navigator
import com.example.jankstats.navigation.rememberNavigationState
import com.example.jankstats.navigation.toEntries

/**
* This activity shows how to use JankStatsAggregator, a class in this test directory layered
Expand All @@ -35,15 +51,10 @@ import com.example.jankstats.databinding.ActivityJankLoggingBinding
* or if JankStatsAggregator issues the report itself.
*/
// [START aggregator_activity_init]
class JankAggregatorActivity : AppCompatActivity() {
class JankAggregatorActivity : ComponentActivity() {

private lateinit var jankStatsAggregator: JankStatsAggregator

// [START_EXCLUDE silent]
private lateinit var binding: ActivityJankLoggingBinding
private lateinit var navController: NavController
private lateinit var appBarConfiguration: AppBarConfiguration

// [START jank_aggregator_listener]
private val jankReportListener =
JankStatsAggregator.OnJankReportListener { reason, totalFrames, jankFrameData ->
Expand All @@ -65,48 +76,90 @@ class JankAggregatorActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// [START_EXCLUDE]
binding = ActivityJankLoggingBinding.inflate(layoutInflater)
setContentView(binding.root)
setupUi()
// [END_EXCLUDE]
// Metrics state holder can be retrieved regardless of JankStats initialization.
val metricsStateHolder = PerformanceMetricsState.getHolderForHierarchy(binding.root)

// Initialize JankStats with an aggregator for the current window.
jankStatsAggregator = JankStatsAggregator(window, jankReportListener)

// Add the Activity name as state.
metricsStateHolder.state?.putState("Activity", javaClass.simpleName)
}
// [END aggregator_activity_init]
enableEdgeToEdge()
setContent {
jankStatsAggregator = remember {
JankStatsAggregator(window, jankReportListener)
}
// ...
// metrics state holder can be retrieved regardless of JankStats initialization
val metricsStateHolder = rememberMetricsStateHolder()
// ...
// add activity name as state
metricsStateHolder.state?.putState("Activity", javaClass.simpleName)

LifecycleResumeEffect(jankStatsAggregator) {
jankStatsAggregator.jankStats.isTrackingEnabled = true
onPauseOrDispose {
jankStatsAggregator.issueJankReport("Activity paused")
jankStatsAggregator.jankStats.isTrackingEnabled = false
}
}

// [START aggregator_tracking_enabled]
override fun onResume() {
super.onResume()
jankStatsAggregator.jankStats.isTrackingEnabled = true
}
val listState = rememberLazyListState()
LaunchedEffect(metricsStateHolder, listState) {
snapshotFlow { listState.isScrollInProgress }.collect { isScrolling ->
if (isScrolling) {
metricsStateHolder.state?.putState("LazyList", "Scrolling")
} else {
metricsStateHolder.state?.removeState("LazyList")
}
}
}

override fun onPause() {
super.onPause()
// Before disabling tracking, issue the report with (optionally) specified reason.
jankStatsAggregator.issueJankReport("Activity paused")
jankStatsAggregator.jankStats.isTrackingEnabled = false
}
// [END aggregator_tracking_enabled]
val topLevelRoutes = remember { setOf<NavKey>(MessageListRoute, ComposeListRoute) }
val navigationState = rememberNavigationState(
startRoute = MessageListRoute,
topLevelRoutes = topLevelRoutes
)
val navigator = remember(navigationState) { Navigator(navigationState) }

override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
val currentStack = navigationState.backStacks[navigationState.topLevelRoute]
val activeKey = currentStack?.lastOrNull() ?: navigationState.topLevelRoute
val canNavigateUp = currentStack != null && currentStack.size > 1

private fun setupUi() {
setSupportActionBar(binding.toolbar)
val title = when (activeKey) {
is MessageListRoute -> "Message List"
is ComposeListRoute -> "Compose List"
is MessageContentRoute -> "Message Content"
else -> "JankStats Sample"
}

val navHostFragment =
supportFragmentManager.findFragmentById(R.id.navigation_container) as NavHostFragment
navController = navHostFragment.navController
val entryProvider = remember(navigator) {
entryProvider {
entry<MessageListRoute> {
MessageList(onItemClick = { headerText ->
navigator.navigate(MessageContentRoute(headerText))
})
}
entry<ComposeListRoute> {
MessageList(onItemClick = { headerText ->
navigator.navigate(MessageContentRoute(headerText))
})
}
entry<MessageContentRoute> { route ->
MessageContentScreen(title = route.title)
}
}
}

appBarConfiguration = AppBarConfiguration(navController.graph)
setupActionBarWithNavController(navController, appBarConfiguration)
JankStatsTheme {
JankStatsScaffold(
title = title,
canNavigateUp = canNavigateUp,
currentTopLevelRoute = navigationState.topLevelRoute,
onNavigateUp = { navigator.goBack() },
onBottomTabSelected = { navKey ->
navigator.navigate(navKey)
}
) { innerPadding ->
NavDisplay(
entries = navigationState.toEntries(entryProvider),
onBack = { navigator.goBack() },
modifier = Modifier.padding(innerPadding)
)
}
}
}
}
}
Loading
Loading