Merge "Add the SPA page enter/leave logging metrcis." into udc-dev

This commit is contained in:
Sunny Shao
2023-03-07 10:12:55 +00:00
committed by Android (Google) Code Review
7 changed files with 383 additions and 1 deletions

View File

@@ -32,6 +32,7 @@ import com.android.settings.spa.app.specialaccess.PictureInPictureListProvider
import com.android.settings.spa.app.specialaccess.SpecialAppAccessPageProvider
import com.android.settings.spa.app.specialaccess.WifiControlAppListProvider
import com.android.settings.spa.app.specialaccess.UseFullScreenIntentAppListProvider
import com.android.settings.spa.core.instrumentation.SpaLogProvider
import com.android.settings.spa.development.UsageStatsPageProvider
import com.android.settings.spa.home.HomePageProvider
import com.android.settings.spa.network.NetworkAndInternetPageProvider
@@ -87,4 +88,5 @@ open class SettingsSpaEnvironment(context: Context) : SpaEnvironment(context) {
),
)
}
override val logger = SpaLogProvider
}

View File

@@ -16,18 +16,29 @@
package com.android.settings.spa
import android.app.ActivityManager
import android.content.Context
import android.content.Intent
import android.os.RemoteException
import android.os.UserHandle
import android.util.Log
import com.android.settingslib.spa.framework.BrowseActivity
import com.android.settingslib.spa.framework.util.SESSION_BROWSE
import com.android.settingslib.spa.framework.util.SESSION_EXTERNAL
import com.android.settingslib.spa.framework.util.appendSpaParams
class SpaActivity : BrowseActivity() {
companion object {
private const val TAG = "SpaActivity"
@JvmStatic
fun Context.startSpaActivity(destination: String) {
val intent = Intent(this, SpaActivity::class.java)
.appendSpaParams(destination = destination)
if (isLaunchedFromInternal()) {
intent.appendSpaParams(sessionName = SESSION_BROWSE)
} else {
intent.appendSpaParams(sessionName = SESSION_EXTERNAL)
}
startActivity(intent)
}
@@ -37,5 +48,15 @@ class SpaActivity : BrowseActivity() {
startSpaActivity("$destinationPrefix/$packageName/${UserHandle.myUserId()}")
return true
}
fun Context.isLaunchedFromInternal(): Boolean {
var pkg: String? = null
try {
pkg = ActivityManager.getService().getLaunchedFromPackage(getActivityToken())
} catch (e: RemoteException) {
Log.v(TAG, "Could not talk to activity manager.", e)
}
return applicationContext.packageName == pkg
}
}
}

View File

@@ -0,0 +1,41 @@
/*
* 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.settings.spa.core.instrumentation
import androidx.annotation.VisibleForTesting
/**
* This class stores some metrics temporary data. Such as the timestamp of the page enter for
* calculating the duration time on page.
*/
class MetricsDataModel {
@VisibleForTesting
val pageTimeStampList = mutableListOf<PageTimeStamp>()
fun addTimeStamp(dataItem: PageTimeStamp){
pageTimeStampList.add(dataItem)
}
fun getPageDuration(pageId: String, removed: Boolean = true): String {
val lastItem = pageTimeStampList.findLast { it.pageId == pageId }
if (removed && lastItem != null) {
pageTimeStampList.remove(lastItem)
}
return if (lastItem == null) "0"
else (System.currentTimeMillis() - lastItem.timeStamp).toString()
}
}

View File

@@ -0,0 +1,132 @@
/*
* 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.settings.spa.core.instrumentation
import android.app.settings.SettingsEnums
import android.os.Bundle
import androidx.annotation.VisibleForTesting
import com.android.settings.core.instrumentation.ElapsedTimeUtils
import com.android.settings.core.instrumentation.SettingsStatsLog
import com.android.settingslib.spa.framework.common.LOG_DATA_SESSION_NAME
import com.android.settingslib.spa.framework.common.LogCategory
import com.android.settingslib.spa.framework.common.LogEvent
import com.android.settingslib.spa.framework.common.SpaLogger
import com.android.settingslib.spa.framework.util.SESSION_BROWSE
import com.android.settingslib.spa.framework.util.SESSION_EXTERNAL
import com.android.settingslib.spa.framework.util.SESSION_SEARCH
import com.android.settingslib.spa.framework.util.SESSION_SLICE
import com.android.settingslib.spa.framework.util.SESSION_UNKNOWN
/**
* To receive the events from spa framework and logging the these events.
*/
object SpaLogProvider : SpaLogger {
private val dataModel = MetricsDataModel()
override fun event(id: String, event: LogEvent, category: LogCategory, extraData: Bundle) {
when(event) {
LogEvent.PAGE_ENTER, LogEvent.PAGE_LEAVE ->
write(SpaLogData(id, event, extraData, dataModel))
else -> return //TODO(b/253979024): Will be implemented in subsequent CLs.
}
}
private fun write(data: SpaLogData) {
with(data) {
SettingsStatsLog.write(
SettingsStatsLog.SETTINGS_SPA_REPORTED /* atomName */,
getSessionType(),
getPageId(),
getTarget(),
getAction(),
getKey(),
getValue(),
getPreValue(),
getElapsedTime()
)
}
}
}
@VisibleForTesting
class SpaLogData(val id: String, val event: LogEvent,
val extraData: Bundle, val dataModel: MetricsDataModel) {
fun getSessionType(): Int {
if (!extraData.containsKey(LOG_DATA_SESSION_NAME)) {
return SettingsEnums.SESSION_UNKNOWN
}
val sessionSource = extraData.getString(LOG_DATA_SESSION_NAME)
return when(sessionSource) {
SESSION_BROWSE -> SettingsEnums.BROWSE
SESSION_SEARCH -> SettingsEnums.SEARCH
SESSION_SLICE -> SettingsEnums.SLICE_TYPE
SESSION_EXTERNAL -> SettingsEnums.EXTERNAL
else -> SettingsEnums.SESSION_UNKNOWN
}
}
fun getPageId(): String {
return when(event) {
LogEvent.PAGE_ENTER, LogEvent.PAGE_LEAVE -> id
else -> getPageIdByEntryId(id)
}
}
//TODO(b/253979024): Will be implemented in subsequent CLs.
fun getTarget(): String? {
return null
}
fun getAction(): Int {
return event.action
}
//TODO(b/253979024): Will be implemented in subsequent CLs.
fun getKey(): String? {
return null
}
fun getValue(): String? {
when(event) {
LogEvent.PAGE_ENTER -> dataModel.addTimeStamp(
PageTimeStamp(id, System.currentTimeMillis()))
LogEvent.PAGE_LEAVE -> return dataModel.getPageDuration(id)
else -> {} //TODO(b/253979024): Will be implemented in subsequent CLs.
}
return null
}
//TODO(b/253979024): Will be implemented in subsequent CLs.
fun getPreValue(): String? {
return null
}
fun getElapsedTime(): Long {
return ElapsedTimeUtils.getElapsedTime(System.currentTimeMillis())
}
//TODO(b/253979024): Will be implemented in subsequent CLs.
private fun getPageIdByEntryId(id: String): String {
return ""
}
}
/**
* The buffer is keeping the time stamp while spa page entering.
*/
data class PageTimeStamp(val pageId: String, val timeStamp: Long)