Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4a85741b authored by Chris Li's avatar Chris Li
Browse files

Allow TaskDisplayArea to have TaskDisplayArea children (3/n)

- Have TaskDisplayArea extends DisplayArea<WindowContainer>

Bug: 175136051
Test: Passed existing tests
Change-Id: I33474acfb0fdb665823a6dcb63635f1e7702a1e2
parent bde6cfbd
Loading
Loading
Loading
Loading
+18 −18
Original line number Diff line number Diff line
@@ -901,6 +901,12 @@
      "group": "WM_DEBUG_ORIENTATION",
      "at": "com\/android\/server\/wm\/WindowManagerService.java"
    },
    "-1069336896": {
      "message": "onRootTaskOrderChanged(): rootTask=%s",
      "level": "DEBUG",
      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
    },
    "-1066383762": {
      "message": "Sleep still waiting to pause %s",
      "level": "VERBOSE",
@@ -1303,6 +1309,12 @@
      "group": "WM_DEBUG_CONFIGURATION",
      "at": "com\/android\/server\/am\/ActivityManagerService.java"
    },
    "-592371899": {
      "message": "Skipping rootTask: (mismatch activity\/rootTask) %s",
      "level": "DEBUG",
      "group": "WM_DEBUG_TASKS",
      "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
    },
    "-583031528": {
      "message": "%s",
      "level": "INFO",
@@ -2119,12 +2131,6 @@
      "group": "WM_DEBUG_APP_TRANSITIONS",
      "at": "com\/android\/server\/wm\/AppTransition.java"
    },
    "349443311": {
      "message": "pauseBackStacks: task=%s mResumedActivity=%s",
      "level": "DEBUG",
      "group": "WM_DEBUG_STATES",
      "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
    },
    "355720268": {
      "message": "stopFreezingDisplayLocked: Unfreezing now",
      "level": "DEBUG",
@@ -2161,6 +2167,12 @@
      "group": "WM_DEBUG_BOOT",
      "at": "com\/android\/server\/wm\/WindowManagerService.java"
    },
    "391189028": {
      "message": "pauseBackTasks: task=%s mResumedActivity=%s",
      "level": "DEBUG",
      "group": "WM_DEBUG_STATES",
      "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
    },
    "397105698": {
      "message": "grantEmbeddedWindowFocus remove request for win=%s dropped since no candidate was found",
      "level": "VERBOSE",
@@ -2245,12 +2257,6 @@
      "group": "WM_DEBUG_WINDOW_ORGANIZER",
      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
    },
    "490877640": {
      "message": "onStackOrderChanged(): stack=%s",
      "level": "DEBUG",
      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
    },
    "495032901": {
      "message": "Expected target stack=%s to restored behind stack=%s but it is behind stack=%s",
      "level": "WARN",
@@ -2575,12 +2581,6 @@
      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
    },
    "875196661": {
      "message": "Skipping stack: (mismatch activity\/stack) %s",
      "level": "DEBUG",
      "group": "WM_DEBUG_TASKS",
      "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
    },
    "883475718": {
      "message": "Report configuration: %s %s %s",
      "level": "VERBOSE",
+12 −11
Original line number Diff line number Diff line
@@ -2300,10 +2300,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
        return count[0];
    }

    @VisibleForTesting
    @Nullable
    Task getTopRootTask() {
        return getItemFromTaskDisplayAreas(TaskDisplayArea::getTopRootTask);
        return getRootTask(t -> true);
    }

    /**
@@ -5479,12 +5478,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
            return;
        }

        // Check if all task display areas have only the empty home stacks left.
        boolean hasNonEmptyHomeStack = forAllRootTasks(stack ->
                !stack.isActivityTypeHome() || stack.hasChild());
        if (!hasNonEmptyHomeStack && getRootTaskCount() > 0) {
            // Release this display if only empty home stack(s) are left. This display will be
            // released along with the stack(s) removal.
        // Check if all task display areas have only the empty home root tasks left.
        boolean hasNonEmptyHomeRootTask = forAllRootTasks(rootTask ->
                !rootTask.isActivityTypeHome() || rootTask.hasChild());
        if (!hasNonEmptyHomeRootTask && getRootTaskCount() > 0) {
            // Release this display if only empty home root task(s) are left. This display will be
            // released along with the root task(s) removal.
            forAllRootTasks(Task::removeIfPossible);
        } else if (getTopRootTask() == null) {
            removeIfPossible();
@@ -5525,12 +5524,14 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
            return;
        }
        mInEnsureActivitiesVisible = true;
        mAtmService.mTaskSupervisor.beginActivityVisibilityUpdate();
        try {
            forAllTaskDisplayAreas(taskDisplayArea -> {
                taskDisplayArea.ensureActivitiesVisible(starting, configChanges,
                        preserveWindows, notifyClients, userLeaving);
            forAllRootTasks(rootTask -> {
                rootTask.ensureActivitiesVisible(starting, configChanges, preserveWindows,
                        notifyClients, userLeaving);
            });
        } finally {
            mAtmService.mTaskSupervisor.endActivityVisibilityUpdate();
            mInEnsureActivitiesVisible = false;
        }
    }
+4 −3
Original line number Diff line number Diff line
@@ -413,9 +413,10 @@ class RecentsAnimation implements RecentsAnimationCallbacks, OnRootTaskOrderChan

    @Override
    public void onRootTaskOrderChanged(Task rootTask) {
        ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "onStackOrderChanged(): stack=%s", rootTask);
        if (mDefaultTaskDisplayArea.getIndexOf(rootTask) == -1 || !rootTask.shouldBeVisible(null)) {
            // The stack is not visible, so ignore this change
        ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "onRootTaskOrderChanged(): rootTask=%s", rootTask);
        if (mDefaultTaskDisplayArea.getRootTask(t -> t == rootTask) == null
                || !rootTask.shouldBeVisible(null)) {
            // The root task is not visible, so ignore this change
            return;
        }
        final RecentsAnimationController controller =
+70 −70
Original line number Diff line number Diff line
@@ -1828,19 +1828,19 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
    }

    /**
     * @return a list of activities which are the top ones in each visible stack. The first
     * @return a list of activities which are the top ones in each visible root task. The first
     * entry will be the focused activity.
     */
    List<IBinder> getTopVisibleActivities() {
        final ArrayList<IBinder> topActivityTokens = new ArrayList<>();
        final Task topFocusedStack = getTopDisplayFocusedRootTask();
        final Task topFocusedRootTask = getTopDisplayFocusedRootTask();
        // Traverse all displays.
        forAllRootTasks(stack -> {
            // Get top activity from a visible stack and add it to the list.
            if (stack.shouldBeVisible(null /* starting */)) {
                final ActivityRecord top = stack.getTopNonFinishingActivity();
        forAllRootTasks(rootTask -> {
            // Get top activity from a visible root task and add it to the list.
            if (rootTask.shouldBeVisible(null /* starting */)) {
                final ActivityRecord top = rootTask.getTopNonFinishingActivity();
                if (top != null) {
                    if (stack == topFocusedStack) {
                    if (rootTask == topFocusedRootTask) {
                        topActivityTokens.add(0, top.appToken);
                    } else {
                        topActivityTokens.add(top.appToken);
@@ -1854,9 +1854,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
    @Nullable
    Task getTopDisplayFocusedRootTask() {
        for (int i = getChildCount() - 1; i >= 0; --i) {
            final Task focusedStack = getChildAt(i).getFocusedRootTask();
            if (focusedStack != null) {
                return focusedStack;
            final Task focusedRootTask = getChildAt(i).getFocusedRootTask();
            if (focusedRootTask != null) {
                return focusedRootTask;
            }
        }
        return null;
@@ -1864,15 +1864,15 @@ class RootWindowContainer extends WindowContainer<DisplayContent>

    @Nullable
    ActivityRecord getTopResumedActivity() {
        final Task focusedStack = getTopDisplayFocusedRootTask();
        if (focusedStack == null) {
        final Task focusedRootTask = getTopDisplayFocusedRootTask();
        if (focusedRootTask == null) {
            return null;
        }
        final ActivityRecord resumedActivity = focusedStack.getResumedActivity();
        final ActivityRecord resumedActivity = focusedRootTask.getResumedActivity();
        if (resumedActivity != null && resumedActivity.app != null) {
            return resumedActivity;
        }
        // The top focused stack might not have a resumed activity yet - look on all displays in
        // The top focused root task might not have a resumed activity yet - look on all displays in
        // focus order.
        return getItemFromTaskDisplayAreas(TaskDisplayArea::getFocusedActivity);
    }
@@ -1997,36 +1997,36 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
    }

    boolean switchUser(int userId, UserState uss) {
        final Task topFocusedStack = getTopDisplayFocusedRootTask();
        final int focusStackId = topFocusedStack != null
                ? topFocusedStack.getRootTaskId() : INVALID_TASK_ID;
        // We dismiss the docked stack whenever we switch users.
        final Task topFocusedRootTask = getTopDisplayFocusedRootTask();
        final int focusRootTaskId = topFocusedRootTask != null
                ? topFocusedRootTask.getRootTaskId() : INVALID_TASK_ID;
        // We dismiss the docked root task whenever we switch users.
        if (getDefaultTaskDisplayArea().isSplitScreenModeActivated()) {
            getDefaultTaskDisplayArea().onSplitScreenModeDismissed();
        }
        // Also dismiss the pinned stack whenever we switch users. Removing the pinned stack will
        // also cause all tasks to be moved to the fullscreen stack at a position that is
        // Also dismiss the pinned root task whenever we switch users. Removing the pinned root task
        // will also cause all tasks to be moved to the fullscreen root task at a position that is
        // appropriate.
        removeRootTasksInWindowingModes(WINDOWING_MODE_PINNED);

        mUserRootTaskInFront.put(mCurrentUser, focusStackId);
        mUserRootTaskInFront.put(mCurrentUser, focusRootTaskId);
        mCurrentUser = userId;

        mTaskSupervisor.mStartingUsers.add(uss);
        forAllRootTasks(stack -> {
            stack.switchUser(userId);
        forAllRootTasks(rootTask -> {
            rootTask.switchUser(userId);
        });

        final int restoreStackId = mUserRootTaskInFront.get(userId);
        Task stack = getRootTask(restoreStackId);
        if (stack == null) {
            stack = getDefaultTaskDisplayArea().getOrCreateRootHomeTask();
        final int restoreRootTaskId = mUserRootTaskInFront.get(userId);
        Task rootTask = getRootTask(restoreRootTaskId);
        if (rootTask == null) {
            rootTask = getDefaultTaskDisplayArea().getOrCreateRootHomeTask();
        }
        final boolean homeInFront = stack.isActivityTypeHome();
        if (stack.isOnHomeDisplay()) {
            stack.moveToFront("switchUserOnHomeDisplay");
        final boolean homeInFront = rootTask.isActivityTypeHome();
        if (rootTask.isOnHomeDisplay()) {
            rootTask.moveToFront("switchUserOnHomeDisplay");
        } else {
            // Stack was moved to another display while user was swapped out.
            // Root task was moved to another display while user was swapped out.
            resumeHomeActivity(null, "switchUserOnOtherDisplay", getDefaultTaskDisplayArea());
        }
        return homeInFront;
@@ -2350,7 +2350,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
        return result;
    }

    void applySleepTokens(boolean applyToStacks) {
    void applySleepTokens(boolean applyToRootTasks) {
        for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
            // Set the sleeping state of the display.
            final DisplayContent display = getChildAt(displayNdx);
@@ -2360,17 +2360,17 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
            }
            display.setIsSleeping(displayShouldSleep);

            if (!applyToStacks) {
            if (!applyToRootTasks) {
                continue;
            }

            // Set the sleeping state of the stacks on the display.
            display.forAllRootTasks(stack -> {
            // Set the sleeping state of the root tasks on the display.
            display.forAllRootTasks(rootTask -> {
                if (displayShouldSleep) {
                    stack.goToSleepIfPossible(false /* shuttingDown */);
                    rootTask.goToSleepIfPossible(false /* shuttingDown */);
                } else {
                    stack.awakeFromSleepingLocked();
                    if (stack.isFocusedStackOnDisplay()
                    rootTask.awakeFromSleepingLocked();
                    if (rootTask.isFocusedStackOnDisplay()
                            && !mTaskSupervisor.getKeyguardController()
                            .isKeyguardOrAodShowing(display.mDisplayId)) {
                        // If the keyguard is unlocked - resume immediately.
@@ -2378,13 +2378,13 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
                        // process the keyguard going away, which can happen before the sleep
                        // token is released. As a result, it is important we resume the
                        // activity here.
                        stack.resumeTopActivityUncheckedLocked(null, null);
                        rootTask.resumeTopActivityUncheckedLocked(null, null);
                    }
                    // The visibility update must not be called before resuming the top, so the
                    // display orientation can be updated first if needed. Otherwise there may
                    // have redundant configuration changes due to apply outdated display
                    // orientation (from keyguard) to activity.
                    stack.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
                    rootTask.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
                            false /* preserveWindows */);
                }
            });
@@ -2427,7 +2427,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
        task.fillTaskInfo(info);

        // A task might be not attached to a display.
        info.position = taskDisplayArea != null ? taskDisplayArea.getIndexOf(task) : 0;
        info.position = taskDisplayArea != null ? taskDisplayArea.getTaskIndexOf(task) : 0;
        info.visible = task.shouldBeVisible(null);
        task.getBounds(info.bounds);

@@ -2471,21 +2471,21 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
    }

    RootTaskInfo getRootTaskInfo(int windowingMode, int activityType) {
        final Task stack = getRootTask(windowingMode, activityType);
        return (stack != null) ? getRootTaskInfo(stack) : null;
        final Task rootTask = getRootTask(windowingMode, activityType);
        return (rootTask != null) ? getRootTaskInfo(rootTask) : null;
    }

    RootTaskInfo getRootTaskInfo(int windowingMode, int activityType, int displayId) {
        final Task stack = getRootTask(windowingMode, activityType, displayId);
        return (stack != null) ? getRootTaskInfo(stack) : null;
        final Task rootTask = getRootTask(windowingMode, activityType, displayId);
        return (rootTask != null) ? getRootTaskInfo(rootTask) : null;
    }

    /** If displayId == INVALID_DISPLAY, this will get root task infos on all displays */
    ArrayList<RootTaskInfo> getAllRootTaskInfos(int displayId) {
        final ArrayList<RootTaskInfo> list = new ArrayList<>();
        if (displayId == INVALID_DISPLAY) {
            forAllRootTasks(stack -> {
                list.add(getRootTaskInfo(stack));
            forAllRootTasks(rootTask -> {
                list.add(getRootTaskInfo(rootTask));
            });
            return list;
        }
@@ -2493,8 +2493,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
        if (display == null) {
            return list;
        }
        display.forAllRootTasks(stack -> {
            list.add(getRootTaskInfo(stack));
        display.forAllRootTasks(rootTask -> {
            list.add(getRootTaskInfo(rootTask));
        });
        return list;
    }
@@ -2955,8 +2955,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
        }

        // If {@code r} is already in target display area and its task is the same as the candidate
        // task, the intention should be getting a launch stack for the reusable activity, so we can
        // use the existing stack.
        // task, the intention should be getting a launch root task for the reusable activity, so we
        // can use the existing root task.
        if (candidateTask != null) {
            final TaskDisplayArea attachedTaskDisplayArea = candidateTask.getDisplayArea();
            if (attachedTaskDisplayArea == null || attachedTaskDisplayArea == taskDisplayArea) {
@@ -2965,9 +2965,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
            // Or the candidate task is already a root task that can be reused by reparenting
            // it to the target display.
            if (candidateTask.isRootTask()) {
                final Task stack = candidateTask.getRootTask();
                stack.reparent(taskDisplayArea, true /* onTop */);
                return stack;
                final Task rootTask = candidateTask.getRootTask();
                rootTask.reparent(taskDisplayArea, true /* onTop */);
                return rootTask;
            }
        }

@@ -2984,16 +2984,16 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
        windowingMode = taskDisplayArea.validateWindowingMode(windowingMode, r, candidateTask,
                r.getActivityType());

        // Return the topmost valid stack on the display.
        // Return the topmost valid root task on the display.
        final int targetWindowingMode = windowingMode;
        final Task topmostValidStack = taskDisplayArea.getRootTask(stack ->
                isValidLaunchRootTask(stack, r, targetWindowingMode));
        if (topmostValidStack != null) {
            return topmostValidStack;
        final Task topmostValidRootTask = taskDisplayArea.getRootTask(rootTask ->
                isValidLaunchRootTask(rootTask, r, targetWindowingMode));
        if (topmostValidRootTask != null) {
            return topmostValidRootTask;
        }

        // If there is no valid stack on the secondary display area - check if new dynamic stack
        // will do.
        // If there is no valid root task on the secondary display area - check if new dynamic root
        // task will do.
        if (taskDisplayArea != getDisplayContent(taskDisplayArea.getDisplayId())
                .getDefaultTaskDisplayArea()) {
            final int activityType =
@@ -3224,8 +3224,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
    }

    void finishVoiceTask(IVoiceInteractionSession session) {
        forAllRootTasks(stack -> {
            stack.finishVoiceTask(session);
        forAllRootTasks(rootTask -> {
            rootTask.finishVoiceTask(session);
        });
    }

@@ -3284,8 +3284,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>

    boolean allResumedActivitiesVisible() {
        boolean[] foundResumed = {false};
        final boolean foundInvisibleResumedActivity = forAllRootTasks(stack -> {
            final ActivityRecord r = stack.getResumedActivity();
        final boolean foundInvisibleResumedActivity = forAllRootTasks(rootTask -> {
            final ActivityRecord r = rootTask.getResumedActivity();
            if (r != null) {
                if (!r.nowVisible) {
                    return true;
@@ -3529,9 +3529,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
            }
        } else {
            final ArrayList<ActivityRecord> activities = new ArrayList<>();
            forAllRootTasks(stack -> {
                if (!dumpVisibleStacksOnly || stack.shouldBeVisible(null)) {
                    activities.addAll(stack.getDumpActivitiesLocked(name));
            forAllRootTasks(rootTask -> {
                if (!dumpVisibleStacksOnly || rootTask.shouldBeVisible(null)) {
                    activities.addAll(rootTask.getDumpActivitiesLocked(name));
                }
            });
            return activities;
@@ -3581,11 +3581,11 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
            pw.print("Display #");
            pw.print(displayContent.mDisplayId);
            pw.println(" (activities from top to bottom):");
            displayContent.forAllRootTasks(stack -> {
            displayContent.forAllRootTasks(rootTask -> {
                if (needSep[0]) {
                    pw.println();
                }
                needSep[0] = stack.dump(fd, pw, dumpAll, dumpClient, dumpPackage, false);
                needSep[0] = rootTask.dump(fd, pw, dumpAll, dumpClient, dumpPackage, false);
                printed[0] |= needSep[0];
            });
            displayContent.forAllTaskDisplayAreas(taskDisplayArea -> {
+20 −18
Original line number Diff line number Diff line
@@ -5320,20 +5320,19 @@ class Task extends WindowContainer<WindowContainer> {
        final TaskDisplayArea taskDisplayArea = getDisplayArea();

        if (inSplitScreenSecondaryWindowingMode()) {
            // If the stack is in split-screen secondary mode, we need to make sure we move the
            // primary split-screen stack forward in the case it is currently behind a fullscreen
            // stack so both halves of the split-screen appear on-top and the fullscreen stack isn't
            // cutting between them.
            // If the root task is in split-screen secondary mode, we need to make sure we move the
            // primary split-screen root task forward in the case it is currently behind a
            // fullscreen root task so both halves of the split-screen appear on-top and the
            // fullscreen root task isn't cutting between them.
            // TODO(b/70677280): This is a workaround until we can fix as part of b/70677280.
            final Task topFullScreenStack =
            final Task topFullScreenRootTask =
                    taskDisplayArea.getTopRootTaskInWindowingMode(WINDOWING_MODE_FULLSCREEN);
            if (topFullScreenStack != null) {
                final Task primarySplitScreenStack =
            if (topFullScreenRootTask != null) {
                final Task primarySplitScreenRootTask =
                        taskDisplayArea.getRootSplitScreenPrimaryTask();
                if (primarySplitScreenStack != null
                        && taskDisplayArea.getIndexOf(topFullScreenStack)
                        > taskDisplayArea.getIndexOf(primarySplitScreenStack)) {
                    primarySplitScreenStack.moveToFront(reason + " splitScreenToTop");
                if (primarySplitScreenRootTask != null
                        && topFullScreenRootTask.compareTo(primarySplitScreenRootTask) > 0) {
                    primarySplitScreenRootTask.moveToFront(reason + " splitScreenToTop");
                }
            }
        }
@@ -5748,7 +5747,7 @@ class Task extends WindowContainer<WindowContainer> {
    }

    /**
     * @return {@code true} if this is the focused stack on its current display, {@code false}
     * @return {@code true} if this is the focused root task on its current display, {@code false}
     * otherwise.
     */
    boolean isFocusedStackOnDisplay() {
@@ -6700,18 +6699,21 @@ class Task extends WindowContainer<WindowContainer> {
        });
    }

    /** @return true if the stack behind this one is a standard activity type. */
    private boolean inFrontOfStandardStack() {
    /** @return true if the root task behind this one is a standard activity type. */
    private boolean inFrontOfStandardRootTask() {
        final TaskDisplayArea taskDisplayArea = getDisplayArea();
        if (taskDisplayArea == null) {
            return false;
        }
        final int index = taskDisplayArea.getIndexOf(this);
        final int index = taskDisplayArea.getTaskIndexOf(this);
        if (index == 0) {
            return false;
        }
        final Task stackBehind = taskDisplayArea.getChildAt(index - 1);
        return stackBehind.isActivityTypeStandard();
        final int[] indexCount = new int[1];
        final Task rootTaskBehind = taskDisplayArea.getRootTask(
                // From bottom to top, find the one behind this Task.
                task -> ++indexCount[0] == index, false /* traverseTopToBottom */);
        return rootTaskBehind.isActivityTypeStandard();
    }

    boolean shouldUpRecreateTaskLocked(ActivityRecord srec, String destAffinity) {
@@ -6732,7 +6734,7 @@ class Task extends WindowContainer<WindowContainer> {
        if (srec.isRootOfTask() && task.getBaseIntent() != null
                && task.getBaseIntent().isDocument()) {
            // Okay, this activity is at the root of its task.  What to do, what to do...
            if (!inFrontOfStandardStack()) {
            if (!inFrontOfStandardRootTask()) {
                // Finishing won't return to an application, so we need to recreate.
                return true;
            }
Loading