1 /* 2 * Copyright (C) 2015 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 android.service.quicksettings; 17 18 import android.annotation.Nullable; 19 import android.app.PendingIntent; 20 import android.graphics.drawable.Icon; 21 import android.os.IBinder; 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 import android.os.RemoteException; 25 import android.text.TextUtils; 26 import android.util.Log; 27 28 /** 29 * A Tile holds the state of a tile that will be displayed 30 * in Quick Settings. 31 * 32 * A tile in Quick Settings exists as an icon with an accompanied label. 33 * It also may have content description for accessibility usability. 34 * The style and layout of the tile may change to match a given 35 * device. 36 */ 37 public final class Tile implements Parcelable { 38 39 private static final String TAG = "Tile"; 40 41 /** 42 * An unavailable state indicates that for some reason this tile is not currently 43 * available to the user, and will have no click action. The tile's icon will be 44 * tinted differently to reflect this state. 45 */ 46 public static final int STATE_UNAVAILABLE = 0; 47 48 /** 49 * This represents a tile that is currently in a disabled state but is still interactable. 50 * 51 * A disabled state indicates that the tile is not currently active (e.g. wifi disconnected or 52 * bluetooth disabled), but is still interactable by the user to modify this state. Tiles 53 * that have boolean states should use this to represent one of their states. The tile's 54 * icon will be tinted differently to reflect this state, but still be distinct from unavailable. 55 */ 56 public static final int STATE_INACTIVE = 1; 57 58 /** 59 * This represents a tile that is currently active. (e.g. wifi is connected, bluetooth is on, 60 * cast is casting). This is the default state. 61 */ 62 public static final int STATE_ACTIVE = 2; 63 64 private IBinder mToken; 65 private Icon mIcon; 66 private CharSequence mLabel; 67 private CharSequence mDefaultLabel; 68 private CharSequence mSubtitle; 69 private CharSequence mContentDescription; 70 private CharSequence mStateDescription; 71 private PendingIntent mPendingIntent; 72 // Default to inactive until clients of the new API can update. 73 private int mState = STATE_INACTIVE; 74 75 private IQSService mService; 76 77 /** 78 * @hide 79 */ Tile(Parcel source)80 public Tile(Parcel source) { 81 readFromParcel(source); 82 } 83 84 /** 85 * @hide 86 */ Tile()87 public Tile() { 88 } 89 90 /** 91 * @hide 92 */ setService(IQSService service, IBinder stub)93 public void setService(IQSService service, IBinder stub) { 94 mService = service; 95 mToken = stub; 96 } 97 98 /** 99 * The current state of the tile. 100 * 101 * @see #STATE_UNAVAILABLE 102 * @see #STATE_INACTIVE 103 * @see #STATE_ACTIVE 104 */ getState()105 public int getState() { 106 return mState; 107 } 108 109 /** 110 * Sets the current state for the tile. 111 * 112 * Does not take effect until {@link #updateTile()} is called. 113 * 114 * @param state One of {@link #STATE_UNAVAILABLE}, {@link #STATE_INACTIVE}, 115 * {@link #STATE_ACTIVE} 116 */ setState(int state)117 public void setState(int state) { 118 mState = state; 119 } 120 121 /** 122 * Gets the current icon for the tile. 123 */ getIcon()124 public Icon getIcon() { 125 return mIcon; 126 } 127 128 /** 129 * Sets the current icon for the tile. 130 * 131 * This icon is expected to be white on alpha, and may be 132 * tinted by the system to match it's theme. 133 * 134 * Does not take effect until {@link #updateTile()} is called. 135 * 136 * @param icon New icon to show. 137 */ setIcon(Icon icon)138 public void setIcon(Icon icon) { 139 this.mIcon = icon; 140 } 141 142 /** 143 * Gets the current label for the tile. 144 */ getLabel()145 public CharSequence getLabel() { 146 return mLabel != null ? mLabel : mDefaultLabel; 147 } 148 149 /** 150 * @hide 151 * @return 152 */ getCustomLabel()153 public CharSequence getCustomLabel() { 154 return mLabel; 155 } 156 157 /** 158 * @hide 159 */ setDefaultLabel(CharSequence defaultLabel)160 public void setDefaultLabel(CharSequence defaultLabel) { 161 mDefaultLabel = defaultLabel; 162 } 163 164 /** 165 * Sets the current label for the tile. 166 * 167 * Does not take effect until {@link #updateTile()} is called. 168 * 169 * @param label New label to show. 170 */ setLabel(CharSequence label)171 public void setLabel(CharSequence label) { 172 this.mLabel = label; 173 } 174 175 /** 176 * Gets the current subtitle for the tile. 177 */ 178 @Nullable getSubtitle()179 public CharSequence getSubtitle() { 180 return mSubtitle; 181 } 182 183 /** 184 * Set the subtitle for the tile. Will be displayed as the secondary label. 185 * @param subtitle the subtitle to show. 186 */ setSubtitle(@ullable CharSequence subtitle)187 public void setSubtitle(@Nullable CharSequence subtitle) { 188 this.mSubtitle = subtitle; 189 } 190 191 /** 192 * Gets the current content description for the tile. 193 */ getContentDescription()194 public CharSequence getContentDescription() { 195 return mContentDescription; 196 } 197 198 /** 199 * Gets the current state description for the tile. 200 */ 201 @Nullable getStateDescription()202 public CharSequence getStateDescription() { 203 return mStateDescription; 204 } 205 206 /** 207 * Sets the current content description for the tile. 208 * 209 * Does not take effect until {@link #updateTile()} is called. 210 * 211 * @param contentDescription New content description to use. 212 */ setContentDescription(CharSequence contentDescription)213 public void setContentDescription(CharSequence contentDescription) { 214 this.mContentDescription = contentDescription; 215 } 216 217 /** 218 * Sets the current state description for the tile. 219 * 220 * Does not take effect until {@link #updateTile()} is called. 221 * 222 * @param stateDescription New state description to use. 223 */ setStateDescription(@ullable CharSequence stateDescription)224 public void setStateDescription(@Nullable CharSequence stateDescription) { 225 this.mStateDescription = stateDescription; 226 } 227 228 @Override describeContents()229 public int describeContents() { 230 return 0; 231 } 232 233 /** 234 * Pushes the state of the Tile to Quick Settings to be displayed. 235 */ updateTile()236 public void updateTile() { 237 try { 238 mService.updateQsTile(this, mToken); 239 } catch (RemoteException e) { 240 Log.e(TAG, "Couldn't update tile"); 241 } 242 } 243 244 /** 245 * Gets the Activity {@link PendingIntent} to be launched when the tile is clicked. 246 */ 247 @Nullable getActivityLaunchForClick()248 public PendingIntent getActivityLaunchForClick() { 249 return mPendingIntent; 250 } 251 252 /** 253 * Sets an Activity {@link PendingIntent} to be launched when the tile is clicked. 254 * 255 * The last value set here will be launched when the user clicks in the tile, instead of 256 * forwarding the `onClick` message to the {@link TileService}. Set to {@code null} to handle 257 * the `onClick` in the `TileService` 258 * (This is the default behavior if this method is never called.) 259 * @param pendingIntent a PendingIntent for an activity to be launched onclick, or {@code null} 260 * to handle the clicks in the `TileService`. 261 */ setActivityLaunchForClick(@ullable PendingIntent pendingIntent)262 public void setActivityLaunchForClick(@Nullable PendingIntent pendingIntent) { 263 if (pendingIntent != null && !pendingIntent.isActivity()) { 264 throw new IllegalArgumentException(); 265 } else { 266 mPendingIntent = pendingIntent; 267 } 268 } 269 270 @Override writeToParcel(Parcel dest, int flags)271 public void writeToParcel(Parcel dest, int flags) { 272 if (mIcon != null) { 273 dest.writeByte((byte) 1); 274 mIcon.writeToParcel(dest, flags); 275 } else { 276 dest.writeByte((byte) 0); 277 } 278 if (mPendingIntent != null) { 279 dest.writeByte((byte) 1); 280 mPendingIntent.writeToParcel(dest, flags); 281 } else { 282 dest.writeByte((byte) 0); 283 } 284 dest.writeInt(mState); 285 TextUtils.writeToParcel(mLabel, dest, flags); 286 TextUtils.writeToParcel(mDefaultLabel, dest, flags); 287 TextUtils.writeToParcel(mSubtitle, dest, flags); 288 TextUtils.writeToParcel(mContentDescription, dest, flags); 289 TextUtils.writeToParcel(mStateDescription, dest, flags); 290 } 291 readFromParcel(Parcel source)292 private void readFromParcel(Parcel source) { 293 if (source.readByte() != 0) { 294 mIcon = Icon.CREATOR.createFromParcel(source); 295 } else { 296 mIcon = null; 297 } 298 if (source.readByte() != 0) { 299 mPendingIntent = PendingIntent.CREATOR.createFromParcel(source); 300 } else { 301 mPendingIntent = null; 302 } 303 mState = source.readInt(); 304 mLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); 305 mDefaultLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); 306 mSubtitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); 307 mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); 308 mStateDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); 309 } 310 311 public static final @android.annotation.NonNull Creator<Tile> CREATOR = new Creator<Tile>() { 312 @Override 313 public Tile createFromParcel(Parcel source) { 314 return new Tile(source); 315 } 316 317 @Override 318 public Tile[] newArray(int size) { 319 return new Tile[size]; 320 } 321 }; 322 }