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