• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.content.res.Resources;
20 import android.graphics.drawable.Drawable;
21 import android.metrics.LogMaker;
22 import android.service.quicksettings.Tile;
23 import android.text.TextUtils;
24 import android.view.View;
25 
26 import androidx.annotation.Nullable;
27 
28 import com.android.internal.logging.InstanceId;
29 import com.android.systemui.plugins.annotations.DependsOn;
30 import com.android.systemui.plugins.annotations.ProvidesInterface;
31 import com.android.systemui.plugins.qs.QSTile.Callback;
32 import com.android.systemui.plugins.qs.QSTile.Icon;
33 import com.android.systemui.plugins.qs.QSTile.State;
34 
35 import java.util.Objects;
36 import java.util.function.Supplier;
37 
38 @ProvidesInterface(version = QSTile.VERSION)
39 @DependsOn(target = QSIconView.class)
40 @DependsOn(target = Callback.class)
41 @DependsOn(target = Icon.class)
42 @DependsOn(target = State.class)
43 public interface QSTile {
44     int VERSION = 4;
45 
getTileSpec()46     String getTileSpec();
47 
isAvailable()48     boolean isAvailable();
setTileSpec(String tileSpec)49     void setTileSpec(String tileSpec);
50 
clearState()51     @Deprecated default void clearState() {}
refreshState()52     void refreshState();
53 
addCallback(Callback callback)54     void addCallback(Callback callback);
removeCallback(Callback callback)55     void removeCallback(Callback callback);
removeCallbacks()56     void removeCallbacks();
57 
createTileView(Context context)58     QSIconView createTileView(Context context);
59 
60     /**
61      * The tile was clicked.
62      *
63      * @param view The view that was clicked.
64      */
click(@ullable View view)65     void click(@Nullable View view);
66 
67     /**
68      * The tile secondary click was triggered.
69      *
70      * @param view The view that was clicked.
71      */
secondaryClick(@ullable View view)72     void secondaryClick(@Nullable View view);
73 
74     /**
75      * The tile was long clicked.
76      *
77      * @param view The view that was clicked.
78      */
longClick(@ullable View view)79     void longClick(@Nullable View view);
80 
userSwitch(int currentUser)81     void userSwitch(int currentUser);
82 
83     /**
84      * @deprecated not needed as {@link com.android.internal.logging.UiEvent} will use
85      * {@link #getMetricsSpec}
86      */
87     @Deprecated
getMetricsCategory()88     int getMetricsCategory();
89 
setListening(Object client, boolean listening)90     void setListening(Object client, boolean listening);
setDetailListening(boolean show)91     void setDetailListening(boolean show);
92 
destroy()93     void destroy();
94 
getTileLabel()95     CharSequence getTileLabel();
96 
getState()97     State getState();
98 
populate(LogMaker logMaker)99     default LogMaker populate(LogMaker logMaker) {
100         return logMaker;
101     }
102 
103     /**
104      * Return a string to be used to identify the tile in UiEvents.
105      */
getMetricsSpec()106     default String getMetricsSpec() {
107         return getClass().getSimpleName();
108     }
109 
110     /**
111      * Return an {@link InstanceId} to be used to identify the tile in UiEvents.
112      */
getInstanceId()113     InstanceId getInstanceId();
114 
isTileReady()115     default boolean isTileReady() {
116         return false;
117     }
118 
119     /**
120      * Return whether the tile is set to its listening state and therefore receiving updates and
121      * refreshes from controllers
122      */
isListening()123     boolean isListening();
124 
125     @ProvidesInterface(version = Callback.VERSION)
126     interface Callback {
127         static final int VERSION = 2;
onStateChanged(State state)128         void onStateChanged(State state);
129     }
130 
131     @ProvidesInterface(version = Icon.VERSION)
132     public static abstract class Icon {
133         public static final int VERSION = 1;
getDrawable(Context context)134         abstract public Drawable getDrawable(Context context);
135 
getInvisibleDrawable(Context context)136         public Drawable getInvisibleDrawable(Context context) {
137             return getDrawable(context);
138         }
139 
140         @Override
hashCode()141         public int hashCode() {
142             return Icon.class.hashCode();
143         }
144 
getPadding()145         public int getPadding() {
146             return 0;
147         }
148 
149         @Override
150         @NonNull
toString()151         public String toString() {
152             return "Icon";
153         }
154     }
155 
156     @ProvidesInterface(version = State.VERSION)
157     public static class State {
158         public static final int VERSION = 1;
159         public static final int DEFAULT_STATE = Tile.STATE_ACTIVE;
160 
161         public Icon icon;
162         public Supplier<Icon> iconSupplier;
163         public int state = DEFAULT_STATE;
164         public CharSequence label;
165         @Nullable public CharSequence secondaryLabel;
166         public CharSequence contentDescription;
167         @Nullable public CharSequence stateDescription;
168         public CharSequence dualLabelContentDescription;
169         public boolean disabledByPolicy;
170         public boolean dualTarget = false;
171         public boolean isTransient = false;
172         public String expandedAccessibilityClassName;
173         public SlashState slash;
174         public boolean handlesLongClick = true;
175         public boolean showRippleEffect = true;
176         @Nullable
177         public Drawable sideViewCustomDrawable;
178         public String spec;
179 
180         /** Get the state text. */
getStateText(int arrayResId, Resources resources)181         public String getStateText(int arrayResId, Resources resources) {
182             if (state == Tile.STATE_UNAVAILABLE || this instanceof QSTile.BooleanState) {
183                 String[] array = resources.getStringArray(arrayResId);
184                 return array[state];
185             } else {
186                 return "";
187             }
188         }
189 
190         /** Get the text for secondaryLabel. */
getSecondaryLabel(String stateText)191         public String getSecondaryLabel(String stateText) {
192             // Use a local reference as the value might change from other threads
193             CharSequence localSecondaryLabel = secondaryLabel;
194             if (TextUtils.isEmpty(localSecondaryLabel)) {
195                 return stateText;
196             }
197             return localSecondaryLabel.toString();
198         }
199 
copyTo(State other)200         public boolean copyTo(State other) {
201             if (other == null) throw new IllegalArgumentException();
202             if (!other.getClass().equals(getClass())) throw new IllegalArgumentException();
203             final boolean changed = !Objects.equals(other.spec, spec)
204                     || !Objects.equals(other.icon, icon)
205                     || !Objects.equals(other.iconSupplier, iconSupplier)
206                     || !Objects.equals(other.label, label)
207                     || !Objects.equals(other.secondaryLabel, secondaryLabel)
208                     || !Objects.equals(other.contentDescription, contentDescription)
209                     || !Objects.equals(other.stateDescription, stateDescription)
210                     || !Objects.equals(other.dualLabelContentDescription,
211                             dualLabelContentDescription)
212                     || !Objects.equals(other.expandedAccessibilityClassName,
213                             expandedAccessibilityClassName)
214                     || !Objects.equals(other.disabledByPolicy, disabledByPolicy)
215                     || !Objects.equals(other.state, state)
216                     || !Objects.equals(other.isTransient, isTransient)
217                     || !Objects.equals(other.dualTarget, dualTarget)
218                     || !Objects.equals(other.slash, slash)
219                     || !Objects.equals(other.handlesLongClick, handlesLongClick)
220                     || !Objects.equals(other.showRippleEffect, showRippleEffect)
221                     || !Objects.equals(other.sideViewCustomDrawable, sideViewCustomDrawable);
222             other.spec = spec;
223             other.icon = icon;
224             other.iconSupplier = iconSupplier;
225             other.label = label;
226             other.secondaryLabel = secondaryLabel;
227             other.contentDescription = contentDescription;
228             other.stateDescription = stateDescription;
229             other.dualLabelContentDescription = dualLabelContentDescription;
230             other.expandedAccessibilityClassName = expandedAccessibilityClassName;
231             other.disabledByPolicy = disabledByPolicy;
232             other.state = state;
233             other.dualTarget = dualTarget;
234             other.isTransient = isTransient;
235             other.slash = slash != null ? slash.copy() : null;
236             other.handlesLongClick = handlesLongClick;
237             other.showRippleEffect = showRippleEffect;
238             other.sideViewCustomDrawable = sideViewCustomDrawable;
239             return changed;
240         }
241 
242         @Override
toString()243         public String toString() {
244             return toStringBuilder().toString();
245         }
246 
247         // Used in dumps to determine current state of a tile.
248         // This string may be used for CTS testing of tiles, so removing elements is discouraged.
toStringBuilder()249         protected StringBuilder toStringBuilder() {
250             final StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('[');
251             sb.append("spec=").append(spec);
252             sb.append(",icon=").append(icon);
253             sb.append(",iconSupplier=").append(iconSupplier);
254             sb.append(",label=").append(label);
255             sb.append(",secondaryLabel=").append(secondaryLabel);
256             sb.append(",contentDescription=").append(contentDescription);
257             sb.append(",stateDescription=").append(stateDescription);
258             sb.append(",dualLabelContentDescription=").append(dualLabelContentDescription);
259             sb.append(",expandedAccessibilityClassName=").append(expandedAccessibilityClassName);
260             sb.append(",disabledByPolicy=").append(disabledByPolicy);
261             sb.append(",dualTarget=").append(dualTarget);
262             sb.append(",isTransient=").append(isTransient);
263             sb.append(",state=").append(state);
264             sb.append(",slash=\"").append(slash).append("\"");
265             sb.append(",sideViewCustomDrawable=").append(sideViewCustomDrawable);
266             return sb.append(']');
267         }
268 
copy()269         public State copy() {
270             State state = new State();
271             copyTo(state);
272             return state;
273         }
274     }
275 
276     @ProvidesInterface(version = BooleanState.VERSION)
277     public static class BooleanState extends State {
278         public static final int VERSION = 1;
279         public boolean value;
280         public boolean forceExpandIcon;
281 
282         @Override
copyTo(State other)283         public boolean copyTo(State other) {
284             final BooleanState o = (BooleanState) other;
285             final boolean changed = super.copyTo(other)
286                     || o.value != value
287                     || o.forceExpandIcon != forceExpandIcon;
288             o.value = value;
289             o.forceExpandIcon = forceExpandIcon;
290             return changed;
291         }
292 
293         @Override
toStringBuilder()294         protected StringBuilder toStringBuilder() {
295             final StringBuilder rt = super.toStringBuilder();
296             rt.insert(rt.length() - 1, ",value=" + value);
297             rt.insert(rt.length() - 1, ",forceExpandIcon=" + forceExpandIcon);
298             return rt;
299         }
300 
301         @Override
copy()302         public State copy() {
303             BooleanState state = new BooleanState();
304             copyTo(state);
305             return state;
306         }
307     }
308 
309     @ProvidesInterface(version = SignalState.VERSION)
310     public static final class SignalState extends BooleanState {
311         public static final int VERSION = 1;
312         public boolean activityIn;
313         public boolean activityOut;
314         public boolean isOverlayIconWide;
315         public int overlayIconId;
316 
317         @Override
copyTo(State other)318         public boolean copyTo(State other) {
319             final SignalState o = (SignalState) other;
320             final boolean changed = o.activityIn != activityIn
321                     || o.activityOut != activityOut
322                     || o.isOverlayIconWide != isOverlayIconWide
323                     || o.overlayIconId != overlayIconId;
324             o.activityIn = activityIn;
325             o.activityOut = activityOut;
326             o.isOverlayIconWide = isOverlayIconWide;
327             o.overlayIconId = overlayIconId;
328             return super.copyTo(other) || changed;
329         }
330 
331         @Override
toStringBuilder()332         protected StringBuilder toStringBuilder() {
333             final StringBuilder rt = super.toStringBuilder();
334             rt.insert(rt.length() - 1, ",activityIn=" + activityIn);
335             rt.insert(rt.length() - 1, ",activityOut=" + activityOut);
336             return rt;
337         }
338 
339         @Override
copy()340         public State copy() {
341             SignalState state = new SignalState();
342             copyTo(state);
343             return state;
344         }
345     }
346 
347     @ProvidesInterface(version = SlashState.VERSION)
348     public static class SlashState {
349         public static final int VERSION = 2;
350 
351         public boolean isSlashed;
352         public float rotation;
353 
354         @Override
toString()355         public String toString() {
356             return "isSlashed=" + isSlashed + ",rotation=" + rotation;
357         }
358 
359         @Override
equals(Object o)360         public boolean equals(Object o) {
361             if (o == null) return false;
362             try {
363                 return (((SlashState) o).rotation == rotation)
364                         && (((SlashState) o).isSlashed == isSlashed);
365             } catch (ClassCastException e) {
366                 return false;
367             }
368         }
369 
copy()370         public SlashState copy() {
371             SlashState state = new SlashState();
372             state.rotation = rotation;
373             state.isSlashed = isSlashed;
374             return state;
375         }
376     }
377 }
378