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.disableflags 17 18 import android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS 19 import android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE 20 import android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS 21 import android.app.StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS 22 import android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS 23 import android.app.StatusBarManager.DISABLE_BACK 24 import android.app.StatusBarManager.DISABLE_CLOCK 25 import android.app.StatusBarManager.DISABLE_EXPAND 26 import android.app.StatusBarManager.DISABLE_HOME 27 import android.app.StatusBarManager.DISABLE_NOTIFICATION_ALERTS 28 import android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS 29 import android.app.StatusBarManager.DISABLE_ONGOING_CALL_CHIP 30 import android.app.StatusBarManager.DISABLE_RECENT 31 import android.app.StatusBarManager.DISABLE_SEARCH 32 import android.app.StatusBarManager.DISABLE_SYSTEM_INFO 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 new and new-after-modification disable flag states, 75 * as well as the differences between them (if there are any). 76 * 77 * Example if [new] and [newAfterLocalModification] are different: 78 * New: EnaihBcRso.qiNGR | New after local modification: EnaihBCRso.qInGR (changed: C.In) 79 * 80 * Example if [new] and [newAfterLocalModification] are the same: 81 * New: EnaihBcRso.qiNGR 82 * 83 * A capital character signifies the flag is set and a lowercase character signifies that the 84 * flag isn't set. The flag states will be logged in the same order as the passed-in lists. 85 * 86 * The difference between states is written between parentheses, and won't be included if there 87 * is no difference. the new-after-modification state also won't be included if there's no 88 * difference from the new state. 89 * 90 * @param new the new disable state that has just been sent. 91 * @param newAfterLocalModification the new disable states after a class has locally modified 92 * them. Null if the class does not locally modify. 93 */ getDisableFlagsStringnull94 fun getDisableFlagsString( 95 new: DisableState, 96 newAfterLocalModification: DisableState? = null 97 ): String { 98 val builder = StringBuilder("Received new disable state: ") 99 100 builder.append(getFlagsString(new)) 101 102 if (newAfterLocalModification != null && new != newAfterLocalModification) { 103 builder.append(" | New after local modification: ") 104 builder.append(getFlagsString(newAfterLocalModification)) 105 builder.append(" ") 106 builder.append(getDiffString(new, newAfterLocalModification)) 107 } 108 109 return builder.toString() 110 } 111 112 /** 113 * Returns a string representing the difference between [old] and [new]. 114 * 115 * - If [old] was "abc.DE" and [new] was "aBC.De", the difference returned would be 116 * "(changed: BC.e)". 117 * - If [old] and [new] are the same, the difference returned would be "(unchanged)". 118 */ getDiffStringnull119 private fun getDiffString(old: DisableState, new: DisableState): String { 120 if (old == new) { 121 return "(unchanged)" 122 } 123 124 val builder = StringBuilder("(") 125 builder.append("changed: ") 126 disable1FlagsList.forEach { 127 val newSymbol = it.getFlagStatus(new.disable1) 128 if (it.getFlagStatus(old.disable1) != newSymbol) { 129 builder.append(newSymbol) 130 } 131 } 132 builder.append(".") 133 disable2FlagsList.forEach { 134 val newSymbol = it.getFlagStatus(new.disable2) 135 if (it.getFlagStatus(old.disable2) != newSymbol) { 136 builder.append(newSymbol) 137 } 138 } 139 builder.append(")") 140 return builder.toString() 141 } 142 143 /** Returns a string representing the disable flag states, e.g. "EnaihBcRso.qiNGR". */ getFlagsStringnull144 private fun getFlagsString(state: DisableState): String { 145 val builder = StringBuilder("") 146 disable1FlagsList.forEach { builder.append(it.getFlagStatus(state.disable1)) } 147 builder.append(".") 148 disable2FlagsList.forEach { builder.append(it.getFlagStatus(state.disable2)) } 149 return builder.toString() 150 } 151 152 /** A POJO representing each disable flag. */ 153 class DisableFlag( 154 private val bitMask: Int, 155 private val flagIsSetSymbol: Char, 156 private val flagNotSetSymbol: Char 157 ) { 158 159 /** 160 * Returns a character representing whether or not this flag is set in [state]. 161 * 162 * A capital character signifies the flag is set and a lowercase character signifies that 163 * the flag isn't set. 164 */ getFlagStatusnull165 internal fun getFlagStatus(state: Int): Char = 166 if (0 != state and this.bitMask) this.flagIsSetSymbol 167 else this.flagNotSetSymbol 168 } 169 170 /** POJO to hold [disable1] and [disable2]. */ 171 data class DisableState(val disable1: Int, val disable2: Int) 172 } 173 174 // LINT.IfChange 175 private val defaultDisable1FlagsList: List<DisableFlagsLogger.DisableFlag> = listOf( 176 DisableFlagsLogger.DisableFlag(DISABLE_EXPAND, 'E', 'e'), 177 DisableFlagsLogger.DisableFlag(DISABLE_NOTIFICATION_ICONS, 'N', 'n'), 178 DisableFlagsLogger.DisableFlag(DISABLE_NOTIFICATION_ALERTS, 'A', 'a'), 179 DisableFlagsLogger.DisableFlag(DISABLE_SYSTEM_INFO, 'I', 'i'), 180 DisableFlagsLogger.DisableFlag(DISABLE_HOME, 'H', 'h'), 181 DisableFlagsLogger.DisableFlag(DISABLE_BACK, 'B', 'b'), 182 DisableFlagsLogger.DisableFlag(DISABLE_CLOCK, 'C', 'c'), 183 DisableFlagsLogger.DisableFlag(DISABLE_RECENT, 'R', 'r'), 184 DisableFlagsLogger.DisableFlag(DISABLE_SEARCH, 'S', 's'), 185 DisableFlagsLogger.DisableFlag(DISABLE_ONGOING_CALL_CHIP, 'O', 'o') 186 ) 187 188 private val defaultDisable2FlagsList: List<DisableFlagsLogger.DisableFlag> = listOf( 189 DisableFlagsLogger.DisableFlag(DISABLE2_QUICK_SETTINGS, 'Q', 'q'), 190 DisableFlagsLogger.DisableFlag(DISABLE2_SYSTEM_ICONS, 'I', 'i'), 191 DisableFlagsLogger.DisableFlag(DISABLE2_NOTIFICATION_SHADE, 'N', 'n'), 192 DisableFlagsLogger.DisableFlag(DISABLE2_GLOBAL_ACTIONS, 'G', 'g'), 193 DisableFlagsLogger.DisableFlag(DISABLE2_ROTATE_SUGGESTIONS, 'R', 'r') 194 ) 195 // LINT.ThenChange(frameworks/base/core/java/android/app/StatusBarManager.java) 196