blob: c4e03f5c65f51512c1cb7c74216b122c407d6add [file] [log] [blame]
Wale Ogunwale076c3b12019-11-20 12:17:22 -08001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.wm;
18
19import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
20
21import static com.android.server.wm.ActivityStack.TAG_VISIBILITY;
22import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_VISIBILITY;
23
Diego Vela671c0072020-03-25 09:39:26 -070024import android.annotation.Nullable;
Wale Ogunwale076c3b12019-11-20 12:17:22 -080025import android.util.Slog;
26
27import com.android.internal.util.function.pooled.PooledConsumer;
28import com.android.internal.util.function.pooled.PooledLambda;
29
30/** Helper class to ensure activities are in the right visible state for a container. */
31class EnsureActivitiesVisibleHelper {
32 private final ActivityStack mContiner;
33 private ActivityRecord mTop;
34 private ActivityRecord mStarting;
35 private boolean mAboveTop;
36 private boolean mContainerShouldBeVisible;
37 private boolean mBehindFullscreenActivity;
38 private int mConfigChanges;
39 private boolean mPreserveWindows;
40 private boolean mNotifyClients;
41
42 EnsureActivitiesVisibleHelper(ActivityStack container) {
43 mContiner = container;
44 }
45
Diego Vela671c0072020-03-25 09:39:26 -070046 /**
47 * Update all attributes except {@link mContiner} to use in subsequent calculations.
48 *
49 * @param starting The activity that is being started
50 * @param configChanges Parts of the configuration that changed for this activity for evaluating
51 * if the screen should be frozen.
52 * @param preserveWindows Flag indicating whether windows should be preserved when updating.
53 * @param notifyClients Flag indicating whether the configuration and visibility changes shoulc
54 * be sent to the clients.
55 */
Wale Ogunwale076c3b12019-11-20 12:17:22 -080056 void reset(ActivityRecord starting, int configChanges, boolean preserveWindows,
57 boolean notifyClients) {
58 mStarting = starting;
Wale Ogunwale85fb19a2019-12-05 10:41:05 +090059 mTop = mContiner.topRunningActivity();
Wale Ogunwale076c3b12019-11-20 12:17:22 -080060 // If the top activity is not fullscreen, then we need to make sure any activities under it
61 // are now visible.
62 mAboveTop = mTop != null;
63 mContainerShouldBeVisible = mContiner.shouldBeVisible(mStarting);
64 mBehindFullscreenActivity = !mContainerShouldBeVisible;
65 mConfigChanges = configChanges;
66 mPreserveWindows = preserveWindows;
67 mNotifyClients = notifyClients;
68 }
69
70 /**
71 * Ensure visibility with an option to also update the configuration of visible activities.
72 * @see ActivityStack#ensureActivitiesVisible(ActivityRecord, int, boolean)
Louis Chang149d5c82019-12-30 09:47:39 +080073 * @see RootWindowContainer#ensureActivitiesVisible(ActivityRecord, int, boolean)
Diego Vela671c0072020-03-25 09:39:26 -070074 * @param starting The top most activity in the task.
75 * The activity is either starting or resuming.
76 * Caller should ensure starting activity is visible.
77 *
78 * @param configChanges Parts of the configuration that changed for this activity for evaluating
79 * if the screen should be frozen.
80 * @param preserveWindows Flag indicating whether windows should be preserved when updating.
81 * @param notifyClients Flag indicating whether the configuration and visibility changes shoulc
82 * be sent to the clients.
Wale Ogunwale076c3b12019-11-20 12:17:22 -080083 */
Diego Vela671c0072020-03-25 09:39:26 -070084 void process(@Nullable ActivityRecord starting, int configChanges, boolean preserveWindows,
Wale Ogunwale076c3b12019-11-20 12:17:22 -080085 boolean notifyClients) {
86 reset(starting, configChanges, preserveWindows, notifyClients);
87
88 if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "ensureActivitiesVisible behind " + mTop
89 + " configChanges=0x" + Integer.toHexString(configChanges));
90 if (mTop != null) {
91 mContiner.checkTranslucentActivityWaiting(mTop);
92 }
93
94 // We should not resume activities that being launched behind because these
95 // activities are actually behind other fullscreen activities, but still required
96 // to be visible (such as performing Recents animation).
97 final boolean resumeTopActivity = mTop != null && !mTop.mLaunchTaskBehind
Evan Rosky226de132020-01-03 18:00:29 -080098 && mContiner.isTopActivityFocusable()
Wale Ogunwale0d465192020-01-23 19:14:44 -080099 && (starting == null || !starting.isDescendantOf(mContiner));
Wale Ogunwale076c3b12019-11-20 12:17:22 -0800100
101 final PooledConsumer f = PooledLambda.obtainConsumer(
102 EnsureActivitiesVisibleHelper::setActivityVisibilityState, this,
Andrii Kulianb9faa032019-10-17 23:11:54 -0700103 PooledLambda.__(ActivityRecord.class), starting, resumeTopActivity);
Wale Ogunwale076c3b12019-11-20 12:17:22 -0800104 mContiner.forAllActivities(f);
105 f.recycle();
106 }
107
Andrii Kulianb9faa032019-10-17 23:11:54 -0700108 private void setActivityVisibilityState(ActivityRecord r, ActivityRecord starting,
109 final boolean resumeTopActivity) {
Wale Ogunwale076c3b12019-11-20 12:17:22 -0800110 final boolean isTop = r == mTop;
111 if (mAboveTop && !isTop) {
112 return;
113 }
114 mAboveTop = false;
115
116 final boolean reallyVisible = r.shouldBeVisible(
117 mBehindFullscreenActivity, false /* ignoringKeyguard */);
118
119 // Check whether activity should be visible without Keyguard influence
120 if (r.visibleIgnoringKeyguard) {
121 if (r.occludesParent()) {
122 // At this point, nothing else needs to be shown in this task.
123 if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Fullscreen: at " + r
124 + " stackVisible=" + mContainerShouldBeVisible
125 + " behindFullscreen=" + mBehindFullscreenActivity);
126 mBehindFullscreenActivity = true;
127 } else {
128 mBehindFullscreenActivity = false;
129 }
130 }
131
132 if (reallyVisible) {
133 if (r.finishing) {
134 return;
135 }
136 if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make visible? " + r
137 + " finishing=" + r.finishing + " state=" + r.getState());
138 // First: if this is not the current activity being started, make
139 // sure it matches the current configuration.
140 if (r != mStarting && mNotifyClients) {
141 r.ensureActivityConfiguration(0 /* globalChanges */, mPreserveWindows,
142 true /* ignoreVisibility */);
143 }
144
145 if (!r.attachedToProcess()) {
146 makeVisibleAndRestartIfNeeded(mStarting, mConfigChanges, isTop,
147 resumeTopActivity && isTop, r);
148 } else if (r.mVisibleRequested) {
149 // If this activity is already visible, then there is nothing to do here.
150 if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
151 "Skipping: already visible at " + r);
152
153 if (r.mClientVisibilityDeferred && mNotifyClients) {
Andrii Kulianb9faa032019-10-17 23:11:54 -0700154 r.makeActiveIfNeeded(r.mClientVisibilityDeferred ? null : starting);
155 r.mClientVisibilityDeferred = false;
Wale Ogunwale076c3b12019-11-20 12:17:22 -0800156 }
157
158 r.handleAlreadyVisible();
159 if (mNotifyClients) {
160 r.makeActiveIfNeeded(mStarting);
161 }
162 } else {
163 r.makeVisibleIfNeeded(mStarting, mNotifyClients);
164 }
165 // Aggregate current change flags.
166 mConfigChanges |= r.configChangeFlags;
167 } else {
168 if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make invisible? " + r
169 + " finishing=" + r.finishing + " state=" + r.getState()
170 + " stackShouldBeVisible=" + mContainerShouldBeVisible
171 + " behindFullscreenActivity=" + mBehindFullscreenActivity
172 + " mLaunchTaskBehind=" + r.mLaunchTaskBehind);
173 r.makeInvisible();
174 }
175
176 final int windowingMode = mContiner.getWindowingMode();
177 if (windowingMode == WINDOWING_MODE_FREEFORM) {
178 // The visibility of tasks and the activities they contain in freeform stack are
179 // determined individually unlike other stacks where the visibility or fullscreen
180 // status of an activity in a previous task affects other.
181 mBehindFullscreenActivity = !mContainerShouldBeVisible;
Jeff Chang24b0bf62019-12-19 19:15:07 +0800182 } else if (!mBehindFullscreenActivity && mContiner.isActivityTypeHome()
183 && r.isRootOfTask()) {
Wale Ogunwale076c3b12019-11-20 12:17:22 -0800184 if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Home task: at " + mContiner
185 + " stackShouldBeVisible=" + mContainerShouldBeVisible
186 + " behindFullscreenActivity=" + mBehindFullscreenActivity);
187 // No other task in the home stack should be visible behind the home activity.
188 // Home activities is usually a translucent activity with the wallpaper behind
189 // them. However, when they don't have the wallpaper behind them, we want to
190 // show activities in the next application stack behind them vs. another
191 // task in the home stack like recents.
192 mBehindFullscreenActivity = true;
193 }
194 }
195
196 private void makeVisibleAndRestartIfNeeded(ActivityRecord starting, int configChanges,
197 boolean isTop, boolean andResume, ActivityRecord r) {
198 // We need to make sure the app is running if it's the top, or it is just made visible from
199 // invisible. If the app is already visible, it must have died while it was visible. In this
200 // case, we'll show the dead window but will not restart the app. Otherwise we could end up
201 // thrashing.
202 if (!isTop && r.mVisibleRequested) {
203 return;
204 }
205
206 // This activity needs to be visible, but isn't even running...
207 // get it started and resume if no other stack in this stack is resumed.
208 if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Start and freeze screen for " + r);
209 if (r != starting) {
210 r.startFreezingScreenLocked(configChanges);
211 }
212 if (!r.mVisibleRequested || r.mLaunchTaskBehind) {
213 if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Starting and making visible: " + r);
214 r.setVisibility(true);
215 }
216 if (r != starting) {
217 mContiner.mStackSupervisor.startSpecificActivity(r, andResume, true /* checkConfig */);
218 }
219 }
220}