• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 package com.android.systemui.statusbar
17 
18 import android.app.StatusBarManager.DISABLE_BACK
19 import android.app.StatusBarManager.DISABLE_CLOCK
20 import android.app.StatusBarManager.DISABLE_EXPAND
21 import android.app.StatusBarManager.DISABLE_HOME
22 import android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS
23 import android.app.StatusBarManager.DISABLE_NOTIFICATION_ALERTS
24 import android.app.StatusBarManager.DISABLE_ONGOING_CALL_CHIP
25 import android.app.StatusBarManager.DISABLE_RECENT
26 import android.app.StatusBarManager.DISABLE_SEARCH
27 import android.app.StatusBarManager.DISABLE_SYSTEM_INFO
28 import android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS
29 import android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE
30 import android.app.StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS
31 import android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS
32 import android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS
33 import com.android.systemui.dagger.SysUISingleton
34 import javax.inject.Inject
35 
36 /**
37  * A singleton that creates concise but readable strings representing the values of the disable
38  * flags for debugging.
39  *
40  * See [CommandQueue.disable] for information about disable flags.
41  *
42  * Note that, for both lists passed in, each flag must have a distinct [DisableFlag.flagIsSetSymbol]
43  * and distinct [DisableFlag.flagNotSetSymbol] within the list. If this isn't true, the logs could
44  * be ambiguous so an [IllegalArgumentException] is thrown.
45  */
46 @SysUISingleton
47 class DisableFlagsLogger constructor(
48     private val disable1FlagsList: List<DisableFlag>,
49     private val disable2FlagsList: List<DisableFlag>
50 ) {
51 
52     @Inject
53     constructor() : this(defaultDisable1FlagsList, defaultDisable2FlagsList)
54 
55     init {
56         if (flagsListHasDuplicateSymbols(disable1FlagsList)) {
57             throw IllegalArgumentException("disable1 flags must have unique symbols")
58         }
59         if (flagsListHasDuplicateSymbols(disable2FlagsList)) {
60             throw IllegalArgumentException("disable2 flags must have unique symbols")
61         }
62     }
63 
flagsListHasDuplicateSymbolsnull64     private fun flagsListHasDuplicateSymbols(list: List<DisableFlag>): Boolean {
65         val numDistinctFlagOffStatus = list.map { it.getFlagStatus(0) }.distinct().count()
66         val numDistinctFlagOnStatus = list
67                 .map { it.getFlagStatus(Int.MAX_VALUE) }
68                 .distinct()
69                 .count()
70         return numDistinctFlagOffStatus < list.count() || numDistinctFlagOnStatus < list.count()
71     }
72 
73     /**
74      * Returns a string representing the, old, new, and new-after-modification disable flag states,
75      * as well as the differences between each of the states.
76      *
77      * Example if [old], [new], and [newAfterLocalModification] are all different:
78      *   Old: EnaiHbcRso.qINgr | New: EnaihBcRso.qiNGR (changed: hB.iGR) | New after local
79      *   modification: EnaihBcRso.qInGR (changed: .n)
80      *
81      * Example if [old] and [new] are the same:
82      *   EnaihBcRso.qiNGR (unchanged)
83      *
84      * A capital character signifies the flag is set and a lowercase character signifies that the
85      * flag isn't set. The flag states will be logged in the same order as the passed-in lists.
86      *
87      * The difference between states is written between parentheses, and won't be included if there
88      * is no difference. the new-after-modification state also won't be included if there's no
89      * difference from the new state.
90      *
91      * @param old the disable state that had been previously sent. Null if we don't need to log the
92      *   previously sent state.
93      * @param new the new disable state that has just been sent.
94      * @param newAfterLocalModification the new disable states after a class has locally modified
95      *   them. Null if the class does not locally modify.
96      */
getDisableFlagsStringnull97     fun getDisableFlagsString(
98         old: DisableState? = null,
99         new: DisableState,
100         newAfterLocalModification: DisableState? = null
101     ): String {
102         val builder = StringBuilder("Received new disable state: ")
103 
104         // This if/else has slightly repetitive code but is easier to read.
105         if (old != null && old != new) {
106             builder.append("Old: ")
107             builder.append(getFlagsString(old))
108             builder.append(" | ")
109             builder.append("New: ")
110             builder.append(getFlagsString(new))
111             builder.append(" ")
112             builder.append(getDiffString(old, new))
113         } else if (old != null && old == new) {
114             // If old and new are the same, we only need to print one of them.
115             builder.append(getFlagsString(new))
116             builder.append(" ")
117             builder.append(getDiffString(old, new))
118         } else { // old == null
119             builder.append(getFlagsString(new))
120             // Don't get a diff string because we have no [old] to compare with.
121         }
122 
123         if (newAfterLocalModification != null && new != newAfterLocalModification) {
124             builder.append(" | New after local modification: ")
125             builder.append(getFlagsString(newAfterLocalModification))
126             builder.append(" ")
127             builder.append(getDiffString(new, newAfterLocalModification))
128         }
129 
130         return builder.toString()
131     }
132 
133     /**
134      * Returns a string representing the difference between [old] and [new].
135      *
136      * - If [old] was "abc.DE" and [new] was "aBC.De", the difference returned would be
137      *   "(changed: BC.e)".
138      * - If [old] and [new] are the same, the difference returned would be "(unchanged)".
139      */
getDiffStringnull140     private fun getDiffString(old: DisableState, new: DisableState): String {
141         if (old == new) {
142             return "(unchanged)"
143         }
144 
145         val builder = StringBuilder("(")
146         builder.append("changed: ")
147         disable1FlagsList.forEach {
148             val newSymbol = it.getFlagStatus(new.disable1)
149             if (it.getFlagStatus(old.disable1) != newSymbol) {
150                 builder.append(newSymbol)
151             }
152         }
153         builder.append(".")
154         disable2FlagsList.forEach {
155             val newSymbol = it.getFlagStatus(new.disable2)
156             if (it.getFlagStatus(old.disable2) != newSymbol) {
157                 builder.append(newSymbol)
158             }
159         }
160         builder.append(")")
161         return builder.toString()
162     }
163 
164     /** Returns a string representing the disable flag states, e.g. "EnaihBcRso.qiNGR".  */
getFlagsStringnull165     private fun getFlagsString(state: DisableState): String {
166         val builder = StringBuilder("")
167         disable1FlagsList.forEach { builder.append(it.getFlagStatus(state.disable1)) }
168         builder.append(".")
169         disable2FlagsList.forEach { builder.append(it.getFlagStatus(state.disable2)) }
170         return builder.toString()
171     }
172 
173     /** A POJO representing each disable flag. */
174     class DisableFlag(
175         private val bitMask: Int,
176         private val flagIsSetSymbol: Char,
177         private val flagNotSetSymbol: Char
178     ) {
179 
180         /**
181          * Returns a character representing whether or not this flag is set in [state].
182          *
183          * A capital character signifies the flag is set and a lowercase character signifies that
184          * the flag isn't set.
185          */
getFlagStatusnull186         internal fun getFlagStatus(state: Int): Char =
187             if (0 != state and this.bitMask) this.flagIsSetSymbol
188             else this.flagNotSetSymbol
189     }
190 
191     /** POJO to hold [disable1] and [disable2]. */
192     data class DisableState(val disable1: Int, val disable2: Int)
193 }
194 
195 // LINT.IfChange
196 private val defaultDisable1FlagsList: List<DisableFlagsLogger.DisableFlag> = listOf(
197         DisableFlagsLogger.DisableFlag(DISABLE_EXPAND, 'E', 'e'),
198         DisableFlagsLogger.DisableFlag(DISABLE_NOTIFICATION_ICONS, 'N', 'n'),
199         DisableFlagsLogger.DisableFlag(DISABLE_NOTIFICATION_ALERTS, 'A', 'a'),
200         DisableFlagsLogger.DisableFlag(DISABLE_SYSTEM_INFO, 'I', 'i'),
201         DisableFlagsLogger.DisableFlag(DISABLE_HOME, 'H', 'h'),
202         DisableFlagsLogger.DisableFlag(DISABLE_BACK, 'B', 'b'),
203         DisableFlagsLogger.DisableFlag(DISABLE_CLOCK, 'C', 'c'),
204         DisableFlagsLogger.DisableFlag(DISABLE_RECENT, 'R', 'r'),
205         DisableFlagsLogger.DisableFlag(DISABLE_SEARCH, 'S', 's'),
206         DisableFlagsLogger.DisableFlag(DISABLE_ONGOING_CALL_CHIP, 'O', 'o')
207 )
208 
209 private val defaultDisable2FlagsList: List<DisableFlagsLogger.DisableFlag> = listOf(
210         DisableFlagsLogger.DisableFlag(DISABLE2_QUICK_SETTINGS, 'Q', 'q'),
211         DisableFlagsLogger.DisableFlag(DISABLE2_SYSTEM_ICONS, 'I', 'i'),
212         DisableFlagsLogger.DisableFlag(DISABLE2_NOTIFICATION_SHADE, 'N', 'n'),
213         DisableFlagsLogger.DisableFlag(DISABLE2_GLOBAL_ACTIONS, 'G', 'g'),
214         DisableFlagsLogger.DisableFlag(DISABLE2_ROTATE_SUGGESTIONS, 'R', 'r')
215 )
216 // LINT.ThenChange(frameworks/base/core/java/android/app/StatusBarManager.java)