1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5 * except in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 11 * KIND, either express or implied. See the License for the specific language governing 12 * permissions and limitations under the License. 13 */ 14 15 package com.android.systemui.plugins.qs; 16 17 import android.content.Context; 18 import android.graphics.drawable.Drawable; 19 import android.metrics.LogMaker; 20 import android.service.quicksettings.Tile; 21 22 import com.android.systemui.plugins.annotations.DependsOn; 23 import com.android.systemui.plugins.annotations.ProvidesInterface; 24 import com.android.systemui.plugins.qs.QSTile.Callback; 25 import com.android.systemui.plugins.qs.QSTile.Icon; 26 import com.android.systemui.plugins.qs.QSTile.State; 27 28 import java.util.Objects; 29 import java.util.function.Supplier; 30 31 @ProvidesInterface(version = QSTile.VERSION) 32 @DependsOn(target = QSIconView.class) 33 @DependsOn(target = DetailAdapter.class) 34 @DependsOn(target = Callback.class) 35 @DependsOn(target = Icon.class) 36 @DependsOn(target = State.class) 37 public interface QSTile { 38 int VERSION = 1; 39 40 DetailAdapter getDetailAdapter(); 41 String getTileSpec(); 42 43 boolean isAvailable(); 44 void setTileSpec(String tileSpec); 45 46 void clearState(); 47 void refreshState(); 48 49 void addCallback(Callback callback); 50 void removeCallback(Callback callback); 51 void removeCallbacks(); 52 53 QSIconView createTileView(Context context); 54 55 void click(); 56 void secondaryClick(); 57 void longClick(); 58 59 void userSwitch(int currentUser); 60 int getMetricsCategory(); 61 62 void setListening(Object client, boolean listening); 63 void setDetailListening(boolean show); 64 65 void destroy(); 66 67 CharSequence getTileLabel(); 68 69 State getState(); 70 71 default LogMaker populate(LogMaker logMaker) { 72 return logMaker; 73 } 74 75 @ProvidesInterface(version = Callback.VERSION) 76 public interface Callback { 77 public static final int VERSION = 1; 78 void onStateChanged(State state); 79 void onShowDetail(boolean show); 80 void onToggleStateChanged(boolean state); 81 void onScanStateChanged(boolean state); 82 void onAnnouncementRequested(CharSequence announcement); 83 } 84 85 @ProvidesInterface(version = Icon.VERSION) 86 public static abstract class Icon { 87 public static final int VERSION = 1; 88 abstract public Drawable getDrawable(Context context); 89 90 public Drawable getInvisibleDrawable(Context context) { 91 return getDrawable(context); 92 } 93 94 @Override 95 public int hashCode() { 96 return Icon.class.hashCode(); 97 } 98 99 public int getPadding() { 100 return 0; 101 } 102 } 103 104 @ProvidesInterface(version = State.VERSION) 105 public static class State { 106 public static final int VERSION = 1; 107 public Icon icon; 108 public Supplier<Icon> iconSupplier; 109 public int state = Tile.STATE_ACTIVE; 110 public CharSequence label; 111 public CharSequence contentDescription; 112 public CharSequence dualLabelContentDescription; 113 public boolean disabledByPolicy; 114 public boolean dualTarget = false; 115 public boolean isTransient = false; 116 public String expandedAccessibilityClassName; 117 public SlashState slash; 118 119 public boolean copyTo(State other) { 120 if (other == null) throw new IllegalArgumentException(); 121 if (!other.getClass().equals(getClass())) throw new IllegalArgumentException(); 122 final boolean changed = !Objects.equals(other.icon, icon) 123 || !Objects.equals(other.iconSupplier, iconSupplier) 124 || !Objects.equals(other.label, label) 125 || !Objects.equals(other.contentDescription, contentDescription) 126 || !Objects.equals(other.dualLabelContentDescription, 127 dualLabelContentDescription) 128 || !Objects.equals(other.expandedAccessibilityClassName, 129 expandedAccessibilityClassName) 130 || !Objects.equals(other.disabledByPolicy, disabledByPolicy) 131 || !Objects.equals(other.state, state) 132 || !Objects.equals(other.isTransient, isTransient) 133 || !Objects.equals(other.dualTarget, dualTarget) 134 || !Objects.equals(other.slash, slash); 135 other.icon = icon; 136 other.iconSupplier = iconSupplier; 137 other.label = label; 138 other.contentDescription = contentDescription; 139 other.dualLabelContentDescription = dualLabelContentDescription; 140 other.expandedAccessibilityClassName = expandedAccessibilityClassName; 141 other.disabledByPolicy = disabledByPolicy; 142 other.state = state; 143 other.dualTarget = dualTarget; 144 other.isTransient = isTransient; 145 other.slash = slash != null ? slash.copy() : null; 146 return changed; 147 } 148 149 @Override 150 public String toString() { 151 return toStringBuilder().toString(); 152 } 153 154 protected StringBuilder toStringBuilder() { 155 final StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('['); 156 sb.append(",icon=").append(icon); 157 sb.append(",iconSupplier=").append(iconSupplier); 158 sb.append(",label=").append(label); 159 sb.append(",contentDescription=").append(contentDescription); 160 sb.append(",dualLabelContentDescription=").append(dualLabelContentDescription); 161 sb.append(",expandedAccessibilityClassName=").append(expandedAccessibilityClassName); 162 sb.append(",disabledByPolicy=").append(disabledByPolicy); 163 sb.append(",dualTarget=").append(dualTarget); 164 sb.append(",isTransient=").append(isTransient); 165 sb.append(",state=").append(state); 166 sb.append(",slash=\"").append(slash).append("\""); 167 return sb.append(']'); 168 } 169 170 public State copy() { 171 State state = new State(); 172 copyTo(state); 173 return state; 174 } 175 } 176 177 @ProvidesInterface(version = BooleanState.VERSION) 178 public static class BooleanState extends State { 179 public static final int VERSION = 1; 180 public boolean value; 181 182 @Override 183 public boolean copyTo(State other) { 184 final BooleanState o = (BooleanState) other; 185 final boolean changed = super.copyTo(other) || o.value != value; 186 o.value = value; 187 return changed; 188 } 189 190 @Override 191 protected StringBuilder toStringBuilder() { 192 final StringBuilder rt = super.toStringBuilder(); 193 rt.insert(rt.length() - 1, ",value=" + value); 194 return rt; 195 } 196 197 @Override 198 public State copy() { 199 BooleanState state = new BooleanState(); 200 copyTo(state); 201 return state; 202 } 203 } 204 205 @ProvidesInterface(version = SignalState.VERSION) 206 public static final class SignalState extends BooleanState { 207 public static final int VERSION = 1; 208 public boolean activityIn; 209 public boolean activityOut; 210 public boolean isOverlayIconWide; 211 public int overlayIconId; 212 213 @Override 214 public boolean copyTo(State other) { 215 final SignalState o = (SignalState) other; 216 final boolean changed = o.activityIn != activityIn 217 || o.activityOut != activityOut 218 || o.isOverlayIconWide != isOverlayIconWide 219 || o.overlayIconId != overlayIconId; 220 o.activityIn = activityIn; 221 o.activityOut = activityOut; 222 o.isOverlayIconWide = isOverlayIconWide; 223 o.overlayIconId = overlayIconId; 224 return super.copyTo(other) || changed; 225 } 226 227 @Override 228 protected StringBuilder toStringBuilder() { 229 final StringBuilder rt = super.toStringBuilder(); 230 rt.insert(rt.length() - 1, ",activityIn=" + activityIn); 231 rt.insert(rt.length() - 1, ",activityOut=" + activityOut); 232 return rt; 233 } 234 235 @Override 236 public State copy() { 237 SignalState state = new SignalState(); 238 copyTo(state); 239 return state; 240 } 241 } 242 243 244 @ProvidesInterface(version = AirplaneBooleanState.VERSION) 245 public static class AirplaneBooleanState extends BooleanState { 246 public static final int VERSION = 1; 247 public boolean isAirplaneMode; 248 249 @Override 250 public boolean copyTo(State other) { 251 final AirplaneBooleanState o = (AirplaneBooleanState) other; 252 final boolean changed = super.copyTo(other) || o.isAirplaneMode != isAirplaneMode; 253 o.isAirplaneMode = isAirplaneMode; 254 return changed; 255 } 256 257 public State copy() { 258 AirplaneBooleanState state = new AirplaneBooleanState(); 259 copyTo(state); 260 return state; 261 } 262 } 263 264 @ProvidesInterface(version = SlashState.VERSION) 265 public static class SlashState { 266 public static final int VERSION = 2; 267 268 public boolean isSlashed; 269 public float rotation; 270 271 @Override 272 public String toString() { 273 return "isSlashed=" + isSlashed + ",rotation=" + rotation; 274 } 275 276 @Override 277 public boolean equals(Object o) { 278 if (o == null) return false; 279 try { 280 return (((SlashState) o).rotation == rotation) 281 && (((SlashState) o).isSlashed == isSlashed); 282 } catch (ClassCastException e) { 283 return false; 284 } 285 } 286 287 public SlashState copy() { 288 SlashState state = new SlashState(); 289 state.rotation = rotation; 290 state.isSlashed = isSlashed; 291 return state; 292 } 293 } 294 } 295