APIs for activity to know when its windowing/pip modes change
Added APIs that allow activities to ask the system if they are currently
in multi-window or picture-in-picture mode and also get notified when
their modes change.
Bug: 25509834
Bug: 25683717
Change-Id: I4b8c316a49940bd6a8b31a93b345f9fd725a4721
diff --git a/api/current.txt b/api/current.txt
index c017754..feb43da 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3411,6 +3411,8 @@
method public android.view.Window getWindow();
method public android.view.WindowManager getWindowManager();
method public boolean hasWindowFocus();
+ method public boolean inMultiWindowMode();
+ method public boolean inPictureInPictureMode();
method public void invalidateOptionsMenu();
method public boolean isChangingConfigurations();
method public final boolean isChild();
@@ -3461,6 +3463,7 @@
method public void onLowMemory();
method public boolean onMenuItemSelected(int, android.view.MenuItem);
method public boolean onMenuOpened(int, android.view.Menu);
+ method public void onMultiWindowModeChanged(boolean);
method public boolean onNavigateUp();
method public boolean onNavigateUpFromChild(android.app.Activity);
method protected void onNewIntent(android.content.Intent);
@@ -3468,6 +3471,7 @@
method public void onOptionsMenuClosed(android.view.Menu);
method public void onPanelClosed(int, android.view.Menu);
method protected void onPause();
+ method public void onPictureInPictureModeChanged(boolean);
method protected void onPostCreate(android.os.Bundle);
method public void onPostCreate(android.os.Bundle, android.os.PersistableBundle);
method protected void onPostResume();
diff --git a/api/system-current.txt b/api/system-current.txt
index 8128819..bc7983a 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3514,6 +3514,8 @@
method public android.view.Window getWindow();
method public android.view.WindowManager getWindowManager();
method public boolean hasWindowFocus();
+ method public boolean inMultiWindowMode();
+ method public boolean inPictureInPictureMode();
method public void invalidateOptionsMenu();
method public boolean isBackgroundVisibleBehind();
method public boolean isChangingConfigurations();
@@ -3566,6 +3568,7 @@
method public void onLowMemory();
method public boolean onMenuItemSelected(int, android.view.MenuItem);
method public boolean onMenuOpened(int, android.view.Menu);
+ method public void onMultiWindowModeChanged(boolean);
method public boolean onNavigateUp();
method public boolean onNavigateUpFromChild(android.app.Activity);
method protected void onNewIntent(android.content.Intent);
@@ -3573,6 +3576,7 @@
method public void onOptionsMenuClosed(android.view.Menu);
method public void onPanelClosed(int, android.view.Menu);
method protected void onPause();
+ method public void onPictureInPictureModeChanged(boolean);
method protected void onPostCreate(android.os.Bundle);
method public void onPostCreate(android.os.Bundle, android.os.PersistableBundle);
method protected void onPostResume();
diff --git a/api/test-current.txt b/api/test-current.txt
index d05dba2..3bcfd67 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -3411,6 +3411,8 @@
method public android.view.Window getWindow();
method public android.view.WindowManager getWindowManager();
method public boolean hasWindowFocus();
+ method public boolean inMultiWindowMode();
+ method public boolean inPictureInPictureMode();
method public void invalidateOptionsMenu();
method public boolean isChangingConfigurations();
method public final boolean isChild();
@@ -3461,6 +3463,7 @@
method public void onLowMemory();
method public boolean onMenuItemSelected(int, android.view.MenuItem);
method public boolean onMenuOpened(int, android.view.Menu);
+ method public void onMultiWindowModeChanged(boolean);
method public boolean onNavigateUp();
method public boolean onNavigateUpFromChild(android.app.Activity);
method protected void onNewIntent(android.content.Intent);
@@ -3468,6 +3471,7 @@
method public void onOptionsMenuClosed(android.view.Menu);
method public void onPanelClosed(int, android.view.Menu);
method protected void onPause();
+ method public void onPictureInPictureModeChanged(boolean);
method protected void onPostCreate(android.os.Bundle);
method public void onPostCreate(android.os.Bundle, android.os.PersistableBundle);
method protected void onPostResume();
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 8bb0ff5..93c6bef 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1727,6 +1727,57 @@
}
/**
+ * Called by the system when the activity changes from fullscreen mode to multi-window mode and
+ * visa-versa.
+ * @see android.R.attr#resizeableActivity
+ *
+ * @param multiWindowMode True if the activity is in multi-window mode.
+ */
+ public void onMultiWindowModeChanged(boolean multiWindowMode) {
+ if (DEBUG_LIFECYCLE) Slog.v(TAG,
+ "onMultiWindowModeChanged " + this + ": " + multiWindowMode);
+ }
+
+ /**
+ * Returns true if the activity is currently in multi-window mode.
+ * @see android.R.attr#resizeableActivity
+ *
+ * @return True if the activity is in multi-window mode.
+ */
+ public boolean inMultiWindowMode() {
+ try {
+ return ActivityManagerNative.getDefault().inMultiWindowMode(mToken);
+ } catch (RemoteException e) {
+ }
+ return false;
+ }
+
+ /**
+ * Called by the system when the activity changes to and from picture-in-picture mode.
+ * @see android.R.attr#supportsPictureInPicture
+ *
+ * @param pictureInPictureMode True if the activity is in picture-in-picture mode.
+ */
+ public void onPictureInPictureModeChanged(boolean pictureInPictureMode) {
+ if (DEBUG_LIFECYCLE) Slog.v(TAG,
+ "onPictureInPictureModeChanged " + this + ": " + pictureInPictureMode);
+ }
+
+ /**
+ * Returns true if the activity is currently in picture-in-picture mode.
+ * @see android.R.attr#supportsPictureInPicture
+ *
+ * @return True if the activity is in picture-in-picture mode.
+ */
+ public boolean inPictureInPictureMode() {
+ try {
+ return ActivityManagerNative.getDefault().inPictureInPictureMode(mToken);
+ } catch (RemoteException e) {
+ }
+ return false;
+ }
+
+ /**
* Called by the system when the device configuration changes while your
* activity is running. Note that this will <em>only</em> be called if
* you have selected configurations you would like to handle with the
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index c05d5e8..ee2efcc 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2733,6 +2733,22 @@
reply.writeInt(res);
return true;
}
+ case IN_MULTI_WINDOW_MODE_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ final IBinder token = data.readStrongBinder();
+ final boolean multiWindowMode = inMultiWindowMode(token);
+ reply.writeNoException();
+ reply.writeInt(multiWindowMode ? 1 : 0);
+ return true;
+ }
+ case IN_PICTURE_IN_PICTURE_MODE_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ final IBinder token = data.readStrongBinder();
+ final boolean pipMode = inPictureInPictureMode(token);
+ reply.writeNoException();
+ reply.writeInt(pipMode ? 1 : 0);
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -6366,5 +6382,33 @@
return res;
}
+ @Override
+ public boolean inMultiWindowMode(IBinder token) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(token);
+ mRemote.transact(IN_MULTI_WINDOW_MODE_TRANSACTION, data, reply, 0);
+ reply.readException();
+ final boolean multiWindowMode = reply.readInt() == 1 ? true : false;
+ data.recycle();
+ reply.recycle();
+ return multiWindowMode;
+ }
+
+ @Override
+ public boolean inPictureInPictureMode(IBinder token) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(token);
+ mRemote.transact(IN_PICTURE_IN_PICTURE_MODE_TRANSACTION, data, reply, 0);
+ reply.readException();
+ final boolean pipMode = reply.readInt() == 1 ? true : false;
+ data.recycle();
+ reply.recycle();
+ return pipMode;
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e64d13a..f3539ff 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1275,6 +1275,18 @@
} catch (IOException e) {
}
}
+
+ @Override
+ public void scheduleMultiWindowModeChanged(IBinder token, boolean multiWindowMode)
+ throws RemoteException {
+ sendMessage(H.MULTI_WINDOW_MODE_CHANGED, token, multiWindowMode ? 1 : 0);
+ }
+
+ @Override
+ public void schedulePictureInPictureModeChanged(IBinder token, boolean pipMode)
+ throws RemoteException {
+ sendMessage(H.PICTURE_IN_PICTURE_MODE_CHANGED, token, pipMode ? 1 : 0);
+ }
}
private int getLifecycleSeq() {
@@ -1336,6 +1348,8 @@
public static final int ENTER_ANIMATION_COMPLETE = 149;
public static final int START_BINDER_TRACKING = 150;
public static final int STOP_BINDER_TRACKING_AND_DUMP = 151;
+ public static final int MULTI_WINDOW_MODE_CHANGED = 152;
+ public static final int PICTURE_IN_PICTURE_MODE_CHANGED = 153;
String codeToString(int code) {
if (DEBUG_MESSAGES) {
@@ -1389,6 +1403,8 @@
case CANCEL_VISIBLE_BEHIND: return "CANCEL_VISIBLE_BEHIND";
case BACKGROUND_VISIBLE_BEHIND_CHANGED: return "BACKGROUND_VISIBLE_BEHIND_CHANGED";
case ENTER_ANIMATION_COMPLETE: return "ENTER_ANIMATION_COMPLETE";
+ case MULTI_WINDOW_MODE_CHANGED: return "MULTI_WINDOW_MODE_CHANGED";
+ case PICTURE_IN_PICTURE_MODE_CHANGED: return "PICTURE_IN_PICTURE_MODE_CHANGED";
}
}
return Integer.toString(code);
@@ -1632,6 +1648,12 @@
case STOP_BINDER_TRACKING_AND_DUMP:
handleStopBinderTrackingAndDump((ParcelFileDescriptor) msg.obj);
break;
+ case MULTI_WINDOW_MODE_CHANGED:
+ handleMultiWindowModeChanged((IBinder) msg.obj, msg.arg1 == 1);
+ break;
+ case PICTURE_IN_PICTURE_MODE_CHANGED:
+ handlePictureInPictureModeChanged((IBinder) msg.obj, msg.arg1 == 1);
+ break;
}
Object obj = msg.obj;
if (obj instanceof SomeArgs) {
@@ -2814,6 +2836,20 @@
}
}
+ private void handleMultiWindowModeChanged(IBinder token, boolean multiWindowMode) {
+ final ActivityClientRecord r = mActivities.get(token);
+ if (r != null) {
+ r.activity.onMultiWindowModeChanged(multiWindowMode);
+ }
+ }
+
+ private void handlePictureInPictureModeChanged(IBinder token, boolean pipMode) {
+ final ActivityClientRecord r = mActivities.get(token);
+ if (r != null) {
+ r.activity.onPictureInPictureModeChanged(pipMode);
+ }
+ }
+
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 44387de..5951c8d 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -720,6 +720,24 @@
return true;
}
+ case SCHEDULE_MULTI_WINDOW_MODE_CHANGED_TRANSACTION:
+ {
+ data.enforceInterface(IApplicationThread.descriptor);
+ final IBinder b = data.readStrongBinder();
+ final boolean multiWindowMode = data.readInt() != 0;
+ scheduleMultiWindowModeChanged(b, multiWindowMode);
+ return true;
+ }
+
+ case SCHEDULE_PICTURE_IN_PICTURE_MODE_CHANGED_TRANSACTION:
+ {
+ data.enforceInterface(IApplicationThread.descriptor);
+ final IBinder b = data.readStrongBinder();
+ final boolean pipMode = data.readInt() != 0;
+ schedulePictureInPictureModeChanged(b, pipMode);
+ return true;
+ }
+
}
return super.onTransact(code, data, reply, flags);
@@ -1454,4 +1472,28 @@
IBinder.FLAG_ONEWAY);
data.recycle();
}
+
+ @Override
+ public final void scheduleMultiWindowModeChanged(
+ IBinder token, boolean multiWindowMode) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(IApplicationThread.descriptor);
+ data.writeStrongBinder(token);
+ data.writeInt(multiWindowMode ? 1 : 0);
+ mRemote.transact(SCHEDULE_MULTI_WINDOW_MODE_CHANGED_TRANSACTION, data, null,
+ IBinder.FLAG_ONEWAY);
+ data.recycle();
+ }
+
+ @Override
+ public final void schedulePictureInPictureModeChanged(IBinder token, boolean pipMode)
+ throws RemoteException {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(IApplicationThread.descriptor);
+ data.writeStrongBinder(token);
+ data.writeInt(pipMode ? 1 : 0);
+ mRemote.transact(SCHEDULE_PICTURE_IN_PICTURE_MODE_CHANGED_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 38c7957..9a01b7b 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -545,6 +545,10 @@
public int getAppStartMode(int uid, String packageName) throws RemoteException;
+ public boolean inMultiWindowMode(IBinder token) throws RemoteException;
+
+ public boolean inPictureInPictureMode(IBinder token) throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -906,4 +910,6 @@
int MOVE_TOP_ACTIVITY_TO_PINNED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 349;
int GET_APP_START_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 350;
int UNLOCK_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 351;
+ int IN_MULTI_WINDOW_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 352;
+ int IN_PICTURE_IN_PICTURE_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 353;
}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 64045f334..dc67026 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -152,6 +152,8 @@
void notifyCleartextNetwork(byte[] firstPacket) throws RemoteException;
void startBinderTracking() throws RemoteException;
void stopBinderTrackingAndDump(FileDescriptor fd) throws RemoteException;
+ void scheduleMultiWindowModeChanged(IBinder token, boolean multiWindowMode) throws RemoteException;
+ void schedulePictureInPictureModeChanged(IBinder token, boolean multiWindowMode) throws RemoteException;
String descriptor = "android.app.IApplicationThread";
@@ -212,4 +214,6 @@
int NOTIFY_CLEARTEXT_NETWORK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+55;
int START_BINDER_TRACKING_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+56;
int STOP_BINDER_TRACKING_AND_DUMP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+57;
+ int SCHEDULE_MULTI_WINDOW_MODE_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+58;
+ int SCHEDULE_PICTURE_IN_PICTURE_MODE_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+59;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b769d39..7d768bd 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -16,65 +16,9 @@
package com.android.server.am;
-import static android.Manifest.permission.INTERACT_ACROSS_USERS;
-import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
-import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static com.android.internal.util.XmlUtils.readBooleanAttribute;
-import static com.android.internal.util.XmlUtils.readIntAttribute;
-import static com.android.internal.util.XmlUtils.readLongAttribute;
-import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
-import static com.android.internal.util.XmlUtils.writeIntAttribute;
-import static com.android.internal.util.XmlUtils.writeLongAttribute;
-import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
-import static com.android.server.am.ActivityManagerDebugConfig.*;
-import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
-import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
-import static org.xmlpull.v1.XmlPullParser.START_TAG;
-
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
-import android.Manifest;
-import android.app.AppOpsManager;
-import android.app.ApplicationThreadNative;
-import android.app.BroadcastOptions;
-import android.app.IActivityContainer;
-import android.app.IActivityContainerCallback;
-import android.app.IAppTask;
-import android.app.ITaskStackListener;
-import android.app.ProfilerInfo;
-import android.app.assist.AssistContent;
-import android.app.assist.AssistStructure;
-import android.app.usage.UsageEvents;
-import android.app.usage.UsageStatsManagerInternal;
-import android.appwidget.AppWidgetManager;
-import android.content.pm.PackageManagerInternal;
-import android.content.pm.PermissionInfo;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.os.BatteryStats;
-import android.os.PersistableBundle;
-import android.os.PowerManager;
-import android.os.Trace;
-import android.os.TransactionTooLargeException;
-import android.os.WorkSource;
-import android.os.storage.IMountService;
-import android.os.storage.MountServiceInternal;
-import android.os.storage.StorageManager;
-import android.service.voice.IVoiceInteractionSession;
-import android.service.voice.VoiceInteractionSession;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.DebugUtils;
-import android.util.SparseIntArray;
-import android.view.Display;
-
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.AssistUtils;
@@ -185,6 +129,7 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
import android.content.pm.PathPermission;
import android.content.pm.PermissionInfo;
@@ -305,6 +250,7 @@
import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
@@ -333,6 +279,7 @@
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LRU;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER_QUICK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES;
@@ -499,9 +446,6 @@
// interaction with foreground processes.
static final long USAGE_STATS_INTERACTION_INTERVAL = 24*60*60*1000L;
- // Maximum number of users we allow to be running at a time.
- static final int MAX_RUNNING_USERS = 3;
-
// This is the amount of time we allow an app to settle after it goes into the background,
// before we start restricting what it can do.
static final int BACKGROUND_SETTLE_TIME = 1*60*1000;
@@ -7210,6 +7154,29 @@
}
}
+ @Override
+ public boolean inMultiWindowMode(IBinder token) {
+ synchronized(this) {
+ final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+ if (r == null) {
+ return false;
+ }
+ // An activity is consider to be in multi-window mode if its task isn't fullscreen.
+ return !r.task.mFullscreen;
+ }
+ }
+
+ @Override
+ public boolean inPictureInPictureMode(IBinder token) {
+ synchronized(this) {
+ final ActivityStack stack = ActivityRecord.getStackLocked(token);
+ if (stack == null) {
+ return false;
+ }
+ return stack.mStackId == PINNED_STACK_ID;
+ }
+ }
+
// =========================================================
// PROCESS INFO
// =========================================================
@@ -8863,7 +8830,7 @@
task.inRecents = true;
mRecentTasks.add(task);
- r.task.stack.addTask(task, false, false);
+ r.task.stack.addTask(task, false, "addAppTask");
task.setLastThumbnailLocked(thumbnail);
task.freeLastThumbnail();
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 65497cf..bad71b2 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -4652,7 +4652,7 @@
TaskRecord task = new TaskRecord(mService, taskId, info, intent, voiceSession,
voiceInteractor);
// add the task to stack first, mTaskPositioner might need the stack association
- addTask(task, toTop, false);
+ addTask(task, toTop, "createTaskRecord");
final boolean isLockscreenShown = mService.mLockScreenShown == LOCK_SCREEN_SHOWN;
if (!layoutTaskInStack(task, info.layout) && mBounds != null && task.mResizeable
&& !isLockscreenShown) {
@@ -4673,7 +4673,9 @@
return new ArrayList<>(mTaskHistory);
}
- void addTask(final TaskRecord task, final boolean toTop, boolean moving) {
+ void addTask(final TaskRecord task, final boolean toTop, String reason) {
+ final ActivityStack prevStack = preAddTask(task, reason);
+
task.stack = this;
if (toTop) {
insertTaskAtTop(task, null);
@@ -4681,18 +4683,31 @@
mTaskHistory.add(0, task);
updateTaskMovement(task, false);
}
- if (!moving && task.voiceSession != null) {
- try {
- task.voiceSession.taskStarted(task.intent, task.taskId);
- } catch (RemoteException e) {
- }
- }
+ postAddTask(task, prevStack);
}
- void positionTask(final TaskRecord task, int position, boolean moving) {
+ void positionTask(final TaskRecord task, int position) {
+ final ActivityStack prevStack = preAddTask(task, "positionTask");
task.stack = this;
insertTaskAtPosition(task, position);
- if (!moving && task.voiceSession != null) {
+ postAddTask(task, prevStack);
+ }
+
+ private ActivityStack preAddTask(TaskRecord task, String reason) {
+ final ActivityStack prevStack = task.stack;
+ if (prevStack != null && prevStack != this) {
+ prevStack.removeTask(task, reason, MOVING);
+ }
+ return prevStack;
+ }
+
+ private void postAddTask(TaskRecord task, ActivityStack prevStack) {
+ if (prevStack != null) {
+ if (prevStack != this
+ && (prevStack.mStackId == PINNED_STACK_ID || mStackId == PINNED_STACK_ID)) {
+ task.reportPictureInPictureModeChange();
+ }
+ } else if (task.voiceSession != null) {
try {
task.voiceSession.taskStarted(task.intent, task.taskId);
} catch (RemoteException e) {
@@ -4754,6 +4769,7 @@
r.setTask(task, null);
task.addActivityToTop(r);
setAppTask(r, task);
+ task.reportPictureInPictureModeChange();
setFocusAndResumeStateIfNeeded(r, wasFocused, wasResumed, "moveActivityToStack");
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 18b3e62..f4ba19f 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2337,8 +2337,8 @@
// above. Go ahead and reset it.
targetStack = computeStackFocus(
sourceRecord, false /* newTask */, null /* bounds */);
- targetStack.addTask(
- task, !launchTaskBehind /* toTop */, false /* moving */);
+ targetStack.addTask(task,
+ !launchTaskBehind /* toTop */, "startActivityUnchecked");
}
}
@@ -3344,7 +3344,7 @@
return false;
}
- stack.addTask(task, false, false);
+ stack.addTask(task, false, "restoreRecentTask");
if (DEBUG_RECENTS) Slog.v(TAG_RECENTS,
"Added restored task=" + task + " to stack=" + stack);
final ArrayList<ActivityRecord> activities = task.mActivities;
@@ -3381,10 +3381,7 @@
final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, toTop);
task.mResizeable = resizeable;
mWindowManager.moveTaskToStack(task.taskId, stack.mStackId, toTop);
- if (task.stack != null) {
- task.stack.removeTask(task, reason, MOVING);
- }
- stack.addTask(task, toTop, MOVING);
+ stack.addTask(task, toTop, reason);
// If the task had focus before (or we're requested to move focus),
// move focus to the new stack.
@@ -3499,11 +3496,7 @@
mWindowManager.positionTaskInStack(
taskId, stackId, position, task.mBounds, task.mOverrideConfig);
- final boolean stackChanged = task.stack != null && task.stack != stack;
- if (stackChanged) {
- task.stack.removeTask(task, "moveTaskToStack", MOVING);
- }
- stack.positionTask(task, position, stackChanged);
+ stack.positionTask(task, position);
// The task might have already been running and its visibility needs to be synchronized with
// the visibility of the stack / windows.
stack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 4d18e96..5ee9eea 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -20,6 +20,7 @@
import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
@@ -1262,7 +1263,8 @@
if (Objects.equals(mBounds, bounds)) {
return null;
}
- Configuration oldConfig = mOverrideConfig;
+ final Configuration oldConfig = mOverrideConfig;
+ final boolean oldFullscreen = mFullscreen;
mFullscreen = bounds == null;
if (mFullscreen) {
@@ -1296,9 +1298,43 @@
? Configuration.ORIENTATION_PORTRAIT
: Configuration.ORIENTATION_LANDSCAPE;
}
+
+ if (mFullscreen != oldFullscreen) {
+ reportMultiWindowModeChange();
+ }
+
return !mOverrideConfig.equals(oldConfig) ? mOverrideConfig : null;
}
+ private void reportMultiWindowModeChange() {
+ for (int i = mActivities.size() - 1; i >= 0; i--) {
+ final ActivityRecord r = mActivities.get(i);
+ if (r.app != null && r.app.thread != null) {
+ try {
+ // An activity is consider to be in multi-window mode if its task isn't
+ // fullscreen.
+ r.app.thread.scheduleMultiWindowModeChanged(r.appToken, !mFullscreen);
+ } catch (Exception e) {
+ Slog.e(TAG, "TaskRecord.reportMultiWindowModeChange: ", e);
+ }
+ }
+ }
+ }
+
+ void reportPictureInPictureModeChange() {
+ for (int i = mActivities.size() - 1; i >= 0; i--) {
+ final ActivityRecord r = mActivities.get(i);
+ if (r.app != null && r.app.thread != null) {
+ try {
+ r.app.thread.schedulePictureInPictureModeChanged(
+ r.appToken, stack.mStackId == PINNED_STACK_ID);
+ } catch (Exception e) {
+ Slog.e(TAG, "TaskRecord.reportMultiWindowModeChange: ", e);
+ }
+ }
+ }
+ }
+
/** Updates the task's bounds and override configuration to match what is expected for the
* input stack. */
void updateOverrideConfigurationForStack(ActivityStack inStack) {