blob: 55fe4cd901e10b32b7cb3d4f33f1b396a4c64385 [file] [log] [blame]
Jason Monkbbadff82015-11-06 15:47:26 -05001/*
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
Jason Monk8f7f3182015-11-18 16:35:14 -050018import android.app.Dialog;
Jason Monkbbadff82015-11-06 15:47:26 -050019import 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;
Jason Monk8f7f3182015-11-18 16:35:14 -050026import android.view.WindowManager;
Jason Monkbbadff82015-11-06 15:47:26 -050027
28/**
Jason Monkd5a204f2015-12-21 08:50:01 -050029 * A TileService provides the user a tile that can be added to Quick Settings.
Jason Monkbbadff82015-11-06 15:47:26 -050030 * 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 *
Jason Monkd5a204f2015-12-21 08:50:01 -050033 * <p>The lifecycle of a TileService is different from some other services in
Jason Monkbbadff82015-11-06 15:47:26 -050034 * 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>
Jason Monkd5a204f2015-12-21 08:50:01 -050039 * <li>When a tile is added by the user its TileService will be bound to and
Jason Monkbbadff82015-11-06 15:47:26 -050040 * {@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>
Jason Monkd5a204f2015-12-21 08:50:01 -050048 * <p>TileService will be detected by tiles that match the {@value #ACTION_QS_TILE}
Jason Monkbbadff82015-11-06 15:47:26 -050049 * 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
Jason Monkd5a204f2015-12-21 08:50:01 -050051 * icon for the tile. Here is an example TileService declaration.</p>
Jason Monkbbadff82015-11-06 15:47:26 -050052 * <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>
Jason Monk8f7f3182015-11-18 16:35:14 -050060 * <action android:name="android.service.quicksettings.action.QS_TILE" />
Jason Monkbbadff82015-11-06 15:47:26 -050061 * </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 /**
Jason Monkd5a204f2015-12-21 08:50:01 -050070 * Action that identifies a Service as being a TileService.
Jason Monkbbadff82015-11-06 15:47:26 -050071 */
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;
Jason Monk8f7f3182015-11-18 16:35:14 -050078 private IBinder mToken;
Jason Monkbbadff82015-11-06 15:47:26 -050079
Jason Monk161ccb52015-12-17 16:43:07 -050080 @Override
81 public void onDestroy() {
82 if (mListening) {
83 onStopListening();
84 mListening = false;
85 }
86 super.onDestroy();
87 }
88
Jason Monkbbadff82015-11-06 15:47:26 -050089 /**
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 /**
Jason Monk8f7f3182015-11-18 16:35:14 -0500131 * 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 /**
Jason Monkbbadff82015-11-06 15:47:26 -0500145 * 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
Jason Monk8f7f3182015-11-18 16:35:14 -0500184 public void onClick(IBinder wtoken) throws RemoteException {
185 mHandler.obtainMessage(H.MSG_TILE_CLICKED, wtoken).sendToTarget();
Jason Monkbbadff82015-11-06 15:47:26 -0500186 }
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:
Jason Monk161ccb52015-12-17 16:43:07 -0500209 TileService.this.onTileAdded();
Jason Monkbbadff82015-11-06 15:47:26 -0500210 break;
211 case MSG_TILE_REMOVED:
Jason Monk161ccb52015-12-17 16:43:07 -0500212 TileService.this.onTileRemoved();
Jason Monkbbadff82015-11-06 15:47:26 -0500213 break;
Jason Monk8f7f3182015-11-18 16:35:14 -0500214 case MSG_STOP_LISTENING:
Jason Monkbbadff82015-11-06 15:47:26 -0500215 if (mListening) {
216 mListening = false;
217 TileService.this.onStopListening();
218 }
219 break;
Jason Monk8f7f3182015-11-18 16:35:14 -0500220 case MSG_START_LISTENING:
Jason Monkbbadff82015-11-06 15:47:26 -0500221 if (!mListening) {
222 mListening = true;
223 TileService.this.onStartListening();
224 }
225 break;
226 case MSG_TILE_CLICKED:
Jason Monk8f7f3182015-11-18 16:35:14 -0500227 mToken = (IBinder) msg.obj;
Jason Monkbbadff82015-11-06 15:47:26 -0500228 TileService.this.onClick();
229 break;
230 }
231 }
232 }
233}