1 /*
2  * Copyright (C) 2020 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.systemui.assist
18 
19 import android.content.ComponentName
20 import android.content.Context
21 import android.content.pm.PackageManager
22 import android.util.Log
23 import com.android.internal.app.AssistUtils
24 import com.android.internal.logging.InstanceId
25 import com.android.internal.logging.InstanceIdSequence
26 import com.android.internal.logging.UiEventLogger
27 import com.android.internal.util.FrameworkStatsLog
28 import com.android.keyguard.KeyguardUpdateMonitor
29 import com.android.systemui.assist.AssistantInvocationEvent.Companion.deviceStateFromLegacyDeviceState
30 import com.android.systemui.assist.AssistantInvocationEvent.Companion.eventFromLegacyInvocationType
31 import javax.inject.Inject
32 import javax.inject.Singleton
33 
34 /** Class for reporting events related to Assistant sessions. */
35 @Singleton
36 open class AssistLogger @Inject constructor(
37     protected val context: Context,
38     protected val uiEventLogger: UiEventLogger,
39     private val assistUtils: AssistUtils,
40     private val phoneStateMonitor: PhoneStateMonitor,
41     private val assistHandleBehaviorController: AssistHandleBehaviorController
42 ) {
43 
44     private val instanceIdSequence = InstanceIdSequence(INSTANCE_ID_MAX)
45 
46     private var currentInstanceId: InstanceId? = null
47 
reportAssistantInvocationEventFromLegacynull48     fun reportAssistantInvocationEventFromLegacy(
49         legacyInvocationType: Int,
50         isInvocationComplete: Boolean,
51         assistantComponent: ComponentName? = null,
52         legacyDeviceState: Int? = null
53     ) {
54         val deviceState = if (legacyDeviceState == null) {
55             null
56         } else {
57             deviceStateFromLegacyDeviceState(legacyDeviceState)
58         }
59         reportAssistantInvocationEvent(
60                 eventFromLegacyInvocationType(legacyInvocationType, isInvocationComplete),
61                 assistantComponent,
62                 deviceState)
63     }
64 
reportAssistantInvocationEventnull65     fun reportAssistantInvocationEvent(
66         invocationEvent: UiEventLogger.UiEventEnum,
67         assistantComponent: ComponentName? = null,
68         deviceState: Int? = null
69     ) {
70 
71         val assistComponentFinal = assistantComponent ?: getAssistantComponentForCurrentUser()
72 
73         val assistantUid = getAssistantUid(assistComponentFinal)
74 
75         val deviceStateFinal = deviceState
76                 ?: deviceStateFromLegacyDeviceState(phoneStateMonitor.phoneState)
77 
78         FrameworkStatsLog.write(
79                 FrameworkStatsLog.ASSISTANT_INVOCATION_REPORTED,
80                 invocationEvent.id,
81                 assistantUid,
82                 assistComponentFinal.flattenToString(),
83                 getOrCreateInstanceId().id,
84                 deviceStateFinal,
85                 assistHandleBehaviorController.areHandlesShowing())
86         reportAssistantInvocationExtraData()
87     }
88 
reportAssistantSessionEventnull89     fun reportAssistantSessionEvent(sessionEvent: UiEventLogger.UiEventEnum) {
90         val assistantComponent = getAssistantComponentForCurrentUser()
91         val assistantUid = getAssistantUid(assistantComponent)
92         uiEventLogger.logWithInstanceId(
93                 sessionEvent,
94                 assistantUid,
95                 assistantComponent.flattenToString(),
96                 getOrCreateInstanceId())
97 
98         if (SESSION_END_EVENTS.contains(sessionEvent)) {
99             clearInstanceId()
100         }
101     }
102 
reportAssistantInvocationExtraDatanull103     protected open fun reportAssistantInvocationExtraData() {
104     }
105 
getOrCreateInstanceIdnull106     protected fun getOrCreateInstanceId(): InstanceId {
107         val instanceId = currentInstanceId ?: instanceIdSequence.newInstanceId()
108         currentInstanceId = instanceId
109         return instanceId
110     }
111 
clearInstanceIdnull112     protected fun clearInstanceId() {
113         currentInstanceId = null
114     }
115 
getAssistantComponentForCurrentUsernull116     protected fun getAssistantComponentForCurrentUser(): ComponentName {
117         return assistUtils.getAssistComponentForUser(KeyguardUpdateMonitor.getCurrentUser())
118     }
119 
getAssistantUidnull120     protected fun getAssistantUid(assistantComponent: ComponentName): Int {
121         var assistantUid = 0
122         try {
123             assistantUid = context.packageManager.getApplicationInfo(
124                     assistantComponent.packageName, /* flags = */
125                     0).uid
126         } catch (e: PackageManager.NameNotFoundException) {
127             Log.e(TAG, "Unable to find Assistant UID", e)
128         }
129         return assistantUid
130     }
131 
132     companion object {
133         protected const val TAG = "AssistLogger"
134 
135         private const val INSTANCE_ID_MAX = 1 shl 20
136 
137         private val SESSION_END_EVENTS =
138                 setOf(
139                         AssistantSessionEvent.ASSISTANT_SESSION_INVOCATION_CANCELLED,
140                         AssistantSessionEvent.ASSISTANT_SESSION_CLOSE)
141     }
142 }