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 mSubtitle; 68 private CharSequence mContentDescription; 69 private CharSequence mStateDescription; 70 private PendingIntent mPendingIntent; 71 // Default to inactive until clients of the new API can update. 72 private int mState = STATE_INACTIVE; 73 74 private IQSService mService; 75 76 /** 77 * @hide 78 */ Tile(Parcel source)79 public Tile(Parcel source) { 80 readFromParcel(source); 81 } 82 83 /** 84 * @hide 85 */ Tile()86 public Tile() { 87 } 88 89 /** 90 * @hide 91 */ setService(IQSService service, IBinder stub)92 public void setService(IQSService service, IBinder stub) { 93 mService = service; 94 mToken = stub; 95 } 96 97 /** 98 * The current state of the tile. 99 * 100 * @see #STATE_UNAVAILABLE 101 * @see #STATE_INACTIVE 102 * @see #STATE_ACTIVE 103 */ getState()104 public int getState() { 105 return mState; 106 } 107 108 /** 109 * Sets the current state for the tile. 110 * 111 * Does not take effect until {@link #updateTile()} is called. 112 * 113 * @param state One of {@link #STATE_UNAVAILABLE}, {@link #STATE_INACTIVE}, 114 * {@link #STATE_ACTIVE} 115 */ setState(int state)116 public void setState(int state) { 117 mState = state; 118 } 119 120 /** 121 * Gets the current icon for the tile. 122 */ getIcon()123 public Icon getIcon() { 124 return mIcon; 125 } 126 127 /** 128 * Sets the current icon for the tile. 129 * 130 * This icon is expected to be white on alpha, and may be 131 * tinted by the system to match it's theme. 132 * 133 * Does not take effect until {@link #updateTile()} is called. 134 * 135 * @param icon New icon to show. 136 */ setIcon(Icon icon)137 public void setIcon(Icon icon) { 138 this.mIcon = icon; 139 } 140 141 /** 142 * Gets the current label for the tile. 143 */ getLabel()144 public CharSequence getLabel() { 145 return mLabel; 146 } 147 148 /** 149 * Sets the current label for the tile. 150 * 151 * Does not take effect until {@link #updateTile()} is called. 152 * 153 * @param label New label to show. 154 */ setLabel(CharSequence label)155 public void setLabel(CharSequence label) { 156 this.mLabel = label; 157 } 158 159 /** 160 * Gets the current subtitle for the tile. 161 */ 162 @Nullable getSubtitle()163 public CharSequence getSubtitle() { 164 return mSubtitle; 165 } 166 167 /** 168 * Set the subtitle for the tile. Will be displayed as the secondary label. 169 * @param subtitle the subtitle to show. 170 */ setSubtitle(@ullable CharSequence subtitle)171 public void setSubtitle(@Nullable CharSequence subtitle) { 172 this.mSubtitle = subtitle; 173 } 174 175 /** 176 * Gets the current content description for the tile. 177 */ getContentDescription()178 public CharSequence getContentDescription() { 179 return mContentDescription; 180 } 181 182 /** 183 * Gets the current state description for the tile. 184 */ 185 @Nullable getStateDescription()186 public CharSequence getStateDescription() { 187 return mStateDescription; 188 } 189 190 /** 191 * Sets the current content description for the tile. 192 * 193 * Does not take effect until {@link #updateTile()} is called. 194 * 195 * @param contentDescription New content description to use. 196 */ setContentDescription(CharSequence contentDescription)197 public void setContentDescription(CharSequence contentDescription) { 198 this.mContentDescription = contentDescription; 199 } 200 201 /** 202 * Sets the current state description for the tile. 203 * 204 * Does not take effect until {@link #updateTile()} is called. 205 * 206 * @param stateDescription New state description to use. 207 */ setStateDescription(@ullable CharSequence stateDescription)208 public void setStateDescription(@Nullable CharSequence stateDescription) { 209 this.mStateDescription = stateDescription; 210 } 211 212 @Override describeContents()213 public int describeContents() { 214 return 0; 215 } 216 217 /** 218 * Pushes the state of the Tile to Quick Settings to be displayed. 219 */ updateTile()220 public void updateTile() { 221 try { 222 mService.updateQsTile(this, mToken); 223 } catch (RemoteException e) { 224 Log.e(TAG, "Couldn't update tile"); 225 } 226 } 227 228 /** 229 * Gets the Activity {@link PendingIntent} to be launched when the tile is clicked. 230 */ 231 @Nullable getActivityLaunchForClick()232 public PendingIntent getActivityLaunchForClick() { 233 return mPendingIntent; 234 } 235 236 /** 237 * Sets an Activity {@link PendingIntent} to be launched when the tile is clicked. 238 * 239 * The last value set here will be launched when the user clicks in the tile, instead of 240 * forwarding the `onClick` message to the {@link TileService}. Set to {@code null} to handle 241 * the `onClick` in the `TileService` 242 * (This is the default behavior if this method is never called.) 243 * @param pendingIntent a PendingIntent for an activity to be launched onclick, or {@code null} 244 * to handle the clicks in the `TileService`. 245 */ setActivityLaunchForClick(@ullable PendingIntent pendingIntent)246 public void setActivityLaunchForClick(@Nullable PendingIntent pendingIntent) { 247 if (pendingIntent != null && !pendingIntent.isActivity()) { 248 throw new IllegalArgumentException(); 249 } else { 250 mPendingIntent = pendingIntent; 251 } 252 } 253 254 @Override writeToParcel(Parcel dest, int flags)255 public void writeToParcel(Parcel dest, int flags) { 256 if (mIcon != null) { 257 dest.writeByte((byte) 1); 258 mIcon.writeToParcel(dest, flags); 259 } else { 260 dest.writeByte((byte) 0); 261 } 262 if (mPendingIntent != null) { 263 dest.writeByte((byte) 1); 264 mPendingIntent.writeToParcel(dest, flags); 265 } else { 266 dest.writeByte((byte) 0); 267 } 268 dest.writeInt(mState); 269 TextUtils.writeToParcel(mLabel, dest, flags); 270 TextUtils.writeToParcel(mSubtitle, dest, flags); 271 TextUtils.writeToParcel(mContentDescription, dest, flags); 272 TextUtils.writeToParcel(mStateDescription, dest, flags); 273 } 274 readFromParcel(Parcel source)275 private void readFromParcel(Parcel source) { 276 if (source.readByte() != 0) { 277 mIcon = Icon.CREATOR.createFromParcel(source); 278 } else { 279 mIcon = null; 280 } 281 if (source.readByte() != 0) { 282 mPendingIntent = PendingIntent.CREATOR.createFromParcel(source); 283 } else { 284 mPendingIntent = null; 285 } 286 mState = source.readInt(); 287 mLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); 288 mSubtitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); 289 mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); 290 mStateDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); 291 } 292 293 public static final @android.annotation.NonNull Creator<Tile> CREATOR = new Creator<Tile>() { 294 @Override 295 public Tile createFromParcel(Parcel source) { 296 return new Tile(source); 297 } 298 299 @Override 300 public Tile[] newArray(int size) { 301 return new Tile[size]; 302 } 303 }; 304 }