blob: 1ab6a77a85e725a4e84436f2a884c0803b90a514 [file] [log] [blame]
John Spurlockf4f6b4c2012-08-25 12:08:03 -04001/*
2 * Copyright (C) 2012 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
Jeff Browncef440f2012-09-25 18:58:48 -070017package com.android.server.dreams;
John Spurlockf4f6b4c2012-08-25 12:08:03 -040018
19import android.content.ComponentName;
20import android.content.Context;
21import android.content.Intent;
22import android.content.ServiceConnection;
23import android.os.Binder;
24import android.os.Handler;
25import android.os.IBinder;
26import android.os.RemoteException;
27import android.os.IBinder.DeathRecipient;
Amith Yamasanicd757062012-10-19 18:23:52 -070028import android.os.UserHandle;
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070029import android.service.dreams.DreamService;
John Spurlockf4f6b4c2012-08-25 12:08:03 -040030import android.service.dreams.IDreamService;
31import android.util.Slog;
32import android.view.IWindowManager;
33import android.view.WindowManager;
34import android.view.WindowManagerGlobal;
35
John Spurlockf4f6b4c2012-08-25 12:08:03 -040036import java.io.PrintWriter;
37import java.util.NoSuchElementException;
38
39/**
40 * Internal controller for starting and stopping the current dream and managing related state.
41 *
Jeff Brown62c82e42012-09-26 01:30:41 -070042 * Assumes all operations are called from the dream handler thread.
John Spurlockf4f6b4c2012-08-25 12:08:03 -040043 */
44final class DreamController {
Jeff Brown62c82e42012-09-26 01:30:41 -070045 private static final String TAG = "DreamController";
John Spurlockf4f6b4c2012-08-25 12:08:03 -040046
47 private final Context mContext;
Jeff Brown62c82e42012-09-26 01:30:41 -070048 private final Handler mHandler;
John Spurlockf4f6b4c2012-08-25 12:08:03 -040049 private final Listener mListener;
Jeff Brown62c82e42012-09-26 01:30:41 -070050 private final IWindowManager mIWindowManager;
John Spurlockf4f6b4c2012-08-25 12:08:03 -040051
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070052 private final Intent mDreamingStartedIntent = new Intent(Intent.ACTION_DREAMING_STARTED)
Jeff Brown62c82e42012-09-26 01:30:41 -070053 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070054 private final Intent mDreamingStoppedIntent = new Intent(Intent.ACTION_DREAMING_STOPPED)
Jeff Brown62c82e42012-09-26 01:30:41 -070055 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
John Spurlockf4f6b4c2012-08-25 12:08:03 -040056
John Spurlock591a9e82012-09-28 12:15:08 -040057 private final Intent mCloseNotificationShadeIntent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
58
Jeff Brown62c82e42012-09-26 01:30:41 -070059 private DreamRecord mCurrentDream;
John Spurlockf4f6b4c2012-08-25 12:08:03 -040060
Jeff Brown62c82e42012-09-26 01:30:41 -070061 public DreamController(Context context, Handler handler, Listener listener) {
John Spurlockf4f6b4c2012-08-25 12:08:03 -040062 mContext = context;
Jeff Brown62c82e42012-09-26 01:30:41 -070063 mHandler = handler;
John Spurlockf4f6b4c2012-08-25 12:08:03 -040064 mListener = listener;
65 mIWindowManager = WindowManagerGlobal.getWindowManagerService();
66 }
67
Jeff Brown62c82e42012-09-26 01:30:41 -070068 public void dump(PrintWriter pw) {
69 pw.println("Dreamland:");
70 if (mCurrentDream != null) {
71 pw.println(" mCurrentDream:");
72 pw.println(" mToken=" + mCurrentDream.mToken);
73 pw.println(" mName=" + mCurrentDream.mName);
74 pw.println(" mIsTest=" + mCurrentDream.mIsTest);
75 pw.println(" mUserId=" + mCurrentDream.mUserId);
76 pw.println(" mBound=" + mCurrentDream.mBound);
77 pw.println(" mService=" + mCurrentDream.mService);
78 pw.println(" mSentStartBroadcast=" + mCurrentDream.mSentStartBroadcast);
79 } else {
80 pw.println(" mCurrentDream: null");
81 }
John Spurlockf4f6b4c2012-08-25 12:08:03 -040082 }
83
Jeff Brown62c82e42012-09-26 01:30:41 -070084 public void startDream(Binder token, ComponentName name, boolean isTest, int userId) {
85 stopDream();
86
Amith Yamasanicd757062012-10-19 18:23:52 -070087 // Close the notification shade. Don't need to send to all, but better to be explicit.
88 mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL);
John Spurlock591a9e82012-09-28 12:15:08 -040089
Jeff Brown62c82e42012-09-26 01:30:41 -070090 Slog.i(TAG, "Starting dream: name=" + name + ", isTest=" + isTest + ", userId=" + userId);
91
92 mCurrentDream = new DreamRecord(token, name, isTest, userId);
93
94 try {
95 mIWindowManager.addWindowToken(token, WindowManager.LayoutParams.TYPE_DREAM);
96 } catch (RemoteException ex) {
97 Slog.e(TAG, "Unable to add window token for dream.", ex);
98 stopDream();
John Spurlockf4f6b4c2012-08-25 12:08:03 -040099 return;
100 }
John Spurlockf4f6b4c2012-08-25 12:08:03 -0400101
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700102 Intent intent = new Intent(DreamService.SERVICE_INTERFACE);
Jeff Brown62c82e42012-09-26 01:30:41 -0700103 intent.setComponent(name);
104 intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
105 try {
106 if (!mContext.bindService(intent, mCurrentDream,
107 Context.BIND_AUTO_CREATE, userId)) {
108 Slog.e(TAG, "Unable to bind dream service: " + intent);
109 stopDream();
John Spurlockf4f6b4c2012-08-25 12:08:03 -0400110 return;
111 }
Jeff Brown62c82e42012-09-26 01:30:41 -0700112 } catch (SecurityException ex) {
113 Slog.e(TAG, "Unable to bind dream service: " + intent, ex);
114 stopDream();
John Spurlockf4f6b4c2012-08-25 12:08:03 -0400115 return;
116 }
117
Jeff Brown62c82e42012-09-26 01:30:41 -0700118 mCurrentDream.mBound = true;
John Spurlockf4f6b4c2012-08-25 12:08:03 -0400119 }
120
Jeff Brown62c82e42012-09-26 01:30:41 -0700121 public void stopDream() {
122 if (mCurrentDream == null) {
John Spurlockf4f6b4c2012-08-25 12:08:03 -0400123 return;
124 }
125
Jeff Brown62c82e42012-09-26 01:30:41 -0700126 final DreamRecord oldDream = mCurrentDream;
John Spurlockf4f6b4c2012-08-25 12:08:03 -0400127 mCurrentDream = null;
Jeff Brown62c82e42012-09-26 01:30:41 -0700128 Slog.i(TAG, "Stopping dream: name=" + oldDream.mName
129 + ", isTest=" + oldDream.mIsTest + ", userId=" + oldDream.mUserId);
John Spurlockf4f6b4c2012-08-25 12:08:03 -0400130
Jeff Brown62c82e42012-09-26 01:30:41 -0700131 if (oldDream.mSentStartBroadcast) {
Amith Yamasanicd757062012-10-19 18:23:52 -0700132 mContext.sendBroadcastAsUser(mDreamingStoppedIntent, UserHandle.ALL);
Jeff Brown62c82e42012-09-26 01:30:41 -0700133 }
134
135 if (oldDream.mService != null) {
Daniel Sandler2d784902012-10-03 23:04:50 -0400136 // Tell the dream that it's being stopped so that
137 // it can shut down nicely before we yank its window token out from
138 // under it.
139 try {
140 oldDream.mService.detach();
141 } catch (RemoteException ex) {
142 // we don't care; this thing is on the way out
143 }
144
Jeff Brown62c82e42012-09-26 01:30:41 -0700145 try {
146 oldDream.mService.asBinder().unlinkToDeath(oldDream, 0);
147 } catch (NoSuchElementException ex) {
148 // don't care
149 }
150 oldDream.mService = null;
151 }
152
153 if (oldDream.mBound) {
154 mContext.unbindService(oldDream);
155 }
156
157 try {
158 mIWindowManager.removeWindowToken(oldDream.mToken);
159 } catch (RemoteException ex) {
160 Slog.w(TAG, "Error removing window token for dream.", ex);
161 }
162
163 mHandler.post(new Runnable() {
164 @Override
165 public void run() {
166 mListener.onDreamStopped(oldDream.mToken);
167 }
168 });
169 }
170
171 private void attach(IDreamService service) {
172 try {
173 service.asBinder().linkToDeath(mCurrentDream, 0);
174 service.attach(mCurrentDream.mToken);
175 } catch (RemoteException ex) {
176 Slog.e(TAG, "The dream service died unexpectedly.", ex);
177 stopDream();
178 return;
179 }
180
181 mCurrentDream.mService = service;
182
183 if (!mCurrentDream.mIsTest) {
Amith Yamasanicd757062012-10-19 18:23:52 -0700184 mContext.sendBroadcastAsUser(mDreamingStartedIntent, UserHandle.ALL);
Jeff Brown62c82e42012-09-26 01:30:41 -0700185 mCurrentDream.mSentStartBroadcast = true;
186 }
187 }
188
189 /**
190 * Callback interface to be implemented by the {@link DreamManagerService}.
191 */
192 public interface Listener {
193 void onDreamStopped(Binder token);
194 }
195
196 private final class DreamRecord implements DeathRecipient, ServiceConnection {
197 public final Binder mToken;
198 public final ComponentName mName;
199 public final boolean mIsTest;
200 public final int mUserId;
201
202 public boolean mBound;
203 public IDreamService mService;
204 public boolean mSentStartBroadcast;
205
206 public DreamRecord(Binder token, ComponentName name,
207 boolean isTest, int userId) {
208 mToken = token;
209 mName = name;
210 mIsTest = isTest;
211 mUserId = userId;
212 }
213
214 // May be called on any thread.
215 @Override
216 public void binderDied() {
217 mHandler.post(new Runnable() {
John Spurlockf4f6b4c2012-08-25 12:08:03 -0400218 @Override
219 public void run() {
Jeff Brown62c82e42012-09-26 01:30:41 -0700220 mService = null;
221 if (mCurrentDream == DreamRecord.this) {
222 stopDream();
223 }
224 }
225 });
226 }
227
228 // May be called on any thread.
229 @Override
230 public void onServiceConnected(ComponentName name, final IBinder service) {
231 mHandler.post(new Runnable() {
232 @Override
233 public void run() {
234 if (mCurrentDream == DreamRecord.this && mService == null) {
235 attach(IDreamService.Stub.asInterface(service));
236 }
237 }
238 });
239 }
240
241 // May be called on any thread.
242 @Override
243 public void onServiceDisconnected(ComponentName name) {
244 mHandler.post(new Runnable() {
245 @Override
246 public void run() {
247 mService = null;
248 if (mCurrentDream == DreamRecord.this) {
249 stopDream();
250 }
251 }
252 });
John Spurlockf4f6b4c2012-08-25 12:08:03 -0400253 }
254 }
John Spurlockf4f6b4c2012-08-25 12:08:03 -0400255}