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.annotation.NonNull; 18 import android.content.Context; 19 import android.graphics.drawable.Drawable; 20 import android.metrics.LogMaker; 21 import android.service.quicksettings.Tile; 22 23 import com.android.internal.logging.InstanceId; 24 import com.android.systemui.plugins.annotations.DependsOn; 25 import com.android.systemui.plugins.annotations.ProvidesInterface; 26 import com.android.systemui.plugins.qs.QSTile.Callback; 27 import com.android.systemui.plugins.qs.QSTile.Icon; 28 import com.android.systemui.plugins.qs.QSTile.State; 29 30 import java.util.Objects; 31 import java.util.function.Supplier; 32 33 @ProvidesInterface(version = QSTile.VERSION) 34 @DependsOn(target = QSIconView.class) 35 @DependsOn(target = DetailAdapter.class) 36 @DependsOn(target = Callback.class) 37 @DependsOn(target = Icon.class) 38 @DependsOn(target = State.class) 39 public interface QSTile { 40 int VERSION = 1; 41 getDetailAdapter()42 DetailAdapter getDetailAdapter(); getTileSpec()43 String getTileSpec(); 44 isAvailable()45 boolean isAvailable(); setTileSpec(String tileSpec)46 void setTileSpec(String tileSpec); 47 clearState()48 @Deprecated default void clearState() {} refreshState()49 void refreshState(); 50 addCallback(Callback callback)51 void addCallback(Callback callback); removeCallback(Callback callback)52 void removeCallback(Callback callback); removeCallbacks()53 void removeCallbacks(); 54 createTileView(Context context)55 QSIconView createTileView(Context context); 56 click()57 void click(); secondaryClick()58 void secondaryClick(); longClick()59 void longClick(); 60 userSwitch(int currentUser)61 void userSwitch(int currentUser); getMetricsCategory()62 int getMetricsCategory(); 63 setListening(Object client, boolean listening)64 void setListening(Object client, boolean listening); setDetailListening(boolean show)65 void setDetailListening(boolean show); 66 destroy()67 void destroy(); 68 getTileLabel()69 CharSequence getTileLabel(); 70 getState()71 State getState(); 72 populate(LogMaker logMaker)73 default LogMaker populate(LogMaker logMaker) { 74 return logMaker; 75 } 76 77 /** 78 * Return a string to be used to identify the tile in UiEvents. 79 */ getMetricsSpec()80 default String getMetricsSpec() { 81 return getClass().getSimpleName(); 82 } 83 84 /** 85 * Return an {@link InstanceId} to be used to identify the tile in UiEvents. 86 */ getInstanceId()87 InstanceId getInstanceId(); 88 89 @ProvidesInterface(version = Callback.VERSION) 90 public interface Callback { 91 public static final int VERSION = 1; onStateChanged(State state)92 void onStateChanged(State state); onShowDetail(boolean show)93 void onShowDetail(boolean show); onToggleStateChanged(boolean state)94 void onToggleStateChanged(boolean state); onScanStateChanged(boolean state)95 void onScanStateChanged(boolean state); onAnnouncementRequested(CharSequence announcement)96 void onAnnouncementRequested(CharSequence announcement); 97 } 98 99 @ProvidesInterface(version = Icon.VERSION) 100 public static abstract class Icon { 101 public static final int VERSION = 1; getDrawable(Context context)102 abstract public Drawable getDrawable(Context context); 103 getInvisibleDrawable(Context context)104 public Drawable getInvisibleDrawable(Context context) { 105 return getDrawable(context); 106 } 107 108 @Override hashCode()109 public int hashCode() { 110 return Icon.class.hashCode(); 111 } 112 getPadding()113 public int getPadding() { 114 return 0; 115 } 116 117 @Override 118 @NonNull toString()119 public String toString() { 120 return "Icon"; 121 } 122 } 123 124 @ProvidesInterface(version = State.VERSION) 125 public static class State { 126 public static final int VERSION = 1; 127 public Icon icon; 128 public Supplier<Icon> iconSupplier; 129 public int state = Tile.STATE_ACTIVE; 130 public CharSequence label; 131 public CharSequence secondaryLabel; 132 public CharSequence contentDescription; 133 public CharSequence stateDescription; 134 public CharSequence dualLabelContentDescription; 135 public boolean disabledByPolicy; 136 public boolean dualTarget = false; 137 public boolean isTransient = false; 138 public String expandedAccessibilityClassName; 139 public SlashState slash; 140 public boolean handlesLongClick = true; 141 public boolean showRippleEffect = true; 142 copyTo(State other)143 public boolean copyTo(State other) { 144 if (other == null) throw new IllegalArgumentException(); 145 if (!other.getClass().equals(getClass())) throw new IllegalArgumentException(); 146 final boolean changed = !Objects.equals(other.icon, icon) 147 || !Objects.equals(other.iconSupplier, iconSupplier) 148 || !Objects.equals(other.label, label) 149 || !Objects.equals(other.secondaryLabel, secondaryLabel) 150 || !Objects.equals(other.contentDescription, contentDescription) 151 || !Objects.equals(other.stateDescription, stateDescription) 152 || !Objects.equals(other.dualLabelContentDescription, 153 dualLabelContentDescription) 154 || !Objects.equals(other.expandedAccessibilityClassName, 155 expandedAccessibilityClassName) 156 || !Objects.equals(other.disabledByPolicy, disabledByPolicy) 157 || !Objects.equals(other.state, state) 158 || !Objects.equals(other.isTransient, isTransient) 159 || !Objects.equals(other.dualTarget, dualTarget) 160 || !Objects.equals(other.slash, slash) 161 || !Objects.equals(other.handlesLongClick, handlesLongClick) 162 || !Objects.equals(other.showRippleEffect, showRippleEffect); 163 other.icon = icon; 164 other.iconSupplier = iconSupplier; 165 other.label = label; 166 other.secondaryLabel = secondaryLabel; 167 other.contentDescription = contentDescription; 168 other.stateDescription = stateDescription; 169 other.dualLabelContentDescription = dualLabelContentDescription; 170 other.expandedAccessibilityClassName = expandedAccessibilityClassName; 171 other.disabledByPolicy = disabledByPolicy; 172 other.state = state; 173 other.dualTarget = dualTarget; 174 other.isTransient = isTransient; 175 other.slash = slash != null ? slash.copy() : null; 176 other.handlesLongClick = handlesLongClick; 177 other.showRippleEffect = showRippleEffect; 178 return changed; 179 } 180 181 @Override toString()182 public String toString() { 183 return toStringBuilder().toString(); 184 } 185 186 // Used in dumps to determine current state of a tile. 187 // This string may be used for CTS testing of tiles, so removing elements is discouraged. toStringBuilder()188 protected StringBuilder toStringBuilder() { 189 final StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('['); 190 sb.append(",icon=").append(icon); 191 sb.append(",iconSupplier=").append(iconSupplier); 192 sb.append(",label=").append(label); 193 sb.append(",secondaryLabel=").append(secondaryLabel); 194 sb.append(",contentDescription=").append(contentDescription); 195 sb.append(",stateDescription=").append(stateDescription); 196 sb.append(",dualLabelContentDescription=").append(dualLabelContentDescription); 197 sb.append(",expandedAccessibilityClassName=").append(expandedAccessibilityClassName); 198 sb.append(",disabledByPolicy=").append(disabledByPolicy); 199 sb.append(",dualTarget=").append(dualTarget); 200 sb.append(",isTransient=").append(isTransient); 201 sb.append(",state=").append(state); 202 sb.append(",slash=\"").append(slash).append("\""); 203 return sb.append(']'); 204 } 205 copy()206 public State copy() { 207 State state = new State(); 208 copyTo(state); 209 return state; 210 } 211 } 212 213 @ProvidesInterface(version = BooleanState.VERSION) 214 public static class BooleanState extends State { 215 public static final int VERSION = 1; 216 public boolean value; 217 218 @Override copyTo(State other)219 public boolean copyTo(State other) { 220 final BooleanState o = (BooleanState) other; 221 final boolean changed = super.copyTo(other) || o.value != value; 222 o.value = value; 223 return changed; 224 } 225 226 @Override toStringBuilder()227 protected StringBuilder toStringBuilder() { 228 final StringBuilder rt = super.toStringBuilder(); 229 rt.insert(rt.length() - 1, ",value=" + value); 230 return rt; 231 } 232 233 @Override copy()234 public State copy() { 235 BooleanState state = new BooleanState(); 236 copyTo(state); 237 return state; 238 } 239 } 240 241 @ProvidesInterface(version = SignalState.VERSION) 242 public static final class SignalState extends BooleanState { 243 public static final int VERSION = 1; 244 public boolean activityIn; 245 public boolean activityOut; 246 public boolean isOverlayIconWide; 247 public int overlayIconId; 248 249 @Override copyTo(State other)250 public boolean copyTo(State other) { 251 final SignalState o = (SignalState) other; 252 final boolean changed = o.activityIn != activityIn 253 || o.activityOut != activityOut 254 || o.isOverlayIconWide != isOverlayIconWide 255 || o.overlayIconId != overlayIconId; 256 o.activityIn = activityIn; 257 o.activityOut = activityOut; 258 o.isOverlayIconWide = isOverlayIconWide; 259 o.overlayIconId = overlayIconId; 260 return super.copyTo(other) || changed; 261 } 262 263 @Override toStringBuilder()264 protected StringBuilder toStringBuilder() { 265 final StringBuilder rt = super.toStringBuilder(); 266 rt.insert(rt.length() - 1, ",activityIn=" + activityIn); 267 rt.insert(rt.length() - 1, ",activityOut=" + activityOut); 268 return rt; 269 } 270 271 @Override copy()272 public State copy() { 273 SignalState state = new SignalState(); 274 copyTo(state); 275 return state; 276 } 277 } 278 279 @ProvidesInterface(version = SlashState.VERSION) 280 public static class SlashState { 281 public static final int VERSION = 2; 282 283 public boolean isSlashed; 284 public float rotation; 285 286 @Override toString()287 public String toString() { 288 return "isSlashed=" + isSlashed + ",rotation=" + rotation; 289 } 290 291 @Override equals(Object o)292 public boolean equals(Object o) { 293 if (o == null) return false; 294 try { 295 return (((SlashState) o).rotation == rotation) 296 && (((SlashState) o).isSlashed == isSlashed); 297 } catch (ClassCastException e) { 298 return false; 299 } 300 } 301 copy()302 public SlashState copy() { 303 SlashState state = new SlashState(); 304 state.rotation = rotation; 305 state.isSlashed = isSlashed; 306 return state; 307 } 308 } 309 } 310