1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.spa.core.instrumentation
18 
19 import android.app.settings.SettingsEnums
20 import android.os.Bundle
21 import androidx.annotation.VisibleForTesting
22 import com.android.settings.core.instrumentation.ElapsedTimeUtils
23 import com.android.settings.core.instrumentation.SettingsStatsLog
24 import com.android.settingslib.spa.framework.common.LOG_DATA_SESSION_NAME
25 import com.android.settingslib.spa.framework.common.LogCategory
26 import com.android.settingslib.spa.framework.common.LogEvent
27 import com.android.settingslib.spa.framework.common.SpaLogger
28 import com.android.settingslib.spa.framework.util.SESSION_BROWSE
29 import com.android.settingslib.spa.framework.util.SESSION_EXTERNAL
30 import com.android.settingslib.spa.framework.util.SESSION_SEARCH
31 import com.android.settingslib.spa.framework.util.SESSION_SLICE
32 import com.android.settingslib.spa.framework.util.SESSION_UNKNOWN
33 
34 /**
35  * To receive the events from spa framework and logging the these events.
36  */
37 object SpaLogProvider : SpaLogger {
38     private val dataModel = MetricsDataModel()
39 
eventnull40     override fun event(id: String, event: LogEvent, category: LogCategory, extraData: Bundle) {
41         when(event) {
42             LogEvent.PAGE_ENTER, LogEvent.PAGE_LEAVE ->
43                 write(SpaLogData(id, event, extraData, dataModel))
44             else -> return  //TODO(b/253979024): Will be implemented in subsequent CLs.
45         }
46     }
47 
writenull48     private fun write(data: SpaLogData) {
49         with(data) {
50             SettingsStatsLog.write(
51                 SettingsStatsLog.SETTINGS_SPA_REPORTED /* atomName */,
52                 getSessionType(),
53                 getPageId(),
54                 getTarget(),
55                 getAction(),
56                 getKey(),
57                 getValue(),
58                 getPreValue(),
59                 getElapsedTime()
60             )
61         }
62     }
63 }
64 
65 @VisibleForTesting
66 class SpaLogData(val id: String, val event: LogEvent,
67                          val extraData: Bundle, val dataModel: MetricsDataModel) {
68 
getSessionTypenull69     fun getSessionType(): Int {
70         if (!extraData.containsKey(LOG_DATA_SESSION_NAME)) {
71             return SettingsEnums.SESSION_UNKNOWN
72         }
73         val sessionSource = extraData.getString(LOG_DATA_SESSION_NAME)
74         return when(sessionSource) {
75             SESSION_BROWSE -> SettingsEnums.SESSION_BROWSE
76             SESSION_SEARCH -> SettingsEnums.SESSION_SEARCH
77             SESSION_SLICE -> SettingsEnums.SESSION_SLICE_TYPE
78             SESSION_EXTERNAL -> SettingsEnums.SESSION_EXTERNAL
79             else -> SettingsEnums.SESSION_UNKNOWN
80         }
81     }
82 
getPageIdnull83     fun getPageId(): String {
84         return when(event) {
85             LogEvent.PAGE_ENTER, LogEvent.PAGE_LEAVE -> id
86             else -> getPageIdByEntryId(id)
87         }
88     }
89 
90     //TODO(b/253979024): Will be implemented in subsequent CLs.
getTargetnull91     fun getTarget(): String? {
92         return null
93     }
94 
getActionnull95     fun getAction(): Int = when (event) {
96         LogEvent.PAGE_ENTER -> SettingsEnums.PAGE_VISIBLE
97         LogEvent.PAGE_LEAVE -> SettingsEnums.PAGE_HIDE
98         LogEvent.ENTRY_CLICK -> SettingsEnums.ACTION_SETTINGS_TILE_CLICK
99         LogEvent.ENTRY_SWITCH -> SettingsEnums.ACTION_SETTINGS_PREFERENCE_CHANGE
100     }
101 
102     //TODO(b/253979024): Will be implemented in subsequent CLs.
getKeynull103     fun getKey(): String? {
104         return null
105     }
106 
getValuenull107     fun getValue(): String? {
108         when(event) {
109             LogEvent.PAGE_ENTER -> dataModel.addTimeStamp(
110                 PageTimeStamp(id, System.currentTimeMillis()))
111             LogEvent.PAGE_LEAVE -> return dataModel.getPageDuration(id)
112             else -> {} //TODO(b/253979024): Will be implemented in subsequent CLs.
113         }
114         return null
115     }
116 
117     //TODO(b/253979024): Will be implemented in subsequent CLs.
getPreValuenull118     fun getPreValue(): String? {
119         return null
120     }
121 
getElapsedTimenull122     fun getElapsedTime(): Long {
123         return ElapsedTimeUtils.getElapsedTime(System.currentTimeMillis())
124     }
125 
126     //TODO(b/253979024): Will be implemented in subsequent CLs. Remove @Suppress when done.
getPageIdByEntryIdnull127     private fun getPageIdByEntryId(@Suppress("UNUSED_PARAMETER") id: String): String {
128         return ""
129     }
130 }
131 
132 /**
133  * The buffer is keeping the time stamp while spa page entering.
134  */
135 data class PageTimeStamp(val pageId: String, val timeStamp: Long)
136