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