Merge "Window Manager Flag Migration (7/n)"
diff --git a/Android.bp b/Android.bp
index 890547b..e3aed6b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -810,8 +810,8 @@
filegroup {
name: "incremental_aidl",
srcs: [
+ "core/java/android/os/incremental/IIncrementalManagerNative.aidl",
"core/java/android/os/incremental/IIncrementalManager.aidl",
- "core/java/android/os/incremental/IIncrementalServiceProxy.aidl",
"core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl",
"core/java/android/os/incremental/IncrementalFileSystemControlParcel.aidl",
"core/java/android/os/incremental/NamedParcelFileDescriptor.aidl",
@@ -1178,7 +1178,7 @@
arg_files: [
"core/res/AndroidManifest.xml",
],
- args: metalava_framework_docs_args + " --show-annotation android.annotation.SystemApi ",
+ args: metalava_framework_docs_args + " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS,process=android.annotation.SystemApi.Process.ALL\\) ",
write_sdk_values: true,
}
@@ -1489,7 +1489,7 @@
merge_annotations_dirs: [
"metalava-manual",
],
- args: " --show-annotation android.annotation.SystemApi",
+ args: " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS,process=android.annotation.SystemApi.Process.ALL\\)",
}
java_library_static {
@@ -1511,7 +1511,7 @@
removed_dex_api_filename: "removed-dex.txt",
args: metalava_framework_docs_args +
" --show-unannotated " +
- " --show-annotation android.annotation.SystemApi " +
+ " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS,process=android.annotation.SystemApi.Process.ALL\\) " +
" --show-annotation android.annotation.TestApi ",
}
@@ -1530,7 +1530,7 @@
" --hide ReferencesHidden " +
" --hide UnhiddenSystemApi " +
" --show-unannotated " +
- " --show-annotation android.annotation.SystemApi " +
+ " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS,process=android.annotation.SystemApi.Process.ALL\\) " +
" --show-annotation android.annotation.TestApi ",
}
@@ -1574,7 +1574,7 @@
arg_files: [
"core/res/AndroidManifest.xml",
],
- args: metalava_framework_docs_args + " --show-annotation android.annotation.SystemApi",
+ args: metalava_framework_docs_args + " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS,process=android.annotation.SystemApi.Process.ALL\\)",
check_api: {
current: {
api_file: "api/system-current.txt",
diff --git a/apct-tests/perftests/core/src/android/wm/InternalWindowOperationPerfTest.java b/apct-tests/perftests/core/src/android/wm/InternalWindowOperationPerfTest.java
index c096cd2..4ed3b4e 100644
--- a/apct-tests/perftests/core/src/android/wm/InternalWindowOperationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/wm/InternalWindowOperationPerfTest.java
@@ -95,7 +95,7 @@
mTraceMarkParser.forAllSlices((key, slices) -> {
for (TraceMarkSlice slice : slices) {
- state.addExtraResult(key, (long) (slice.getDurarionInSeconds() * NANOS_PER_S));
+ state.addExtraResult(key, (long) (slice.getDurationInSeconds() * NANOS_PER_S));
}
});
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java b/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java
index b075239..fe2b1f6 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java
@@ -23,11 +23,15 @@
import android.util.ArrayMap;
import android.util.Log;
+import com.android.internal.util.ArrayUtils;
+
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
import java.util.concurrent.TimeUnit;
/**
@@ -140,6 +144,8 @@
/** @see #addExtraResult(String, long) */
private ArrayMap<String, ArrayList<Long>> mExtraResults;
+ private final List<Long> mTmpDurations = Arrays.asList(0L);
+
// Statistics. These values will be filled when the benchmark has finished.
// The computation needs double precision, but long int is fine for final reporting.
private Stats mStats;
@@ -188,14 +194,25 @@
if (duration < 0) {
throw new RuntimeException("duration is negative: " + duration);
}
+ mTmpDurations.set(0, duration);
+ return keepRunning(mTmpDurations);
+ }
+
+ /**
+ * Similar to the {@link #keepRunning(long)} but accepts a list of durations
+ */
+ public boolean keepRunning(List<Long> durations) {
switch (mState) {
case NOT_STARTED:
mState = WARMUP;
mWarmupStartTime = System.nanoTime();
return true;
case WARMUP: {
+ if (ArrayUtils.isEmpty(durations)) {
+ return true;
+ }
final long timeSinceStartingWarmup = System.nanoTime() - mWarmupStartTime;
- ++mWarmupIterations;
+ mWarmupIterations += durations.size();
if (mWarmupIterations >= WARMUP_MIN_ITERATIONS
&& timeSinceStartingWarmup >= mWarmupDurationNs) {
beginBenchmark(timeSinceStartingWarmup, mWarmupIterations);
@@ -203,7 +220,10 @@
return true;
}
case RUNNING: {
- mResults.add(duration);
+ if (ArrayUtils.isEmpty(durations)) {
+ return true;
+ }
+ mResults.addAll(durations);
final boolean keepRunning = mResults.size() < mMaxIterations;
if (!keepRunning) {
mStats = new Stats(mResults);
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/TraceMarkParser.java b/apct-tests/perftests/utils/src/android/perftests/utils/TraceMarkParser.java
index 1afed3a..b15b6f6 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/TraceMarkParser.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/TraceMarkParser.java
@@ -40,6 +40,8 @@
private final Predicate<TraceMarkLine> mTraceLineFilter;
+ private static final long MICROS_PER_SECOND = 1000L * 1000L;
+
public TraceMarkParser(Predicate<TraceMarkLine> traceLineFilter) {
mTraceLineFilter = traceLineFilter;
}
@@ -116,13 +118,19 @@
}
}
+ public void reset() {
+ mSlicesMap.clear();
+ mDepthMap.clear();
+ mPendingStarts.clear();
+ }
+
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
forAllSlices((key, slices) -> {
double totalMs = 0;
for (TraceMarkSlice s : slices) {
- totalMs += s.getDurarionInSeconds() * 1000;
+ totalMs += s.getDurationInSeconds() * 1000;
}
sb.append(key).append(" count=").append(slices.size()).append(" avg=")
.append(totalMs / slices.size()).append("ms\n");
@@ -134,6 +142,10 @@
return sb.toString();
}
+ static double microsecondToSeconds(long ms) {
+ return (ms * 1.0d) / MICROS_PER_SECOND;
+ }
+
public static class TraceMarkSlice {
public final TraceMarkLine begin;
public final TraceMarkLine end;
@@ -143,7 +155,11 @@
this.end = end;
}
- public double getDurarionInSeconds() {
+ public double getDurationInSeconds() {
+ return microsecondToSeconds(end.timestamp - begin.timestamp);
+ }
+
+ public long getDurationInMicroseconds() {
return end.timestamp - begin.timestamp;
}
}
@@ -164,7 +180,7 @@
static final char SYNC_END = 'E';
public final String taskPid;
- public final double timestamp;
+ public final long timestamp; // in microseconds
public final String name;
public final boolean isAsync;
public final boolean isBegin;
@@ -179,7 +195,7 @@
if (timeBegin < 0) {
throw new IllegalArgumentException("Timestamp start not found");
}
- timestamp = Double.parseDouble(rawLine.substring(timeBegin, timeEnd));
+ timestamp = parseMicroseconds(rawLine.substring(timeBegin, timeEnd));
isAsync = type == ASYNC_START || type == ASYNC_FINISH;
isBegin = type == ASYNC_START || type == SYNC_BEGIN;
@@ -223,9 +239,29 @@
return null;
}
+ /**
+ * Parse the timestamp from atrace output, the format will be like:
+ * 84962.920719 where the decimal part will be always exactly 6 digits.
+ * ^^^^^ ^^^^^^
+ * | |
+ * sec microsec
+ */
+ static long parseMicroseconds(String line) {
+ int end = line.length();
+ long t = 0;
+ for (int i = 0; i < end; i++) {
+ char c = line.charAt(i);
+ if (c >= '0' && c <= '9') {
+ t = t * 10 + (c - '0');
+ }
+ }
+ return t;
+ }
+
@Override
public String toString() {
- return "TraceMarkLine{pid=" + taskPid + " time=" + timestamp + " name=" + name
+ return "TraceMarkLine{pid=" + taskPid + " time="
+ + microsecondToSeconds(timestamp) + " name=" + name
+ " async=" + isAsync + " begin=" + isBegin + "}";
}
}
diff --git a/apex/Android.bp b/apex/Android.bp
new file mode 100644
index 0000000..9ea3953
--- /dev/null
+++ b/apex/Android.bp
@@ -0,0 +1,39 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+mainline_stubs_args =
+ "--error UnhiddenSystemApi " +
+ "--hide BroadcastBehavior " +
+ "--hide DeprecationMismatch " +
+ "--hide HiddenSuperclass " +
+ "--hide HiddenTypedefConstant " +
+ "--hide HiddenTypeParameter " +
+ "--hide MissingPermission " +
+ "--hide RequiresPermission " +
+ "--hide SdkConstant " +
+ "--hide Todo " +
+ "--hide Typo " +
+ "--hide UnavailableSymbol "
+
+stubs_defaults {
+ name: "framework-module-stubs-defaults-publicapi",
+ args: mainline_stubs_args,
+ installable: false,
+}
+
+stubs_defaults {
+ name: "framework-module-stubs-defaults-systemapi",
+ args: mainline_stubs_args + " --show-annotation android.annotation.SystemApi ",
+ installable: false,
+}
diff --git a/api/system-current.txt b/api/system-current.txt
index 507c4df..b449b2e 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -9697,6 +9697,7 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyOtaEmergencyNumberDbInstalled();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio();
method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
+ method public void requestModemActivityInfo(@NonNull android.os.ResultReceiver);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestNumberVerification(@NonNull android.telephony.PhoneNumberRange, long, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.NumberVerificationCallback);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetCarrierKeysForImsiEncryption();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean resetRadioConfig();
diff --git a/cmds/media/Android.bp b/cmds/media/Android.bp
deleted file mode 100644
index 7879c53..0000000
--- a/cmds/media/Android.bp
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright 2013 The Android Open Source Project
-//
-
-java_binary {
- name: "media",
- wrapper: "media",
- srcs: ["**/*.java"],
-}
diff --git a/cmds/media/MODULE_LICENSE_APACHE2 b/cmds/media/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/cmds/media/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/cmds/media/NOTICE b/cmds/media/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/cmds/media/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
- Copyright (c) 2005-2008, The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/cmds/media/media b/cmds/media/media
deleted file mode 100755
index 00c3915..0000000
--- a/cmds/media/media
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/system/bin/sh
-export CLASSPATH=/system/framework/media.jar
-exec app_process /system/bin com.android.commands.media.Media "$@"
diff --git a/core/java/android/annotation/SystemApi.java b/core/java/android/annotation/SystemApi.java
index e96ff01..f589cc5 100644
--- a/core/java/android/annotation/SystemApi.java
+++ b/core/java/android/annotation/SystemApi.java
@@ -41,4 +41,29 @@
@Target({TYPE, FIELD, METHOD, CONSTRUCTOR, ANNOTATION_TYPE, PACKAGE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SystemApi {
+ enum Client {
+ /**
+ * Specifies that the intended clients of a SystemApi are privileged apps.
+ * This is the default value for {@link #client}.
+ */
+ PRIVILEGED_APPS,
+ }
+
+ enum Process {
+ /**
+ * Specifies that the SystemAPI is available in every Java processes.
+ * This is the default value for {@link #process}.
+ */
+ ALL,
+ }
+
+ /**
+ * The intended client of this SystemAPI.
+ */
+ Client client() default android.annotation.SystemApi.Client.PRIVILEGED_APPS;
+
+ /**
+ * The process(es) that this SystemAPI is available
+ */
+ Process process() default android.annotation.SystemApi.Process.ALL;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 9ed6c6a..5cdc505 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3417,7 +3417,7 @@
private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
final int displayId;
try {
- displayId = ActivityTaskManager.getService().getActivityDisplayId(r.token);
+ displayId = ActivityTaskManager.getService().getDisplayId(r.token);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 37136a1..e2b1b86 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -164,7 +164,7 @@
boolean convertToTranslucent(in IBinder token, in Bundle options);
void notifyActivityDrawn(in IBinder token);
void reportActivityFullyDrawn(in IBinder token, boolean restoredFromBundle);
- int getActivityDisplayId(in IBinder activityToken);
+ int getDisplayId(in IBinder activityToken);
boolean isImmersive(in IBinder token);
void setImmersive(in IBinder token, boolean immersive);
boolean isTopActivityImmersive();
@@ -405,6 +405,14 @@
void setDisablePreviewScreenshots(IBinder token, boolean disable);
/**
+ * It should only be called from home activity to remove its outdated snapshot. The home
+ * snapshot is used to speed up entering home from screen off. If the content of home activity
+ * is significantly different from before taking the snapshot, then the home activity can use
+ * this method to avoid inconsistent transition.
+ */
+ void invalidateHomeTaskSnapshot(IBinder homeToken);
+
+ /**
* Return the user id of last resumed activity.
*/
int getLastResumedActivityUserId();
diff --git a/core/java/android/app/TaskEmbedder.java b/core/java/android/app/TaskEmbedder.java
index 000bfc1..e5707bb 100644
--- a/core/java/android/app/TaskEmbedder.java
+++ b/core/java/android/app/TaskEmbedder.java
@@ -184,7 +184,7 @@
return false;
}
- // Create a container surface to which the ActivityDisplay will be reparented
+ // Create a container surface to which the DisplayContent will be reparented
final String name = "TaskEmbedder - " + Integer.toHexString(System.identityHashCode(this));
mSurfaceControl = new SurfaceControl.Builder()
.setContainerLayer()
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 63eb7ce..ec981b2 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2324,6 +2324,11 @@
/**
* Activity action: Starts the administrator to show policy compliance for the provisioning.
+ * This action is used any time that the administrator has an opportunity to show policy
+ * compliance before the end of setup wizard. This could happen as part of the admin-integrated
+ * provisioning flow (in which case this gets sent after {@link #ACTION_GET_PROVISIONING_MODE}),
+ * or it could happen during provisioning finalization if the administrator supports
+ * finalization during setup wizard.
*/
public static final String ACTION_ADMIN_POLICY_COMPLIANCE =
"android.app.action.ADMIN_POLICY_COMPLIANCE";
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 291d1d9..8404705 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1642,7 +1642,7 @@
// Workaround for legacy API for getting a BluetoothAdapter not
// passing a context
if (mContext != null) {
- return null;
+ return mContext.getFeatureId();
}
return null;
}
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index cff4c2d..7ff6466 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -62,7 +62,7 @@
* @hide
*/
public BluetoothManager(Context context) {
- if (null == null) {
+ if (context.getFeatureId() == null) {
context = context.getApplicationContext();
if (context == null) {
throw new IllegalArgumentException(
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index fe774f8..85027d9 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4991,7 +4991,7 @@
* {@link android.os.incremental.IncrementalManager}.
* @hide
*/
- public static final String INCREMENTAL_SERVICE = "incremental";
+ public static final String INCREMENTAL_SERVICE = "incremental_service";
/**
* Determine whether the given permission is allowed for a particular
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 6e890ba..94af541 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -946,7 +946,8 @@
INSTALL_REASON_POLICY,
INSTALL_REASON_DEVICE_RESTORE,
INSTALL_REASON_DEVICE_SETUP,
- INSTALL_REASON_USER
+ INSTALL_REASON_USER,
+ INSTALL_REASON_ROLLBACK
})
@Retention(RetentionPolicy.SOURCE)
public @interface InstallReason {}
@@ -977,6 +978,13 @@
public static final int INSTALL_REASON_USER = 4;
/**
+ * Code indicating that the package installation was a rollback initiated by RollbackManager.
+ *
+ * @hide
+ */
+ public static final int INSTALL_REASON_ROLLBACK = 5;
+
+ /**
* @hide
*/
public static final int INSTALL_UNKNOWN = 0;
diff --git a/core/java/android/content/rollback/IRollbackManager.aidl b/core/java/android/content/rollback/IRollbackManager.aidl
index 8c2a65f..cda0e98 100644
--- a/core/java/android/content/rollback/IRollbackManager.aidl
+++ b/core/java/android/content/rollback/IRollbackManager.aidl
@@ -44,9 +44,10 @@
// Used by the staging manager to notify the RollbackManager that a session is
// being staged. In the case of multi-package sessions, the specified sessionId
// is that of the parent session.
+ // Returns the rollback id if rollback was enabled successfully, or -1 if not.
//
// NOTE: This call is synchronous.
- boolean notifyStagedSession(int sessionId);
+ int notifyStagedSession(int sessionId);
// Used by the staging manager to notify the RollbackManager of the apk
// session for a staged session.
diff --git a/core/java/android/os/incremental/IIncrementalManager.aidl b/core/java/android/os/incremental/IIncrementalManager.aidl
index d6446d4..f84d7ef 100644
--- a/core/java/android/os/incremental/IIncrementalManager.aidl
+++ b/core/java/android/os/incremental/IIncrementalManager.aidl
@@ -16,89 +16,22 @@
package android.os.incremental;
+import android.os.incremental.IncrementalFileSystemControlParcel;
import android.os.incremental.IncrementalDataLoaderParamsParcel;
+import android.content.pm.IDataLoaderStatusListener;
-/** @hide */
+/**
+ * Binder service to receive calls from native Incremental Service and handle Java tasks such as
+ * looking up data loader service package names, binding and talking to the data loader service.
+ * @hide
+ */
interface IIncrementalManager {
- /**
- * A set of flags for the |createMode| parameters when creating a new Incremental storage.
- */
- const int CREATE_MODE_TEMPORARY_BIND = 1;
- const int CREATE_MODE_PERMANENT_BIND = 2;
- const int CREATE_MODE_CREATE = 4;
- const int CREATE_MODE_OPEN_EXISTING = 8;
-
- /**
- * Opens or creates a storage given a target path and data loader params. Returns the storage ID.
- */
- int openStorage(in @utf8InCpp String path);
- int createStorage(in @utf8InCpp String path, in IncrementalDataLoaderParamsParcel params, int createMode);
- int createLinkedStorage(in @utf8InCpp String path, int otherStorageId, int createMode);
-
- /**
- * Bind-mounts a path under a storage to a full path. Can be permanent or temporary.
- */
- const int BIND_TEMPORARY = 0;
- const int BIND_PERMANENT = 1;
- int makeBindMount(int storageId, in @utf8InCpp String pathUnderStorage, in @utf8InCpp String targetFullPath, int bindType);
-
- /**
- * Deletes an existing bind mount on a path under a storage. Returns 0 on success, and -errno on failure.
- */
- int deleteBindMount(int storageId, in @utf8InCpp String targetFullPath);
-
- /**
- * Creates a directory under a storage. The target directory is specified by its relative path under the storage.
- */
- int makeDirectory(int storageId, in @utf8InCpp String pathUnderStorage);
-
- /**
- * Recursively creates a directory under a storage. The target directory is specified by its relative path under the storage.
- * All the parent directories of the target directory will be created if they do not exist already.
- */
- int makeDirectories(int storageId, in @utf8InCpp String pathUnderStorage);
-
- /**
- * Creates a file under a storage, specifying its name, size and metadata.
- */
- int makeFile(int storageId, in @utf8InCpp String pathUnderStorage, long size, in byte[] metadata);
-
- /**
- * Creates a file under a storage. Content of the file is from a range inside another file.
- * Both files are specified by relative paths under storage.
- */
- int makeFileFromRange(int storageId, in @utf8InCpp String targetPathUnderStorage, in @utf8InCpp String sourcePathUnderStorage, long start, long end);
-
- /**
- * Creates a hard link between two files in two storage instances.
- * Source and dest specified by parent storage IDs and their relative paths under the storage.
- * The source and dest storage instances should be in the same fs mount.
- * Note: destStorageId can be the same as sourceStorageId.
- */
- int makeLink(int sourceStorageId, in @utf8InCpp String sourcePathUnderStorage, int destStorageId, in @utf8InCpp String destPathUnderStorage);
-
- /**
- * Deletes a hard link in a storage, specified by the relative path of the link target under storage.
- */
- int unlink(int storageId, in @utf8InCpp String pathUnderStorage);
-
- /**
- * Checks if a file's certain range is loaded. File is specified by relative file path under storage.
- */
- boolean isFileRangeLoaded(int storageId, in @utf8InCpp String pathUnderStorage, long start, long end);
-
- /**
- * Reads the metadata of a file. File is specified by relative path under storage.
- */
- byte[] getFileMetadata(int storageId, in @utf8InCpp String pathUnderStorage);
-
- /**
- * Starts loading data for a storage.
- */
- boolean startLoading(int storageId);
-
- /**
- * Deletes a storage given its ID. Deletes its bind mounts and unmount it. Stop its data loader.
- */
- void deleteStorage(int storageId);
+ boolean prepareDataLoader(int mountId,
+ in IncrementalFileSystemControlParcel control,
+ in IncrementalDataLoaderParamsParcel params,
+ in IDataLoaderStatusListener listener);
+ boolean startDataLoader(int mountId);
+ void showHealthBlockedUI(int mountId);
+ void destroyDataLoader(int mountId);
+ void newFileForDataLoader(int mountId, long inode, in byte[] metadata);
}
diff --git a/core/java/android/os/incremental/IIncrementalManagerNative.aidl b/core/java/android/os/incremental/IIncrementalManagerNative.aidl
new file mode 100644
index 0000000..d9c7c6b
--- /dev/null
+++ b/core/java/android/os/incremental/IIncrementalManagerNative.aidl
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.incremental;
+
+import android.os.incremental.IncrementalDataLoaderParamsParcel;
+
+/** @hide */
+interface IIncrementalManagerNative {
+ /**
+ * A set of flags for the |createMode| parameters when creating a new Incremental storage.
+ */
+ const int CREATE_MODE_TEMPORARY_BIND = 1;
+ const int CREATE_MODE_PERMANENT_BIND = 2;
+ const int CREATE_MODE_CREATE = 4;
+ const int CREATE_MODE_OPEN_EXISTING = 8;
+
+ /**
+ * Opens or creates a storage given a target path and data loader params. Returns the storage ID.
+ */
+ int openStorage(in @utf8InCpp String path);
+ int createStorage(in @utf8InCpp String path, in IncrementalDataLoaderParamsParcel params, int createMode);
+ int createLinkedStorage(in @utf8InCpp String path, int otherStorageId, int createMode);
+
+ /**
+ * Bind-mounts a path under a storage to a full path. Can be permanent or temporary.
+ */
+ const int BIND_TEMPORARY = 0;
+ const int BIND_PERMANENT = 1;
+ int makeBindMount(int storageId, in @utf8InCpp String pathUnderStorage, in @utf8InCpp String targetFullPath, int bindType);
+
+ /**
+ * Deletes an existing bind mount on a path under a storage. Returns 0 on success, and -errno on failure.
+ */
+ int deleteBindMount(int storageId, in @utf8InCpp String targetFullPath);
+
+ /**
+ * Creates a directory under a storage. The target directory is specified by its relative path under the storage.
+ */
+ int makeDirectory(int storageId, in @utf8InCpp String pathUnderStorage);
+
+ /**
+ * Recursively creates a directory under a storage. The target directory is specified by its relative path under the storage.
+ * All the parent directories of the target directory will be created if they do not exist already.
+ */
+ int makeDirectories(int storageId, in @utf8InCpp String pathUnderStorage);
+
+ /**
+ * Creates a file under a storage, specifying its name, size and metadata.
+ */
+ int makeFile(int storageId, in @utf8InCpp String pathUnderStorage, long size, in byte[] metadata);
+
+ /**
+ * Creates a file under a storage. Content of the file is from a range inside another file.
+ * Both files are specified by relative paths under storage.
+ */
+ int makeFileFromRange(int storageId, in @utf8InCpp String targetPathUnderStorage, in @utf8InCpp String sourcePathUnderStorage, long start, long end);
+
+ /**
+ * Creates a hard link between two files in two storage instances.
+ * Source and dest specified by parent storage IDs and their relative paths under the storage.
+ * The source and dest storage instances should be in the same fs mount.
+ * Note: destStorageId can be the same as sourceStorageId.
+ */
+ int makeLink(int sourceStorageId, in @utf8InCpp String sourcePathUnderStorage, int destStorageId, in @utf8InCpp String destPathUnderStorage);
+
+ /**
+ * Deletes a hard link in a storage, specified by the relative path of the link target under storage.
+ */
+ int unlink(int storageId, in @utf8InCpp String pathUnderStorage);
+
+ /**
+ * Checks if a file's certain range is loaded. File is specified by relative file path under storage.
+ */
+ boolean isFileRangeLoaded(int storageId, in @utf8InCpp String pathUnderStorage, long start, long end);
+
+ /**
+ * Reads the metadata of a file. File is specified by relative path under storage.
+ */
+ byte[] getFileMetadata(int storageId, in @utf8InCpp String pathUnderStorage);
+
+ /**
+ * Starts loading data for a storage.
+ */
+ boolean startLoading(int storageId);
+
+ /**
+ * Deletes a storage given its ID. Deletes its bind mounts and unmount it. Stop its data loader.
+ */
+ void deleteStorage(int storageId);
+}
diff --git a/core/java/android/os/incremental/IIncrementalServiceProxy.aidl b/core/java/android/os/incremental/IIncrementalServiceProxy.aidl
deleted file mode 100644
index ffff52e..0000000
--- a/core/java/android/os/incremental/IIncrementalServiceProxy.aidl
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os.incremental;
-
-import android.os.incremental.IncrementalFileSystemControlParcel;
-import android.os.incremental.IncrementalDataLoaderParamsParcel;
-import android.content.pm.IDataLoaderStatusListener;
-
-/**
- * Binder service to receive calls from native Incremental Service and handle Java tasks such as
- * looking up data loader service package names, binding and talking to the data loader service.
- * @hide
- */
-interface IIncrementalServiceProxy {
- boolean prepareDataLoader(int mountId,
- in IncrementalFileSystemControlParcel control,
- in IncrementalDataLoaderParamsParcel params,
- in IDataLoaderStatusListener listener);
- boolean startDataLoader(int mountId);
- void showHealthBlockedUI(int mountId);
- void destroyDataLoader(int mountId);
- void newFileForDataLoader(int mountId, long inode, in byte[] metadata);
-}
diff --git a/core/java/android/os/incremental/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java
index 5aabf86..c30f558 100644
--- a/core/java/android/os/incremental/IncrementalManager.java
+++ b/core/java/android/os/incremental/IncrementalManager.java
@@ -36,31 +36,28 @@
import java.nio.file.Paths;
/**
- * Provides operations to open or create an IncrementalStorage, using IIncrementalManager service.
- * Example Usage:
+ * Provides operations to open or create an IncrementalStorage, using IIncrementalManagerNative
+ * service. Example Usage:
*
* <blockquote><pre>
- * IncrementalManager manager = (IncrementalManager) getSystemService(Context.INCREMENTAL_MANAGER);
+ * IncrementalManager manager = (IncrementalManager) getSystemService(Context.INCREMENTAL_SERVICE);
* IncrementalStorage storage = manager.openStorage("/path/to/incremental/dir");
* </pre></blockquote>
*
* @hide
*/
@SystemService(Context.INCREMENTAL_SERVICE)
-public class IncrementalManager {
+public final class IncrementalManager {
private static final String TAG = "IncrementalManager";
- private final IIncrementalManager mService;
- @GuardedBy("mStorages")
- private final SparseArray<IncrementalStorage> mStorages = new SparseArray<>();
public static final int CREATE_MODE_TEMPORARY_BIND =
- IIncrementalManager.CREATE_MODE_TEMPORARY_BIND;
+ IIncrementalManagerNative.CREATE_MODE_TEMPORARY_BIND;
public static final int CREATE_MODE_PERMANENT_BIND =
- IIncrementalManager.CREATE_MODE_PERMANENT_BIND;
+ IIncrementalManagerNative.CREATE_MODE_PERMANENT_BIND;
public static final int CREATE_MODE_CREATE =
- IIncrementalManager.CREATE_MODE_CREATE;
+ IIncrementalManagerNative.CREATE_MODE_CREATE;
public static final int CREATE_MODE_OPEN_EXISTING =
- IIncrementalManager.CREATE_MODE_OPEN_EXISTING;
+ IIncrementalManagerNative.CREATE_MODE_OPEN_EXISTING;
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"CREATE_MODE_"}, value = {
@@ -72,8 +69,12 @@
public @interface CreateMode {
}
- public IncrementalManager(@NonNull IIncrementalManager is) {
- mService = is;
+ private final @Nullable IIncrementalManagerNative mNativeService;
+ @GuardedBy("mStorages")
+ private final SparseArray<IncrementalStorage> mStorages = new SparseArray<>();
+
+ public IncrementalManager(IIncrementalManagerNative nativeService) {
+ mNativeService = nativeService;
}
/**
@@ -82,6 +83,7 @@
* @param storageId The storage ID to identify the storage object.
* @return IncrementalStorage object corresponding to storage ID.
*/
+ // TODO(b/136132412): remove this
@Nullable
public IncrementalStorage getStorage(int storageId) {
synchronized (mStorages) {
@@ -95,8 +97,8 @@
*
* @param path Absolute path to mount Incremental File System on.
* @param params IncrementalDataLoaderParams object to configure data loading.
- * @param createMode Mode for opening an old Incremental File System mount or
- * creating a new mount.
+ * @param createMode Mode for opening an old Incremental File System mount or creating
+ * a new mount.
* @param autoStartDataLoader Set true to immediately start data loader after creating storage.
* @return IncrementalStorage object corresponding to the mounted directory.
*/
@@ -105,11 +107,11 @@
@NonNull IncrementalDataLoaderParams params, @CreateMode int createMode,
boolean autoStartDataLoader) {
try {
- final int id = mService.createStorage(path, params.getData(), createMode);
+ final int id = mNativeService.createStorage(path, params.getData(), createMode);
if (id < 0) {
return null;
}
- final IncrementalStorage storage = new IncrementalStorage(mService, id);
+ final IncrementalStorage storage = new IncrementalStorage(mNativeService, id);
synchronized (mStorages) {
mStorages.put(id, storage);
}
@@ -123,8 +125,8 @@
}
/**
- * Opens an existing Incremental File System mounted directory and returns an
- * IncrementalStorage object.
+ * Opens an existing Incremental File System mounted directory and returns an IncrementalStorage
+ * object.
*
* @param path Absolute target path that Incremental File System has been mounted on.
* @return IncrementalStorage object corresponding to the mounted directory.
@@ -132,11 +134,11 @@
@Nullable
public IncrementalStorage openStorage(@NonNull String path) {
try {
- final int id = mService.openStorage(path);
+ final int id = mNativeService.openStorage(path);
if (id < 0) {
return null;
}
- final IncrementalStorage storage = new IncrementalStorage(mService, id);
+ final IncrementalStorage storage = new IncrementalStorage(mNativeService, id);
synchronized (mStorages) {
mStorages.put(id, storage);
}
@@ -155,11 +157,12 @@
public IncrementalStorage createStorage(@NonNull String path,
@NonNull IncrementalStorage linkedStorage, @CreateMode int createMode) {
try {
- final int id = mService.createLinkedStorage(path, linkedStorage.getId(), createMode);
+ final int id = mNativeService.createLinkedStorage(
+ path, linkedStorage.getId(), createMode);
if (id < 0) {
return null;
}
- final IncrementalStorage storage = new IncrementalStorage(mService, id);
+ final IncrementalStorage storage = new IncrementalStorage(mNativeService, id);
synchronized (mStorages) {
mStorages.put(id, storage);
}
@@ -175,6 +178,7 @@
* @param file Target file to search storage for.
* @return Absolute path which is a bind-mount point of Incremental File System.
*/
+ @Nullable
private Path getStoragePathForFile(File file) {
File currentPath = new File(file.getParent());
while (currentPath.getParent() != null) {
@@ -198,18 +202,19 @@
* </li>
* </ol>
*
- * @param sourcePath Absolute path to the source. Should be the same type as the destPath
- * (file or dir). Expected to already exist and is an Incremental path.
- * @param destPath Absolute path to the destination.
- * @throws IllegalArgumentException when 1) source does not exist,
- * or 2) source and dest type mismatch (one is file and the other is dir),
- * or 3) source path is not on Incremental File System,
- * @throws IOException when 1) cannot find the root path of the Incremental storage of source,
- * or 2) cannot retrieve the Incremental storage instance of the source,
- * or 3) renaming a file, but dest is not on the same Incremental Storage,
- * or 4) renaming a dir, dest dir does not exist but fails to be created.
- *
- * TODO(b/136132412): add unit tests
+ * @param sourcePath Absolute path to the source. Should be the same type as the destPath (file
+ * or dir). Expected to already exist and is an Incremental path.
+ * @param destPath Absolute path to the destination.
+ * @throws IllegalArgumentException when 1) source does not exist, or 2) source and dest type
+ * mismatch (one is file and the other is dir), or 3) source
+ * path is not on Incremental File System,
+ * @throws IOException when 1) cannot find the root path of the Incremental storage
+ * of source, or 2) cannot retrieve the Incremental storage
+ * instance of the source, or 3) renaming a file, but dest is
+ * not on the same Incremental Storage, or 4) renaming a dir,
+ * dest dir does not exist but fails to be created.
+ * <p>
+ * TODO(b/136132412): add unit tests
*/
public void rename(@NonNull String sourcePath, @NonNull String destPath) throws IOException {
final File source = new File(sourcePath);
@@ -243,6 +248,7 @@
if (storage == null) {
throw new IOException("Failed to retrieve storage from Incremental Service.");
}
+
if (source.isFile()) {
renameFile(storage, storagePath, source, dest);
} else {
@@ -304,11 +310,11 @@
*/
public void closeStorage(@NonNull String path) {
try {
- final int id = mService.openStorage(path);
+ final int id = mNativeService.openStorage(path);
if (id < 0) {
return;
}
- mService.deleteStorage(id);
+ mNativeService.deleteStorage(id);
synchronized (mStorages) {
mStorages.remove(id);
}
@@ -321,7 +327,7 @@
* Checks if path is mounted on Incremental File System.
*/
public static boolean isIncrementalPath(@NonNull String path) {
- // TODO(b/136132412): implement native method
+ // TODO(b/136132412): add jni implementation
return false;
}
}
diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java
index 2bf89ed..2750868 100644
--- a/core/java/android/os/incremental/IncrementalStorage.java
+++ b/core/java/android/os/incremental/IncrementalStorage.java
@@ -24,11 +24,11 @@
import java.io.IOException;
/**
- * Provides operations on an Incremental File System directory, using IncrementalService. Example
- * usage:
+ * Provides operations on an Incremental File System directory, using IncrementalServiceNative.
+ * Example usage:
*
* <blockquote><pre>
- * IncrementalManager manager = (IncrementalManager) getSystemService(Context.INCREMENTAL_MANAGER);
+ * IncrementalManager manager = (IncrementalManager) getSystemService(Context.INCREMENTAL_SERVICE);
* IncrementalStorage storage = manager.openStorage("/path/to/incremental/dir");
* storage.makeDirectory("subdir");
* </pre></blockquote>
@@ -38,10 +38,10 @@
public final class IncrementalStorage {
private static final String TAG = "IncrementalStorage";
private final int mId;
- private final IIncrementalManager mService;
+ private final IIncrementalManagerNative mService;
- public IncrementalStorage(@NonNull IIncrementalManager is, int id) {
+ public IncrementalStorage(@NonNull IIncrementalManagerNative is, int id) {
mService = is;
mId = id;
}
@@ -72,7 +72,7 @@
throws IOException {
try {
int res = mService.makeBindMount(mId, sourcePathUnderStorage, targetPath,
- IIncrementalManager.BIND_TEMPORARY);
+ IIncrementalManagerNative.BIND_TEMPORARY);
if (res < 0) {
throw new IOException("bind() failed with errno " + -res);
}
@@ -103,7 +103,7 @@
throws IOException {
try {
int res = mService.makeBindMount(mId, sourcePathUnderStorage, targetPath,
- IIncrementalManager.BIND_PERMANENT);
+ IIncrementalManagerNative.BIND_PERMANENT);
if (res < 0) {
throw new IOException("bind() permanent failed with errno " + -res);
}
@@ -274,7 +274,8 @@
throw new IOException("moveDir() requires that destination dir already exists.");
}
try {
- int res = mService.makeBindMount(mId, "", destPath, IIncrementalManager.BIND_PERMANENT);
+ int res = mService.makeBindMount(mId, "", destPath,
+ IIncrementalManagerNative.BIND_PERMANENT);
if (res < 0) {
throw new IOException("moveDir() failed at making bind mount, errno " + -res);
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 165c284..bd1eb21 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10312,6 +10312,19 @@
public static final String ERROR_LOGCAT_PREFIX = "logcat_for_";
/**
+ * Maximum number of bytes of a system crash/ANR/etc. report that
+ * ActivityManagerService should send to DropBox, as a prefix of the
+ * dropbox tag of the report type. For example,
+ * "max_error_bytes_for_system_server_anr" controls the maximum
+ * number of bytes captured with system server ANR reports.
+ * <p>
+ * Type: int (max size in bytes)
+ *
+ * @hide
+ */
+ public static final String MAX_ERROR_BYTES_PREFIX = "max_error_bytes_for_";
+
+ /**
* The interval in minutes after which the amount of free storage left
* on the device is logged to the event log
*
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index f6da01b..c287ae3 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -1308,8 +1308,7 @@
* Broadcast action: When SMS-MMS db is being created. If file-based encryption is
* supported, this broadcast indicates creation of the db in credential-encrypted
* storage. A boolean is specified in {@link #EXTRA_IS_INITIAL_CREATE} to indicate if
- * this is the initial create of the db. Requires
- * {@link android.Manifest.permission#READ_SMS} to receive.
+ * this is the initial create of the db.
*
* @see #EXTRA_IS_INITIAL_CREATE
*
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 49a73ee..7562bad 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -222,6 +222,8 @@
private ArrayMap<String, Set<String>> mPackageToUserTypeWhitelist = new ArrayMap<>();
private ArrayMap<String, Set<String>> mPackageToUserTypeBlacklist = new ArrayMap<>();
+ private final ArraySet<String> mRollbackWhitelistedPackages = new ArraySet<>();
+
/**
* Map of system pre-defined, uniquely named actors; keys are namespace,
* value maps actor name to package name.
@@ -382,6 +384,10 @@
return mBugreportWhitelistedPackages;
}
+ public Set<String> getRollbackWhitelistedPackages() {
+ return mRollbackWhitelistedPackages;
+ }
+
/**
* Gets map of packagesNames to userTypes, dictating on which user types each package should be
* initially installed, and then removes this map from SystemConfig.
@@ -1078,6 +1084,16 @@
}
XmlUtils.skipCurrentTag(parser);
} break;
+ case "rollback-whitelisted-app": {
+ String pkgname = parser.getAttributeValue(null, "package");
+ if (pkgname == null) {
+ Slog.w(TAG, "<" + name + "> without package in " + permFile
+ + " at " + parser.getPositionDescription());
+ } else {
+ mRollbackWhitelistedPackages.add(pkgname);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ } break;
default: {
Slog.w(TAG, "Tag " + name + " is unknown in "
+ permFile + " at " + parser.getPositionDescription());
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 31c19ca..a98d7db 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -566,6 +566,7 @@
optional LowPowerMode low_power_mode = 70;
optional SettingProto lte_service_forced = 71 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ repeated SettingProto max_error_bytes = 151;
optional SettingProto mdc_initial_max_retry = 72 [ (android.privacy).dest = DEST_AUTOMATIC ];
message Mhl {
@@ -1058,5 +1059,5 @@
// Please insert fields in alphabetical order and group them into messages
// if possible (to avoid reaching the method limit).
- // Next tag = 151;
+ // Next tag = 152;
}
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 43f65e3..183c04e 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -120,7 +120,7 @@
prebuilt_etc {
name: "privapp_whitelist_com.android.storagemanager",
- product_specific: true,
+ system_ext_specific: true,
sub_dir: "permissions",
src: "com.android.storagemanager.xml",
filename_from_src: true,
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index eff353c..3060476 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -7,12 +7,6 @@
"group": "WM_DEBUG_KEEP_SCREEN_ON",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "-2138637148": {
- "message": "Clearing focused app, displayId=%d",
- "level": "VERBOSE",
- "group": "WM_DEBUG_FOCUS_LIGHT",
- "at": "com\/android\/server\/wm\/ActivityDisplay.java"
- },
"-2127842445": {
"message": "Clearing startingData for token=%s",
"level": "VERBOSE",
@@ -709,6 +703,12 @@
"group": "WM_DEBUG_BOOT",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-603199586": {
+ "message": "Clearing focused app, displayId=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_FOCUS_LIGHT",
+ "at": "com\/android\/server\/wm\/DisplayContent.java"
+ },
"-583031528": {
"message": "%s",
"level": "INFO",
@@ -1315,6 +1315,12 @@
"group": "WM_SHOW_TRANSACTIONS",
"at": "com\/android\/server\/wm\/WindowSurfaceController.java"
},
+ "584499099": {
+ "message": "Set focused app to: %s moveFocusNow=%b displayId=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_FOCUS_LIGHT",
+ "at": "com\/android\/server\/wm\/DisplayContent.java"
+ },
"585096182": {
"message": "SURFACE isColorSpaceAgnostic=%b: %s",
"level": "INFO",
@@ -1513,12 +1519,6 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/WindowStateAnimator.java"
},
- "917739349": {
- "message": "Set focused app to: %s moveFocusNow=%b displayId=%d",
- "level": "VERBOSE",
- "group": "WM_DEBUG_FOCUS_LIGHT",
- "at": "com\/android\/server\/wm\/ActivityDisplay.java"
- },
"954470154": {
"message": "FORCED DISPLAY SCALING DISABLED",
"level": "INFO",
diff --git a/media/Android.bp b/media/Android.bp
index 1912930..e2bdad1 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -82,7 +82,7 @@
"--hide MissingPermission --hide BroadcastBehavior " +
"--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " +
"--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo " +
- "--hide HiddenTypedefConstant --show-annotation android.annotation.SystemApi "
+ "--hide HiddenTypedefConstant --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS,process=android.annotation.SystemApi.Process.ALL\\) "
droidstubs {
name: "updatable-media-stubs",
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 39c55fd..9b4a6d6 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -140,8 +140,6 @@
<item><xliff:g id="qualcomm">Qualcomm®</xliff:g> <xliff:g id="aptx">aptX™</xliff:g> audio</item>
<item><xliff:g id="qualcomm">Qualcomm®</xliff:g> <xliff:g id="aptx_hd">aptX™ HD</xliff:g> audio</item>
<item>LDAC</item>
- <item>Enable Optional Codecs</item>
- <item>Disable Optional Codecs</item>
</string-array>
<!-- Values for Bluetooth Audio Codec selection preference. -->
@@ -152,8 +150,6 @@
<item>2</item>
<item>3</item>
<item>4</item>
- <item>5</item>
- <item>6</item>
</string-array>
<!-- Summaries for Bluetooth Audio Codec selection preference. [CHAR LIMIT=50]-->
@@ -164,8 +160,6 @@
<item><xliff:g id="qualcomm">Qualcomm®</xliff:g> <xliff:g id="aptx">aptX™</xliff:g> audio</item>
<item><xliff:g id="qualcomm">Qualcomm®</xliff:g> <xliff:g id="aptx_hd">aptX™ HD</xliff:g> audio</item>
<item>LDAC</item>
- <item>Enable Optional Codecs</item>
- <item>Disable Optional Codecs</item>
</string-array>
<!-- Titles for Bluetooth Audio Codec Sample Rate selection preference. [CHAR LIMIT=50] -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
index 5cf44e1..a82231a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
@@ -23,6 +23,9 @@
import android.text.TextUtils;
import android.util.Pair;
+import androidx.annotation.NonNull;
+import androidx.preference.Preference;
+
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import java.util.ArrayList;
@@ -132,34 +135,44 @@
return ((Instrumentable) object).getMetricsCategory();
}
- public void logDashboardStartIntent(Context context, Intent intent,
- int sourceMetricsCategory) {
+ /**
+ * Logs an event when the preference is clicked.
+ *
+ * @return true if the preference is loggable, otherwise false
+ */
+ public boolean logClickedPreference(@NonNull Preference preference, int sourceMetricsCategory) {
+ if (preference == null) {
+ return false;
+ }
+ return logSettingsTileClick(preference.getKey(), sourceMetricsCategory)
+ || logStartedIntent(preference.getIntent(), sourceMetricsCategory)
+ || logSettingsTileClick(preference.getFragment(), sourceMetricsCategory);
+ }
+
+ /**
+ * Logs an event when the intent is started.
+ *
+ * @return true if the intent is loggable, otherwise false
+ */
+ public boolean logStartedIntent(Intent intent, int sourceMetricsCategory) {
if (intent == null) {
- return;
+ return false;
}
final ComponentName cn = intent.getComponent();
- if (cn == null) {
- final String action = intent.getAction();
- if (TextUtils.isEmpty(action)) {
- // Not loggable
- return;
- }
- action(sourceMetricsCategory,
- MetricsEvent.ACTION_SETTINGS_TILE_CLICK,
- SettingsEnums.PAGE_UNKNOWN,
- action,
- 0);
- return;
- } else if (TextUtils.equals(cn.getPackageName(), context.getPackageName())) {
- // Going to a Setting internal page, skip click logging in favor of page's own
- // visibility logging.
- return;
+ return logSettingsTileClick(cn != null ? cn.flattenToString() : intent.getAction(),
+ sourceMetricsCategory);
+ }
+
+ private boolean logSettingsTileClick(String logKey, int sourceMetricsCategory) {
+ if (TextUtils.isEmpty(logKey)) {
+ // Not loggable
+ return false;
}
action(sourceMetricsCategory,
MetricsEvent.ACTION_SETTINGS_TILE_CLICK,
SettingsEnums.PAGE_UNKNOWN,
- cn.flattenToString(),
+ logKey,
0);
+ return true;
}
-
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
index 8a0ae91..ed0857c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
@@ -26,6 +26,8 @@
import android.content.Context;
import android.content.Intent;
+import androidx.preference.Preference;
+
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import org.junit.Before;
@@ -60,19 +62,42 @@
}
@Test
- public void logDashboardStartIntent_intentEmpty_shouldNotLog() {
- mProvider.logDashboardStartIntent(mContext, null /* intent */,
+ public void logClickedPreference_preferenceEmpty_shouldNotLog() {
+ final boolean loggable = mProvider.logClickedPreference(null /* preference */,
MetricsEvent.SETTINGS_GESTURES);
+ assertThat(loggable).isFalse();
verifyNoMoreInteractions(mLogWriter);
}
@Test
- public void logDashboardStartIntent_intentHasNoComponent_shouldLog() {
+ public void logClickedPreference_preferenceHasKey_shouldLog() {
+ final String key = "abc";
+ final Preference preference = new Preference(mContext);
+ preference.setKey(key);
+
+ final boolean loggable = mProvider.logClickedPreference(preference,
+ MetricsEvent.SETTINGS_GESTURES);
+
+ assertThat(loggable).isTrue();
+ verify(mLogWriter).action(
+ MetricsEvent.SETTINGS_GESTURES,
+ MetricsEvent.ACTION_SETTINGS_TILE_CLICK,
+ SettingsEnums.PAGE_UNKNOWN,
+ key,
+ 0);
+ }
+
+ @Test
+ public void logClickedPreference_preferenceHasIntent_shouldLog() {
+ final Preference preference = new Preference(mContext);
final Intent intent = new Intent(Intent.ACTION_ASSIST);
+ preference.setIntent(intent);
- mProvider.logDashboardStartIntent(mContext, intent, MetricsEvent.SETTINGS_GESTURES);
+ final boolean loggable = mProvider.logClickedPreference(preference,
+ MetricsEvent.SETTINGS_GESTURES);
+ assertThat(loggable).isTrue();
verify(mLogWriter).action(
MetricsEvent.SETTINGS_GESTURES,
MetricsEvent.ACTION_SETTINGS_TILE_CLICK,
@@ -82,11 +107,54 @@
}
@Test
- public void logDashboardStartIntent_intentIsExternal_shouldLog() {
+ public void logClickedPreference_preferenceHasFragment_shouldLog() {
+ final Preference preference = new Preference(mContext);
+ final String fragment = "com.android.settings.tts.TextToSpeechSettings";
+ preference.setFragment(fragment);
+
+ final boolean loggable = mProvider.logClickedPreference(preference,
+ MetricsEvent.SETTINGS_GESTURES);
+
+ assertThat(loggable).isTrue();
+ verify(mLogWriter).action(
+ MetricsEvent.SETTINGS_GESTURES,
+ MetricsEvent.ACTION_SETTINGS_TILE_CLICK,
+ SettingsEnums.PAGE_UNKNOWN,
+ fragment,
+ 0);
+ }
+
+ @Test
+ public void logStartedIntent_intentEmpty_shouldNotLog() {
+ final boolean loggable = mProvider.logStartedIntent(null /* intent */,
+ MetricsEvent.SETTINGS_GESTURES);
+
+ assertThat(loggable).isFalse();
+ verifyNoMoreInteractions(mLogWriter);
+ }
+
+ @Test
+ public void logStartedIntent_intentHasNoComponent_shouldLog() {
+ final Intent intent = new Intent(Intent.ACTION_ASSIST);
+
+ final boolean loggable = mProvider.logStartedIntent(intent, MetricsEvent.SETTINGS_GESTURES);
+
+ assertThat(loggable).isTrue();
+ verify(mLogWriter).action(
+ MetricsEvent.SETTINGS_GESTURES,
+ MetricsEvent.ACTION_SETTINGS_TILE_CLICK,
+ SettingsEnums.PAGE_UNKNOWN,
+ Intent.ACTION_ASSIST,
+ 0);
+ }
+
+ @Test
+ public void logStartedIntent_intentIsExternal_shouldLog() {
final Intent intent = new Intent().setComponent(new ComponentName("pkg", "cls"));
- mProvider.logDashboardStartIntent(mContext, intent, MetricsEvent.SETTINGS_GESTURES);
+ final boolean loggable = mProvider.logStartedIntent(intent, MetricsEvent.SETTINGS_GESTURES);
+ assertThat(loggable).isTrue();
verify(mLogWriter).action(
MetricsEvent.SETTINGS_GESTURES,
MetricsEvent.ACTION_SETTINGS_TILE_CLICK,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 0a2dd38..80077c8 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -691,6 +691,9 @@
dumpRepeatedSetting(s, p,
Settings.Global.ERROR_LOGCAT_PREFIX,
GlobalSettingsProto.ERROR_LOGCAT_LINES);
+ dumpRepeatedSetting(s, p,
+ Settings.Global.MAX_ERROR_BYTES_PREFIX,
+ GlobalSettingsProto.MAX_ERROR_BYTES);
final long euiccToken = p.start(GlobalSettingsProto.EUICC);
dumpSetting(s, p,
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index c23a494..d5a3254 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -324,6 +324,7 @@
Settings.Global.LOW_POWER_MODE_SUGGESTION_PARAMS,
Settings.Global.LTE_SERVICE_FORCED,
Settings.Global.LID_BEHAVIOR,
+ Settings.Global.MAX_ERROR_BYTES_PREFIX,
Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
Settings.Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY,
Settings.Global.MDC_INITIAL_MAX_RETRY,
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 70f8e15..deaafca 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -28,6 +28,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import android.annotation.NonNull;
+import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.RecentTaskInfo;
import android.app.ActivityManager.RunningTaskInfo;
@@ -161,6 +162,23 @@
}
/**
+ * Removes the outdated snapshot of home task.
+ */
+ public void invalidateHomeTaskSnapshot(final Activity homeActivity) {
+ mBackgroundExecutor.submit(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ ActivityTaskManager.getService().invalidateHomeTaskSnapshot(
+ homeActivity.getActivityToken());
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to invalidate home snapshot", e);
+ }
+ }
+ });
+ }
+
+ /**
* @return the activity label, badging if necessary.
*/
public String getBadgedActivityLabel(ActivityInfo info, int userId) {
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
index 7c78ef8..743fd6a 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -456,7 +456,7 @@
mLog.e("setWifiTethering: failed to get WifiManager!");
return TETHER_ERROR_SERVICE_UNAVAIL;
}
- if ((enable && mgr.startSoftAp(null /* use existing wifi config */))
+ if ((enable && mgr.startTetheredHotspot(null /* use existing softap config */))
|| (!enable && mgr.stopSoftAp())) {
mWifiTetherRequested = enable;
return TETHER_ERROR_NO_ERROR;
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
index 0273ed3..cdbc541 100644
--- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
@@ -94,7 +94,7 @@
import android.net.util.InterfaceParams;
import android.net.util.NetworkConstants;
import android.net.util.SharedLog;
-import android.net.wifi.WifiConfiguration;
+import android.net.wifi.SoftApConfiguration;
import android.net.wifi.WifiManager;
import android.net.wifi.p2p.WifiP2pGroup;
import android.net.wifi.p2p.WifiP2pInfo;
@@ -806,12 +806,12 @@
// TODO: Test with and without interfaceStatusChanged().
@Test
public void failingWifiTetheringLegacyApBroadcast() throws Exception {
- when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
+ when(mWifiManager.startTetheredHotspot(any(SoftApConfiguration.class))).thenReturn(true);
// Emulate pressing the WiFi tethering button.
mTethering.startTethering(TETHERING_WIFI, null, false);
mLooper.dispatchAll();
- verify(mWifiManager, times(1)).startSoftAp(null);
+ verify(mWifiManager, times(1)).startTetheredHotspot(null);
verifyNoMoreInteractions(mWifiManager);
verifyNoMoreInteractions(mNMService);
@@ -833,12 +833,12 @@
// TODO: Test with and without interfaceStatusChanged().
@Test
public void workingWifiTetheringEnrichedApBroadcast() throws Exception {
- when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
+ when(mWifiManager.startTetheredHotspot(any(SoftApConfiguration.class))).thenReturn(true);
// Emulate pressing the WiFi tethering button.
mTethering.startTethering(TETHERING_WIFI, null, false);
mLooper.dispatchAll();
- verify(mWifiManager, times(1)).startSoftAp(null);
+ verify(mWifiManager, times(1)).startTetheredHotspot(null);
verifyNoMoreInteractions(mWifiManager);
verifyNoMoreInteractions(mNMService);
@@ -907,13 +907,13 @@
// TODO: Test with and without interfaceStatusChanged().
@Test
public void failureEnablingIpForwarding() throws Exception {
- when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
+ when(mWifiManager.startTetheredHotspot(any(SoftApConfiguration.class))).thenReturn(true);
doThrow(new RemoteException()).when(mNMService).setIpForwardingEnabled(true);
// Emulate pressing the WiFi tethering button.
mTethering.startTethering(TETHERING_WIFI, null, false);
mLooper.dispatchAll();
- verify(mWifiManager, times(1)).startSoftAp(null);
+ verify(mWifiManager, times(1)).startTetheredHotspot(null);
verifyNoMoreInteractions(mWifiManager);
verifyNoMoreInteractions(mNMService);
@@ -1155,7 +1155,7 @@
when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
.thenReturn(upstreamState);
- when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
+ when(mWifiManager.startTetheredHotspot(any(SoftApConfiguration.class))).thenReturn(true);
mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
mLooper.dispatchAll();
tetherState = callback.pollTetherStatesChanged();
diff --git a/services/Android.bp b/services/Android.bp
index fd4094f..8376d2b 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -111,7 +111,7 @@
srcs: [":services-sources"],
installable: false,
// TODO: remove the --hide options below
- args: " --show-single-annotation android.annotation.SystemApi" +
+ args: " --show-single-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.INTERNAL,process=android.annotation.SystemApi.Process.SYSTEM_SERVER\\)" +
" --hide-annotation android.annotation.Hide" +
" --hide-package com.google.android.startop.iorap" +
" --hide ReferencesHidden" +
diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java
index 92d1da5..c0f10a3 100644
--- a/services/core/java/com/android/server/MmsServiceBroker.java
+++ b/services/core/java/com/android/server/MmsServiceBroker.java
@@ -16,8 +16,6 @@
package com.android.server;
-import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
-
import android.Manifest;
import android.app.AppOpsManager;
import android.app.PendingIntent;
@@ -39,7 +37,6 @@
import android.os.UserHandle;
import android.service.carrier.CarrierMessagingService;
import android.telephony.SmsManager;
-import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Slog;
@@ -526,11 +523,11 @@
// Grant permission for the carrier app.
Intent intent = new Intent(action);
- TelephonyManager telephonyManager = (TelephonyManager)
- mContext.getSystemService(Context.TELEPHONY_SERVICE);
- List<String> carrierPackages = telephonyManager
- .getCarrierPackageNamesForIntentAndPhone(
- intent, getPhoneIdFromSubId(subId));
+ TelephonyManager telephonyManager =
+ (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ List<String> carrierPackages =
+ telephonyManager.getCarrierPackageNamesForIntentAndPhone(
+ intent, SubscriptionManager.getPhoneId(subId));
if (carrierPackages != null && carrierPackages.size() == 1) {
LocalServices.getService(UriGrantsManagerInternal.class)
.grantUriPermissionFromIntent(callingUid, carrierPackages.get(0),
@@ -542,13 +539,4 @@
return contentUri;
}
}
-
- private int getPhoneIdFromSubId(int subId) {
- SubscriptionManager subManager = (SubscriptionManager)
- mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
- if (subManager == null) return INVALID_SIM_SLOT_INDEX;
- SubscriptionInfo info = subManager.getActiveSubscriptionInfo(subId);
- if (info == null) return INVALID_SIM_SLOT_INDEX;
- return info.getSimSlotIndex();
- }
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 7f62747..6bc117b 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -16,7 +16,6 @@
package com.android.server;
-import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
import static android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED;
import static android.telephony.TelephonyRegistryManager.SIM_ACTIVATION_TYPE_DATA;
import static android.telephony.TelephonyRegistryManager.SIM_ACTIVATION_TYPE_VOICE;
@@ -60,7 +59,6 @@
import android.telephony.Rlog;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
-import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
@@ -99,7 +97,7 @@
* and 15973975 by saving the phoneId of the registrant and then using the
* phoneId when deciding to to make a callback. This is necessary because
* a subId changes from to a dummy value when a SIM is removed and thus won't
- * compare properly. Because getPhoneIdFromSubId(int subId) handles
+ * compare properly. Because SubscriptionManager.getPhoneId(int subId) handles
* the dummy value conversion we properly do the callbacks.
*
* Eventually we may want to remove the notion of dummy value but for now this
@@ -133,7 +131,7 @@
int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
- int phoneId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
+ int phoneId = SubscriptionManager.INVALID_PHONE_INDEX;
boolean matchPhoneStateListenerEvent(int events) {
return (callback != null) && ((events & this.events) != 0);
@@ -233,7 +231,7 @@
private int mDefaultSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
- private int mDefaultPhoneId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
+ private int mDefaultPhoneId = SubscriptionManager.INVALID_PHONE_INDEX;
private int[] mRingingCallState;
@@ -360,7 +358,7 @@
SubscriptionManager.getDefaultSubscriptionId());
int newDefaultPhoneId = intent.getIntExtra(
SubscriptionManager.EXTRA_SLOT_INDEX,
- getPhoneIdFromSubId(newDefaultSubId));
+ SubscriptionManager.getPhoneId(newDefaultSubId));
if (DBG) {
log("onReceive:current mDefaultSubId=" + mDefaultSubId
+ " current mDefaultPhoneId=" + mDefaultPhoneId
@@ -770,7 +768,7 @@
return;
}
- int phoneId = getPhoneIdFromSubId(subId);
+ int phoneId = SubscriptionManager.getPhoneId(subId);
synchronized (mRecords) {
// register
IBinder b = callback.asBinder();
@@ -1101,7 +1099,7 @@
// Called only by Telecomm to communicate call state across different phone accounts. So
// there is no need to add a valid subId or slotId.
broadcastCallStateChanged(state, phoneNumber,
- SubscriptionManager.INVALID_SIM_SLOT_INDEX,
+ SubscriptionManager.INVALID_PHONE_INDEX,
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
}
@@ -1326,7 +1324,7 @@
synchronized (mRecords) {
mCarrierNetworkChangeState = active;
for (int subId : subIds) {
- int phoneId = getPhoneIdFromSubId(subId);
+ int phoneId = SubscriptionManager.getPhoneId(subId);
if (VDBG) {
log("notifyCarrierNetworkChange: active=" + active + "subId: " + subId);
@@ -1359,7 +1357,7 @@
log("notifyCellInfoForSubscriber: subId=" + subId
+ " cellInfo=" + cellInfo);
}
- int phoneId = getPhoneIdFromSubId(subId);
+ int phoneId = SubscriptionManager.getPhoneId(subId);
synchronized (mRecords) {
if (validatePhoneId(phoneId)) {
mCellInfo.set(phoneId, cellInfo);
@@ -1450,7 +1448,7 @@
log("notifyCallForwardingChangedForSubscriber: subId=" + subId
+ " cfi=" + cfi);
}
- int phoneId = getPhoneIdFromSubId(subId);
+ int phoneId = SubscriptionManager.getPhoneId(subId);
synchronized (mRecords) {
if (validatePhoneId(phoneId)) {
mCallForwarding[phoneId] = cfi;
@@ -1478,7 +1476,7 @@
if (!checkNotifyPermission("notifyDataActivity()" )) {
return;
}
- int phoneId = getPhoneIdFromSubId(subId);
+ int phoneId = SubscriptionManager.getPhoneId(subId);
synchronized (mRecords) {
if (validatePhoneId(phoneId)) {
mDataActivity[phoneId] = state;
@@ -1629,7 +1627,7 @@
log("notifyCellLocationForSubscriber: subId=" + subId
+ " cellLocation=" + cellLocation);
}
- int phoneId = getPhoneIdFromSubId(subId);
+ int phoneId = SubscriptionManager.getPhoneId(subId);
synchronized (mRecords) {
if (validatePhoneId(phoneId)) {
mCellLocation[phoneId] = cellLocation;
@@ -1657,7 +1655,7 @@
if (!checkNotifyPermission("notifyOtaspChanged()" )) {
return;
}
- int phoneId = getPhoneIdFromSubId(subId);
+ int phoneId = SubscriptionManager.getPhoneId(subId);
synchronized (mRecords) {
if (validatePhoneId(phoneId)) {
mOtaspMode[phoneId] = otaspMode;
@@ -1761,7 +1759,7 @@
if (!checkNotifyPermission("notifyImsCallDisconnectCause()")) {
return;
}
- int phoneId = getPhoneIdFromSubId(subId);
+ int phoneId = SubscriptionManager.getPhoneId(subId);
synchronized (mRecords) {
if (validatePhoneId(phoneId)) {
mImsReasonInfo.set(phoneId, imsReasonInfo);
@@ -1821,7 +1819,7 @@
if (VDBG) {
log("notifySrvccStateChanged: subId=" + subId + " srvccState=" + state);
}
- int phoneId = getPhoneIdFromSubId(subId);
+ int phoneId = SubscriptionManager.getPhoneId(subId);
synchronized (mRecords) {
if (validatePhoneId(phoneId)) {
mSrvccState[phoneId] = state;
@@ -2229,7 +2227,7 @@
intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
}
// If the phoneId is invalid, the broadcast is for overall call state.
- if (phoneId != SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+ if (phoneId != SubscriptionManager.INVALID_PHONE_INDEX) {
intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId);
intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, phoneId);
}
@@ -2702,18 +2700,4 @@
private static CallQuality createCallQuality() {
return new CallQuality(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
-
- private int getPhoneIdFromSubId(int subId) {
- SubscriptionManager subManager = (SubscriptionManager)
- mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
- if (subManager == null) return INVALID_SIM_SLOT_INDEX;
-
- if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
- subId = SubscriptionManager.getDefaultSubscriptionId();
- }
-
- SubscriptionInfo info = subManager.getActiveSubscriptionInfo(subId);
- if (info == null) return INVALID_SIM_SLOT_INDEX;
- return info.getSimSlotIndex();
- }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c2dd046..b55d6ad 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -490,7 +490,7 @@
static final String[] EMPTY_STRING_ARRAY = new String[0];
// How many bytes to write into the dropbox log before truncating
- static final int DROPBOX_MAX_SIZE = 192 * 1024;
+ static final int DROPBOX_DEFAULT_MAX_SIZE = 192 * 1024;
// Assumes logcat entries average around 100 bytes; that's not perfect stack traces count
// as one line, but close enough for now.
static final int RESERVED_BYTES_PER_LOGCAT_LINE = 100;
@@ -9770,9 +9770,12 @@
sb.append(report);
}
- String setting = Settings.Global.ERROR_LOGCAT_PREFIX + dropboxTag;
- int lines = Settings.Global.getInt(mContext.getContentResolver(), setting, 0);
- int maxDataFileSize = DROPBOX_MAX_SIZE - sb.length()
+ String logcatSetting = Settings.Global.ERROR_LOGCAT_PREFIX + dropboxTag;
+ String maxBytesSetting = Settings.Global.MAX_ERROR_BYTES_PREFIX + dropboxTag;
+ int lines = Settings.Global.getInt(mContext.getContentResolver(), logcatSetting, 0);
+ int dropboxMaxSize = Settings.Global.getInt(
+ mContext.getContentResolver(), maxBytesSetting, DROPBOX_DEFAULT_MAX_SIZE);
+ int maxDataFileSize = dropboxMaxSize - sb.length()
- lines * RESERVED_BYTES_PER_LOGCAT_LINE;
if (dataFile != null && maxDataFileSize > 0) {
@@ -18433,7 +18436,7 @@
public ActivityPresentationInfo getActivityPresentationInfo(IBinder token) {
int displayId = Display.INVALID_DISPLAY;
try {
- displayId = mActivityTaskManager.getActivityDisplayId(token);
+ displayId = mActivityTaskManager.getDisplayId(token);
} catch (RemoteException e) {
}
diff --git a/services/core/java/com/android/server/incremental/IncrementalManagerService.java b/services/core/java/com/android/server/incremental/IncrementalManagerService.java
new file mode 100644
index 0000000..1b1a292
--- /dev/null
+++ b/services/core/java/com/android/server/incremental/IncrementalManagerService.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.incremental;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.pm.DataLoaderManager;
+import android.content.pm.IDataLoader;
+import android.content.pm.IDataLoaderStatusListener;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ServiceManager;
+import android.os.ShellCallback;
+import android.os.incremental.IIncrementalManager;
+import android.os.incremental.IncrementalDataLoaderParamsParcel;
+import android.os.incremental.IncrementalFileSystemControlParcel;
+import android.util.Slog;
+
+import java.io.FileDescriptor;
+
+/**
+ * This service has the following purposes:
+ * 1) Starts the IIncrementalManager binder service.
+ * 1) Starts the native IIncrementalManagerService binder service.
+ * 2) Handles shell commands for "incremental" service.
+ * 3) Handles binder calls from the native IIncrementalManagerService binder service and pass
+ * them to a data loader binder service.
+ */
+
+public class IncrementalManagerService extends IIncrementalManager.Stub {
+ private static final String TAG = "IncrementalManagerService";
+ private static final String BINDER_SERVICE_NAME = "incremental";
+ // DataLoaderManagerService should have been started before us
+ private @NonNull DataLoaderManager mDataLoaderManager;
+ private long mNativeInstance;
+ private final @NonNull Context mContext;
+
+ /**
+ * Starts IIncrementalManager binder service and register to Service Manager.
+ * Starts the native IIncrementalManagerNative binder service.
+ */
+ public static IncrementalManagerService start(Context context) {
+ IncrementalManagerService self = new IncrementalManagerService(context);
+ if (self.mNativeInstance == 0) {
+ return null;
+ }
+ return self;
+ }
+
+ private IncrementalManagerService(Context context) {
+ mContext = context;
+ mDataLoaderManager = mContext.getSystemService(DataLoaderManager.class);
+ ServiceManager.addService(BINDER_SERVICE_NAME, this);
+ // Starts and register IIncrementalManagerNative service
+ // TODO(b/136132412): add jni implementation
+ }
+ /**
+ * Notifies native IIncrementalManager service that system is ready.
+ */
+ public void systemReady() {
+ // TODO(b/136132412): add jni implementation
+ }
+
+ /**
+ * Finds data loader service provider and binds to it. This requires PackageManager.
+ */
+ @Override
+ public boolean prepareDataLoader(int mountId, IncrementalFileSystemControlParcel control,
+ IncrementalDataLoaderParamsParcel params,
+ IDataLoaderStatusListener listener) {
+ Bundle dataLoaderParams = new Bundle();
+ dataLoaderParams.putCharSequence("packageName", params.packageName);
+ dataLoaderParams.putParcelable("control", control);
+ dataLoaderParams.putParcelable("params", params);
+ DataLoaderManager dataLoaderManager = mContext.getSystemService(DataLoaderManager.class);
+ if (dataLoaderManager == null) {
+ Slog.e(TAG, "Failed to find data loader manager service");
+ return false;
+ }
+ if (!dataLoaderManager.initializeDataLoader(mountId, dataLoaderParams, listener)) {
+ Slog.e(TAG, "Failed to initialize data loader");
+ return false;
+ }
+ return true;
+ }
+
+
+ @Override
+ public boolean startDataLoader(int mountId) {
+ IDataLoader dataLoader = mDataLoaderManager.getDataLoader(mountId);
+ if (dataLoader == null) {
+ Slog.e(TAG, "Start failed to retrieve data loader for ID=" + mountId);
+ return false;
+ }
+ try {
+ // TODO: fix file list
+ dataLoader.start(null);
+ return true;
+ } catch (RemoteException ex) {
+ return false;
+ }
+ }
+
+ @Override
+ public void destroyDataLoader(int mountId) {
+ IDataLoader dataLoader = mDataLoaderManager.getDataLoader(mountId);
+ if (dataLoader == null) {
+ Slog.e(TAG, "Destroy failed to retrieve data loader for ID=" + mountId);
+ return;
+ }
+ try {
+ dataLoader.destroy();
+ } catch (RemoteException ex) {
+ return;
+ }
+ }
+
+ // TODO: remove this
+ @Override
+ public void newFileForDataLoader(int mountId, long inode, byte[] metadata) {
+ IDataLoader dataLoader = mDataLoaderManager.getDataLoader(mountId);
+ if (dataLoader == null) {
+ Slog.e(TAG, "Failed to retrieve data loader for ID=" + mountId);
+ return;
+ }
+ try {
+ dataLoader.onFileCreated(inode, metadata);
+ } catch (RemoteException ex) {
+ }
+ }
+
+ @Override
+ public void showHealthBlockedUI(int mountId) {
+ // TODO(b/136132412): implement this
+ }
+
+ @Override
+ public void onShellCommand(@NonNull FileDescriptor in, @NonNull FileDescriptor out,
+ FileDescriptor err, @NonNull String[] args, ShellCallback callback,
+ @NonNull ResultReceiver resultReceiver) {
+ (new IncrementalManagerShellCommand(mContext)).exec(
+ this, in, out, err, args, callback, resultReceiver);
+ }
+}
diff --git a/services/core/java/com/android/server/incremental/IncrementalManagerShellCommand.java b/services/core/java/com/android/server/incremental/IncrementalManagerShellCommand.java
new file mode 100644
index 0000000..d35e806
--- /dev/null
+++ b/services/core/java/com/android/server/incremental/IncrementalManagerShellCommand.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.incremental;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.IIntentReceiver;
+import android.content.IIntentSender;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.content.pm.InstallationFile;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.ShellCommand;
+import android.os.incremental.IncrementalDataLoaderParams;
+import android.util.Slog;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Defines actions to handle adb commands like "adb abb incremental ...".
+ */
+public final class IncrementalManagerShellCommand extends ShellCommand {
+ private static final String TAG = "IncrementalShellCommand";
+ // Assuming the adb data loader is always installed on the device
+ private static final String LOADER_PACKAGE_NAME = "com.android.incremental.nativeadb";
+ private final @NonNull Context mContext;
+
+ private static final int ERROR_INVALID_ARGUMENTS = -1;
+ private static final int ERROR_DATA_LOADER_INIT = -2;
+ private static final int ERROR_COMMAND_EXECUTION = -3;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({ERROR_INVALID_ARGUMENTS, ERROR_DATA_LOADER_INIT, ERROR_COMMAND_EXECUTION})
+ public @interface IncrementalShellCommandErrorCode {
+ }
+
+ IncrementalManagerShellCommand(@NonNull Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public int onCommand(@Nullable String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(null);
+ }
+ switch (cmd) {
+ case "install-start":
+ return runInstallStart();
+ case "install-finish":
+ return runInstallFinish();
+ default:
+ return handleDefaultCommands(cmd);
+ }
+ }
+
+ @Override
+ public void onHelp() {
+ PrintWriter pw = getOutPrintWriter();
+ pw.println("Incremental Service Commands:");
+ pw.println(" help");
+ pw.println(" Print this help text.");
+ pw.println(" install-start");
+ pw.println(" Opens an installation session");
+ pw.println(" install-finish SESSION_ID --file NAME:SIZE:INDEX --file NAME:SIZE:INDEX ...");
+ pw.println(" Commits an installation session specified by session ID for an APK ");
+ pw.println(" or a bundle of splits. Configures lib dirs or OBB files if specified.");
+ }
+
+ private int runInstallStart() {
+ final PrintWriter pw = getOutPrintWriter();
+ final PackageInstaller packageInstaller =
+ mContext.getPackageManager().getPackageInstaller();
+ if (packageInstaller == null) {
+ pw.println("Failed to get PackageInstaller.");
+ return ERROR_COMMAND_EXECUTION;
+ }
+
+ final Map<String, ParcelFileDescriptor> dataLoaderDynamicArgs = getDataLoaderDynamicArgs();
+ if (dataLoaderDynamicArgs == null) {
+ pw.println("File names and sizes don't match.");
+ return ERROR_DATA_LOADER_INIT;
+ }
+ final IncrementalDataLoaderParams params = new IncrementalDataLoaderParams(
+ "", LOADER_PACKAGE_NAME, dataLoaderDynamicArgs);
+ PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(
+ PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+ sessionParams.installFlags |= PackageManager.INSTALL_ALL_USERS;
+ // Replace existing if same package is already installed
+ sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
+ sessionParams.setIncrementalParams(params);
+
+ try {
+ int sessionId = packageInstaller.createSession(sessionParams);
+ pw.println("Successfully opened session: sessionId = " + sessionId);
+ } catch (Exception ex) {
+ pw.println("Failed to create session.");
+ return ERROR_COMMAND_EXECUTION;
+ } finally {
+ try {
+ for (Map.Entry<String, ParcelFileDescriptor> nfd
+ : dataLoaderDynamicArgs.entrySet()) {
+ nfd.getValue().close();
+ }
+ } catch (IOException ignored) {
+ }
+ }
+ return 0;
+ }
+
+ private int runInstallFinish() {
+ final PrintWriter pw = getOutPrintWriter();
+ final int sessionId = parseInt(getNextArgRequired());
+ final List<InstallationFile> installationFiles = parseFileArgs(pw);
+ if (installationFiles == null) {
+ pw.println("Must specify at least one file to install.");
+ return ERROR_INVALID_ARGUMENTS;
+ }
+ final int numFiles = installationFiles.size();
+ if (numFiles == 0) {
+ pw.println("Must specify at least one file to install.");
+ return ERROR_INVALID_ARGUMENTS;
+ }
+
+ final PackageInstaller packageInstaller = mContext.getPackageManager()
+ .getPackageInstaller();
+ if (packageInstaller == null) {
+ pw.println("Failed to get PackageInstaller.");
+ return ERROR_COMMAND_EXECUTION;
+ }
+
+ final LocalIntentReceiver localReceiver = new LocalIntentReceiver();
+ boolean success = false;
+
+ PackageInstaller.Session session = null;
+ try {
+ session = packageInstaller.openSession(sessionId);
+ for (int i = 0; i < numFiles; i++) {
+ InstallationFile file = installationFiles.get(i);
+ session.addFile(file.getName(), file.getSize(), file.getMetadata());
+ }
+ session.commit(localReceiver.getIntentSender());
+ final Intent result = localReceiver.getResult();
+ final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+ PackageInstaller.STATUS_FAILURE);
+ if (status == PackageInstaller.STATUS_SUCCESS) {
+ success = true;
+ pw.println("Success");
+ return 0;
+ } else {
+ pw.println("Failure ["
+ + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
+ return ERROR_COMMAND_EXECUTION;
+ }
+ } catch (Exception e) {
+ e.printStackTrace(pw);
+ return ERROR_COMMAND_EXECUTION;
+ } finally {
+ if (!success) {
+ try {
+ if (session != null) {
+ session.abandon();
+ }
+ } catch (Exception ignore) {
+ }
+ }
+ }
+ }
+
+ private static class LocalIntentReceiver {
+ private final LinkedBlockingQueue<Intent> mResult = new LinkedBlockingQueue<>();
+
+ private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
+ @Override
+ public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
+ IIntentReceiver finishedReceiver, String requiredPermission,
+ Bundle options) {
+ try {
+ mResult.offer(intent, 5, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ };
+
+ public IntentSender getIntentSender() {
+ return new IntentSender((IIntentSender) mLocalSender);
+ }
+
+ public Intent getResult() {
+ try {
+ return mResult.take();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ /** Helpers. */
+ private Map<String, ParcelFileDescriptor> getDataLoaderDynamicArgs() {
+ Map<String, ParcelFileDescriptor> dataLoaderDynamicArgs = new HashMap<>();
+ final FileDescriptor outFd = getOutFileDescriptor();
+ final FileDescriptor inFd = getInFileDescriptor();
+ try {
+ dataLoaderDynamicArgs.put("inFd", ParcelFileDescriptor.dup(inFd));
+ dataLoaderDynamicArgs.put("outFd", ParcelFileDescriptor.dup(outFd));
+ return dataLoaderDynamicArgs;
+ } catch (Exception ex) {
+ Slog.e(TAG, "Failed to dup FDs");
+ return null;
+ }
+ }
+
+ private long parseLong(String arg) {
+ long result = -1;
+ try {
+ result = Long.parseLong(arg);
+ } catch (NumberFormatException e) {
+ }
+ return result;
+ }
+
+ private int parseInt(String arg) {
+ int result = -1;
+ try {
+ result = Integer.parseInt(arg);
+ } catch (NumberFormatException e) {
+ }
+ return result;
+ }
+
+ private List<InstallationFile> parseFileArgs(PrintWriter pw) {
+ List<InstallationFile> fileList = new ArrayList<>();
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case "--file": {
+ final String fileArgs = getNextArgRequired();
+ final String[] args = fileArgs.split(":");
+ if (args.length != 3) {
+ pw.println("Invalid file args: " + fileArgs);
+ return null;
+ }
+ final String name = args[0];
+ final long size = parseLong(args[1]);
+ if (size < 0) {
+ pw.println("Invalid file size in: " + fileArgs);
+ return null;
+ }
+ final long index = parseLong(args[2]);
+ if (index < 0) {
+ pw.println("Invalid file index in: " + fileArgs);
+ return null;
+ }
+ final byte[] metadata = String.valueOf(index).getBytes(StandardCharsets.UTF_8);
+ fileList.add(new InstallationFile(name, size, metadata));
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ return fileList;
+ }
+}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index c25e206..2cb7e3b 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -70,6 +70,7 @@
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
+import android.os.ShellCallback;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
@@ -1042,6 +1043,13 @@
private boolean mVoiceButtonHandled = false;
@Override
+ public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+ String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
+ (new MediaShellCommand()).exec(this, in, out, err, args, callback,
+ resultReceiver);
+ }
+
+ @Override
public ISession createSession(String packageName, ISessionCallback cb, String tag,
Bundle sessionInfo, int userId) throws RemoteException {
final int pid = Binder.getCallingPid();
diff --git a/cmds/media/src/com/android/commands/media/Media.java b/services/core/java/com/android/server/media/MediaShellCommand.java
similarity index 64%
rename from cmds/media/src/com/android/commands/media/Media.java
rename to services/core/java/com/android/server/media/MediaShellCommand.java
index 1e915f8..20df271 100644
--- a/cmds/media/src/com/android/commands/media/Media.java
+++ b/services/core/java/com/android/server/media/MediaShellCommand.java
@@ -1,29 +1,27 @@
/*
-**
-** Copyright 2013, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
-package com.android.commands.media;
+package com.android.server.media;
import android.app.ActivityThread;
import android.content.Context;
import android.media.MediaMetadata;
import android.media.session.ISessionManager;
import android.media.session.MediaController;
-import android.media.session.MediaController.PlaybackInfo;
-import android.media.session.MediaSession.QueueItem;
+import android.media.session.MediaSession;
import android.media.session.MediaSessionManager;
import android.media.session.PlaybackState;
import android.os.Bundle;
@@ -31,59 +29,41 @@
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.ShellCommand;
import android.os.SystemClock;
-import android.util.AndroidException;
+import android.text.TextUtils;
import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
-import com.android.internal.os.BaseCommand;
-
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
-import java.io.PrintStream;
+import java.io.PrintWriter;
import java.util.List;
-public class Media extends BaseCommand {
+/**
+ * ShellCommand for MediaSessionService.
+ */
+public class MediaShellCommand extends ShellCommand {
// This doesn't belongs to any package. Setting the package name to empty string.
private static final String PACKAGE_NAME = "";
private static ActivityThread sThread;
private static MediaSessionManager sMediaSessionManager;
private ISessionManager mSessionService;
-
- /**
- * Command-line entry point.
- *
- * @param args The command-line arguments
- */
- public static void main(String[] args) {
- (new Media()).run(args);
- }
+ private PrintWriter mWriter;
+ private PrintWriter mErrorWriter;
@Override
- public void onShowUsage(PrintStream out) {
- out.println(
- "usage: media [subcommand] [options]\n" +
- " media dispatch KEY\n" +
- " media list-sessions\n" +
- " media monitor <tag>\n" +
- " media volume [options]\n" +
- "\n" +
- "media dispatch: dispatch a media key to the system.\n" +
- " KEY may be: play, pause, play-pause, mute, headsethook,\n" +
- " stop, next, previous, rewind, record, fast-forword.\n" +
- "media list-sessions: print a list of the current sessions.\n" +
- "media monitor: monitor updates to the specified session.\n" +
- " Use the tag from list-sessions.\n" +
- "media volume: " + VolumeCtrl.USAGE
- );
- }
+ public int onCommand(String cmd) {
+ mWriter = getOutPrintWriter();
+ mErrorWriter = getErrPrintWriter();
- @Override
- public void onRun() throws Exception {
+ if (TextUtils.isEmpty(cmd)) {
+ return handleDefaultCommands(cmd);
+ }
if (sThread == null) {
- Looper.prepareMainLooper();
+ Looper.prepare();
sThread = ActivityThread.systemMain();
Context context = sThread.getSystemContext();
sMediaSessionManager =
@@ -92,25 +72,47 @@
mSessionService = ISessionManager.Stub.asInterface(ServiceManager.checkService(
Context.MEDIA_SESSION_SERVICE));
if (mSessionService == null) {
- System.err.println(NO_SYSTEM_ERROR_CODE);
- throw new AndroidException(
+ throw new IllegalStateException(
"Can't connect to media session service; is the system running?");
}
- String op = nextArgRequired();
-
- if (op.equals("dispatch")) {
- runDispatch();
- } else if (op.equals("list-sessions")) {
- runListSessions();
- } else if (op.equals("monitor")) {
- runMonitor();
- } else if (op.equals("volume")) {
- runVolume();
- } else {
- showError("Error: unknown command '" + op + "'");
- return;
+ try {
+ if (cmd.equals("dispatch")) {
+ runDispatch();
+ } else if (cmd.equals("list-sessions")) {
+ runListSessions();
+ } else if (cmd.equals("monitor")) {
+ runMonitor();
+ } else if (cmd.equals("volume")) {
+ runVolume();
+ } else {
+ showError("Error: unknown command '" + cmd + "'");
+ return -1;
+ }
+ } catch (Exception e) {
+ showError(e.toString());
+ return -1;
}
+ return 0;
+ }
+
+ @Override
+ public void onHelp() {
+ mWriter.println("usage: media_session [subcommand] [options]");
+ mWriter.println(" media_session dispatch KEY");
+ mWriter.println(" media_session dispatch KEY");
+ mWriter.println(" media_session list-sessions");
+ mWriter.println(" media_session monitor <tag>");
+ mWriter.println(" media_session volume [options]");
+ mWriter.println();
+ mWriter.println("media_session dispatch: dispatch a media key to the system.");
+ mWriter.println(" KEY may be: play, pause, play-pause, mute, headsethook,");
+ mWriter.println(" stop, next, previous, rewind, record, fast-forword.");
+ mWriter.println("media_session list-sessions: print a list of the current sessions.");
+ mWriter.println("media_session monitor: monitor updates to the specified session.");
+ mWriter.println(" Use the tag from list-sessions.");
+ mWriter.println("media_session volume: " + VolumeCtrl.USAGE);
+ mWriter.println();
}
private void sendMediaKey(KeyEvent event) {
@@ -121,7 +123,7 @@
}
private void runMonitor() throws Exception {
- String id = nextArgRequired();
+ String id = getNextArgRequired();
if (id == null) {
showError("Error: must include a session id");
return;
@@ -133,7 +135,8 @@
for (MediaController controller : controllers) {
try {
if (controller != null && id.equals(controller.getTag())) {
- ControllerMonitor monitor = new ControllerMonitor(controller);
+ MediaShellCommand.ControllerMonitor monitor =
+ new MediaShellCommand.ControllerMonitor(controller);
monitor.run();
success = true;
break;
@@ -143,15 +146,15 @@
}
}
} catch (Exception e) {
- System.out.println("***Error monitoring session*** " + e.getMessage());
+ mErrorWriter.println("***Error monitoring session*** " + e.getMessage());
}
if (!success) {
- System.out.println("No session found with id " + id);
+ mErrorWriter.println("No session found with id " + id);
}
}
private void runDispatch() throws Exception {
- String cmd = nextArgRequired();
+ String cmd = getNextArgRequired();
int keycode;
if ("play".equals(cmd)) {
keycode = KeyEvent.KEYCODE_MEDIA_PLAY;
@@ -186,68 +189,73 @@
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD));
}
+ void showError(String errMsg) {
+ onHelp();
+ mErrorWriter.println(errMsg);
+ }
+
class ControllerCallback extends MediaController.Callback {
@Override
public void onSessionDestroyed() {
- System.out.println("onSessionDestroyed. Enter q to quit.");
+ mWriter.println("onSessionDestroyed. Enter q to quit.");
}
@Override
public void onSessionEvent(String event, Bundle extras) {
- System.out.println("onSessionEvent event=" + event + ", extras=" + extras);
+ mWriter.println("onSessionEvent event=" + event + ", extras=" + extras);
}
@Override
public void onPlaybackStateChanged(PlaybackState state) {
- System.out.println("onPlaybackStateChanged " + state);
+ mWriter.println("onPlaybackStateChanged " + state);
}
@Override
public void onMetadataChanged(MediaMetadata metadata) {
String mmString = metadata == null ? null : "title=" + metadata
.getDescription();
- System.out.println("onMetadataChanged " + mmString);
+ mWriter.println("onMetadataChanged " + mmString);
}
@Override
- public void onQueueChanged(List<QueueItem> queue) {
- System.out.println("onQueueChanged, "
+ public void onQueueChanged(List<MediaSession.QueueItem> queue) {
+ mWriter.println("onQueueChanged, "
+ (queue == null ? "null queue" : " size=" + queue.size()));
}
@Override
public void onQueueTitleChanged(CharSequence title) {
- System.out.println("onQueueTitleChange " + title);
+ mWriter.println("onQueueTitleChange " + title);
}
@Override
public void onExtrasChanged(Bundle extras) {
- System.out.println("onExtrasChanged " + extras);
+ mWriter.println("onExtrasChanged " + extras);
}
@Override
- public void onAudioInfoChanged(PlaybackInfo info) {
- System.out.println("onAudioInfoChanged " + info);
+ public void onAudioInfoChanged(MediaController.PlaybackInfo info) {
+ mWriter.println("onAudioInfoChanged " + info);
}
}
private class ControllerMonitor {
private final MediaController mController;
- private final ControllerCallback mControllerCallback;
+ private final MediaShellCommand.ControllerCallback mControllerCallback;
ControllerMonitor(MediaController controller) {
mController = controller;
- mControllerCallback = new ControllerCallback();
+ mControllerCallback = new MediaShellCommand.ControllerCallback();
}
void printUsageMessage() {
try {
- System.out.println("V2Monitoring session " + mController.getTag()
+ mWriter.println("V2Monitoring session " + mController.getTag()
+ "... available commands: play, pause, next, previous");
} catch (RuntimeException e) {
- System.out.println("Error trying to monitor session!");
+ mWriter.println("Error trying to monitor session!");
}
- System.out.println("(q)uit: finish monitoring");
+ mWriter.println("(q)uit: finish monitoring");
}
void run() throws RemoteException {
@@ -258,7 +266,7 @@
try {
mController.registerCallback(mControllerCallback);
} catch (RuntimeException e) {
- System.out.println("Error registering monitor callback");
+ mErrorWriter.println("Error registering monitor callback");
}
}
};
@@ -284,7 +292,7 @@
} else if ("previous".equals(line)) {
dispatchKeyCode(KeyEvent.KEYCODE_MEDIA_PREVIOUS);
} else {
- System.out.println("Invalid command: " + line);
+ mErrorWriter.println("Invalid command: " + line);
}
synchronized (this) {
@@ -316,19 +324,19 @@
mController.dispatchMediaButtonEvent(down);
mController.dispatchMediaButtonEvent(up);
} catch (RuntimeException e) {
- System.out.println("Failed to dispatch " + keyCode);
+ mErrorWriter.println("Failed to dispatch " + keyCode);
}
}
}
private void runListSessions() {
- System.out.println("Sessions:");
+ mWriter.println("Sessions:");
try {
List<MediaController> controllers = sMediaSessionManager.getActiveSessions(null);
for (MediaController controller : controllers) {
if (controller != null) {
try {
- System.out.println(" tag=" + controller.getTag()
+ mWriter.println(" tag=" + controller.getTag()
+ ", package=" + controller.getPackageName());
} catch (RuntimeException e) {
// ignore
@@ -336,7 +344,7 @@
}
}
} catch (Exception e) {
- System.out.println("***Error listing sessions***");
+ mErrorWriter.println("***Error listing sessions***");
}
}
diff --git a/cmds/media/src/com/android/commands/media/VolumeCtrl.java b/services/core/java/com/android/server/media/VolumeCtrl.java
old mode 100755
new mode 100644
similarity index 64%
rename from cmds/media/src/com/android/commands/media/VolumeCtrl.java
rename to services/core/java/com/android/server/media/VolumeCtrl.java
index 1629c6f..7a26665
--- a/cmds/media/src/com/android/commands/media/VolumeCtrl.java
+++ b/services/core/java/com/android/server/media/VolumeCtrl.java
@@ -1,21 +1,20 @@
/*
-**
-** Copyright 2016, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
-package com.android.commands.media;
+package com.android.server.media;
import android.content.Context;
import android.media.AudioManager;
@@ -26,45 +25,41 @@
import com.android.internal.os.BaseCommand;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.PrintStream;
-import java.lang.ArrayIndexOutOfBoundsException;
-
/**
* Command line tool to exercise AudioService.setStreamVolume()
* and AudioService.adjustStreamVolume()
*/
public class VolumeCtrl {
- private final static String TAG = "VolumeCtrl";
+ private static final String TAG = "VolumeCtrl";
// --stream affects --set, --adj or --get options.
// --show affects --set and --adj options.
// --get can be used with --set, --adj or by itself.
- public final static String USAGE = new String(
- "the options are as follows: \n" +
- "\t\t--stream STREAM selects the stream to control, see AudioManager.STREAM_*\n" +
- "\t\t controls AudioManager.STREAM_MUSIC if no stream is specified\n"+
- "\t\t--set INDEX sets the volume index value\n" +
- "\t\t--adj DIRECTION adjusts the volume, use raise|same|lower for the direction\n" +
- "\t\t--get outputs the current volume\n" +
- "\t\t--show shows the UI during the volume change\n" +
- "\texamples:\n" +
- "\t\tadb shell media volume --show --stream 3 --set 11\n" +
- "\t\tadb shell media volume --stream 0 --adj lower\n" +
- "\t\tadb shell media volume --stream 3 --get\n"
- );
+ public static final String USAGE = new String("the options are as follows: \n"
+ + "\t\t--stream STREAM selects the stream to control, see AudioManager.STREAM_*\n"
+ + "\t\t controls AudioManager.STREAM_MUSIC if no stream is specified\n"
+ + "\t\t--set INDEX sets the volume index value\n"
+ + "\t\t--adj DIRECTION adjusts the volume, use raise|same|lower for the direction\n"
+ + "\t\t--get outputs the current volume\n"
+ + "\t\t--show shows the UI during the volume change\n"
+ + "\texamples:\n"
+ + "\t\tadb shell media volume --show --stream 3 --set 11\n"
+ + "\t\tadb shell media volume --stream 0 --adj lower\n"
+ + "\t\tadb shell media volume --stream 3 --get\n"
+ );
- private final static int VOLUME_CONTROL_MODE_SET = 1;
- private final static int VOLUME_CONTROL_MODE_ADJUST = 2;
+ private static final int VOLUME_CONTROL_MODE_SET = 1;
+ private static final int VOLUME_CONTROL_MODE_ADJUST = 2;
- private final static String ADJUST_LOWER = "lower";
- private final static String ADJUST_SAME = "same";
- private final static String ADJUST_RAISE = "raise";
+ private static final String ADJUST_LOWER = "lower";
+ private static final String ADJUST_SAME = "same";
+ private static final String ADJUST_RAISE = "raise";
- public static void run(BaseCommand cmd) throws Exception {
+ /**
+ * Runs a given MediaShellCommand
+ */
+ public static void run(MediaShellCommand cmd) throws Exception {
//----------------------------------------
// Default parameters
int stream = AudioManager.STREAM_MUSIC;
@@ -78,7 +73,7 @@
// read options
String option;
String adjustment = null;
- while ((option = cmd.nextOption()) != null) {
+ while ((option = cmd.getNextOption()) != null) {
switch (option) {
case "--show":
showUi = true;
@@ -88,17 +83,17 @@
log(LOG_V, "will get volume");
break;
case "--stream":
- stream = Integer.decode(cmd.nextArgRequired()).intValue();
+ stream = Integer.decode(cmd.getNextArgRequired()).intValue();
log(LOG_V, "will control stream=" + stream + " (" + streamName(stream) + ")");
break;
case "--set":
- volIndex = Integer.decode(cmd.nextArgRequired()).intValue();
+ volIndex = Integer.decode(cmd.getNextArgRequired()).intValue();
mode = VOLUME_CONTROL_MODE_SET;
log(LOG_V, "will set volume to index=" + volIndex);
break;
case "--adj":
mode = VOLUME_CONTROL_MODE_ADJUST;
- adjustment = cmd.nextArgRequired();
+ adjustment = cmd.getNextArgRequired();
log(LOG_V, "will adjust volume");
break;
default:
@@ -140,7 +135,7 @@
if ((volIndex > audioService.getStreamMaxVolume(stream))
|| (volIndex < audioService.getStreamMinVolume(stream))) {
cmd.showError(String.format("Error: invalid volume index %d for stream %d "
- + "(should be in [%d..%d])", volIndex, stream,
+ + "(should be in [%d..%d])", volIndex, stream,
audioService.getStreamMinVolume(stream),
audioService.getStreamMaxVolume(stream)));
return;
@@ -149,7 +144,7 @@
//----------------------------------------
// Non-interactive test
- final int flag = showUi? AudioManager.FLAG_SHOW_UI : 0;
+ final int flag = showUi ? AudioManager.FLAG_SHOW_UI : 0;
final String pack = cmd.getClass().getPackage().getName();
if (mode == VOLUME_CONTROL_MODE_SET) {
audioService.setStreamVolume(stream, volIndex, flag, pack/*callingPackage*/);
@@ -157,9 +152,9 @@
audioService.adjustStreamVolume(stream, adjDir, flag, pack);
}
if (doGet) {
- log(LOG_V, "volume is " + audioService.getStreamVolume(stream) +
- " in range [" + audioService.getStreamMinVolume(stream) +
- ".." + audioService.getStreamMaxVolume(stream) + "]");
+ log(LOG_V, "volume is " + audioService.getStreamVolume(stream)
+ + " in range [" + audioService.getStreamMinVolume(stream)
+ + ".." + audioService.getStreamMaxVolume(stream) + "]");
}
}
@@ -181,5 +176,4 @@
return "invalid stream";
}
}
-
}
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 2b4b409..5ae8c58 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -17,11 +17,11 @@
package com.android.server.pm;
import android.annotation.IntDef;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.apex.ApexInfo;
import android.apex.ApexInfoList;
import android.apex.ApexSessionInfo;
+import android.apex.ApexSessionParams;
import android.apex.IApexService;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -176,13 +176,9 @@
* enough for it to be activated at the next boot, the caller needs to call
* {@link #markStagedSessionReady(int)}.
*
- * @param sessionId the identifier of the {@link PackageInstallerSession} being submitted.
- * @param childSessionIds if {@code sessionId} is a multi-package session, this should contain
- * an array of identifiers of all the child sessions. Otherwise it should
- * be an empty array.
* @throws PackageManagerException if call to apexd fails
*/
- abstract ApexInfoList submitStagedSession(int sessionId, @NonNull int[] childSessionIds)
+ abstract ApexInfoList submitStagedSession(ApexSessionParams params)
throws PackageManagerException;
/**
@@ -450,11 +446,10 @@
}
@Override
- ApexInfoList submitStagedSession(int sessionId, @NonNull int[] childSessionIds)
- throws PackageManagerException {
+ ApexInfoList submitStagedSession(ApexSessionParams params) throws PackageManagerException {
try {
final ApexInfoList apexInfoList = new ApexInfoList();
- mApexService.submitStagedSession(sessionId, childSessionIds, apexInfoList);
+ mApexService.submitStagedSession(params, apexInfoList);
return apexInfoList;
} catch (RemoteException re) {
Slog.e(TAG, "Unable to contact apexservice", re);
@@ -686,7 +681,7 @@
}
@Override
- ApexInfoList submitStagedSession(int sessionId, int[] childSessionIds)
+ ApexInfoList submitStagedSession(ApexSessionParams params)
throws PackageManagerException {
throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
"Device doesn't support updating APEX");
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 7ea4e98..688c34f 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -21,6 +21,7 @@
import android.apex.ApexInfo;
import android.apex.ApexInfoList;
import android.apex.ApexSessionInfo;
+import android.apex.ApexSessionParams;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
@@ -36,6 +37,8 @@
import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
import android.content.pm.ParceledListSlice;
import android.content.rollback.IRollbackManager;
+import android.content.rollback.RollbackInfo;
+import android.content.rollback.RollbackManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -49,6 +52,7 @@
import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseIntArray;
import android.util.apk.ApkSignatureVerifier;
import com.android.internal.annotations.GuardedBy;
@@ -82,6 +86,9 @@
@GuardedBy("mStagedSessions")
private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>();
+ @GuardedBy("mStagedSessions")
+ private final SparseIntArray mSessionRollbackIds = new SparseIntArray();
+
StagingManager(PackageInstallerService pi, ApexManager am, Context context) {
mPi = pi;
mApexManager = am;
@@ -166,18 +173,32 @@
private List<PackageInfo> submitSessionToApexService(
@NonNull PackageInstallerSession session) throws PackageManagerException {
- final IntArray childSessionsIds = new IntArray();
+ final IntArray childSessionIds = new IntArray();
if (session.isMultiPackage()) {
for (int id : session.getChildSessionIds()) {
if (isApexSession(mStagedSessions.get(id))) {
- childSessionsIds.add(id);
+ childSessionIds.add(id);
+ }
+ }
+ }
+ ApexSessionParams apexSessionParams = new ApexSessionParams();
+ apexSessionParams.sessionId = session.sessionId;
+ apexSessionParams.childSessionIds = childSessionIds.toArray();
+ if (session.params.installReason == PackageManager.INSTALL_REASON_ROLLBACK) {
+ apexSessionParams.isRollback = true;
+ apexSessionParams.rollbackId = retrieveRollbackIdForCommitSession(session.sessionId);
+ } else {
+ synchronized (mStagedSessions) {
+ int rollbackId = mSessionRollbackIds.get(session.sessionId, -1);
+ if (rollbackId != -1) {
+ apexSessionParams.hasRollbackEnabled = true;
+ apexSessionParams.rollbackId = rollbackId;
}
}
}
// submitStagedSession will throw a PackageManagerException if apexd verification fails,
// which will be propagated to populate stagedSessionErrorMessage of this session.
- final ApexInfoList apexInfoList = mApexManager.submitStagedSession(session.sessionId,
- childSessionsIds.toArray());
+ final ApexInfoList apexInfoList = mApexManager.submitStagedSession(apexSessionParams);
final List<PackageInfo> result = new ArrayList<>();
for (ApexInfo apexInfo : apexInfoList.apexInfos) {
final PackageInfo packageInfo;
@@ -208,6 +229,19 @@
return result;
}
+ private int retrieveRollbackIdForCommitSession(int sessionId) throws PackageManagerException {
+ RollbackManager rm = mContext.getSystemService(RollbackManager.class);
+
+ List<RollbackInfo> rollbacks = rm.getRecentlyCommittedRollbacks();
+ for (RollbackInfo rollback : rollbacks) {
+ if (rollback.getCommittedSessionId() == sessionId) {
+ return rollback.getRollbackId();
+ }
+ }
+ throw new PackageManagerException(
+ "Could not find rollback id for commit session: " + sessionId);
+ }
+
private void checkRequiredVersionCode(final PackageInstallerSession session,
final PackageInfo activePackage) throws PackageManagerException {
if (session.params.requiredInstalledVersionCode == PackageManager.VERSION_CODE_HIGHEST) {
@@ -633,6 +667,7 @@
void abortSession(@NonNull PackageInstallerSession session) {
synchronized (mStagedSessions) {
mStagedSessions.remove(session.sessionId);
+ mSessionRollbackIds.delete(session.sessionId);
}
}
@@ -865,6 +900,28 @@
*/
private void handlePreRebootVerification_Start(@NonNull PackageInstallerSession session) {
Slog.d(TAG, "Starting preRebootVerification for session " + session.sessionId);
+
+ if ((session.params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
+ // If rollback is enabled for this session, we call through to the RollbackManager
+ // with the list of sessions it must enable rollback for. Note that
+ // notifyStagedSession is a synchronous operation.
+ final IRollbackManager rm = IRollbackManager.Stub.asInterface(
+ ServiceManager.getService(Context.ROLLBACK_SERVICE));
+ try {
+ // NOTE: To stay consistent with the non-staged install flow, we don't fail the
+ // entire install if rollbacks can't be enabled.
+ int rollbackId = rm.notifyStagedSession(session.sessionId);
+ if (rollbackId != -1) {
+ synchronized (mStagedSessions) {
+ mSessionRollbackIds.put(session.sessionId, rollbackId);
+ }
+ }
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Failed to notifyStagedSession for session: "
+ + session.sessionId, re);
+ }
+ }
+
notifyPreRebootVerification_Start_Complete(session.sessionId);
}
@@ -929,25 +986,6 @@
* </ul></p>
*/
private void handlePreRebootVerification_End(@NonNull PackageInstallerSession session) {
- if ((session.params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
- // If rollback is enabled for this session, we call through to the RollbackManager
- // with the list of sessions it must enable rollback for. Note that
- // notifyStagedSession is a synchronous operation.
- final IRollbackManager rm = IRollbackManager.Stub.asInterface(
- ServiceManager.getService(Context.ROLLBACK_SERVICE));
- try {
- // NOTE: To stay consistent with the non-staged install flow, we don't fail the
- // entire install if rollbacks can't be enabled.
- if (!rm.notifyStagedSession(session.sessionId)) {
- Slog.e(TAG, "Unable to enable rollback for session: "
- + session.sessionId);
- }
- } catch (RemoteException re) {
- Slog.e(TAG, "Failed to notifyStagedSession for session: "
- + session.sessionId, re);
- }
- }
-
// Proactively mark session as ready before calling apexd. Although this call order
// looks counter-intuitive, this is the easiest way to ensure that session won't end up
// in the inconsistent state:
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index cb110c3..0d8f257 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -157,6 +157,7 @@
import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.Trace;
import android.os.UEventObserver;
import android.os.UserHandle;
import android.os.VibrationEffect;
@@ -4603,6 +4604,7 @@
public void screenTurningOn(final ScreenOnListener screenOnListener) {
if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turning on...");
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenTurningOn", 0 /* cookie */);
updateScreenOffSleepToken(false);
mDefaultDisplayPolicy.screenTurnedOn(screenOnListener);
@@ -4665,6 +4667,7 @@
if (!mDefaultDisplayPolicy.finishScreenTurningOn()) {
return; // Spurious or not ready yet.
}
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "screenTurningOn", 0 /* cookie */);
final boolean enableScreen;
final boolean awake = mDefaultDisplayPolicy.isAwake();
diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java
index 8b79c3f..6898e1c 100644
--- a/services/core/java/com/android/server/rollback/Rollback.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -418,6 +418,7 @@
if (isStaged()) {
parentParams.setStaged();
}
+ parentParams.setInstallReason(PackageManager.INSTALL_REASON_ROLLBACK);
int parentSessionId = packageInstaller.createSession(parentParams);
PackageInstaller.Session parentSession = packageInstaller.openSession(
@@ -484,6 +485,7 @@
synchronized (mLock) {
mState = ROLLBACK_STATE_AVAILABLE;
mRestoreUserDataInProgress = false;
+ info.setCommittedSessionId(-1);
}
sendFailure(context, statusReceiver,
RollbackManager.STATUS_FAILURE_INSTALL,
@@ -500,7 +502,6 @@
mRestoreUserDataInProgress = false;
}
- info.setCommittedSessionId(parentSessionId);
info.getCausePackages().addAll(causePackages);
RollbackStore.deletePackageCodePaths(this);
RollbackStore.saveRollback(this);
@@ -528,6 +529,7 @@
);
mState = ROLLBACK_STATE_COMMITTED;
+ info.setCommittedSessionId(parentSessionId);
mRestoreUserDataInProgress = true;
parentSession.commit(receiver.getIntentSender());
} catch (IOException e) {
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 3f5e2a4..9324870 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -897,11 +897,11 @@
}
@Override
- public boolean notifyStagedSession(int sessionId) {
+ public int notifyStagedSession(int sessionId) {
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("notifyStagedSession may only be called by the system.");
}
- final LinkedBlockingQueue<Boolean> result = new LinkedBlockingQueue<>();
+ final LinkedBlockingQueue<Integer> result = new LinkedBlockingQueue<>();
// NOTE: We post this runnable on the RollbackManager's binder thread because we'd prefer
// to preserve the invariant that all operations that modify state happen there.
@@ -911,7 +911,7 @@
final PackageInstaller.SessionInfo session = installer.getSessionInfo(sessionId);
if (session == null) {
Slog.e(TAG, "No matching install session for: " + sessionId);
- result.offer(false);
+ result.offer(-1);
return;
}
@@ -923,7 +923,7 @@
if (!session.isMultiPackage()) {
if (!enableRollbackForPackageSession(newRollback.rollback, session)) {
Slog.e(TAG, "Unable to enable rollback for session: " + sessionId);
- result.offer(false);
+ result.offer(-1);
return;
}
} else {
@@ -932,25 +932,30 @@
installer.getSessionInfo(childSessionId);
if (childSession == null) {
Slog.e(TAG, "No matching child install session for: " + childSessionId);
- result.offer(false);
+ result.offer(-1);
return;
}
if (!enableRollbackForPackageSession(newRollback.rollback, childSession)) {
Slog.e(TAG, "Unable to enable rollback for session: " + sessionId);
- result.offer(false);
+ result.offer(-1);
return;
}
}
}
- result.offer(completeEnableRollback(newRollback, true) != null);
+ Rollback rollback = completeEnableRollback(newRollback, true);
+ if (rollback == null) {
+ result.offer(-1);
+ } else {
+ result.offer(rollback.info.getRollbackId());
+ }
});
try {
return result.take();
} catch (InterruptedException ie) {
Slog.e(TAG, "Interrupted while waiting for notifyStagedSession response");
- return false;
+ return -1;
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
deleted file mode 100644
index 35b64e7..0000000
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ /dev/null
@@ -1,1384 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.wm;
-
-import static android.app.ActivityTaskManager.INVALID_STACK_ID;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.os.Build.VERSION_CODES.N;
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.Display.FLAG_PRIVATE;
-import static android.view.Display.REMOVE_MODE_DESTROY_CONTENT;
-
-import static com.android.server.am.ActivityDisplayProto.DISPLAY;
-import static com.android.server.am.ActivityDisplayProto.FOCUSED_STACK_ID;
-import static com.android.server.am.ActivityDisplayProto.ID;
-import static com.android.server.am.ActivityDisplayProto.RESUMED_ACTIVITY;
-import static com.android.server.am.ActivityDisplayProto.SINGLE_TASK_INSTANCE;
-import static com.android.server.am.ActivityDisplayProto.STACKS;
-import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
-import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
-import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
-import static com.android.server.wm.RootActivityContainer.FindTaskResult;
-import static com.android.server.wm.RootActivityContainer.TAG_STATES;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
-
-import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.app.ActivityManagerInternal;
-import android.app.ActivityOptions;
-import android.app.WindowConfiguration;
-import android.content.pm.ActivityInfo;
-import android.content.res.Configuration;
-import android.graphics.Point;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.IntArray;
-import android.util.Slog;
-import android.util.proto.ProtoOutputStream;
-import android.view.Display;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.function.pooled.PooledConsumer;
-import com.android.internal.util.function.pooled.PooledLambda;
-import com.android.internal.util.function.pooled.PooledPredicate;
-import com.android.server.protolog.common.ProtoLog;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-
-/**
- * Exactly one of these classes per Display in the system. Capable of holding zero or more
- * attached {@link ActivityStack}s.
- */
-class ActivityDisplay extends DisplayContent {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityDisplay" : TAG_ATM;
- private static final String TAG_STACK = TAG + POSTFIX_STACK;
-
- static final int POSITION_TOP = Integer.MAX_VALUE;
- static final int POSITION_BOTTOM = Integer.MIN_VALUE;
-
- /**
- * Counter for next free stack ID to use for dynamic activity stacks. Unique across displays.
- */
- private static int sNextFreeStackId = 0;
-
- private RootActivityContainer mRootActivityContainer;
- /** Actual Display this object tracks. */
- int mDisplayId;
- Display mDisplay;
-
- /**
- * All of the stacks on this display. Order matters, topmost stack is in front of all other
- * stacks, bottommost behind. Accessed directly by ActivityManager package classes. Any calls
- * changing the list should also call {@link #onStackOrderChanged()}.
- */
- private ArrayList<OnStackOrderChangedListener> mStackOrderChangedCallbacks = new ArrayList<>();
-
- /** Array of all UIDs that are present on the display. */
- private IntArray mDisplayAccessUIDs = new IntArray();
-
- /** All tokens used to put activities on this stack to sleep (including mOffToken) */
- final ArrayList<ActivityTaskManagerInternal.SleepToken> mAllSleepTokens = new ArrayList<>();
- /** The token acquired by ActivityStackSupervisor to put stacks on the display to sleep */
- ActivityTaskManagerInternal.SleepToken mOffToken;
-
- private boolean mSleeping;
-
- /** We started the process of removing the display from the system. */
- private boolean mRemoving;
-
- /**
- * The display is removed from the system and we are just waiting for all activities on it to be
- * finished before removing this object.
- */
- private boolean mRemoved;
-
- /** The display can only contain one task. */
- private boolean mSingleTaskInstance;
-
- /**
- * Non-null if the last size compatibility mode activity is using non-native screen
- * configuration. The activity is not able to put in multi-window mode, so it exists only one
- * per display.
- */
- private ActivityRecord mLastCompatModeActivity;
-
- /**
- * A focusable stack that is purposely to be positioned at the top. Although the stack may not
- * have the topmost index, it is used as a preferred candidate to prevent being unable to resume
- * target stack properly when there are other focusable always-on-top stacks.
- */
- private ActivityStack mPreferredTopFocusableStack;
-
- /**
- * If this is the same as {@link #getFocusedStack} then the activity on the top of the focused
- * stack has been resumed. If stacks are changing position this will hold the old stack until
- * the new stack becomes resumed after which it will be set to current focused stack.
- */
- private ActivityStack mLastFocusedStack;
-
- // Used in updating the display size
- private Point mTmpDisplaySize = new Point();
-
- // Used in updating override configurations
- private final Configuration mTempConfig = new Configuration();
-
- private final FindTaskResult mTmpFindTaskResult = new FindTaskResult();
-
- ActivityDisplay(RootActivityContainer root, Display display) {
- super(display, root.mWindowManager);
- mRootActivityContainer = root;
- mDisplayId = display.getDisplayId();
- mDisplay = display;
-
- if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Adding display=" + display);
-
- mWmService.mDisplayWindowSettings.applySettingsToDisplayLocked(this);
-
- if (mWmService.mDisplayManagerInternal != null) {
- mWmService.mDisplayManagerInternal
- .setDisplayInfoOverrideFromWindowManager(mDisplayId, getDisplayInfo());
- configureDisplayPolicy();
- }
-
- reconfigureDisplayLocked();
- onRequestedOverrideConfigurationChanged(getRequestedOverrideConfiguration());
- mWmService.mDisplayNotificationController.dispatchDisplayAdded(this);
- }
-
- void onDisplayChanged() {
- // The window policy is responsible for stopping activities on the default display.
- final int displayId = mDisplay.getDisplayId();
- if (displayId != DEFAULT_DISPLAY) {
- final int displayState = mDisplay.getState();
- if (displayState == Display.STATE_OFF && mOffToken == null) {
- mOffToken = mAtmService.acquireSleepToken("Display-off", displayId);
- } else if (displayState == Display.STATE_ON && mOffToken != null) {
- mOffToken.release();
- mOffToken = null;
- }
- }
-
- mDisplay.getRealSize(mTmpDisplaySize);
- setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y);
- updateDisplayInfo();
- mWmService.requestTraversal();
- }
-
- void addStack(ActivityStack stack, int position) {
- setStackOnDisplay(stack, position);
- positionStackAt(stack, position);
- mAtmService.updateSleepIfNeededLocked();
- }
-
- void onStackRemoved(ActivityStack stack) {
- if (DEBUG_STACK) {
- Slog.v(TAG_STACK, "removeStack: detaching " + stack + " from displayId=" + mDisplayId);
- }
- if (mPreferredTopFocusableStack == stack) {
- mPreferredTopFocusableStack = null;
- }
- releaseSelfIfNeeded();
- mAtmService.updateSleepIfNeededLocked();
- onStackOrderChanged(stack);
- }
-
- void positionStackAtTop(ActivityStack stack, boolean includingParents) {
- positionStackAtTop(stack, includingParents, null /* updateLastFocusedStackReason */);
- }
-
- void positionStackAtTop(ActivityStack stack, boolean includingParents,
- String updateLastFocusedStackReason) {
- positionStackAt(stack, getStackCount(), includingParents, updateLastFocusedStackReason);
- }
-
- void positionStackAtBottom(ActivityStack stack) {
- positionStackAtBottom(stack, null /* updateLastFocusedStackReason */);
- }
-
- void positionStackAtBottom(ActivityStack stack, String updateLastFocusedStackReason) {
- positionStackAt(stack, 0, false /* includingParents */, updateLastFocusedStackReason);
- }
-
- private void positionStackAt(ActivityStack stack, int position) {
- positionStackAt(stack, position, false /* includingParents */,
- null /* updateLastFocusedStackReason */);
- }
-
- private void positionStackAt(ActivityStack stack, int position, boolean includingParents,
- String updateLastFocusedStackReason) {
- // TODO: Keep in sync with WindowContainer.positionChildAt(), once we change that to adjust
- // the position internally, also update the logic here
- final ActivityStack prevFocusedStack = updateLastFocusedStackReason != null
- ? getFocusedStack() : null;
- final boolean wasContained = getIndexOf(stack) >= 0;
- if (mSingleTaskInstance && getStackCount() == 1 && !wasContained) {
- throw new IllegalStateException(
- "positionStackAt: Can only have one task on display=" + this);
- }
-
- // Since positionChildAt() is called during the creation process of pinned stacks,
- // ActivityStack#getStack() can be null.
- positionStackAt(position, stack, includingParents);
-
- // The insert position may be adjusted to non-top when there is always-on-top stack. Since
- // the original position is preferred to be top, the stack should have higher priority when
- // we are looking for top focusable stack. The condition {@code wasContained} restricts the
- // preferred stack is set only when moving an existing stack to top instead of adding a new
- // stack that may be too early (e.g. in the middle of launching or reparenting).
- if (wasContained && position >= getStackCount() - 1 && stack.isFocusableAndVisible()) {
- mPreferredTopFocusableStack = stack;
- } else if (mPreferredTopFocusableStack == stack) {
- mPreferredTopFocusableStack = null;
- }
-
- if (updateLastFocusedStackReason != null) {
- final ActivityStack currentFocusedStack = getFocusedStack();
- if (currentFocusedStack != prevFocusedStack) {
- mLastFocusedStack = prevFocusedStack;
- EventLogTags.writeWmFocusedStack(mRootActivityContainer.mCurrentUser, mDisplayId,
- currentFocusedStack == null ? -1 : currentFocusedStack.getStackId(),
- mLastFocusedStack == null ? -1 : mLastFocusedStack.getStackId(),
- updateLastFocusedStackReason);
- }
- }
-
- onStackOrderChanged(stack);
- }
-
- ActivityStack getStack(int stackId) {
- for (int i = getStackCount() - 1; i >= 0; --i) {
- final ActivityStack stack = getStackAt(i);
- if (stack.mStackId == stackId) {
- return stack;
- }
- }
- return null;
- }
-
- boolean alwaysCreateStack(int windowingMode, int activityType) {
- // Always create a stack for fullscreen, freeform, and split-screen-secondary windowing
- // modes so that we can manage visual ordering and return types correctly.
- return activityType == ACTIVITY_TYPE_STANDARD
- && (windowingMode == WINDOWING_MODE_FULLSCREEN
- || windowingMode == WINDOWING_MODE_FREEFORM
- || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
- }
-
- /**
- * Returns an existing stack compatible with the windowing mode and activity type or creates one
- * if a compatible stack doesn't exist.
- * @see #getStack(int, int)
- * @see #createStack(int, int, boolean)
- */
- ActivityStack getOrCreateStack(int windowingMode, int activityType,
- boolean onTop) {
- if (!alwaysCreateStack(windowingMode, activityType)) {
- ActivityStack stack = getStack(windowingMode, activityType);
- if (stack != null) {
- return stack;
- }
- }
- return createStack(windowingMode, activityType, onTop);
- }
-
- /**
- * Returns an existing stack compatible with the input params or creates one
- * if a compatible stack doesn't exist.
- * @see #getOrCreateStack(int, int, boolean)
- */
- ActivityStack getOrCreateStack(@Nullable ActivityRecord r,
- @Nullable ActivityOptions options, @Nullable Task candidateTask, int activityType,
- boolean onTop) {
- // First preference is the windowing mode in the activity options if set.
- int windowingMode = (options != null)
- ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
- // Validate that our desired windowingMode will work under the current conditions.
- // UNDEFINED windowing mode is a valid result and means that the new stack will inherit
- // it's display's windowing mode.
- windowingMode = validateWindowingMode(windowingMode, r, candidateTask, activityType);
- return getOrCreateStack(windowingMode, activityType, onTop);
- }
-
- @VisibleForTesting
- int getNextStackId() {
- return sNextFreeStackId++;
- }
-
- /**
- * Creates a stack matching the input windowing mode and activity type on this display.
- * @param windowingMode The windowing mode the stack should be created in. If
- * {@link WindowConfiguration#WINDOWING_MODE_UNDEFINED} then the stack will
- * inherit it's parent's windowing mode.
- * @param activityType The activityType the stack should be created in. If
- * {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} then the stack will
- * be created in {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
- * @param onTop If true the stack will be created at the top of the display, else at the bottom.
- * @return The newly created stack.
- */
- ActivityStack createStack(int windowingMode, int activityType, boolean onTop) {
-
- if (mSingleTaskInstance && getStackCount() > 0) {
- // Create stack on default display instead since this display can only contain 1 stack.
- // TODO: Kinda a hack, but better that having the decision at each call point. Hoping
- // this goes away once ActivityView is no longer using virtual displays.
- return mRootActivityContainer.getDefaultDisplay().createStack(
- windowingMode, activityType, onTop);
- }
-
- if (activityType == ACTIVITY_TYPE_UNDEFINED) {
- // Can't have an undefined stack type yet...so re-map to standard. Anyone that wants
- // anything else should be passing it in anyways...
- activityType = ACTIVITY_TYPE_STANDARD;
- }
-
- if (activityType != ACTIVITY_TYPE_STANDARD) {
- // For now there can be only one stack of a particular non-standard activity type on a
- // display. So, get that ignoring whatever windowing mode it is currently in.
- ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
- if (stack != null) {
- throw new IllegalArgumentException("Stack=" + stack + " of activityType="
- + activityType + " already on display=" + this + ". Can't have multiple.");
- }
- }
-
- if (!isWindowingModeSupported(windowingMode, mAtmService.mSupportsMultiWindow,
- mAtmService.mSupportsSplitScreenMultiWindow,
- mAtmService.mSupportsFreeformWindowManagement,
- mAtmService.mSupportsPictureInPicture, activityType)) {
- throw new IllegalArgumentException("Can't create stack for unsupported windowingMode="
- + windowingMode);
- }
-
- final int stackId = getNextStackId();
- return createStackUnchecked(windowingMode, activityType, stackId, onTop);
- }
-
- @VisibleForTesting
- ActivityStack createStackUnchecked(int windowingMode, int activityType,
- int stackId, boolean onTop) {
- if (windowingMode == WINDOWING_MODE_PINNED && activityType != ACTIVITY_TYPE_STANDARD) {
- throw new IllegalArgumentException("Stack with windowing mode cannot with non standard "
- + "activity type.");
- }
- return new ActivityStack(this, stackId,
- mRootActivityContainer.mStackSupervisor, windowingMode, activityType, onTop);
- }
-
- /**
- * Get the preferred focusable stack in priority. If the preferred stack does not exist, find a
- * focusable and visible stack from the top of stacks in this display.
- */
- ActivityStack getFocusedStack() {
- if (mPreferredTopFocusableStack != null) {
- return mPreferredTopFocusableStack;
- }
-
- for (int i = getStackCount() - 1; i >= 0; --i) {
- final ActivityStack stack = getStackAt(i);
- if (stack.isFocusableAndVisible()) {
- return stack;
- }
- }
-
- return null;
- }
-
- ActivityStack getNextFocusableStack(ActivityStack currentFocus, boolean ignoreCurrent) {
- final int currentWindowingMode = currentFocus != null
- ? currentFocus.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
-
- ActivityStack candidate = null;
- for (int i = getStackCount() - 1; i >= 0; --i) {
- final ActivityStack stack = getStackAt(i);
- if (ignoreCurrent && stack == currentFocus) {
- continue;
- }
- if (!stack.isFocusableAndVisible()) {
- continue;
- }
-
- if (currentWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
- && candidate == null && stack.inSplitScreenPrimaryWindowingMode()) {
- // If the currently focused stack is in split-screen secondary we save off the
- // top primary split-screen stack as a candidate for focus because we might
- // prefer focus to move to an other stack to avoid primary split-screen stack
- // overlapping with a fullscreen stack when a fullscreen stack is higher in z
- // than the next split-screen stack. Assistant stack, I am looking at you...
- // We only move the focus to the primary-split screen stack if there isn't a
- // better alternative.
- candidate = stack;
- continue;
- }
- if (candidate != null && stack.inSplitScreenSecondaryWindowingMode()) {
- // Use the candidate stack since we are now at the secondary split-screen.
- return candidate;
- }
- return stack;
- }
- return candidate;
- }
-
- ActivityRecord getResumedActivity() {
- final ActivityStack focusedStack = getFocusedStack();
- if (focusedStack == null) {
- return null;
- }
- // TODO(b/111541062): Move this into ActivityStack#getResumedActivity()
- // Check if the focused stack has the resumed activity
- ActivityRecord resumedActivity = focusedStack.getResumedActivity();
- if (resumedActivity == null || resumedActivity.app == null) {
- // If there is no registered resumed activity in the stack or it is not running -
- // try to use previously resumed one.
- resumedActivity = focusedStack.mPausingActivity;
- if (resumedActivity == null || resumedActivity.app == null) {
- // If previously resumed activity doesn't work either - find the topmost running
- // activity that can be focused.
- resumedActivity = focusedStack.topRunningActivity(true /* focusableOnly */);
- }
- }
- return resumedActivity;
- }
-
- ActivityStack getLastFocusedStack() {
- return mLastFocusedStack;
- }
-
- boolean allResumedActivitiesComplete() {
- for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityRecord r = getStackAt(stackNdx).getResumedActivity();
- if (r != null && !r.isState(RESUMED)) {
- return false;
- }
- }
- final ActivityStack currentFocusedStack = getFocusedStack();
- if (DEBUG_STACK) {
- Slog.d(TAG_STACK, "allResumedActivitiesComplete: mLastFocusedStack changing from="
- + mLastFocusedStack + " to=" + currentFocusedStack);
- }
- mLastFocusedStack = currentFocusedStack;
- return true;
- }
-
- /**
- * Pause all activities in either all of the stacks or just the back stacks. This is done before
- * resuming a new activity and to make sure that previously active activities are
- * paused in stacks that are no longer visible or in pinned windowing mode. This does not
- * pause activities in visible stacks, so if an activity is launched within the same stack/task,
- * then we should explicitly pause that stack's top activity.
- * @param userLeaving Passed to pauseActivity() to indicate whether to call onUserLeaving().
- * @param resuming The resuming activity.
- * @return {@code true} if any activity was paused as a result of this call.
- */
- boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming) {
- boolean someActivityPaused = false;
- for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = getStackAt(stackNdx);
- final ActivityRecord resumedActivity = stack.getResumedActivity();
- if (resumedActivity != null
- && (stack.getVisibility(resuming) != STACK_VISIBILITY_VISIBLE
- || !stack.isFocusable())) {
- if (DEBUG_STATES) Slog.d(TAG_STATES, "pauseBackStacks: stack=" + stack +
- " mResumedActivity=" + resumedActivity);
- someActivityPaused |= stack.startPausingLocked(userLeaving, false /* uiSleeping*/,
- resuming);
- }
- }
- return someActivityPaused;
- }
-
- /**
- * Find task for putting the Activity in.
- */
- void findTaskLocked(final ActivityRecord r, final boolean isPreferredDisplay,
- FindTaskResult result) {
- mTmpFindTaskResult.clear();
- for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = getStackAt(stackNdx);
- if (!r.hasCompatibleActivityType(stack)) {
- if (DEBUG_TASKS) {
- Slog.d(TAG_TASKS, "Skipping stack: (mismatch activity/stack) " + stack);
- }
- continue;
- }
-
- mTmpFindTaskResult.process(r, stack);
- // It is possible to have tasks in multiple stacks with the same root affinity, so
- // we should keep looking after finding an affinity match to see if there is a
- // better match in another stack. Also, task affinity isn't a good enough reason
- // to target a display which isn't the source of the intent, so skip any affinity
- // matches not on the specified display.
- if (mTmpFindTaskResult.mRecord != null) {
- if (mTmpFindTaskResult.mIdealMatch) {
- result.setTo(mTmpFindTaskResult);
- return;
- } else if (isPreferredDisplay) {
- // Note: since the traversing through the stacks is top down, the floating
- // tasks should always have lower priority than any affinity-matching tasks
- // in the fullscreen stacks
- result.setTo(mTmpFindTaskResult);
- }
- }
- }
- }
-
- /**
- * Removes stacks in the input windowing modes from the system if they are of activity type
- * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
- */
- void removeStacksInWindowingModes(int... windowingModes) {
- if (windowingModes == null || windowingModes.length == 0) {
- return;
- }
-
- // Collect the stacks that are necessary to be removed instead of performing the removal
- // by looping mStacks, so that we don't miss any stacks after the stack size changed or
- // stacks reordered.
- final ArrayList<ActivityStack> stacks = new ArrayList<>();
- for (int j = windowingModes.length - 1 ; j >= 0; --j) {
- final int windowingMode = windowingModes[j];
- for (int i = getStackCount() - 1; i >= 0; --i) {
- final ActivityStack stack = getStackAt(i);
- if (!stack.isActivityTypeStandardOrUndefined()) {
- continue;
- }
- if (stack.getWindowingMode() != windowingMode) {
- continue;
- }
- stacks.add(stack);
- }
- }
-
- for (int i = stacks.size() - 1; i >= 0; --i) {
- mRootActivityContainer.mStackSupervisor.removeStack(stacks.get(i));
- }
- }
-
- void removeStacksWithActivityTypes(int... activityTypes) {
- if (activityTypes == null || activityTypes.length == 0) {
- return;
- }
-
- // Collect the stacks that are necessary to be removed instead of performing the removal
- // by looping mStacks, so that we don't miss any stacks after the stack size changed or
- // stacks reordered.
- final ArrayList<ActivityStack> stacks = new ArrayList<>();
- for (int j = activityTypes.length - 1 ; j >= 0; --j) {
- final int activityType = activityTypes[j];
- for (int i = getStackCount() - 1; i >= 0; --i) {
- final ActivityStack stack = getStackAt(i);
- if (stack.getActivityType() == activityType) {
- stacks.add(stack);
- }
- }
- }
-
- for (int i = stacks.size() - 1; i >= 0; --i) {
- mRootActivityContainer.mStackSupervisor.removeStack(stacks.get(i));
- }
- }
-
- void onSplitScreenModeDismissed() {
- mAtmService.deferWindowLayout();
- try {
- // Adjust the windowing mode of any stack in secondary split-screen to fullscreen.
- for (int i = getStackCount() - 1; i >= 0; --i) {
- final ActivityStack otherStack = getStackAt(i);
- if (!otherStack.inSplitScreenSecondaryWindowingMode()) {
- continue;
- }
- otherStack.setWindowingMode(WINDOWING_MODE_UNDEFINED, false /* animate */,
- false /* showRecents */, false /* enteringSplitScreenMode */,
- true /* deferEnsuringVisibility */, false /* creating */);
- }
- } finally {
- final ActivityStack topFullscreenStack =
- getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
- final ActivityStack homeStack = getHomeStack();
- if (topFullscreenStack != null && homeStack != null && !isTopStack(homeStack)) {
- // Whenever split-screen is dismissed we want the home stack directly behind the
- // current top fullscreen stack so it shows up when the top stack is finished.
- // TODO: Would be better to use ActivityDisplay.positionChildAt() for this, however
- // ActivityDisplay doesn't have a direct controller to WM side yet. We can switch
- // once we have that.
- homeStack.moveToFront("onSplitScreenModeDismissed");
- topFullscreenStack.moveToFront("onSplitScreenModeDismissed");
- }
- mAtmService.continueWindowLayout();
- }
- }
-
- void onSplitScreenModeActivated() {
- mAtmService.deferWindowLayout();
- try {
- // Adjust the windowing mode of any affected by split-screen to split-screen secondary.
- final ActivityStack splitScreenPrimaryStack = getSplitScreenPrimaryStack();
- for (int i = getStackCount() - 1; i >= 0; --i) {
- final ActivityStack otherStack = getStackAt(i);
- if (otherStack == splitScreenPrimaryStack
- || !otherStack.affectedBySplitScreenResize()) {
- continue;
- }
- otherStack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
- false /* animate */, false /* showRecents */,
- true /* enteringSplitScreenMode */, true /* deferEnsuringVisibility */,
- false /* creating */);
- }
- } finally {
- mAtmService.continueWindowLayout();
- }
- }
-
- /**
- * Returns true if the {@param windowingMode} is supported based on other parameters passed in.
- * @param windowingMode The windowing mode we are checking support for.
- * @param supportsMultiWindow If we should consider support for multi-window mode in general.
- * @param supportsSplitScreen If we should consider support for split-screen multi-window.
- * @param supportsFreeform If we should consider support for freeform multi-window.
- * @param supportsPip If we should consider support for picture-in-picture mutli-window.
- * @param activityType The activity type under consideration.
- * @return true if the windowing mode is supported.
- */
- private boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow,
- boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip,
- int activityType) {
-
- if (windowingMode == WINDOWING_MODE_UNDEFINED
- || windowingMode == WINDOWING_MODE_FULLSCREEN) {
- return true;
- }
- if (!supportsMultiWindow) {
- return false;
- }
-
- final int displayWindowingMode = getWindowingMode();
- if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
- return supportsSplitScreen
- && WindowConfiguration.supportSplitScreenWindowingMode(activityType)
- // Freeform windows and split-screen windows don't mix well, so prevent
- // split windowing modes on freeform displays.
- && displayWindowingMode != WINDOWING_MODE_FREEFORM;
- }
-
- if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) {
- return false;
- }
-
- if (!supportsPip && windowingMode == WINDOWING_MODE_PINNED) {
- return false;
- }
- return true;
- }
-
- /**
- * Resolves the windowing mode that an {@link ActivityRecord} would be in if started on this
- * display with the provided parameters.
- *
- * @param r The ActivityRecord in question.
- * @param options Options to start with.
- * @param task The task within-which the activity would start.
- * @param activityType The type of activity to start.
- * @return The resolved (not UNDEFINED) windowing-mode that the activity would be in.
- */
- int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
- @Nullable Task task, int activityType) {
-
- // First preference if the windowing mode in the activity options if set.
- int windowingMode = (options != null)
- ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
-
- // If windowing mode is unset, then next preference is the candidate task, then the
- // activity record.
- if (windowingMode == WINDOWING_MODE_UNDEFINED) {
- if (task != null) {
- windowingMode = task.getWindowingMode();
- }
- if (windowingMode == WINDOWING_MODE_UNDEFINED && r != null) {
- windowingMode = r.getWindowingMode();
- }
- if (windowingMode == WINDOWING_MODE_UNDEFINED) {
- // Use the display's windowing mode.
- windowingMode = getWindowingMode();
- }
- }
- windowingMode = validateWindowingMode(windowingMode, r, task, activityType);
- return windowingMode != WINDOWING_MODE_UNDEFINED
- ? windowingMode : WINDOWING_MODE_FULLSCREEN;
- }
-
- /**
- * Check that the requested windowing-mode is appropriate for the specified task and/or activity
- * on this display.
- *
- * @param windowingMode The windowing-mode to validate.
- * @param r The {@link ActivityRecord} to check against.
- * @param task The {@link Task} to check against.
- * @param activityType An activity type.
- * @return The provided windowingMode or the closest valid mode which is appropriate.
- */
- int validateWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable Task task,
- int activityType) {
- // Make sure the windowing mode we are trying to use makes sense for what is supported.
- boolean supportsMultiWindow = mAtmService.mSupportsMultiWindow;
- boolean supportsSplitScreen = mAtmService.mSupportsSplitScreenMultiWindow;
- boolean supportsFreeform = mAtmService.mSupportsFreeformWindowManagement;
- boolean supportsPip = mAtmService.mSupportsPictureInPicture;
- if (supportsMultiWindow) {
- if (task != null) {
- supportsMultiWindow = task.isResizeable();
- supportsSplitScreen = task.supportsSplitScreenWindowingMode();
- // TODO: Do we need to check for freeform and Pip support here?
- } else if (r != null) {
- supportsMultiWindow = r.isResizeable();
- supportsSplitScreen = r.supportsSplitScreenWindowingMode();
- supportsFreeform = r.supportsFreeform();
- supportsPip = r.supportsPictureInPicture();
- }
- }
-
- final boolean inSplitScreenMode = hasSplitScreenPrimaryStack();
- if (!inSplitScreenMode
- && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) {
- // Switch to the display's windowing mode if we are not in split-screen mode and we are
- // trying to launch in split-screen secondary.
- windowingMode = WINDOWING_MODE_UNDEFINED;
- } else if (inSplitScreenMode && (windowingMode == WINDOWING_MODE_FULLSCREEN
- || windowingMode == WINDOWING_MODE_UNDEFINED)
- && supportsSplitScreen) {
- windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
- }
-
- if (windowingMode != WINDOWING_MODE_UNDEFINED
- && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen,
- supportsFreeform, supportsPip, activityType)) {
- return windowingMode;
- }
- return WINDOWING_MODE_UNDEFINED;
- }
-
- boolean isTopStack(ActivityStack stack) {
- return stack == getTopStack();
- }
-
- boolean isTopNotPinnedStack(ActivityStack stack) {
- for (int i = getStackCount() - 1; i >= 0; --i) {
- final ActivityStack current = getStackAt(i);
- if (!current.inPinnedWindowingMode()) {
- return current == stack;
- }
- }
- return false;
- }
-
- ActivityStack getTopStackInWindowingMode(int windowingMode) {
- for (int i = getStackCount() - 1; i >= 0; --i) {
- final ActivityStack current = getStackAt(i);
- if (windowingMode == current.getWindowingMode()) {
- return current;
- }
- }
- return null;
- }
-
- ActivityRecord topRunningActivity() {
- return topRunningActivity(false /* considerKeyguardState */);
- }
-
- /**
- * Returns the top running activity in the focused stack. In the case the focused stack has no
- * such activity, the next focusable stack on this display is returned.
- *
- * @param considerKeyguardState Indicates whether the locked state should be considered. if
- * {@code true} and the keyguard is locked, only activities that
- * can be shown on top of the keyguard will be considered.
- * @return The top running activity. {@code null} if none is available.
- */
- ActivityRecord topRunningActivity(boolean considerKeyguardState) {
- ActivityRecord topRunning = null;
- final ActivityStack focusedStack = getFocusedStack();
- if (focusedStack != null) {
- topRunning = focusedStack.topRunningActivity();
- }
-
- // Look in other focusable stacks.
- if (topRunning == null) {
- for (int i = getStackCount() - 1; i >= 0; --i) {
- final ActivityStack stack = getStackAt(i);
- // Only consider focusable stacks other than the current focused one.
- if (stack == focusedStack || !stack.isFocusable()) {
- continue;
- }
- topRunning = stack.topRunningActivity();
- if (topRunning != null) {
- break;
- }
- }
- }
-
- // This activity can be considered the top running activity if we are not considering
- // the locked state, the keyguard isn't locked, or we can show when locked.
- if (topRunning != null && considerKeyguardState
- && mRootActivityContainer.mStackSupervisor.getKeyguardController().isKeyguardLocked()
- && !topRunning.canShowWhenLocked()) {
- return null;
- }
-
- return topRunning;
- }
-
- boolean updateDisplayOverrideConfigurationLocked() {
- Configuration values = new Configuration();
- computeScreenConfiguration(values);
-
- mAtmService.mH.sendMessage(PooledLambda.obtainMessage(
- ActivityManagerInternal::updateOomLevelsForDisplay, mAtmService.mAmInternal,
- mDisplayId));
-
- Settings.System.clearConfiguration(values);
- updateDisplayOverrideConfigurationLocked(values, null /* starting */,
- false /* deferResume */, mAtmService.mTmpUpdateConfigurationResult);
- return mAtmService.mTmpUpdateConfigurationResult.changes != 0;
- }
-
- /**
- * Updates override configuration specific for the selected display. If no config is provided,
- * new one will be computed in WM based on current display info.
- */
- boolean updateDisplayOverrideConfigurationLocked(Configuration values,
- ActivityRecord starting, boolean deferResume,
- ActivityTaskManagerService.UpdateConfigurationResult result) {
-
- int changes = 0;
- boolean kept = true;
-
- mAtmService.deferWindowLayout();
- try {
- if (values != null) {
- if (mDisplayId == DEFAULT_DISPLAY) {
- // Override configuration of the default display duplicates global config, so
- // we're calling global config update instead for default display. It will also
- // apply the correct override config.
- changes = mAtmService.updateGlobalConfigurationLocked(values,
- false /* initLocale */, false /* persistent */,
- UserHandle.USER_NULL /* userId */, deferResume);
- } else {
- changes = performDisplayOverrideConfigUpdate(values, deferResume);
- }
- }
-
- kept = mAtmService.ensureConfigAndVisibilityAfterUpdate(starting, changes);
- } finally {
- mAtmService.continueWindowLayout();
- }
-
- if (result != null) {
- result.changes = changes;
- result.activityRelaunched = !kept;
- }
- return kept;
- }
-
- int performDisplayOverrideConfigUpdate(Configuration values, boolean deferResume) {
- mTempConfig.setTo(getRequestedOverrideConfiguration());
- final int changes = mTempConfig.updateFrom(values);
- if (changes != 0) {
- Slog.i(TAG, "Override config changes=" + Integer.toHexString(changes) + " "
- + mTempConfig + " for displayId=" + mDisplayId);
- onRequestedOverrideConfigurationChanged(mTempConfig);
-
- final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0;
- if (isDensityChange && mDisplayId == DEFAULT_DISPLAY) {
- mAtmService.mAppWarnings.onDensityChanged();
-
- // Post message to start process to avoid possible deadlock of calling into AMS with
- // the ATMS lock held.
- final Message msg = PooledLambda.obtainMessage(
- ActivityManagerInternal::killAllBackgroundProcessesExcept,
- mAtmService.mAmInternal, N,
- ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
- mAtmService.mH.sendMessage(msg);
- }
- mWmService.mDisplayNotificationController.dispatchDisplayChanged(
- this, getConfiguration());
- }
- return changes;
- }
-
- @Override
- public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
- final int currRotation =
- getRequestedOverrideConfiguration().windowConfiguration.getRotation();
- if (currRotation != ROTATION_UNDEFINED
- && currRotation != overrideConfiguration.windowConfiguration.getRotation()) {
- applyRotationLocked(currRotation,
- overrideConfiguration.windowConfiguration.getRotation());
- }
- super.onRequestedOverrideConfigurationChanged(overrideConfiguration);
- mWmService.setNewDisplayOverrideConfiguration(overrideConfiguration, this);
- mAtmService.addWindowLayoutReasons(
- ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED);
- }
-
- @Override
- public void onConfigurationChanged(Configuration newParentConfig) {
- // update resources before cascade so that docked/pinned stacks use the correct info
- preOnConfigurationChanged();
- super.onConfigurationChanged(newParentConfig);
- }
-
- /** Checks whether the given activity is in size compatibility mode and notifies the change. */
- void handleActivitySizeCompatModeIfNeeded(ActivityRecord r) {
- if (!r.isState(RESUMED) || r.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
- // The callback is only interested in the foreground changes of fullscreen activity.
- return;
- }
- if (!r.inSizeCompatMode()) {
- if (mLastCompatModeActivity != null) {
- mAtmService.getTaskChangeNotificationController()
- .notifySizeCompatModeActivityChanged(mDisplayId, null /* activityToken */);
- }
- mLastCompatModeActivity = null;
- return;
- }
- if (mLastCompatModeActivity == r) {
- return;
- }
- mLastCompatModeActivity = r;
- mAtmService.getTaskChangeNotificationController()
- .notifySizeCompatModeActivityChanged(mDisplayId, r.appToken);
- }
-
- @Override
- public String toString() {
- return "ActivityDisplay={" + mDisplayId + " numStacks=" + getStackCount() + "}";
- }
-
- boolean isPrivate() {
- return (mDisplay.getFlags() & FLAG_PRIVATE) != 0;
- }
-
- boolean isUidPresent(int uid) {
- final PooledPredicate p = PooledLambda.obtainPredicate(
- ActivityRecord::isUid, PooledLambda.__(ActivityRecord.class), uid);
- final boolean isUidPresent = mDisplayContent.getActivity(p) != null;
- p.recycle();
- return isUidPresent;
- }
-
- /**
- * @see #mRemoved
- */
- boolean isRemoved() {
- return mRemoved;
- }
-
- /**
- * @see #mRemoving
- */
- boolean isRemoving() {
- return mRemoving;
- }
-
- void remove() {
- mRemoving = true;
- final boolean destroyContentOnRemoval = shouldDestroyContentOnRemove();
- ActivityStack lastReparentedStack = null;
- mPreferredTopFocusableStack = null;
-
- // Stacks could be reparented from the removed display to other display. While
- // reparenting the last stack of the removed display, the remove display is ready to be
- // released (no more ActivityStack). But, we cannot release it at that moment or the
- // related WindowContainer will also be removed. So, we set display as removed after
- // reparenting stack finished.
- final ActivityDisplay toDisplay = mRootActivityContainer.getDefaultDisplay();
- mRootActivityContainer.mStackSupervisor.beginDeferResume();
- try {
- int numStacks = getStackCount();
- // Keep the order from bottom to top.
- for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
- final ActivityStack stack = getStackAt(stackNdx);
- // Always finish non-standard type stacks.
- if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) {
- stack.finishAllActivitiesImmediately();
- } else {
- // If default display is in split-window mode, set windowing mode of the stack
- // to split-screen secondary. Otherwise, set the windowing mode to undefined by
- // default to let stack inherited the windowing mode from the new display.
- final int windowingMode = toDisplay.hasSplitScreenPrimaryStack()
- ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
- : WINDOWING_MODE_UNDEFINED;
- stack.reparent(toDisplay, true /* onTop */);
- stack.setWindowingMode(windowingMode);
- lastReparentedStack = stack;
- }
- // Stacks may be removed from this display. Ensure each stack will be processed and
- // the loop will end.
- stackNdx -= numStacks - getStackCount();
- numStacks = getStackCount();
- }
- } finally {
- mRootActivityContainer.mStackSupervisor.endDeferResume();
- }
- mRemoved = true;
-
- // Only update focus/visibility for the last one because there may be many stacks are
- // reparented and the intermediate states are unnecessary.
- if (lastReparentedStack != null) {
- lastReparentedStack.postReparent();
- }
- releaseSelfIfNeeded();
-
- if (!mAllSleepTokens.isEmpty()) {
- mRootActivityContainer.mSleepTokens.removeAll(mAllSleepTokens);
- mAllSleepTokens.clear();
- mAtmService.updateSleepIfNeededLocked();
- }
- }
-
- private void releaseSelfIfNeeded() {
- if (!mRemoved) {
- return;
- }
-
- final ActivityStack stack = getStackCount() == 1 ? getStackAt(0) : null;
- if (stack != null && stack.isActivityTypeHome() && !stack.hasChild()) {
- // Release this display if an empty home stack is the only thing left.
- // Since it is the last stack, this display will be released along with the stack
- // removal.
- stack.removeIfPossible();
- } else if (getTopStack() == null) {
- removeIfPossible();
- mRootActivityContainer.removeChild(this);
- mRootActivityContainer.mStackSupervisor
- .getKeyguardController().onDisplayRemoved(mDisplayId);
- }
- }
-
- /** Update and get all UIDs that are present on the display and have access to it. */
- IntArray getPresentUIDs() {
- mDisplayAccessUIDs.clear();
- final PooledConsumer c = PooledLambda.obtainConsumer(ActivityDisplay::addActivityUid,
- PooledLambda.__(ActivityRecord.class), mDisplayAccessUIDs);
- mDisplayContent.forAllActivities(c);
- c.recycle();
- return mDisplayAccessUIDs;
- }
-
- private static void addActivityUid(ActivityRecord r, IntArray uids) {
- uids.add(r.getUid());
- }
-
- @VisibleForTesting
- boolean shouldDestroyContentOnRemove() {
- return mDisplay.getRemoveMode() == REMOVE_MODE_DESTROY_CONTENT;
- }
-
- boolean shouldSleep() {
- return (getStackCount() == 0 || !mAllSleepTokens.isEmpty())
- && (mAtmService.mRunningVoice == null);
- }
-
- void setFocusedApp(ActivityRecord r, boolean moveFocusNow) {
- final ActivityRecord newFocus;
- final IBinder token = r.appToken;
- if (token == null) {
- ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Clearing focused app, displayId=%d",
- mDisplayId);
- newFocus = null;
- } else {
- newFocus = mWmService.mRoot.getActivityRecord(token);
- if (newFocus == null) {
- Slog.w(TAG_WM, "Attempted to set focus to non-existing app token: " + token
- + ", displayId=" + mDisplayId);
- }
- ProtoLog.v(WM_DEBUG_FOCUS_LIGHT,
- "Set focused app to: %s moveFocusNow=%b displayId=%d", newFocus,
- moveFocusNow, mDisplayId);
- }
-
- final boolean changed = setFocusedApp(newFocus);
- if (moveFocusNow && changed) {
- mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
- true /*updateInputWindows*/);
- }
- }
-
- /**
- * @return the stack currently above the {@param stack}. Can be null if the {@param stack} is
- * already top-most.
- */
- ActivityStack getStackAbove(ActivityStack stack) {
- final int stackIndex = getIndexOf(stack) + 1;
- return (stackIndex < getStackCount()) ? getStackAt(stackIndex) : null;
- }
-
- /**
- * Adjusts the {@param stack} behind the last visible stack in the display if necessary.
- * Generally used in conjunction with {@link #moveStackBehindStack}.
- */
- void moveStackBehindBottomMostVisibleStack(ActivityStack stack) {
- if (stack.shouldBeVisible(null)) {
- // Skip if the stack is already visible
- return;
- }
-
- // Move the stack to the bottom to not affect the following visibility checks
- positionStackAtBottom(stack);
-
- // Find the next position where the stack should be placed
- final int numStacks = getStackCount();
- for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
- final ActivityStack s = getStackAt(stackNdx);
- if (s == stack) {
- continue;
- }
- final int winMode = s.getWindowingMode();
- final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN ||
- winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
- if (s.shouldBeVisible(null) && isValidWindowingMode) {
- // Move the provided stack to behind this stack
- positionStackAt(stack, Math.max(0, stackNdx - 1));
- break;
- }
- }
- }
-
- /**
- * Moves the {@param stack} behind the given {@param behindStack} if possible. If
- * {@param behindStack} is not currently in the display, then then the stack is moved to the
- * back. Generally used in conjunction with {@link #moveStackBehindBottomMostVisibleStack}.
- */
- void moveStackBehindStack(ActivityStack stack, ActivityStack behindStack) {
- if (behindStack == null || behindStack == stack) {
- return;
- }
-
- // Note that positionChildAt will first remove the given stack before inserting into the
- // list, so we need to adjust the insertion index to account for the removed index
- // TODO: Remove this logic when WindowContainer.positionChildAt() is updated to adjust the
- // position internally
- final int stackIndex = getIndexOf(stack);
- final int behindStackIndex = getIndexOf(behindStack);
- final int insertIndex = stackIndex <= behindStackIndex
- ? behindStackIndex - 1 : behindStackIndex;
- positionStackAt(stack, Math.max(0, insertIndex));
- }
-
- void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
- boolean preserveWindows, boolean notifyClients) {
- for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = getStackAt(stackNdx);
- stack.ensureActivitiesVisible(starting, configChanges, preserveWindows,
- notifyClients);
- }
- }
-
- void moveHomeStackToFront(String reason) {
- final ActivityStack homeStack = getHomeStack();
- if (homeStack != null) {
- homeStack.moveToFront(reason);
- }
- }
-
- /**
- * Moves the focusable home activity to top. If there is no such activity, the home stack will
- * still move to top.
- */
- void moveHomeActivityToTop(String reason) {
- final ActivityRecord top = getHomeActivity();
- if (top == null) {
- moveHomeStackToFront(reason);
- return;
- }
- top.moveFocusableActivityToTop(reason);
- }
-
- @Nullable
- ActivityRecord getHomeActivity() {
- return getHomeActivityForUser(mRootActivityContainer.mCurrentUser);
- }
-
- @Nullable
- ActivityRecord getHomeActivityForUser(int userId) {
- final ActivityStack homeStack = getHomeStack();
- if (homeStack == null) {
- return null;
- }
-
- final PooledPredicate p = PooledLambda.obtainPredicate(
- ActivityDisplay::isHomeActivityForUser, PooledLambda.__(ActivityRecord.class),
- userId);
- final ActivityRecord r = homeStack.getActivity(p);
- p.recycle();
- return r;
- }
-
- private static boolean isHomeActivityForUser(ActivityRecord r, int userId) {
- return r.isActivityTypeHome() && (userId == UserHandle.USER_ALL || r.mUserId == userId);
- }
-
- boolean isSleeping() {
- return mSleeping;
- }
-
- void setIsSleeping(boolean asleep) {
- mSleeping = asleep;
- }
-
- /**
- * Adds a listener to be notified whenever the stack order in the display changes. Currently
- * only used by the {@link RecentsAnimation} to determine whether to interrupt and cancel the
- * current animation when the system state changes.
- */
- void registerStackOrderChangedListener(OnStackOrderChangedListener listener) {
- if (!mStackOrderChangedCallbacks.contains(listener)) {
- mStackOrderChangedCallbacks.add(listener);
- }
- }
-
- /**
- * Removes a previously registered stack order change listener.
- */
- void unregisterStackOrderChangedListener(OnStackOrderChangedListener listener) {
- mStackOrderChangedCallbacks.remove(listener);
- }
-
- /**
- * Notifies of a stack order change
- * @param stack The stack which triggered the order change
- */
- private void onStackOrderChanged(ActivityStack stack) {
- for (int i = mStackOrderChangedCallbacks.size() - 1; i >= 0; i--) {
- mStackOrderChangedCallbacks.get(i).onStackOrderChanged(stack);
- }
- }
-
- void setDisplayToSingleTaskInstance() {
- final int childCount = getStackCount();
- if (childCount > 1) {
- throw new IllegalArgumentException("Display already has multiple stacks. display="
- + this);
- }
- if (childCount > 0) {
- final ActivityStack stack = getStackAt(0);
- if (stack.getChildCount() > 1) {
- throw new IllegalArgumentException("Display stack already has multiple tasks."
- + " display=" + this + " stack=" + stack);
- }
- }
-
- mSingleTaskInstance = true;
- }
-
- /** Returns true if the display can only contain one task */
- boolean isSingleTaskInstance() {
- return mSingleTaskInstance;
- }
-
- @VisibleForTesting
- void removeAllTasks() {
- mDisplayContent.forAllTasks((t) -> { t.getStack().removeChild(t, "removeAllTasks"); });
- }
-
- public void dump(PrintWriter pw, String prefix) {
- pw.println(prefix + "displayId=" + mDisplayId + " stacks=" + getStackCount()
- + (mSingleTaskInstance ? " mSingleTaskInstance" : ""));
- final String myPrefix = prefix + " ";
- ActivityStack stack = getHomeStack();
- if (stack != null) {
- pw.println(myPrefix + "mHomeStack=" + stack);
- }
- stack = getRecentsStack();
- if (stack != null) {
- pw.println(myPrefix + "mRecentsStack=" + stack);
- }
- stack = getPinnedStack();
- if (stack != null) {
- pw.println(myPrefix + "mPinnedStack=" + stack);
- }
- stack = getSplitScreenPrimaryStack();
- if (stack != null) {
- pw.println(myPrefix + "mSplitScreenPrimaryStack=" + stack);
- }
- if (mPreferredTopFocusableStack != null) {
- pw.println(myPrefix + "mPreferredTopFocusableStack=" + mPreferredTopFocusableStack);
- }
- if (mLastFocusedStack != null) {
- pw.println(myPrefix + "mLastFocusedStack=" + mLastFocusedStack);
- }
- }
-
- public void dumpStacks(PrintWriter pw) {
- for (int i = getStackCount() - 1; i >= 0; --i) {
- pw.print(getStackAt(i).mStackId);
- if (i > 0) {
- pw.print(",");
- }
- }
- }
-
- public void dumpDebug(ProtoOutputStream proto, long fieldId,
- @WindowTraceLogLevel int logLevel) {
- final long token = proto.start(fieldId);
- dumpDebugInner(proto, DISPLAY, logLevel);
- proto.write(ID, mDisplayId);
- proto.write(SINGLE_TASK_INSTANCE, mSingleTaskInstance);
- final ActivityStack focusedStack = getFocusedStack();
- if (focusedStack != null) {
- proto.write(FOCUSED_STACK_ID, focusedStack.mStackId);
- final ActivityRecord focusedActivity = focusedStack.getDisplay().getResumedActivity();
- if (focusedActivity != null) {
- focusedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY);
- }
- } else {
- proto.write(FOCUSED_STACK_ID, INVALID_STACK_ID);
- }
- for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = getStackAt(stackNdx);
- stack.dumpDebug(proto, STACKS, logLevel);
- }
- proto.end(token);
- }
-
- /**
- * Callback for when the order of the stacks in the display changes.
- */
- interface OnStackOrderChangedListener {
- void onStackOrderChanged(ActivityStack stack);
- }
-}
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 20d1d1c..c8357e2 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -190,6 +190,8 @@
final int mTransitionType;
/** Whether the process was already running when the transition started. */
final boolean mProcessRunning;
+ /** whether the process of the launching activity didn't have any active activity. */
+ final boolean mProcessSwitch;
/** The activities that should be drawn. */
final LinkedList<ActivityRecord> mPendingDrawActivities = new LinkedList<>();
/** The latest activity to have been launched. */
@@ -218,7 +220,8 @@
/** @return Non-null if there will be a window drawn event for the launch. */
@Nullable
static TransitionInfo create(@NonNull ActivityRecord r,
- @NonNull LaunchingState launchingState, boolean processRunning, int startResult) {
+ @NonNull LaunchingState launchingState, boolean processRunning,
+ boolean processSwitch, int startResult) {
int transitionType = INVALID_TRANSITION_TYPE;
if (processRunning) {
if (startResult == START_SUCCESS) {
@@ -235,16 +238,18 @@
// That means the startResult is neither START_SUCCESS nor START_TASK_TO_FRONT.
return null;
}
- return new TransitionInfo(r, launchingState, transitionType, processRunning);
+ return new TransitionInfo(r, launchingState, transitionType, processRunning,
+ processSwitch);
}
/** Use {@link TransitionInfo#create} instead to ensure the transition type is valid. */
private TransitionInfo(ActivityRecord r, LaunchingState launchingState, int transitionType,
- boolean processRunning) {
+ boolean processRunning, boolean processSwitch) {
mLaunchingState = launchingState;
mTransitionStartTimeNs = launchingState.mCurrentTransitionStartTimeNs;
mTransitionType = transitionType;
mProcessRunning = processRunning;
+ mProcessSwitch = processSwitch;
mCurrentTransitionDeviceUptime =
(int) TimeUnit.MILLISECONDS.toSeconds(SystemClock.uptimeMillis());
setLatestLaunchedActivity(r);
@@ -282,6 +287,14 @@
return mPendingDrawActivities.isEmpty();
}
+ /**
+ * @return {@code true} if the transition info should be sent to MetricsLogger, StatsLog, or
+ * LaunchObserver.
+ */
+ boolean isInterestingToLoggerAndObserver() {
+ return mProcessSwitch;
+ }
+
int calculateCurrentDelay() {
return calculateDelay(SystemClock.elapsedRealtimeNanos());
}
@@ -540,13 +553,8 @@
return;
}
- if (!processSwitch) {
- abort(info, "not a process switch");
- return;
- }
-
final TransitionInfo newInfo = TransitionInfo.create(launchedActivity, launchingState,
- processRunning, resultCode);
+ processRunning, processSwitch, resultCode);
if (newInfo == null) {
abort(info, "unrecognized launch");
return;
@@ -557,7 +565,12 @@
mTransitionInfoList.add(newInfo);
mLastTransitionInfo.put(launchedActivity, newInfo);
startLaunchTrace(newInfo);
- launchObserverNotifyActivityLaunched(newInfo);
+ if (newInfo.isInterestingToLoggerAndObserver()) {
+ launchObserverNotifyActivityLaunched(newInfo);
+ } else {
+ // As abort for no process switch.
+ launchObserverNotifyIntentFailed();
+ }
}
/**
@@ -733,7 +746,9 @@
launchObserverNotifyActivityLaunchCancelled(info);
} else {
logAppTransitionFinished(info);
- launchObserverNotifyActivityLaunchFinished(info, timestampNs);
+ if (info.isInterestingToLoggerAndObserver()) {
+ launchObserverNotifyActivityLaunchFinished(info, timestampNs);
+ }
}
info.mPendingDrawActivities.clear();
mTransitionInfoList.remove(info);
@@ -768,8 +783,11 @@
// Take a snapshot of the transition info before sending it to the handler for logging.
// This will avoid any races with other operations that modify the ActivityRecord.
final TransitionInfoSnapshot infoSnapshot = new TransitionInfoSnapshot(info);
- BackgroundThread.getHandler().post(() -> logAppTransition(
- info.mCurrentTransitionDeviceUptime, info.mCurrentTransitionDelayMs, infoSnapshot));
+ if (info.isInterestingToLoggerAndObserver()) {
+ BackgroundThread.getHandler().post(() -> logAppTransition(
+ info.mCurrentTransitionDeviceUptime, info.mCurrentTransitionDelayMs,
+ infoSnapshot));
+ }
BackgroundThread.getHandler().post(() -> logAppDisplayed(infoSnapshot));
if (info.mPendingFullyDrawn != null) {
info.mPendingFullyDrawn.run();
@@ -905,6 +923,18 @@
return null;
}
+ final long currentTimestampNs = SystemClock.elapsedRealtimeNanos();
+ final long startupTimeMs = info.mPendingFullyDrawn != null
+ ? info.mWindowsDrawnDelayMs
+ : TimeUnit.NANOSECONDS.toMillis(currentTimestampNs - info.mTransitionStartTimeNs);
+ final TransitionInfoSnapshot infoSnapshot =
+ new TransitionInfoSnapshot(info, r, (int) startupTimeMs);
+ BackgroundThread.getHandler().post(() -> logAppFullyDrawn(infoSnapshot));
+
+ if (!info.isInterestingToLoggerAndObserver()) {
+ return infoSnapshot;
+ }
+
// Record the handling of the reportFullyDrawn callback in the trace system. This is not
// actually used to trace this function, but instead the logical task that this function
// fullfils (handling reportFullyDrawn() callbacks).
@@ -914,10 +944,6 @@
final LogMaker builder = new LogMaker(APP_TRANSITION_REPORTED_DRAWN);
builder.setPackageName(r.packageName);
builder.addTaggedData(FIELD_CLASS_NAME, r.info.name);
- final long currentTimestampNs = SystemClock.elapsedRealtimeNanos();
- final long startupTimeMs = info.mPendingFullyDrawn != null
- ? info.mWindowsDrawnDelayMs
- : TimeUnit.NANOSECONDS.toMillis(currentTimestampNs - info.mTransitionStartTimeNs);
builder.addTaggedData(APP_TRANSITION_REPORTED_DRAWN_MS, startupTimeMs);
builder.setType(restoredFromBundle
? TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE
@@ -940,10 +966,6 @@
// the trace slice to have a noticable duration.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- final TransitionInfoSnapshot infoSnapshot =
- new TransitionInfoSnapshot(info, r, (int) startupTimeMs);
- BackgroundThread.getHandler().post(() -> logAppFullyDrawn(infoSnapshot));
-
// Notify reportFullyDrawn event.
launchObserverNotifyReportFullyDrawn(r, currentTimestampNs);
@@ -1069,7 +1091,8 @@
return;
}
info.mLaunchTraceName = "launching: " + info.mLastLaunchedActivity.packageName;
- Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, info.mLaunchTraceName, 0);
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, info.mLaunchTraceName,
+ (int) info.mTransitionStartTimeNs /* cookie */);
}
/** Stops trace for the launch is completed or cancelled. */
@@ -1078,7 +1101,8 @@
if (info.mLaunchTraceName == null) {
return;
}
- Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, info.mLaunchTraceName, 0);
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, info.mLaunchTraceName,
+ (int) info.mTransitionStartTimeNs /* cookie */);
info.mLaunchTraceName = null;
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 5d9fb8a..6de9dbd 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1640,6 +1640,17 @@
allowTaskSnapshot, activityCreated, fromRecents, snapshot);
if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
+ if (isActivityTypeHome()) {
+ // The snapshot of home is only used once because it won't be updated while screen
+ // is on (see {@link TaskSnapshotController#screenTurningOff}).
+ mWmService.mTaskSnapshotController.removeSnapshotCache(task.mTaskId);
+ // TODO(b/9684093): Use more general condition to specify the case.
+ if (mDisplayContent.mAppTransition
+ .getAppTransition() != WindowManager.TRANSIT_KEYGUARD_GOING_AWAY) {
+ // Only use snapshot of home as starting window when unlocking.
+ return false;
+ }
+ }
return createSnapshot(snapshot);
}
@@ -1991,7 +2002,7 @@
return getActivityStack() != null ? getActivityStack().mStackId : INVALID_STACK_ID;
}
- ActivityDisplay getDisplay() {
+ DisplayContent getDisplay() {
final ActivityStack stack = getActivityStack();
return stack != null ? stack.getDisplay() : null;
}
@@ -2148,7 +2159,7 @@
boolean isKeyguardLocked = mAtmService.isKeyguardLocked();
boolean isCurrentAppLocked =
mAtmService.getLockTaskModeState() != LOCK_TASK_MODE_NONE;
- final ActivityDisplay display = getDisplay();
+ final DisplayContent display = getDisplay();
boolean hasPinnedStack = display != null && display.hasPinnedStack();
// Don't return early if !isNotLocked, since we want to throw an exception if the activity
// is in an incorrect state
@@ -2417,7 +2428,7 @@
stack.adjustFocusToNextFocusableStack("finish-top");
} else {
// Only move the next stack to top in its display.
- final ActivityDisplay display = stack.getDisplay();
+ final DisplayContent display = stack.getDisplay();
next = display.topRunningActivity();
if (next != null) {
display.positionStackAtTop(next.getActivityStack(),
@@ -2591,9 +2602,9 @@
mStackSupervisor.mGoingToSleepActivities.remove(this);
final ActivityStack stack = getActivityStack();
- final ActivityDisplay display = getDisplay();
+ final DisplayContent display = getDisplay();
// TODO(b/137329632): Exclude current activity when looking for the next one with
- // ActivityDisplay#topRunningActivity().
+ // DisplayContent#topRunningActivity().
final ActivityRecord next = display.topRunningActivity();
final boolean isLastStackOverEmptyHome =
next == null && stack.isFocusedStackOnDisplay() && display.getHomeStack() != null;
@@ -4660,7 +4671,7 @@
}
r.setSavedState(null /* savedState */);
- final ActivityDisplay display = r.getDisplay();
+ final DisplayContent display = r.getDisplay();
if (display != null) {
display.handleActivitySizeCompatModeIfNeeded(r);
}
@@ -6257,7 +6268,7 @@
}
// The role of CompatDisplayInsets is like the override bounds.
- final ActivityDisplay display = getDisplay();
+ final DisplayContent display = getDisplay();
if (display != null) {
mCompatDisplayInsets = new CompatDisplayInsets(display.mDisplayContent,
getWindowConfiguration().getBounds(),
@@ -6527,7 +6538,7 @@
onMergedOverrideConfigurationChanged();
}
- final ActivityDisplay display = getDisplay();
+ final DisplayContent display = getDisplay();
if (display == null) {
return;
}
@@ -7276,7 +7287,7 @@
* otherwise.
*/
boolean isResumedActivityOnDisplay() {
- final ActivityDisplay display = getDisplay();
+ final DisplayContent display = getDisplay();
return display != null && this == display.getResumedActivity();
}
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index eb1f638..677d2a1 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -131,8 +131,6 @@
import android.app.IActivityController;
import android.app.RemoteAction;
import android.app.ResultInfo;
-import android.app.WindowConfiguration.ActivityType;
-import android.app.WindowConfiguration.WindowingMode;
import android.app.servertransaction.ActivityResultItem;
import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.NewIntentItem;
@@ -144,7 +142,6 @@
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
-import android.graphics.Region;
import android.os.Binder;
import android.os.Debug;
import android.os.Handler;
@@ -154,9 +151,7 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
-import android.os.UserHandle;
import android.service.voice.IVoiceInteractionSession;
-import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Slog;
@@ -732,7 +727,7 @@
}
}
- ActivityStack(ActivityDisplay display, int stackId, ActivityStackSupervisor supervisor,
+ ActivityStack(DisplayContent display, int stackId, ActivityStackSupervisor supervisor,
int windowingMode, int activityType, boolean onTop) {
super(supervisor.mService.mWindowManager);
mStackId = stackId;
@@ -816,7 +811,7 @@
}
}
- final ActivityDisplay display = getDisplay();
+ final DisplayContent display = getDisplay();
if (display == null ) {
return;
}
@@ -946,7 +941,7 @@
boolean creating) {
final int currentMode = getWindowingMode();
final int currentOverrideMode = getRequestedOverrideWindowingMode();
- final ActivityDisplay display = getDisplay();
+ final DisplayContent display = getDisplay();
final Task topTask = getTopMostTask();
final ActivityStack splitScreenStack = display.getSplitScreenPrimaryStack();
int windowingMode = preferredWindowingMode;
@@ -1116,8 +1111,8 @@
!PRESERVE_WINDOWS);
}
- ActivityDisplay getDisplay() {
- return mRootActivityContainer.getActivityDisplay(mDisplayId);
+ DisplayContent getDisplay() {
+ return getDisplayContent();
}
/**
@@ -1250,7 +1245,7 @@
/** @return true if the stack can only contain one task */
boolean isSingleTaskInstance() {
- final ActivityDisplay display = getDisplay();
+ final DisplayContent display = getDisplay();
return display != null && display.isSingleTaskInstance();
}
@@ -1291,7 +1286,7 @@
return;
}
- final ActivityDisplay display = getDisplay();
+ final DisplayContent display = getDisplay();
if (inSplitScreenSecondaryWindowingMode()) {
// If the stack is in split-screen seconardy mode, we need to make sure we move the
@@ -1358,7 +1353,7 @@
@Override
public boolean isAttached() {
- final ActivityDisplay display = getDisplay();
+ final DisplayContent display = getDisplay();
return display != null && !display.isRemoved();
}
@@ -1777,7 +1772,7 @@
}
boolean isTopStackOnDisplay() {
- final ActivityDisplay display = getDisplay();
+ final DisplayContent display = getDisplay();
return display != null && display.isTopStack(this);
}
@@ -1786,7 +1781,7 @@
* otherwise.
*/
boolean isFocusedStackOnDisplay() {
- final ActivityDisplay display = getDisplay();
+ final DisplayContent display = getDisplay();
return display != null && this == display.getFocusedStack();
}
@@ -1815,7 +1810,7 @@
return STACK_VISIBILITY_INVISIBLE;
}
- final ActivityDisplay display = getDisplay();
+ final DisplayContent display = getDisplay();
boolean gotSplitScreenStack = false;
boolean gotOpaqueSplitScreenPrimary = false;
boolean gotOpaqueSplitScreenSecondary = false;
@@ -2049,13 +2044,13 @@
* {@link Display#FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD} applied.
*/
boolean canShowWithInsecureKeyguard() {
- final ActivityDisplay activityDisplay = getDisplay();
- if (activityDisplay == null) {
+ final DisplayContent displayContent = getDisplay();
+ if (displayContent == null) {
throw new IllegalStateException("Stack is not attached to any display, stackId="
+ mStackId);
}
- final int flags = activityDisplay.mDisplay.getFlags();
+ final int flags = displayContent.mDisplay.getFlags();
return (flags & FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0;
}
@@ -2224,7 +2219,7 @@
}
next.delayedResume = false;
- final ActivityDisplay display = getDisplay();
+ final DisplayContent display = getDisplay();
// If the top activity is the resumed one, nothing to do.
if (mResumedActivity == next && next.isState(RESUMED)
@@ -2966,7 +2961,7 @@
/** @return true if the stack behind this one is a standard activity type. */
private boolean inFrontOfStandardStack() {
- final ActivityDisplay display = getDisplay();
+ final DisplayContent display = getDisplay();
if (display == null) {
return false;
}
@@ -3665,7 +3660,7 @@
return;
}
- final ActivityDisplay display = getDisplay();
+ final DisplayContent display = getDisplay();
final boolean topFocused = mRootActivityContainer.isTopDisplayFocusedStack(this);
if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "removeChild: task=" + child);
@@ -3693,7 +3688,7 @@
}
void moveHomeStackToFrontIfNeeded(
- boolean wasTopFocusedStack, ActivityDisplay display, String reason) {
+ boolean wasTopFocusedStack, DisplayContent display, String reason) {
if (!hasChild() && wasTopFocusedStack) {
// We only need to adjust focused stack if this stack is in focus and we are not in the
// process of moving the task to the top of the stack that will be focused.
@@ -3790,11 +3785,11 @@
return;
}
super.setAlwaysOnTop(alwaysOnTop);
- final ActivityDisplay display = getDisplay();
+ final DisplayContent display = getDisplay();
// positionChildAtTop() must be called even when always on top gets turned off because we
// need to make sure that the stack is moved from among always on top windows to below other
// always on top windows. Since the position the stack should be inserted into is calculated
- // properly in {@link ActivityDisplay#getTopInsertPosition()} in both cases, we can just
+ // properly in {@link DisplayContent#getTopInsertPosition()} in both cases, we can just
// request that the stack is put at top here.
display.positionStackAtTop(this, false /* includingParents */);
}
@@ -4352,11 +4347,10 @@
@Override
protected void onParentChanged(
ConfigurationContainer newParent, ConfigurationContainer oldParent) {
- // TODO(display-merge): Remove cast
- final ActivityDisplay display = newParent != null
- ? (ActivityDisplay) ((WindowContainer) newParent).getDisplayContent() : null;
- final ActivityDisplay oldDisplay = oldParent != null
- ? (ActivityDisplay) ((WindowContainer) oldParent).getDisplayContent() : null;
+ final DisplayContent display = newParent != null
+ ? ((WindowContainer) newParent).getDisplayContent() : null;
+ final DisplayContent oldDisplay = oldParent != null
+ ? ((WindowContainer) oldParent).getDisplayContent() : null;
mDisplayId = (display != null) ? display.mDisplayId : INVALID_DISPLAY;
mPrevDisplayId = (oldDisplay != null) ? oldDisplay.mDisplayId : INVALID_DISPLAY;
@@ -5408,7 +5402,7 @@
}
boolean shouldSleepActivities() {
- final ActivityDisplay display = getDisplay();
+ final DisplayContent display = getDisplay();
// Do not sleep activities in this stack if we're marked as focused and the keyguard
// is in the process of going away.
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 8c5fd8c..43dce73 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -401,12 +401,12 @@
private final MoveTaskToFullscreenHelper mMoveTaskToFullscreenHelper =
new MoveTaskToFullscreenHelper();
private class MoveTaskToFullscreenHelper {
- private ActivityDisplay mToDisplay;
+ private DisplayContent mToDisplay;
private boolean mOnTop;
private Task mTopTask;
private boolean mSchedulePictureInPictureModeChange;
- void process(ActivityStack fromStack, ActivityDisplay toDisplay, boolean onTop,
+ void process(ActivityStack fromStack, DisplayContent toDisplay, boolean onTop,
boolean schedulePictureInPictureModeChange) {
mSchedulePictureInPictureModeChange = schedulePictureInPictureModeChange;
mToDisplay = toDisplay;
@@ -1122,9 +1122,9 @@
return true;
}
- final ActivityDisplay activityDisplay =
- mRootActivityContainer.getActivityDisplayOrCreate(launchDisplayId);
- if (activityDisplay == null || activityDisplay.isRemoved()) {
+ final DisplayContent displayContent =
+ mRootActivityContainer.getDisplayContentOrCreate(launchDisplayId);
+ if (displayContent == null || displayContent.isRemoved()) {
Slog.w(TAG, "Launch on display check: display not found");
return false;
}
@@ -1140,10 +1140,10 @@
}
// Check if caller is already present on display
- final boolean uidPresentOnDisplay = activityDisplay.isUidPresent(callingUid);
+ final boolean uidPresentOnDisplay = displayContent.isUidPresent(callingUid);
- final int displayOwnerUid = activityDisplay.mDisplay.getOwnerUid();
- if (activityDisplay.mDisplay.getType() == TYPE_VIRTUAL && displayOwnerUid != SYSTEM_UID
+ final int displayOwnerUid = displayContent.mDisplay.getOwnerUid();
+ if (displayContent.mDisplay.getType() == TYPE_VIRTUAL && displayOwnerUid != SYSTEM_UID
&& displayOwnerUid != aInfo.applicationInfo.uid) {
// Limit launching on virtual displays, because their contents can be read from Surface
// by apps that created them.
@@ -1161,7 +1161,7 @@
}
}
- if (!activityDisplay.isPrivate()) {
+ if (!displayContent.isPrivate()) {
// Anyone can launch on a public display.
if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
+ " allow launch on public display");
@@ -1482,7 +1482,7 @@
currentStack, forceNonResizeable);
}
- private void moveHomeStackToFrontIfNeeded(int flags, ActivityDisplay display, String reason) {
+ private void moveHomeStackToFrontIfNeeded(int flags, DisplayContent display, String reason) {
final ActivityStack focusedStack = display.getFocusedStack();
if ((display.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
@@ -1542,8 +1542,8 @@
mService.deferWindowLayout();
try {
final int windowingMode = fromStack.getWindowingMode();
- final ActivityDisplay toDisplay =
- mRootActivityContainer.getActivityDisplay(toDisplayId);
+ final DisplayContent toDisplay =
+ mRootActivityContainer.getDisplayContent(toDisplayId);
if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
// We are moving all tasks from the docked stack to the fullscreen stack,
@@ -1668,7 +1668,7 @@
// static stacks need to be adjusted so they don't overlap with the docked stack.
// We get the bounds to use from window manager which has been adjusted for any
// screen controls and is also the same for all stacks.
- final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+ final DisplayContent display = mRootActivityContainer.getDefaultDisplay();
final Rect otherTaskRect = new Rect();
for (int i = display.getStackCount() - 1; i >= 0; --i) {
final ActivityStack current = display.getStackAt(i);
@@ -1934,7 +1934,7 @@
* Returns the reparent target stack, creating the stack if necessary. This call also enforces
* the various checks on tasks that are going to be reparented from one stack to another.
*/
- // TODO: Look into changing users to this method to ActivityDisplay.resolveWindowingMode()
+ // TODO: Look into changing users to this method to DisplayContent.resolveWindowingMode()
ActivityStack getReparentTargetStack(Task task, ActivityStack stack, boolean toTop) {
final ActivityStack prevStack = task.getStack();
final int stackId = stack.mStackId;
@@ -2426,8 +2426,8 @@
throw new IllegalStateException("Task resolved to incompatible display");
}
- final ActivityDisplay preferredDisplay =
- mRootActivityContainer.getActivityDisplay(preferredDisplayId);
+ final DisplayContent preferredDisplay =
+ mRootActivityContainer.getDisplayContent(preferredDisplayId);
final boolean singleTaskInstance = preferredDisplay != null
&& preferredDisplay.isSingleTaskInstance();
@@ -2818,7 +2818,7 @@
// call this at the end to make sure that tasks exists on the window manager side.
setResizingDuringAnimation(task);
- final ActivityDisplay display = task.getStack().getDisplay();
+ final DisplayContent display = task.getStack().getDisplay();
final ActivityStack topSecondaryStack =
display.getTopStackInWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
if (topSecondaryStack.isActivityTypeHome()) {
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 695f58c..4c165df 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -43,6 +43,7 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import android.view.RemoteAnimationAdapter;
@@ -180,8 +181,8 @@
}
options.setLaunchDisplayId(displayId);
- final ActivityDisplay display =
- mService.mRootActivityContainer.getActivityDisplay(displayId);
+ final DisplayContent display =
+ mService.mRootActivityContainer.getDisplayContent(displayId);
// The home activity will be started later, defer resuming to avoid unneccerary operations
// (e.g. start home recursively) when creating home stack.
mSupervisor.beginDeferResume();
@@ -385,6 +386,7 @@
} else {
callingPid = callingUid = -1;
}
+ final SparseArray<String> startingUidPkgs = new SparseArray<>();
final long origId = Binder.clearCallingIdentity();
try {
intents = ArrayUtils.filterNotNull(intents, Intent[]::new);
@@ -411,9 +413,14 @@
callingUid, realCallingUid, UserHandle.USER_NULL));
aInfo = mService.mAmInternal.getActivityInfoForUser(aInfo, userId);
- if (aInfo != null && (aInfo.applicationInfo.privateFlags
- & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
- throw new IllegalArgumentException("FLAG_CANT_SAVE_STATE not supported here");
+ if (aInfo != null) {
+ if ((aInfo.applicationInfo.privateFlags
+ & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
+ throw new IllegalArgumentException(
+ "FLAG_CANT_SAVE_STATE not supported here");
+ }
+ startingUidPkgs.put(aInfo.applicationInfo.uid,
+ aInfo.applicationInfo.packageName);
}
final boolean top = i == intents.length - 1;
@@ -439,6 +446,16 @@
.setOriginatingPendingIntent(originatingPendingIntent)
.setAllowBackgroundActivityStart(allowBackgroundActivityStart);
}
+ // Log if the activities to be started have different uids.
+ if (startingUidPkgs.size() > 1) {
+ final StringBuilder sb = new StringBuilder("startActivities: different apps [");
+ final int size = startingUidPkgs.size();
+ for (int i = 0; i < size; i++) {
+ sb.append(startingUidPkgs.valueAt(i)).append(i == size - 1 ? "]" : ", ");
+ }
+ sb.append(" from ").append(callingPackage);
+ Slog.wtf(TAG, sb.toString());
+ }
final ActivityRecord[] outActivity = new ActivityRecord[1];
// Lock the loop to ensure the activities launched in a sequence.
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 46c4d87..f0bc412 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -2038,7 +2038,7 @@
}
@Override
- public int getActivityDisplayId(IBinder activityToken) throws RemoteException {
+ public int getDisplayId(IBinder activityToken) throws RemoteException {
synchronized (mGlobalLock) {
final ActivityStack stack = ActivityRecord.getStackLocked(activityToken);
if (stack != null && stack.mDisplayId != INVALID_DISPLAY) {
@@ -4572,6 +4572,17 @@
}
}
+ @Override
+ public void invalidateHomeTaskSnapshot(IBinder token) {
+ synchronized (mGlobalLock) {
+ final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+ if (r == null || !r.isActivityTypeHome()) {
+ return;
+ }
+ mWindowManager.mTaskSnapshotController.removeSnapshotCache(r.getTask().mTaskId);
+ }
+ }
+
/** Return the user id of the last resumed activity. */
@Override
public @UserIdInt
@@ -4691,7 +4702,7 @@
"registerRemoteAnimations");
definition.setCallingPidUid(Binder.getCallingPid(), Binder.getCallingUid());
synchronized (mGlobalLock) {
- final ActivityDisplay display = mRootActivityContainer.getActivityDisplay(displayId);
+ final DisplayContent display = mRootActivityContainer.getDisplayContent(displayId);
if (display == null) {
Slog.e(TAG, "Couldn't find display with id: " + displayId);
return;
@@ -4899,8 +4910,8 @@
"setDisplayToSingleTaskInstance");
final long origId = Binder.clearCallingIdentity();
try {
- final ActivityDisplay display =
- mRootActivityContainer.getActivityDisplayOrCreate(displayId);
+ final DisplayContent display =
+ mRootActivityContainer.getDisplayContentOrCreate(displayId);
if (display != null) {
display.setDisplayToSingleTaskInstance();
}
@@ -5198,8 +5209,8 @@
int updateGlobalConfigurationLocked(@NonNull Configuration values, boolean initLocale,
boolean persistent, int userId, boolean deferResume) {
- final ActivityDisplay defaultDisplay =
- mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY);
+ final DisplayContent defaultDisplay =
+ mRootActivityContainer.getDisplayContent(DEFAULT_DISPLAY);
mTempConfig.setTo(getGlobalConfiguration());
final int changes = mTempConfig.updateFrom(values);
@@ -6205,12 +6216,12 @@
// We might change the visibilities here, so prepare an empty app transition which
// might be overridden later if we actually change visibilities.
- final ActivityDisplay activityDisplay =
- mRootActivityContainer.getActivityDisplay(displayId);
- if (activityDisplay == null) {
+ final DisplayContent displayContent =
+ mRootActivityContainer.getDisplayContent(displayId);
+ if (displayContent == null) {
return;
}
- final DisplayContent dc = activityDisplay.mDisplayContent;
+ final DisplayContent dc = displayContent.mDisplayContent;
final boolean wasTransitionSet =
dc.mAppTransition.getAppTransition() != TRANSIT_NONE;
if (!wasTransitionSet) {
@@ -6557,9 +6568,9 @@
return;
}
synchronized (mGlobalLock) {
- final ActivityDisplay activityDisplay =
- mRootActivityContainer.getActivityDisplay(displayId);
- if (activityDisplay == null) {
+ final DisplayContent displayContent =
+ mRootActivityContainer.getDisplayContent(displayId);
+ if (displayContent == null) {
// Call might come when display is not yet added or has been removed.
if (DEBUG_CONFIGURATION) {
Slog.w(TAG, "Trying to update display configuration for non-existing "
@@ -6576,7 +6587,7 @@
return;
}
process.mIsImeProcess = true;
- process.registerDisplayConfigurationListenerLocked(activityDisplay);
+ process.registerDisplayConfigurationListenerLocked(displayContent);
}
}
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index bd0ea3d..dd3365c 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -384,7 +384,6 @@
* When you call this function, make sure that the following functions are called as well to
* keep proper z-order.
* - {@Link DisplayContent#positionStackAt(POSITION_TOP, TaskStack)};
- * - {@Link ActivityDisplay#positionChildAtTop(ActivityStack)};
* */
public void setAlwaysOnTop(boolean alwaysOnTop) {
mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration());
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 9e5734b..e3ea2c5 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -16,24 +16,33 @@
package com.android.server.wm;
+import static android.app.ActivityTaskManager.INVALID_STACK_ID;
import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.os.Build.VERSION_CODES.N;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.util.DisplayMetrics.DENSITY_DEFAULT;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.FLAG_PRIVATE;
import static android.view.Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
import static android.view.Display.INVALID_DISPLAY;
+import static android.view.Display.REMOVE_MODE_DESTROY_CONTENT;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_LEFT_GESTURES;
import static android.view.InsetsState.ITYPE_RIGHT_GESTURES;
@@ -75,10 +84,20 @@
import static android.view.WindowManager.TRANSIT_TASK_OPEN;
import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
+import static com.android.server.am.ActivityDisplayProto.DISPLAY;
+import static com.android.server.am.ActivityDisplayProto.FOCUSED_STACK_ID;
+import static com.android.server.am.ActivityDisplayProto.RESUMED_ACTIVITY;
+import static com.android.server.am.ActivityDisplayProto.SINGLE_TASK_INSTANCE;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
+import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
+import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK;
import static com.android.server.wm.DisplayContentProto.ABOVE_APP_WINDOWS;
import static com.android.server.wm.DisplayContentProto.APP_TRANSITION;
import static com.android.server.wm.DisplayContentProto.BELOW_APP_WINDOWS;
@@ -105,6 +124,7 @@
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_SCREEN_ON;
import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
+import static com.android.server.wm.RootActivityContainer.TAG_STATES;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
@@ -124,6 +144,7 @@
import static com.android.server.wm.WindowManagerService.H.WINDOW_HIDE_TIMEOUT;
import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
import static com.android.server.wm.WindowManagerService.SEAMLESS_ROTATION_TIMEOUT_DURATION;
+import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_REMOVING_FOCUS;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_ASSIGN_LAYERS;
@@ -141,6 +162,11 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
+import android.app.ActivityOptions;
+import android.app.WindowConfiguration;
+import android.content.pm.ActivityInfo;
import android.content.pm.ActivityInfo.ScreenOrientation;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
@@ -158,14 +184,17 @@
import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Message;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
+import android.provider.Settings;
import android.util.ArraySet;
import android.util.DisplayMetrics;
+import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -198,6 +227,7 @@
import com.android.internal.util.function.pooled.PooledConsumer;
import com.android.internal.util.function.pooled.PooledFunction;
import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.util.function.pooled.PooledPredicate;
import com.android.server.AnimationThread;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.protolog.common.ProtoLog;
@@ -225,6 +255,7 @@
class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowContainer>
implements WindowManagerPolicy.DisplayContentInfo {
private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayContent" : TAG_WM;
+ private static final String TAG_STACK = TAG + POSTFIX_STACK;
/** The default scaling mode that scales content automatically. */
static final int FORCE_SCALING_MODE_AUTO = 0;
@@ -241,7 +272,7 @@
ActivityTaskManagerService mAtmService;
/** Unique identifier of this display. */
- private final int mDisplayId;
+ final int mDisplayId;
/**
* Most surfaces will be a child of this window. There are some special layers and windows
@@ -330,8 +361,8 @@
* @see WindowManagerService#setForcedDisplayScalingMode(int, int)
*/
boolean mDisplayScalingDisabled;
+ final Display mDisplay;
private final DisplayInfo mDisplayInfo = new DisplayInfo();
- private final Display mDisplay;
private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
private final DisplayPolicy mDisplayPolicy;
private final DisplayRotation mDisplayRotation;
@@ -567,6 +598,72 @@
private final SparseArray<ShellRoot> mShellRoots = new SparseArray<>();
+ /**
+ * Counter for next free stack ID to use for dynamic activity stacks. Unique across displays.
+ */
+ private static int sNextFreeStackId = 0;
+
+ private RootActivityContainer mRootActivityContainer;
+
+ /**
+ * All of the stacks on this display. Order matters, topmost stack is in front of all other
+ * stacks, bottommost behind. Accessed directly by ActivityManager package classes. Any calls
+ * changing the list should also call {@link #onStackOrderChanged()}.
+ */
+ private ArrayList<OnStackOrderChangedListener> mStackOrderChangedCallbacks = new ArrayList<>();
+
+ /** Array of all UIDs that are present on the display. */
+ private IntArray mDisplayAccessUIDs = new IntArray();
+
+ /** All tokens used to put activities on this stack to sleep (including mOffToken) */
+ final ArrayList<ActivityTaskManagerInternal.SleepToken> mAllSleepTokens = new ArrayList<>();
+ /** The token acquired by ActivityStackSupervisor to put stacks on the display to sleep */
+ ActivityTaskManagerInternal.SleepToken mOffToken;
+
+ private boolean mSleeping;
+
+ /** We started the process of removing the display from the system. */
+ private boolean mRemoving;
+
+ /**
+ * The display is removed from the system and we are just waiting for all activities on it to be
+ * finished before removing this object.
+ */
+ private boolean mRemoved;
+
+ /** The display can only contain one task. */
+ private boolean mSingleTaskInstance;
+
+ /**
+ * Non-null if the last size compatibility mode activity is using non-native screen
+ * configuration. The activity is not able to put in multi-window mode, so it exists only one
+ * per display.
+ */
+ private ActivityRecord mLastCompatModeActivity;
+
+ /**
+ * A focusable stack that is purposely to be positioned at the top. Although the stack may not
+ * have the topmost index, it is used as a preferred candidate to prevent being unable to resume
+ * target stack properly when there are other focusable always-on-top stacks.
+ */
+ private ActivityStack mPreferredTopFocusableStack;
+
+ /**
+ * If this is the same as {@link #getFocusedStack} then the activity on the top of the focused
+ * stack has been resumed. If stacks are changing position this will hold the old stack until
+ * the new stack becomes resumed after which it will be set to current focused stack.
+ */
+ private ActivityStack mLastFocusedStack;
+
+ // Used in updating the display size
+ private Point mTmpDisplaySize = new Point();
+
+ // Used in updating override configurations
+ private final Configuration mTempConfig = new Configuration();
+
+ private final RootActivityContainer.FindTaskResult
+ mTmpFindTaskResult = new RootActivityContainer.FindTaskResult();
+
private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> {
WindowStateAnimator winAnimator = w.mWinAnimator;
final ActivityRecord activity = w.mActivityRecord;
@@ -846,17 +943,18 @@
* Create new {@link DisplayContent} instance, add itself to the root window container and
* initialize direct children.
* @param display May not be null.
- * @param service You know.
- * @param activityDisplay The ActivityDisplay for the display container.
+ * @param root {@link RootActivityContainer}
*/
- DisplayContent(Display display, WindowManagerService service) {
- super(service);
- if (service.mRoot.getDisplayContent(display.getDisplayId()) != null) {
+ DisplayContent(Display display, RootActivityContainer root) {
+ super(root.mWindowManager);
+ if (mWmService.mRoot.getDisplayContent(display.getDisplayId()) != null) {
throw new IllegalArgumentException("Display with ID=" + display.getDisplayId()
- + " already exists=" + service.mRoot.getDisplayContent(display.getDisplayId())
+ + " already exists="
+ + mWmService.mRoot.getDisplayContent(display.getDisplayId())
+ " new=" + display);
}
+ mRootActivityContainer = root;
mAtmService = mWmService.mAtmService;
mDisplay = display;
mDisplayId = display.getDisplayId();
@@ -870,13 +968,13 @@
calculateDisplayCutoutForRotation(mDisplayInfo.rotation));
initializeDisplayBaseInfo();
- mAppTransition = new AppTransition(service.mContext, service, this);
- mAppTransition.registerListenerLocked(service.mActivityManagerAppTransitionNotifier);
- mAppTransitionController = new AppTransitionController(service, this);
- mUnknownAppVisibilityController = new UnknownAppVisibilityController(service, this);
+ mAppTransition = new AppTransition(mWmService.mContext, mWmService, this);
+ mAppTransition.registerListenerLocked(mWmService.mActivityManagerAppTransitionNotifier);
+ mAppTransitionController = new AppTransitionController(mWmService, this);
+ mUnknownAppVisibilityController = new UnknownAppVisibilityController(mWmService, this);
AnimationHandler animationHandler = new AnimationHandler();
- mBoundsAnimationController = new BoundsAnimationController(service.mContext,
+ mBoundsAnimationController = new BoundsAnimationController(mWmService.mContext,
mAppTransition, AnimationThread.getHandler(), animationHandler);
final InputChannel inputChannel = mWmService.mInputManager.monitorInput(
@@ -894,9 +992,9 @@
mWmService.mAtmService.getRecentTasks().getInputListener());
}
- mDisplayPolicy = new DisplayPolicy(service, this);
- mDisplayRotation = new DisplayRotation(service, this);
- mCloseToSquareMaxAspectRatio = service.mContext.getResources().getFloat(
+ mDisplayPolicy = new DisplayPolicy(mWmService, this);
+ mDisplayRotation = new DisplayRotation(mWmService, this);
+ mCloseToSquareMaxAspectRatio = mWmService.mContext.getResources().getFloat(
com.android.internal.R.dimen.config_closeToSquareDisplayMaxAspectRatio);
if (isDefaultDisplay) {
// The policy may be invoked right after here, so it requires the necessary default
@@ -910,8 +1008,8 @@
mDisplayPolicy.systemReady();
}
mWindowCornerRadius = mDisplayPolicy.getWindowCornerRadius();
- mDividerControllerLocked = new DockedStackDividerController(service, this);
- mPinnedStackControllerLocked = new PinnedStackController(service, this);
+ mDividerControllerLocked = new DockedStackDividerController(mWmService, this);
+ mPinnedStackControllerLocked = new PinnedStackController(mWmService, this);
final SurfaceControl.Builder b = mWmService.makeSurfaceBuilder(mSession)
.setOpaque(true)
@@ -941,9 +1039,23 @@
mDisplayReady = true;
mWmService.mAnimator.addDisplayLocked(mDisplayId);
- mInputMonitor = new InputMonitor(service, mDisplayId);
+ mInputMonitor = new InputMonitor(mWmService, mDisplayId);
mInsetsStateController = new InsetsStateController(this);
mInsetsPolicy = new InsetsPolicy(mInsetsStateController, this);
+
+ if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Adding display=" + display);
+
+ mWmService.mDisplayWindowSettings.applySettingsToDisplayLocked(this);
+
+ if (mWmService.mDisplayManagerInternal != null) {
+ mWmService.mDisplayManagerInternal
+ .setDisplayInfoOverrideFromWindowManager(mDisplayId, getDisplayInfo());
+ configureDisplayPolicy();
+ }
+
+ reconfigureDisplayLocked();
+ onRequestedOverrideConfigurationChanged(getRequestedOverrideConfiguration());
+ mWmService.mDisplayNotificationController.dispatchDisplayAdded(this);
}
boolean isReady() {
@@ -1189,9 +1301,7 @@
if (mDisplayRotation.isWaitingForRemoteRotation()) {
return;
}
- // TODO(display-merge): Remove cast
- final boolean configUpdated =
- ((ActivityDisplay) this).updateDisplayOverrideConfigurationLocked();
+ final boolean configUpdated = updateDisplayOverrideConfigurationLocked();
if (configUpdated) {
return;
}
@@ -1222,9 +1332,8 @@
if (handled && requestingContainer instanceof ActivityRecord) {
final ActivityRecord activityRecord = (ActivityRecord) requestingContainer;
- // TODO(display-merge): Remove cast
- final boolean kept = ((ActivityDisplay) this).updateDisplayOverrideConfigurationLocked(
- config, activityRecord, false /* deferResume */, null /* result */);
+ final boolean kept = updateDisplayOverrideConfigurationLocked(config, activityRecord,
+ false /* deferResume */, null /* result */);
activityRecord.frozenBeforeDestroy = true;
if (!kept) {
mWmService.mAtmService.mRootActivityContainer.resumeFocusedStacksTopActivities();
@@ -1232,9 +1341,8 @@
} else {
// We have a new configuration to push so we need to update ATMS for now.
// TODO: Clean up display configuration push between ATMS and WMS after unification.
- // TODO(display-merge): Remove cast
- ((ActivityDisplay) this.mDisplayContent).updateDisplayOverrideConfigurationLocked(
- config, null /* starting */, false /* deferResume */, null);
+ updateDisplayOverrideConfigurationLocked(config, null /* starting */,
+ false /* deferResume */, null);
}
return handled;
}
@@ -1915,15 +2023,9 @@
}
@Override
- public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
- mCurrentOverrideConfigurationChanges =
- getRequestedOverrideConfiguration().diff(overrideConfiguration);
- super.onRequestedOverrideConfigurationChanged(overrideConfiguration);
- mCurrentOverrideConfigurationChanges = 0;
- }
-
- @Override
public void onConfigurationChanged(Configuration newParentConfig) {
+ // update resources before cascade so that docked/pinned stacks use the correct info
+ preOnConfigurationChanged();
final int lastOrientation = getConfiguration().orientation;
super.onConfigurationChanged(newParentConfig);
if (mDisplayPolicy != null) {
@@ -1947,8 +2049,7 @@
/**
* Updates the resources used by docked/pinned controllers. This needs to be called at the
* beginning of a configuration update cascade since the metrics from these resources are used
- * for bounds calculations. Since ActivityDisplay initiates the configuration update, this
- * should be called from there instead of DisplayContent's onConfigurationChanged.
+ * for bounds calculations.
*/
void preOnConfigurationChanged() {
final DockedStackDividerController dividerController = getDockedDividerController();
@@ -2430,9 +2531,7 @@
setRotationAnimation(null);
mWmService.mAnimator.removeDisplayLocked(mDisplayId);
mInputMonitor.onDisplayRemoved();
- // TODO(display-merge): Remove cast
- mWmService.mDisplayNotificationController
- .dispatchDisplayRemoved((ActivityDisplay) this);
+ mWmService.mDisplayNotificationController.dispatchDisplayRemoved(this);
} finally {
mDisplayReady = false;
mRemovingDisplay = false;
@@ -2645,6 +2744,29 @@
}
}
+ public void dumpDebug(ProtoOutputStream proto, long fieldId,
+ @WindowTraceLogLevel int logLevel) {
+ final long token = proto.start(fieldId);
+ dumpDebugInner(proto, DISPLAY, logLevel);
+ proto.write(com.android.server.am.ActivityDisplayProto.ID, mDisplayId);
+ proto.write(SINGLE_TASK_INSTANCE, mSingleTaskInstance);
+ final ActivityStack focusedStack = getFocusedStack();
+ if (focusedStack != null) {
+ proto.write(FOCUSED_STACK_ID, focusedStack.mStackId);
+ final ActivityRecord focusedActivity = focusedStack.getDisplay().getResumedActivity();
+ if (focusedActivity != null) {
+ focusedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY);
+ }
+ } else {
+ proto.write(FOCUSED_STACK_ID, INVALID_STACK_ID);
+ }
+ for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+ final ActivityStack stack = getStackAt(stackNdx);
+ stack.dumpDebug(proto, com.android.server.am.ActivityDisplayProto.STACKS, logLevel);
+ }
+ proto.end(token);
+ }
+
// TODO(proto-merge): Remove once protos for ActivityDisplay and DisplayContent are merged.
public void dumpDebugInner(ProtoOutputStream proto, long fieldId,
@WindowTraceLogLevel int logLevel) {
@@ -2705,7 +2827,9 @@
@Override
public void dump(PrintWriter pw, String prefix, boolean dumpAll) {
super.dump(pw, prefix, dumpAll);
- pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId);
+ pw.print(prefix);
+ pw.println("Display: mDisplayId=" + mDisplayId + " stacks=" + getStackCount() + (
+ mSingleTaskInstance ? " mSingleTaskInstance" : ""));
final String subPrefix = " " + prefix;
pw.print(subPrefix); pw.print("init="); pw.print(mInitialDisplayWidth); pw.print("x");
pw.print(mInitialDisplayHeight); pw.print(" "); pw.print(mInitialDisplayDensity);
@@ -2741,6 +2865,12 @@
if (mLastFocus != mCurrentFocus) {
pw.print(" mLastFocus="); pw.println(mLastFocus);
}
+ if (mPreferredTopFocusableStack != null) {
+ pw.println(prefix + "mPreferredTopFocusableStack=" + mPreferredTopFocusableStack);
+ }
+ if (mLastFocusedStack != null) {
+ pw.println(prefix + "mLastFocusedStack=" + mLastFocusedStack);
+ }
if (mLosingFocus.size() > 0) {
pw.println();
pw.println(" Windows losing focus:");
@@ -2818,6 +2948,10 @@
if (splitScreenPrimaryStack != null) {
pw.println(prefix + "splitScreenPrimaryStack=" + splitScreenPrimaryStack.getName());
}
+ final ActivityStack recentsStack = getRecentsStack();
+ if (recentsStack != null) {
+ pw.println(prefix + "recentsStack=" + recentsStack.getName());
+ }
pw.println();
mDividerControllerLocked.dump(prefix, pw);
@@ -4103,8 +4237,7 @@
+ " already exist on display=" + this + " stack=" + stack);
}
mSplitScreenPrimaryStack = stack;
- // TODO(display-merge): Remove cast
- ((ActivityDisplay) this.mDisplayContent).onSplitScreenModeActivated();
+ mDisplayContent.onSplitScreenModeActivated();
mDividerControllerLocked.notifyDockedStackExistsChanged(true);
}
}
@@ -4118,8 +4251,7 @@
mPinnedStack = null;
} else if (stack == mSplitScreenPrimaryStack) {
mSplitScreenPrimaryStack = null;
- // TODO(display-merge): Remove cast
- ((ActivityDisplay) this.mDisplayContent).onSplitScreenModeDismissed();
+ mDisplayContent.onSplitScreenModeDismissed();
// Re-set the split-screen create mode whenever the split-screen stack is removed.
mWmService.setDockedStackCreateStateLocked(
SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, null /* initialBounds */);
@@ -4144,8 +4276,7 @@
@Override
protected void removeChild(ActivityStack stack) {
super.removeChild(stack);
- // TODO(display-merge): Remove cast
- ((ActivityDisplay) this.mDisplayContent).onStackRemoved(stack);
+ mDisplayContent.onStackRemoved(stack);
removeStackReferenceIfNeeded(stack);
}
@@ -5377,4 +5508,1132 @@
}
return mMetricsLogger;
}
+
+ void onDisplayChanged() {
+ // The window policy is responsible for stopping activities on the default display.
+ final int displayId = mDisplay.getDisplayId();
+ if (displayId != DEFAULT_DISPLAY) {
+ final int displayState = mDisplay.getState();
+ if (displayState == Display.STATE_OFF && mOffToken == null) {
+ mOffToken = mAtmService.acquireSleepToken("Display-off", displayId);
+ } else if (displayState == Display.STATE_ON && mOffToken != null) {
+ mOffToken.release();
+ mOffToken = null;
+ }
+ }
+
+ mDisplay.getRealSize(mTmpDisplaySize);
+ setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y);
+ updateDisplayInfo();
+ mWmService.requestTraversal();
+ }
+
+ void addStack(ActivityStack stack, int position) {
+ setStackOnDisplay(stack, position);
+ positionStackAt(stack, position);
+ mAtmService.updateSleepIfNeededLocked();
+ }
+
+ void onStackRemoved(ActivityStack stack) {
+ if (ActivityTaskManagerDebugConfig.DEBUG_STACK) {
+ Slog.v(TAG_STACK, "removeStack: detaching " + stack + " from displayId=" + mDisplayId);
+ }
+ if (mPreferredTopFocusableStack == stack) {
+ mPreferredTopFocusableStack = null;
+ }
+ releaseSelfIfNeeded();
+ mAtmService.updateSleepIfNeededLocked();
+ onStackOrderChanged(stack);
+ }
+
+ void positionStackAtTop(ActivityStack stack, boolean includingParents) {
+ positionStackAtTop(stack, includingParents, null /* updateLastFocusedStackReason */);
+ }
+
+ void positionStackAtTop(ActivityStack stack, boolean includingParents,
+ String updateLastFocusedStackReason) {
+ positionStackAt(stack, getStackCount(), includingParents, updateLastFocusedStackReason);
+ }
+
+ void positionStackAtBottom(ActivityStack stack) {
+ positionStackAtBottom(stack, null /* updateLastFocusedStackReason */);
+ }
+
+ void positionStackAtBottom(ActivityStack stack, String updateLastFocusedStackReason) {
+ positionStackAt(stack, 0, false /* includingParents */, updateLastFocusedStackReason);
+ }
+
+ private void positionStackAt(ActivityStack stack, int position) {
+ positionStackAt(stack, position, false /* includingParents */,
+ null /* updateLastFocusedStackReason */);
+ }
+
+ private void positionStackAt(ActivityStack stack, int position, boolean includingParents,
+ String updateLastFocusedStackReason) {
+ // TODO: Keep in sync with WindowContainer.positionChildAt(), once we change that to adjust
+ // the position internally, also update the logic here
+ final ActivityStack prevFocusedStack = updateLastFocusedStackReason != null
+ ? getFocusedStack() : null;
+ final boolean wasContained = getIndexOf(stack) >= 0;
+ if (mSingleTaskInstance && getStackCount() == 1 && !wasContained) {
+ throw new IllegalStateException(
+ "positionStackAt: Can only have one task on display=" + this);
+ }
+
+ // Since positionChildAt() is called during the creation process of pinned stacks,
+ // ActivityStack#getStack() can be null.
+ positionStackAt(position, stack, includingParents);
+
+ // The insert position may be adjusted to non-top when there is always-on-top stack. Since
+ // the original position is preferred to be top, the stack should have higher priority when
+ // we are looking for top focusable stack. The condition {@code wasContained} restricts the
+ // preferred stack is set only when moving an existing stack to top instead of adding a new
+ // stack that may be too early (e.g. in the middle of launching or reparenting).
+ if (wasContained && position >= getStackCount() - 1 && stack.isFocusableAndVisible()) {
+ mPreferredTopFocusableStack = stack;
+ } else if (mPreferredTopFocusableStack == stack) {
+ mPreferredTopFocusableStack = null;
+ }
+
+ if (updateLastFocusedStackReason != null) {
+ final ActivityStack currentFocusedStack = getFocusedStack();
+ if (currentFocusedStack != prevFocusedStack) {
+ mLastFocusedStack = prevFocusedStack;
+ EventLogTags.writeWmFocusedStack(mRootActivityContainer.mCurrentUser, mDisplayId,
+ currentFocusedStack == null ? -1 : currentFocusedStack.getStackId(),
+ mLastFocusedStack == null ? -1 : mLastFocusedStack.getStackId(),
+ updateLastFocusedStackReason);
+ }
+ }
+
+ onStackOrderChanged(stack);
+ }
+
+ ActivityStack getStack(int stackId) {
+ for (int i = getStackCount() - 1; i >= 0; --i) {
+ final ActivityStack stack = getStackAt(i);
+ if (stack.mStackId == stackId) {
+ return stack;
+ }
+ }
+ return null;
+ }
+
+ boolean alwaysCreateStack(int windowingMode, int activityType) {
+ // Always create a stack for fullscreen, freeform, and split-screen-secondary windowing
+ // modes so that we can manage visual ordering and return types correctly.
+ return activityType == ACTIVITY_TYPE_STANDARD
+ && (windowingMode == WINDOWING_MODE_FULLSCREEN
+ || windowingMode == WINDOWING_MODE_FREEFORM
+ || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ }
+
+ /**
+ * Returns an existing stack compatible with the windowing mode and activity type or creates one
+ * if a compatible stack doesn't exist.
+ * @see #getStack(int, int)
+ * @see #createStack(int, int, boolean)
+ */
+ ActivityStack getOrCreateStack(int windowingMode, int activityType,
+ boolean onTop) {
+ if (!alwaysCreateStack(windowingMode, activityType)) {
+ ActivityStack stack = getStack(windowingMode, activityType);
+ if (stack != null) {
+ return stack;
+ }
+ }
+ return createStack(windowingMode, activityType, onTop);
+ }
+
+ /**
+ * Returns an existing stack compatible with the input params or creates one
+ * if a compatible stack doesn't exist.
+ * @see #getOrCreateStack(int, int, boolean)
+ */
+ ActivityStack getOrCreateStack(@Nullable ActivityRecord r,
+ @Nullable ActivityOptions options, @Nullable Task candidateTask, int activityType,
+ boolean onTop) {
+ // First preference is the windowing mode in the activity options if set.
+ int windowingMode = (options != null)
+ ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
+ // Validate that our desired windowingMode will work under the current conditions.
+ // UNDEFINED windowing mode is a valid result and means that the new stack will inherit
+ // it's display's windowing mode.
+ windowingMode = validateWindowingMode(windowingMode, r, candidateTask, activityType);
+ return getOrCreateStack(windowingMode, activityType, onTop);
+ }
+
+ @VisibleForTesting
+ int getNextStackId() {
+ return sNextFreeStackId++;
+ }
+
+ /**
+ * Creates a stack matching the input windowing mode and activity type on this display.
+ * @param windowingMode The windowing mode the stack should be created in. If
+ * {@link WindowConfiguration#WINDOWING_MODE_UNDEFINED} then the stack will
+ * inherit its parent's windowing mode.
+ * @param activityType The activityType the stack should be created in. If
+ * {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} then the stack will
+ * be created in {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
+ * @param onTop If true the stack will be created at the top of the display, else at the bottom.
+ * @return The newly created stack.
+ */
+ ActivityStack createStack(int windowingMode, int activityType, boolean onTop) {
+ if (mSingleTaskInstance && getStackCount() > 0) {
+ // Create stack on default display instead since this display can only contain 1 stack.
+ // TODO: Kinda a hack, but better that having the decision at each call point. Hoping
+ // this goes away once ActivityView is no longer using virtual displays.
+ return mRootActivityContainer.getDefaultDisplay().createStack(
+ windowingMode, activityType, onTop);
+ }
+
+ if (activityType == ACTIVITY_TYPE_UNDEFINED) {
+ // Can't have an undefined stack type yet...so re-map to standard. Anyone that wants
+ // anything else should be passing it in anyways...
+ activityType = ACTIVITY_TYPE_STANDARD;
+ }
+
+ if (activityType != ACTIVITY_TYPE_STANDARD) {
+ // For now there can be only one stack of a particular non-standard activity type on a
+ // display. So, get that ignoring whatever windowing mode it is currently in.
+ ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
+ if (stack != null) {
+ throw new IllegalArgumentException("Stack=" + stack + " of activityType="
+ + activityType + " already on display=" + this + ". Can't have multiple.");
+ }
+ }
+
+ if (!isWindowingModeSupported(windowingMode, mAtmService.mSupportsMultiWindow,
+ mAtmService.mSupportsSplitScreenMultiWindow,
+ mAtmService.mSupportsFreeformWindowManagement,
+ mAtmService.mSupportsPictureInPicture, activityType)) {
+ throw new IllegalArgumentException("Can't create stack for unsupported windowingMode="
+ + windowingMode);
+ }
+
+ final int stackId = getNextStackId();
+ return createStackUnchecked(windowingMode, activityType, stackId, onTop);
+ }
+
+ @VisibleForTesting
+ ActivityStack createStackUnchecked(int windowingMode, int activityType,
+ int stackId, boolean onTop) {
+ if (windowingMode == WINDOWING_MODE_PINNED && activityType != ACTIVITY_TYPE_STANDARD) {
+ throw new IllegalArgumentException("Stack with windowing mode cannot with non standard "
+ + "activity type.");
+ }
+ return new ActivityStack(this, stackId, mRootActivityContainer.mStackSupervisor,
+ windowingMode, activityType, onTop);
+ }
+
+ /**
+ * Get the preferred focusable stack in priority. If the preferred stack does not exist, find a
+ * focusable and visible stack from the top of stacks in this display.
+ */
+ ActivityStack getFocusedStack() {
+ if (mPreferredTopFocusableStack != null) {
+ return mPreferredTopFocusableStack;
+ }
+
+ for (int i = getStackCount() - 1; i >= 0; --i) {
+ final ActivityStack stack = getStackAt(i);
+ if (stack.isFocusableAndVisible()) {
+ return stack;
+ }
+ }
+
+ return null;
+ }
+
+ ActivityStack getNextFocusableStack(ActivityStack currentFocus, boolean ignoreCurrent) {
+ final int currentWindowingMode = currentFocus != null
+ ? currentFocus.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
+
+ ActivityStack candidate = null;
+ for (int i = getStackCount() - 1; i >= 0; --i) {
+ final ActivityStack stack = getStackAt(i);
+ if (ignoreCurrent && stack == currentFocus) {
+ continue;
+ }
+ if (!stack.isFocusableAndVisible()) {
+ continue;
+ }
+
+ if (currentWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
+ && candidate == null && stack.inSplitScreenPrimaryWindowingMode()) {
+ // If the currently focused stack is in split-screen secondary we save off the
+ // top primary split-screen stack as a candidate for focus because we might
+ // prefer focus to move to an other stack to avoid primary split-screen stack
+ // overlapping with a fullscreen stack when a fullscreen stack is higher in z
+ // than the next split-screen stack. Assistant stack, I am looking at you...
+ // We only move the focus to the primary-split screen stack if there isn't a
+ // better alternative.
+ candidate = stack;
+ continue;
+ }
+ if (candidate != null && stack.inSplitScreenSecondaryWindowingMode()) {
+ // Use the candidate stack since we are now at the secondary split-screen.
+ return candidate;
+ }
+ return stack;
+ }
+ return candidate;
+ }
+
+ ActivityRecord getResumedActivity() {
+ final ActivityStack focusedStack = getFocusedStack();
+ if (focusedStack == null) {
+ return null;
+ }
+ // TODO(b/111541062): Move this into ActivityStack#getResumedActivity()
+ // Check if the focused stack has the resumed activity
+ ActivityRecord resumedActivity = focusedStack.getResumedActivity();
+ if (resumedActivity == null || resumedActivity.app == null) {
+ // If there is no registered resumed activity in the stack or it is not running -
+ // try to use previously resumed one.
+ resumedActivity = focusedStack.mPausingActivity;
+ if (resumedActivity == null || resumedActivity.app == null) {
+ // If previously resumed activity doesn't work either - find the topmost running
+ // activity that can be focused.
+ resumedActivity = focusedStack.topRunningActivity(true /* focusableOnly */);
+ }
+ }
+ return resumedActivity;
+ }
+
+ ActivityStack getLastFocusedStack() {
+ return mLastFocusedStack;
+ }
+
+ boolean allResumedActivitiesComplete() {
+ for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+ final ActivityRecord r = getStackAt(stackNdx).getResumedActivity();
+ if (r != null && !r.isState(RESUMED)) {
+ return false;
+ }
+ }
+ final ActivityStack currentFocusedStack = getFocusedStack();
+ if (ActivityTaskManagerDebugConfig.DEBUG_STACK) {
+ Slog.d(TAG_STACK, "allResumedActivitiesComplete: mLastFocusedStack changing from="
+ + mLastFocusedStack + " to=" + currentFocusedStack);
+ }
+ mLastFocusedStack = currentFocusedStack;
+ return true;
+ }
+
+ /**
+ * Pause all activities in either all of the stacks or just the back stacks. This is done before
+ * resuming a new activity and to make sure that previously active activities are
+ * paused in stacks that are no longer visible or in pinned windowing mode. This does not
+ * pause activities in visible stacks, so if an activity is launched within the same stack/task,
+ * then we should explicitly pause that stack's top activity.
+ * @param userLeaving Passed to pauseActivity() to indicate whether to call onUserLeaving().
+ * @param resuming The resuming activity.
+ * @return {@code true} if any activity was paused as a result of this call.
+ */
+ boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming) {
+ boolean someActivityPaused = false;
+ for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+ final ActivityStack stack = getStackAt(stackNdx);
+ final ActivityRecord resumedActivity = stack.getResumedActivity();
+ if (resumedActivity != null
+ && (stack.getVisibility(resuming) != STACK_VISIBILITY_VISIBLE
+ || !stack.isFocusable())) {
+ if (DEBUG_STATES) Slog.d(TAG_STATES, "pauseBackStacks: stack=" + stack
+ + " mResumedActivity=" + resumedActivity);
+ someActivityPaused |= stack.startPausingLocked(userLeaving, false /* uiSleeping*/,
+ resuming);
+ }
+ }
+ return someActivityPaused;
+ }
+
+ /**
+ * Find task for putting the Activity in.
+ */
+ void findTaskLocked(final ActivityRecord r, final boolean isPreferredDisplay,
+ RootActivityContainer.FindTaskResult result) {
+ mTmpFindTaskResult.clear();
+ for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+ final ActivityStack stack = getStackAt(stackNdx);
+ if (!r.hasCompatibleActivityType(stack)) {
+ if (DEBUG_TASKS) {
+ Slog.d(TAG_TASKS, "Skipping stack: (mismatch activity/stack) " + stack);
+ }
+ continue;
+ }
+
+ mTmpFindTaskResult.process(r, stack);
+ // It is possible to have tasks in multiple stacks with the same root affinity, so
+ // we should keep looking after finding an affinity match to see if there is a
+ // better match in another stack. Also, task affinity isn't a good enough reason
+ // to target a display which isn't the source of the intent, so skip any affinity
+ // matches not on the specified display.
+ if (mTmpFindTaskResult.mRecord != null) {
+ if (mTmpFindTaskResult.mIdealMatch) {
+ result.setTo(mTmpFindTaskResult);
+ return;
+ } else if (isPreferredDisplay) {
+ // Note: since the traversing through the stacks is top down, the floating
+ // tasks should always have lower priority than any affinity-matching tasks
+ // in the fullscreen stacks
+ result.setTo(mTmpFindTaskResult);
+ }
+ }
+ }
+ }
+
+ /**
+ * Removes stacks in the input windowing modes from the system if they are of activity type
+ * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
+ */
+ void removeStacksInWindowingModes(int... windowingModes) {
+ if (windowingModes == null || windowingModes.length == 0) {
+ return;
+ }
+
+ // Collect the stacks that are necessary to be removed instead of performing the removal
+ // by looping mStacks, so that we don't miss any stacks after the stack size changed or
+ // stacks reordered.
+ final ArrayList<ActivityStack> stacks = new ArrayList<>();
+ for (int j = windowingModes.length - 1; j >= 0; --j) {
+ final int windowingMode = windowingModes[j];
+ for (int i = getStackCount() - 1; i >= 0; --i) {
+ final ActivityStack stack = getStackAt(i);
+ if (!stack.isActivityTypeStandardOrUndefined()) {
+ continue;
+ }
+ if (stack.getWindowingMode() != windowingMode) {
+ continue;
+ }
+ stacks.add(stack);
+ }
+ }
+
+ for (int i = stacks.size() - 1; i >= 0; --i) {
+ mRootActivityContainer.mStackSupervisor.removeStack(stacks.get(i));
+ }
+ }
+
+ void removeStacksWithActivityTypes(int... activityTypes) {
+ if (activityTypes == null || activityTypes.length == 0) {
+ return;
+ }
+
+ // Collect the stacks that are necessary to be removed instead of performing the removal
+ // by looping mStacks, so that we don't miss any stacks after the stack size changed or
+ // stacks reordered.
+ final ArrayList<ActivityStack> stacks = new ArrayList<>();
+ for (int j = activityTypes.length - 1; j >= 0; --j) {
+ final int activityType = activityTypes[j];
+ for (int i = getStackCount() - 1; i >= 0; --i) {
+ final ActivityStack stack = getStackAt(i);
+ if (stack.getActivityType() == activityType) {
+ stacks.add(stack);
+ }
+ }
+ }
+
+ for (int i = stacks.size() - 1; i >= 0; --i) {
+ mRootActivityContainer.mStackSupervisor.removeStack(stacks.get(i));
+ }
+ }
+
+ void onSplitScreenModeDismissed() {
+ mAtmService.deferWindowLayout();
+ try {
+ // Adjust the windowing mode of any stack in secondary split-screen to fullscreen.
+ for (int i = getStackCount() - 1; i >= 0; --i) {
+ final ActivityStack otherStack = getStackAt(i);
+ if (!otherStack.inSplitScreenSecondaryWindowingMode()) {
+ continue;
+ }
+ otherStack.setWindowingMode(WINDOWING_MODE_UNDEFINED, false /* animate */,
+ false /* showRecents */, false /* enteringSplitScreenMode */,
+ true /* deferEnsuringVisibility */, false /* creating */);
+ }
+ } finally {
+ final ActivityStack topFullscreenStack =
+ getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ final ActivityStack homeStack = getHomeStack();
+ if (topFullscreenStack != null && homeStack != null && !isTopStack(homeStack)) {
+ // Whenever split-screen is dismissed we want the home stack directly behind the
+ // current top fullscreen stack so it shows up when the top stack is finished.
+ // TODO: Would be better to use ActivityDisplay.positionChildAt() for this, however
+ // ActivityDisplay doesn't have a direct controller to WM side yet. We can switch
+ // once we have that.
+ homeStack.moveToFront("onSplitScreenModeDismissed");
+ topFullscreenStack.moveToFront("onSplitScreenModeDismissed");
+ }
+ mAtmService.continueWindowLayout();
+ }
+ }
+
+ void onSplitScreenModeActivated() {
+ mAtmService.deferWindowLayout();
+ try {
+ // Adjust the windowing mode of any affected by split-screen to split-screen secondary.
+ final ActivityStack splitScreenPrimaryStack = getSplitScreenPrimaryStack();
+ for (int i = getStackCount() - 1; i >= 0; --i) {
+ final ActivityStack otherStack = getStackAt(i);
+ if (otherStack == splitScreenPrimaryStack
+ || !otherStack.affectedBySplitScreenResize()) {
+ continue;
+ }
+ otherStack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
+ false /* animate */, false /* showRecents */,
+ true /* enteringSplitScreenMode */, true /* deferEnsuringVisibility */,
+ false /* creating */);
+ }
+ } finally {
+ mAtmService.continueWindowLayout();
+ }
+ }
+
+ /**
+ * Returns true if the {@param windowingMode} is supported based on other parameters passed in.
+ * @param windowingMode The windowing mode we are checking support for.
+ * @param supportsMultiWindow If we should consider support for multi-window mode in general.
+ * @param supportsSplitScreen If we should consider support for split-screen multi-window.
+ * @param supportsFreeform If we should consider support for freeform multi-window.
+ * @param supportsPip If we should consider support for picture-in-picture mutli-window.
+ * @param activityType The activity type under consideration.
+ * @return true if the windowing mode is supported.
+ */
+ private boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow,
+ boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip,
+ int activityType) {
+
+ if (windowingMode == WINDOWING_MODE_UNDEFINED
+ || windowingMode == WINDOWING_MODE_FULLSCREEN) {
+ return true;
+ }
+ if (!supportsMultiWindow) {
+ return false;
+ }
+
+ final int displayWindowingMode = getWindowingMode();
+ if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+ || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
+ return supportsSplitScreen
+ && WindowConfiguration.supportSplitScreenWindowingMode(activityType)
+ // Freeform windows and split-screen windows don't mix well, so prevent
+ // split windowing modes on freeform displays.
+ && displayWindowingMode != WINDOWING_MODE_FREEFORM;
+ }
+
+ if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) {
+ return false;
+ }
+
+ if (!supportsPip && windowingMode == WINDOWING_MODE_PINNED) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Resolves the windowing mode that an {@link ActivityRecord} would be in if started on this
+ * display with the provided parameters.
+ *
+ * @param r The ActivityRecord in question.
+ * @param options Options to start with.
+ * @param task The task within-which the activity would start.
+ * @param activityType The type of activity to start.
+ * @return The resolved (not UNDEFINED) windowing-mode that the activity would be in.
+ */
+ int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
+ @Nullable Task task, int activityType) {
+
+ // First preference if the windowing mode in the activity options if set.
+ int windowingMode = (options != null)
+ ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
+
+ // If windowing mode is unset, then next preference is the candidate task, then the
+ // activity record.
+ if (windowingMode == WINDOWING_MODE_UNDEFINED) {
+ if (task != null) {
+ windowingMode = task.getWindowingMode();
+ }
+ if (windowingMode == WINDOWING_MODE_UNDEFINED && r != null) {
+ windowingMode = r.getWindowingMode();
+ }
+ if (windowingMode == WINDOWING_MODE_UNDEFINED) {
+ // Use the display's windowing mode.
+ windowingMode = getWindowingMode();
+ }
+ }
+ windowingMode = validateWindowingMode(windowingMode, r, task, activityType);
+ return windowingMode != WINDOWING_MODE_UNDEFINED
+ ? windowingMode : WINDOWING_MODE_FULLSCREEN;
+ }
+
+ /**
+ * Check that the requested windowing-mode is appropriate for the specified task and/or activity
+ * on this display.
+ *
+ * @param windowingMode The windowing-mode to validate.
+ * @param r The {@link ActivityRecord} to check against.
+ * @param task The {@link Task} to check against.
+ * @param activityType An activity type.
+ * @return The provided windowingMode or the closest valid mode which is appropriate.
+ */
+ int validateWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable Task task,
+ int activityType) {
+ // Make sure the windowing mode we are trying to use makes sense for what is supported.
+ boolean supportsMultiWindow = mAtmService.mSupportsMultiWindow;
+ boolean supportsSplitScreen = mAtmService.mSupportsSplitScreenMultiWindow;
+ boolean supportsFreeform = mAtmService.mSupportsFreeformWindowManagement;
+ boolean supportsPip = mAtmService.mSupportsPictureInPicture;
+ if (supportsMultiWindow) {
+ if (task != null) {
+ supportsMultiWindow = task.isResizeable();
+ supportsSplitScreen = task.supportsSplitScreenWindowingMode();
+ // TODO: Do we need to check for freeform and Pip support here?
+ } else if (r != null) {
+ supportsMultiWindow = r.isResizeable();
+ supportsSplitScreen = r.supportsSplitScreenWindowingMode();
+ supportsFreeform = r.supportsFreeform();
+ supportsPip = r.supportsPictureInPicture();
+ }
+ }
+
+ final boolean inSplitScreenMode = hasSplitScreenPrimaryStack();
+ if (!inSplitScreenMode
+ && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) {
+ // Switch to the display's windowing mode if we are not in split-screen mode and we are
+ // trying to launch in split-screen secondary.
+ windowingMode = WINDOWING_MODE_UNDEFINED;
+ } else if (inSplitScreenMode && (windowingMode == WINDOWING_MODE_FULLSCREEN
+ || windowingMode == WINDOWING_MODE_UNDEFINED)
+ && supportsSplitScreen) {
+ windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+ }
+
+ if (windowingMode != WINDOWING_MODE_UNDEFINED
+ && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen,
+ supportsFreeform, supportsPip, activityType)) {
+ return windowingMode;
+ }
+ return WINDOWING_MODE_UNDEFINED;
+ }
+
+ boolean isTopStack(ActivityStack stack) {
+ return stack == getTopStack();
+ }
+
+ boolean isTopNotPinnedStack(ActivityStack stack) {
+ for (int i = getStackCount() - 1; i >= 0; --i) {
+ final ActivityStack current = getStackAt(i);
+ if (!current.inPinnedWindowingMode()) {
+ return current == stack;
+ }
+ }
+ return false;
+ }
+
+ ActivityRecord topRunningActivity() {
+ return topRunningActivity(false /* considerKeyguardState */);
+ }
+
+ /**
+ * Returns the top running activity in the focused stack. In the case the focused stack has no
+ * such activity, the next focusable stack on this display is returned.
+ *
+ * @param considerKeyguardState Indicates whether the locked state should be considered. if
+ * {@code true} and the keyguard is locked, only activities that
+ * can be shown on top of the keyguard will be considered.
+ * @return The top running activity. {@code null} if none is available.
+ */
+ ActivityRecord topRunningActivity(boolean considerKeyguardState) {
+ ActivityRecord topRunning = null;
+ final ActivityStack focusedStack = getFocusedStack();
+ if (focusedStack != null) {
+ topRunning = focusedStack.topRunningActivity();
+ }
+
+ // Look in other focusable stacks.
+ if (topRunning == null) {
+ for (int i = getStackCount() - 1; i >= 0; --i) {
+ final ActivityStack stack = getStackAt(i);
+ // Only consider focusable stacks other than the current focused one.
+ if (stack == focusedStack || !stack.isFocusable()) {
+ continue;
+ }
+ topRunning = stack.topRunningActivity();
+ if (topRunning != null) {
+ break;
+ }
+ }
+ }
+
+ // This activity can be considered the top running activity if we are not considering
+ // the locked state, the keyguard isn't locked, or we can show when locked.
+ if (topRunning != null && considerKeyguardState
+ && mRootActivityContainer.mStackSupervisor.getKeyguardController()
+ .isKeyguardLocked()
+ && !topRunning.canShowWhenLocked()) {
+ return null;
+ }
+
+ return topRunning;
+ }
+
+ boolean updateDisplayOverrideConfigurationLocked() {
+ Configuration values = new Configuration();
+ computeScreenConfiguration(values);
+
+ mAtmService.mH.sendMessage(PooledLambda.obtainMessage(
+ ActivityManagerInternal::updateOomLevelsForDisplay, mAtmService.mAmInternal,
+ mDisplayId));
+
+ Settings.System.clearConfiguration(values);
+ updateDisplayOverrideConfigurationLocked(values, null /* starting */,
+ false /* deferResume */, mAtmService.mTmpUpdateConfigurationResult);
+ return mAtmService.mTmpUpdateConfigurationResult.changes != 0;
+ }
+
+ /**
+ * Updates override configuration specific for the selected display. If no config is provided,
+ * new one will be computed in WM based on current display info.
+ */
+ boolean updateDisplayOverrideConfigurationLocked(Configuration values,
+ ActivityRecord starting, boolean deferResume,
+ ActivityTaskManagerService.UpdateConfigurationResult result) {
+
+ int changes = 0;
+ boolean kept = true;
+
+ mAtmService.deferWindowLayout();
+ try {
+ if (values != null) {
+ if (mDisplayId == DEFAULT_DISPLAY) {
+ // Override configuration of the default display duplicates global config, so
+ // we're calling global config update instead for default display. It will also
+ // apply the correct override config.
+ changes = mAtmService.updateGlobalConfigurationLocked(values,
+ false /* initLocale */, false /* persistent */,
+ UserHandle.USER_NULL /* userId */, deferResume);
+ } else {
+ changes = performDisplayOverrideConfigUpdate(values, deferResume);
+ }
+ }
+
+ kept = mAtmService.ensureConfigAndVisibilityAfterUpdate(starting, changes);
+ } finally {
+ mAtmService.continueWindowLayout();
+ }
+
+ if (result != null) {
+ result.changes = changes;
+ result.activityRelaunched = !kept;
+ }
+ return kept;
+ }
+
+ int performDisplayOverrideConfigUpdate(Configuration values, boolean deferResume) {
+ mTempConfig.setTo(getRequestedOverrideConfiguration());
+ final int changes = mTempConfig.updateFrom(values);
+ if (changes != 0) {
+ Slog.i(TAG, "Override config changes=" + Integer.toHexString(changes) + " "
+ + mTempConfig + " for displayId=" + mDisplayId);
+ onRequestedOverrideConfigurationChanged(mTempConfig);
+
+ final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0;
+ if (isDensityChange && mDisplayId == DEFAULT_DISPLAY) {
+ mAtmService.mAppWarnings.onDensityChanged();
+
+ // Post message to start process to avoid possible deadlock of calling into AMS with
+ // the ATMS lock held.
+ final Message msg = PooledLambda.obtainMessage(
+ ActivityManagerInternal::killAllBackgroundProcessesExcept,
+ mAtmService.mAmInternal, N,
+ ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+ mAtmService.mH.sendMessage(msg);
+ }
+ mWmService.mDisplayNotificationController.dispatchDisplayChanged(
+ this, getConfiguration());
+ }
+ return changes;
+ }
+
+ @Override
+ public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
+ final int currRotation =
+ getRequestedOverrideConfiguration().windowConfiguration.getRotation();
+ if (currRotation != ROTATION_UNDEFINED
+ && currRotation != overrideConfiguration.windowConfiguration.getRotation()) {
+ applyRotationLocked(currRotation,
+ overrideConfiguration.windowConfiguration.getRotation());
+ }
+ mCurrentOverrideConfigurationChanges =
+ getRequestedOverrideConfiguration().diff(overrideConfiguration);
+ super.onRequestedOverrideConfigurationChanged(overrideConfiguration);
+ mCurrentOverrideConfigurationChanges = 0;
+ mWmService.setNewDisplayOverrideConfiguration(overrideConfiguration, this);
+ mAtmService.addWindowLayoutReasons(
+ ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED);
+ }
+
+ /** Checks whether the given activity is in size compatibility mode and notifies the change. */
+ void handleActivitySizeCompatModeIfNeeded(ActivityRecord r) {
+ if (!r.isState(RESUMED) || r.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
+ // The callback is only interested in the foreground changes of fullscreen activity.
+ return;
+ }
+ if (!r.inSizeCompatMode()) {
+ if (mLastCompatModeActivity != null) {
+ mAtmService.getTaskChangeNotificationController()
+ .notifySizeCompatModeActivityChanged(mDisplayId, null /* activityToken */);
+ }
+ mLastCompatModeActivity = null;
+ return;
+ }
+ if (mLastCompatModeActivity == r) {
+ return;
+ }
+ mLastCompatModeActivity = r;
+ mAtmService.getTaskChangeNotificationController()
+ .notifySizeCompatModeActivityChanged(mDisplayId, r.appToken);
+ }
+
+ boolean isUidPresent(int uid) {
+ final PooledPredicate p = PooledLambda.obtainPredicate(
+ ActivityRecord::isUid, PooledLambda.__(ActivityRecord.class), uid);
+ final boolean isUidPresent = mDisplayContent.getActivity(p) != null;
+ p.recycle();
+ return isUidPresent;
+ }
+
+ /**
+ * @see #mRemoved
+ */
+ boolean isRemoved() {
+ return mRemoved;
+ }
+
+ /**
+ * @see #mRemoving
+ */
+ boolean isRemoving() {
+ return mRemoving;
+ }
+
+ void remove() {
+ mRemoving = true;
+ final boolean destroyContentOnRemoval = shouldDestroyContentOnRemove();
+ ActivityStack lastReparentedStack = null;
+ mPreferredTopFocusableStack = null;
+
+ // Stacks could be reparented from the removed display to other display. While
+ // reparenting the last stack of the removed display, the remove display is ready to be
+ // released (no more ActivityStack). But, we cannot release it at that moment or the
+ // related WindowContainer will also be removed. So, we set display as removed after
+ // reparenting stack finished.
+ final DisplayContent toDisplay = mRootActivityContainer.getDefaultDisplay();
+ mRootActivityContainer.mStackSupervisor.beginDeferResume();
+ try {
+ int numStacks = getStackCount();
+ // Keep the order from bottom to top.
+ for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
+ final ActivityStack stack = getStackAt(stackNdx);
+ // Always finish non-standard type stacks.
+ if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) {
+ stack.finishAllActivitiesImmediately();
+ } else {
+ // If default display is in split-window mode, set windowing mode of the stack
+ // to split-screen secondary. Otherwise, set the windowing mode to undefined by
+ // default to let stack inherited the windowing mode from the new display.
+ final int windowingMode = toDisplay.hasSplitScreenPrimaryStack()
+ ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
+ : WINDOWING_MODE_UNDEFINED;
+ stack.reparent(toDisplay, true /* onTop */);
+ stack.setWindowingMode(windowingMode);
+ lastReparentedStack = stack;
+ }
+ // Stacks may be removed from this display. Ensure each stack will be processed and
+ // the loop will end.
+ stackNdx -= numStacks - getStackCount();
+ numStacks = getStackCount();
+ }
+ } finally {
+ mRootActivityContainer.mStackSupervisor.endDeferResume();
+ }
+ mRemoved = true;
+
+ // Only update focus/visibility for the last one because there may be many stacks are
+ // reparented and the intermediate states are unnecessary.
+ if (lastReparentedStack != null) {
+ lastReparentedStack.postReparent();
+ }
+ releaseSelfIfNeeded();
+
+ if (!mAllSleepTokens.isEmpty()) {
+ mRootActivityContainer.mSleepTokens.removeAll(mAllSleepTokens);
+ mAllSleepTokens.clear();
+ mAtmService.updateSleepIfNeededLocked();
+ }
+ }
+
+ private void releaseSelfIfNeeded() {
+ if (!mRemoved) {
+ return;
+ }
+
+ final ActivityStack stack = getStackCount() == 1 ? getStackAt(0) : null;
+ if (stack != null && stack.isActivityTypeHome() && !stack.hasChild()) {
+ // Release this display if an empty home stack is the only thing left.
+ // Since it is the last stack, this display will be released along with the stack
+ // removal.
+ stack.removeIfPossible();
+ } else if (getTopStack() == null) {
+ removeIfPossible();
+ mRootActivityContainer.removeChild(this);
+ mRootActivityContainer.mStackSupervisor
+ .getKeyguardController().onDisplayRemoved(mDisplayId);
+ }
+ }
+
+ /** Update and get all UIDs that are present on the display and have access to it. */
+ IntArray getPresentUIDs() {
+ mDisplayAccessUIDs.clear();
+ final PooledConsumer c = PooledLambda.obtainConsumer(DisplayContent::addActivityUid,
+ PooledLambda.__(ActivityRecord.class), mDisplayAccessUIDs);
+ mDisplayContent.forAllActivities(c);
+ c.recycle();
+ return mDisplayAccessUIDs;
+ }
+
+ private static void addActivityUid(ActivityRecord r, IntArray uids) {
+ uids.add(r.getUid());
+ }
+
+ @VisibleForTesting
+ boolean shouldDestroyContentOnRemove() {
+ return mDisplay.getRemoveMode() == REMOVE_MODE_DESTROY_CONTENT;
+ }
+
+ boolean shouldSleep() {
+ return (getStackCount() == 0 || !mAllSleepTokens.isEmpty())
+ && (mAtmService.mRunningVoice == null);
+ }
+
+ void setFocusedApp(ActivityRecord r, boolean moveFocusNow) {
+ final ActivityRecord newFocus;
+ final IBinder token = r.appToken;
+ if (token == null) {
+ ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Clearing focused app, displayId=%d",
+ mDisplayId);
+ newFocus = null;
+ } else {
+ newFocus = mWmService.mRoot.getActivityRecord(token);
+ if (newFocus == null) {
+ Slog.w(TAG_WM, "Attempted to set focus to non-existing app token: " + token
+ + ", displayId=" + mDisplayId);
+ }
+ ProtoLog.v(WM_DEBUG_FOCUS_LIGHT,
+ "Set focused app to: %s moveFocusNow=%b displayId=%d", newFocus,
+ moveFocusNow, mDisplayId);
+ }
+
+ final boolean changed = setFocusedApp(newFocus);
+ if (moveFocusNow && changed) {
+ mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
+ true /*updateInputWindows*/);
+ }
+ }
+
+ /**
+ * @return the stack currently above the {@param stack}. Can be null if the {@param stack} is
+ * already top-most.
+ */
+ ActivityStack getStackAbove(ActivityStack stack) {
+ final int stackIndex = getIndexOf(stack) + 1;
+ return (stackIndex < getStackCount()) ? getStackAt(stackIndex) : null;
+ }
+
+ /**
+ * Adjusts the {@param stack} behind the last visible stack in the display if necessary.
+ * Generally used in conjunction with {@link #moveStackBehindStack}.
+ */
+ void moveStackBehindBottomMostVisibleStack(ActivityStack stack) {
+ if (stack.shouldBeVisible(null)) {
+ // Skip if the stack is already visible
+ return;
+ }
+
+ // Move the stack to the bottom to not affect the following visibility checks
+ positionStackAtBottom(stack);
+
+ // Find the next position where the stack should be placed
+ final int numStacks = getStackCount();
+ for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
+ final ActivityStack s = getStackAt(stackNdx);
+ if (s == stack) {
+ continue;
+ }
+ final int winMode = s.getWindowingMode();
+ final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN
+ || winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+ if (s.shouldBeVisible(null) && isValidWindowingMode) {
+ // Move the provided stack to behind this stack
+ positionStackAt(stack, Math.max(0, stackNdx - 1));
+ break;
+ }
+ }
+ }
+
+ /**
+ * Moves the {@param stack} behind the given {@param behindStack} if possible. If
+ * {@param behindStack} is not currently in the display, then then the stack is moved to the
+ * back. Generally used in conjunction with {@link #moveStackBehindBottomMostVisibleStack}.
+ */
+ void moveStackBehindStack(ActivityStack stack, ActivityStack behindStack) {
+ if (behindStack == null || behindStack == stack) {
+ return;
+ }
+
+ // Note that positionChildAt will first remove the given stack before inserting into the
+ // list, so we need to adjust the insertion index to account for the removed index
+ // TODO: Remove this logic when WindowContainer.positionChildAt() is updated to adjust the
+ // position internally
+ final int stackIndex = getIndexOf(stack);
+ final int behindStackIndex = getIndexOf(behindStack);
+ final int insertIndex = stackIndex <= behindStackIndex
+ ? behindStackIndex - 1 : behindStackIndex;
+ positionStackAt(stack, Math.max(0, insertIndex));
+ }
+
+ void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
+ boolean preserveWindows, boolean notifyClients) {
+ for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+ final ActivityStack stack = getStackAt(stackNdx);
+ stack.ensureActivitiesVisible(starting, configChanges, preserveWindows,
+ notifyClients);
+ }
+ }
+
+ void moveHomeStackToFront(String reason) {
+ final ActivityStack homeStack = getHomeStack();
+ if (homeStack != null) {
+ homeStack.moveToFront(reason);
+ }
+ }
+
+ /**
+ * Moves the focusable home activity to top. If there is no such activity, the home stack will
+ * still move to top.
+ */
+ void moveHomeActivityToTop(String reason) {
+ final ActivityRecord top = getHomeActivity();
+ if (top == null) {
+ moveHomeStackToFront(reason);
+ return;
+ }
+ top.moveFocusableActivityToTop(reason);
+ }
+
+ @Nullable
+ ActivityRecord getHomeActivity() {
+ return getHomeActivityForUser(mRootActivityContainer.mCurrentUser);
+ }
+
+ @Nullable
+ ActivityRecord getHomeActivityForUser(int userId) {
+ final ActivityStack homeStack = getHomeStack();
+ if (homeStack == null) {
+ return null;
+ }
+
+ final PooledPredicate p = PooledLambda.obtainPredicate(
+ DisplayContent::isHomeActivityForUser, PooledLambda.__(ActivityRecord.class),
+ userId);
+ final ActivityRecord r = homeStack.getActivity(p);
+ p.recycle();
+ return r;
+ }
+
+ private static boolean isHomeActivityForUser(ActivityRecord r, int userId) {
+ return r.isActivityTypeHome() && (userId == UserHandle.USER_ALL || r.mUserId == userId);
+ }
+
+ boolean isSleeping() {
+ return mSleeping;
+ }
+
+ void setIsSleeping(boolean asleep) {
+ mSleeping = asleep;
+ }
+
+ /**
+ * Adds a listener to be notified whenever the stack order in the display changes. Currently
+ * only used by the {@link RecentsAnimation} to determine whether to interrupt and cancel the
+ * current animation when the system state changes.
+ */
+ void registerStackOrderChangedListener(OnStackOrderChangedListener listener) {
+ if (!mStackOrderChangedCallbacks.contains(listener)) {
+ mStackOrderChangedCallbacks.add(listener);
+ }
+ }
+
+ /**
+ * Removes a previously registered stack order change listener.
+ */
+ void unregisterStackOrderChangedListener(OnStackOrderChangedListener listener) {
+ mStackOrderChangedCallbacks.remove(listener);
+ }
+
+ /**
+ * Notifies of a stack order change
+ * @param stack The stack which triggered the order change
+ */
+ private void onStackOrderChanged(ActivityStack stack) {
+ for (int i = mStackOrderChangedCallbacks.size() - 1; i >= 0; i--) {
+ mStackOrderChangedCallbacks.get(i).onStackOrderChanged(stack);
+ }
+ }
+
+ void setDisplayToSingleTaskInstance() {
+ final int childCount = getStackCount();
+ if (childCount > 1) {
+ throw new IllegalArgumentException("Display already has multiple stacks. display="
+ + this);
+ }
+ if (childCount > 0) {
+ final ActivityStack stack = getStackAt(0);
+ if (stack.getChildCount() > 1) {
+ throw new IllegalArgumentException("Display stack already has multiple tasks."
+ + " display=" + this + " stack=" + stack);
+ }
+ }
+
+ mSingleTaskInstance = true;
+ }
+
+ /** Returns true if the display can only contain one task */
+ boolean isSingleTaskInstance() {
+ return mSingleTaskInstance;
+ }
+
+ @VisibleForTesting
+ void removeAllTasks() {
+ forAllTasks((t) -> { t.getStack().removeChild(t, "removeAllTasks"); });
+ }
+
+ /**
+ * Callback for when the order of the stacks in the display changes.
+ */
+ interface OnStackOrderChangedListener {
+ void onStackOrderChanged(ActivityStack stack);
+ }
+
+ public void dumpStacks(PrintWriter pw) {
+ for (int i = getStackCount() - 1; i >= 0; --i) {
+ pw.print(getStackAt(i).mStackId);
+ if (i > 0) {
+ pw.print(",");
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/DisplayWindowListenerController.java b/services/core/java/com/android/server/wm/DisplayWindowListenerController.java
index 78fea74..bb31d45 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowListenerController.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowListenerController.java
@@ -41,7 +41,7 @@
try {
for (int i = 0; i < mService.mAtmService.mRootActivityContainer.getChildCount();
++i) {
- ActivityDisplay d = mService.mAtmService.mRootActivityContainer.getChildAt(i);
+ DisplayContent d = mService.mAtmService.mRootActivityContainer.getChildAt(i);
listener.onDisplayAdded(d.mDisplayId);
}
} catch (RemoteException e) { }
@@ -52,7 +52,7 @@
mDisplayListeners.unregister(listener);
}
- void dispatchDisplayAdded(ActivityDisplay display) {
+ void dispatchDisplayAdded(DisplayContent display) {
int count = mDisplayListeners.beginBroadcast();
for (int i = 0; i < count; ++i) {
try {
@@ -85,7 +85,7 @@
mDisplayListeners.finishBroadcast();
}
- void dispatchDisplayRemoved(ActivityDisplay display) {
+ void dispatchDisplayRemoved(DisplayContent display) {
int count = mDisplayListeners.beginBroadcast();
for (int i = 0; i < count; ++i) {
try {
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 3a0696f..6f81957 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -296,7 +296,7 @@
boolean requestDismissKeyguard = false;
for (int displayNdx = mRootActivityContainer.getChildCount() - 1;
displayNdx >= 0; displayNdx--) {
- final ActivityDisplay display = mRootActivityContainer.getChildAt(displayNdx);
+ final DisplayContent display = mRootActivityContainer.getChildAt(displayNdx);
final KeyguardDisplayState state = getDisplay(display.mDisplayId);
state.visibilitiesUpdated(this, display);
requestDismissKeyguard |= state.mRequestDismissKeyguard;
@@ -420,7 +420,7 @@
private void updateKeyguardSleepToken() {
for (int displayNdx = mRootActivityContainer.getChildCount() - 1;
displayNdx >= 0; displayNdx--) {
- final ActivityDisplay display = mRootActivityContainer.getChildAt(displayNdx);
+ final DisplayContent display = mRootActivityContainer.getChildAt(displayNdx);
updateKeyguardSleepToken(display.mDisplayId);
}
}
@@ -483,7 +483,7 @@
}
}
- void visibilitiesUpdated(KeyguardController controller, ActivityDisplay display) {
+ void visibilitiesUpdated(KeyguardController controller, DisplayContent display) {
final boolean lastOccluded = mOccluded;
final ActivityRecord lastDismissActivity = mDismissingKeyguardActivity;
mRequestDismissKeyguard = false;
@@ -530,7 +530,7 @@
* Only the top non-pinned activity of the focusable stack on each display can control its
* occlusion state.
*/
- private ActivityStack getStackForControllingOccluding(ActivityDisplay display) {
+ private ActivityStack getStackForControllingOccluding(DisplayContent display) {
for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getStackAt(stackNdx);
if (stack != null && stack.isFocusableAndVisible()
diff --git a/services/core/java/com/android/server/wm/LaunchParamsPersister.java b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
index c3bcc74..8cf3dc8 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsPersister.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
@@ -223,8 +223,8 @@
private boolean saveTaskToLaunchParam(Task task, PersistableLaunchParams params) {
final ActivityStack stack = task.getStack();
final int displayId = stack.mDisplayId;
- final ActivityDisplay display =
- mSupervisor.mRootActivityContainer.getActivityDisplay(displayId);
+ final DisplayContent display =
+ mSupervisor.mRootActivityContainer.getDisplayContent(displayId);
final DisplayInfo info = new DisplayInfo();
display.mDisplay.getDisplayInfo(info);
@@ -260,7 +260,7 @@
return;
}
- final ActivityDisplay display = mSupervisor.mRootActivityContainer.getActivityDisplay(
+ final DisplayContent display = mSupervisor.mRootActivityContainer.getDisplayContent(
persistableParams.mDisplayUniqueId);
if (display != null) {
outParams.mPreferredDisplayId = display.mDisplayId;
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index e199b28..71bbb70 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -208,7 +208,7 @@
synchronized (mService.mGlobalLock) {
// Unfreeze the task list once we touch down in a task
final RootActivityContainer rac = mService.mRootActivityContainer;
- final DisplayContent dc = rac.getActivityDisplay(displayId).mDisplayContent;
+ final DisplayContent dc = rac.getDisplayContent(displayId).mDisplayContent;
if (dc.pointWithinAppWindow(x, y)) {
final ActivityStack stack = mService.getTopDisplayFocusedStack();
final Task topTask = stack != null ? stack.getTopMostTask() : null;
@@ -1317,7 +1317,7 @@
// TODO(b/126185105): Find a different signal to use besides isSingleTaskInstance
final ActivityStack stack = task.getStack();
if (stack != null) {
- ActivityDisplay display = stack.getDisplay();
+ DisplayContent display = stack.getDisplay();
if (display != null && display.isSingleTaskInstance()) {
return false;
}
@@ -1387,7 +1387,7 @@
}
// Trim tasks that are in stacks that are behind the home stack
- final ActivityDisplay display = stack.getDisplay();
+ final DisplayContent display = stack.getDisplay();
return display.getIndexOf(stack) < display.getIndexOf(display.getHomeStack());
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index b398626..0a8e747 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -53,14 +53,14 @@
* cleanup. See {@link com.android.server.wm.RecentsAnimationController}.
*/
class RecentsAnimation implements RecentsAnimationCallbacks,
- ActivityDisplay.OnStackOrderChangedListener {
+ DisplayContent.OnStackOrderChangedListener {
private static final String TAG = RecentsAnimation.class.getSimpleName();
private final ActivityTaskManagerService mService;
private final ActivityStackSupervisor mStackSupervisor;
private final ActivityStartController mActivityStartController;
private final WindowManagerService mWindowManager;
- private final ActivityDisplay mDefaultDisplay;
+ private final DisplayContent mDefaultDisplay;
private final Intent mTargetIntent;
private final ComponentName mRecentsComponent;
private final int mRecentsUid;
@@ -180,7 +180,7 @@
ActivityRecord targetActivity = getTargetActivity(targetStack);
final boolean hasExistingActivity = targetActivity != null;
if (hasExistingActivity) {
- final ActivityDisplay display = targetActivity.getDisplay();
+ final DisplayContent display = targetActivity.getDisplay();
mRestoreTargetBehindStack = display.getStackAbove(targetStack);
if (mRestoreTargetBehindStack == null) {
notifyAnimationCancelBeforeStart(recentsAnimationRunner);
@@ -250,7 +250,7 @@
mWindowManager.cancelRecentsAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION,
"startRecentsActivity");
mWindowManager.initializeRecentsAnimation(mTargetActivityType, recentsAnimationRunner,
- this, mDefaultDisplay.mDisplayId,
+ this, mDefaultDisplay.getDisplayId(),
mStackSupervisor.mRecentTasks.getRecentTaskIds(), targetActivity);
// If we updated the launch-behind state, update the visibility of the activities after
@@ -351,7 +351,7 @@
}
} else if (reorderMode == REORDER_MOVE_TO_ORIGINAL_POSITION){
// Restore the target stack to its previous position
- final ActivityDisplay display = targetActivity.getDisplay();
+ final DisplayContent display = targetActivity.getDisplay();
display.moveStackBehindStack(targetStack, mRestoreTargetBehindStack);
if (WM_DEBUG_RECENTS_ANIMATIONS.isLogToAny()) {
final ActivityStack aboveTargetStack =
diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
index 3aa91d5..d787cbc 100644
--- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
+++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
@@ -258,7 +258,7 @@
private void processCreatedTasks() {
if (mCreatedTasks.isEmpty()) return;
- ActivityDisplay display = mParent.getDisplay();
+ DisplayContent display = mParent.getDisplay();
final boolean singleTaskInstanceDisplay = display.isSingleTaskInstance();
if (singleTaskInstanceDisplay) {
display = mParent.mRootActivityContainer.getDefaultDisplay();
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index 704a4b7..7dd9790 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -109,7 +109,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.ResolverActivity;
-import com.android.internal.util.ToBooleanFunction;
import com.android.internal.util.function.pooled.PooledConsumer;
import com.android.internal.util.function.pooled.PooledFunction;
import com.android.internal.util.function.pooled.PooledLambda;
@@ -176,10 +175,10 @@
* List of displays which contain activities, sorted by z-order.
* The last entry in the list is the topmost.
*/
- private final ArrayList<ActivityDisplay> mActivityDisplays = new ArrayList<>();
+ private final ArrayList<DisplayContent> mDisplayContents = new ArrayList<>();
/** Reference to default display so we can quickly look it up. */
- private ActivityDisplay mDefaultDisplay;
+ private DisplayContent mDefaultDisplay;
private final SparseArray<IntArray> mDisplayAccessUIDs = new SparseArray<>();
/** The current user */
@@ -355,35 +354,35 @@
final Display[] displays = mDisplayManager.getDisplays();
for (int displayNdx = 0; displayNdx < displays.length; ++displayNdx) {
final Display display = displays[displayNdx];
- final ActivityDisplay activityDisplay = new ActivityDisplay(this, display);
- if (activityDisplay.mDisplayId == DEFAULT_DISPLAY) {
- mDefaultDisplay = activityDisplay;
+ final DisplayContent displayContent = new DisplayContent(display, this);
+ if (displayContent.mDisplayId == DEFAULT_DISPLAY) {
+ mDefaultDisplay = displayContent;
}
- addChild(activityDisplay, ActivityDisplay.POSITION_TOP);
+ addChild(displayContent, DisplayContent.POSITION_TOP);
}
calculateDefaultMinimalSizeOfResizeableTasks();
- final ActivityDisplay defaultDisplay = getDefaultDisplay();
+ final DisplayContent defaultDisplay = getDefaultDisplay();
defaultDisplay.getOrCreateStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
- positionChildAt(defaultDisplay, ActivityDisplay.POSITION_TOP);
+ positionChildAt(defaultDisplay, DisplayContent.POSITION_TOP);
}
// TODO(multi-display): Look at all callpoints to make sure they make sense in multi-display.
- ActivityDisplay getDefaultDisplay() {
+ DisplayContent getDefaultDisplay() {
return mDefaultDisplay;
}
/**
- * Get an existing instance of {@link ActivityDisplay} that has the given uniqueId. Unique ID is
+ * Get an existing instance of {@link DisplayContent} that has the given uniqueId. Unique ID is
* defined in {@link DisplayInfo#uniqueId}.
*
* @param uniqueId the unique ID of the display
- * @return the {@link ActivityDisplay} or {@code null} if nothing is found.
+ * @return the {@link DisplayContent} or {@code null} if nothing is found.
*/
- ActivityDisplay getActivityDisplay(String uniqueId) {
- for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
- final ActivityDisplay display = mActivityDisplays.get(i);
+ DisplayContent getDisplayContent(String uniqueId) {
+ for (int i = mDisplayContents.size() - 1; i >= 0; --i) {
+ final DisplayContent display = mDisplayContents.get(i);
final boolean isValid = display.mDisplay.isValid();
if (isValid && display.mDisplay.getUniqueId().equals(uniqueId)) {
return display;
@@ -393,26 +392,26 @@
return null;
}
- // TODO: Look into consolidating with getActivityDisplayOrCreate()
- ActivityDisplay getActivityDisplay(int displayId) {
- for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
- final ActivityDisplay activityDisplay = mActivityDisplays.get(i);
- if (activityDisplay.mDisplayId == displayId) {
- return activityDisplay;
+ // TODO: Look into consolidating with getDisplayContentOrCreate()
+ DisplayContent getDisplayContent(int displayId) {
+ for (int i = mDisplayContents.size() - 1; i >= 0; --i) {
+ final DisplayContent displayContent = mDisplayContents.get(i);
+ if (displayContent.mDisplayId == displayId) {
+ return displayContent;
}
}
return null;
}
/**
- * Get an existing instance of {@link ActivityDisplay} or create new if there is a
+ * Get an existing instance of {@link DisplayContent} or create new if there is a
* corresponding record in display manager.
*/
- // TODO: Look into consolidating with getActivityDisplay()
- @Nullable ActivityDisplay getActivityDisplayOrCreate(int displayId) {
- ActivityDisplay activityDisplay = getActivityDisplay(displayId);
- if (activityDisplay != null) {
- return activityDisplay;
+ // TODO: Look into consolidating with getDisplayContent()
+ @Nullable DisplayContent getDisplayContentOrCreate(int displayId) {
+ DisplayContent displayContent = getDisplayContent(displayId);
+ if (displayContent != null) {
+ return displayContent;
}
if (mDisplayManager == null) {
// The system isn't fully initialized yet.
@@ -424,9 +423,9 @@
return null;
}
// The display hasn't been added to ActivityManager yet, create a new record now.
- activityDisplay = new ActivityDisplay(this, display);
- addChild(activityDisplay, ActivityDisplay.POSITION_BOTTOM);
- return activityDisplay;
+ displayContent = new DisplayContent(display, this);
+ addChild(displayContent, DisplayContent.POSITION_BOTTOM);
+ return displayContent;
}
ActivityRecord getDefaultDisplayHomeActivity() {
@@ -434,21 +433,21 @@
}
ActivityRecord getDefaultDisplayHomeActivityForUser(int userId) {
- return getActivityDisplay(DEFAULT_DISPLAY).getHomeActivityForUser(userId);
+ return getDisplayContent(DEFAULT_DISPLAY).getHomeActivityForUser(userId);
}
boolean startHomeOnAllDisplays(int userId, String reason) {
boolean homeStarted = false;
- for (int i = mActivityDisplays.size() - 1; i >= 0; i--) {
- final int displayId = mActivityDisplays.get(i).mDisplayId;
+ for (int i = mDisplayContents.size() - 1; i >= 0; i--) {
+ final int displayId = mDisplayContents.get(i).mDisplayId;
homeStarted |= startHomeOnDisplay(userId, reason, displayId);
}
return homeStarted;
}
void startHomeOnEmptyDisplays(String reason) {
- for (int i = mActivityDisplays.size() - 1; i >= 0; i--) {
- final ActivityDisplay display = mActivityDisplays.get(i);
+ for (int i = mDisplayContents.size() - 1; i >= 0; i--) {
+ final DisplayContent display = mDisplayContents.get(i);
if (display.topRunningActivity() == null) {
startHomeOnDisplay(mCurrentUser, reason, display.mDisplayId);
}
@@ -630,7 +629,7 @@
displayId = DEFAULT_DISPLAY;
}
- final ActivityRecord r = getActivityDisplay(displayId).getHomeActivity();
+ final ActivityRecord r = getDisplayContent(displayId).getHomeActivity();
final String myReason = reason + " resumeHomeActivity";
// Only resume home activity if isn't finishing.
@@ -672,7 +671,7 @@
return false;
}
- final ActivityDisplay display = getActivityDisplay(displayId);
+ final DisplayContent display = getDisplayContent(displayId);
if (display == null || display.isRemoved() || !display.supportsSystemDecorations()) {
// Can't launch home on display that doesn't support system decorations.
return false;
@@ -772,10 +771,8 @@
if (displayContent != null) {
// Update the configuration of the activities on the display.
- // TODO(display-merge): Remove cast
- return ((ActivityDisplay) displayContent)
- .updateDisplayOverrideConfigurationLocked(config, starting, deferResume,
- null /* result */);
+ return displayContent.updateDisplayOverrideConfigurationLocked(config, starting,
+ deferResume, null /* result */);
} else {
return true;
}
@@ -789,8 +786,8 @@
final ArrayList<IBinder> topActivityTokens = new ArrayList<>();
final ActivityStack topFocusedStack = getTopDisplayFocusedStack();
// Traverse all displays.
- for (int i = mActivityDisplays.size() - 1; i >= 0; i--) {
- final ActivityDisplay display = mActivityDisplays.get(i);
+ for (int i = mDisplayContents.size() - 1; i >= 0; i--) {
+ final DisplayContent display = mDisplayContents.get(i);
// Traverse all stacks on a display.
for (int j = display.getStackCount() - 1; j >= 0; --j) {
final ActivityStack stack = display.getStackAt(j);
@@ -811,8 +808,8 @@
}
ActivityStack getTopDisplayFocusedStack() {
- for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
- final ActivityStack focusedStack = mActivityDisplays.get(i).getFocusedStack();
+ for (int i = mDisplayContents.size() - 1; i >= 0; --i) {
+ final ActivityStack focusedStack = mDisplayContents.get(i).getFocusedStack();
if (focusedStack != null) {
return focusedStack;
}
@@ -831,8 +828,8 @@
}
// The top focused stack might not have a resumed activity yet - look on all displays in
// focus order.
- for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
- final ActivityDisplay display = mActivityDisplays.get(i);
+ for (int i = mDisplayContents.size() - 1; i >= 0; --i) {
+ final DisplayContent display = mDisplayContents.get(i);
final ActivityRecord resumedActivityOnDisplay = display.getResumedActivity();
if (resumedActivityOnDisplay != null) {
return resumedActivityOnDisplay;
@@ -861,8 +858,8 @@
// previous app if this activity is being hosted by the process that is actually still the
// foreground.
WindowProcessController fgApp = null;
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+ for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+ final DisplayContent display = mDisplayContents.get(displayNdx);
for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getStackAt(stackNdx);
if (isTopDisplayFocusedStack(stack)) {
@@ -889,8 +886,8 @@
boolean attachApplication(WindowProcessController app) throws RemoteException {
final String processName = app.mName;
boolean didSomething = false;
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+ for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+ final DisplayContent display = mDisplayContents.get(displayNdx);
final ActivityStack stack = display.getFocusedStack();
if (stack == null) {
continue;
@@ -958,8 +955,8 @@
try {
mStackSupervisor.getKeyguardController().beginActivityVisibilityUpdate();
// First the front stacks. In case any are not fullscreen and are in front of home.
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+ for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+ final DisplayContent display = mDisplayContents.get(displayNdx);
display.ensureActivitiesVisible(starting, configChanges, preserveWindows,
notifyClients);
}
@@ -988,8 +985,8 @@
mCurrentUser = userId;
mStackSupervisor.mStartingUsers.add(uss);
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+ for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+ final DisplayContent display = mDisplayContents.get(displayNdx);
for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getStackAt(stackNdx);
stack.switchUser(userId);
@@ -1036,8 +1033,8 @@
* @param onTop Indicates whether container should be place on top or on bottom.
*/
void moveStackToDisplay(int stackId, int displayId, boolean onTop) {
- final ActivityDisplay activityDisplay = getActivityDisplayOrCreate(displayId);
- if (activityDisplay == null) {
+ final DisplayContent displayContent = getDisplayContentOrCreate(displayId);
+ if (displayContent == null) {
throw new IllegalArgumentException("moveStackToDisplay: Unknown displayId="
+ displayId);
}
@@ -1047,7 +1044,7 @@
+ stackId);
}
- final ActivityDisplay currentDisplay = stack.getDisplay();
+ final DisplayContent currentDisplay = stack.getDisplay();
if (currentDisplay == null) {
throw new IllegalStateException("moveStackToDisplay: Stack with stack=" + stack
+ " is not attached to any display.");
@@ -1058,14 +1055,14 @@
+ " to its current displayId=" + displayId);
}
- if (activityDisplay.isSingleTaskInstance() && activityDisplay.getStackCount() > 0) {
+ if (displayContent.isSingleTaskInstance() && displayContent.getStackCount() > 0) {
// We don't allow moving stacks to single instance display that already has a child.
Slog.e(TAG, "Can not move stack=" + stack
- + " to single task instance display=" + activityDisplay);
+ + " to single task instance display=" + displayContent);
return;
}
- stack.reparent(activityDisplay.mDisplayContent, onTop);
+ stack.reparent(displayContent.mDisplayContent, onTop);
// TODO(multi-display): resize stacks properly if moved from split-screen.
}
@@ -1098,7 +1095,7 @@
String reason) {
mService.deferWindowLayout();
- final ActivityDisplay display = r.getActivityStack().getDisplay();
+ final DisplayContent display = r.getActivityStack().getDisplay();
try {
final Task task = r.getTask();
@@ -1168,8 +1165,8 @@
}
void executeAppTransitionForAllDisplay() {
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+ for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+ final DisplayContent display = mDisplayContents.get(displayNdx);
display.mDisplayContent.executeAppTransition();
}
}
@@ -1194,7 +1191,7 @@
mTmpFindTaskResult.clear();
// Looking up task on preferred display first
- final ActivityDisplay preferredDisplay = getActivityDisplay(preferredDisplayId);
+ final DisplayContent preferredDisplay = getDisplayContent(preferredDisplayId);
if (preferredDisplay != null) {
preferredDisplay.findTaskLocked(r, true /* isPreferredDisplay */, mTmpFindTaskResult);
if (mTmpFindTaskResult.mIdealMatch) {
@@ -1202,8 +1199,8 @@
}
}
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+ for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+ final DisplayContent display = mDisplayContents.get(displayNdx);
if (display.mDisplayId == preferredDisplayId) {
continue;
}
@@ -1227,8 +1224,8 @@
int finishTopCrashedActivities(WindowProcessController app, String reason) {
Task finishedTask = null;
ActivityStack focusedStack = getTopDisplayFocusedStack();
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+ for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+ final DisplayContent display = mDisplayContents.get(displayNdx);
// It is possible that request to finish activity might also remove its task and stack,
// so we need to be careful with indexes in the loop and check child count every time.
for (int stackNdx = 0; stackNdx < display.getStackCount(); ++stackNdx) {
@@ -1259,9 +1256,9 @@
result = targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+ for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
boolean resumedOnDisplay = false;
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+ final DisplayContent display = mDisplayContents.get(displayNdx);
for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getStackAt(stackNdx);
final ActivityRecord topRunningActivity = stack.topRunningActivity();
@@ -1291,7 +1288,7 @@
final ActivityStack focusedStack = display.getFocusedStack();
if (focusedStack != null) {
result |= focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions);
- } else if (targetStack == null && !display.hasChild()) {
+ } else if (targetStack == null && display.getStackCount() == 0) {
result |= resumeHomeActivity(null /* prev */, "empty-display",
display.mDisplayId);
}
@@ -1302,9 +1299,9 @@
}
void applySleepTokens(boolean applyToStacks) {
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+ for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
// Set the sleeping state of the display.
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+ final DisplayContent display = mDisplayContents.get(displayNdx);
final boolean displayShouldSleep = display.shouldSleep();
if (displayShouldSleep == display.isSleeping()) {
continue;
@@ -1358,8 +1355,8 @@
}
protected ActivityStack getStack(int stackId) {
- for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
- final ActivityStack stack = mActivityDisplays.get(i).getStack(stackId);
+ for (int i = mDisplayContents.size() - 1; i >= 0; --i) {
+ final ActivityStack stack = mDisplayContents.get(i).getStack(stackId);
if (stack != null) {
return stack;
}
@@ -1367,11 +1364,11 @@
return null;
}
- /** @see ActivityDisplay#getStack(int, int) */
+ /** @see DisplayContent#getStack(int, int) */
ActivityStack getStack(int windowingMode, int activityType) {
- for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
+ for (int i = mDisplayContents.size() - 1; i >= 0; --i) {
final ActivityStack stack =
- mActivityDisplays.get(i).getStack(windowingMode, activityType);
+ mDisplayContents.get(i).getStack(windowingMode, activityType);
if (stack != null) {
return stack;
}
@@ -1381,7 +1378,7 @@
private ActivityStack getStack(int windowingMode, int activityType,
int displayId) {
- ActivityDisplay display = getActivityDisplay(displayId);
+ DisplayContent display = getDisplayContent(displayId);
if (display == null) {
return null;
}
@@ -1390,7 +1387,7 @@
private ActivityManager.StackInfo getStackInfo(ActivityStack stack) {
final int displayId = stack.mDisplayId;
- final ActivityDisplay display = getActivityDisplay(displayId);
+ final DisplayContent display = getDisplayContent(displayId);
ActivityManager.StackInfo info = new ActivityManager.StackInfo();
stack.getBounds(info.bounds);
info.displayId = displayId;
@@ -1455,8 +1452,8 @@
ArrayList<ActivityManager.StackInfo> getAllStackInfos(int displayId) {
ArrayList<ActivityManager.StackInfo> list = new ArrayList<>();
if (displayId == INVALID_DISPLAY) {
- for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+ for (int displayNdx = 0; displayNdx < mDisplayContents.size(); ++displayNdx) {
+ final DisplayContent display = mDisplayContents.get(displayNdx);
for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getStackAt(stackNdx);
list.add(getStackInfo(stack));
@@ -1464,7 +1461,7 @@
}
return list;
}
- final ActivityDisplay display = getActivityDisplay(displayId);
+ final DisplayContent display = getDisplayContent(displayId);
if (display == null) {
return list;
}
@@ -1493,7 +1490,7 @@
public void onDisplayAdded(int displayId) {
if (DEBUG_STACK) Slog.v(TAG, "Display added displayId=" + displayId);
synchronized (mService.mGlobalLock) {
- final ActivityDisplay display = getActivityDisplayOrCreate(displayId);
+ final DisplayContent display = getDisplayContentOrCreate(displayId);
if (display == null) {
return;
}
@@ -1519,12 +1516,12 @@
}
synchronized (mService.mGlobalLock) {
- final ActivityDisplay activityDisplay = getActivityDisplay(displayId);
- if (activityDisplay == null) {
+ final DisplayContent displayContent = getDisplayContent(displayId);
+ if (displayContent == null) {
return;
}
- activityDisplay.remove();
+ displayContent.remove();
}
}
@@ -1532,9 +1529,9 @@
public void onDisplayChanged(int displayId) {
if (DEBUG_STACK) Slog.v(TAG, "Display changed displayId=" + displayId);
synchronized (mService.mGlobalLock) {
- final ActivityDisplay activityDisplay = getActivityDisplay(displayId);
- if (activityDisplay != null) {
- activityDisplay.onDisplayChanged();
+ final DisplayContent displayContent = getDisplayContent(displayId);
+ if (displayContent != null) {
+ displayContent.onDisplayChanged();
}
}
}
@@ -1542,12 +1539,12 @@
/** Update lists of UIDs that are present on displays and have access to them. */
void updateUIDsPresentOnDisplay() {
mDisplayAccessUIDs.clear();
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ActivityDisplay activityDisplay = mActivityDisplays.get(displayNdx);
+ for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+ final DisplayContent displayContent = mDisplayContents.get(displayNdx);
// Only bother calculating the whitelist for private displays
- if (activityDisplay.isPrivate()) {
+ if (displayContent.isPrivate()) {
mDisplayAccessUIDs.append(
- activityDisplay.mDisplayId, activityDisplay.getPresentUIDs());
+ displayContent.mDisplayId, displayContent.getPresentUIDs());
}
}
// Store updated lists in DisplayManager. Callers from outside of AM should get them there.
@@ -1555,7 +1552,7 @@
}
ActivityStack findStackBehind(ActivityStack stack) {
- final ActivityDisplay display = getActivityDisplay(stack.mDisplayId);
+ final DisplayContent display = getDisplayContent(stack.mDisplayId);
if (display != null) {
for (int i = display.getStackCount() - 1; i >= 0; i--) {
if (display.getStackAt(i) == stack && i > 0) {
@@ -1569,12 +1566,12 @@
@Override
protected int getChildCount() {
- return mActivityDisplays.size();
+ return mDisplayContents.size();
}
@Override
- protected ActivityDisplay getChildAt(int index) {
- return mActivityDisplays.get(index);
+ protected DisplayContent getChildAt(int index) {
+ return mDisplayContents.get(index);
}
@Override
@@ -1592,61 +1589,59 @@
/** Change the z-order of the given display. */
private void positionChildAt(DisplayContent display, int position) {
- if (position >= mActivityDisplays.size()) {
- position = mActivityDisplays.size() - 1;
+ if (position >= mDisplayContents.size()) {
+ position = mDisplayContents.size() - 1;
} else if (position < 0) {
position = 0;
}
- // TODO(display-merge): Remove cast
- final ActivityDisplay activityDisplay = (ActivityDisplay) display;
- if (mActivityDisplays.isEmpty()) {
- mActivityDisplays.add(activityDisplay);
- } else if (mActivityDisplays.get(position) != display) {
- mActivityDisplays.remove(display);
- mActivityDisplays.add(position, activityDisplay);
+ if (mDisplayContents.isEmpty()) {
+ mDisplayContents.add(display);
+ } else if (mDisplayContents.get(position) != display) {
+ mDisplayContents.remove(display);
+ mDisplayContents.add(position, display);
}
mStackSupervisor.updateTopResumedActivityIfNeeded();
}
@VisibleForTesting
- void addChild(ActivityDisplay activityDisplay, int position) {
- positionChildAt(activityDisplay, position);
- mRootWindowContainer.positionChildAt(position, activityDisplay.mDisplayContent);
+ void addChild(DisplayContent displayContent, int position) {
+ positionChildAt(displayContent, position);
+ mRootWindowContainer.positionChildAt(position, displayContent);
}
- void removeChild(ActivityDisplay activityDisplay) {
- // The caller must tell the controller of {@link ActivityDisplay} to release its container
- // {@link DisplayContent}. That is done in {@link ActivityDisplay#releaseSelfIfNeeded}).
- mActivityDisplays.remove(activityDisplay);
+ void removeChild(DisplayContent displayContent) {
+ // The caller must tell the controller of {@link DisplayContent} to release its container
+ // {@link DisplayContent}. That is done in {@link DisplayContent#releaseSelfIfNeeded}).
+ mDisplayContents.remove(displayContent);
}
Configuration getDisplayOverrideConfiguration(int displayId) {
- final ActivityDisplay activityDisplay = getActivityDisplayOrCreate(displayId);
- if (activityDisplay == null) {
+ final DisplayContent displayContent = getDisplayContentOrCreate(displayId);
+ if (displayContent == null) {
throw new IllegalArgumentException("No display found with id: " + displayId);
}
- return activityDisplay.getRequestedOverrideConfiguration();
+ return displayContent.getRequestedOverrideConfiguration();
}
void setDisplayOverrideConfiguration(Configuration overrideConfiguration, int displayId) {
- final ActivityDisplay activityDisplay = getActivityDisplayOrCreate(displayId);
- if (activityDisplay == null) {
+ final DisplayContent displayContent = getDisplayContentOrCreate(displayId);
+ if (displayContent == null) {
throw new IllegalArgumentException("No display found with id: " + displayId);
}
- activityDisplay.onRequestedOverrideConfigurationChanged(overrideConfiguration);
+ displayContent.onRequestedOverrideConfigurationChanged(overrideConfiguration);
}
void prepareForShutdown() {
- for (int i = 0; i < mActivityDisplays.size(); i++) {
- createSleepToken("shutdown", mActivityDisplays.get(i).mDisplayId);
+ for (int i = 0; i < mDisplayContents.size(); i++) {
+ createSleepToken("shutdown", mDisplayContents.get(i).mDisplayId);
}
}
ActivityTaskManagerInternal.SleepToken createSleepToken(String tag, int displayId) {
- final ActivityDisplay display = getActivityDisplay(displayId);
+ final DisplayContent display = getDisplayContent(displayId);
if (display == null) {
throw new IllegalArgumentException("Invalid display: " + displayId);
}
@@ -1660,7 +1655,7 @@
private void removeSleepToken(SleepTokenImpl token) {
mSleepTokens.remove(token);
- final ActivityDisplay display = getActivityDisplay(token.mDisplayId);
+ final DisplayContent display = getDisplayContent(token.mDisplayId);
if (display != null) {
display.mAllSleepTokens.remove(token);
if (display.mAllSleepTokens.isEmpty()) {
@@ -1717,8 +1712,8 @@
}
void scheduleDestroyAllActivities(WindowProcessController app, String reason) {
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+ for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+ final DisplayContent display = mDisplayContents.get(displayNdx);
for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getStackAt(stackNdx);
stack.scheduleDestroyActivities(app, reason);
@@ -1730,8 +1725,8 @@
// successfully put to sleep.
boolean putStacksToSleep(boolean allowDelay, boolean shuttingDown) {
boolean allSleep = true;
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+ for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+ final DisplayContent display = mDisplayContents.get(displayNdx);
for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
// Stacks and activities could be removed while putting activities to sleep if
// the app process was gone. This prevents us getting exception by accessing an
@@ -1801,8 +1796,8 @@
}
boolean hasAwakeDisplay() {
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+ for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+ final DisplayContent display = mDisplayContents.get(displayNdx);
if (!display.shouldSleep()) {
return true;
}
@@ -1878,7 +1873,7 @@
return stack;
}
}
- final ActivityDisplay display = getActivityDisplayOrCreate(displayId);
+ final DisplayContent display = getDisplayContentOrCreate(displayId);
if (display != null) {
stack = display.getOrCreateStack(r, options, candidateTask, activityType, onTop);
if (stack != null) {
@@ -1890,7 +1885,7 @@
// Give preference to the stack and display of the input task and activity if they match the
// mode we want to launch into.
stack = null;
- ActivityDisplay display = null;
+ DisplayContent display = null;
if (candidateTask != null) {
stack = candidateTask.getStack();
}
@@ -1948,8 +1943,8 @@
private ActivityStack getValidLaunchStackOnDisplay(int displayId, @NonNull ActivityRecord r,
@Nullable Task candidateTask, @Nullable ActivityOptions options,
@Nullable LaunchParamsController.LaunchParams launchParams) {
- final ActivityDisplay activityDisplay = getActivityDisplayOrCreate(displayId);
- if (activityDisplay == null) {
+ final DisplayContent displayContent = getDisplayContentOrCreate(displayId);
+ if (displayContent == null) {
throw new IllegalArgumentException(
"Display with displayId=" + displayId + " not found.");
}
@@ -1978,12 +1973,12 @@
windowingMode = options != null ? options.getLaunchWindowingMode()
: r.getWindowingMode();
}
- windowingMode = activityDisplay.validateWindowingMode(windowingMode, r, candidateTask,
+ windowingMode = displayContent.validateWindowingMode(windowingMode, r, candidateTask,
r.getActivityType());
// Return the topmost valid stack on the display.
- for (int i = activityDisplay.getStackCount() - 1; i >= 0; --i) {
- final ActivityStack stack = activityDisplay.getStackAt(i);
+ for (int i = displayContent.getStackCount() - 1; i >= 0; --i) {
+ final ActivityStack stack = displayContent.getStackAt(i);
if (isValidLaunchStack(stack, r, windowingMode)) {
return stack;
}
@@ -1994,7 +1989,7 @@
final int activityType =
options != null && options.getLaunchActivityType() != ACTIVITY_TYPE_UNDEFINED
? options.getLaunchActivityType() : r.getActivityType();
- return activityDisplay.createStack(windowingMode, activityType, true /*onTop*/);
+ return displayContent.createStack(windowingMode, activityType, true /*onTop*/);
}
return null;
@@ -2056,11 +2051,11 @@
ActivityStack getNextFocusableStack(@NonNull ActivityStack currentFocus,
boolean ignoreCurrent) {
// First look for next focusable stack on the same display
- ActivityDisplay preferredDisplay = currentFocus.getDisplay();
+ DisplayContent preferredDisplay = currentFocus.getDisplay();
if (preferredDisplay == null) {
// Stack is currently detached because it is being removed. Use the previous display it
// was on.
- preferredDisplay = getActivityDisplay(currentFocus.mPrevDisplayId);
+ preferredDisplay = getDisplayContent(currentFocus.mPrevDisplayId);
}
final ActivityStack preferredFocusableStack = preferredDisplay.getNextFocusableStack(
currentFocus, ignoreCurrent);
@@ -2075,8 +2070,8 @@
}
// Now look through all displays
- for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
- final ActivityDisplay display = mActivityDisplays.get(i);
+ for (int i = mDisplayContents.size() - 1; i >= 0; --i) {
+ final DisplayContent display = mDisplayContents.get(i);
if (display == preferredDisplay) {
// We've already checked this one
continue;
@@ -2102,8 +2097,8 @@
* @return Next valid {@link ActivityStack}, null if not found.
*/
ActivityStack getNextValidLaunchStack(@NonNull ActivityRecord r, int currentFocus) {
- for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
- final ActivityDisplay display = mActivityDisplays.get(i);
+ for (int i = mDisplayContents.size() - 1; i >= 0; --i) {
+ final DisplayContent display = mDisplayContents.get(i);
if (display.mDisplayId == currentFocus) {
continue;
}
@@ -2118,8 +2113,8 @@
boolean handleAppDied(WindowProcessController app) {
boolean hasVisibleActivities = false;
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+ for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+ final DisplayContent display = mDisplayContents.get(displayNdx);
for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getStackAt(stackNdx);
hasVisibleActivities |= stack.handleAppDiedLocked(app);
@@ -2231,8 +2226,8 @@
}
void finishVoiceTask(IVoiceInteractionSession session) {
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+ for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+ final DisplayContent display = mDisplayContents.get(displayNdx);
final int numStacks = display.getStackCount();
for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
final ActivityStack stack = display.getStackAt(stackNdx);
@@ -2246,20 +2241,20 @@
* ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
*/
void removeStacksInWindowingModes(int... windowingModes) {
- for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
- mActivityDisplays.get(i).removeStacksInWindowingModes(windowingModes);
+ for (int i = mDisplayContents.size() - 1; i >= 0; --i) {
+ mDisplayContents.get(i).removeStacksInWindowingModes(windowingModes);
}
}
void removeStacksWithActivityTypes(int... activityTypes) {
- for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
- mActivityDisplays.get(i).removeStacksWithActivityTypes(activityTypes);
+ for (int i = mDisplayContents.size() - 1; i >= 0; --i) {
+ mDisplayContents.get(i).removeStacksWithActivityTypes(activityTypes);
}
}
ActivityRecord topRunningActivity() {
- for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
- final ActivityRecord topActivity = mActivityDisplays.get(i).topRunningActivity();
+ for (int i = mDisplayContents.size() - 1; i >= 0; --i) {
+ final ActivityRecord topActivity = mDisplayContents.get(i).topRunningActivity();
if (topActivity != null) {
return topActivity;
}
@@ -2268,9 +2263,9 @@
}
boolean allResumedActivitiesIdle() {
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+ for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
// TODO(b/117135575): Check resumed activities on all visible stacks.
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+ final DisplayContent display = mDisplayContents.get(displayNdx);
if (display.isSleeping()) {
// No resumed activities while display is sleeping.
continue;
@@ -2298,8 +2293,8 @@
boolean allResumedActivitiesVisible() {
boolean foundResumed = false;
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+ for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+ final DisplayContent display = mDisplayContents.get(displayNdx);
for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getStackAt(stackNdx);
final ActivityRecord r = stack.getResumedActivity();
@@ -2316,8 +2311,8 @@
boolean allPausedActivitiesComplete() {
boolean pausing = true;
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+ for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+ final DisplayContent display = mDisplayContents.get(displayNdx);
for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getStackAt(stackNdx);
final ActivityRecord r = stack.mPausingActivity;
@@ -2381,8 +2376,8 @@
}
void cancelInitializingActivities() {
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+ for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+ final DisplayContent display = mDisplayContents.get(displayNdx);
for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getStackAt(stackNdx);
stack.cancelInitializingActivities();
@@ -2467,9 +2462,9 @@
}
ActivityRecord isInAnyStack(IBinder token) {
- int numDisplays = mActivityDisplays.size();
+ int numDisplays = mDisplayContents.size();
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+ final DisplayContent display = mDisplayContents.get(displayNdx);
for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getStackAt(stackNdx);
final ActivityRecord r = stack.isInStackLocked(token);
@@ -2503,9 +2498,9 @@
// activity on all displays, or if there are no resumed activities in the system.
boolean noResumedActivities = true;
boolean allFocusedProcessesDiffer = true;
- for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) {
- final ActivityDisplay activityDisplay = mActivityDisplays.get(displayNdx);
- final ActivityRecord resumedActivity = activityDisplay.getResumedActivity();
+ for (int displayNdx = 0; displayNdx < mDisplayContents.size(); ++displayNdx) {
+ final DisplayContent displayContent = mDisplayContents.get(displayNdx);
+ final ActivityRecord resumedActivity = displayContent.getResumedActivity();
final WindowProcessController resumedActivityProcess =
resumedActivity == null ? null : resumedActivity.app;
@@ -2550,9 +2545,9 @@
return getTopDisplayFocusedStack().getDumpActivitiesLocked(name);
} else {
ArrayList<ActivityRecord> activities = new ArrayList<>();
- int numDisplays = mActivityDisplays.size();
+ int numDisplays = mDisplayContents.size();
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+ final DisplayContent display = mDisplayContents.get(displayNdx);
for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getStackAt(stackNdx);
if (!dumpVisibleStacksOnly || stack.shouldBeVisible(null)) {
@@ -2567,9 +2562,9 @@
public void dump(PrintWriter pw, String prefix) {
pw.print(prefix);
pw.println("topDisplayFocusedStack=" + getTopDisplayFocusedStack());
- for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
- final ActivityDisplay display = mActivityDisplays.get(i);
- display.dump(pw, prefix);
+ for (int i = mDisplayContents.size() - 1; i >= 0; --i) {
+ final DisplayContent display = mDisplayContents.get(i);
+ display.dump(pw, prefix, true /* dumpAll */);
}
}
@@ -2579,17 +2574,17 @@
*/
void dumpDisplayConfigs(PrintWriter pw, String prefix) {
pw.print(prefix); pw.println("Display override configurations:");
- final int displayCount = mActivityDisplays.size();
+ final int displayCount = mDisplayContents.size();
for (int i = 0; i < displayCount; i++) {
- final ActivityDisplay activityDisplay = mActivityDisplays.get(i);
- pw.print(prefix); pw.print(" "); pw.print(activityDisplay.mDisplayId); pw.print(": ");
- pw.println(activityDisplay.getRequestedOverrideConfiguration());
+ final DisplayContent displayContent = mDisplayContents.get(i);
+ pw.print(prefix); pw.print(" "); pw.print(displayContent.mDisplayId); pw.print(": ");
+ pw.println(displayContent.getRequestedOverrideConfiguration());
}
}
public void dumpDisplays(PrintWriter pw) {
- for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
- final ActivityDisplay display = mActivityDisplays.get(i);
+ for (int i = mDisplayContents.size() - 1; i >= 0; --i) {
+ final DisplayContent display = mDisplayContents.get(i);
pw.print("[id:" + display.mDisplayId + " stacks:");
display.dumpStacks(pw);
pw.print("]");
@@ -2600,18 +2595,18 @@
String dumpPackage) {
boolean printed = false;
boolean needSep = false;
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- ActivityDisplay activityDisplay = mActivityDisplays.get(displayNdx);
- pw.print("Display #"); pw.print(activityDisplay.mDisplayId);
+ for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+ DisplayContent displayContent = mDisplayContents.get(displayNdx);
+ pw.print("Display #"); pw.print(displayContent.mDisplayId);
pw.println(" (activities from top to bottom):");
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+ final DisplayContent display = mDisplayContents.get(displayNdx);
for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getStackAt(stackNdx);
pw.println();
printed = stack.dump(fd, pw, dumpAll, dumpClient, dumpPackage, needSep);
needSep = printed;
}
- printThisActivity(pw, activityDisplay.getResumedActivity(), dumpPackage, needSep,
+ printThisActivity(pw, displayContent.getResumedActivity(), dumpPackage, needSep,
" ResumedActivity:");
}
@@ -2632,9 +2627,9 @@
@WindowTraceLogLevel int logLevel) {
final long token = proto.start(fieldId);
super.dumpDebug(proto, CONFIGURATION_CONTAINER, logLevel);
- for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) {
- final ActivityDisplay activityDisplay = mActivityDisplays.get(displayNdx);
- activityDisplay.dumpDebug(proto, DISPLAYS, logLevel);
+ for (int displayNdx = 0; displayNdx < mDisplayContents.size(); ++displayNdx) {
+ final DisplayContent displayContent = mDisplayContents.get(displayNdx);
+ displayContent.dumpDebug(proto, DISPLAYS, logLevel);
}
mStackSupervisor.getKeyguardController().dumpDebug(proto, KEYGUARD_CONTROLLER);
// TODO(b/111541062): Update tests to look for resumed activities on all displays
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 0e07e52..1b2274a 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -135,7 +135,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.util.ToBooleanFunction;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.pooled.PooledConsumer;
import com.android.internal.util.function.pooled.PooledFunction;
@@ -1583,8 +1582,8 @@
if (!inPinnedWindowingMode() && mStack != null) {
final int defaultMinSizeDp =
mAtmService.mRootActivityContainer.mDefaultMinSizeOfResizeableTaskDp;
- final ActivityDisplay display =
- mAtmService.mRootActivityContainer.getActivityDisplay(mStack.mDisplayId);
+ final DisplayContent display =
+ mAtmService.mRootActivityContainer.getDisplayContent(mStack.mDisplayId);
final float density =
(float) display.getConfiguration().densityDpi / DisplayMetrics.DENSITY_DEFAULT;
final int defaultMinSize = (int) (defaultMinSizeDp * density);
@@ -1995,7 +1994,7 @@
((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT;
final Rect parentBounds =
new Rect(newParentConfig.windowConfiguration.getBounds());
- final ActivityDisplay display = mStack.getDisplay();
+ final DisplayContent display = mStack.getDisplay();
if (display != null && display.mDisplayContent != null) {
// If a freeform window moves below system bar, there is no way to move it again
// by touch. Because its caption is covered by system bar. So we exclude them
@@ -2188,7 +2187,7 @@
final ActivityStack prevStack = getTaskStack();
final boolean wasTopFocusedStack =
mAtmService.mRootActivityContainer.isTopDisplayFocusedStack(prevStack);
- final ActivityDisplay prevStackDisplay = prevStack.getDisplay();
+ final DisplayContent prevStackDisplay = prevStack.getDisplay();
position = stack.findPositionForTask(this, position, showForAllUsers());
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 9d19cfe..4de61f0 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -137,7 +137,7 @@
// STEP 1: Determine the display to launch the activity/task.
final int displayId = getPreferredLaunchDisplay(task, options, source, currentParams);
outParams.mPreferredDisplayId = displayId;
- ActivityDisplay display = mSupervisor.mRootActivityContainer.getActivityDisplay(displayId);
+ DisplayContent display = mSupervisor.mRootActivityContainer.getDisplayContent(displayId);
if (DEBUG) {
appendLog("display-id=" + outParams.mPreferredDisplayId + " display-windowing-mode="
+ display.getWindowingMode());
@@ -282,7 +282,7 @@
if (source != null && source.inFreeformWindowingMode()
&& resolvedMode == WINDOWING_MODE_FREEFORM
&& outParams.mBounds.isEmpty()
- && source.getDisplayId() == display.mDisplayId) {
+ && source.getDisplayId() == display.getDisplayId()) {
// Set bounds to be not very far from source activity.
cascadeBounds(source.getConfiguration().windowConfiguration.getBounds(),
display, outParams.mBounds);
@@ -333,17 +333,17 @@
}
if (displayId != INVALID_DISPLAY
- && mSupervisor.mRootActivityContainer.getActivityDisplay(displayId) == null) {
+ && mSupervisor.mRootActivityContainer.getDisplayContent(displayId) == null) {
displayId = currentParams.mPreferredDisplayId;
}
displayId = (displayId == INVALID_DISPLAY) ? currentParams.mPreferredDisplayId : displayId;
return (displayId != INVALID_DISPLAY
- && mSupervisor.mRootActivityContainer.getActivityDisplay(displayId) != null)
+ && mSupervisor.mRootActivityContainer.getDisplayContent(displayId) != null)
? displayId : DEFAULT_DISPLAY;
}
- private boolean canInheritWindowingModeFromSource(@NonNull ActivityDisplay display,
+ private boolean canInheritWindowingModeFromSource(@NonNull DisplayContent display,
@Nullable ActivityRecord source) {
if (source == null) {
return false;
@@ -365,10 +365,10 @@
// Only inherit windowing mode if both source and target activities are on the same display.
// Otherwise we may have unintended freeform windows showing up if an activity in freeform
// window launches an activity on a fullscreen display by specifying display ID.
- return display.mDisplayId == source.getDisplayId();
+ return display.getDisplayId() == source.getDisplayId();
}
- private boolean canApplyFreeformWindowPolicy(@NonNull ActivityDisplay display, int launchMode) {
+ private boolean canApplyFreeformWindowPolicy(@NonNull DisplayContent display, int launchMode) {
return mSupervisor.mService.mSupportsFreeformWindowManagement
&& (display.inFreeformWindowingMode() || launchMode == WINDOWING_MODE_FREEFORM);
}
@@ -378,7 +378,7 @@
&& launchMode == WINDOWING_MODE_PINNED;
}
- private void getLayoutBounds(@NonNull ActivityDisplay display, @NonNull ActivityRecord root,
+ private void getLayoutBounds(@NonNull DisplayContent display, @NonNull ActivityRecord root,
@NonNull ActivityInfo.WindowLayout windowLayout, @NonNull Rect outBounds) {
final int verticalGravity = windowLayout.gravity & Gravity.VERTICAL_GRAVITY_MASK;
final int horizontalGravity = windowLayout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
@@ -488,7 +488,7 @@
return orientation;
}
- private void cascadeBounds(@NonNull Rect srcBounds, @NonNull ActivityDisplay display,
+ private void cascadeBounds(@NonNull Rect srcBounds, @NonNull DisplayContent display,
@NonNull Rect outBounds) {
outBounds.set(srcBounds);
float density = (float) display.getConfiguration().densityDpi / DENSITY_DEFAULT;
@@ -500,7 +500,7 @@
outBounds.offset(dx, dy);
}
- private void getTaskBounds(@NonNull ActivityRecord root, @NonNull ActivityDisplay display,
+ private void getTaskBounds(@NonNull ActivityRecord root, @NonNull DisplayContent display,
@NonNull ActivityInfo.WindowLayout layout, int resolvedMode, boolean hasInitialBounds,
@NonNull Rect inOutBounds) {
if (resolvedMode == WINDOWING_MODE_FULLSCREEN) {
@@ -567,7 +567,7 @@
}
}
- private int resolveOrientation(@NonNull ActivityRecord root, @NonNull ActivityDisplay display,
+ private int resolveOrientation(@NonNull ActivityRecord root, @NonNull DisplayContent display,
@NonNull Rect bounds) {
int orientation = resolveOrientation(root);
@@ -593,7 +593,7 @@
return orientation;
}
- private void getDefaultFreeformSize(@NonNull ActivityDisplay display,
+ private void getDefaultFreeformSize(@NonNull DisplayContent display,
@NonNull ActivityInfo.WindowLayout layout, int orientation, @NonNull Rect bounds) {
// Default size, which is letterboxing/pillarboxing in display. That's to say the large
// dimension of default size is the small dimension of display size, and the small dimension
@@ -637,7 +637,7 @@
* Gets centered bounds of width x height. If inOutBounds is not empty, the result bounds
* centers at its center or display's app bounds center if inOutBounds is empty.
*/
- private void centerBounds(@NonNull ActivityDisplay display, int width, int height,
+ private void centerBounds(@NonNull DisplayContent display, int width, int height,
@NonNull Rect inOutBounds) {
if (inOutBounds.isEmpty()) {
inOutBounds.set(display.mDisplayContent.mDisplayFrames.mStable);
@@ -647,7 +647,7 @@
inOutBounds.set(left, top, left + width, top + height);
}
- private void adjustBoundsToFitInDisplay(@NonNull ActivityDisplay display,
+ private void adjustBoundsToFitInDisplay(@NonNull DisplayContent display,
@NonNull Rect inOutBounds) {
final Rect displayStableBounds = display.mDisplayContent.mDisplayFrames.mStable;
@@ -702,7 +702,7 @@
* @param display the display which tasks are to check
* @param inOutBounds the bounds used to input initial bounds and output result bounds
*/
- private void adjustBoundsToAvoidConflictInDisplay(@NonNull ActivityDisplay display,
+ private void adjustBoundsToAvoidConflictInDisplay(@NonNull DisplayContent display,
@NonNull Rect inOutBounds) {
final List<Rect> taskBoundsToCheck = new ArrayList<>();
for (int i = 0; i < display.getStackCount(); ++i) {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotCache.java b/services/core/java/com/android/server/wm/TaskSnapshotCache.java
index 5cbab5d..7b0d841 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotCache.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotCache.java
@@ -109,7 +109,7 @@
removeRunningEntry(taskId);
}
- private void removeRunningEntry(int taskId) {
+ void removeRunningEntry(int taskId) {
final CacheEntry entry = mRunningCache.get(taskId);
if (entry != null) {
mAppTaskMap.remove(entry.topApp);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index f5b46f4..dee9e9f 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -171,22 +171,30 @@
}
void snapshotTasks(ArraySet<Task> tasks) {
+ snapshotTasks(mTmpTasks, false /* allowSnapshotHome */);
+ }
+
+ private void snapshotTasks(ArraySet<Task> tasks, boolean allowSnapshotHome) {
for (int i = tasks.size() - 1; i >= 0; i--) {
final Task task = tasks.valueAt(i);
- final int mode = getSnapshotMode(task);
final TaskSnapshot snapshot;
- switch (mode) {
- case SNAPSHOT_MODE_NONE:
- continue;
- case SNAPSHOT_MODE_APP_THEME:
- snapshot = drawAppThemeSnapshot(task);
- break;
- case SNAPSHOT_MODE_REAL:
- snapshot = snapshotTask(task);
- break;
- default:
- snapshot = null;
- break;
+ final boolean snapshotHome = allowSnapshotHome && task.isActivityTypeHome();
+ if (snapshotHome) {
+ snapshot = snapshotTask(task);
+ } else {
+ switch (getSnapshotMode(task)) {
+ case SNAPSHOT_MODE_NONE:
+ continue;
+ case SNAPSHOT_MODE_APP_THEME:
+ snapshot = drawAppThemeSnapshot(task);
+ break;
+ case SNAPSHOT_MODE_REAL:
+ snapshot = snapshotTask(task);
+ break;
+ default:
+ snapshot = null;
+ break;
+ }
}
if (snapshot != null) {
final GraphicBuffer buffer = snapshot.getSnapshot();
@@ -196,8 +204,11 @@
+ buffer.getHeight());
} else {
mCache.putSnapshot(task, snapshot);
- mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
- task.onSnapshotChanged(snapshot);
+ // Don't persist or notify the change for the temporal snapshot.
+ if (!snapshotHome) {
+ mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
+ task.onSnapshotChanged(snapshot);
+ }
}
}
}
@@ -450,6 +461,10 @@
mPersister.onTaskRemovedFromRecents(taskId, userId);
}
+ void removeSnapshotCache(int taskId) {
+ mCache.removeRunningEntry(taskId);
+ }
+
/**
* See {@link TaskSnapshotPersister#removeObsoleteFiles}
*/
@@ -485,7 +500,9 @@
mTmpTasks.add(task);
}
});
- snapshotTasks(mTmpTasks);
+ // Allow taking snapshot of home when turning screen off to reduce the delay of
+ // unlocking/waking to home.
+ snapshotTasks(mTmpTasks, true /* allowSnapshotHome */);
}
} finally {
listener.onScreenOff();
diff --git a/services/core/java/com/android/server/wm/WindowManagerConstants.java b/services/core/java/com/android/server/wm/WindowManagerConstants.java
index 10c8ef0..74d5c04 100644
--- a/services/core/java/com/android/server/wm/WindowManagerConstants.java
+++ b/services/core/java/com/android/server/wm/WindowManagerConstants.java
@@ -19,6 +19,8 @@
import static android.provider.AndroidDeviceConfig.KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE;
import static android.provider.AndroidDeviceConfig.KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
import android.provider.AndroidDeviceConfig;
import android.provider.DeviceConfig;
@@ -72,8 +74,8 @@
WindowManagerConstants(WindowManagerGlobalLock globalLock,
Runnable updateSystemGestureExclusionCallback,
DeviceConfigInterface deviceConfig) {
- mGlobalLock = globalLock;
- mUpdateSystemGestureExclusionCallback = updateSystemGestureExclusionCallback;
+ mGlobalLock = checkNotNull(globalLock);
+ mUpdateSystemGestureExclusionCallback = checkNotNull(updateSystemGestureExclusionCallback);
mDeviceConfig = deviceConfig;
mListenerAndroid = this::onAndroidPropertiesChanged;
mListenerWindowManager = this::onWindowPropertiesChanged;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b9f7ab3..acaaed9 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -405,8 +405,7 @@
private static final int ANIMATION_COMPLETED_TIMEOUT_MS = 5000;
- final WindowManagerConstants mConstants = new WindowManagerConstants(this,
- DeviceConfigInterface.REAL);
+ final WindowManagerConstants mConstants;
final WindowTracing mWindowTracing;
@@ -1232,6 +1231,7 @@
mHighRefreshRateBlacklist = HighRefreshRateBlacklist.create(context.getResources());
+ mConstants = new WindowManagerConstants(this, DeviceConfigInterface.REAL);
mConstants.start(new HandlerExecutor(mH));
LocalServices.addService(WindowManagerInternal.class, new LocalService());
@@ -1721,7 +1721,7 @@
}
}
- return mAtmService.mRootActivityContainer.getActivityDisplayOrCreate(displayId);
+ return mAtmService.mRootActivityContainer.getDisplayContentOrCreate(displayId);
}
private boolean doesAddToastWindowRequireToken(String packageName, int callingUid,
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index ddf8e9b..1a41006 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -575,14 +575,14 @@
return true;
}
- final ActivityDisplay display = activity.getDisplay();
+ final DisplayContent display = activity.getDisplay();
if (display == null) {
// No need to update if the activity hasn't attach to any display.
return false;
}
boolean canUpdate = false;
- final ActivityDisplay topDisplay =
+ final DisplayContent topDisplay =
mPreQTopResumedActivity != null ? mPreQTopResumedActivity.getDisplay() : null;
// Update the topmost activity if current top activity is
// - not on any display OR
@@ -938,15 +938,15 @@
mAtm.mH.sendMessage(m);
}
- void registerDisplayConfigurationListenerLocked(ActivityDisplay activityDisplay) {
- if (activityDisplay == null) {
+ void registerDisplayConfigurationListenerLocked(DisplayContent displayContent) {
+ if (displayContent == null) {
return;
}
// A process can only register to one display to listener to the override configuration
// change. Unregister existing listener if it has one before register the new one.
unregisterDisplayConfigurationListenerLocked();
- mDisplayId = activityDisplay.mDisplayId;
- activityDisplay.registerConfigurationChangeListener(this);
+ mDisplayId = displayContent.mDisplayId;
+ displayContent.registerConfigurationChangeListener(this);
}
@VisibleForTesting
@@ -954,10 +954,10 @@
if (mDisplayId == INVALID_DISPLAY) {
return;
}
- final ActivityDisplay activityDisplay =
- mAtm.mRootActivityContainer.getActivityDisplay(mDisplayId);
- if (activityDisplay != null) {
- activityDisplay.unregisterConfigurationChangeListener(this);
+ final DisplayContent displayContent =
+ mAtm.mRootActivityContainer.getDisplayContent(mDisplayId);
+ if (displayContent != null) {
+ displayContent.unregisterConfigurationChangeListener(this);
}
mDisplayId = INVALID_DISPLAY;
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
index fb9c68a..40ada2a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -30,6 +30,7 @@
import android.apex.ApexInfo;
import android.apex.ApexSessionInfo;
+import android.apex.ApexSessionParams;
import android.apex.IApexService;
import android.content.Context;
import android.content.pm.PackageInfo;
@@ -183,19 +184,18 @@
public void testSubmitStagedSession_throwPackageManagerException() throws RemoteException {
doAnswer(invocation -> {
throw new Exception();
- }).when(mApexService).submitStagedSession(anyInt(), any(), any());
+ }).when(mApexService).submitStagedSession(any(), any());
assertThrows(PackageManagerException.class,
- () -> mApexManager.submitStagedSession(TEST_SESSION_ID, TEST_CHILD_SESSION_ID));
+ () -> mApexManager.submitStagedSession(testParamsWithChildren()));
}
@Test
public void testSubmitStagedSession_throwRunTimeException() throws RemoteException {
- doThrow(RemoteException.class).when(mApexService).submitStagedSession(anyInt(), any(),
- any());
+ doThrow(RemoteException.class).when(mApexService).submitStagedSession(any(), any());
assertThrows(RuntimeException.class,
- () -> mApexManager.submitStagedSession(TEST_SESSION_ID, TEST_CHILD_SESSION_ID));
+ () -> mApexManager.submitStagedSession(testParamsWithChildren()));
}
@Test
@@ -272,6 +272,13 @@
return stagedSessionInfo;
}
+ private static ApexSessionParams testParamsWithChildren() {
+ ApexSessionParams params = new ApexSessionParams();
+ params.sessionId = TEST_SESSION_ID;
+ params.childSessionIds = TEST_CHILD_SESSION_ID;
+ return params;
+ }
+
/**
* Copies a specified {@code resourceId} to a temp file. Returns a non-null file if the copy
* succeeded
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
index 5928641..9c17de9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -47,7 +47,7 @@
import org.junit.runner.RunWith;
/**
- * Tests for the {@link ActivityDisplay} class.
+ * Tests for the {@link DisplayContent} class.
*
* Build/Install/Run:
* atest WmTests:ActivityDisplayTests
@@ -55,12 +55,13 @@
@SmallTest
@Presubmit
@RunWith(WindowTestRunner.class)
+// TODO(b/144248496): Merge to DisplayContentTests
public class ActivityDisplayTests extends ActivityTestsBase {
@Test
public void testLastFocusedStackIsUpdatedWhenMovingStack() {
// Create a stack at bottom.
- final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+ final DisplayContent display = mRootActivityContainer.getDefaultDisplay();
final ActivityStack stack =
new StackBuilder(mRootActivityContainer).setOnTop(!ON_TOP).build();
final ActivityStack prevFocusedStack = display.getFocusedStack();
@@ -103,13 +104,13 @@
}
/**
- * Test {@link ActivityDisplay#mPreferredTopFocusableStack} will be cleared when the stack is
+ * Test {@link DisplayContent#mPreferredTopFocusableStack} will be cleared when the stack is
* removed or moved to back, and the focused stack will be according to z-order.
*/
@Test
public void testStackShouldNotBeFocusedAfterMovingToBackOrRemoving() {
// Create a display which only contains 2 stacks.
- final ActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
+ final DisplayContent display = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
final ActivityStack stack1 = createFullscreenStackWithSimpleActivityAt(display);
final ActivityStack stack2 = createFullscreenStackWithSimpleActivityAt(display);
@@ -128,13 +129,13 @@
}
/**
- * Verifies {@link ActivityDisplay#remove} should not resume home stack on the removing display.
+ * Verifies {@link DisplayContent#remove} should not resume home stack on the removing display.
*/
@Test
public void testNotResumeHomeStackOnRemovingDisplay() {
// Create a display which supports system decoration and allows reparenting stacks to
// another display when the display is removed.
- final ActivityDisplay display = new TestActivityDisplay.Builder(
+ final DisplayContent display = new TestDisplayContent.Builder(
mService, 1000, 1500).setSystemDecorations(true).build();
doReturn(false).when(display).shouldDestroyContentOnRemove();
@@ -154,7 +155,7 @@
verify(homeStack, never()).resumeTopActivityUncheckedLocked(any(), any());
}
- private ActivityStack createFullscreenStackWithSimpleActivityAt(ActivityDisplay display) {
+ private ActivityStack createFullscreenStackWithSimpleActivityAt(DisplayContent display) {
final ActivityStack fullscreenStack = display.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP);
final Task fullscreenTask = new TaskBuilder(mService.mStackSupervisor)
@@ -168,7 +169,7 @@
*/
@Test
public void testTopRunningActivity() {
- final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+ final DisplayContent display = mRootActivityContainer.getDefaultDisplay();
final KeyguardController keyguard = mSupervisor.getKeyguardController();
final ActivityStack stack = new StackBuilder(mRootActivityContainer).build();
final ActivityRecord activity = stack.getTopNonFinishingActivity();
@@ -208,7 +209,7 @@
assertTopRunningActivity(showWhenLockedActivity, display);
}
- private static void assertTopRunningActivity(ActivityRecord top, ActivityDisplay display) {
+ private static void assertTopRunningActivity(ActivityRecord top, DisplayContent display) {
assertEquals(top, display.topRunningActivity());
assertEquals(top, display.topRunningActivity(true /* considerKeyguardState */));
}
@@ -218,7 +219,7 @@
*/
@Test
public void testAlwaysOnTopStackLocation() {
- final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+ final DisplayContent display = mRootActivityContainer.getDefaultDisplay();
final ActivityStack alwaysOnTopStack = display.createStack(WINDOWING_MODE_FREEFORM,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true)
@@ -283,7 +284,7 @@
}
private void removeStackTests(Runnable runnable) {
- final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+ final DisplayContent display = mRootActivityContainer.getDefaultDisplay();
final ActivityStack stack1 = display.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, ON_TOP);
final ActivityStack stack2 = display.createStack(WINDOWING_MODE_FULLSCREEN,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 7a449b3..89723d1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -635,8 +635,8 @@
final ActivityStack stack1 = new StackBuilder(mRootActivityContainer).build();
mStack.moveToFront("test");
// The stack2 is needed here for moving back to simulate the
- // {@link ActivityDisplay#mPreferredTopFocusableStack} is cleared, so
- // {@link ActivityDisplay#getFocusedStack} will rely on the order of focusable-and-visible
+ // {@link DisplayContent#mPreferredTopFocusableStack} is cleared, so
+ // {@link DisplayContent#getFocusedStack} will rely on the order of focusable-and-visible
// stacks. Then when mActivity is finishing, its stack will be invisible (no running
// activities in the stack) that is the key condition to verify.
final ActivityStack stack2 = new StackBuilder(mRootActivityContainer).build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
index 0219539..530adb5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
@@ -112,7 +112,7 @@
@Test
public void testHandleNonResizableTaskOnSecondaryDisplay() {
// Create an unresizable task on secondary display.
- final ActivityDisplay newDisplay = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
+ final DisplayContent newDisplay = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
final ActivityStack stack = new StackBuilder(mRootActivityContainer)
.setDisplay(newDisplay).build();
final ActivityRecord unresizableActivity = stack.getTopNonFinishingActivity();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index 47f454e..8a1a10d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -54,7 +54,6 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import android.content.ComponentName;
@@ -78,7 +77,7 @@
@Presubmit
@RunWith(WindowTestRunner.class)
public class ActivityStackTests extends ActivityTestsBase {
- private ActivityDisplay mDefaultDisplay;
+ private DisplayContent mDefaultDisplay;
private ActivityStack mStack;
private Task mTask;
@@ -279,7 +278,7 @@
@Test
public void testMoveStackToBackIncludingParent() {
- final ActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
+ final DisplayContent display = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
final ActivityStack stack1 = createStackForShouldBeVisibleTest(display,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
final ActivityStack stack2 = createStackForShouldBeVisibleTest(display,
@@ -815,7 +814,7 @@
@SuppressWarnings("TypeParameterUnusedInFormals")
private ActivityStack createStackForShouldBeVisibleTest(
- ActivityDisplay display, int windowingMode, int activityType, boolean onTop) {
+ DisplayContent display, int windowingMode, int activityType, boolean onTop) {
final ActivityStack stack;
if (activityType == ACTIVITY_TYPE_HOME) {
// Home stack and activity are created in ActivityTestsBase#setupActivityManagerService
@@ -998,7 +997,7 @@
@Test
public void testFinishCurrentActivity() {
// Create 2 activities on a new display.
- final ActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
+ final DisplayContent display = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
final ActivityStack stack1 = createStackForShouldBeVisibleTest(display,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
final ActivityStack stack2 = createStackForShouldBeVisibleTest(display,
@@ -1065,6 +1064,7 @@
StackOrderChangedListener listener = new StackOrderChangedListener();
mDefaultDisplay.registerStackOrderChangedListener(listener);
try {
+ mStack.mReparenting = true;
mDefaultDisplay.addStack(mStack, 0);
} finally {
mDefaultDisplay.unregisterStackOrderChangedListener(listener);
@@ -1156,10 +1156,10 @@
private void verifyShouldSleepActivities(boolean focusedStack,
boolean keyguardGoingAway, boolean displaySleeping, boolean expected) {
- final ActivityDisplay display = mock(ActivityDisplay.class);
+ final DisplayContent display = mock(DisplayContent.class);
final KeyguardController keyguardController = mSupervisor.getKeyguardController();
- doReturn(display).when(mRootActivityContainer).getActivityDisplay(anyInt());
+ doReturn(display).when(mStack).getDisplay();
doReturn(keyguardGoingAway).when(keyguardController).isKeyguardGoingAway();
doReturn(displaySleeping).when(display).isSleeping();
doReturn(focusedStack).when(mStack).isFocusedStackOnDisplay();
@@ -1168,7 +1168,7 @@
}
private static class StackOrderChangedListener
- implements ActivityDisplay.OnStackOrderChangedListener {
+ implements DisplayContent.OnStackOrderChangedListener {
public boolean mChanged = false;
@Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 018c10a..7e22dfc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -47,9 +47,9 @@
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.verify;
-import static com.android.server.wm.ActivityDisplay.POSITION_BOTTOM;
-import static com.android.server.wm.ActivityDisplay.POSITION_TOP;
import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
+import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.google.common.truth.Truth.assertThat;
@@ -502,7 +502,7 @@
*/
@Test
public void testTaskModeViolation() {
- final ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
+ final DisplayContent display = mService.mRootActivityContainer.getDefaultDisplay();
display.removeAllTasks();
assertNoTasks(display);
@@ -517,7 +517,7 @@
assertNoTasks(display);
}
- private void assertNoTasks(ActivityDisplay display) {
+ private void assertNoTasks(DisplayContent display) {
for (int i = display.getStackCount() - 1; i >= 0; --i) {
final ActivityStack stack = display.getStackAt(i);
assertFalse(stack.hasChild());
@@ -761,8 +761,8 @@
false /* mockGetLaunchStack */);
// Create a secondary display at bottom.
- final TestActivityDisplay secondaryDisplay =
- new TestActivityDisplay.Builder(mService, 1000, 1500)
+ final TestDisplayContent secondaryDisplay =
+ new TestDisplayContent.Builder(mService, 1000, 1500)
.setPosition(POSITION_BOTTOM).build();
final ActivityStack stack = secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
@@ -800,8 +800,8 @@
false /* mockGetLaunchStack */);
// Create a secondary display with an activity.
- final TestActivityDisplay secondaryDisplay =
- new TestActivityDisplay.Builder(mService, 1000, 1500).build();
+ final TestDisplayContent secondaryDisplay =
+ new TestDisplayContent.Builder(mService, 1000, 1500).build();
mRootActivityContainer.addChild(secondaryDisplay, POSITION_TOP);
final ActivityRecord singleTaskActivity = createSingleTaskActivityOn(
secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
@@ -853,7 +853,7 @@
false /* mockGetLaunchStack */);
// Create a secondary display at bottom.
- final TestActivityDisplay secondaryDisplay = addNewActivityDisplayAt(POSITION_BOTTOM);
+ final TestDisplayContent secondaryDisplay = addNewDisplayContentAt(POSITION_BOTTOM);
secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index 07b7cf4..591ed51 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -126,7 +126,7 @@
assertEquals(0, removed.size());
added.clear();
// Check adding a display
- ActivityDisplay newDisp1 = new TestActivityDisplay.Builder(mService, 600, 800).build();
+ DisplayContent newDisp1 = new TestDisplayContent.Builder(mService, 600, 800).build();
assertEquals(1, added.size());
assertEquals(0, changed.size());
assertEquals(0, removed.size());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index 0021cc5..b72cc94 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -77,9 +77,9 @@
mRootActivityContainer = mService.mRootActivityContainer;
}
- /** Creates and adds a {@link TestActivityDisplay} to supervisor at the given position. */
- TestActivityDisplay addNewActivityDisplayAt(int position) {
- return new TestActivityDisplay.Builder(mService, 1000, 1500).setPosition(position).build();
+ /** Creates and adds a {@link TestDisplayContent} to supervisor at the given position. */
+ TestDisplayContent addNewDisplayContentAt(int position) {
+ return new TestDisplayContent.Builder(mService, 1000, 1500).setPosition(position).build();
}
/** Sets the default minimum task size to 1 so that tests can use small task sizes */
@@ -381,7 +381,7 @@
static class StackBuilder {
private final RootActivityContainer mRootActivityContainer;
- private ActivityDisplay mDisplay;
+ private DisplayContent mDisplay;
private int mStackId = -1;
private int mWindowingMode = WINDOWING_MODE_UNDEFINED;
private int mActivityType = ACTIVITY_TYPE_STANDARD;
@@ -408,15 +408,8 @@
return this;
}
- // TODO(display-merge): Remove
- StackBuilder setDisplay(ActivityDisplay display) {
- mDisplay = display;
- return this;
- }
-
StackBuilder setDisplay(DisplayContent display) {
- // TODO(display-merge): Remove cast
- mDisplay = (ActivityDisplay) display;
+ mDisplay = display;
return this;
}
@@ -449,7 +442,7 @@
if (mOnTop) {
// We move the task to front again in order to regain focus after activity
// added to the stack.
- // Or {@link ActivityDisplay#mPreferredTopFocusableStack} could be other
+ // Or {@link DisplayContent#mPreferredTopFocusableStack} could be other
// stacks (e.g. home stack).
stack.moveToFront("createActivityStack");
} else {
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 6f1e6df..0c7fad4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -181,7 +181,7 @@
@Test
public void testLandscapeSeascapeRotationByPolicy() {
- // This instance has been spied in {@link TestActivityDisplay}.
+ // This instance has been spied in {@link TestDisplayContent}.
final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 14c09eb..ccbafd4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -768,9 +768,8 @@
activity.setRequestedOrientation(newOrientation);
- // TODO(display-merge): Remove cast
- verify((ActivityDisplay) dc, never()).updateDisplayOverrideConfigurationLocked(any(),
- eq(activity), anyBoolean(), same(null));
+ verify(dc, never()).updateDisplayOverrideConfigurationLocked(any(), eq(activity),
+ anyBoolean(), same(null));
assertEquals(dc.getDisplayRotation().getUserRotation(), dc.getRotation());
}
@@ -964,7 +963,7 @@
invocation -> {
continued[0] = true;
return true;
- }).when((ActivityDisplay) dc).updateDisplayOverrideConfigurationLocked();
+ }).when(dc).updateDisplayOverrideConfigurationLocked();
final boolean[] called = new boolean[1];
mWm.mDisplayRotationController =
new IDisplayWindowRotationController.Stub() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
index 9e5d9da..84914bb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
@@ -80,7 +80,7 @@
private TestPersisterQueue mPersisterQueue;
private File mFolder;
- private ActivityDisplay mTestDisplay;
+ private DisplayContent mTestDisplay;
private String mDisplayUniqueId;
private Task mTestTask;
private Task mTaskWithDifferentUser;
@@ -104,9 +104,9 @@
deleteRecursively(mFolder);
mDisplayUniqueId = "test:" + Integer.toString(sNextUniqueId++);
- mTestDisplay = new TestActivityDisplay.Builder(mService, 1000, 1500)
+ mTestDisplay = new TestDisplayContent.Builder(mService, 1000, 1500)
.setUniqueId(mDisplayUniqueId).build();
- when(mRootActivityContainer.getActivityDisplay(eq(mDisplayUniqueId)))
+ when(mRootActivityContainer.getDisplayContent(eq(mDisplayUniqueId)))
.thenReturn(mTestDisplay);
ActivityStack stack = mTestDisplay.createStack(TEST_WINDOWING_MODE,
@@ -180,7 +180,7 @@
public void testReturnsEmptyDisplayIfDisplayIsNotFound() {
mTarget.saveTask(mTestTask);
- when(mRootActivityContainer.getActivityDisplay(eq(mDisplayUniqueId))).thenReturn(null);
+ when(mRootActivityContainer.getDisplayContent(eq(mDisplayUniqueId))).thenReturn(null);
mTarget.getLaunchParams(mTestTask, null, mResult);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 09d7b54..eaf4aa3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -102,7 +102,7 @@
UserManager.USER_TYPE_PROFILE_MANAGED);
private static final int INVALID_STACK_ID = 999;
- private ActivityDisplay mDisplay;
+ private DisplayContent mDisplay;
private ActivityStack mStack;
private TestTaskPersister mTaskPersister;
private TestRecentTasks mRecentTasks;
@@ -117,7 +117,7 @@
public void setUp() throws Exception {
mTaskPersister = new TestTaskPersister(mContext.getFilesDir());
spyOn(mTaskPersister);
- mDisplay = mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY);
+ mDisplay = mRootActivityContainer.getDisplayContent(DEFAULT_DISPLAY);
// Set the recent tasks we should use for testing in this class.
mRecentTasks = new TestRecentTasks(mService, mTaskPersister);
@@ -653,8 +653,8 @@
mRecentTasks.setOnlyTestVisibleRange();
mRecentTasks.setParameters(-1 /* min */, 3 /* max */, -1 /* ms */);
- final ActivityDisplay singleTaskDisplay =
- addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
+ final DisplayContent singleTaskDisplay =
+ addNewDisplayContentAt(DisplayContent.POSITION_TOP);
singleTaskDisplay.setDisplayToSingleTaskInstance();
ActivityStack singleTaskStack = singleTaskDisplay.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
@@ -833,7 +833,7 @@
mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */);
final ActivityStack homeStack = mDisplay.getHomeStack();
- final ActivityDisplay otherDisplay = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
+ final DisplayContent otherDisplay = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
final ActivityStack otherDisplayStack = otherDisplay.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 2374847..945928d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -138,8 +138,7 @@
@Test
public void testIncludedApps_expectTargetAndVisible() {
mWm.setRecentsAnimationController(mController);
- // TODO(display-merge): Remove cast
- final ActivityStack homeStack = ((ActivityDisplay) mDisplayContent).getOrCreateStack(
+ final ActivityStack homeStack = mDisplayContent.getOrCreateStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
final ActivityRecord homeActivity =
new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
@@ -164,8 +163,7 @@
@Test
public void testWallpaperIncluded_expectTarget() throws Exception {
mWm.setRecentsAnimationController(mController);
- // TODO(display-merge): Remove cast
- final ActivityStack homeStack = ((ActivityDisplay) mDisplayContent).getOrCreateStack(
+ final ActivityStack homeStack = mDisplayContent.getOrCreateStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
final ActivityRecord homeAppWindow =
new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
@@ -194,8 +192,7 @@
@Test
public void testWallpaperAnimatorCanceled_expectAnimationKeepsRunning() throws Exception {
mWm.setRecentsAnimationController(mController);
- // TODO(display-merge): Remove cast
- final ActivityStack homeStack = ((ActivityDisplay) mDisplayContent).getOrCreateStack(
+ final ActivityStack homeStack = mDisplayContent.getOrCreateStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
final ActivityRecord homeActivity =
new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
@@ -226,8 +223,7 @@
@Test
public void testFinish_expectTargetAndWallpaperAdaptersRemoved() {
mWm.setRecentsAnimationController(mController);
- // TODO(display-merge): Remove cast
- final ActivityStack homeStack = ((ActivityDisplay) mDisplayContent).getOrCreateStack(
+ final ActivityStack homeStack = mDisplayContent.getOrCreateStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
final ActivityRecord homeActivity =
new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index 8fbb16c..07be3e4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -88,7 +88,7 @@
@Test
public void testRecentsActivityVisiblility() {
- ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+ DisplayContent display = mRootActivityContainer.getDefaultDisplay();
ActivityStack recentsStack = display.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_RECENTS, true /* onTop */);
ActivityRecord recentActivity = new ActivityBuilder(mService)
@@ -116,7 +116,7 @@
@Test
public void testPreloadRecentsActivity() {
- final ActivityDisplay defaultDisplay = mRootActivityContainer.getDefaultDisplay();
+ final DisplayContent defaultDisplay = mRootActivityContainer.getDefaultDisplay();
final ActivityStack homeStack =
defaultDisplay.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
defaultDisplay.positionStackAtTop(homeStack, false /* includingParents */);
@@ -149,7 +149,7 @@
mService.startRecentsActivity(recentsIntent, null /* assistDataReceiver */,
null /* recentsAnimationRunner */);
- ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+ DisplayContent display = mRootActivityContainer.getDefaultDisplay();
ActivityStack recentsStack = display.getStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_RECENTS);
assertThat(recentsStack).isNotNull();
@@ -178,7 +178,7 @@
@Test
public void testRestartRecentsActivity() throws Exception {
// Have a recents activity that is not attached to its process (ActivityRecord.app = null).
- ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+ DisplayContent display = mRootActivityContainer.getDefaultDisplay();
ActivityStack recentsStack = display.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_RECENTS, true /* onTop */);
ActivityRecord recentActivity = new ActivityBuilder(mService).setComponent(
@@ -207,7 +207,7 @@
@Test
public void testSetLaunchTaskBehindOfTargetActivity() {
- ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+ DisplayContent display = mRootActivityContainer.getDefaultDisplay();
display.mDisplayContent.mBoundsAnimationController = mock(BoundsAnimationController.class);
ActivityStack homeStack = display.getHomeStack();
// Assume the home activity support recents.
@@ -253,7 +253,7 @@
@Test
public void testCancelAnimationOnVisibleStackOrderChange() {
- ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
+ DisplayContent display = mService.mRootActivityContainer.getDefaultDisplay();
display.mDisplayContent.mBoundsAnimationController = mock(BoundsAnimationController.class);
ActivityStack fullscreenStack = display.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
@@ -299,7 +299,7 @@
@Test
public void testKeepAnimationOnHiddenStackOrderChange() {
- ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
+ DisplayContent display = mService.mRootActivityContainer.getDefaultDisplay();
ActivityStack fullscreenStack = display.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
new ActivityBuilder(mService)
@@ -335,7 +335,7 @@
@Test
public void testMultipleUserHomeActivity_findUserHomeTask() {
- ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
+ DisplayContent display = mService.mRootActivityContainer.getDefaultDisplay();
ActivityStack homeStack = display.getStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME);
ActivityRecord otherUserHomeActivity = new ActivityBuilder(mService)
.setStack(homeStack)
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index 5417ade..2d45a59 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -128,7 +128,7 @@
mRootActivityContainer.moveActivityToPinnedStack(firstActivity, sourceBounds,
0f /*aspectRatio*/, "initialMove");
- final ActivityDisplay display = mFullscreenStack.getDisplay();
+ final DisplayContent display = mFullscreenStack.getDisplay();
ActivityStack pinnedStack = display.getPinnedStack();
// Ensure a task has moved over.
ensureStackPlacement(pinnedStack, firstActivity);
@@ -166,7 +166,7 @@
@Test
public void testApplySleepTokens() {
- final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+ final DisplayContent display = mRootActivityContainer.getDefaultDisplay();
final KeyguardController keyguard = mSupervisor.getKeyguardController();
final ActivityStack stack = new StackBuilder(mRootActivityContainer)
.setCreateActivity(false)
@@ -202,7 +202,7 @@
false /* expectResumeTopActivity */);
}
- private void verifySleepTokenBehavior(ActivityDisplay display, KeyguardController keyguard,
+ private void verifySleepTokenBehavior(DisplayContent display, KeyguardController keyguard,
ActivityStack stack, boolean displaySleeping, boolean displayShouldSleep,
boolean isFocusedStack, boolean keyguardShowing, boolean expectWakeFromSleep,
boolean expectResumeTopActivity) {
@@ -225,7 +225,7 @@
*/
@Test
public void testRemovingStackOnAppCrash() {
- final ActivityDisplay defaultDisplay = mRootActivityContainer.getDefaultDisplay();
+ final DisplayContent defaultDisplay = mRootActivityContainer.getDefaultDisplay();
final int originalStackCount = defaultDisplay.getStackCount();
final ActivityStack stack = mRootActivityContainer.getDefaultDisplay().createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
@@ -336,7 +336,7 @@
@Test
public void testFindTaskToMoveToFrontWhenRecentsOnTop() {
// Create stack/task on default display.
- final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+ final DisplayContent display = mRootActivityContainer.getDefaultDisplay();
final ActivityStack targetStack = new StackBuilder(mRootActivityContainer)
.setOnTop(false)
.build();
@@ -360,14 +360,14 @@
@Test
public void testFindTaskToMoveToFrontWhenRecentsOnOtherDisplay() {
// Create stack/task on default display.
- final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+ final DisplayContent display = mRootActivityContainer.getDefaultDisplay();
final ActivityStack targetStack = display.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, false /* onTop */);
final Task targetTask = new TaskBuilder(mSupervisor).setStack(targetStack).build();
// Create Recents on secondary display.
- final TestActivityDisplay secondDisplay = addNewActivityDisplayAt(
- ActivityDisplay.POSITION_TOP);
+ final TestDisplayContent secondDisplay = addNewDisplayContentAt(
+ DisplayContent.POSITION_TOP);
final ActivityStack stack = secondDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_RECENTS, true /* onTop */);
final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
@@ -387,7 +387,7 @@
@Test
public void testResumeActivityWhenNonTopmostStackIsTopFocused() {
// Create a stack at bottom.
- final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+ final DisplayContent display = mRootActivityContainer.getDefaultDisplay();
final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, false /* onTop */));
final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
@@ -415,8 +415,9 @@
@Test
public void testResumeFocusedStacksStartsHomeActivity_NoActivities() {
mFullscreenStack.removeIfPossible();
- mService.mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY).getHomeStack().removeIfPossible();
- mService.mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY)
+ mService.mRootActivityContainer.getDisplayContent(DEFAULT_DISPLAY).getHomeStack()
+ .removeIfPossible();
+ mService.mRootActivityContainer.getDisplayContent(DEFAULT_DISPLAY)
.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
doReturn(true).when(mRootActivityContainer).resumeHomeActivity(any(), any(), anyInt());
@@ -437,13 +438,14 @@
@Test
public void testResumeFocusedStacksStartsHomeActivity_ActivityOnSecondaryScreen() {
mFullscreenStack.removeIfPossible();
- mService.mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY).getHomeStack().removeIfPossible();
- mService.mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY)
+ mService.mRootActivityContainer.getDisplayContent(DEFAULT_DISPLAY).getHomeStack()
+ .removeIfPossible();
+ mService.mRootActivityContainer.getDisplayContent(DEFAULT_DISPLAY)
.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
// Create an activity on secondary display.
- final TestActivityDisplay secondDisplay = addNewActivityDisplayAt(
- ActivityDisplay.POSITION_TOP);
+ final TestDisplayContent secondDisplay = addNewDisplayContentAt(
+ DisplayContent.POSITION_TOP);
final ActivityStack stack = secondDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
@@ -467,7 +469,7 @@
@Test
public void testResumeActivityLingeringTransition() {
// Create a stack at top.
- final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+ final DisplayContent display = mRootActivityContainer.getDefaultDisplay();
final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, false /* onTop */));
final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
@@ -487,7 +489,7 @@
@Test
public void testResumeActivityLingeringTransition_notExecuted() {
// Create a stack at bottom.
- final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+ final DisplayContent display = mRootActivityContainer.getDefaultDisplay();
final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, false /* onTop */));
final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
@@ -515,8 +517,8 @@
mockResolveSecondaryHomeActivity();
// Create secondary displays.
- final TestActivityDisplay secondDisplay =
- new TestActivityDisplay.Builder(mService, 1000, 1500)
+ final TestDisplayContent secondDisplay =
+ new TestDisplayContent.Builder(mService, 1000, 1500)
.setSystemDecorations(true).build();
doReturn(true).when(mRootActivityContainer)
@@ -582,8 +584,8 @@
@Test
public void testStartSecondaryHomeOnDisplayWithUserKeyLocked() {
// Create secondary displays.
- final TestActivityDisplay secondDisplay =
- new TestActivityDisplay.Builder(mService, 1000, 1500)
+ final TestDisplayContent secondDisplay =
+ new TestDisplayContent.Builder(mService, 1000, 1500)
.setSystemDecorations(true).build();
// Use invalid user id to let StorageManager.isUserKeyUnlocked() return false.
@@ -608,8 +610,8 @@
@Test
public void testStartSecondaryHomeOnDisplayWithoutSysDecorations() {
// Create secondary displays.
- final TestActivityDisplay secondDisplay =
- new TestActivityDisplay.Builder(mService, 1000, 1500)
+ final TestDisplayContent secondDisplay =
+ new TestDisplayContent.Builder(mService, 1000, 1500)
.setSystemDecorations(false).build();
mRootActivityContainer.startHomeOnDisplay(0 /* userId */, "testStartSecondaryHome",
@@ -831,8 +833,8 @@
@Test
public void testGetLaunchStackWithRealCallerId() {
// Create a non-system owned virtual display.
- final TestActivityDisplay secondaryDisplay =
- new TestActivityDisplay.Builder(mService, 1000, 1500)
+ final TestDisplayContent secondaryDisplay =
+ new TestDisplayContent.Builder(mService, 1000, 1500)
.setType(TYPE_VIRTUAL).setOwnerUid(100).build();
// Create an activity with specify the original launch pid / uid.
diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
index 66f4d2a..b32cb8b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
@@ -57,9 +57,9 @@
@Test
public void testCollectTasksByLastActiveTime() {
// Create a number of stacks with tasks (of incrementing active time)
- final ArrayList<ActivityDisplay> displays = new ArrayList<>();
- final ActivityDisplay display =
- new TestActivityDisplay.Builder(mService, 1000, 2500).build();
+ final ArrayList<DisplayContent> displays = new ArrayList<>();
+ final DisplayContent display =
+ new TestDisplayContent.Builder(mService, 1000, 2500).build();
displays.add(display);
final int numStacks = 2;
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 46f95ed..be0fd2b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -67,7 +67,7 @@
private Task mTask;
private ActivityRecord mActivity;
- private void setUpApp(ActivityDisplay display) {
+ private void setUpApp(DisplayContent display) {
mStack = new StackBuilder(mRootActivityContainer).setDisplay(display).build();
mTask = mStack.getBottomMostTask();
mActivity = mTask.getTopNonFinishingActivity();
@@ -79,7 +79,7 @@
@Test
public void testRestartProcessIfVisible() {
- setUpApp(new TestActivityDisplay.Builder(mService, 1000, 2500).build());
+ setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).build());
doNothing().when(mSupervisor).scheduleRestartTimeout(mActivity);
mActivity.mVisibleRequested = true;
mActivity.setSavedState(null /* savedState */);
@@ -99,7 +99,7 @@
public void testKeepBoundsWhenChangingFromFreeformToFullscreen() {
removeGlobalMinSizeRestriction();
// create freeform display and a freeform app
- ActivityDisplay display = new TestActivityDisplay.Builder(mService, 2000, 1000)
+ DisplayContent display = new TestDisplayContent.Builder(mService, 2000, 1000)
.setCanRotate(false)
.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM).build();
setUpApp(display);
@@ -126,7 +126,7 @@
@Test
public void testFixedAspectRatioBoundsWithDecor() {
final int decorHeight = 200; // e.g. The device has cutout.
- setUpApp(new TestActivityDisplay.Builder(mService, 600, 800)
+ setUpApp(new TestDisplayContent.Builder(mService, 600, 800)
.setNotch(decorHeight).build());
mActivity.info.minAspectRatio = mActivity.info.maxAspectRatio = 1;
@@ -152,11 +152,11 @@
@Test
public void testFixedScreenConfigurationWhenMovingToDisplay() {
- setUpApp(new TestActivityDisplay.Builder(mService, 1000, 2500).build());
+ setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).build());
// Make a new less-tall display with lower density
- final ActivityDisplay newDisplay =
- new TestActivityDisplay.Builder(mService, 1000, 2000)
+ final DisplayContent newDisplay =
+ new TestDisplayContent.Builder(mService, 1000, 2000)
.setDensityDpi(200).build();
mActivity = new ActivityBuilder(mService)
@@ -180,7 +180,7 @@
@Test
public void testFixedScreenBoundsWhenDisplaySizeChanged() {
- setUpApp(new TestActivityDisplay.Builder(mService, 1000, 2500).build());
+ setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).build());
prepareUnresizable(-1f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
assertFalse(mActivity.inSizeCompatMode());
@@ -203,7 +203,7 @@
@Test
public void testLetterboxFullscreenBounds() {
- setUpApp(new TestActivityDisplay.Builder(mService, 1000, 2500).build());
+ setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).build());
// Fill out required fields on default display since WM-side is mocked out
prepareUnresizable(-1.f /* maxAspect */, SCREEN_ORIENTATION_LANDSCAPE);
@@ -213,10 +213,10 @@
@Test
public void testMoveToDifferentOrientDisplay() {
- setUpApp(new TestActivityDisplay.Builder(mService, 1000, 2500).build());
+ setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).build());
- final ActivityDisplay newDisplay =
- new TestActivityDisplay.Builder(mService, 2000, 1000)
+ final DisplayContent newDisplay =
+ new TestDisplayContent.Builder(mService, 2000, 1000)
.setCanRotate(false).build();
prepareUnresizable(-1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
@@ -235,7 +235,7 @@
@Test
public void testFixedOrientRotateCutoutDisplay() {
// Create a display with a notch/cutout
- setUpApp(new TestActivityDisplay.Builder(mService, 1000, 2500).setNotch(60).build());
+ setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).setNotch(60).build());
prepareUnresizable(1.4f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
final Rect origBounds = new Rect(mActivity.getBounds());
@@ -259,7 +259,7 @@
@Test
public void testFixedAspOrientChangeOrient() {
- setUpApp(new TestActivityDisplay.Builder(mService, 1000, 2500).build());
+ setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).build());
prepareUnresizable(1.4f /* maxAspect */, SCREEN_ORIENTATION_LANDSCAPE);
// The display aspect ratio 2.5 > 1.4 (max of activity), so the size is fitted.
@@ -286,7 +286,7 @@
@Test
public void testFixedScreenLayoutSizeBits() {
- setUpApp(new TestActivityDisplay.Builder(mService, 1000, 2500).build());
+ setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).build());
final int fixedScreenLayout = Configuration.SCREENLAYOUT_LONG_NO
| Configuration.SCREENLAYOUT_SIZE_NORMAL
| Configuration.SCREENLAYOUT_COMPAT_NEEDED;
@@ -314,9 +314,9 @@
@Test
public void testResetNonVisibleActivity() {
- setUpApp(new TestActivityDisplay.Builder(mService, 1000, 2500).build());
+ setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).build());
prepareUnresizable(1.5f, SCREEN_ORIENTATION_UNSPECIFIED);
- final ActivityDisplay display = mStack.getDisplay();
+ final DisplayContent display = mStack.getDisplay();
// Resize the display so the activity is in size compatibility mode.
resizeDisplay(display, 900, 1800);
@@ -354,7 +354,7 @@
*/
@Test
public void testHandleActivitySizeCompatMode() {
- setUpApp(new TestActivityDisplay.Builder(mService, 1000, 2000).build());
+ setUpApp(new TestDisplayContent.Builder(mService, 1000, 2000).build());
ActivityRecord activity = mActivity;
activity.setState(ActivityStack.ActivityState.RESUMED, "testHandleActivitySizeCompatMode");
prepareUnresizable(-1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
@@ -412,7 +412,7 @@
ensureActivityConfiguration();
}
- private void resizeDisplay(ActivityDisplay display, int width, int height) {
+ private void resizeDisplay(DisplayContent display, int width, int height) {
final DisplayContent displayContent = display.mDisplayContent;
displayContent.mBaseDisplayWidth = width;
displayContent.mBaseDisplayHeight = height;
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index a172b65..811f46f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -286,13 +286,12 @@
// Mock root, some default display, and home stack.
spyOn(mWmService.mRoot);
- final ActivityDisplay display = mAtmService.mRootActivityContainer.getDefaultDisplay();
+ final DisplayContent display = mAtmService.mRootActivityContainer.getDefaultDisplay();
// Set default display to be in fullscreen mode. Devices with PC feature may start their
// default display in freeform mode but some of tests in WmTests have implicit assumption on
// that the default display is in fullscreen mode.
display.setDisplayWindowingMode(WINDOWING_MODE_FULLSCREEN);
spyOn(display);
- spyOn(display.mDisplayContent);
final ActivityStack homeStack = display.getStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
spyOn(homeStack);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 9a91efe..5aa41eb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -107,7 +107,7 @@
// =============================
@Test
public void testDefaultToPrimaryDisplay() {
- createNewActivityDisplay(WINDOWING_MODE_FREEFORM);
+ createNewDisplayContent(WINDOWING_MODE_FREEFORM);
assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
@@ -127,8 +127,8 @@
@Test
public void testUsesPreviousDisplayIdIfSet() {
- createNewActivityDisplay(WINDOWING_MODE_FREEFORM);
- final TestActivityDisplay display = createNewActivityDisplay(WINDOWING_MODE_FULLSCREEN);
+ createNewDisplayContent(WINDOWING_MODE_FREEFORM);
+ final TestDisplayContent display = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN);
mCurrent.mPreferredDisplayId = display.mDisplayId;
@@ -140,9 +140,9 @@
@Test
public void testUsesSourcesDisplayIdIfSet() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
- final TestActivityDisplay fullscreenDisplay = createNewActivityDisplay(
+ final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
WINDOWING_MODE_FULLSCREEN);
mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -157,9 +157,9 @@
@Test
public void testUsesOptionsDisplayIdIfSet() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
- final TestActivityDisplay fullscreenDisplay = createNewActivityDisplay(
+ final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
WINDOWING_MODE_FULLSCREEN);
mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -176,9 +176,9 @@
@Test
public void testUsesTasksDisplayIdPriorToSourceIfSet() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
- final TestActivityDisplay fullscreenDisplay = createNewActivityDisplay(
+ final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
WINDOWING_MODE_FULLSCREEN);
mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -193,7 +193,7 @@
@Test
public void testUsesTaskDisplayIdIfSet() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
ActivityRecord source = createSourceActivity(freeformDisplay);
@@ -205,9 +205,9 @@
@Test
public void testUsesNoDisplaySourceHandoverDisplayIdIfSet() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
- final TestActivityDisplay fullscreenDisplay = createNewActivityDisplay(
+ final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
WINDOWING_MODE_FULLSCREEN);
mCurrent.mPreferredDisplayId = fullscreenDisplay.mDisplayId;
@@ -227,7 +227,7 @@
// =====================================
@Test
public void testBoundsInOptionsInfersFreeformOnFreeformDisplay() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
final ActivityOptions options = ActivityOptions.makeBasic();
@@ -258,7 +258,7 @@
@Test
public void testInheritsFreeformModeFromSourceOnFullscreenDisplay() {
- final TestActivityDisplay fullscreenDisplay = createNewActivityDisplay(
+ final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
WINDOWING_MODE_FULLSCREEN);
final ActivityRecord source = createSourceActivity(fullscreenDisplay);
source.setWindowingMode(WINDOWING_MODE_FREEFORM);
@@ -272,7 +272,7 @@
@Test
public void testKeepsPictureInPictureLaunchModeInOptions() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
final ActivityOptions options = ActivityOptions.makeBasic();
@@ -289,7 +289,7 @@
@Test
public void testKeepsPictureInPictureLaunchModeWithBoundsInOptions() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
final ActivityOptions options = ActivityOptions.makeBasic();
@@ -321,7 +321,7 @@
@Test
public void testNonEmptyLayoutInfersFreeformOnFreeformDisplay() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -338,7 +338,7 @@
@Test
public void testNonEmptyLayoutInfersFreeformWithEmptySize() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -382,7 +382,7 @@
@Test
public void testRespectsFullyResolvedCurrentParam_Fullscreen() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -397,7 +397,7 @@
@Test
public void testRespectsModeFromFullyResolvedCurrentParam_NonEmptyBounds() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -414,7 +414,7 @@
@Test
public void testForceMaximizesUnresizeableApp() {
mService.mSizeCompatFreeform = false;
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
final ActivityOptions options = ActivityOptions.makeBasic();
@@ -437,7 +437,7 @@
@Test
public void testLaunchesAppInWindowOnFreeformDisplay() {
mService.mSizeCompatFreeform = true;
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
Rect expectedLaunchBounds = new Rect(0, 0, 200, 100);
@@ -494,7 +494,7 @@
@Test
public void testUsesFullscreenWhenRequestedOnFreeformDisplay() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
final ActivityOptions options = ActivityOptions.makeBasic();
@@ -510,7 +510,7 @@
@Test
public void testUsesFreeformByDefaultForPostNApp() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
final ActivityOptions options = ActivityOptions.makeBasic();
@@ -525,7 +525,7 @@
@Test
public void testUsesFreeformByDefaultForPreNResizeableAppWithoutOrientationRequest() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
final ActivityOptions options = ActivityOptions.makeBasic();
@@ -559,7 +559,7 @@
// ===============================
@Test
public void testKeepsBoundsWithPictureInPictureLaunchModeInOptions() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
final ActivityOptions options = ActivityOptions.makeBasic();
@@ -578,7 +578,7 @@
@Test
public void testRespectsLaunchBoundsWithFreeformSourceOnFullscreenDisplay() {
- final TestActivityDisplay fullscreenDisplay = createNewActivityDisplay(
+ final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
WINDOWING_MODE_FULLSCREEN);
final ActivityRecord source = createSourceActivity(fullscreenDisplay);
source.setWindowingMode(WINDOWING_MODE_FREEFORM);
@@ -595,7 +595,7 @@
@Test
public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_LeftGravity() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -611,7 +611,7 @@
@Test
public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_TopGravity() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -627,7 +627,7 @@
@Test
public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_TopLeftGravity() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -644,7 +644,7 @@
@Test
public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_RightGravity() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -660,7 +660,7 @@
@Test
public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_BottomGravity() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -676,7 +676,7 @@
@Test
public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_BottomRightGravity() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -693,7 +693,7 @@
@Test
public void testNonEmptyLayoutBoundsOnFreeformDisplay_CenterToDisplay() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -709,7 +709,7 @@
@Test
public void testNonEmptyLayoutBoundsOnFreeformDisplay_LeftGravity() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -725,7 +725,7 @@
@Test
public void testNonEmptyLayoutBoundsOnFreeformDisplay_TopGravity() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -741,7 +741,7 @@
@Test
public void testNonEmptyLayoutBoundsOnFreeformDisplay_TopLeftGravity() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -757,7 +757,7 @@
@Test
public void testNonEmptyLayoutBoundsOnFreeformDisplay_RightGravity() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -773,7 +773,7 @@
@Test
public void testNonEmptyLayoutBoundsOnFreeformDisplay_BottomGravity() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -789,7 +789,7 @@
@Test
public void testNonEmptyLayoutBoundsOnFreeformDisplay_RightBottomGravity() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -805,7 +805,7 @@
@Test
public void testNonEmptyLayoutFractionBoundsOnFreeformDisplay() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -821,7 +821,7 @@
@Test
public void testRespectBoundsFromFullyResolvedCurrentParam_NonEmptyBounds() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -836,7 +836,7 @@
@Test
public void testReturnBoundsForFullscreenWindowingMode() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -851,7 +851,7 @@
@Test
public void testUsesDisplayOrientationForNoSensorOrientation() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
final ActivityOptions options = ActivityOptions.makeBasic();
@@ -875,7 +875,7 @@
@Test
public void testRespectsAppRequestedOrientation_Landscape() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
final ActivityOptions options = ActivityOptions.makeBasic();
@@ -892,7 +892,7 @@
@Test
public void testRespectsAppRequestedOrientation_Portrait() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
final ActivityOptions options = ActivityOptions.makeBasic();
@@ -909,7 +909,7 @@
@Test
public void testDefaultSizeSmallerThanBigScreen() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
final ActivityOptions options = ActivityOptions.makeBasic();
@@ -933,7 +933,7 @@
@Test
public void testDefaultFreeformSizeCenteredToDisplay() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
final ActivityOptions options = ActivityOptions.makeBasic();
@@ -954,7 +954,7 @@
@Test
public void testCascadesToSourceSizeForFreeform() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
final ActivityOptions options = ActivityOptions.makeBasic();
@@ -981,7 +981,7 @@
@Test
public void testAdjustBoundsToFitDisplay_TopLeftOutOfDisplay() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
final ActivityOptions options = ActivityOptions.makeBasic();
@@ -1003,7 +1003,7 @@
@Test
public void testAdjustBoundsToFitDisplay_BottomRightOutOfDisplay() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
final ActivityOptions options = ActivityOptions.makeBasic();
@@ -1025,7 +1025,7 @@
@Test
public void testAdjustBoundsToFitNewDisplay_LargerThanDisplay() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
final ActivityOptions options = ActivityOptions.makeBasic();
@@ -1052,7 +1052,7 @@
overrideConfig.setLayoutDirection(new Locale("ar", "EG"));
mRootActivityContainer.onRequestedOverrideConfigurationChanged(overrideConfig);
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
final ActivityOptions options = ActivityOptions.makeBasic();
@@ -1073,7 +1073,7 @@
@Test
public void testRespectsLayoutMinDimensions() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
// This test case requires a relatively big app bounds to ensure the default size calculated
@@ -1098,7 +1098,7 @@
@Test
public void testRotatesInPlaceInitialBoundsMismatchOrientation() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
final ActivityOptions options = ActivityOptions.makeBasic();
@@ -1115,7 +1115,7 @@
@Test
public void testShiftsToRightForCloseToLeftBoundsWhenConflict() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
addFreeformTaskTo(freeformDisplay, new Rect(50, 50, 100, 150));
@@ -1132,7 +1132,7 @@
@Test
public void testShiftsToLeftForCloseToRightBoundsWhenConflict() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
addFreeformTaskTo(freeformDisplay, new Rect(1720, 50, 1830, 150));
@@ -1149,7 +1149,7 @@
@Test
public void testShiftsToRightFirstForHorizontallyCenteredAndCloseToTopWhenConflict() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
addFreeformTaskTo(freeformDisplay, new Rect(0, 0, 100, 300));
@@ -1166,7 +1166,7 @@
@Test
public void testShiftsToLeftNoSpaceOnRightForHorizontallyCenteredAndCloseToTopWhenConflict() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
addFreeformTaskTo(freeformDisplay, new Rect(120, 0, 240, 300));
@@ -1183,7 +1183,7 @@
@Test
public void testShiftsToBottomRightFirstForCenteredBoundsWhenConflict() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
addFreeformTaskTo(freeformDisplay, new Rect(120, 0, 240, 100));
@@ -1200,7 +1200,7 @@
@Test
public void testShiftsToTopLeftIfNoSpaceOnBottomRightForCenteredBoundsWhenConflict() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
addFreeformTaskTo(freeformDisplay, new Rect(120, 67, 240, 100));
@@ -1230,7 +1230,7 @@
@Test
public void testAdjustsBoundsToFitInDisplayFullyResolvedBounds() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
mCurrent.mPreferredDisplayId = Display.INVALID_DISPLAY;
@@ -1248,7 +1248,7 @@
@Test
public void testAdjustsBoundsToAvoidConflictFullyResolvedBounds() {
- final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
addFreeformTaskTo(freeformDisplay, new Rect(0, 0, 200, 100));
@@ -1283,7 +1283,7 @@
@Test
public void testNoMultiDisplaySupports() {
final boolean orgValue = mService.mSupportsMultiDisplay;
- final TestActivityDisplay display = createNewActivityDisplay(WINDOWING_MODE_FULLSCREEN);
+ final TestDisplayContent display = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN);
mCurrent.mPreferredDisplayId = display.mDisplayId;
try {
@@ -1296,8 +1296,8 @@
}
}
- private TestActivityDisplay createNewActivityDisplay(int windowingMode) {
- final TestActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
+ private TestDisplayContent createNewDisplayContent(int windowingMode) {
+ final TestDisplayContent display = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
display.setWindowingMode(windowingMode);
display.setBounds(DISPLAY_BOUNDS);
display.getConfiguration().densityDpi = DENSITY_DEFAULT;
@@ -1311,13 +1311,13 @@
return display;
}
- private ActivityRecord createSourceActivity(TestActivityDisplay display) {
+ private ActivityRecord createSourceActivity(TestDisplayContent display) {
final ActivityStack stack = display.createStack(display.getWindowingMode(),
ACTIVITY_TYPE_STANDARD, true);
return new ActivityBuilder(mService).setStack(stack).setCreateTask(true).build();
}
- private void addFreeformTaskTo(TestActivityDisplay display, Rect bounds) {
+ private void addFreeformTaskTo(TestDisplayContent display, Rect bounds) {
final ActivityStack stack = display.createStack(display.getWindowingMode(),
ACTIVITY_TYPE_STANDARD, true);
stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 39e7885..1a18df5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -193,7 +193,7 @@
@FlakyTest(bugId = 137879065)
public void testFitWithinBounds() {
final Rect parentBounds = new Rect(10, 10, 200, 200);
- ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
+ DisplayContent display = mService.mRootActivityContainer.getDefaultDisplay();
ActivityStack stack = display.createStack(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
@@ -232,7 +232,7 @@
@Test
@FlakyTest(bugId = 137879065)
public void testBoundsOnModeChangeFreeformToFullscreen() {
- ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
+ DisplayContent display = mService.mRootActivityContainer.getDefaultDisplay();
ActivityStack stack = new StackBuilder(mRootActivityContainer).setDisplay(display)
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
Task task = stack.getBottomMostTask();
@@ -265,9 +265,9 @@
public void testFullscreenBoundsForcedOrientation() {
final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
final Rect fullScreenBoundsPort = new Rect(0, 0, 1080, 1920);
- ActivityDisplay display = new TestActivityDisplay.Builder(
+ DisplayContent display = new TestDisplayContent.Builder(
mService, fullScreenBounds.width(), fullScreenBounds.height()).build();
- assertTrue(mRootActivityContainer.getActivityDisplay(display.mDisplayId) != null);
+ assertTrue(mRootActivityContainer.getDisplayContent(display.mDisplayId) != null);
// Fix the display orientation to landscape which is the natural rotation (0) for the test
// display.
final DisplayRotation dr = display.mDisplayContent.getDisplayRotation();
@@ -328,7 +328,7 @@
@Test
public void testIgnoresForcedOrientationWhenParentHandles() {
final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
- ActivityDisplay display = new TestActivityDisplay.Builder(
+ DisplayContent display = new TestDisplayContent.Builder(
mService, fullScreenBounds.width(), fullScreenBounds.height()).build();
display.getRequestedOverrideConfiguration().orientation =
@@ -809,7 +809,7 @@
private void testStackBoundsConfiguration(int windowingMode, Rect parentBounds, Rect bounds,
Rect expectedConfigBounds) {
- ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
+ DisplayContent display = mService.mRootActivityContainer.getDefaultDisplay();
ActivityStack stack = display.createStack(windowingMode, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
similarity index 94%
rename from services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java
rename to services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
index 247cd87..325cea7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
@@ -35,11 +35,11 @@
import android.view.DisplayCutout;
import android.view.DisplayInfo;
-class TestActivityDisplay extends ActivityDisplay {
+class TestDisplayContent extends DisplayContent {
private final ActivityStackSupervisor mSupervisor;
- private TestActivityDisplay(ActivityStackSupervisor supervisor, Display display) {
- super(supervisor.mService.mRootActivityContainer, display);
+ private TestDisplayContent(ActivityStackSupervisor supervisor, Display display) {
+ super(display, supervisor.mService.mRootActivityContainer);
// Normally this comes from display-properties as exposed by WM. Without that, just
// hard-code to FULLSCREEN for tests.
setWindowingMode(WINDOWING_MODE_FULLSCREEN);
@@ -140,13 +140,13 @@
mInfo.logicalDensityDpi = dpi;
return this;
}
- TestActivityDisplay build() {
+ TestDisplayContent build() {
final int displayId = SystemServicesTestRule.sNextDisplayId++;
final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
mInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
- final TestActivityDisplay newDisplay;
+ final TestDisplayContent newDisplay;
synchronized (mService.mGlobalLock) {
- newDisplay = new TestActivityDisplay(mService.mStackSupervisor, display);
+ newDisplay = new TestDisplayContent(mService.mStackSupervisor, display);
mService.mRootActivityContainer.addChild(newDisplay, mPosition);
}
// disable the normal system decorations
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index 4d25a83..6108db3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -61,33 +61,33 @@
assertEquals(INVALID_DISPLAY, mWpc.getDisplayId());
// Register to display 1 as a listener.
- TestActivityDisplay testActivityDisplay1 = createTestActivityDisplayInContainer();
- mWpc.registerDisplayConfigurationListenerLocked(testActivityDisplay1);
- assertTrue(testActivityDisplay1.containsListener(mWpc));
- assertEquals(testActivityDisplay1.mDisplayId, mWpc.getDisplayId());
+ TestDisplayContent testDisplayContent1 = createTestDisplayContentInContainer();
+ mWpc.registerDisplayConfigurationListenerLocked(testDisplayContent1);
+ assertTrue(testDisplayContent1.containsListener(mWpc));
+ assertEquals(testDisplayContent1.mDisplayId, mWpc.getDisplayId());
// Move to display 2.
- TestActivityDisplay testActivityDisplay2 = createTestActivityDisplayInContainer();
- mWpc.registerDisplayConfigurationListenerLocked(testActivityDisplay2);
- assertFalse(testActivityDisplay1.containsListener(mWpc));
- assertTrue(testActivityDisplay2.containsListener(mWpc));
- assertEquals(testActivityDisplay2.mDisplayId, mWpc.getDisplayId());
+ TestDisplayContent testDisplayContent2 = createTestDisplayContentInContainer();
+ mWpc.registerDisplayConfigurationListenerLocked(testDisplayContent2);
+ assertFalse(testDisplayContent1.containsListener(mWpc));
+ assertTrue(testDisplayContent2.containsListener(mWpc));
+ assertEquals(testDisplayContent2.mDisplayId, mWpc.getDisplayId());
- // Null ActivityDisplay will not change anything.
+ // Null DisplayContent will not change anything.
mWpc.registerDisplayConfigurationListenerLocked(null);
- assertTrue(testActivityDisplay2.containsListener(mWpc));
- assertEquals(testActivityDisplay2.mDisplayId, mWpc.getDisplayId());
+ assertTrue(testDisplayContent2.containsListener(mWpc));
+ assertEquals(testDisplayContent2.mDisplayId, mWpc.getDisplayId());
// Unregister listener will remove the wpc from registered displays.
mWpc.unregisterDisplayConfigurationListenerLocked();
- assertFalse(testActivityDisplay1.containsListener(mWpc));
- assertFalse(testActivityDisplay2.containsListener(mWpc));
+ assertFalse(testDisplayContent1.containsListener(mWpc));
+ assertFalse(testDisplayContent2.containsListener(mWpc));
assertEquals(INVALID_DISPLAY, mWpc.getDisplayId());
// Unregistration still work even if the display was removed.
- mWpc.registerDisplayConfigurationListenerLocked(testActivityDisplay1);
- assertEquals(testActivityDisplay1.mDisplayId, mWpc.getDisplayId());
- mRootActivityContainer.removeChild(testActivityDisplay1);
+ mWpc.registerDisplayConfigurationListenerLocked(testDisplayContent1);
+ assertEquals(testDisplayContent1.mDisplayId, mWpc.getDisplayId());
+ mRootActivityContainer.removeChild(testDisplayContent1);
mWpc.unregisterDisplayConfigurationListenerLocked();
assertEquals(INVALID_DISPLAY, mWpc.getDisplayId());
}
@@ -129,7 +129,7 @@
orderVerifier.verifyNoMoreInteractions();
}
- private TestActivityDisplay createTestActivityDisplayInContainer() {
- return new TestActivityDisplay.Builder(mService, 1000, 1500).build();
+ private TestDisplayContent createTestDisplayContentInContainer() {
+ return new TestDisplayContent.Builder(mService, 1000, 1500).build();
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 22ba90b..6f53428 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -340,8 +340,8 @@
/** Creates a {@link DisplayContent} and adds it to the system. */
DisplayContent createNewDisplay(DisplayInfo info) {
- final ActivityDisplay display =
- new TestActivityDisplay.Builder(mWm.mAtmService, info).build();
+ final DisplayContent display =
+ new TestDisplayContent.Builder(mWm.mAtmService, info).build();
return display.mDisplayContent;
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index a121974..5a4a3d0 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -9679,7 +9679,8 @@
* {@link android.telephony.ModemActivityInfo} object.
* @hide
*/
- public void requestModemActivityInfo(ResultReceiver result) {
+ @SystemApi
+ public void requestModemActivityInfo(@NonNull ResultReceiver result) {
try {
ITelephony service = getITelephony();
if (service != null) {
diff --git a/tests/ActivityManagerPerfTests/stub-app/Android.bp b/tests/ActivityManagerPerfTests/stub-app/Android.bp
new file mode 100644
index 0000000..a3c1f5b
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/stub-app/Android.bp
@@ -0,0 +1,68 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+ name: "ActivityManagerPerfTestsStubApp1",
+ static_libs: ["ActivityManagerPerfTestsUtils"],
+ srcs: [
+ "src/**/*.java",
+ ],
+ resource_dirs: [
+ "app1/res",
+ "res",
+ ],
+ platform_apis: true,
+ certificate: "platform",
+ aaptflags: [
+ "--rename-manifest-package com.android.stubs.am1",
+ "--auto-add-overlay",
+ ],
+}
+
+android_test_helper_app {
+ name: "ActivityManagerPerfTestsStubApp2",
+ static_libs: ["ActivityManagerPerfTestsUtils"],
+ srcs: [
+ "src/**/*.java",
+ ],
+ resource_dirs: [
+ "app2/res",
+ "res",
+ ],
+ platform_apis: true,
+ certificate: "platform",
+ aaptflags: [
+ "--rename-manifest-package com.android.stubs.am2",
+ "--auto-add-overlay",
+ ],
+}
+
+android_test_helper_app {
+ name: "ActivityManagerPerfTestsStubApp3",
+ static_libs: ["ActivityManagerPerfTestsUtils"],
+ srcs: [
+ "src/**/*.java",
+ ],
+ resource_dirs: [
+ "app3/res",
+ "res",
+ ],
+ platform_apis: true,
+ certificate: "platform",
+ aaptflags: [
+ "--rename-manifest-package com.android.stubs.am3",
+ "--auto-add-overlay",
+ ],
+}
+
diff --git a/tests/ActivityManagerPerfTests/stub-app/AndroidManifest.xml b/tests/ActivityManagerPerfTests/stub-app/AndroidManifest.xml
new file mode 100644
index 0000000..a57f64c
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/stub-app/AndroidManifest.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.stubs.am">
+
+ <uses-permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"/>
+ <application android:label="Android TestCase" >
+ <provider
+ android:authorities="@string/authority"
+ android:name=".TestContentProvider"
+ android:exported="true" />
+ <receiver
+ android:name=".TestBroadcastReceiver"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="com.android.stubs.am.ACTION_BROADCAST_TEST" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </receiver>
+ <service
+ android:name=".InitService"
+ android:exported="true" />
+ <service
+ android:name=".TestService"
+ android:exported="true" />
+ <activity
+ android:name=".TestActivity"
+ android:excludeFromRecents="true"
+ android:turnScreenOn="true"
+ android:launchMode="singleTask">
+ <intent-filter>
+ <action android:name="com.android.stubs.am.ACTION_START_TEST_ACTIVITY" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
+
diff --git a/tests/ActivityManagerPerfTests/stub-app/app1/res/values/config.xml b/tests/ActivityManagerPerfTests/stub-app/app1/res/values/config.xml
new file mode 100644
index 0000000..667472d
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/stub-app/app1/res/values/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="authority" translatable="false">com.android.stubs.am1.testapp</string>
+</resources>
diff --git a/tests/ActivityManagerPerfTests/stub-app/app2/res/values/config.xml b/tests/ActivityManagerPerfTests/stub-app/app2/res/values/config.xml
new file mode 100644
index 0000000..0852735
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/stub-app/app2/res/values/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="authority" translatable="false">com.android.stubs.am2.testapp</string>
+</resources>
diff --git a/tests/ActivityManagerPerfTests/stub-app/app3/res/values/config.xml b/tests/ActivityManagerPerfTests/stub-app/app3/res/values/config.xml
new file mode 100644
index 0000000..6895d72
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/stub-app/app3/res/values/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="authority" translatable="false">com.android.stubs.am3.testapp</string>
+</resources>
diff --git a/tests/ActivityManagerPerfTests/stub-app/res/layout/activity_content.xml b/tests/ActivityManagerPerfTests/stub-app/res/layout/activity_content.xml
new file mode 100644
index 0000000..f79f006
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/stub-app/res/layout/activity_content.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
diff --git a/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/InitService.java b/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/InitService.java
new file mode 100644
index 0000000..18fdc44
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/InitService.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.stubs.am;
+
+import static com.android.frameworks.perftests.am.util.Constants.COMMAND_ACQUIRE_CONTENT_PROVIDER;
+import static com.android.frameworks.perftests.am.util.Constants.COMMAND_BIND_SERVICE;
+import static com.android.frameworks.perftests.am.util.Constants.COMMAND_RELEASE_CONTENT_PROVIDER;
+import static com.android.frameworks.perftests.am.util.Constants.COMMAND_SEND_BROADCAST;
+import static com.android.frameworks.perftests.am.util.Constants.COMMAND_START_ACTIVITY;
+import static com.android.frameworks.perftests.am.util.Constants.COMMAND_STOP_ACTIVITY;
+import static com.android.frameworks.perftests.am.util.Constants.COMMAND_UNBIND_SERVICE;
+
+import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.IContentProvider;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.frameworks.perftests.am.util.Constants;
+import com.android.frameworks.perftests.am.util.ICommandReceiver;
+
+public class InitService extends Service {
+ private static final String TAG = "InitService";
+ public static final boolean VERBOSE = false;
+
+ private static class Stub extends ICommandReceiver.Stub {
+ private final Context mContext;
+ private final Messenger mCallback;
+ private final Handler mHandler;
+ private final Messenger mMessenger;
+ final ArrayMap<String, MyServiceConnection> mServices =
+ new ArrayMap<String, MyServiceConnection>();
+ final ArrayMap<Uri, IContentProvider> mProviders =
+ new ArrayMap<Uri, IContentProvider>();
+
+ Stub(Context context, Messenger callback) {
+ mContext = context;
+ mCallback = callback;
+ HandlerThread thread = new HandlerThread("result handler");
+ thread.start();
+ mHandler = new H(thread.getLooper());
+ mMessenger = new Messenger(mHandler);
+ }
+
+ private class H extends Handler {
+ H(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == Constants.MSG_DEFAULT) {
+ if (VERBOSE) {
+ Log.i(TAG, "H: received seq=" + msg.arg1 + ", result=" + msg.arg2);
+ }
+ sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, msg.arg1, msg.arg2, null);
+ } else if (msg.what == Constants.MSG_UNBIND_DONE) {
+ if (VERBOSE) {
+ Log.i(TAG, "H: received unbind=" + msg.obj);
+ }
+ synchronized (InitService.sStub) {
+ Bundle b = (Bundle) msg.obj;
+ String pkg = b.getString(Constants.EXTRA_SOURCE_PACKAGE, "");
+ MyServiceConnection c = mServices.remove(pkg);
+ if (c != null) {
+ sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, c.mSeq,
+ Constants.RESULT_NO_ERROR, null);
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void sendCommand(int command, int seq, String sourcePackage, String targetPackage,
+ int flags, Bundle bundle) {
+ if (VERBOSE) {
+ Log.i(TAG, "Received command=" + command + ", seq=" + seq + ", from="
+ + sourcePackage + ", to=" + targetPackage + ", flags=" + flags);
+ }
+ switch (command) {
+ case COMMAND_BIND_SERVICE:
+ handleBindService(seq, targetPackage, flags, bundle);
+ break;
+ case COMMAND_UNBIND_SERVICE:
+ handleUnbindService(seq, targetPackage);
+ break;
+ case COMMAND_ACQUIRE_CONTENT_PROVIDER:
+ acquireProvider(seq, bundle.getParcelable(Constants.EXTRA_URI));
+ break;
+ case COMMAND_RELEASE_CONTENT_PROVIDER:
+ releaseProvider(seq, bundle.getParcelable(Constants.EXTRA_URI));
+ break;
+ case COMMAND_SEND_BROADCAST:
+ sendBroadcast(seq, targetPackage);
+ break;
+ case COMMAND_START_ACTIVITY:
+ startActivity(seq, targetPackage);
+ break;
+ case COMMAND_STOP_ACTIVITY:
+ stopActivity(seq, targetPackage);
+ break;
+ }
+ }
+
+ private void handleBindService(int seq, String targetPackage, int flags, Bundle bundle) {
+ Intent intent = new Intent();
+ intent.setClassName(targetPackage, "com.android.stubs.am.TestService");
+ intent.putExtra(Constants.EXTRA_RECEIVER_CALLBACK, mMessenger);
+ if (bundle != null) {
+ intent.putExtras(bundle);
+ }
+ synchronized (this) {
+ if (!mServices.containsKey(targetPackage)) {
+ MyServiceConnection c = new MyServiceConnection(mCallback);
+ c.mSeq = seq;
+ if (!mContext.bindService(intent, c, flags)) {
+ Log.e(TAG, "Unable to bind to service in " + targetPackage);
+ sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, seq,
+ Constants.RESULT_ERROR, null);
+ } else {
+ if (VERBOSE) {
+ Log.i(TAG, "Bind to service " + intent);
+ }
+ mServices.put(targetPackage, c);
+ }
+ } else {
+ sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, seq,
+ Constants.RESULT_NO_ERROR, null);
+ }
+ }
+ }
+
+ private void handleUnbindService(int seq, String target) {
+ MyServiceConnection c = null;
+ synchronized (this) {
+ c = mServices.get(target);
+ }
+ if (c != null) {
+ c.mSeq = seq;
+ mContext.unbindService(c);
+ }
+ }
+
+ private void acquireProvider(int seq, Uri uri) {
+ ContentResolver resolver = mContext.getContentResolver();
+ IContentProvider provider = resolver.acquireProvider(uri);
+ if (provider != null) {
+ synchronized (mProviders) {
+ mProviders.put(uri, provider);
+ }
+ sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, seq,
+ Constants.RESULT_NO_ERROR, null);
+ } else {
+ sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, seq,
+ Constants.RESULT_ERROR, null);
+ }
+ }
+
+ private void releaseProvider(int seq, Uri uri) {
+ ContentResolver resolver = mContext.getContentResolver();
+ IContentProvider provider;
+ synchronized (mProviders) {
+ provider = mProviders.get(uri);
+ }
+ if (provider != null) {
+ resolver.releaseProvider(provider);
+ synchronized (mProviders) {
+ mProviders.remove(uri);
+ }
+ }
+ sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, seq,
+ Constants.RESULT_NO_ERROR, null);
+ }
+
+ private void sendBroadcast(final int seq, String targetPackage) {
+ Intent intent = new Intent(Constants.STUB_ACTION_BROADCAST);
+ intent.setPackage(targetPackage);
+ mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, seq,
+ Constants.RESULT_NO_ERROR, null);
+ }
+ }, null, 0, null, null);
+ }
+
+ private void startActivity(int seq, String targetPackage) {
+ Intent intent = new Intent(Constants.STUB_ACTION_ACTIVITY);
+ intent.setClassName(targetPackage, "com.android.stubs.am.TestActivity");
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ intent.putExtra(Constants.EXTRA_ARG1, seq);
+ intent.putExtra(Constants.EXTRA_RECEIVER_CALLBACK, mMessenger);
+ mContext.startActivity(intent);
+ }
+
+ private void stopActivity(int seq, String targetPackage) {
+ Intent intent = new Intent(Constants.STUB_ACTION_ACTIVITY);
+ intent.setClassName(targetPackage, "com.android.stubs.am.TestActivity");
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ intent.putExtra(Constants.EXTRA_REQ_FINISH_ACTIVITY, true);
+ intent.putExtra(Constants.EXTRA_ARG1, seq);
+ intent.putExtra(Constants.EXTRA_RECEIVER_CALLBACK, mMessenger);
+ mContext.startActivity(intent);
+ }
+ };
+
+ private static void sendResult(Messenger callback, int what, int seq, int result, Object obj) {
+ Message msg = Message.obtain();
+ msg.what = what;
+ msg.arg1 = seq;
+ msg.arg2 = result;
+ msg.obj = obj;
+ try {
+ if (VERBOSE) {
+ Log.i(TAG, "Sending result seq=" + seq + ", result=" + result);
+ }
+ callback.send(msg);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error in sending result back", e);
+ }
+ msg.recycle();
+ }
+
+ private static class MyServiceConnection implements ServiceConnection {
+ private Messenger mCallback;
+ int mSeq;
+
+ MyServiceConnection(Messenger callback) {
+ mCallback = callback;
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, mSeq,
+ Constants.RESULT_NO_ERROR, null);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ synchronized (sStub) {
+ MyServiceConnection c = sStub.mServices.remove(name.getPackageName());
+ if (c != null) {
+ sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, c.mSeq,
+ Constants.RESULT_NO_ERROR, null);
+ }
+ }
+ }
+ }
+
+ private static Stub sStub = null;
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return new Binder();
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ Messenger callback = intent.getParcelableExtra(Constants.EXTRA_RECEIVER_CALLBACK);
+ if (sStub == null) {
+ sStub = new Stub(getApplicationContext(), callback);
+ }
+
+ Bundle extras = new Bundle();
+ extras.putString(Constants.EXTRA_SOURCE_PACKAGE, getPackageName());
+ extras.putBinder(Constants.EXTRA_RECEIVER_CALLBACK, sStub);
+ sendResult(callback, Constants.REPLY_PACKAGE_START_RESULT,
+ intent.getIntExtra(Constants.EXTRA_SEQ, -1), 0, extras);
+ return START_NOT_STICKY;
+ }
+}
diff --git a/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/TestActivity.java b/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/TestActivity.java
new file mode 100644
index 0000000..f7ea356
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/TestActivity.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.stubs.am;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.frameworks.perftests.am.util.Constants;
+
+public class TestActivity extends Activity {
+ private static final String TAG = "TestActivity";
+ private static final boolean VERBOSE = InitService.VERBOSE;
+
+ private Messenger mResultTo;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ if (VERBOSE) {
+ Log.i(TAG, getPackageName() + " onCreate()");
+ }
+ setContentView(R.layout.activity_content);
+ mResultTo = getIntent().getParcelableExtra(Constants.EXTRA_RECEIVER_CALLBACK);
+ }
+
+ @Override
+ public void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ setIntent(intent);
+ mResultTo = intent.getParcelableExtra(Constants.EXTRA_RECEIVER_CALLBACK);
+ if (intent.getBooleanExtra(Constants.EXTRA_REQ_FINISH_ACTIVITY, false)) {
+ if (VERBOSE) {
+ Log.i(TAG, getPackageName() + " finishing activity");
+ }
+ finish();
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ if (VERBOSE) {
+ Log.i(TAG, getPackageName() + " onResume()");
+ }
+ sendResult(Constants.RESULT_NO_ERROR);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (VERBOSE) {
+ Log.i(TAG, getPackageName() + " onDestroy()");
+ }
+ sendResult(Constants.RESULT_NO_ERROR);
+ }
+
+ private void sendResult(int result) {
+ Message msg = Message.obtain();
+ msg.arg1 = getIntent().getIntExtra(Constants.EXTRA_ARG1, -1);
+ msg.arg2 = result;
+ try {
+ mResultTo.send(msg);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error in sending result back", e);
+ }
+ }
+}
diff --git a/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/TestBroadcastReceiver.java b/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/TestBroadcastReceiver.java
new file mode 100644
index 0000000..36c7a0a
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/TestBroadcastReceiver.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.android.stubs.am;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+public class TestBroadcastReceiver extends BroadcastReceiver {
+ private static final String TAG = "TestBroadcastReceiver";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.i(TAG, context.getPackageName() + " received broadcast: " + intent);
+ }
+}
diff --git a/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/TestContentProvider.java b/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/TestContentProvider.java
new file mode 100644
index 0000000..4fdbf1f
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/TestContentProvider.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.stubs.am;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.util.Log;
+
+public class TestContentProvider extends ContentProvider {
+ private static final String TAG = "TestContentProvider";
+ private static final boolean VERBOSE = InitService.VERBOSE;
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ return null;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return null;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public boolean onCreate() {
+ if (VERBOSE) {
+ Log.i(TAG, getContext().getPackageName() + " onCreate()");
+ }
+ return false;
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ return 0;
+ }
+}
diff --git a/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/TestService.java b/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/TestService.java
new file mode 100644
index 0000000..ba220e0
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/TestService.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.stubs.am;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.frameworks.perftests.am.util.Constants;
+
+public class TestService extends Service {
+ private static final String TAG = "TestService";
+ private static final boolean VERBOSE = InitService.VERBOSE;
+
+ private Binder mStub = new Binder();
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ if (VERBOSE) {
+ Log.i(TAG, getPackageName() + " onBind()");
+ }
+ return mStub;
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ if (VERBOSE) {
+ Log.i(TAG, getPackageName() + " onStartCommand()");
+ }
+ return START_NOT_STICKY;
+ }
+
+ @Override
+ public boolean onUnbind(Intent intent) {
+ if (VERBOSE) {
+ Log.i(TAG, getPackageName() + " onUnbind()");
+ }
+ Messenger messenger = intent.getParcelableExtra(Constants.EXTRA_RECEIVER_CALLBACK);
+ Message msg = Message.obtain();
+ msg.what = Constants.MSG_UNBIND_DONE;
+ Bundle b = new Bundle();
+ b.putString(Constants.EXTRA_SOURCE_PACKAGE, getPackageName());
+ msg.obj = b;
+ try {
+ messenger.send(msg);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error in sending result back", e);
+ }
+ return false;
+ }
+}
diff --git a/tests/ActivityManagerPerfTests/tests/AndroidTest.xml b/tests/ActivityManagerPerfTests/tests/AndroidTest.xml
index 76c40b2..475bb82 100644
--- a/tests/ActivityManagerPerfTests/tests/AndroidTest.xml
+++ b/tests/ActivityManagerPerfTests/tests/AndroidTest.xml
@@ -17,6 +17,9 @@
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
<option name="test-file-name" value="ActivityManagerPerfTests.apk"/>
<option name="test-file-name" value="ActivityManagerPerfTestsTestApp.apk"/>
+ <option name="test-file-name" value="ActivityManagerPerfTestsStubApp1.apk"/>
+ <option name="test-file-name" value="ActivityManagerPerfTestsStubApp2.apk"/>
+ <option name="test-file-name" value="ActivityManagerPerfTestsStubApp3.apk"/>
<option name="cleanup-apks" value="true"/>
</target_preparer>
@@ -26,4 +29,4 @@
<option name="package" value="com.android.frameworks.perftests.amtests"/>
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
</test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/OomAdjPerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/OomAdjPerfTest.java
new file mode 100644
index 0000000..1d3ff06
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/OomAdjPerfTest.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworks.perftests.am.tests;
+
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.net.Uri;
+import android.os.HandlerThread;
+import android.perftests.utils.ManualBenchmarkState;
+import android.perftests.utils.PerfManualStatusReporter;
+import android.perftests.utils.TraceMarkParser;
+import android.perftests.utils.TraceMarkParser.TraceMarkLine;
+import android.perftests.utils.TraceMarkParser.TraceMarkSlice;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+
+import com.android.frameworks.perftests.am.util.AtraceUtils;
+import com.android.frameworks.perftests.am.util.TargetPackageUtils;
+import com.android.frameworks.perftests.am.util.Utils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This benchmark test basically manipulates 3 test packages, let them bind to
+ * each other, send broadcast to each other, etc. All of these actions essentially
+ * triggers OomAdjuster to update the oom_adj scores and proc state of them.
+ * In the meanwhile it'll also monitor the atrace output, extract duration between
+ * the start and exit entries of the updateOomAdjLocked, include each of them
+ * into the stats; when there are enough samples in the stats, the test will
+ * stop and output the mean/stddev time spent on the updateOomAdjLocked.
+ */
+@RunWith(JUnit4.class)
+@LargeTest
+public final class OomAdjPerfTest {
+ private static final String TAG = "OomAdjPerfTest";
+ private static final boolean VERBOSE = true;
+
+ private static final String STUB_PACKAGE1_NAME = "com.android.stubs.am1";
+ private static final String STUB_PACKAGE2_NAME = "com.android.stubs.am2";
+ private static final String STUB_PACKAGE3_NAME = "com.android.stubs.am3";
+
+ private static final Uri STUB_PACKAGE1_URI = new Uri.Builder().scheme(
+ ContentResolver.SCHEME_CONTENT).authority("com.android.stubs.am1.testapp").build();
+ private static final Uri STUB_PACKAGE2_URI = new Uri.Builder().scheme(
+ ContentResolver.SCHEME_CONTENT).authority("com.android.stubs.am2.testapp").build();
+ private static final Uri STUB_PACKAGE3_URI = new Uri.Builder().scheme(
+ ContentResolver.SCHEME_CONTENT).authority("com.android.stubs.am3.testapp").build();
+ private static final long NANOS_PER_MICROSECOND = 1000L;
+
+ private static final String ATRACE_CATEGORY = "am";
+ private static final String ATRACE_OOMADJ_PREFIX = "updateOomAdj_";
+
+ @Rule
+ public PerfManualStatusReporter mPerfManualStatusReporter = new PerfManualStatusReporter();
+ private TraceMarkParser mTraceMarkParser = new TraceMarkParser(this::shouldFilterTraceLine);
+ private final ArrayList<Long> mDurations = new ArrayList<Long>();
+ private Context mContext;
+ private HandlerThread mHandlerThread;
+
+ @Before
+ public void setUp() {
+ mContext = InstrumentationRegistry.getTargetContext();
+ mHandlerThread = new HandlerThread("command receiver");
+ mHandlerThread.start();
+ TargetPackageUtils.initCommandResultReceiver(mHandlerThread.getLooper());
+
+ Utils.runShellCommand("cmd deviceidle whitelist +" + STUB_PACKAGE1_NAME);
+ Utils.runShellCommand("cmd deviceidle whitelist +" + STUB_PACKAGE2_NAME);
+ Utils.runShellCommand("cmd deviceidle whitelist +" + STUB_PACKAGE3_NAME);
+ TargetPackageUtils.startStubPackage(mContext, STUB_PACKAGE1_NAME);
+ TargetPackageUtils.startStubPackage(mContext, STUB_PACKAGE2_NAME);
+ TargetPackageUtils.startStubPackage(mContext, STUB_PACKAGE3_NAME);
+ }
+
+ @After
+ public void tearDown() {
+ TargetPackageUtils.stopStubPackage(mContext, STUB_PACKAGE1_NAME);
+ TargetPackageUtils.stopStubPackage(mContext, STUB_PACKAGE2_NAME);
+ TargetPackageUtils.stopStubPackage(mContext, STUB_PACKAGE3_NAME);
+ Utils.runShellCommand("cmd deviceidle whitelist -" + STUB_PACKAGE1_NAME);
+ Utils.runShellCommand("cmd deviceidle whitelist -" + STUB_PACKAGE2_NAME);
+ Utils.runShellCommand("cmd deviceidle whitelist -" + STUB_PACKAGE3_NAME);
+ mHandlerThread.quitSafely();
+ }
+
+ @Test
+ public void testOomAdj() {
+ final AtraceUtils atraceUtils = AtraceUtils.getInstance(
+ InstrumentationRegistry.getInstrumentation());
+ final ManualBenchmarkState state = mPerfManualStatusReporter.getBenchmarkState();
+ atraceUtils.startTrace(ATRACE_CATEGORY);
+ while (state.keepRunning(mDurations)) {
+ runCUJWithOomComputationOnce();
+
+ // Now kick off the trace dump
+ mDurations.clear();
+ atraceUtils.performDump(mTraceMarkParser, this::handleTraceMarkSlices);
+ }
+ atraceUtils.stopTrace();
+ }
+
+ private boolean shouldFilterTraceLine(final TraceMarkLine line) {
+ return line.name.startsWith(ATRACE_OOMADJ_PREFIX);
+ }
+
+ private void handleTraceMarkSlices(String key, List<TraceMarkSlice> slices) {
+ for (TraceMarkSlice slice: slices) {
+ mDurations.add(slice.getDurationInMicroseconds() * NANOS_PER_MICROSECOND);
+ }
+ }
+
+ /**
+ * This tries to mimic a user journey, involes multiple activity/service starts/stop,
+ * the time spent on oom adj computation would be different between all these samples,
+ * but with enough samples, we'll be able to know the overall distribution of the time
+ * spent on it.
+ */
+ private void runCUJWithOomComputationOnce() {
+ // Start activity from package1
+ TargetPackageUtils.startActivity(STUB_PACKAGE1_NAME, STUB_PACKAGE1_NAME);
+ // Start activity from package2
+ TargetPackageUtils.startActivity(STUB_PACKAGE2_NAME, STUB_PACKAGE2_NAME);
+ // Start activity from package3
+ TargetPackageUtils.startActivity(STUB_PACKAGE3_NAME, STUB_PACKAGE3_NAME);
+
+ // Stop activity in package1
+ TargetPackageUtils.stopActivity(STUB_PACKAGE1_NAME, STUB_PACKAGE1_NAME);
+ // Stop activity in package2
+ TargetPackageUtils.stopActivity(STUB_PACKAGE2_NAME, STUB_PACKAGE2_NAME);
+ // Stop activity in package3
+ TargetPackageUtils.stopActivity(STUB_PACKAGE3_NAME, STUB_PACKAGE3_NAME);
+
+ // Bind from package1 to package2
+ TargetPackageUtils.bindService(STUB_PACKAGE1_NAME, STUB_PACKAGE2_NAME,
+ Context.BIND_AUTO_CREATE);
+ // Acquire content provider from package 1 to package3
+ TargetPackageUtils.acquireProvider(STUB_PACKAGE1_NAME, STUB_PACKAGE3_NAME,
+ STUB_PACKAGE3_URI);
+ // Start activity from package1
+ TargetPackageUtils.startActivity(STUB_PACKAGE1_NAME, STUB_PACKAGE1_NAME);
+ // Bind from package2 to package3
+ TargetPackageUtils.bindService(STUB_PACKAGE2_NAME, STUB_PACKAGE3_NAME,
+ Context.BIND_AUTO_CREATE);
+ // Unbind from package 1 to package 2
+ TargetPackageUtils.unbindService(STUB_PACKAGE1_NAME, STUB_PACKAGE2_NAME, 0);
+ // Stop activity in package1
+ TargetPackageUtils.stopActivity(STUB_PACKAGE1_NAME, STUB_PACKAGE1_NAME);
+
+ // Send broadcast to all of them
+ TargetPackageUtils.sendBroadcast(STUB_PACKAGE1_NAME, STUB_PACKAGE1_NAME);
+ TargetPackageUtils.sendBroadcast(STUB_PACKAGE2_NAME, STUB_PACKAGE2_NAME);
+ TargetPackageUtils.sendBroadcast(STUB_PACKAGE3_NAME, STUB_PACKAGE3_NAME);
+
+ // Bind from package1 to package2 again
+ TargetPackageUtils.bindService(STUB_PACKAGE1_NAME, STUB_PACKAGE2_NAME,
+ Context.BIND_AUTO_CREATE);
+ // Create a cycle: package3 to package1
+ TargetPackageUtils.bindService(STUB_PACKAGE3_NAME, STUB_PACKAGE1_NAME,
+ Context.BIND_AUTO_CREATE);
+
+ // Send broadcast to all of them again
+ TargetPackageUtils.sendBroadcast(STUB_PACKAGE1_NAME, STUB_PACKAGE1_NAME);
+ TargetPackageUtils.sendBroadcast(STUB_PACKAGE2_NAME, STUB_PACKAGE2_NAME);
+ TargetPackageUtils.sendBroadcast(STUB_PACKAGE3_NAME, STUB_PACKAGE3_NAME);
+ // Start activity in package3
+ TargetPackageUtils.startActivity(STUB_PACKAGE3_NAME, STUB_PACKAGE3_NAME);
+
+ // Break the cycle: unbind from package3 to package1
+ TargetPackageUtils.unbindService(STUB_PACKAGE3_NAME, STUB_PACKAGE1_NAME, 0);
+
+ // Bind from package3 to package1 with waive priority
+ TargetPackageUtils.bindService(STUB_PACKAGE3_NAME, STUB_PACKAGE1_NAME,
+ Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY);
+ // Release provider connection
+ TargetPackageUtils.releaseProvider(STUB_PACKAGE1_NAME, STUB_PACKAGE3_NAME,
+ STUB_PACKAGE3_URI);
+ // Unbind from package1 to package2
+ TargetPackageUtils.unbindService(STUB_PACKAGE1_NAME, STUB_PACKAGE2_NAME, 0);
+ // Unbind from package2 to packagae3
+ TargetPackageUtils.unbindService(STUB_PACKAGE2_NAME, STUB_PACKAGE3_NAME, 0);
+
+ // Bind from package3 to package2 with BIND_ABOVE_CLIENT
+ TargetPackageUtils.bindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME,
+ Context.BIND_AUTO_CREATE | Context.BIND_ABOVE_CLIENT);
+ // Unbind from package3 to packagae2
+ TargetPackageUtils.unbindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME, 0);
+
+ // Bind from package3 to package2 with BIND_ALLOW_OOM_MANAGEMENT
+ TargetPackageUtils.bindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME,
+ Context.BIND_AUTO_CREATE | Context.BIND_ALLOW_OOM_MANAGEMENT);
+ // Unbind from package3 to packagae2
+ TargetPackageUtils.unbindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME, 0);
+
+ // Bind from package3 to package2 with BIND_IMPORTANT
+ TargetPackageUtils.bindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME,
+ Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT);
+ // Unbind from package3 to packagae2
+ TargetPackageUtils.unbindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME, 0);
+
+ // Bind from package3 to package2 with BIND_NOT_FOREGROUND
+ TargetPackageUtils.bindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME,
+ Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND);
+ // Unbind from package3 to packagae2
+ TargetPackageUtils.unbindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME, 0);
+
+ // Bind from package3 to package2 with BIND_NOT_PERCEPTIBLE
+ TargetPackageUtils.bindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME,
+ Context.BIND_AUTO_CREATE | Context.BIND_NOT_PERCEPTIBLE);
+ // Unbind from package3 to packagae2
+ TargetPackageUtils.unbindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME, 0);
+
+ // Stop activity in package3
+ TargetPackageUtils.stopActivity(STUB_PACKAGE3_NAME, STUB_PACKAGE3_NAME);
+ // Unbind from package3 to package1
+ TargetPackageUtils.unbindService(STUB_PACKAGE3_NAME, STUB_PACKAGE1_NAME, 0);
+ }
+}
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/AtraceUtils.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/AtraceUtils.java
new file mode 100644
index 0000000..fcccfce
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/AtraceUtils.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworks.perftests.am.util;
+
+import android.app.Instrumentation;
+import android.app.UiAutomation;
+import android.os.ParcelFileDescriptor;
+import android.perftests.utils.TraceMarkParser;
+import android.perftests.utils.TraceMarkParser.TraceMarkSlice;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.List;
+import java.util.function.BiConsumer;
+
+// Simplified version of AtraceLogger.
+public class AtraceUtils {
+ private static final String TAG = "AtraceUtils";
+ private static final boolean VERBOSE = true;
+
+ private static final String ATRACE_START = "atrace --async_start -b %d -c %s";
+ private static final String ATRACE_DUMP = "atrace --async_dump";
+ private static final String ATRACE_STOP = "atrace --async_stop";
+ private static final int DEFAULT_ATRACE_BUF_SIZE = 1024;
+
+ private UiAutomation mAutomation;
+ private static AtraceUtils sUtils = null;
+ private boolean mStarted = false;
+
+ private AtraceUtils(Instrumentation instrumentation) {
+ mAutomation = instrumentation.getUiAutomation();
+ }
+
+ public static AtraceUtils getInstance(Instrumentation instrumentation) {
+ if (sUtils == null) {
+ sUtils = new AtraceUtils(instrumentation);
+ }
+ return sUtils;
+ }
+
+ /**
+ * @param categories The list of the categories to trace, separated with space.
+ */
+ public void startTrace(String categories) {
+ synchronized (this) {
+ if (mStarted) {
+ throw new IllegalStateException("atrace already started");
+ }
+ Utils.runShellCommand(String.format(
+ ATRACE_START, DEFAULT_ATRACE_BUF_SIZE, categories));
+ mStarted = true;
+ }
+ }
+
+ public void stopTrace() {
+ synchronized (this) {
+ mStarted = false;
+ Utils.runShellCommand(ATRACE_STOP);
+ }
+ }
+
+ /**
+ * @param parser The function that can accept the buffer of atrace dump and parse it.
+ * @param handler The parse result handler
+ */
+ public void performDump(TraceMarkParser parser,
+ BiConsumer<String, List<TraceMarkSlice>> handler) {
+ parser.reset();
+ try {
+ if (VERBOSE) {
+ Log.i(TAG, "Collecting atrace dump...");
+ }
+ writeDataToBuf(mAutomation.executeShellCommand(ATRACE_DUMP), parser);
+ } catch (IOException e) {
+ Log.e(TAG, "Error in reading dump", e);
+ }
+ parser.forAllSlices(handler);
+ }
+
+ // The given file descriptor here will be closed by this function
+ private void writeDataToBuf(ParcelFileDescriptor pfDescriptor,
+ TraceMarkParser parser) throws IOException {
+ InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(pfDescriptor);
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ parser.visit(line);
+ }
+ }
+ }
+}
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TargetPackageUtils.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TargetPackageUtils.java
index 046dd6b..d7f4d9d 100644
--- a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TargetPackageUtils.java
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TargetPackageUtils.java
@@ -22,12 +22,18 @@
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
-import android.os.ResultReceiver;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
import android.os.SystemClock;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.Pair;
import org.junit.Assert;
@@ -36,6 +42,7 @@
public class TargetPackageUtils {
private static final String TAG = TargetPackageUtils.class.getSimpleName();
+ public static final boolean VERBOSE = true;
public static final String PACKAGE_NAME = "com.android.frameworks.perftests.amteststestapp";
public static final String ACTIVITY_NAME = PACKAGE_NAME + ".TestActivity";
@@ -48,6 +55,12 @@
// Cache for test app's uid, so we only have to query it once.
private static int sTestAppUid = -1;
+ private static final ArrayMap<String, ICommandReceiver> sStubPackages =
+ new ArrayMap<String, ICommandReceiver>();
+ private static final ArrayMap<Integer, CountDownLatch> sCommandLatches =
+ new ArrayMap<Integer, CountDownLatch>();
+ private static int sSeqNum = 0;
+
/**
* Kills the test package synchronously.
*/
@@ -145,5 +158,160 @@
}
}
+ private static boolean isUidRunning(int uid) {
+ return !Utils.runShellCommand(String.format("cmd activity get-uid-state %d", uid))
+ .contains("(NONEXISTENT)");
+ }
+
+ public static void startStubPackage(Context context, String pkgName) {
+ stopStubPackage(context, pkgName);
+ try {
+ Pair<Integer, CountDownLatch> pair = obtainLatch();
+ Intent intent = new Intent();
+ intent.setComponent(new ComponentName(pkgName, Constants.STUB_INIT_SERVICE_NAME));
+ intent.putExtra(Constants.EXTRA_SOURCE_PACKAGE, context.getPackageName());
+ intent.putExtra(Constants.EXTRA_RECEIVER_CALLBACK, sMessenger);
+ intent.putExtra(Constants.EXTRA_SEQ, pair.first);
+ context.startService(intent);
+ Assert.assertTrue("Timeout when waiting for starting package " + pkgName,
+ pair.second.await(AWAIT_SERVICE_CONNECT_MS, TimeUnit.MILLISECONDS));
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static void stopStubPackage(Context context, String pkgName) {
+ final PackageManager pm = context.getPackageManager();
+ try {
+ final int uid = pm.getPackageUid(pkgName, 0);
+ if (isUidRunning(uid)) {
+ ActivityManager am = context.getSystemService(ActivityManager.class);
+ am.forceStopPackage(pkgName);
+ while (isUidRunning(uid)) {
+ SystemClock.sleep(WAIT_TIME_MS);
+ }
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static void initCommandResultReceiver(Looper looper) {
+ if (sMessenger == null) {
+ sMessenger = new Messenger(new H(looper));
+ }
+ }
+
+ private static void onPackageStartResult(int seq, Bundle bundle) {
+ ICommandReceiver receiver = ICommandReceiver.Stub.asInterface(
+ bundle.getBinder(Constants.EXTRA_RECEIVER_CALLBACK));
+ String sourcePkg = bundle.getString(Constants.EXTRA_SOURCE_PACKAGE);
+ sStubPackages.put(sourcePkg, receiver);
+ releaseLatch(seq);
+ }
+
+ private static void onCommandResult(int seq, int result) {
+ Assert.assertTrue("Error in command seq " + seq, result == Constants.RESULT_NO_ERROR);
+ releaseLatch(seq);
+ }
+
+ private static Messenger sMessenger = null;
+ private static class H extends Handler {
+ H(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case Constants.REPLY_PACKAGE_START_RESULT:
+ onPackageStartResult(msg.arg1 /* seq */, (Bundle) msg.obj);
+ break;
+ case Constants.REPLY_COMMAND_RESULT:
+ onCommandResult(msg.arg1, msg.arg2);
+ break;
+ }
+ }
+ }
+
+ private static Pair<Integer, CountDownLatch> obtainLatch() {
+ CountDownLatch latch = new CountDownLatch(1);
+ int seq;
+ synchronized (sCommandLatches) {
+ seq = sSeqNum++;
+ sCommandLatches.put(seq, latch);
+ }
+ return new Pair<>(seq, latch);
+ }
+
+ private static void releaseLatch(int seq) {
+ synchronized (sCommandLatches) {
+ CountDownLatch latch = sCommandLatches.get(seq);
+ if (latch != null) {
+ latch.countDown();
+ sCommandLatches.remove(seq);
+ }
+ }
+ }
+
+ public static void sendCommand(int command, String sourcePackage, String targetPackage,
+ int flags, Bundle bundle, boolean waitForResult) {
+ ICommandReceiver receiver = sStubPackages.get(sourcePackage);
+ Assert.assertTrue("Package hasn't been started: " + sourcePackage, receiver != null);
+ try {
+ Pair<Integer, CountDownLatch> pair = null;
+ if (waitForResult) {
+ pair = obtainLatch();
+ }
+ if (VERBOSE) {
+ Log.i(TAG, "Sending command=" + command + ", seq=" + pair.first + ", from="
+ + sourcePackage + ", to=" + targetPackage + ", flags=" + flags);
+ }
+ receiver.sendCommand(command, pair.first, sourcePackage, targetPackage, flags, bundle);
+ if (waitForResult) {
+ Assert.assertTrue("Timeout when waiting for command " + command + " from "
+ + sourcePackage + " to " + targetPackage,
+ pair.second.await(AWAIT_SERVICE_CONNECT_MS, TimeUnit.MILLISECONDS));
+ }
+ } catch (RemoteException | InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static void bindService(String sourcePackage, String targetPackage, int flags) {
+ sendCommand(Constants.COMMAND_BIND_SERVICE, sourcePackage, targetPackage, flags, null,
+ true);
+ }
+
+ public static void unbindService(String sourcePackage, String targetPackage, int flags) {
+ sendCommand(Constants.COMMAND_UNBIND_SERVICE, sourcePackage, targetPackage, flags, null,
+ true);
+ }
+
+ public static void acquireProvider(String sourcePackage, String targetPackage, Uri uri) {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(Constants.EXTRA_URI, uri);
+ sendCommand(Constants.COMMAND_ACQUIRE_CONTENT_PROVIDER, sourcePackage, targetPackage, 0,
+ bundle, true);
+ }
+
+ public static void releaseProvider(String sourcePackage, String targetPackage, Uri uri) {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(Constants.EXTRA_URI, uri);
+ sendCommand(Constants.COMMAND_RELEASE_CONTENT_PROVIDER, sourcePackage, targetPackage, 0,
+ bundle, true);
+ }
+
+ public static void sendBroadcast(String sourcePackage, String targetPackage) {
+ sendCommand(Constants.COMMAND_SEND_BROADCAST, sourcePackage, targetPackage, 0, null, true);
+ }
+
+ public static void startActivity(String sourcePackage, String targetPackage) {
+ sendCommand(Constants.COMMAND_START_ACTIVITY, sourcePackage, targetPackage, 0, null, true);
+ }
+
+ public static void stopActivity(String sourcePackage, String targetPackage) {
+ sendCommand(Constants.COMMAND_STOP_ACTIVITY, sourcePackage, targetPackage, 0, null, true);
+ }
}
diff --git a/tests/ActivityManagerPerfTests/utils/Android.bp b/tests/ActivityManagerPerfTests/utils/Android.bp
index 300b7ea..766c3ac 100644
--- a/tests/ActivityManagerPerfTests/utils/Android.bp
+++ b/tests/ActivityManagerPerfTests/utils/Android.bp
@@ -18,6 +18,7 @@
srcs: [
"src/**/*.java",
"src/com/android/frameworks/perftests/am/util/ITimeReceiverCallback.aidl",
+ "src/com/android/frameworks/perftests/am/util/ICommandReceiver.aidl",
],
static_libs: [
"androidx.test.rules",
diff --git a/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/Constants.java b/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/Constants.java
index 9b076c5..8e58665 100644
--- a/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/Constants.java
+++ b/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/Constants.java
@@ -30,4 +30,33 @@
public static final String EXTRA_RECEIVER_CALLBACK = "receiver_callback_binder";
public static final String EXTRA_LOOPER_IDLE_CALLBACK = "looper_idle_callback_binder";
+ public static final String EXTRA_SOURCE_PACKAGE = "source_package";
+ public static final String EXTRA_URI = "uri";
+ public static final String EXTRA_REQ_FINISH_ACTIVITY = "req_finish_activity";
+ public static final String EXTRA_SEQ = "seq";
+ public static final String EXTRA_ARG1 = "arg1";
+ public static final String EXTRA_ARG2 = "arg2";
+
+ public static final int RESULT_NO_ERROR = 0;
+ public static final int RESULT_ERROR = 1;
+ public static final String STUB_INIT_SERVICE_NAME = "com.android.stubs.am.InitService";
+
+ public static final int COMMAND_BIND_SERVICE = 1;
+ public static final int COMMAND_UNBIND_SERVICE = 2;
+ public static final int COMMAND_ACQUIRE_CONTENT_PROVIDER = 3;
+ public static final int COMMAND_RELEASE_CONTENT_PROVIDER = 4;
+ public static final int COMMAND_SEND_BROADCAST = 5;
+ public static final int COMMAND_START_ACTIVITY = 6;
+ public static final int COMMAND_STOP_ACTIVITY = 7;
+
+ public static final int MSG_DEFAULT = 0;
+ public static final int MSG_UNBIND_DONE = 1;
+
+ public static final int REPLY_PACKAGE_START_RESULT = 0;
+ public static final int REPLY_COMMAND_RESULT = 1;
+
+ public static final String STUB_ACTION_ACTIVITY =
+ "com.android.stubs.am.ACTION_START_TEST_ACTIVITY";
+ public static final String STUB_ACTION_BROADCAST =
+ "com.android.stubs.am.ACTION_BROADCAST_TEST";
}
diff --git a/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/ICommandReceiver.aidl b/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/ICommandReceiver.aidl
new file mode 100644
index 0000000..59ea761
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/ICommandReceiver.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworks.perftests.am.util;
+
+import android.os.Bundle;
+
+interface ICommandReceiver {
+ oneway void sendCommand(int command, int seq, String sourcePackage, String targetPackage,
+ int flags, in Bundle bundle);
+}