Merge "Fixes app crash when starts activity with FLAG_ACTIVITY_REORDER_TO_FRONT" into tm-qpr-dev
This commit is contained in:
@@ -82,6 +82,12 @@ public final class TaskFragmentInfo implements Parcelable {
|
|||||||
*/
|
*/
|
||||||
private final boolean mIsTaskFragmentClearedForPip;
|
private final boolean mIsTaskFragmentClearedForPip;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the last running activity of the TaskFragment was removed because it was reordered to
|
||||||
|
* front of the Task.
|
||||||
|
*/
|
||||||
|
private final boolean mIsClearedForReorderActivityToFront;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The maximum {@link ActivityInfo.WindowLayout#minWidth} and
|
* The maximum {@link ActivityInfo.WindowLayout#minWidth} and
|
||||||
* {@link ActivityInfo.WindowLayout#minHeight} aggregated from the TaskFragment's child
|
* {@link ActivityInfo.WindowLayout#minHeight} aggregated from the TaskFragment's child
|
||||||
@@ -96,7 +102,7 @@ public final class TaskFragmentInfo implements Parcelable {
|
|||||||
@NonNull Configuration configuration, int runningActivityCount,
|
@NonNull Configuration configuration, int runningActivityCount,
|
||||||
boolean isVisible, @NonNull List<IBinder> activities, @NonNull Point positionInParent,
|
boolean isVisible, @NonNull List<IBinder> activities, @NonNull Point positionInParent,
|
||||||
boolean isTaskClearedForReuse, boolean isTaskFragmentClearedForPip,
|
boolean isTaskClearedForReuse, boolean isTaskFragmentClearedForPip,
|
||||||
@NonNull Point minimumDimensions) {
|
boolean isClearedForReorderActivityToFront, @NonNull Point minimumDimensions) {
|
||||||
mFragmentToken = requireNonNull(fragmentToken);
|
mFragmentToken = requireNonNull(fragmentToken);
|
||||||
mToken = requireNonNull(token);
|
mToken = requireNonNull(token);
|
||||||
mConfiguration.setTo(configuration);
|
mConfiguration.setTo(configuration);
|
||||||
@@ -106,6 +112,7 @@ public final class TaskFragmentInfo implements Parcelable {
|
|||||||
mPositionInParent.set(positionInParent);
|
mPositionInParent.set(positionInParent);
|
||||||
mIsTaskClearedForReuse = isTaskClearedForReuse;
|
mIsTaskClearedForReuse = isTaskClearedForReuse;
|
||||||
mIsTaskFragmentClearedForPip = isTaskFragmentClearedForPip;
|
mIsTaskFragmentClearedForPip = isTaskFragmentClearedForPip;
|
||||||
|
mIsClearedForReorderActivityToFront = isClearedForReorderActivityToFront;
|
||||||
mMinimumDimensions.set(minimumDimensions);
|
mMinimumDimensions.set(minimumDimensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,6 +167,11 @@ public final class TaskFragmentInfo implements Parcelable {
|
|||||||
return mIsTaskFragmentClearedForPip;
|
return mIsTaskFragmentClearedForPip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @hide */
|
||||||
|
public boolean isClearedForReorderActivityToFront() {
|
||||||
|
return mIsClearedForReorderActivityToFront;
|
||||||
|
}
|
||||||
|
|
||||||
@WindowingMode
|
@WindowingMode
|
||||||
public int getWindowingMode() {
|
public int getWindowingMode() {
|
||||||
return mConfiguration.windowConfiguration.getWindowingMode();
|
return mConfiguration.windowConfiguration.getWindowingMode();
|
||||||
@@ -207,6 +219,7 @@ public final class TaskFragmentInfo implements Parcelable {
|
|||||||
&& mPositionInParent.equals(that.mPositionInParent)
|
&& mPositionInParent.equals(that.mPositionInParent)
|
||||||
&& mIsTaskClearedForReuse == that.mIsTaskClearedForReuse
|
&& mIsTaskClearedForReuse == that.mIsTaskClearedForReuse
|
||||||
&& mIsTaskFragmentClearedForPip == that.mIsTaskFragmentClearedForPip
|
&& mIsTaskFragmentClearedForPip == that.mIsTaskFragmentClearedForPip
|
||||||
|
&& mIsClearedForReorderActivityToFront == that.mIsClearedForReorderActivityToFront
|
||||||
&& mMinimumDimensions.equals(that.mMinimumDimensions);
|
&& mMinimumDimensions.equals(that.mMinimumDimensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,6 +233,7 @@ public final class TaskFragmentInfo implements Parcelable {
|
|||||||
mPositionInParent.readFromParcel(in);
|
mPositionInParent.readFromParcel(in);
|
||||||
mIsTaskClearedForReuse = in.readBoolean();
|
mIsTaskClearedForReuse = in.readBoolean();
|
||||||
mIsTaskFragmentClearedForPip = in.readBoolean();
|
mIsTaskFragmentClearedForPip = in.readBoolean();
|
||||||
|
mIsClearedForReorderActivityToFront = in.readBoolean();
|
||||||
mMinimumDimensions.readFromParcel(in);
|
mMinimumDimensions.readFromParcel(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,6 +249,7 @@ public final class TaskFragmentInfo implements Parcelable {
|
|||||||
mPositionInParent.writeToParcel(dest, flags);
|
mPositionInParent.writeToParcel(dest, flags);
|
||||||
dest.writeBoolean(mIsTaskClearedForReuse);
|
dest.writeBoolean(mIsTaskClearedForReuse);
|
||||||
dest.writeBoolean(mIsTaskFragmentClearedForPip);
|
dest.writeBoolean(mIsTaskFragmentClearedForPip);
|
||||||
|
dest.writeBoolean(mIsClearedForReorderActivityToFront);
|
||||||
mMinimumDimensions.writeToParcel(dest, flags);
|
mMinimumDimensions.writeToParcel(dest, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,8 +277,9 @@ public final class TaskFragmentInfo implements Parcelable {
|
|||||||
+ " activities=" + mActivities
|
+ " activities=" + mActivities
|
||||||
+ " positionInParent=" + mPositionInParent
|
+ " positionInParent=" + mPositionInParent
|
||||||
+ " isTaskClearedForReuse=" + mIsTaskClearedForReuse
|
+ " isTaskClearedForReuse=" + mIsTaskClearedForReuse
|
||||||
+ " isTaskFragmentClearedForPip" + mIsTaskFragmentClearedForPip
|
+ " isTaskFragmentClearedForPip=" + mIsTaskFragmentClearedForPip
|
||||||
+ " minimumDimensions" + mMinimumDimensions
|
+ " mIsClearedForReorderActivityToFront=" + mIsClearedForReorderActivityToFront
|
||||||
|
+ " minimumDimensions=" + mMinimumDimensions
|
||||||
+ "}";
|
+ "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -389,6 +389,10 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
// launching activity in the Task.
|
// launching activity in the Task.
|
||||||
mTransactionManager.getCurrentTransactionRecord().setOriginType(TRANSIT_CLOSE);
|
mTransactionManager.getCurrentTransactionRecord().setOriginType(TRANSIT_CLOSE);
|
||||||
mPresenter.cleanupContainer(wct, container, false /* shouldFinishDependent */);
|
mPresenter.cleanupContainer(wct, container, false /* shouldFinishDependent */);
|
||||||
|
} else if (taskFragmentInfo.isClearedForReorderActivityToFront()) {
|
||||||
|
// Do not finish the dependents if this TaskFragment was cleared to reorder
|
||||||
|
// the launching Activity to front of the Task.
|
||||||
|
mPresenter.cleanupContainer(wct, container, false /* shouldFinishDependent */);
|
||||||
} else if (!container.isWaitingActivityAppear()) {
|
} else if (!container.isWaitingActivityAppear()) {
|
||||||
// Do not finish the container before the expected activity appear until
|
// Do not finish the container before the expected activity appear until
|
||||||
// timeout.
|
// timeout.
|
||||||
|
|||||||
@@ -169,6 +169,7 @@ public class EmbeddingTestUtils {
|
|||||||
new Point(),
|
new Point(),
|
||||||
false /* isTaskClearedForReuse */,
|
false /* isTaskClearedForReuse */,
|
||||||
false /* isTaskFragmentClearedForPip */,
|
false /* isTaskFragmentClearedForPip */,
|
||||||
|
false /* isClearedForReorderActivityToFront */,
|
||||||
new Point());
|
new Point());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -144,6 +144,6 @@ public class JetpackTaskFragmentOrganizerTest {
|
|||||||
mock(WindowContainerToken.class), new Configuration(), 0 /* runningActivityCount */,
|
mock(WindowContainerToken.class), new Configuration(), 0 /* runningActivityCount */,
|
||||||
false /* isVisible */, new ArrayList<>(), new Point(),
|
false /* isVisible */, new ArrayList<>(), new Point(),
|
||||||
false /* isTaskClearedForReuse */, false /* isTaskFragmentClearedForPip */,
|
false /* isTaskClearedForReuse */, false /* isTaskFragmentClearedForPip */,
|
||||||
new Point());
|
false /* isClearedForReorderActivityToFront */, new Point());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2394,7 +2394,7 @@ class ActivityStarter {
|
|||||||
mStartActivity.mUserId);
|
mStartActivity.mUserId);
|
||||||
if (act != null) {
|
if (act != null) {
|
||||||
final Task task = act.getTask();
|
final Task task = act.getTask();
|
||||||
boolean actuallyMoved = task.moveActivityToFrontLocked(act);
|
boolean actuallyMoved = task.moveActivityToFront(act);
|
||||||
if (actuallyMoved) {
|
if (actuallyMoved) {
|
||||||
// Only record if the activity actually moved.
|
// Only record if the activity actually moved.
|
||||||
mMovedToTopActivity = act;
|
mMovedToTopActivity = act;
|
||||||
|
|||||||
@@ -1408,13 +1408,26 @@ class Task extends TaskFragment {
|
|||||||
* Reorder the history task so that the passed activity is brought to the front.
|
* Reorder the history task so that the passed activity is brought to the front.
|
||||||
* @return whether it was actually moved (vs already being top).
|
* @return whether it was actually moved (vs already being top).
|
||||||
*/
|
*/
|
||||||
final boolean moveActivityToFrontLocked(ActivityRecord newTop) {
|
final boolean moveActivityToFront(ActivityRecord newTop) {
|
||||||
ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing and adding activity %s to root task at top "
|
ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing and adding activity %s to root task at top "
|
||||||
+ "callers=%s", newTop, Debug.getCallers(4));
|
+ "callers=%s", newTop, Debug.getCallers(4));
|
||||||
int origDist = getDistanceFromTop(newTop);
|
final TaskFragment taskFragment = newTop.getTaskFragment();
|
||||||
positionChildAtTop(newTop);
|
boolean moved;
|
||||||
|
if (taskFragment != this) {
|
||||||
|
if (taskFragment.isEmbedded() && taskFragment.getNonFinishingActivityCount() == 1) {
|
||||||
|
taskFragment.mClearedForReorderActivityToFront = true;
|
||||||
|
}
|
||||||
|
newTop.reparent(this, POSITION_TOP);
|
||||||
|
moved = true;
|
||||||
|
if (taskFragment.isEmbedded()) {
|
||||||
|
mAtmService.mWindowOrganizerController.mTaskFragmentOrganizerController
|
||||||
|
.onActivityReparentedToTask(newTop);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
moved = moveChildToFront(newTop);
|
||||||
|
}
|
||||||
updateEffectiveIntent();
|
updateEffectiveIntent();
|
||||||
return getDistanceFromTop(newTop) != origDist;
|
return moved;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -3096,20 +3109,6 @@ class Task extends TaskFragment {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void positionChildAtTop(ActivityRecord child) {
|
|
||||||
positionChildAt(child, POSITION_TOP);
|
|
||||||
}
|
|
||||||
|
|
||||||
void positionChildAt(ActivityRecord child, int position) {
|
|
||||||
if (child == null) {
|
|
||||||
Slog.w(TAG_WM,
|
|
||||||
"Attempted to position of non-existing app");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
positionChildAt(position, child, false /* includeParents */);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setTaskDescription(TaskDescription taskDescription) {
|
void setTaskDescription(TaskDescription taskDescription) {
|
||||||
mTaskDescription = taskDescription;
|
mTaskDescription = taskDescription;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -246,6 +246,12 @@ class TaskFragment extends WindowContainer<WindowContainer> {
|
|||||||
*/
|
*/
|
||||||
boolean mClearedTaskFragmentForPip;
|
boolean mClearedTaskFragmentForPip;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The last running activity of the TaskFragment was removed and added to the top-most of the
|
||||||
|
* Task because it was launched with FLAG_ACTIVITY_REORDER_TO_FRONT.
|
||||||
|
*/
|
||||||
|
boolean mClearedForReorderActivityToFront;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When we are in the process of pausing an activity, before starting the
|
* When we are in the process of pausing an activity, before starting the
|
||||||
* next one, this variable holds the activity that is currently being paused.
|
* next one, this variable holds the activity that is currently being paused.
|
||||||
@@ -1866,6 +1872,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
|
|||||||
ActivityRecord r = topRunningActivity();
|
ActivityRecord r = topRunningActivity();
|
||||||
mClearedTaskForReuse = false;
|
mClearedTaskForReuse = false;
|
||||||
mClearedTaskFragmentForPip = false;
|
mClearedTaskFragmentForPip = false;
|
||||||
|
mClearedForReorderActivityToFront = false;
|
||||||
|
|
||||||
final ActivityRecord addingActivity = child.asActivityRecord();
|
final ActivityRecord addingActivity = child.asActivityRecord();
|
||||||
final boolean isAddingActivity = addingActivity != null;
|
final boolean isAddingActivity = addingActivity != null;
|
||||||
@@ -2465,6 +2472,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
|
|||||||
positionInParent,
|
positionInParent,
|
||||||
mClearedTaskForReuse,
|
mClearedTaskForReuse,
|
||||||
mClearedTaskFragmentForPip,
|
mClearedTaskFragmentForPip,
|
||||||
|
mClearedForReorderActivityToFront,
|
||||||
calculateMinDimension());
|
calculateMinDimension());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2743,6 +2751,16 @@ class TaskFragment extends WindowContainer<WindowContainer> {
|
|||||||
return callback.test(this) ? this : null;
|
return callback.test(this) ? this : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the passed child to front
|
||||||
|
* @return whether it was actually moved (vs already being top).
|
||||||
|
*/
|
||||||
|
boolean moveChildToFront(WindowContainer newTop) {
|
||||||
|
int origDist = getDistanceFromTop(newTop);
|
||||||
|
positionChildAt(POSITION_TOP, newTop, false /* includeParents */);
|
||||||
|
return getDistanceFromTop(newTop) != origDist;
|
||||||
|
}
|
||||||
|
|
||||||
String toFullString() {
|
String toFullString() {
|
||||||
final StringBuilder sb = new StringBuilder(128);
|
final StringBuilder sb = new StringBuilder(128);
|
||||||
sb.append(this);
|
sb.append(this);
|
||||||
|
|||||||
@@ -2809,7 +2809,7 @@ public class ActivityRecordTests extends WindowTestsBase {
|
|||||||
final Task task = activity.getTask();
|
final Task task = activity.getTask();
|
||||||
final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build();
|
final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build();
|
||||||
topActivity.setVisible(false);
|
topActivity.setVisible(false);
|
||||||
task.positionChildAt(topActivity, POSITION_TOP);
|
task.positionChildAt(POSITION_TOP, topActivity, false /* includeParents */);
|
||||||
activity.addStartingWindow(mPackageName, android.R.style.Theme, null, true, true, false,
|
activity.addStartingWindow(mPackageName, android.R.style.Theme, null, true, true, false,
|
||||||
true, false, false, false);
|
true, false, false, false);
|
||||||
waitUntilHandlersIdle();
|
waitUntilHandlersIdle();
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import static android.view.Surface.ROTATION_0;
|
|||||||
import static android.view.Surface.ROTATION_90;
|
import static android.view.Surface.ROTATION_90;
|
||||||
import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
|
import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
|
||||||
|
|
||||||
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
|
||||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
||||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
||||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
|
||||||
@@ -82,6 +83,7 @@ import android.util.TypedXmlSerializer;
|
|||||||
import android.util.Xml;
|
import android.util.Xml;
|
||||||
import android.view.Display;
|
import android.view.Display;
|
||||||
import android.view.DisplayInfo;
|
import android.view.DisplayInfo;
|
||||||
|
import android.window.TaskFragmentOrganizer;
|
||||||
|
|
||||||
import androidx.test.filters.MediumTest;
|
import androidx.test.filters.MediumTest;
|
||||||
|
|
||||||
@@ -1469,6 +1471,26 @@ public class TaskTests extends WindowTestsBase {
|
|||||||
tf0, parentTask.getTaskFragment(TaskFragment::isOrganizedTaskFragment));
|
tf0, parentTask.getTaskFragment(TaskFragment::isOrganizedTaskFragment));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReorderActivityToFront() {
|
||||||
|
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
|
||||||
|
final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
|
||||||
|
doNothing().when(task).onActivityVisibleRequestedChanged();
|
||||||
|
final ActivityRecord activity = task.getTopMostActivity();
|
||||||
|
|
||||||
|
final TaskFragment fragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
|
||||||
|
final ActivityRecord embeddedActivity = fragment.getTopMostActivity();
|
||||||
|
task.moveActivityToFront(activity);
|
||||||
|
assertEquals("Activity must be moved to front", activity, task.getTopMostActivity());
|
||||||
|
|
||||||
|
doNothing().when(fragment).sendTaskFragmentInfoChanged();
|
||||||
|
task.moveActivityToFront(embeddedActivity);
|
||||||
|
assertEquals("Activity must be moved to front", embeddedActivity,
|
||||||
|
task.getTopMostActivity());
|
||||||
|
assertEquals("Activity must not be embedded", embeddedActivity,
|
||||||
|
task.getTopChild());
|
||||||
|
}
|
||||||
|
|
||||||
private Task getTestTask() {
|
private Task getTestTask() {
|
||||||
final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
|
final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
|
||||||
return task.getBottomMostTask();
|
return task.getBottomMostTask();
|
||||||
|
|||||||
Reference in New Issue
Block a user