Pass ActivityOptions back from finishing activity.

Adding an ActivityOptions parameter to convertToTranslucent provides
a mechanism for delivering these options to the activity that
launched the one that is returning.

Fixes bug 13032208.
Fixes bug 14469460.
Fixes bug 14597427.

Change-Id: I4115dd3c69de9d175f6df0498a6e964fca5eca29
This commit is contained in:
Craig Mautner
2014-05-09 17:05:11 -07:00
parent e4f1960652
commit 233ceeebab
12 changed files with 132 additions and 75 deletions

View File

@@ -30,7 +30,6 @@ import com.android.internal.policy.PolicyManager;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentCallbacks2;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -1150,6 +1149,12 @@ public class Activity extends ContextThemeWrapper
}
getApplication().dispatchActivityStarted(this);
final ActivityOptions activityOptions = getActivityOptions();
if (activityOptions != null &&
activityOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
mEnterTransitionCoordinator = activityOptions.createEnterActivityTransition(this);
}
}
/**
@@ -5272,19 +5277,29 @@ public class Activity extends ContextThemeWrapper
*
* @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.
* @param options activity options delivered to the activity below this one. The options
* are retrieved using {@link #getActivityOptions}.
*
* @see #convertFromTranslucent()
* @see TranslucentConversionListener
*
* @hide
*/
public void convertToTranslucent(TranslucentConversionListener callback) {
void convertToTranslucent(TranslucentConversionListener callback, ActivityOptions options) {
boolean drawComplete;
try {
mTranslucentCallback = callback;
mChangeCanvasToTranslucent =
ActivityManagerNative.getDefault().convertToTranslucent(mToken);
ActivityManagerNative.getDefault().convertToTranslucent(mToken, options);
drawComplete = true;
} catch (RemoteException e) {
// pass
// Make callback return as though it timed out.
mChangeCanvasToTranslucent = false;
drawComplete = false;
}
if (!mChangeCanvasToTranslucent && mTranslucentCallback != null) {
// Window is already translucent.
mTranslucentCallback.onTranslucentConversionComplete(drawComplete);
}
}
@@ -5299,6 +5314,22 @@ public class Activity extends ContextThemeWrapper
}
}
/**
* Retrieve the ActivityOptions passed in from the launching activity or passed back
* from an activity launched by this activity in its call to {@link
* #convertToTranslucent(TranslucentConversionListener, ActivityOptions)}
*
* @return The ActivityOptions passed to {@link #convertToTranslucent}.
* @hide
*/
ActivityOptions getActivityOptions() {
try {
return ActivityManagerNative.getDefault().getActivityOptions(mToken);
} catch (RemoteException e) {
}
return null;
}
/**
* Adjust the current immersive mode setting.
*
@@ -5533,30 +5564,12 @@ public class Activity extends ContextThemeWrapper
mParent = parent;
}
final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token,
Application application, Intent intent, ActivityInfo info, CharSequence title,
Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances,
Configuration config) {
attach(context, aThread, instr, token, 0, application, intent, info, title, parent, id,
lastNonConfigurationInstances, config);
}
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config) {
attach(context, aThread, instr, token, ident, application, intent, info, title, parent, id,
lastNonConfigurationInstances, config, null, null);
}
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, Bundle options, IVoiceInteractor voiceInteractor) {
Configuration config, IVoiceInteractor voiceInteractor) {
attachBaseContext(context);
mFragments.attachActivity(this, mContainer, null);
@@ -5597,12 +5610,6 @@ public class Activity extends ContextThemeWrapper
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
if (options != null) {
ActivityOptions activityOptions = new ActivityOptions(options);
if (activityOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
mEnterTransitionCoordinator = activityOptions.createEnterActivityTransition(this);
}
}
}
/** @hide */
@@ -5873,7 +5880,7 @@ public class Activity extends ContextThemeWrapper
* occurred waiting for the Activity to complete drawing.
*
* @see Activity#convertFromTranslucent()
* @see Activity#convertToTranslucent(TranslucentConversionListener)
* @see Activity#convertToTranslucent(TranslucentConversionListener, ActivityOptions)
*/
public void onTranslucentConversionComplete(boolean drawComplete);
}

View File

@@ -1542,12 +1542,28 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
case CONVERT_TO_TRANSLUCENT_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
boolean converted = convertToTranslucent(token);
final Bundle bundle;
if (data.readInt() == 0) {
bundle = null;
} else {
bundle = data.readBundle();
}
final ActivityOptions options = bundle == null ? null : new ActivityOptions(bundle);
boolean converted = convertToTranslucent(token, options);
reply.writeNoException();
reply.writeInt(converted ? 1 : 0);
return true;
}
case GET_ACTIVITY_OPTIONS_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
final ActivityOptions options = getActivityOptions(token);
reply.writeNoException();
reply.writeBundle(options == null ? null : options.toBundle());
return true;
}
case SET_IMMERSIVE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
@@ -4059,12 +4075,18 @@ class ActivityManagerProxy implements IActivityManager
return res;
}
public boolean convertToTranslucent(IBinder token)
public boolean convertToTranslucent(IBinder token, ActivityOptions options)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(token);
if (options == null) {
data.writeInt(0);
} else {
data.writeInt(1);
data.writeBundle(options.toBundle());
}
mRemote.transact(CONVERT_TO_TRANSLUCENT_TRANSACTION, data, reply, 0);
reply.readException();
boolean res = reply.readInt() != 0;
@@ -4073,6 +4095,20 @@ class ActivityManagerProxy implements IActivityManager
return res;
}
public ActivityOptions getActivityOptions(IBinder token) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(token);
mRemote.transact(GET_ACTIVITY_OPTIONS_TRANSACTION, data, reply, 0);
reply.readException();
Bundle bundle = reply.readBundle();
ActivityOptions options = bundle == null ? null : new ActivityOptions(bundle);
data.recycle();
reply.recycle();
return options;
}
public void setImmersive(IBinder token, boolean immersive)
throws RemoteException {
Parcel data = Parcel.obtain();

View File

@@ -76,7 +76,6 @@ import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
import android.util.LogPrinter;
import android.util.Pair;
import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.util.SuperNotCalledException;
@@ -294,7 +293,6 @@ public final class ActivityThread {
boolean isForward;
int pendingConfigChanges;
boolean onlyLocalRequest;
Bundle activityOptions;
View mPendingRemoveWindow;
WindowManager mPendingRemoveWindowManager;
@@ -593,8 +591,7 @@ public final class ActivityThread {
public final void scheduleResumeActivity(IBinder token, int processState,
boolean isForward, Bundle resumeArgs) {
updateProcessState(processState, false);
sendMessage(H.RESUME_ACTIVITY, new Pair<IBinder, Bundle>(token, resumeArgs),
isForward ? 1 : 0);
sendMessage(H.RESUME_ACTIVITY, token, isForward ? 1 : 0);
}
public final void scheduleSendResult(IBinder token, List<ResultInfo> results) {
@@ -611,8 +608,7 @@ public final class ActivityThread {
IVoiceInteractor voiceInteractor, int procState, Bundle state,
PersistableBundle persistentState, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler,
Bundle resumeArgs) {
String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
updateProcessState(procState, false);
@@ -636,7 +632,6 @@ public final class ActivityThread {
r.profileFile = profileName;
r.profileFd = profileFd;
r.autoStopProfiler = autoStopProfiler;
r.activityOptions = resumeArgs;
updatePendingConfiguration(curConfig);
@@ -1301,9 +1296,7 @@ public final class ActivityThread {
break;
case RESUME_ACTIVITY:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
final Pair<IBinder, Bundle> resumeArgs = (Pair<IBinder, Bundle>) msg.obj;
handleResumeActivity(resumeArgs.first, resumeArgs.second, true,
msg.arg1 != 0, true);
handleResumeActivity((IBinder) msg.obj, true, msg.arg1 != 0, true);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case SEND_RESULT:
@@ -2083,7 +2076,7 @@ public final class ActivityThread {
+ ", comp=" + name
+ ", token=" + token);
}
return performLaunchActivity(r, null, null);
return performLaunchActivity(r, null);
}
public final Activity getActivity(IBinder token) {
@@ -2136,8 +2129,7 @@ public final class ActivityThread {
sendMessage(H.CLEAN_UP_CONTEXT, cci);
}
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent,
Bundle options) {
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
ActivityInfo aInfo = r.activityInfo;
@@ -2195,7 +2187,7 @@ public final class ActivityThread {
+ r.activityInfo.name + " with config " + config);
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config, options,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.voiceInteractor);
if (customIntent != null) {
@@ -2321,12 +2313,12 @@ public final class ActivityThread {
if (localLOGV) Slog.v(
TAG, "Handling launch of " + r);
Activity a = performLaunchActivity(r, customIntent, r.activityOptions);
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
handleResumeActivity(r.token, r.activityOptions, false, r.isForward,
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed);
if (!r.activity.mFinished && r.startsNotResumed) {
@@ -2886,7 +2878,7 @@ public final class ActivityThread {
r.mPendingRemoveWindowManager = null;
}
final void handleResumeActivity(IBinder token, Bundle resumeArgs,
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
@@ -3809,7 +3801,6 @@ public final class ActivityThread {
}
}
r.startsNotResumed = tmp.startsNotResumed;
r.activityOptions = null;
handleLaunchActivity(r, currentIntent);
}

View File

@@ -151,11 +151,10 @@ public abstract class ApplicationThreadNative extends Binder
ParcelFileDescriptor profileFd = data.readInt() != 0
? ParcelFileDescriptor.CREATOR.createFromParcel(data) : null;
boolean autoStopProfiler = data.readInt() != 0;
Bundle resumeArgs = data.readBundle();
scheduleLaunchActivity(intent, b, ident, info, curConfig, compatInfo,
voiceInteractor, procState, state, persistentState,
ri, pi, notResumed, isForward, profileName, profileFd,
autoStopProfiler, resumeArgs);
autoStopProfiler);
return true;
}
@@ -736,8 +735,7 @@ class ApplicationThreadProxy implements IApplicationThread {
IVoiceInteractor voiceInteractor, int procState, Bundle state,
PersistableBundle persistentState, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler,
Bundle resumeArgs)
String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler)
throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
@@ -763,7 +761,6 @@ class ApplicationThreadProxy implements IApplicationThread {
data.writeInt(0);
}
data.writeInt(autoStopProfiler ? 1 : 0);
data.writeBundle(resumeArgs);
mRemote.transact(SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();

View File

@@ -121,7 +121,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator
mActivity.convertFromTranslucent();
}
}
});
}, null);
Drawable background = getDecor().getBackground();
if (background != null) {
window.setBackgroundDrawable(null);
@@ -230,7 +230,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator
public void onTranslucentConversionComplete(boolean drawComplete) {
fadeOutBackground();
}
});
}, null);
} else {
fadeOutBackground();
}

View File

@@ -309,8 +309,9 @@ public interface IActivityManager extends IInterface {
public void finishHeavyWeightApp() throws RemoteException;
public boolean convertFromTranslucent(IBinder token) throws RemoteException;
public boolean convertToTranslucent(IBinder token) throws RemoteException;
public boolean convertToTranslucent(IBinder token, ActivityOptions options) throws RemoteException;
public void notifyActivityDrawn(IBinder token) throws RemoteException;
public ActivityOptions getActivityOptions(IBinder token) throws RemoteException;
public void setImmersive(IBinder token, boolean immersive) throws RemoteException;
public boolean isImmersive(IBinder token) throws RemoteException;
@@ -737,4 +738,5 @@ public interface IActivityManager extends IInterface {
int IS_IN_LOCK_TASK_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+216;
int SET_RECENTS_ACTIVITY_VALUES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+217;
int START_VOICE_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+218;
int GET_ACTIVITY_OPTIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+219;
}

View File

@@ -61,8 +61,7 @@ public interface IApplicationThread extends IInterface {
IVoiceInteractor voiceInteractor, int procState, Bundle state,
PersistableBundle persistentState, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler,
Bundle resumeArgs)
String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler)
throws RemoteException;
void scheduleRelaunchActivity(IBinder token, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, int configChanges,

View File

@@ -1036,10 +1036,10 @@ public class Instrumentation {
IllegalAccessException {
Activity activity = (Activity)clazz.newInstance();
ActivityThread aThread = null;
activity.attach(context, aThread, this, token, application, intent,
activity.attach(context, aThread, this, token, 0, application, intent,
info, title, parent, id,
(Activity.NonConfigurationInstances)lastNonConfigurationInstance,
new Configuration());
new Configuration(), null);
return activity;
}

View File

@@ -9028,7 +9028,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
@Override
public boolean convertToTranslucent(IBinder token) {
public boolean convertToTranslucent(IBinder token, ActivityOptions options) {
final long origId = Binder.clearCallingIdentity();
try {
synchronized (this) {
@@ -9037,7 +9037,7 @@ public final class ActivityManagerService extends ActivityManagerNative
return false;
}
if (r.changeWindowTranslucency(false)) {
r.task.stack.convertToTranslucent(r);
r.task.stack.convertToTranslucent(r, options);
mWindowManager.setAppFullscreen(token, false);
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
return true;
@@ -9049,6 +9049,24 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
@Override
public ActivityOptions getActivityOptions(IBinder token) {
final long origId = Binder.clearCallingIdentity();
try {
synchronized (this) {
final ActivityRecord r = ActivityRecord.isInStackLocked(token);
if (r != null) {
final ActivityOptions activityOptions = r.pendingOptions;
r.pendingOptions = null;
return activityOptions;
}
return null;
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
@Override
public void setImmersive(IBinder token, boolean immersive) {
synchronized(this) {

View File

@@ -347,7 +347,7 @@ final class ActivityRecord {
ActivityInfo aInfo, Configuration _configuration,
ActivityRecord _resultTo, String _resultWho, int _reqCode,
boolean _componentSpecified, ActivityStackSupervisor supervisor,
ActivityContainer container) {
ActivityContainer container, Bundle options) {
service = _service;
appToken = new Token(this);
info = aInfo;
@@ -378,6 +378,9 @@ final class ActivityRecord {
hasBeenLaunched = false;
mStackSupervisor = supervisor;
mInitialActivityContainer = container;
if (options != null) {
pendingOptions = new ActivityOptions(options);
}
// This starts out true, since the initial state of an activity
// is that we have everything, and we shouldn't never consider it
@@ -711,6 +714,9 @@ final class ActivityRecord {
+ pendingOptions.getThumbnail().getHeight()));
}
break;
default:
Slog.e(TAG, "applyOptionsLocked: Unknown animationType=" + animationType);
break;
}
pendingOptions = null;
}

View File

@@ -205,6 +205,9 @@ final class ActivityStack {
ActivityRecord mTranslucentActivityWaiting = null;
ArrayList<ActivityRecord> mUndrawnActivitiesBelowTopTranslucent =
new ArrayList<ActivityRecord>();
// Options passed from the caller of the convertToTranslucent to the activity that will
// appear below it.
ActivityOptions mReturningActivityOptions = null;
/**
* Set when we know we are going to be calling updateConfiguration()
@@ -1218,6 +1221,7 @@ final class ActivityStack {
TAG, "Making visible and scheduling visibility: " + r);
try {
if (mTranslucentActivityWaiting != null) {
r.updateOptionsLocked(mReturningActivityOptions);
mUndrawnActivitiesBelowTopTranslucent.add(r);
}
setVisibile(r, true);
@@ -1295,9 +1299,10 @@ final class ActivityStack {
}
}
void convertToTranslucent(ActivityRecord r) {
void convertToTranslucent(ActivityRecord r, ActivityOptions options) {
mTranslucentActivityWaiting = r;
mUndrawnActivitiesBelowTopTranslucent.clear();
mReturningActivityOptions = options;
mHandler.sendEmptyMessageDelayed(TRANSLUCENT_TIMEOUT_MSG, TRANSLUCENT_CONVERSION_TIMEOUT);
}
@@ -1470,8 +1475,6 @@ final class ActivityStack {
next.sleeping = false;
mStackSupervisor.mWaitingVisibleActivities.remove(next);
next.updateOptionsLocked(options);
if (DEBUG_SWITCH) Slog.v(TAG, "Resuming " + next);
// If we are currently pausing an activity, then don't do anything
@@ -1915,7 +1918,6 @@ final class ActivityStack {
: AppTransition.TRANSIT_ACTIVITY_OPEN, keepCurTransition);
mNoAnimActivities.remove(r);
}
r.updateOptionsLocked(options);
mWindowManager.addAppToken(task.mActivities.indexOf(r),
r.appToken, r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId,
@@ -1966,13 +1968,14 @@ final class ActivityStack {
(r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId,
r.info.configChanges);
ActivityOptions.abort(options);
options = null;
}
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
if (doResume) {
mStackSupervisor.resumeTopActivitiesLocked();
mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
}
}

View File

@@ -1022,14 +1022,12 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_TOP);
Bundle options = (r.pendingOptions == null) ? null : r.pendingOptions.toBundle();
r.clearOptionsLocked();
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info,
new Configuration(mService.mConfiguration), r.compat, r.task.voiceInteractor,
app.repProcState, r.icicle, r.persistentState, results, newIntents, !andResume,
mService.isNextTransitionForward(), profileFile, profileFd, profileAutoStop,
options);
mService.isNextTransitionForward(), profileFile, profileFd, profileAutoStop
);
if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
// This may be a heavy-weight process! Note that the package
@@ -1325,7 +1323,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
requestCode, componentSpecified, this, container);
requestCode, componentSpecified, this, container, options);
if (outActivity != null) {
outActivity[0] = r;
}