Merge changes from topic "b147213487" into rvc-dev am: 8e726a2ef7 am: 2d42c72f14 am: bd9a3d97c6

Change-Id: I1ee5b9985bdd25555a38aea7e86935b81dd799ff
This commit is contained in:
Riddle Hsu
2020-05-12 09:50:24 +00:00
committed by Automerger Merge Worker
17 changed files with 598 additions and 23 deletions

View File

@@ -7151,6 +7151,11 @@ public class Activity extends ContextThemeWrapper
writer.println(mChangingConfigurations);
writer.print(innerPrefix); writer.print("mCurrentConfig=");
writer.println(mCurrentConfig);
if (getResources().hasOverrideDisplayAdjustments()) {
writer.print(innerPrefix);
writer.print("FixedRotationAdjustments=");
writer.println(getResources().getDisplayAdjustments().getFixedRotationAdjustments());
}
mFragments.dumpLoaders(innerPrefix, fd, writer, args);
mFragments.getFragmentManager().dump(innerPrefix, fd, writer, args);

View File

@@ -156,6 +156,8 @@ import android.util.proto.ProtoOutputStream;
import android.view.Choreographer;
import android.view.ContextThemeWrapper;
import android.view.Display;
import android.view.DisplayAdjustments;
import android.view.DisplayAdjustments.FixedRotationAdjustments;
import android.view.ThreadedRenderer;
import android.view.View;
import android.view.ViewDebug;
@@ -215,6 +217,7 @@ import java.util.Objects;
import java.util.TimeZone;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
final class RemoteServiceException extends AndroidRuntimeException {
public RemoteServiceException(String msg) {
@@ -405,6 +408,9 @@ public final class ActivityThread extends ClientTransactionHandler {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final ResourcesManager mResourcesManager;
/** The active adjustments that override the {@link DisplayAdjustments} in resources. */
private ArrayList<Pair<IBinder, Consumer<DisplayAdjustments>>> mActiveRotationAdjustments;
// Registry of remote cancellation transports pending a reply with reply handles.
@GuardedBy("this")
private @Nullable Map<SafeCancellationTransport, CancellationSignal> mRemoteCancellations;
@@ -541,6 +547,12 @@ public final class ActivityThread extends ClientTransactionHandler {
@UnsupportedAppUsage
boolean mPreserveWindow;
/**
* If non-null, the activity is launching with a specified rotation, the adjustments should
* be consumed before activity creation.
*/
FixedRotationAdjustments mPendingFixedRotationAdjustments;
@LifecycleState
private int mLifecycleState = PRE_ON_CREATE;
@@ -557,7 +569,7 @@ public final class ActivityThread extends ClientTransactionHandler {
PersistableBundle persistentState, List<ResultInfo> pendingResults,
List<ReferrerIntent> pendingNewIntents, boolean isForward,
ProfilerInfo profilerInfo, ClientTransactionHandler client,
IBinder assistToken) {
IBinder assistToken, FixedRotationAdjustments fixedRotationAdjustments) {
this.token = token;
this.assistToken = assistToken;
this.ident = ident;
@@ -575,6 +587,7 @@ public final class ActivityThread extends ClientTransactionHandler {
this.overrideConfig = overrideConfig;
this.packageInfo = client.getPackageInfoNoCheck(activityInfo.applicationInfo,
compatInfo);
mPendingFixedRotationAdjustments = fixedRotationAdjustments;
init();
}
@@ -3233,6 +3246,44 @@ public final class ActivityThread extends ClientTransactionHandler {
sendMessage(H.CLEAN_UP_CONTEXT, cci);
}
@Override
public void handleFixedRotationAdjustments(@NonNull IBinder token,
@Nullable FixedRotationAdjustments fixedRotationAdjustments) {
final Consumer<DisplayAdjustments> override = fixedRotationAdjustments != null
? displayAdjustments -> displayAdjustments.setFixedRotationAdjustments(
fixedRotationAdjustments)
: null;
if (!mResourcesManager.overrideTokenDisplayAdjustments(token, override)) {
// No resources are associated with the token.
return;
}
if (mActivities.get(token) == null) {
// Only apply the override to application for activity token because the appearance of
// activity is usually more sensitive to the application resources.
return;
}
// Apply the last override to application resources for compatibility. Because the Resources
// of Display can be from application, e.g.
// applicationContext.getSystemService(DisplayManager.class).getDisplay(displayId)
// and the deprecated usage:
// applicationContext.getSystemService(WindowManager.class).getDefaultDisplay();
final Consumer<DisplayAdjustments> appOverride;
if (mActiveRotationAdjustments == null) {
mActiveRotationAdjustments = new ArrayList<>(2);
}
if (override != null) {
mActiveRotationAdjustments.add(Pair.create(token, override));
appOverride = override;
} else {
mActiveRotationAdjustments.removeIf(adjustmentsPair -> adjustmentsPair.first == token);
appOverride = mActiveRotationAdjustments.isEmpty()
? null
: mActiveRotationAdjustments.get(mActiveRotationAdjustments.size() - 1).second;
}
mInitialApplication.getResources().overrideDisplayAdjustments(appOverride);
}
/** Core implementation of activity launch. */
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
@@ -3446,6 +3497,13 @@ public final class ActivityThread extends ClientTransactionHandler {
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
// The rotation adjustments must be applied before creating the activity, so the activity
// can get the adjusted display info during creation.
if (r.mPendingFixedRotationAdjustments != null) {
handleFixedRotationAdjustments(r.token, r.mPendingFixedRotationAdjustments);
r.mPendingFixedRotationAdjustments = null;
}
final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
// For debugging purposes, if the activity's package name contains the value of
// the "debug.use-second-display" system property as a substring, then show

View File

@@ -25,6 +25,7 @@ import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.os.IBinder;
import android.util.MergedConfiguration;
import android.view.DisplayAdjustments.FixedRotationAdjustments;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.ReferrerIntent;
@@ -167,6 +168,10 @@ public abstract class ClientTransactionHandler {
/** Deliver app configuration change notification. */
public abstract void handleConfigurationChanged(Configuration config);
/** Apply addition adjustments to override display information. */
public abstract void handleFixedRotationAdjustments(IBinder token,
FixedRotationAdjustments fixedRotationAdjustments);
/**
* Get {@link android.app.ActivityThread.ActivityClientRecord} instance that corresponds to the
* provided token.

View File

@@ -59,6 +59,7 @@ import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.WeakHashMap;
import java.util.function.Consumer;
import java.util.function.Predicate;
/** @hide */
@@ -1296,6 +1297,35 @@ public class ResourcesManager {
}
}
/**
* Overrides the display adjustments of all resources which are associated with the given token.
*
* @param token The token that owns the resources.
* @param override The operation to override the existing display adjustments. If it is null,
* the override adjustments will be cleared.
* @return {@code true} if the override takes effect.
*/
public boolean overrideTokenDisplayAdjustments(IBinder token,
@Nullable Consumer<DisplayAdjustments> override) {
boolean handled = false;
synchronized (this) {
final ActivityResources tokenResources = mActivityResourceReferences.get(token);
if (tokenResources == null) {
return false;
}
final ArrayList<WeakReference<Resources>> resourcesRefs =
tokenResources.activityResources;
for (int i = resourcesRefs.size() - 1; i >= 0; i--) {
final Resources res = resourcesRefs.get(i).get();
if (res != null) {
res.overrideDisplayAdjustments(override);
handled = true;
}
}
}
return handled;
}
private class UpdateHandler implements Resources.UpdateCallbacks {
/**

View File

@@ -0,0 +1,112 @@
/*
* Copyright 2020 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.app.servertransaction;
import android.app.ClientTransactionHandler;
import android.os.IBinder;
import android.os.Parcel;
import android.view.DisplayAdjustments.FixedRotationAdjustments;
import java.util.Objects;
/**
* The request to update display adjustments for a rotated activity or window token.
* @hide
*/
public class FixedRotationAdjustmentsItem extends ClientTransactionItem {
/** The token who may have {@link android.content.res.Resources}. */
private IBinder mToken;
/**
* The adjustments for the display adjustments of resources. If it is null, the existing
* rotation adjustments will be dropped to restore natural state.
*/
private FixedRotationAdjustments mFixedRotationAdjustments;
private FixedRotationAdjustmentsItem() {}
/** Obtain an instance initialized with provided params. */
public static FixedRotationAdjustmentsItem obtain(IBinder token,
FixedRotationAdjustments fixedRotationAdjustments) {
FixedRotationAdjustmentsItem instance =
ObjectPool.obtain(FixedRotationAdjustmentsItem.class);
if (instance == null) {
instance = new FixedRotationAdjustmentsItem();
}
instance.mToken = token;
instance.mFixedRotationAdjustments = fixedRotationAdjustments;
return instance;
}
@Override
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
client.handleFixedRotationAdjustments(mToken, mFixedRotationAdjustments);
}
@Override
public void recycle() {
mToken = null;
mFixedRotationAdjustments = null;
ObjectPool.recycle(this);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeStrongBinder(mToken);
dest.writeTypedObject(mFixedRotationAdjustments, flags);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final FixedRotationAdjustmentsItem other = (FixedRotationAdjustmentsItem) o;
return Objects.equals(mToken, other.mToken)
&& Objects.equals(mFixedRotationAdjustments, other.mFixedRotationAdjustments);
}
@Override
public int hashCode() {
int result = 17;
result = 31 * result + Objects.hashCode(mToken);
result = 31 * result + Objects.hashCode(mFixedRotationAdjustments);
return result;
}
private FixedRotationAdjustmentsItem(Parcel in) {
mToken = in.readStrongBinder();
mFixedRotationAdjustments = in.readTypedObject(FixedRotationAdjustments.CREATOR);
}
public static final Creator<FixedRotationAdjustmentsItem> CREATOR =
new Creator<FixedRotationAdjustmentsItem>() {
public FixedRotationAdjustmentsItem createFromParcel(Parcel in) {
return new FixedRotationAdjustmentsItem(in);
}
public FixedRotationAdjustmentsItem[] newArray(int size) {
return new FixedRotationAdjustmentsItem[size];
}
};
}

View File

@@ -33,6 +33,7 @@ import android.os.IBinder;
import android.os.Parcel;
import android.os.PersistableBundle;
import android.os.Trace;
import android.view.DisplayAdjustments.FixedRotationAdjustments;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.content.ReferrerIntent;
@@ -64,6 +65,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
private boolean mIsForward;
private ProfilerInfo mProfilerInfo;
private IBinder mAssistToken;
private FixedRotationAdjustments mFixedRotationAdjustments;
@Override
public void preExecute(ClientTransactionHandler client, IBinder token) {
@@ -79,7 +81,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
mPendingResults, mPendingNewIntents, mIsForward,
mProfilerInfo, client, mAssistToken);
mProfilerInfo, client, mAssistToken, mFixedRotationAdjustments);
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -101,14 +103,14 @@ public class LaunchActivityItem extends ClientTransactionItem {
String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
PersistableBundle persistentState, List<ResultInfo> pendingResults,
List<ReferrerIntent> pendingNewIntents, boolean isForward, ProfilerInfo profilerInfo,
IBinder assistToken) {
IBinder assistToken, FixedRotationAdjustments fixedRotationAdjustments) {
LaunchActivityItem instance = ObjectPool.obtain(LaunchActivityItem.class);
if (instance == null) {
instance = new LaunchActivityItem();
}
setValues(instance, intent, ident, info, curConfig, overrideConfig, compatInfo, referrer,
voiceInteractor, procState, state, persistentState, pendingResults,
pendingNewIntents, isForward, profilerInfo, assistToken);
pendingNewIntents, isForward, profilerInfo, assistToken, fixedRotationAdjustments);
return instance;
}
@@ -116,7 +118,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
@Override
public void recycle() {
setValues(this, null, 0, null, null, null, null, null, null, 0, null, null, null, null,
false, null, null);
false, null, null, null);
ObjectPool.recycle(this);
}
@@ -142,6 +144,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
dest.writeBoolean(mIsForward);
dest.writeTypedObject(mProfilerInfo, flags);
dest.writeStrongBinder(mAssistToken);
dest.writeTypedObject(mFixedRotationAdjustments, flags);
}
/** Read from Parcel. */
@@ -156,7 +159,8 @@ public class LaunchActivityItem extends ClientTransactionItem {
in.createTypedArrayList(ResultInfo.CREATOR),
in.createTypedArrayList(ReferrerIntent.CREATOR), in.readBoolean(),
in.readTypedObject(ProfilerInfo.CREATOR),
in.readStrongBinder());
in.readStrongBinder(),
in.readTypedObject(FixedRotationAdjustments.CREATOR));
}
public static final @android.annotation.NonNull Creator<LaunchActivityItem> CREATOR =
@@ -192,7 +196,8 @@ public class LaunchActivityItem extends ClientTransactionItem {
&& Objects.equals(mPendingNewIntents, other.mPendingNewIntents)
&& mIsForward == other.mIsForward
&& Objects.equals(mProfilerInfo, other.mProfilerInfo)
&& Objects.equals(mAssistToken, other.mAssistToken);
&& Objects.equals(mAssistToken, other.mAssistToken)
&& Objects.equals(mFixedRotationAdjustments, other.mFixedRotationAdjustments);
}
@Override
@@ -212,6 +217,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
result = 31 * result + (mIsForward ? 1 : 0);
result = 31 * result + Objects.hashCode(mProfilerInfo);
result = 31 * result + Objects.hashCode(mAssistToken);
result = 31 * result + Objects.hashCode(mFixedRotationAdjustments);
return result;
}
@@ -247,7 +253,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
+ ",referrer=" + mReferrer + ",procState=" + mProcState + ",state=" + mState
+ ",persistentState=" + mPersistentState + ",pendingResults=" + mPendingResults
+ ",pendingNewIntents=" + mPendingNewIntents + ",profilerInfo=" + mProfilerInfo
+ " assistToken=" + mAssistToken
+ ",assistToken=" + mAssistToken + ",rotationAdj=" + mFixedRotationAdjustments
+ "}";
}
@@ -257,7 +263,8 @@ public class LaunchActivityItem extends ClientTransactionItem {
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken) {
boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken,
FixedRotationAdjustments fixedRotationAdjustments) {
instance.mIntent = intent;
instance.mIdent = ident;
instance.mInfo = info;
@@ -274,5 +281,6 @@ public class LaunchActivityItem extends ClientTransactionItem {
instance.mIsForward = isForward;
instance.mProfilerInfo = profilerInfo;
instance.mAssistToken = assistToken;
instance.mFixedRotationAdjustments = fixedRotationAdjustments;
}
}

View File

@@ -81,6 +81,7 @@ import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
/**
* Class for accessing an application's resources. This sits on top of the
@@ -140,6 +141,9 @@ public class Resources {
@UnsupportedAppUsage
private DrawableInflater mDrawableInflater;
/** Used to override the returned adjustments of {@link #getDisplayAdjustments}. */
private DisplayAdjustments mOverrideDisplayAdjustments;
/** Lock object used to protect access to {@link #mTmpValue}. */
private final Object mTmpValueLock = new Object();
@@ -2055,9 +2059,40 @@ public class Resources {
/** @hide */
@UnsupportedAppUsage
public DisplayAdjustments getDisplayAdjustments() {
final DisplayAdjustments overrideDisplayAdjustments = mOverrideDisplayAdjustments;
if (overrideDisplayAdjustments != null) {
return overrideDisplayAdjustments;
}
return mResourcesImpl.getDisplayAdjustments();
}
/**
* Customize the display adjustments based on the current one in {@link #mResourcesImpl}, in
* order to isolate the effect with other instances of {@link Resource} that may share the same
* instance of {@link ResourcesImpl}.
*
* @param override The operation to override the existing display adjustments. If it is null,
* the override adjustments will be cleared.
* @hide
*/
public void overrideDisplayAdjustments(@Nullable Consumer<DisplayAdjustments> override) {
if (override != null) {
mOverrideDisplayAdjustments = new DisplayAdjustments(
mResourcesImpl.getDisplayAdjustments());
override.accept(mOverrideDisplayAdjustments);
} else {
mOverrideDisplayAdjustments = null;
}
}
/**
* Return {@code true} if the override display adjustments have been set.
* @hide
*/
public boolean hasOverrideDisplayAdjustments() {
return mOverrideDisplayAdjustments != null;
}
/**
* Return the current configuration that is in effect for this resource
* object. The returned object should be treated as read-only.

View File

@@ -103,6 +103,14 @@ public final class Display {
private int mCachedAppWidthCompat;
private int mCachedAppHeightCompat;
/**
* Indicates that the application is started in a different rotation than the real display, so
* the display information may be adjusted. That ensures the methods {@link #getRotation},
* {@link #getRealSize}, {@link #getRealMetrics}, and {@link #getCutout} are consistent with how
* the application window is laid out.
*/
private boolean mMayAdjustByFixedRotation;
/**
* The default Display id, which is the id of the primary display assuming there is one.
*/
@@ -804,7 +812,9 @@ public final class Display {
public int getRotation() {
synchronized (this) {
updateDisplayInfoLocked();
return mDisplayInfo.rotation;
return mMayAdjustByFixedRotation
? getDisplayAdjustments().getRotation(mDisplayInfo.rotation)
: mDisplayInfo.rotation;
}
}
@@ -828,7 +838,9 @@ public final class Display {
public DisplayCutout getCutout() {
synchronized (this) {
updateDisplayInfoLocked();
return mDisplayInfo.displayCutout;
return mMayAdjustByFixedRotation
? getDisplayAdjustments().getDisplayCutout(mDisplayInfo.displayCutout)
: mDisplayInfo.displayCutout;
}
}
@@ -1140,6 +1152,9 @@ public final class Display {
updateDisplayInfoLocked();
outSize.x = mDisplayInfo.logicalWidth;
outSize.y = mDisplayInfo.logicalHeight;
if (mMayAdjustByFixedRotation) {
getDisplayAdjustments().adjustSize(outSize, mDisplayInfo.rotation);
}
}
}
@@ -1159,6 +1174,9 @@ public final class Display {
updateDisplayInfoLocked();
mDisplayInfo.getLogicalMetrics(outMetrics,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
if (mMayAdjustByFixedRotation) {
getDisplayAdjustments().adjustMetrics(outMetrics, mDisplayInfo.rotation);
}
}
}
@@ -1225,6 +1243,9 @@ public final class Display {
}
}
}
mMayAdjustByFixedRotation = mResources != null
&& mResources.hasOverrideDisplayAdjustments();
}
private void updateCachedAppSizeIfNeededLocked() {
@@ -1243,9 +1264,12 @@ public final class Display {
public String toString() {
synchronized (this) {
updateDisplayInfoLocked();
mDisplayInfo.getAppMetrics(mTempMetrics, getDisplayAdjustments());
final DisplayAdjustments adjustments = getDisplayAdjustments();
mDisplayInfo.getAppMetrics(mTempMetrics, adjustments);
return "Display id " + mDisplayId + ": " + mDisplayInfo
+ ", " + mTempMetrics + ", isValid=" + mIsValid;
+ (mMayAdjustByFixedRotation
? (", " + adjustments.getFixedRotationAdjustments() + ", ") : ", ")
+ mTempMetrics + ", isValid=" + mIsValid;
}
}

View File

@@ -21,6 +21,10 @@ import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Point;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.DisplayMetrics;
import java.util.Objects;
@@ -30,6 +34,7 @@ public class DisplayAdjustments {
private volatile CompatibilityInfo mCompatInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
private final Configuration mConfiguration = new Configuration(Configuration.EMPTY);
private FixedRotationAdjustments mFixedRotationAdjustments;
@UnsupportedAppUsage
public DisplayAdjustments() {
@@ -44,6 +49,7 @@ public class DisplayAdjustments {
public DisplayAdjustments(@NonNull DisplayAdjustments daj) {
setCompatibilityInfo(daj.mCompatInfo);
mConfiguration.setTo(daj.getConfiguration());
mFixedRotationAdjustments = daj.mFixedRotationAdjustments;
}
@UnsupportedAppUsage
@@ -84,11 +90,78 @@ public class DisplayAdjustments {
return mConfiguration;
}
public void setFixedRotationAdjustments(FixedRotationAdjustments fixedRotationAdjustments) {
mFixedRotationAdjustments = fixedRotationAdjustments;
}
public FixedRotationAdjustments getFixedRotationAdjustments() {
return mFixedRotationAdjustments;
}
/** Returns {@code false} if the width and height of display should swap. */
private boolean noFlip(@Surface.Rotation int realRotation) {
final FixedRotationAdjustments rotationAdjustments = mFixedRotationAdjustments;
if (rotationAdjustments == null) {
return true;
}
// Check if the delta is rotated by 90 degrees.
return (realRotation - rotationAdjustments.mRotation + 4) % 2 == 0;
}
/** Adjusts the given size if possible. */
public void adjustSize(@NonNull Point size, @Surface.Rotation int realRotation) {
if (noFlip(realRotation)) {
return;
}
final int w = size.x;
size.x = size.y;
size.y = w;
}
/** Adjusts the given metrics if possible. */
public void adjustMetrics(@NonNull DisplayMetrics metrics, @Surface.Rotation int realRotation) {
if (noFlip(realRotation)) {
return;
}
int w = metrics.widthPixels;
metrics.widthPixels = metrics.heightPixels;
metrics.heightPixels = w;
w = metrics.noncompatWidthPixels;
metrics.noncompatWidthPixels = metrics.noncompatHeightPixels;
metrics.noncompatHeightPixels = w;
float x = metrics.xdpi;
metrics.xdpi = metrics.ydpi;
metrics.ydpi = x;
x = metrics.noncompatXdpi;
metrics.noncompatXdpi = metrics.noncompatYdpi;
metrics.noncompatYdpi = x;
}
/** Returns the adjusted cutout if available. Otherwise the original cutout is returned. */
@Nullable
public DisplayCutout getDisplayCutout(@Nullable DisplayCutout realCutout) {
final FixedRotationAdjustments rotationAdjustments = mFixedRotationAdjustments;
return rotationAdjustments != null && rotationAdjustments.mRotatedDisplayCutout != null
? rotationAdjustments.mRotatedDisplayCutout
: realCutout;
}
/** Returns the adjusted rotation if available. Otherwise the original rotation is returned. */
@Surface.Rotation
public int getRotation(@Surface.Rotation int realRotation) {
final FixedRotationAdjustments rotationAdjustments = mFixedRotationAdjustments;
return rotationAdjustments != null ? rotationAdjustments.mRotation : realRotation;
}
@Override
public int hashCode() {
int hash = 17;
hash = hash * 31 + Objects.hashCode(mCompatInfo);
hash = hash * 31 + Objects.hashCode(mConfiguration);
hash = hash * 31 + Objects.hashCode(mFixedRotationAdjustments);
return hash;
}
@@ -98,7 +171,82 @@ public class DisplayAdjustments {
return false;
}
DisplayAdjustments daj = (DisplayAdjustments)o;
return Objects.equals(daj.mCompatInfo, mCompatInfo) &&
Objects.equals(daj.mConfiguration, mConfiguration);
return Objects.equals(daj.mCompatInfo, mCompatInfo)
&& Objects.equals(daj.mConfiguration, mConfiguration)
&& Objects.equals(daj.mFixedRotationAdjustments, mFixedRotationAdjustments);
}
/**
* An application can be launched in different rotation than the real display. This class
* provides the information to adjust the values returned by {@link #Display}.
* @hide
*/
public static class FixedRotationAdjustments implements Parcelable {
/** The application-based rotation. */
@Surface.Rotation
final int mRotation;
/** Non-null if the device has cutout. */
@Nullable
final DisplayCutout mRotatedDisplayCutout;
public FixedRotationAdjustments(@Surface.Rotation int rotation, DisplayCutout cutout) {
mRotation = rotation;
mRotatedDisplayCutout = cutout;
}
@Override
public int hashCode() {
int hash = 17;
hash = hash * 31 + mRotation;
hash = hash * 31 + Objects.hashCode(mRotatedDisplayCutout);
return hash;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof FixedRotationAdjustments)) {
return false;
}
final FixedRotationAdjustments other = (FixedRotationAdjustments) o;
return mRotation == other.mRotation
&& Objects.equals(mRotatedDisplayCutout, other.mRotatedDisplayCutout);
}
@Override
public String toString() {
return "FixedRotationAdjustments{rotation=" + Surface.rotationToString(mRotation)
+ " cutout=" + mRotatedDisplayCutout + "}";
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mRotation);
dest.writeTypedObject(
new DisplayCutout.ParcelableWrapper(mRotatedDisplayCutout), flags);
}
private FixedRotationAdjustments(Parcel in) {
mRotation = in.readInt();
final DisplayCutout.ParcelableWrapper cutoutWrapper =
in.readTypedObject(DisplayCutout.ParcelableWrapper.CREATOR);
mRotatedDisplayCutout = cutoutWrapper != null ? cutoutWrapper.get() : null;
}
public static final Creator<FixedRotationAdjustments> CREATOR =
new Creator<FixedRotationAdjustments>() {
public FixedRotationAdjustments createFromParcel(Parcel in) {
return new FixedRotationAdjustments(in);
}
public FixedRotationAdjustments[] newArray(int size) {
return new FixedRotationAdjustments[size];
}
};
}
}

View File

@@ -144,11 +144,12 @@ public class ObjectPoolTests {
IBinder assistToken = new Binder();
LaunchActivityItem emptyItem = LaunchActivityItem.obtain(null, 0, null, null, null, null,
null, null, 0, null, null, null, null, false, null, null);
null, null, 0, null, null, null, null, false, null, null, null);
LaunchActivityItem item = LaunchActivityItem.obtain(intent, ident, activityInfo,
config(), overrideConfig, compat, referrer, null /* voiceInteractor */,
procState, bundle, persistableBundle, resultInfoList(), referrerIntentList(),
true /* isForward */, null /* profilerInfo */, assistToken);
true /* isForward */, null /* profilerInfo */, assistToken,
null /* fixedRotationAdjustments */);
assertNotSame(item, emptyItem);
assertFalse(item.equals(emptyItem));
@@ -158,7 +159,8 @@ public class ObjectPoolTests {
LaunchActivityItem item2 = LaunchActivityItem.obtain(intent, ident, activityInfo,
config(), overrideConfig, compat, referrer, null /* voiceInteractor */,
procState, bundle, persistableBundle, resultInfoList(), referrerIntentList(),
true /* isForward */, null /* profilerInfo */, assistToken);
true /* isForward */, null /* profilerInfo */, assistToken,
null /* fixedRotationAdjustments */);
assertSame(item, item2);
assertFalse(item2.equals(emptyItem));
}

View File

@@ -267,7 +267,7 @@ public class TransactionExecutorTests {
null /* voiceInteractor */, 0 /* procState */, null /* state */,
null /* persistentState */, null /* pendingResults */,
null /* pendingNewIntents */, false /* isForward */, null /* profilerInfo */,
null /* assistToken*/));
null /* assistToken */, null /* fixedRotationAdjustments */));
launchTransaction.addCallback(launchItem);
mExecutor.execute(launchTransaction);

View File

@@ -52,6 +52,9 @@ import android.os.PersistableBundle;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.view.DisplayAdjustments.FixedRotationAdjustments;
import android.view.DisplayCutout;
import android.view.Surface;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -187,11 +190,14 @@ public class TransactionParcelTests {
bundle.putParcelable("data", new ParcelableData(1));
PersistableBundle persistableBundle = new PersistableBundle();
persistableBundle.putInt("k", 4);
FixedRotationAdjustments fixedRotationAdjustments = new FixedRotationAdjustments(
Surface.ROTATION_90, DisplayCutout.NO_CUTOUT);
LaunchActivityItem item = LaunchActivityItem.obtain(intent, ident, activityInfo,
config(), overrideConfig, compat, referrer, null /* voiceInteractor */,
procState, bundle, persistableBundle, resultInfoList(), referrerIntentList(),
true /* isForward */, null /* profilerInfo */, new Binder());
true /* isForward */, null /* profilerInfo */, new Binder(),
fixedRotationAdjustments);
writeAndPrepareForReading(item);
// Read from parcel and assert
@@ -340,6 +346,22 @@ public class TransactionParcelTests {
assertTrue(transaction.equals(result));
}
@Test
public void testFixedRotationAdjustments() {
ClientTransaction transaction = ClientTransaction.obtain(new StubAppThread(),
null /* activityToken */);
transaction.addCallback(FixedRotationAdjustmentsItem.obtain(new Binder(),
new FixedRotationAdjustments(Surface.ROTATION_270, DisplayCutout.NO_CUTOUT)));
writeAndPrepareForReading(transaction);
// Read from parcel and assert
ClientTransaction result = ClientTransaction.CREATOR.createFromParcel(mParcel);
assertEquals(transaction.hashCode(), result.hashCode());
assertTrue(transaction.equals(result));
}
/** Write to {@link #mParcel} and reset its position to prepare for reading from the start. */
private void writeAndPrepareForReading(Parcelable parcelable) {
parcelable.writeToParcel(mParcel, 0 /* flags */);

View File

@@ -259,4 +259,35 @@ public class ResourcesManagerTest extends TestCase {
expectedConfig2.orientation = Configuration.ORIENTATION_LANDSCAPE;
assertEquals(expectedConfig2, resources2.getConfiguration());
}
@SmallTest
public void testOverrideDisplayAdjustments() {
final int originalOverrideDensity = 200;
final int overrideDisplayDensity = 400;
final Binder token = new Binder();
final Configuration overrideConfig = new Configuration();
overrideConfig.densityDpi = originalOverrideDensity;
final Resources resources = mResourcesManager.createBaseTokenResources(
token, APP_ONE_RES_DIR, null /* splitResDirs */, null /* overlayDirs */,
null /* libDirs */, Display.DEFAULT_DISPLAY, overrideConfig,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null /* classLoader */,
null /* loaders */);
// Update the override.
boolean handled = mResourcesManager.overrideTokenDisplayAdjustments(token,
adjustments -> adjustments.getConfiguration().densityDpi = overrideDisplayDensity);
assertTrue(handled);
assertTrue(resources.hasOverrideDisplayAdjustments());
assertEquals(overrideDisplayDensity,
resources.getDisplayAdjustments().getConfiguration().densityDpi);
// Clear the override.
handled = mResourcesManager.overrideTokenDisplayAdjustments(token, null /* override */);
assertTrue(handled);
assertFalse(resources.hasOverrideDisplayAdjustments());
assertEquals(originalOverrideDensity,
resources.getDisplayAdjustments().getConfiguration().densityDpi);
}
}

View File

@@ -19,6 +19,9 @@ package android.view;
import static org.junit.Assert.assertEquals;
import android.content.res.Configuration;
import android.graphics.Point;
import android.util.DisplayMetrics;
import android.view.DisplayAdjustments.FixedRotationAdjustments;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -67,4 +70,38 @@ public class DisplayAdjustmentsTests {
assertEquals(configuration, newAdjustments.getConfiguration());
}
@Test
public void testFixedRotationAdjustments() {
final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments();
final int realRotation = Surface.ROTATION_0;
final int fixedRotation = Surface.ROTATION_90;
mDisplayAdjustments.setFixedRotationAdjustments(
new FixedRotationAdjustments(fixedRotation, null /* cutout */));
final int w = 1000;
final int h = 2000;
final Point size = new Point(w, h);
mDisplayAdjustments.adjustSize(size, realRotation);
assertEquals(fixedRotation, mDisplayAdjustments.getRotation(realRotation));
assertEquals(new Point(h, w), size);
final DisplayMetrics metrics = new DisplayMetrics();
metrics.xdpi = metrics.noncompatXdpi = w;
metrics.widthPixels = metrics.noncompatWidthPixels = w;
metrics.ydpi = metrics.noncompatYdpi = h;
metrics.heightPixels = metrics.noncompatHeightPixels = h;
final DisplayMetrics flippedMetrics = new DisplayMetrics();
flippedMetrics.xdpi = flippedMetrics.noncompatXdpi = h;
flippedMetrics.widthPixels = flippedMetrics.noncompatWidthPixels = h;
flippedMetrics.ydpi = flippedMetrics.noncompatYdpi = w;
flippedMetrics.heightPixels = flippedMetrics.noncompatHeightPixels = w;
mDisplayAdjustments.adjustMetrics(metrics, realRotation);
assertEquals(flippedMetrics, metrics);
}
}

View File

@@ -225,7 +225,8 @@ public class ActivityThreadClientTest {
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null /* referrer */,
null /* voiceInteractor */, null /* state */, null /* persistentState */,
null /* pendingResults */, null /* pendingNewIntents */, true /* isForward */,
null /* profilerInfo */, mThread /* client */, null /* asssitToken */);
null /* profilerInfo */, mThread /* client */, null /* asssitToken */,
null /* fixedRotationAdjustments */);
}
@Override

View File

@@ -842,7 +842,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(),
r.getSavedState(), r.getPersistentSavedState(), results, newIntents,
dc.isNextTransitionForward(), proc.createProfilerInfoIfNeeded(),
r.assistToken));
r.assistToken, r.createFixedRotationAdjustmentsIfNeeded()));
// Set desired final state.
final ActivityLifecycleItem lifecycleItem;

View File

@@ -19,6 +19,7 @@ package com.android.server.wm;
import static android.os.Process.INVALID_UID;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
@@ -40,6 +41,7 @@ import static com.android.server.wm.WindowTokenProto.WINDOW_CONTAINER;
import android.annotation.CallSuper;
import android.app.IWindowToken;
import android.app.servertransaction.FixedRotationAdjustmentsItem;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Debug;
@@ -47,6 +49,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.DisplayAdjustments.FixedRotationAdjustments;
import android.view.DisplayInfo;
import android.view.InsetsState;
import android.view.SurfaceControl;
@@ -529,6 +532,7 @@ class WindowToken extends WindowContainer<WindowState> {
mFixedRotationTransformState = new FixedRotationTransformState(info, displayFrames,
insetsState, new Configuration(config), mDisplayContent.getRotation());
onConfigurationChanged(getParent().getConfiguration());
notifyFixedRotationTransform(true /* enabled */);
}
/**
@@ -546,6 +550,7 @@ class WindowToken extends WindowContainer<WindowState> {
mFixedRotationTransformState = fixedRotationState;
fixedRotationState.mAssociatedTokens.add(this);
onConfigurationChanged(getParent().getConfiguration());
notifyFixedRotationTransform(true /* enabled */);
}
void finishFixedRotationTransform() {
@@ -578,9 +583,52 @@ class WindowToken extends WindowContainer<WindowState> {
// The state is cleared at the end, because it is used to indicate that other windows can
// use seamless rotation when applying rotation to display.
for (int i = state.mAssociatedTokens.size() - 1; i >= 0; i--) {
state.mAssociatedTokens.get(i).mFixedRotationTransformState = null;
state.mAssociatedTokens.get(i).cleanUpFixedRotationTransformState();
}
cleanUpFixedRotationTransformState();
}
private void cleanUpFixedRotationTransformState() {
mFixedRotationTransformState = null;
notifyFixedRotationTransform(false /* enabled */);
}
/** Notifies application side to enable or disable the rotation adjustment of display info. */
private void notifyFixedRotationTransform(boolean enabled) {
FixedRotationAdjustments adjustments = null;
// A token may contain windows of the same processes or different processes. The list is
// used to avoid sending the same adjustments to a process multiple times.
ArrayList<WindowProcessController> notifiedProcesses = null;
for (int i = mChildren.size() - 1; i >= 0; i--) {
final WindowState w = mChildren.get(i);
final WindowProcessController app;
if (w.mAttrs.type == TYPE_APPLICATION_STARTING) {
// Use the host activity because starting window is controlled by window manager.
final ActivityRecord r = asActivityRecord();
if (r == null) {
continue;
}
app = r.app;
} else {
app = mWmService.mAtmService.mProcessMap.getProcess(w.mSession.mPid);
}
if (app == null || !app.hasThread()) {
continue;
}
if (notifiedProcesses == null) {
notifiedProcesses = new ArrayList<>(2);
adjustments = enabled ? createFixedRotationAdjustmentsIfNeeded() : null;
} else if (notifiedProcesses.contains(app)) {
continue;
}
notifiedProcesses.add(app);
try {
mWmService.mAtmService.getLifecycleManager().scheduleTransaction(
app.getThread(), FixedRotationAdjustmentsItem.obtain(token, adjustments));
} catch (RemoteException e) {
Slog.w(TAG, "Failed to schedule DisplayAdjustmentsItem to " + app, e);
}
}
}
/** Restores the changes that applies to this container. */
@@ -590,6 +638,7 @@ class WindowToken extends WindowContainer<WindowState> {
// The window may be detached or detaching.
return;
}
notifyFixedRotationTransform(false /* enabled */);
final int originalRotation = getWindowConfiguration().getRotation();
onConfigurationChanged(parent.getConfiguration());
onCancelFixedRotationTransform(originalRotation);
@@ -603,6 +652,14 @@ class WindowToken extends WindowContainer<WindowState> {
void onCancelFixedRotationTransform(int originalDisplayRotation) {
}
FixedRotationAdjustments createFixedRotationAdjustmentsIfNeeded() {
if (!isFixedRotationTransforming()) {
return null;
}
return new FixedRotationAdjustments(mFixedRotationTransformState.mDisplayInfo.rotation,
mFixedRotationTransformState.mDisplayInfo.displayCutout);
}
@Override
void resolveOverrideConfiguration(Configuration newParentConfig) {
super.resolveOverrideConfiguration(newParentConfig);