DreamControllerpublic final class DreamController extends Object Internal controller for starting and stopping the current dream and managing related state.
Assumes all operations are called from the dream handler thread. |
Fields Summary |
---|
private static final String | TAG | private static final int | DREAM_CONNECTION_TIMEOUT | private static final int | DREAM_FINISH_TIMEOUT | private final android.content.Context | mContext | private final android.os.Handler | mHandler | private final Listener | mListener | private final android.view.IWindowManager | mIWindowManager | private final android.content.Intent | mDreamingStartedIntent | private final android.content.Intent | mDreamingStoppedIntent | private final android.content.Intent | mCloseNotificationShadeIntent | private DreamRecord | mCurrentDream | private final Runnable | mStopUnconnectedDreamRunnable | private final Runnable | mStopStubbornDreamRunnable |
Constructors Summary |
---|
public DreamController(android.content.Context context, android.os.Handler handler, Listener listener)
mContext = context;
mHandler = handler;
mListener = listener;
mIWindowManager = WindowManagerGlobal.getWindowManagerService();
|
Methods Summary |
---|
private void | attach(android.service.dreams.IDreamService service)
try {
service.asBinder().linkToDeath(mCurrentDream, 0);
service.attach(mCurrentDream.mToken, mCurrentDream.mCanDoze);
} catch (RemoteException ex) {
Slog.e(TAG, "The dream service died unexpectedly.", ex);
stopDream(true /*immediate*/);
return;
}
mCurrentDream.mService = service;
if (!mCurrentDream.mIsTest) {
mContext.sendBroadcastAsUser(mDreamingStartedIntent, UserHandle.ALL);
mCurrentDream.mSentStartBroadcast = true;
}
| public void | dump(java.io.PrintWriter pw)
pw.println("Dreamland:");
if (mCurrentDream != null) {
pw.println(" mCurrentDream:");
pw.println(" mToken=" + mCurrentDream.mToken);
pw.println(" mName=" + mCurrentDream.mName);
pw.println(" mIsTest=" + mCurrentDream.mIsTest);
pw.println(" mCanDoze=" + mCurrentDream.mCanDoze);
pw.println(" mUserId=" + mCurrentDream.mUserId);
pw.println(" mBound=" + mCurrentDream.mBound);
pw.println(" mService=" + mCurrentDream.mService);
pw.println(" mSentStartBroadcast=" + mCurrentDream.mSentStartBroadcast);
pw.println(" mWakingGently=" + mCurrentDream.mWakingGently);
} else {
pw.println(" mCurrentDream: null");
}
| public void | startDream(android.os.Binder token, android.content.ComponentName name, boolean isTest, boolean canDoze, int userId)
stopDream(true /*immediate*/);
Trace.traceBegin(Trace.TRACE_TAG_POWER, "startDream");
try {
// Close the notification shade. Don't need to send to all, but better to be explicit.
mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL);
Slog.i(TAG, "Starting dream: name=" + name
+ ", isTest=" + isTest + ", canDoze=" + canDoze
+ ", userId=" + userId);
mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId);
try {
mIWindowManager.addWindowToken(token, WindowManager.LayoutParams.TYPE_DREAM);
} catch (RemoteException ex) {
Slog.e(TAG, "Unable to add window token for dream.", ex);
stopDream(true /*immediate*/);
return;
}
Intent intent = new Intent(DreamService.SERVICE_INTERFACE);
intent.setComponent(name);
intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
try {
if (!mContext.bindServiceAsUser(intent, mCurrentDream,
Context.BIND_AUTO_CREATE, new UserHandle(userId))) {
Slog.e(TAG, "Unable to bind dream service: " + intent);
stopDream(true /*immediate*/);
return;
}
} catch (SecurityException ex) {
Slog.e(TAG, "Unable to bind dream service: " + intent, ex);
stopDream(true /*immediate*/);
return;
}
mCurrentDream.mBound = true;
mHandler.postDelayed(mStopUnconnectedDreamRunnable, DREAM_CONNECTION_TIMEOUT);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
| public void | stopDream(boolean immediate)
if (mCurrentDream == null) {
return;
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "stopDream");
try {
if (!immediate) {
if (mCurrentDream.mWakingGently) {
return; // already waking gently
}
if (mCurrentDream.mService != null) {
// Give the dream a moment to wake up and finish itself gently.
mCurrentDream.mWakingGently = true;
try {
mCurrentDream.mService.wakeUp();
mHandler.postDelayed(mStopStubbornDreamRunnable, DREAM_FINISH_TIMEOUT);
return;
} catch (RemoteException ex) {
// oh well, we tried, finish immediately instead
}
}
}
final DreamRecord oldDream = mCurrentDream;
mCurrentDream = null;
Slog.i(TAG, "Stopping dream: name=" + oldDream.mName
+ ", isTest=" + oldDream.mIsTest + ", canDoze=" + oldDream.mCanDoze
+ ", userId=" + oldDream.mUserId);
mHandler.removeCallbacks(mStopUnconnectedDreamRunnable);
mHandler.removeCallbacks(mStopStubbornDreamRunnable);
if (oldDream.mSentStartBroadcast) {
mContext.sendBroadcastAsUser(mDreamingStoppedIntent, UserHandle.ALL);
}
if (oldDream.mService != null) {
// Tell the dream that it's being stopped so that
// it can shut down nicely before we yank its window token out from
// under it.
try {
oldDream.mService.detach();
} catch (RemoteException ex) {
// we don't care; this thing is on the way out
}
try {
oldDream.mService.asBinder().unlinkToDeath(oldDream, 0);
} catch (NoSuchElementException ex) {
// don't care
}
oldDream.mService = null;
}
if (oldDream.mBound) {
mContext.unbindService(oldDream);
}
try {
mIWindowManager.removeWindowToken(oldDream.mToken);
} catch (RemoteException ex) {
Slog.w(TAG, "Error removing window token for dream.", ex);
}
mHandler.post(new Runnable() {
@Override
public void run() {
mListener.onDreamStopped(oldDream.mToken);
}
});
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
|
|