Add convertToTranslucent to API.
Rename convertToOpaque to convertFromTranslucent. Add the
counterpart to Activity.convertFromTranslucent() for returning from
opaque to a translucent Activity. The caller should wait until
TranslucentConversionListener.onTranslucentConversionComplete() is
called before actually changing the background to translucent.
Change-Id: Id04b026bcc4dd8bad9a33a7af126e1bb28fb9c03
diff --git a/api/current.txt b/api/current.txt
index 3318e06..cf1d923 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2697,7 +2697,8 @@
method public void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);
method public void closeContextMenu();
method public void closeOptionsMenu();
- method public void convertToOpaque();
+ method public void convertFromTranslucent();
+ method public void convertToTranslucent(android.app.Activity.TranslucentConversionListener);
method public android.app.PendingIntent createPendingResult(int, android.content.Intent, int);
method public final deprecated void dismissDialog(int);
method public boolean dispatchGenericMotionEvent(android.view.MotionEvent);
@@ -2883,6 +2884,10 @@
field public static final int RESULT_OK = -1; // 0xffffffff
}
+ public static abstract interface Activity.TranslucentConversionListener {
+ method public abstract void onTranslucentConversionComplete(boolean);
+ }
+
public deprecated class ActivityGroup extends android.app.Activity {
ctor public ActivityGroup();
ctor public ActivityGroup(boolean);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index d1efd0d1..fa746ba 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -745,6 +745,7 @@
// protected by synchronized (this)
int mResultCode = RESULT_CANCELED;
Intent mResultData = null;
+ private TranslucentConversionListener mTranslucentCallback;
private boolean mTitleReady = false;
@@ -1382,6 +1383,7 @@
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStop " + this);
if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false);
getApplication().dispatchActivityStopped(this);
+ mTranslucentCallback = null;
mCalled = true;
}
@@ -4886,23 +4888,62 @@
/**
* Convert a translucent themed Activity {@link android.R.attr#windowIsTranslucent} to a
* fullscreen opaque Activity.
- *
+ * <p>
* Call this whenever the background of a translucent Activity has changed to become opaque.
- * Doing so will allow the previously visible Activity behind this one to be stopped. Stopped
- * apps consume no CPU cycles and are eligible for removal when reclaiming memory.
- *
+ * Doing so will allow the {@link android.view.Surface} of the Activity behind to be released.
+ * <p>
* This call has no effect on non-translucent activities or on activities with the
* {@link android.R.attr#windowIsFloating} attribute.
+ *
+ * @see #convertToTranslucent(TranslucentConversionListener)
+ * @see TranslucentConversionListener
*/
- public void convertToOpaque() {
+ public void convertFromTranslucent() {
try {
- ActivityManagerNative.getDefault().convertToOpaque(mToken);
+ mTranslucentCallback = null;
+ ActivityManagerNative.getDefault().convertFromTranslucent(mToken);
} catch (RemoteException e) {
// pass
}
}
/**
+ * Convert a translucent themed Activity {@link android.R.attr#windowIsTranslucent} back from
+ * opaque to translucent following a call to {@link #convertFromTranslucent()}.
+ * <p>
+ * Calling this allows the Activity behind this one to be seen again. Once all such Activities
+ * have been redrawn {@link TranslucentConversionListener#onTranslucentConversionComplete} will
+ * be called indicating that it is safe to make this activity translucent again. Until
+ * {@link TranslucentConversionListener#onTranslucentConversionComplete} is called the image
+ * behind the frontmost Activity will be indeterminate.
+ * <p>
+ * This call has no effect on non-translucent activities or on activities with the
+ * {@link android.R.attr#windowIsFloating} attribute.
+ *
+ * @param callback the method to call when all visible Activities behind this one have been
+ * drawn and it is safe to make this Activity translucent again.
+ *
+ * @see #convertFromTranslucent()
+ * @see TranslucentConversionListener
+ */
+ public void convertToTranslucent(TranslucentConversionListener callback) {
+ try {
+ mTranslucentCallback = callback;
+ ActivityManagerNative.getDefault().convertToTranslucent(mToken);
+ } catch (RemoteException e) {
+ // pass
+ }
+ }
+
+ /** @hide */
+ void onTranslucentConversionComplete(boolean drawComplete) {
+ if (mTranslucentCallback != null) {
+ mTranslucentCallback.onTranslucentConversionComplete(drawComplete);
+ mTranslucentCallback = null;
+ }
+ }
+
+ /**
* Adjust the current immersive mode setting.
*
* Note that changing this value will have no effect on the activity's
@@ -4947,6 +4988,7 @@
* @return The new action mode, or <code>null</code> if the activity does not want to
* provide special handling for this action mode. (It will be handled by the system.)
*/
+ @Override
public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
initActionBar();
if (mActionBar != null) {
@@ -4961,6 +5003,7 @@
*
* @param mode The new action mode.
*/
+ @Override
public void onActionModeStarted(ActionMode mode) {
}
@@ -4970,6 +5013,7 @@
*
* @param mode The action mode that just finished.
*/
+ @Override
public void onActionModeFinished(ActionMode mode) {
}
@@ -5373,4 +5417,26 @@
}
}
}
+
+ /**
+ * Interface for informing a translucent {@link Activity} once all visible activities below it
+ * have completed drawing. This is necessary only after an {@link Activity} has been made
+ * opaque using {@link Activity#convertFromTranslucent()} and before it has been drawn
+ * translucent again following a call to {@link
+ * Activity#convertToTranslucent(TranslucentConversionListener)}.
+ */
+ public interface TranslucentConversionListener {
+ /**
+ * Callback made following {@link Activity#convertToTranslucent} once all visible Activities
+ * below the top one have been redrawn. Following this callback it is safe to make the top
+ * Activity translucent because the underlying Activity has been drawn.
+ *
+ * @param drawComplete True if the background Activity has drawn itself. False if a timeout
+ * occurred waiting for the Activity to complete drawing.
+ *
+ * @see Activity#convertFromTranslucent()
+ * @see Activity#convertToTranslucent(TranslucentConversionListener)
+ */
+ public void onTranslucentConversionComplete(boolean drawComplete);
+ }
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index a23611ec..acfcb40 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1499,10 +1499,18 @@
return true;
}
- case CONVERT_TO_OPAQUE_TRANSACTION: {
+ case CONVERT_FROM_TRANSLUCENT_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
- convertToOpaque(token);
+ convertFromTranslucent(token);
+ reply.writeNoException();
+ return true;
+ }
+
+ case CONVERT_TO_TRANSLUCENT_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IBinder token = data.readStrongBinder();
+ convertToTranslucent(token);
reply.writeNoException();
return true;
}
@@ -1957,6 +1965,13 @@
return true;
}
+ case NOTIFY_ACTIVITY_DRAWN_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IBinder token = data.readStrongBinder();
+ notifyActivityDrawn(token);
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -3840,13 +3855,25 @@
reply.recycle();
}
- public void convertToOpaque(IBinder token)
+ public void convertFromTranslucent(IBinder token)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(token);
- mRemote.transact(CONVERT_TO_OPAQUE_TRANSACTION, data, reply, 0);
+ mRemote.transact(CONVERT_FROM_TRANSLUCENT_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
+ public void convertToTranslucent(IBinder token)
+ throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(token);
+ mRemote.transact(CONVERT_TO_TRANSLUCENT_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
@@ -4482,5 +4509,16 @@
reply.recycle();
}
+ public void notifyActivityDrawn(IBinder token) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(token);
+ mRemote.transact(NOTIFY_ACTIVITY_DRAWN_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 4568525..a23f304 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1222,6 +1222,9 @@
queueOrSendMessage(H.TRIM_MEMORY, null, level);
}
+ public void scheduleTranslucentConversionComplete(IBinder token, boolean drawComplete) {
+ queueOrSendMessage(H.TRANSLUCENT_CONVERSION_COMPLETE, token, drawComplete ? 1 : 0);
+ }
}
private class H extends Handler {
@@ -1269,6 +1272,7 @@
public static final int DUMP_PROVIDER = 141;
public static final int UNSTABLE_PROVIDER_DIED = 142;
public static final int REQUEST_ACTIVITY_EXTRAS = 143;
+ public static final int TRANSLUCENT_CONVERSION_COMPLETE = 144;
String codeToString(int code) {
if (DEBUG_MESSAGES) {
switch (code) {
@@ -1316,6 +1320,7 @@
case DUMP_PROVIDER: return "DUMP_PROVIDER";
case UNSTABLE_PROVIDER_DIED: return "UNSTABLE_PROVIDER_DIED";
case REQUEST_ACTIVITY_EXTRAS: return "REQUEST_ACTIVITY_EXTRAS";
+ case TRANSLUCENT_CONVERSION_COMPLETE: return "TRANSLUCENT_CONVERSION_COMPLETE";
}
}
return Integer.toString(code);
@@ -1530,6 +1535,9 @@
case REQUEST_ACTIVITY_EXTRAS:
handleRequestActivityExtras((RequestActivityExtras)msg.obj);
break;
+ case TRANSLUCENT_CONVERSION_COMPLETE:
+ handleTranslucentConversionComplete((IBinder)msg.obj, msg.arg1 == 1);
+ break;
}
if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
}
@@ -2452,7 +2460,14 @@
} catch (RemoteException e) {
}
}
-
+
+ public void handleTranslucentConversionComplete(IBinder token, boolean drawComplete) {
+ ActivityClientRecord r = mActivities.get(token);
+ if (r != null) {
+ r.activity.onTranslucentConversionComplete(drawComplete);
+ }
+ }
+
private static final ThreadLocal<Intent> sCurrentBroadcastIntent = new ThreadLocal<Intent>();
/**
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index e903447..cc495aa 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -603,6 +603,16 @@
reply.writeNoException();
return true;
}
+
+ case SCHEDULE_TRANSLUCENT_CONVERSION_COMPLETE_TRANSACTION:
+ {
+ data.enforceInterface(IApplicationThread.descriptor);
+ IBinder token = data.readStrongBinder();
+ boolean timeout = data.readInt() == 1;
+ scheduleTranslucentConversionComplete(token, timeout);
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -1197,6 +1207,7 @@
data.recycle();
}
+ @Override
public void unstableProviderDied(IBinder provider) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
@@ -1205,6 +1216,7 @@
data.recycle();
}
+ @Override
public void requestActivityExtras(IBinder activityToken, IBinder requestToken, int requestType)
throws RemoteException {
Parcel data = Parcel.obtain();
@@ -1215,4 +1227,15 @@
mRemote.transact(REQUEST_ACTIVITY_EXTRAS_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
data.recycle();
}
+
+ @Override
+ public void scheduleTranslucentConversionComplete(IBinder token, boolean timeout)
+ throws RemoteException {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(IApplicationThread.descriptor);
+ data.writeStrongBinder(token);
+ data.writeInt(timeout ? 1 : 0);
+ mRemote.transact(SCHEDULE_TRANSLUCENT_CONVERSION_COMPLETE_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
+ data.recycle();
+ }
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 3793c73..19858dc 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -258,7 +258,7 @@
StrictMode.ViolationInfo crashInfo) throws RemoteException;
/*
- * This will deliver the specified signal to all the persistent processes. Currently only
+ * This will deliver the specified signal to all the persistent processes. Currently only
* SIGUSR1 is delivered. All others are ignored.
*/
public void signalPersistentProcesses(int signal) throws RemoteException;
@@ -301,7 +301,9 @@
public void finishHeavyWeightApp() throws RemoteException;
- public void convertToOpaque(IBinder token) throws RemoteException;
+ public void convertFromTranslucent(IBinder token) throws RemoteException;
+ public void convertToTranslucent(IBinder token) throws RemoteException;
+ public void notifyActivityDrawn(IBinder token) throws RemoteException;
public void setImmersive(IBinder token, boolean immersive) throws RemoteException;
public boolean isImmersive(IBinder token) throws RemoteException;
@@ -494,7 +496,7 @@
thisTime = source.readLong();
totalTime = source.readLong();
}
- };
+ }
String descriptor = "android.app.IActivityManager";
@@ -670,6 +672,8 @@
int GET_STACK_BOXES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+170;
int SET_FOCUSED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+171;
int GET_STACK_BOX_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+172;
- int CONVERT_TO_OPAQUE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+173;
- int REPORT_ACTIVITY_FULLY_DRAWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+174;
+ int CONVERT_FROM_TRANSLUCENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+173;
+ int CONVERT_TO_TRANSLUCENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+174;
+ int NOTIFY_ACTIVITY_DRAWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+175;
+ int REPORT_ACTIVITY_FULLY_DRAWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+176;
}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index a009bd3..286566d 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -133,6 +133,8 @@
void unstableProviderDied(IBinder provider) throws RemoteException;
void requestActivityExtras(IBinder activityToken, IBinder requestToken, int requestType)
throws RemoteException;
+ void scheduleTranslucentConversionComplete(IBinder token, boolean timeout)
+ throws RemoteException;
String descriptor = "android.app.IApplicationThread";
@@ -183,4 +185,5 @@
int DUMP_DB_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+45;
int UNSTABLE_PROVIDER_DIED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+46;
int REQUEST_ACTIVITY_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+47;
+ int SCHEDULE_TRANSLUCENT_CONVERSION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+48;
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index c957ebb..e41f642 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1000,7 +1000,6 @@
static final int USER_SWITCH_TIMEOUT_MSG = 36;
static final int IMMERSIVE_MODE_LOCK_MSG = 37;
static final int PERSIST_URI_GRANTS = 38;
- static final int SET_FOCUSED_STACK = 39;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1493,18 +1492,6 @@
writeGrantedUriPermissions();
break;
}
- case SET_FOCUSED_STACK: {
- synchronized (ActivityManagerService.this) {
- ActivityStack stack = mStackSupervisor.getStack(msg.arg1);
- if (stack != null) {
- ActivityRecord r = stack.topRunningActivityLocked(null);
- if (r != null) {
- setFocusedActivityLocked(r);
- }
- }
- }
- break;
- }
}
}
};
@@ -2081,7 +2068,26 @@
@Override
public void setFocusedStack(int stackId) {
if (DEBUG_FOCUS) Slog.d(TAG, "setFocusedStack: stackId=" + stackId);
- mHandler.obtainMessage(SET_FOCUSED_STACK, stackId, 0).sendToTarget();
+ synchronized (ActivityManagerService.this) {
+ ActivityStack stack = mStackSupervisor.getStack(stackId);
+ if (stack != null) {
+ ActivityRecord r = stack.topRunningActivityLocked(null);
+ if (r != null) {
+ setFocusedActivityLocked(r);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void notifyActivityDrawn(IBinder token) {
+ if (DEBUG_VISBILITY) Slog.d(TAG, "notifyActivityDrawn: token=" + token);
+ synchronized (this) {
+ ActivityRecord r= mStackSupervisor.isInAnyStackLocked(token);
+ if (r != null) {
+ r.task.stack.notifyActivityDrawnLocked(r);
+ }
+ }
}
final void applyUpdateLockStateLocked(ActivityRecord r) {
@@ -8048,7 +8054,7 @@
}
@Override
- public void convertToOpaque(IBinder token) {
+ public void convertFromTranslucent(IBinder token) {
final long origId = Binder.clearCallingIdentity();
try {
synchronized (this) {
@@ -8056,8 +8062,28 @@
if (r == null) {
return;
}
- if (r.convertToOpaque()) {
- mWindowManager.setAppFullscreen(token);
+ if (r.changeWindowTranslucency(true)) {
+ mWindowManager.setAppFullscreen(token, true);
+ mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
+ public void convertToTranslucent(IBinder token) {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (this) {
+ final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+ if (r == null) {
+ return;
+ }
+ if (r.changeWindowTranslucency(false)) {
+ r.task.stack.convertToTranslucent(r);
+ mWindowManager.setAppFullscreen(token, false);
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
}
}
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 4f09407..2ae9ed6 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -17,6 +17,7 @@
package com.android.server.am;
import android.os.Trace;
+import com.android.internal.R.styleable;
import com.android.internal.app.ResolverActivity;
import com.android.server.AttributeCache;
import com.android.server.am.ActivityStack.ActivityState;
@@ -505,19 +506,23 @@
}
}
- boolean convertToOpaque() {
- if (fullscreen) {
+ boolean changeWindowTranslucency(boolean toOpaque) {
+ if (fullscreen == toOpaque) {
+ return false;
+ }
+ AttributeCache.Entry ent =
+ AttributeCache.instance().get(packageName, realTheme, styleable.Window);
+ if (ent == null
+ || !ent.array.getBoolean(styleable.Window_windowIsTranslucent, false)
+ || ent.array.getBoolean(styleable.Window_windowIsFloating, false)) {
return false;
}
- AttributeCache.Entry ent = AttributeCache.instance().get(packageName,
- realTheme, com.android.internal.R.styleable.Window);
- if (ent != null && !ent.array.getBoolean(
- com.android.internal.R.styleable.Window_windowIsFloating, false)) {
- fullscreen = true;
- ++task.numFullscreen;
- }
- return fullscreen;
+ // Keep track of the number of fullscreen activities in this task.
+ task.numFullscreen += toOpaque ? +1 : -1;
+
+ fullscreen = toOpaque;
+ return true;
}
void putInHistory() {
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 98b3ce9..be03ee3 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -118,6 +118,10 @@
// is being started.
static final boolean SHOW_APP_STARTING_PREVIEW = true;
+ // How long to wait for all background Activities to redraw following a call to
+ // convertToTranslucent().
+ static final long TRANSLUCENT_CONVERSION_TIMEOUT = 2000;
+
enum ActivityState {
INITIALIZING,
RESUMED,
@@ -184,6 +188,16 @@
*/
ActivityRecord mLastStartedActivity = null;
+ // The topmost Activity passed to convertToTranslucent(). When non-null it means we are
+ // waiting for all Activities in mUndrawnActivitiesBelowTopTranslucent to be removed as they
+ // are drawn. When the last member of mUndrawnActivitiesBelowTopTranslucent is removed the
+ // Activity in mTranslucentActivityWaiting is notified via
+ // Activity.onTranslucentConversionComplete(false). If a timeout occurs prior to the last
+ // background activity being drawn then the same call will be made with a true value.
+ ActivityRecord mTranslucentActivityWaiting = null;
+ ArrayList<ActivityRecord> mUndrawnActivitiesBelowTopTranslucent =
+ new ArrayList<ActivityRecord>();
+
/**
* Set when we know we are going to be calling updateConfiguration()
* soon, so want to skip intermediate config checks.
@@ -215,6 +229,7 @@
static final int LAUNCH_TICK_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 3;
static final int STOP_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 4;
static final int DESTROY_ACTIVITIES_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 5;
+ static final int TRANSLUCENT_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 6;
static class ScheduleDestroyArgs {
final ProcessRecord mOwner;
@@ -285,7 +300,12 @@
synchronized (mService) {
destroyActivitiesLocked(args.mOwner, args.mOomAdj, args.mReason);
}
- }
+ } break;
+ case TRANSLUCENT_TIMEOUT_MSG: {
+ synchronized (mService) {
+ notifyActivityDrawnLocked(null);
+ }
+ } break;
}
}
}
@@ -952,6 +972,16 @@
TAG, "ensureActivitiesVisible behind " + top
+ " configChanges=0x" + Integer.toHexString(configChanges));
+ if (mTranslucentActivityWaiting != top) {
+ mUndrawnActivitiesBelowTopTranslucent.clear();
+ if (mTranslucentActivityWaiting != null) {
+ // Call the callback with a timeout indication.
+ notifyActivityDrawnLocked(null);
+ mTranslucentActivityWaiting = null;
+ }
+ mHandler.removeMessages(TRANSLUCENT_TIMEOUT_MSG);
+ }
+
// If the top activity is not fullscreen, then we need to
// make sure any activities under it are now visible.
boolean aboveTop = true;
@@ -1018,6 +1048,9 @@
if (DEBUG_VISBILITY) Slog.v(
TAG, "Making visible and scheduling visibility: " + r);
try {
+ if (mTranslucentActivityWaiting != null) {
+ mUndrawnActivitiesBelowTopTranslucent.add(r);
+ }
mWindowManager.setAppVisibility(r.appToken, true);
r.sleeping = false;
r.app.pendingUiClean = true;
@@ -1091,6 +1124,42 @@
return showHomeBehindStack;
}
+ void convertToTranslucent(ActivityRecord r) {
+ mTranslucentActivityWaiting = r;
+ mUndrawnActivitiesBelowTopTranslucent.clear();
+ mHandler.sendEmptyMessageDelayed(TRANSLUCENT_TIMEOUT_MSG, TRANSLUCENT_CONVERSION_TIMEOUT);
+ }
+
+ /**
+ * Called as activities below the top translucent activity are redrawn. When the last one is
+ * redrawn notify the top activity by calling
+ * {@link Activity#onTranslucentConversionComplete}.
+ *
+ * @param r The most recent background activity to be drawn. Or, if r is null then a timeout
+ * occurred and the activity will be notified immediately.
+ */
+ void notifyActivityDrawnLocked(ActivityRecord r) {
+ if ((r == null)
+ || (mUndrawnActivitiesBelowTopTranslucent.remove(r) &&
+ mUndrawnActivitiesBelowTopTranslucent.isEmpty())) {
+ // The last undrawn activity below the top has just been drawn. If there is an
+ // opaque activity at the top, notify it that it can become translucent safely now.
+ final ActivityRecord waitingActivity = mTranslucentActivityWaiting;
+ mTranslucentActivityWaiting = null;
+ mUndrawnActivitiesBelowTopTranslucent.clear();
+ mHandler.removeMessages(TRANSLUCENT_TIMEOUT_MSG);
+
+ if (waitingActivity != null && waitingActivity.app != null &&
+ waitingActivity.app.thread != null) {
+ try {
+ waitingActivity.app.thread.scheduleTranslucentConversionComplete(
+ waitingActivity.appToken, r != null);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ }
+
/**
* Ensure that the top activity in the stack is resumed.
*
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
index 63f91ac..d39798d 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2475,8 +2475,7 @@
public void handleMessage(Message msg) {
switch (msg.what) {
case IDLE_TIMEOUT_MSG: {
- if (DEBUG_IDLE) Slog.d(TAG, "handleMessage: IDLE_TIMEOUT_MSG: Callers=" +
- Debug.getCallers(4));
+ if (DEBUG_IDLE) Slog.d(TAG, "handleMessage: IDLE_TIMEOUT_MSG: r=" + msg.obj);
if (mService.mDidDexOpt) {
mService.mDidDexOpt = false;
Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
@@ -2489,6 +2488,7 @@
activityIdleInternal((ActivityRecord)msg.obj);
} break;
case IDLE_NOW_MSG: {
+ if (DEBUG_IDLE) Slog.d(TAG, "handleMessage: IDLE_NOW_MSG: r=" + msg.obj);
activityIdleInternal((ActivityRecord)msg.obj);
} break;
case RESUME_TOP_ACTIVITY_MSG: {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index ee2ef37..50d267f 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -25,6 +25,7 @@
import android.app.AppOpsManager;
import android.util.TimeUtils;
import android.view.IWindowId;
+
import com.android.internal.app.IBatteryStats;
import com.android.internal.policy.PolicyManager;
import com.android.internal.policy.impl.PhoneWindowManager;
@@ -4117,10 +4118,11 @@
}
}
- public void setAppFullscreen(IBinder token) {
+ public void setAppFullscreen(IBinder token, boolean toOpaque) {
AppWindowToken atoken = findAppWindowToken(token);
if (atoken != null) {
- atoken.appFullscreen = true;
+ atoken.appFullscreen = toOpaque;
+ requestTraversal();
}
}
@@ -7020,6 +7022,7 @@
public static final int CLIENT_FREEZE_TIMEOUT = 30;
public static final int TAP_OUTSIDE_STACK = 31;
+ public static final int NOTIFY_ACTIVITY_DRAWN = 32;
@Override
public void handleMessage(Message msg) {
@@ -7452,6 +7455,13 @@
}
}
}
+ break;
+ case NOTIFY_ACTIVITY_DRAWN:
+ try {
+ mActivityManager.notifyActivityDrawn((IBinder) msg.obj);
+ } catch (RemoteException e) {
+ }
+ break;
}
if (DEBUG_WINDOW_TRACE) {
Slog.v(TAG, "handleMessage: exit");
@@ -8759,6 +8769,7 @@
+ " interesting=" + numInteresting
+ " drawn=" + wtoken.numDrawnWindows);
wtoken.allDrawn = true;
+ mH.obtainMessage(H.NOTIFY_ACTIVITY_DRAWN, wtoken.token).sendToTarget();
}
}
}