1 /*
2  * Copyright (C) 2019 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.qs.logging
18 
19 import android.content.res.Configuration.ORIENTATION_LANDSCAPE
20 import android.content.res.Configuration.ORIENTATION_PORTRAIT
21 import android.content.res.Configuration.Orientation
22 import android.service.quicksettings.Tile
23 import android.view.View
24 import com.android.systemui.log.ConstantStringsLogger
25 import com.android.systemui.log.ConstantStringsLoggerImpl
26 import com.android.systemui.log.LogBuffer
27 import com.android.systemui.log.core.LogLevel.DEBUG
28 import com.android.systemui.log.core.LogLevel.ERROR
29 import com.android.systemui.log.core.LogLevel.VERBOSE
30 import com.android.systemui.log.dagger.QSConfigLog
31 import com.android.systemui.log.dagger.QSLog
32 import com.android.systemui.plugins.qs.QSTile
33 import com.android.systemui.statusbar.StatusBarState
34 import com.google.errorprone.annotations.CompileTimeConstant
35 import javax.inject.Inject
36 
37 private const val TAG = "QSLog"
38 
39 class QSLogger
40 @Inject
41 constructor(
42     @QSLog private val buffer: LogBuffer,
43     @QSConfigLog private val configChangedBuffer: LogBuffer,
44 ) : ConstantStringsLogger by ConstantStringsLoggerImpl(buffer, TAG) {
45 
46     fun logException(@CompileTimeConstant logMsg: String, ex: Exception) {
47         buffer.log(TAG, ERROR, {}, { logMsg }, exception = ex)
48     }
49 
50     fun v(@CompileTimeConstant msg: String, arg: Any) {
51         buffer.log(TAG, VERBOSE, { str1 = arg.toString() }, { "$msg: $str1" })
52     }
53 
54     fun d(@CompileTimeConstant msg: String, arg: Any) {
55         buffer.log(TAG, DEBUG, { str1 = arg.toString() }, { "$msg: $str1" })
56     }
57 
58     fun logTileAdded(tileSpec: String) {
59         buffer.log(TAG, DEBUG, { str1 = tileSpec }, { "[$str1] Tile added" })
60     }
61 
62     fun logTileDestroyed(tileSpec: String, reason: String) {
63         buffer.log(
64             TAG,
65             DEBUG,
66             {
67                 str1 = tileSpec
68                 str2 = reason
69             },
70             { "[$str1] Tile destroyed. Reason: $str2" }
71         )
72     }
73 
74     fun logTileChangeListening(tileSpec: String, listening: Boolean) {
75         buffer.log(
76             TAG,
77             VERBOSE,
78             {
79                 bool1 = listening
80                 str1 = tileSpec
81             },
82             { "[$str1] Tile listening=$bool1" }
83         )
84     }
85 
86     fun logAllTilesChangeListening(listening: Boolean, containerName: String, allSpecs: String) {
87         buffer.log(
88             TAG,
89             DEBUG,
90             {
91                 bool1 = listening
92                 str1 = containerName
93                 str2 = allSpecs
94             },
95             { "Tiles listening=$bool1 in $str1. $str2" }
96         )
97     }
98 
99     fun logTileClick(tileSpec: String, statusBarState: Int, state: Int, eventId: Int) {
100         buffer.log(
101             TAG,
102             DEBUG,
103             {
104                 str1 = tileSpec
105                 int1 = eventId
106                 str2 = StatusBarState.toString(statusBarState)
107                 str3 = toStateString(state)
108             },
109             { "[$str1][$int1] Tile clicked. StatusBarState=$str2. TileState=$str3" }
110         )
111     }
112 
113     fun logHandleClick(tileSpec: String, eventId: Int) {
114         buffer.log(
115             TAG,
116             DEBUG,
117             {
118                 str1 = tileSpec
119                 int1 = eventId
120             },
121             { "[$str1][$int1] Tile handling click." }
122         )
123     }
124 
125     fun logTileSecondaryClick(tileSpec: String, statusBarState: Int, state: Int, eventId: Int) {
126         buffer.log(
127             TAG,
128             DEBUG,
129             {
130                 str1 = tileSpec
131                 int1 = eventId
132                 str2 = StatusBarState.toString(statusBarState)
133                 str3 = toStateString(state)
134             },
135             { "[$str1][$int1] Tile secondary clicked. StatusBarState=$str2. TileState=$str3" }
136         )
137     }
138 
139     fun logHandleSecondaryClick(tileSpec: String, eventId: Int) {
140         buffer.log(
141             TAG,
142             DEBUG,
143             {
144                 str1 = tileSpec
145                 int1 = eventId
146             },
147             { "[$str1][$int1] Tile handling secondary click." }
148         )
149     }
150 
151     fun logTileLongClick(tileSpec: String, statusBarState: Int, state: Int, eventId: Int) {
152         buffer.log(
153             TAG,
154             DEBUG,
155             {
156                 str1 = tileSpec
157                 int1 = eventId
158                 str2 = StatusBarState.toString(statusBarState)
159                 str3 = toStateString(state)
160             },
161             { "[$str1][$int1] Tile long clicked. StatusBarState=$str2. TileState=$str3" }
162         )
163     }
164 
165     fun logHandleLongClick(tileSpec: String, eventId: Int) {
166         buffer.log(
167             TAG,
168             DEBUG,
169             {
170                 str1 = tileSpec
171                 int1 = eventId
172             },
173             { "[$str1][$int1] Tile handling long click." }
174         )
175     }
176 
177     fun logInternetTileUpdate(tileSpec: String, lastType: Int, callback: String) {
178         buffer.log(
179             TAG,
180             VERBOSE,
181             {
182                 str1 = tileSpec
183                 int1 = lastType
184                 str2 = callback
185             },
186             { "[$str1] mLastTileState=$int1, Callback=$str2." }
187         )
188     }
189 
190     // TODO(b/250618218): Remove this method once we know the root cause of b/250618218.
191     fun logTileBackgroundColorUpdateIfInternetTile(
192         tileSpec: String,
193         state: Int,
194         disabledByPolicy: Boolean,
195         color: Int
196     ) {
197         // This method is added to further debug b/250618218 which has only been observed from the
198         // InternetTile, so we are only logging the background color change for the InternetTile
199         // to avoid spamming the QSLogger.
200         if (tileSpec != "internet") {
201             return
202         }
203         buffer.log(
204             TAG,
205             VERBOSE,
206             {
207                 str1 = tileSpec
208                 int1 = state
209                 bool1 = disabledByPolicy
210                 int2 = color
211             },
212             { "[$str1] state=$int1, disabledByPolicy=$bool1, color=$int2." }
213         )
214     }
215 
216     fun logTileUpdated(tileSpec: String, state: QSTile.State) {
217         buffer.log(
218             TAG,
219             VERBOSE,
220             {
221                 str1 = tileSpec
222                 str2 = state.label?.toString()
223                 str3 = state.icon?.toString()
224                 int1 = state.state
225                 if (state is QSTile.SignalState) {
226                     bool1 = true
227                     bool2 = state.activityIn
228                     bool3 = state.activityOut
229                 }
230             },
231             {
232                 "[$str1] Tile updated. Label=$str2. State=$int1. Icon=$str3." +
233                     if (bool1) " Activity in/out=$bool2/$bool3" else ""
234             }
235         )
236     }
237 
238     fun logPanelExpanded(expanded: Boolean, containerName: String) {
239         buffer.log(
240             TAG,
241             DEBUG,
242             {
243                 str1 = containerName
244                 bool1 = expanded
245             },
246             { "$str1 expanded=$bool1" }
247         )
248     }
249 
250     fun logOnViewAttached(orientation: Int, containerName: String) {
251         buffer.log(
252             TAG,
253             DEBUG,
254             {
255                 str1 = containerName
256                 int1 = orientation
257             },
258             { "onViewAttached: $str1 orientation $int1" }
259         )
260     }
261 
262     fun logOnViewDetached(orientation: Int, containerName: String) {
263         buffer.log(
264             TAG,
265             DEBUG,
266             {
267                 str1 = containerName
268                 int1 = orientation
269             },
270             { "onViewDetached: $str1 orientation $int1" }
271         )
272     }
273 
274     fun logOnConfigurationChanged(
275         @Orientation oldOrientation: Int,
276         @Orientation newOrientation: Int,
277         newShouldUseSplitShade: Boolean,
278         oldShouldUseSplitShade: Boolean,
279         containerName: String
280     ) {
281         configChangedBuffer.log(
282             TAG,
283             DEBUG,
284             {
285                 str1 = containerName
286                 int1 = oldOrientation
287                 int2 = newOrientation
288                 bool1 = oldShouldUseSplitShade
289                 bool2 = newShouldUseSplitShade
290             },
291             {
292                 "config change: " +
293                     "$str1 orientation=${toOrientationString(int2)} " +
294                     "(was ${toOrientationString(int1)}), " +
295                     "splitShade=$bool2 (was $bool1)"
296             }
297         )
298     }
299 
300     fun logSwitchTileLayout(
301         after: Boolean,
302         before: Boolean,
303         force: Boolean,
304         containerName: String
305     ) {
306         buffer.log(
307             TAG,
308             DEBUG,
309             {
310                 str1 = containerName
311                 bool1 = after
312                 bool2 = before
313                 bool3 = force
314             },
315             { "change tile layout: $str1 horizontal=$bool1 (was $bool2), force? $bool3" }
316         )
317     }
318 
319     fun logTileDistributionInProgress(tilesPerPageCount: Int, totalTilesCount: Int) {
320         buffer.log(
321             TAG,
322             DEBUG,
323             {
324                 int1 = tilesPerPageCount
325                 int2 = totalTilesCount
326             },
327             { "Distributing tiles: [tilesPerPageCount=$int1] [totalTilesCount=$int2]" }
328         )
329     }
330 
331     fun logTileDistributed(tileName: String, pageIndex: Int) {
332         buffer.log(
333             TAG,
334             DEBUG,
335             {
336                 str1 = tileName
337                 int1 = pageIndex
338             },
339             { "Adding $str1 to page number $int1" }
340         )
341     }
342 
343     private fun toStateString(state: Int): String {
344         return when (state) {
345             Tile.STATE_ACTIVE -> "active"
346             Tile.STATE_INACTIVE -> "inactive"
347             Tile.STATE_UNAVAILABLE -> "unavailable"
348             else -> "wrong state"
349         }
350     }
351 
352     fun logVisibility(viewName: String, @View.Visibility visibility: Int) {
353         buffer.log(
354             TAG,
355             DEBUG,
356             {
357                 str1 = viewName
358                 str2 = toVisibilityString(visibility)
359             },
360             { "$str1 visibility: $str2" }
361         )
362     }
363 
364     private fun toVisibilityString(visibility: Int): String {
365         return when (visibility) {
366             View.VISIBLE -> "VISIBLE"
367             View.INVISIBLE -> "INVISIBLE"
368             View.GONE -> "GONE"
369             else -> "undefined"
370         }
371     }
372 }
373 
374 private inline fun toOrientationString(@Orientation orientation: Int): String {
375     return when (orientation) {
376         ORIENTATION_LANDSCAPE -> "land"
377         ORIENTATION_PORTRAIT -> "port"
378         else -> "undefined"
379     }
380 }
381