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