TileService.java revision bbadff8603ca6922a0ef89338bee5b59d6dcf641
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 */ 16package android.service.quicksettings; 17 18import android.app.Service; 19import android.content.Intent; 20import android.os.Handler; 21import android.os.IBinder; 22import android.os.Looper; 23import android.os.Message; 24import android.os.RemoteException; 25 26/** 27 * A QSTileService provides the user a tile that can be added to Quick Settings. 28 * Quick Settings is a space provided that allows the user to change settings and 29 * take quick actions without leaving the context of their current app. 30 * 31 * <p>The lifecycle of a QSTileService is different from some other services in 32 * that it may be unbound during parts of its lifecycle. Any of the following 33 * lifecycle events can happen indepently in a separate binding/creation of the 34 * service.</p> 35 * 36 * <ul> 37 * <li>When a tile is added by the user its QSTileService will be bound to and 38 * {@link #onTileAdded()} will be called.</li> 39 * 40 * <li>When a tile should be up to date and listing will be indicated by 41 * {@link #onStartListening()} and {@link #onStopListening()}.</li> 42 * 43 * <li>When the user removes a tile from Quick Settings {@link #onStopListening()} 44 * will be called.</li> 45 * </ul> 46 * <p>QSTileService will be detected by tiles that match the {@value #ACTION_QS_TILE} 47 * and require the permission "android.permission.BIND_QUICK_SETTINGS_TILE". 48 * The label and icon for the service will be used as the default label and 49 * icon for the tile. Here is an example QSTileService declaration.</p> 50 * <pre class="prettyprint"> 51 * {@literal 52 * <service 53 * android:name=".MyQSTileService" 54 * android:label="@string/my_default_tile_label" 55 * android:icon="@drawable/my_default_icon_label" 56 * android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"> 57 * <intent-filter> 58 * <action android:name="android.intent.action.QS_TILE" /> 59 * </intent-filter> 60 * </service>} 61 * </pre> 62 * 63 * @see Tile Tile for details about the UI of a Quick Settings Tile. 64 */ 65public class TileService extends Service { 66 67 /** 68 * Action that identifies a Service as being a QSTileService. 69 */ 70 public static final String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE"; 71 72 private final H mHandler = new H(Looper.getMainLooper()); 73 74 private boolean mListening = false; 75 private Tile mTile; 76 77 /** 78 * Called when the user adds this tile to Quick Settings. 79 * <p/> 80 * Note that this is not guaranteed to be called between {@link #onCreate()} 81 * and {@link #onStartListening()}, it will only be called when the tile is added 82 * and not on subsequent binds. 83 */ 84 public void onTileAdded() { 85 } 86 87 /** 88 * Called when the user removes this tile from Quick Settings. 89 */ 90 public void onTileRemoved() { 91 } 92 93 /** 94 * Called when this tile moves into a listening state. 95 * <p/> 96 * When this tile is in a listening state it is expected to keep the 97 * UI up to date. Any listeners or callbacks needed to keep this tile 98 * up to date should be registered here and unregistered in {@link #onStopListening()}. 99 * 100 * @see #getQsTile() 101 * @see Tile#updateTile() 102 */ 103 public void onStartListening() { 104 } 105 106 /** 107 * Called when this tile moves out of the listening state. 108 */ 109 public void onStopListening() { 110 } 111 112 /** 113 * Called when the user clicks on this tile. 114 */ 115 public void onClick() { 116 } 117 118 /** 119 * Gets the {@link Tile} for this service. 120 * <p/> 121 * This tile may be used to get or set the current state for this 122 * tile. This tile is only valid for updates between {@link #onStartListening()} 123 * and {@link #onStopListening()}. 124 */ 125 public final Tile getQsTile() { 126 return mTile; 127 } 128 129 @Override 130 public IBinder onBind(Intent intent) { 131 return new IQSTileService.Stub() { 132 @Override 133 public void setQSTile(Tile tile) throws RemoteException { 134 mHandler.obtainMessage(H.MSG_SET_TILE, tile).sendToTarget(); 135 } 136 137 @Override 138 public void onTileRemoved() throws RemoteException { 139 mHandler.sendEmptyMessage(H.MSG_TILE_REMOVED); 140 } 141 142 @Override 143 public void onTileAdded() throws RemoteException { 144 mHandler.sendEmptyMessage(H.MSG_TILE_ADDED); 145 } 146 147 @Override 148 public void onStopListening() throws RemoteException { 149 mHandler.sendEmptyMessage(H.MSG_STOP_LISTENING); 150 } 151 152 @Override 153 public void onStartListening() throws RemoteException { 154 mHandler.sendEmptyMessage(H.MSG_START_LISTENING); 155 } 156 157 @Override 158 public void onClick() throws RemoteException { 159 mHandler.sendEmptyMessage(H.MSG_TILE_CLICKED); 160 } 161 }; 162 } 163 164 private class H extends Handler { 165 private static final int MSG_SET_TILE = 1; 166 private static final int MSG_START_LISTENING = 2; 167 private static final int MSG_STOP_LISTENING = 3; 168 private static final int MSG_TILE_ADDED = 4; 169 private static final int MSG_TILE_REMOVED = 5; 170 private static final int MSG_TILE_CLICKED = 6; 171 172 public H(Looper looper) { 173 super(looper); 174 } 175 176 @Override 177 public void handleMessage(Message msg) { 178 switch (msg.what) { 179 case MSG_SET_TILE: 180 mTile = (Tile) msg.obj; 181 break; 182 case MSG_TILE_ADDED: 183 TileService.this.onTileRemoved(); 184 break; 185 case MSG_TILE_REMOVED: 186 TileService.this.onTileAdded(); 187 break; 188 case MSG_START_LISTENING: 189 if (mListening) { 190 mListening = false; 191 TileService.this.onStopListening(); 192 } 193 break; 194 case MSG_STOP_LISTENING: 195 if (!mListening) { 196 mListening = true; 197 TileService.this.onStartListening(); 198 } 199 break; 200 case MSG_TILE_CLICKED: 201 TileService.this.onClick(); 202 break; 203 } 204 } 205 } 206} 207