Merge "Add window layout affinity." into rvc-dev am: 7fcb7d59c4 am: 807b8e42df am: 3d0ba25d61 am: a24ecf75a0
Change-Id: I603abe4ab9a8008e3b169d89a3b5933d562a349b
This commit is contained in:
@@ -1222,13 +1222,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
|
||||
dest.writeInt(lockTaskLaunchMode);
|
||||
if (windowLayout != null) {
|
||||
dest.writeInt(1);
|
||||
dest.writeInt(windowLayout.width);
|
||||
dest.writeFloat(windowLayout.widthFraction);
|
||||
dest.writeInt(windowLayout.height);
|
||||
dest.writeFloat(windowLayout.heightFraction);
|
||||
dest.writeInt(windowLayout.gravity);
|
||||
dest.writeInt(windowLayout.minWidth);
|
||||
dest.writeInt(windowLayout.minHeight);
|
||||
windowLayout.writeToParcel(dest);
|
||||
} else {
|
||||
dest.writeInt(0);
|
||||
}
|
||||
@@ -1372,8 +1366,8 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
|
||||
* @attr ref android.R.styleable#AndroidManifestLayout_minHeight
|
||||
*/
|
||||
public static final class WindowLayout {
|
||||
public WindowLayout(int width, float widthFraction, int height, float heightFraction, int gravity,
|
||||
int minWidth, int minHeight) {
|
||||
public WindowLayout(int width, float widthFraction, int height, float heightFraction,
|
||||
int gravity, int minWidth, int minHeight) {
|
||||
this.width = width;
|
||||
this.widthFraction = widthFraction;
|
||||
this.height = height;
|
||||
@@ -1392,6 +1386,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
|
||||
gravity = source.readInt();
|
||||
minWidth = source.readInt();
|
||||
minHeight = source.readInt();
|
||||
windowLayoutAffinity = source.readString();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1457,6 +1452,13 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
|
||||
*/
|
||||
public final int minHeight;
|
||||
|
||||
/**
|
||||
* Affinity of window layout parameters. Activities with the same UID and window layout
|
||||
* affinity will share the same window dimension record.
|
||||
* @hide
|
||||
*/
|
||||
public String windowLayoutAffinity;
|
||||
|
||||
/**
|
||||
* Returns if this {@link WindowLayout} has specified bounds.
|
||||
* @hide
|
||||
@@ -1464,5 +1466,17 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
|
||||
public boolean hasSpecifiedSize() {
|
||||
return width >= 0 || height >= 0 || widthFraction >= 0 || heightFraction >= 0;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void writeToParcel(Parcel dest) {
|
||||
dest.writeInt(width);
|
||||
dest.writeFloat(widthFraction);
|
||||
dest.writeInt(height);
|
||||
dest.writeFloat(heightFraction);
|
||||
dest.writeInt(gravity);
|
||||
dest.writeInt(minWidth);
|
||||
dest.writeInt(minHeight);
|
||||
dest.writeString(windowLayoutAffinity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,6 @@ import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.parsing.ParsingPackageUtils;
|
||||
import android.content.pm.permission.SplitPermissionInfoParcelable;
|
||||
import android.content.pm.split.DefaultSplitAssetLoader;
|
||||
import android.content.pm.split.SplitAssetDependencyLoader;
|
||||
@@ -209,6 +208,8 @@ public class PackageParser {
|
||||
public static final String TAG_USES_SPLIT = "uses-split";
|
||||
|
||||
public static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect";
|
||||
public static final String METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY =
|
||||
"android.activity_window_layout_affinity";
|
||||
|
||||
/**
|
||||
* Bit mask of all the valid bits that can be set in recreateOnConfigChanges.
|
||||
@@ -4560,6 +4561,8 @@ public class PackageParser {
|
||||
}
|
||||
}
|
||||
|
||||
resolveWindowLayout(a);
|
||||
|
||||
if (!setExported) {
|
||||
a.info.exported = a.intents.size() > 0;
|
||||
}
|
||||
@@ -4726,6 +4729,35 @@ public class PackageParser {
|
||||
height, heightFraction, gravity, minWidth, minHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves values in {@link ActivityInfo.WindowLayout}.
|
||||
*
|
||||
* <p>{@link ActivityInfo.WindowLayout#windowLayoutAffinity} has a fallback metadata used in
|
||||
* Android R and some variants of pre-R.
|
||||
*/
|
||||
private void resolveWindowLayout(Activity activity) {
|
||||
// There isn't a metadata for us to fall back. Whatever is in layout is correct.
|
||||
if (activity.metaData == null
|
||||
|| !activity.metaData.containsKey(METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ActivityInfo aInfo = activity.info;
|
||||
// Layout already specifies a value. We should just use that one.
|
||||
if (aInfo.windowLayout != null && aInfo.windowLayout.windowLayoutAffinity != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String windowLayoutAffinity = activity.metaData.getString(
|
||||
METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY);
|
||||
if (aInfo.windowLayout == null) {
|
||||
aInfo.windowLayout = new ActivityInfo.WindowLayout(-1 /* width */,
|
||||
-1 /* widthFraction */, -1 /* height */, -1 /* heightFraction */,
|
||||
Gravity.NO_GRAVITY, -1 /* minWidth */, -1 /* minHeight */);
|
||||
}
|
||||
aInfo.windowLayout.windowLayoutAffinity = windowLayoutAffinity;
|
||||
}
|
||||
|
||||
private Activity parseActivityAlias(Package owner, Resources res,
|
||||
XmlResourceParser parser, int flags, String[] outError,
|
||||
CachedComponentArgs cachedArgs)
|
||||
|
||||
@@ -285,14 +285,8 @@ public class ParsedActivity extends ParsedMainComponent {
|
||||
dest.writeBundle(this.metaData);
|
||||
|
||||
if (windowLayout != null) {
|
||||
dest.writeBoolean(true);
|
||||
dest.writeInt(windowLayout.width);
|
||||
dest.writeFloat(windowLayout.widthFraction);
|
||||
dest.writeInt(windowLayout.height);
|
||||
dest.writeFloat(windowLayout.heightFraction);
|
||||
dest.writeInt(windowLayout.gravity);
|
||||
dest.writeInt(windowLayout.minWidth);
|
||||
dest.writeInt(windowLayout.minHeight);
|
||||
dest.writeInt(1);
|
||||
windowLayout.writeToParcel(dest);
|
||||
} else {
|
||||
dest.writeBoolean(false);
|
||||
}
|
||||
|
||||
@@ -17,16 +17,17 @@
|
||||
package android.content.pm.parsing.component;
|
||||
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
||||
|
||||
import static android.content.pm.parsing.component.ComponentParseUtils.flag;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.ActivityTaskManager;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageParser;
|
||||
|
||||
import android.content.pm.parsing.ParsingPackage;
|
||||
import android.content.pm.parsing.ParsingPackageUtils;
|
||||
import android.content.pm.parsing.ParsingUtils;
|
||||
import android.content.pm.parsing.result.ParseInput;
|
||||
import android.content.pm.parsing.result.ParseResult;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
@@ -42,9 +43,6 @@ import android.view.WindowManager;
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import android.content.pm.parsing.ParsingPackageUtils;
|
||||
import android.content.pm.parsing.result.ParseInput;
|
||||
import android.content.pm.parsing.result.ParseResult;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
@@ -379,6 +377,12 @@ public class ParsedActivityUtils {
|
||||
}
|
||||
}
|
||||
|
||||
ParseResult<ActivityInfo.WindowLayout> layoutResult = resolveWindowLayout(activity, input);
|
||||
if (layoutResult.isError()) {
|
||||
return input.error(layoutResult);
|
||||
}
|
||||
activity.windowLayout = layoutResult.getResult();
|
||||
|
||||
if (!setExported) {
|
||||
activity.exported = activity.getIntents().size() > 0;
|
||||
}
|
||||
@@ -481,4 +485,35 @@ public class ParsedActivityUtils {
|
||||
sw.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves values in {@link ActivityInfo.WindowLayout}.
|
||||
*
|
||||
* <p>{@link ActivityInfo.WindowLayout#windowLayoutAffinity} has a fallback metadata used in
|
||||
* Android R and some variants of pre-R.
|
||||
*/
|
||||
private static ParseResult<ActivityInfo.WindowLayout> resolveWindowLayout(
|
||||
ParsedActivity activity, ParseInput input) {
|
||||
// There isn't a metadata for us to fall back. Whatever is in layout is correct.
|
||||
if (activity.metaData == null || !activity.metaData.containsKey(
|
||||
PackageParser.METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY)) {
|
||||
return input.success(activity.windowLayout);
|
||||
}
|
||||
|
||||
// Layout already specifies a value. We should just use that one.
|
||||
if (activity.windowLayout != null && activity.windowLayout.windowLayoutAffinity != null) {
|
||||
return input.success(activity.windowLayout);
|
||||
}
|
||||
|
||||
String windowLayoutAffinity = activity.metaData.getString(
|
||||
PackageParser.METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY);
|
||||
ActivityInfo.WindowLayout layout = activity.windowLayout;
|
||||
if (layout == null) {
|
||||
layout = new ActivityInfo.WindowLayout(-1 /* width */, -1 /* widthFraction */,
|
||||
-1 /* height */, -1 /* heightFraction */, Gravity.NO_GRAVITY,
|
||||
-1 /* minWidth */, -1 /* minHeight */);
|
||||
}
|
||||
layout.windowLayoutAffinity = windowLayoutAffinity;
|
||||
return input.success(layout);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1589,6 +1589,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
info.taskAffinity = uid + ":" + info.taskAffinity;
|
||||
}
|
||||
taskAffinity = info.taskAffinity;
|
||||
if (info.windowLayout != null && info.windowLayout.windowLayoutAffinity != null
|
||||
&& !info.windowLayout.windowLayoutAffinity.startsWith(uid)) {
|
||||
info.windowLayout.windowLayoutAffinity =
|
||||
uid + ":" + info.windowLayout.windowLayoutAffinity;
|
||||
}
|
||||
stateNotNeeded = (aInfo.flags & FLAG_STATE_NOT_NEEDED) != 0;
|
||||
nonLocalizedLabel = aInfo.nonLocalizedLabel;
|
||||
labelRes = aInfo.labelRes;
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
package com.android.server.wm;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.content.ComponentName;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Environment;
|
||||
@@ -87,9 +89,17 @@ class LaunchParamsPersister {
|
||||
* launching activity of tasks) to {@link PersistableLaunchParams} that stores launch metadata
|
||||
* that are stable across reboots.
|
||||
*/
|
||||
private final SparseArray<ArrayMap<ComponentName, PersistableLaunchParams>> mMap =
|
||||
private final SparseArray<ArrayMap<ComponentName, PersistableLaunchParams>> mLaunchParamsMap =
|
||||
new SparseArray<>();
|
||||
|
||||
/**
|
||||
* A map from {@link android.content.pm.ActivityInfo.WindowLayout#windowLayoutAffinity} to
|
||||
* activity's component name for reverse queries from window layout affinities to activities.
|
||||
* Used to decide if we should use another activity's record with the same affinity.
|
||||
*/
|
||||
private final ArrayMap<String, ArraySet<ComponentName>> mWindowLayoutAffinityMap =
|
||||
new ArrayMap<>();
|
||||
|
||||
LaunchParamsPersister(PersisterQueue persisterQueue, ActivityStackSupervisor supervisor) {
|
||||
this(persisterQueue, supervisor, Environment::getDataSystemCeDirectory);
|
||||
}
|
||||
@@ -112,7 +122,7 @@ class LaunchParamsPersister {
|
||||
}
|
||||
|
||||
void onCleanupUser(int userId) {
|
||||
mMap.remove(userId);
|
||||
mLaunchParamsMap.remove(userId);
|
||||
}
|
||||
|
||||
private void loadLaunchParams(int userId) {
|
||||
@@ -128,7 +138,7 @@ class LaunchParamsPersister {
|
||||
final File[] paramsFiles = launchParamsFolder.listFiles();
|
||||
final ArrayMap<ComponentName, PersistableLaunchParams> map =
|
||||
new ArrayMap<>(paramsFiles.length);
|
||||
mMap.put(userId, map);
|
||||
mLaunchParamsMap.put(userId, map);
|
||||
|
||||
for (File paramsFile : paramsFiles) {
|
||||
if (!paramsFile.isFile()) {
|
||||
@@ -179,10 +189,12 @@ class LaunchParamsPersister {
|
||||
continue;
|
||||
}
|
||||
|
||||
params.restoreFromXml(parser);
|
||||
params.restore(paramsFile, parser);
|
||||
}
|
||||
|
||||
map.put(name, params);
|
||||
addComponentNameToLaunchParamAffinityMapIfNotNull(
|
||||
name, params.mWindowLayoutAffinity);
|
||||
} catch (Exception e) {
|
||||
Slog.w(TAG, "Failed to restore launch params for " + name, e);
|
||||
filesToDelete.add(paramsFile);
|
||||
@@ -204,19 +216,17 @@ class LaunchParamsPersister {
|
||||
final ComponentName name = task.realActivity;
|
||||
final int userId = task.mUserId;
|
||||
PersistableLaunchParams params;
|
||||
ArrayMap<ComponentName, PersistableLaunchParams> map = mMap.get(userId);
|
||||
ArrayMap<ComponentName, PersistableLaunchParams> map = mLaunchParamsMap.get(userId);
|
||||
if (map == null) {
|
||||
map = new ArrayMap<>();
|
||||
mMap.put(userId, map);
|
||||
mLaunchParamsMap.put(userId, map);
|
||||
}
|
||||
|
||||
params = map.get(name);
|
||||
if (params == null) {
|
||||
params = new PersistableLaunchParams();
|
||||
map.put(name, params);
|
||||
}
|
||||
params = map.computeIfAbsent(name, componentName -> new PersistableLaunchParams());
|
||||
final boolean changed = saveTaskToLaunchParam(task, display, params);
|
||||
|
||||
addComponentNameToLaunchParamAffinityMapIfNotNull(name, params.mWindowLayoutAffinity);
|
||||
|
||||
if (changed) {
|
||||
mPersisterQueue.updateLastOrAddItem(
|
||||
new LaunchParamsWriteQueueItem(userId, name, params),
|
||||
@@ -243,19 +253,63 @@ class LaunchParamsPersister {
|
||||
params.mBounds.setEmpty();
|
||||
}
|
||||
|
||||
String launchParamAffinity = task.mWindowLayoutAffinity;
|
||||
changed |= Objects.equals(launchParamAffinity, params.mWindowLayoutAffinity);
|
||||
params.mWindowLayoutAffinity = launchParamAffinity;
|
||||
|
||||
if (changed) {
|
||||
params.mTimestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
private void addComponentNameToLaunchParamAffinityMapIfNotNull(
|
||||
ComponentName name, String launchParamAffinity) {
|
||||
if (launchParamAffinity == null) {
|
||||
return;
|
||||
}
|
||||
mWindowLayoutAffinityMap.computeIfAbsent(launchParamAffinity, affinity -> new ArraySet<>())
|
||||
.add(name);
|
||||
}
|
||||
|
||||
void getLaunchParams(Task task, ActivityRecord activity, LaunchParams outParams) {
|
||||
final ComponentName name = task != null ? task.realActivity : activity.mActivityComponent;
|
||||
final int userId = task != null ? task.mUserId : activity.mUserId;
|
||||
final String windowLayoutAffinity;
|
||||
if (task != null) {
|
||||
windowLayoutAffinity = task.mWindowLayoutAffinity;
|
||||
} else {
|
||||
ActivityInfo.WindowLayout layout = activity.info.windowLayout;
|
||||
windowLayoutAffinity = layout == null ? null : layout.windowLayoutAffinity;
|
||||
}
|
||||
|
||||
outParams.reset();
|
||||
Map<ComponentName, PersistableLaunchParams> map = mMap.get(userId);
|
||||
Map<ComponentName, PersistableLaunchParams> map = mLaunchParamsMap.get(userId);
|
||||
if (map == null) {
|
||||
return;
|
||||
}
|
||||
final PersistableLaunchParams persistableParams = map.get(name);
|
||||
|
||||
// First use its own record as a reference.
|
||||
PersistableLaunchParams persistableParams = map.get(name);
|
||||
// Next we'll compare these params against all existing params with the same affinity and
|
||||
// use the newest one.
|
||||
if (windowLayoutAffinity != null
|
||||
&& mWindowLayoutAffinityMap.get(windowLayoutAffinity) != null) {
|
||||
ArraySet<ComponentName> candidates = mWindowLayoutAffinityMap.get(windowLayoutAffinity);
|
||||
for (int i = 0; i < candidates.size(); ++i) {
|
||||
ComponentName candidate = candidates.valueAt(i);
|
||||
final PersistableLaunchParams candidateParams = map.get(candidate);
|
||||
if (candidateParams == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (persistableParams == null
|
||||
|| candidateParams.mTimestamp > persistableParams.mTimestamp) {
|
||||
persistableParams = candidateParams;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (persistableParams == null) {
|
||||
return;
|
||||
@@ -272,10 +326,10 @@ class LaunchParamsPersister {
|
||||
|
||||
void removeRecordForPackage(String packageName) {
|
||||
final List<File> fileToDelete = new ArrayList<>();
|
||||
for (int i = 0; i < mMap.size(); ++i) {
|
||||
int userId = mMap.keyAt(i);
|
||||
for (int i = 0; i < mLaunchParamsMap.size(); ++i) {
|
||||
int userId = mLaunchParamsMap.keyAt(i);
|
||||
final File launchParamsFolder = getLaunchParamFolder(userId);
|
||||
ArrayMap<ComponentName, PersistableLaunchParams> map = mMap.valueAt(i);
|
||||
ArrayMap<ComponentName, PersistableLaunchParams> map = mLaunchParamsMap.valueAt(i);
|
||||
for (int j = map.size() - 1; j >= 0; --j) {
|
||||
final ComponentName name = map.keyAt(j);
|
||||
if (name.getPackageName().equals(packageName)) {
|
||||
@@ -409,6 +463,7 @@ class LaunchParamsPersister {
|
||||
private static final String ATTR_WINDOWING_MODE = "windowing_mode";
|
||||
private static final String ATTR_DISPLAY_UNIQUE_ID = "display_unique_id";
|
||||
private static final String ATTR_BOUNDS = "bounds";
|
||||
private static final String ATTR_WINDOW_LAYOUT_AFFINITY = "window_layout_affinity";
|
||||
|
||||
/** The bounds within the parent container. */
|
||||
final Rect mBounds = new Rect();
|
||||
@@ -419,14 +474,29 @@ class LaunchParamsPersister {
|
||||
/** The windowing mode to be in. */
|
||||
int mWindowingMode;
|
||||
|
||||
/**
|
||||
* Last {@link android.content.pm.ActivityInfo.WindowLayout#windowLayoutAffinity} of the
|
||||
* window.
|
||||
*/
|
||||
@Nullable String mWindowLayoutAffinity;
|
||||
|
||||
/**
|
||||
* Timestamp from {@link System#currentTimeMillis()} when this record is captured, or last
|
||||
* modified time when the record is restored from storage.
|
||||
*/
|
||||
long mTimestamp;
|
||||
|
||||
void saveToXml(XmlSerializer serializer) throws IOException {
|
||||
serializer.attribute(null, ATTR_DISPLAY_UNIQUE_ID, mDisplayUniqueId);
|
||||
serializer.attribute(null, ATTR_WINDOWING_MODE,
|
||||
Integer.toString(mWindowingMode));
|
||||
serializer.attribute(null, ATTR_BOUNDS, mBounds.flattenToString());
|
||||
if (mWindowLayoutAffinity != null) {
|
||||
serializer.attribute(null, ATTR_WINDOW_LAYOUT_AFFINITY, mWindowLayoutAffinity);
|
||||
}
|
||||
}
|
||||
|
||||
void restoreFromXml(XmlPullParser parser) {
|
||||
void restore(File xmlFile, XmlPullParser parser) {
|
||||
for (int i = 0; i < parser.getAttributeCount(); ++i) {
|
||||
final String attrValue = parser.getAttributeValue(i);
|
||||
switch (parser.getAttributeName(i)) {
|
||||
@@ -443,16 +513,28 @@ class LaunchParamsPersister {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ATTR_WINDOW_LAYOUT_AFFINITY:
|
||||
mWindowLayoutAffinity = attrValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// The modified time could be a few seconds later than the timestamp when the record is
|
||||
// captured, which is a good enough estimate to the capture time after a reboot or a
|
||||
// user switch.
|
||||
mTimestamp = xmlFile.lastModified();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder builder = new StringBuilder("PersistableLaunchParams{");
|
||||
builder.append("windowingMode=" + mWindowingMode);
|
||||
builder.append(" windowingMode=" + mWindowingMode);
|
||||
builder.append(" displayUniqueId=" + mDisplayUniqueId);
|
||||
builder.append(" bounds=" + mBounds);
|
||||
if (mWindowLayoutAffinity != null) {
|
||||
builder.append(" launchParamsAffinity=" + mWindowLayoutAffinity);
|
||||
}
|
||||
builder.append(" timestamp=" + mTimestamp);
|
||||
builder.append(" }");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@@ -199,6 +199,7 @@ class Task extends WindowContainer<WindowContainer> {
|
||||
private static final String ATTR_MIN_WIDTH = "min_width";
|
||||
private static final String ATTR_MIN_HEIGHT = "min_height";
|
||||
private static final String ATTR_PERSIST_TASK_VERSION = "persist_task_version";
|
||||
private static final String ATTR_WINDOW_LAYOUT_AFFINITY = "window_layout_affinity";
|
||||
|
||||
// Current version of the task record we persist. Used to check if we need to run any upgrade
|
||||
// code.
|
||||
@@ -233,6 +234,8 @@ class Task extends WindowContainer<WindowContainer> {
|
||||
|
||||
String affinity; // The affinity name for this task, or null; may change identity.
|
||||
String rootAffinity; // Initial base affinity, or null; does not change from initial root.
|
||||
String mWindowLayoutAffinity; // Launch param affinity of this task or null. Used when saving
|
||||
// launch params of this task.
|
||||
IVoiceInteractionSession voiceSession; // Voice interaction session driving task
|
||||
IVoiceInteractor voiceInteractor; // Associated interactor to provide to app
|
||||
Intent intent; // The original intent that started the task. Note that this value can
|
||||
@@ -1001,6 +1004,8 @@ class Task extends WindowContainer<WindowContainer> {
|
||||
origActivity = new ComponentName(info.packageName, info.name);
|
||||
}
|
||||
}
|
||||
mWindowLayoutAffinity =
|
||||
info.windowLayout == null ? null : info.windowLayout.windowLayoutAffinity;
|
||||
|
||||
final int intentFlags = intent == null ? 0 : intent.getFlags();
|
||||
if ((intentFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
|
||||
@@ -3410,6 +3415,9 @@ class Task extends WindowContainer<WindowContainer> {
|
||||
pw.println();
|
||||
}
|
||||
}
|
||||
if (mWindowLayoutAffinity != null) {
|
||||
pw.print(prefix); pw.print("windowLayoutAffinity="); pw.println(mWindowLayoutAffinity);
|
||||
}
|
||||
if (voiceSession != null || voiceInteractor != null) {
|
||||
pw.print(prefix); pw.print("VOICE: session=0x");
|
||||
pw.print(Integer.toHexString(System.identityHashCode(voiceSession)));
|
||||
@@ -3591,6 +3599,9 @@ class Task extends WindowContainer<WindowContainer> {
|
||||
} else if (rootAffinity != null) {
|
||||
out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
|
||||
}
|
||||
if (mWindowLayoutAffinity != null) {
|
||||
out.attribute(null, ATTR_WINDOW_LAYOUT_AFFINITY, mWindowLayoutAffinity);
|
||||
}
|
||||
out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
|
||||
out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents));
|
||||
out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
|
||||
@@ -3748,6 +3759,7 @@ class Task extends WindowContainer<WindowContainer> {
|
||||
String affinity = null;
|
||||
String rootAffinity = null;
|
||||
boolean hasRootAffinity = false;
|
||||
String windowLayoutAffinity = null;
|
||||
boolean rootHasReset = false;
|
||||
boolean autoRemoveRecents = false;
|
||||
boolean askedCompatMode = false;
|
||||
@@ -3800,6 +3812,9 @@ class Task extends WindowContainer<WindowContainer> {
|
||||
rootAffinity = attrValue;
|
||||
hasRootAffinity = true;
|
||||
break;
|
||||
case ATTR_WINDOW_LAYOUT_AFFINITY:
|
||||
windowLayoutAffinity = attrValue;
|
||||
break;
|
||||
case ATTR_ROOTHASRESET:
|
||||
rootHasReset = Boolean.parseBoolean(attrValue);
|
||||
break;
|
||||
@@ -3955,6 +3970,7 @@ class Task extends WindowContainer<WindowContainer> {
|
||||
realActivitySuspended, userSetupComplete, minWidth, minHeight, null /*stack*/);
|
||||
task.mLastNonFullscreenBounds = lastNonFullscreenBounds;
|
||||
task.setBounds(lastNonFullscreenBounds);
|
||||
task.mWindowLayoutAffinity = windowLayoutAffinity;
|
||||
|
||||
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
|
||||
task.addChild(activities.get(activityNdx));
|
||||
|
||||
@@ -37,8 +37,8 @@ import android.graphics.Rect;
|
||||
import android.os.UserHandle;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.MediumTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.pm.PackageList;
|
||||
@@ -72,6 +72,10 @@ public class LaunchParamsPersisterTests extends ActivityTestsBase {
|
||||
ComponentName.createRelative("com.android.foo", ".BarActivity");
|
||||
private static final ComponentName ALTERNATIVE_COMPONENT =
|
||||
ComponentName.createRelative("com.android.foo", ".AlternativeBarActivity");
|
||||
private static final String TEST_WINDOW_LAYOUT_AFFINITY = "135:.Affinity";
|
||||
private static final String TEST_ALTERNATIVE_WINDOW_LAYOUT_AFFINITY =
|
||||
"246:.AlternativeAffinity";
|
||||
private static final String TEST_DIFFERENT_AFFINITY_WITH_SAME_UID = "135:.DifferentAffinity";
|
||||
|
||||
private static final int TEST_WINDOWING_MODE = WINDOWING_MODE_FREEFORM;
|
||||
private static final Rect TEST_BOUNDS = new Rect(100, 200, 300, 400);
|
||||
@@ -99,11 +103,12 @@ public class LaunchParamsPersisterTests extends ActivityTestsBase {
|
||||
public void setUp() throws Exception {
|
||||
mPersisterQueue = new TestPersisterQueue();
|
||||
|
||||
final File cacheFolder = InstrumentationRegistry.getContext().getCacheDir();
|
||||
final File cacheFolder =
|
||||
InstrumentationRegistry.getInstrumentation().getContext().getCacheDir();
|
||||
mFolder = new File(cacheFolder, "launch_params_tests");
|
||||
deleteRecursively(mFolder);
|
||||
|
||||
mDisplayUniqueId = "test:" + Integer.toString(sNextUniqueId++);
|
||||
mDisplayUniqueId = "test:" + sNextUniqueId++;
|
||||
mTestDisplay = new TestDisplayContent.Builder(mService, 1000, 1500)
|
||||
.setUniqueId(mDisplayUniqueId).build();
|
||||
when(mRootWindowContainer.getDisplayContent(eq(mDisplayUniqueId)))
|
||||
@@ -210,6 +215,61 @@ public class LaunchParamsPersisterTests extends ActivityTestsBase {
|
||||
assertTrue("Result should be empty.", mResult.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUsesRecordWithSameWindowLayoutAffinityInSameInstance_NoPreviousRecord() {
|
||||
mTestTask.mWindowLayoutAffinity = TEST_WINDOW_LAYOUT_AFFINITY;
|
||||
mTarget.saveTask(mTestTask);
|
||||
|
||||
mTaskWithDifferentComponent.mWindowLayoutAffinity = TEST_WINDOW_LAYOUT_AFFINITY;
|
||||
mTarget.getLaunchParams(mTaskWithDifferentComponent, null, mResult);
|
||||
|
||||
assertEquals(mTestDisplay.mDisplayId, mResult.mPreferredDisplayId);
|
||||
assertEquals(TEST_WINDOWING_MODE, mResult.mWindowingMode);
|
||||
assertEquals(TEST_BOUNDS, mResult.mBounds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUsesRecordWithSameWindowLayoutAffinityInSameInstance_HasOldPreviousRecord()
|
||||
throws Exception {
|
||||
mTaskWithDifferentComponent.mWindowLayoutAffinity = TEST_WINDOW_LAYOUT_AFFINITY;
|
||||
mTarget.saveTask(mTaskWithDifferentComponent);
|
||||
|
||||
Thread.sleep(1); // Sleep 1ms so that the timestamp can for sure increase.
|
||||
|
||||
mTestTask.mWindowLayoutAffinity = TEST_WINDOW_LAYOUT_AFFINITY;
|
||||
mTarget.saveTask(mTestTask);
|
||||
|
||||
mTarget.getLaunchParams(mTaskWithDifferentComponent, null, mResult);
|
||||
|
||||
assertEquals(mTestDisplay.mDisplayId, mResult.mPreferredDisplayId);
|
||||
assertEquals(TEST_WINDOWING_MODE, mResult.mWindowingMode);
|
||||
assertEquals(TEST_BOUNDS, mResult.mBounds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReturnsEmptyLaunchParamsUidInLaunchAffinityMismatch() {
|
||||
mTestTask.mWindowLayoutAffinity = TEST_WINDOW_LAYOUT_AFFINITY;
|
||||
mTarget.saveTask(mTestTask);
|
||||
|
||||
mTaskWithDifferentComponent.mWindowLayoutAffinity = TEST_DIFFERENT_AFFINITY_WITH_SAME_UID;
|
||||
mResult.mWindowingMode = WINDOWING_MODE_FULLSCREEN;
|
||||
mTarget.getLaunchParams(mTaskWithDifferentComponent, null, mResult);
|
||||
|
||||
assertTrue("Result must be empty.", mResult.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReturnsEmptyLaunchParamsWindowLayoutAffinityMismatch() {
|
||||
mTestTask.affinity = TEST_WINDOW_LAYOUT_AFFINITY;
|
||||
mTarget.saveTask(mTestTask);
|
||||
|
||||
mTaskWithDifferentComponent.mWindowLayoutAffinity = TEST_ALTERNATIVE_WINDOW_LAYOUT_AFFINITY;
|
||||
mResult.mWindowingMode = WINDOWING_MODE_FULLSCREEN;
|
||||
mTarget.getLaunchParams(mTaskWithDifferentComponent, null, mResult);
|
||||
|
||||
assertTrue("Result must be empty.", mResult.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSavesAndRestoresLaunchParamsAcrossInstances() {
|
||||
mTarget.saveTask(mTestTask);
|
||||
@@ -227,6 +287,52 @@ public class LaunchParamsPersisterTests extends ActivityTestsBase {
|
||||
assertEquals(TEST_BOUNDS, mResult.mBounds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUsesRecordWithSameWindowLayoutAffinityAcrossInstances_NoPreviousRecord() {
|
||||
mTestTask.mWindowLayoutAffinity = TEST_WINDOW_LAYOUT_AFFINITY;
|
||||
mTarget.saveTask(mTestTask);
|
||||
mPersisterQueue.flush();
|
||||
|
||||
final LaunchParamsPersister target = new LaunchParamsPersister(mPersisterQueue, mSupervisor,
|
||||
mUserFolderGetter);
|
||||
target.onSystemReady();
|
||||
target.onUnlockUser(TEST_USER_ID);
|
||||
|
||||
mTaskWithDifferentComponent.mWindowLayoutAffinity = TEST_WINDOW_LAYOUT_AFFINITY;
|
||||
target.getLaunchParams(mTaskWithDifferentComponent, null, mResult);
|
||||
|
||||
assertEquals(mTestDisplay.mDisplayId, mResult.mPreferredDisplayId);
|
||||
assertEquals(TEST_WINDOWING_MODE, mResult.mWindowingMode);
|
||||
assertEquals(TEST_BOUNDS, mResult.mBounds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUsesRecordWithSameWindowLayoutAffinityAcrossInstances_HasOldPreviousRecord()
|
||||
throws Exception {
|
||||
mTaskWithDifferentComponent.mWindowLayoutAffinity = TEST_WINDOW_LAYOUT_AFFINITY;
|
||||
mTarget.saveTask(mTaskWithDifferentComponent);
|
||||
mPersisterQueue.flush();
|
||||
|
||||
// Sleep 1s because many file systems only save last modified time as precise as 1s so we
|
||||
// can for sure know the last modified time is different.
|
||||
Thread.sleep(1000);
|
||||
|
||||
mTestTask.mWindowLayoutAffinity = TEST_WINDOW_LAYOUT_AFFINITY;
|
||||
mTarget.saveTask(mTestTask);
|
||||
mPersisterQueue.flush();
|
||||
|
||||
final LaunchParamsPersister target = new LaunchParamsPersister(mPersisterQueue, mSupervisor,
|
||||
mUserFolderGetter);
|
||||
target.onSystemReady();
|
||||
target.onUnlockUser(TEST_USER_ID);
|
||||
|
||||
target.getLaunchParams(mTaskWithDifferentComponent, null, mResult);
|
||||
|
||||
assertEquals(mTestDisplay.mDisplayId, mResult.mPreferredDisplayId);
|
||||
assertEquals(TEST_WINDOWING_MODE, mResult.mWindowingMode);
|
||||
assertEquals(TEST_BOUNDS, mResult.mBounds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClearsRecordsOfTheUserOnUserCleanUp() {
|
||||
mTarget.saveTask(mTestTask);
|
||||
|
||||
Reference in New Issue
Block a user