Merge "Introducing WindowConfiguration"

This commit is contained in:
Wale Ogunwale
2017-08-18 17:46:25 +00:00
committed by Android (Google) Code Review
11 changed files with 391 additions and 181 deletions

View File

@@ -0,0 +1,19 @@
/*
* 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 android.app;
parcelable WindowConfiguration;

View File

@@ -0,0 +1,225 @@
/*
* 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 android.app;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.DisplayInfo;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Class that contains windowing configuration/state for other objects that contain windows directly
* or indirectly. E.g. Activities, Task, Displays, ...
* The test class is {@link com.android.server.wm.WindowConfigurationTests} which must be kept
* up-to-date and ran anytime changes are made to this class.
* @hide
*/
public class WindowConfiguration implements Parcelable, Comparable<WindowConfiguration> {
/**
* {@link android.graphics.Rect} defining app bounds. The dimensions override usages of
* {@link DisplayInfo#appHeight} and {@link DisplayInfo#appWidth} and mirrors these values at
* the display level. Lower levels can override these values to provide custom bounds to enforce
* features such as a max aspect ratio.
*/
private Rect mAppBounds;
@IntDef(flag = true,
value = {
WINDOW_CONFIG_APP_BOUNDS,
})
@Retention(RetentionPolicy.SOURCE)
public @interface WindowConfig {}
/** Bit that indicates that the {@link #mAppBounds} changed. */
public static final int WINDOW_CONFIG_APP_BOUNDS = 1 << 0;
public WindowConfiguration() {
unset();
}
public WindowConfiguration(WindowConfiguration configuration) {
setTo(configuration);
}
private WindowConfiguration(Parcel in) {
readFromParcel(in);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(mAppBounds, flags);
}
private void readFromParcel(Parcel source) {
mAppBounds = source.readParcelable(Rect.class.getClassLoader());
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<WindowConfiguration> CREATOR = new Creator<WindowConfiguration>() {
@Override
public WindowConfiguration createFromParcel(Parcel in) {
return new WindowConfiguration(in);
}
@Override
public WindowConfiguration[] newArray(int size) {
return new WindowConfiguration[size];
}
};
/**
* Set {@link #mAppBounds} to the input Rect.
* @param rect The rect value to set {@link #mAppBounds} to.
* @see #getAppBounds()
*/
public void setAppBounds(Rect rect) {
if (rect == null) {
mAppBounds = null;
return;
}
setAppBounds(rect.left, rect.top, rect.right, rect.bottom);
}
/**
* @see #setAppBounds(Rect)
* @see #getAppBounds()
*/
public void setAppBounds(int left, int top, int right, int bottom) {
if (mAppBounds == null) {
mAppBounds = new Rect();
}
mAppBounds.set(left, top, right, bottom);
}
/**
* @see #setAppBounds(Rect)
*/
public Rect getAppBounds() {
return mAppBounds;
}
public void setTo(WindowConfiguration other) {
setAppBounds(other.mAppBounds);
}
/** Set this object to completely undefined. */
public void unset() {
setToDefaults();
}
public void setToDefaults() {
setAppBounds(null);
}
/**
* Copies the fields from delta into this Configuration object, keeping
* track of which ones have changed. Any undefined fields in {@code delta}
* are ignored and not copied in to the current Configuration.
*
* @return a bit mask of the changed fields, as per {@link #diff}
*/
public @WindowConfig int updateFrom(@NonNull WindowConfiguration delta) {
int changed = 0;
if (delta.mAppBounds != null && !delta.mAppBounds.equals(mAppBounds)) {
changed |= WINDOW_CONFIG_APP_BOUNDS;
setAppBounds(delta.mAppBounds);
}
return changed;
}
/**
* Return a bit mask of the differences between this Configuration object and the given one.
* Does not change the values of either. Any undefined fields in <var>other</var> are ignored.
* @param other The configuration to diff against.
* @param compareUndefined If undefined values should be compared.
* @return Returns a bit mask indicating which configuration
* values has changed, containing any combination of {@link WindowConfig} flags.
*
* @see Configuration#diff(Configuration)
*/
public @WindowConfig long diff(WindowConfiguration other, boolean compareUndefined) {
long changes = 0;
// Make sure that one of the values is not null and that they are not equal.
if ((compareUndefined || other.mAppBounds != null)
&& mAppBounds != other.mAppBounds
&& (mAppBounds == null || !mAppBounds.equals(other.mAppBounds))) {
changes |= WINDOW_CONFIG_APP_BOUNDS;
}
return changes;
}
@Override
public int compareTo(WindowConfiguration that) {
int n = 0;
if (mAppBounds == null && that.mAppBounds != null) {
return 1;
} else if (mAppBounds != null && that.mAppBounds == null) {
return -1;
} else if (mAppBounds != null && that.mAppBounds != null) {
n = mAppBounds.left - that.mAppBounds.left;
if (n != 0) return n;
n = mAppBounds.top - that.mAppBounds.top;
if (n != 0) return n;
n = mAppBounds.right - that.mAppBounds.right;
if (n != 0) return n;
n = mAppBounds.bottom - that.mAppBounds.bottom;
if (n != 0) return n;
}
// if (n != 0) return n;
return n;
}
@Override
public boolean equals(Object that) {
if (that == null) return false;
if (that == this) return true;
if (!(that instanceof WindowConfiguration)) {
return false;
}
return this.compareTo((WindowConfiguration) that) == 0;
}
@Override
public int hashCode() {
int result = 0;
if (mAppBounds != null) {
result = 31 * result + mAppBounds.hashCode();
}
return result;
}
@Override
public String toString() {
return "{mAppBounds=" + mAppBounds + "}";
}
}

View File

@@ -780,6 +780,13 @@ public class ActivityInfo extends ComponentInfo
* constant starts at the high bits.
*/
public static final int CONFIG_FONT_SCALE = 0x40000000;
/**
* Bit indicating changes to window configuration that isn't exposed to apps.
* This is for internal use only and apps don't handle it.
* @hide
* {@link Configuration}.
*/
public static final int CONFIG_WINDOW_CONFIGURATION = 0x20000000;
/** @hide
* Unfortunately the constants for config changes in native code are

View File

@@ -19,15 +19,14 @@ package android.content.res;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.WindowConfiguration;
import android.content.pm.ActivityInfo;
import android.content.pm.ActivityInfo.Config;
import android.graphics.Rect;
import android.os.Build;
import android.os.LocaleList;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.view.DisplayInfo;
import android.view.View;
import com.android.internal.util.XmlUtils;
@@ -42,7 +41,6 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Locale;
/**
* This class describes all device configuration information that can
* impact the resources the application retrieves. This includes both
@@ -298,13 +296,11 @@ public final class Configuration implements Parcelable, Comparable<Configuration
/**
* @hide
* {@link android.graphics.Rect} defining app bounds. The dimensions override usages of
* {@link DisplayInfo#appHeight} and {@link DisplayInfo#appWidth} and mirrors these values at
* the display level. Lower levels can override these values to provide custom bounds to enforce
* features such as a max aspect ratio.
* TODO(b/36812336): Move appBounds out of {@link Configuration}.
* Configuration relating to the windowing state of the object associated with this
* Configuration. Contents of this field are not intended to affect resources, but need to be
* communicated and propagated at the same time as the rest of Configuration.
*/
public Rect appBounds;
public final WindowConfiguration windowConfiguration = new WindowConfiguration();
/** @hide */
static public int resetScreenLayout(int curLayout) {
@@ -895,9 +891,9 @@ public final class Configuration implements Parcelable, Comparable<Configuration
compatScreenWidthDp = o.compatScreenWidthDp;
compatScreenHeightDp = o.compatScreenHeightDp;
compatSmallestScreenWidthDp = o.compatSmallestScreenWidthDp;
setAppBounds(o.appBounds);
assetsSeq = o.assetsSeq;
seq = o.seq;
windowConfiguration.setTo(o.windowConfiguration);
}
public String toString() {
@@ -1046,9 +1042,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
case NAVIGATIONHIDDEN_YES: sb.append("/h"); break;
default: sb.append("/"); sb.append(navigationHidden); break;
}
if (appBounds != null) {
sb.append(" appBounds="); sb.append(appBounds);
}
sb.append(" winConfig="); sb.append(windowConfiguration);
if (assetsSeq != 0) {
sb.append(" as.").append(assetsSeq);
}
@@ -1083,8 +1077,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration
smallestScreenWidthDp = compatSmallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
densityDpi = DENSITY_DPI_UNDEFINED;
assetsSeq = ASSETS_SEQ_UNDEFINED;
appBounds = null;
seq = 0;
windowConfiguration.setToDefaults();
}
/**
@@ -1183,7 +1177,6 @@ public final class Configuration implements Parcelable, Comparable<Configuration
changed |= ActivityInfo.CONFIG_ORIENTATION;
orientation = delta.orientation;
}
if (((delta.screenLayout & SCREENLAYOUT_SIZE_MASK) != SCREENLAYOUT_SIZE_UNDEFINED)
&& (delta.screenLayout & SCREENLAYOUT_SIZE_MASK)
!= (screenLayout & SCREENLAYOUT_SIZE_MASK)) {
@@ -1271,10 +1264,6 @@ public final class Configuration implements Parcelable, Comparable<Configuration
if (delta.compatSmallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
compatSmallestScreenWidthDp = delta.compatSmallestScreenWidthDp;
}
if (delta.appBounds != null && !delta.appBounds.equals(appBounds)) {
changed |= ActivityInfo.CONFIG_SCREEN_SIZE;
setAppBounds(delta.appBounds);
}
if (delta.assetsSeq != ASSETS_SEQ_UNDEFINED && delta.assetsSeq != assetsSeq) {
changed |= ActivityInfo.CONFIG_ASSETS_PATHS;
assetsSeq = delta.assetsSeq;
@@ -1282,6 +1271,9 @@ public final class Configuration implements Parcelable, Comparable<Configuration
if (delta.seq != 0) {
seq = delta.seq;
}
if (windowConfiguration.updateFrom(delta.windowConfiguration) != 0) {
changed |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
}
return changed;
}
@@ -1433,13 +1425,10 @@ public final class Configuration implements Parcelable, Comparable<Configuration
changed |= ActivityInfo.CONFIG_ASSETS_PATHS;
}
// Make sure that one of the values is not null and that they are not equal.
if ((compareUndefined || delta.appBounds != null)
&& appBounds != delta.appBounds
&& (appBounds == null || (!publicOnly && !appBounds.equals(delta.appBounds))
|| (publicOnly && (appBounds.width() != delta.appBounds.width()
|| appBounds.height() != delta.appBounds.height())))) {
changed |= ActivityInfo.CONFIG_SCREEN_SIZE;
// WindowConfiguration differences aren't considered public...
if (!publicOnly
&& windowConfiguration.diff(delta.windowConfiguration, compareUndefined) != 0) {
changed |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
}
return changed;
@@ -1537,7 +1526,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
dest.writeInt(compatScreenWidthDp);
dest.writeInt(compatScreenHeightDp);
dest.writeInt(compatSmallestScreenWidthDp);
dest.writeValue(appBounds);
dest.writeValue(windowConfiguration);
dest.writeInt(assetsSeq);
dest.writeInt(seq);
}
@@ -1573,7 +1562,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
compatScreenWidthDp = source.readInt();
compatScreenHeightDp = source.readInt();
compatSmallestScreenWidthDp = source.readInt();
appBounds = (Rect) source.readValue(null);
windowConfiguration.setTo((WindowConfiguration) source.readValue(null));
assetsSeq = source.readInt();
seq = source.readInt();
}
@@ -1663,21 +1652,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration
if (n != 0) return n;
n = this.assetsSeq - that.assetsSeq;
if (n != 0) return n;
if (this.appBounds == null && that.appBounds != null) {
return 1;
} else if (this.appBounds != null && that.appBounds == null) {
return -1;
} else if (this.appBounds != null && that.appBounds != null) {
n = this.appBounds.left - that.appBounds.left;
if (n != 0) return n;
n = this.appBounds.top - that.appBounds.top;
if (n != 0) return n;
n = this.appBounds.right - that.appBounds.right;
if (n != 0) return n;
n = this.appBounds.bottom - that.appBounds.bottom;
if (n != 0) return n;
}
n = windowConfiguration.compareTo(that.windowConfiguration);
if (n != 0) return n;
// if (n != 0) return n;
return n;
@@ -1765,33 +1741,6 @@ public final class Configuration implements Parcelable, Comparable<Configuration
setLocales(loc == null ? LocaleList.getEmptyLocaleList() : new LocaleList(loc));
}
/**
* @hide
*
* Helper method for setting the app bounds.
*/
public void setAppBounds(Rect rect) {
if (rect == null) {
appBounds = null;
return;
}
setAppBounds(rect.left, rect.top, rect.right, rect.bottom);
}
/**
* @hide
*
* Helper method for setting the app bounds.
*/
public void setAppBounds(int left, int top, int right, int bottom) {
if (appBounds == null) {
appBounds = new Rect();
}
appBounds.set(left, top, right, bottom);
}
/**
* @hide
*
@@ -2282,6 +2231,10 @@ public final class Configuration implements Parcelable, Comparable<Configuration
if (base.assetsSeq != change.assetsSeq) {
delta.assetsSeq = change.assetsSeq;
}
if (!base.windowConfiguration.equals(change.windowConfiguration)) {
delta.windowConfiguration.setTo(change.windowConfiguration);
}
return delta;
}
@@ -2354,10 +2307,9 @@ public final class Configuration implements Parcelable, Comparable<Configuration
SMALLEST_SCREEN_WIDTH_DP_UNDEFINED);
configOut.densityDpi = XmlUtils.readIntAttribute(parser, XML_ATTR_DENSITY,
DENSITY_DPI_UNDEFINED);
configOut.appBounds =
Rect.unflattenFromString(XmlUtils.readStringAttribute(parser, XML_ATTR_APP_BOUNDS));
// For persistence, we don't care about assetsSeq, so do not read it out.
// For persistence, we don't care about assetsSeq and WindowConfiguration, so do not read it
// out.
}
@@ -2427,11 +2379,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
XmlUtils.writeIntAttribute(xml, XML_ATTR_DENSITY, config.densityDpi);
}
if (config.appBounds != null) {
XmlUtils.writeStringAttribute(xml, XML_ATTR_APP_BOUNDS,
config.appBounds.flattenToString());
}
// For persistence, we do not care about assetsSeq, so do not write it out.
// For persistence, we do not care about assetsSeq and window configuration, so do not write
// it out.
}
}

View File

@@ -23,6 +23,7 @@ import static android.view.DisplayInfoProto.LOGICAL_WIDTH;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArraySet;
@@ -568,10 +569,10 @@ public final class DisplayInfo implements Parcelable {
outMetrics.xdpi = outMetrics.noncompatXdpi = physicalXDpi;
outMetrics.ydpi = outMetrics.noncompatYdpi = physicalYDpi;
width = configuration != null && configuration.appBounds != null
? configuration.appBounds.width() : width;
height = configuration != null && configuration.appBounds != null
? configuration.appBounds.height() : height;
final Rect appBounds = configuration != null
? configuration.windowConfiguration.getAppBounds() : null;
width = appBounds != null ? appBounds.width() : width;
height = appBounds != null ? appBounds.height() : height;
outMetrics.noncompatWidthPixels = outMetrics.widthPixels = width;
outMetrics.noncompatHeightPixels = outMetrics.heightPixels = height;

View File

@@ -46,6 +46,7 @@ import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
import static android.content.pm.ActivityInfo.CONFIG_UI_MODE;
import static android.content.pm.ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
import static android.content.pm.ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
@@ -429,11 +430,11 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
pw.print("\"");
pw.print(" primaryColor=");
pw.println(Integer.toHexString(taskDescription.getPrimaryColor()));
pw.print(prefix); pw.print(" backgroundColor=");
pw.print(prefix + " backgroundColor=");
pw.println(Integer.toHexString(taskDescription.getBackgroundColor()));
pw.print(prefix); pw.print(" statusBarColor=");
pw.print(prefix + " statusBarColor=");
pw.println(Integer.toHexString(taskDescription.getStatusBarColor()));
pw.print(prefix); pw.print(" navigationBarColor=");
pw.print(prefix + " navigationBarColor=");
pw.println(Integer.toHexString(taskDescription.getNavigationBarColor()));
}
if (iconFilename == null && taskDescription.getIcon() != null) {
@@ -2311,9 +2312,9 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
// We must base this on the parent configuration, because we set our override
// configuration's appBounds based on the result of this method. If we used our own
// configuration, it would be influenced by past invocations.
final Configuration configuration = getParent().getConfiguration();
final int containingAppWidth = configuration.appBounds.width();
final int containingAppHeight = configuration.appBounds.height();
final Rect appBounds = getParent().getConfiguration().windowConfiguration.getAppBounds();
final int containingAppWidth = appBounds.width();
final int containingAppHeight = appBounds.height();
int maxActivityWidth = containingAppWidth;
int maxActivityHeight = containingAppHeight;
@@ -2342,8 +2343,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
outBounds.set(0, 0, maxActivityWidth, maxActivityHeight);
// Position the activity frame on the opposite side of the nav bar.
final int navBarPosition = service.mWindowManager.getNavBarPosition();
final int left = navBarPosition == NAV_BAR_LEFT
? configuration.appBounds.right - outBounds.width() : 0;
final int left = navBarPosition == NAV_BAR_LEFT ? appBounds.right - outBounds.width() : 0;
outBounds.offsetTo(left, 0 /* top */);
}
@@ -2574,6 +2574,10 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
changes &= ~CONFIG_SMALLEST_SCREEN_SIZE;
}
}
// We don't want window configuration to cause relaunches.
if ((changes & CONFIG_WINDOW_CONFIGURATION) != 0) {
changes &= ~CONFIG_WINDOW_CONFIGURATION;
}
return changes;
}

View File

@@ -1205,8 +1205,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
final int leftInset = mTmpRect.left;
final int topInset = mTmpRect.top;
// appBounds at the root level should mirror the app screen size.
config.setAppBounds(leftInset /*left*/, topInset /*top*/, leftInset + displayInfo.appWidth /*right*/,
topInset + displayInfo.appHeight /*bottom*/);
config.windowConfiguration.setAppBounds(leftInset /* left */, topInset /* top */,
leftInset + displayInfo.appWidth /* right */,
topInset + displayInfo.appHeight /* bottom */);
final boolean rotated = (displayInfo.rotation == Surface.ROTATION_90
|| displayInfo.rotation == Surface.ROTATION_270);

View File

@@ -241,8 +241,8 @@ public class DockedStackDividerController implements DimLayerUser {
final int leftInset = mTmpRect.left;
final int topInset = mTmpRect.top;
config.setAppBounds(leftInset /*left*/, topInset /*top*/, leftInset + appWidth /*right*/,
topInset + appHeight /*bottom*/);
config.windowConfiguration.setAppBounds(leftInset /*left*/, topInset /*top*/,
leftInset + appWidth /*right*/, topInset + appHeight /*bottom*/);
config.screenWidthDp = (int)
(mService.mPolicy.getConfigDisplayWidth(dw, dh, rotation, baseConfig.uiMode,

View File

@@ -16,11 +16,9 @@
package com.android.server.wm;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import android.app.ActivityManager.StackId;
import android.app.RemoteAction;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Handler;
@@ -30,11 +28,9 @@ import android.util.Slog;
import android.util.SparseArray;
import android.view.DisplayInfo;
import com.android.server.UiThread;
import com.android.internal.annotations.VisibleForTesting;
import java.lang.ref.WeakReference;
import java.util.List;
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
@@ -278,9 +274,9 @@ public class StackWindowController
int width;
int height;
final Rect parentAppBounds = parentConfig.appBounds;
final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds();
config.setAppBounds(!bounds.isEmpty() ? bounds : null);
config.windowConfiguration.setAppBounds(!bounds.isEmpty() ? bounds : null);
boolean intersectParentBounds = false;
if (StackId.tasksAreFloating(mStackId)) {
@@ -295,7 +291,7 @@ public class StackWindowController
nonDecorBounds.inset(mTmpNonDecorInsets);
// Move app bounds to zero to apply intersection with parent correctly. They are
// used only for evaluating width and height, so it's OK to move them around.
config.appBounds.offsetTo(0, 0);
config.windowConfiguration.getAppBounds().offsetTo(0, 0);
intersectParentBounds = true;
}
width = (int) (stableBounds.width() / density);
@@ -319,8 +315,8 @@ public class StackWindowController
intersectParentBounds = true;
}
if (intersectParentBounds && config.appBounds != null) {
config.appBounds.intersect(parentAppBounds);
if (intersectParentBounds && config.windowConfiguration.getAppBounds() != null) {
config.windowConfiguration.getAppBounds().intersect(parentAppBounds);
}
config.screenWidthDp = width;

View File

@@ -126,7 +126,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
// Verify with nav bar on the right.
when(service.mWindowManager.getNavBarPosition()).thenReturn(navBarPosition);
task.getConfiguration().setAppBounds(taskBounds);
task.getConfiguration().windowConfiguration.setAppBounds(taskBounds);
record.info.maxAspectRatio = aspectRatio;
record.ensureActivityConfigurationLocked(0 /* globalChanges */, false /* preserveWindow */);
assertEquals(expectedActivityBounds, record.getBounds());

View File

@@ -11,36 +11,38 @@
* 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
* limitations under the License.
*/
package com.android.server.wm;
import android.app.ActivityManager;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.view.DisplayInfo;
import org.junit.Test;
import android.app.WindowConfiguration;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.DisplayInfo;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS;
import static android.content.pm.ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
/**
* Test class to exercise logic related to {@link android.content.res.Configuration#appBounds}.
* Test class to for {@link android.app.WindowConfiguration}.
*
* Build/Install/Run:
* bit FrameworksServicesTests:com.android.server.wm.AppBoundsTests
* bit FrameworksServicesTests:com.android.server.wm.WindowConfigurationTests
*/
@SmallTest
@Presubmit
@org.junit.runner.RunWith(AndroidJUnit4.class)
public class AppBoundsTests extends WindowTestsBase {
public class WindowConfigurationTests extends WindowTestsBase {
private Rect mParentBounds;
@Override
@@ -49,44 +51,82 @@ public class AppBoundsTests extends WindowTestsBase {
mParentBounds = new Rect(10 /*left*/, 30 /*top*/, 80 /*right*/, 60 /*bottom*/);
}
/**
* Ensures that appBounds causes {@link android.content.pm.ActivityInfo.CONFIG_APP_BOUNDS} diff.
*/
/** Tests {@link android.app.WindowConfiguration#diff(WindowConfiguration, boolean)}. */
@Test
public void testAppBoundsConfigurationDiff() {
final Configuration config = new Configuration();
public void testDiff() {
final Configuration config1 = new Configuration();
final WindowConfiguration winConfig1 = config1.windowConfiguration;
final Configuration config2 = new Configuration();
config.appBounds = new Rect(0, 1, 1, 0);
config2.appBounds = new Rect(1, 2, 2, 1);
final WindowConfiguration winConfig2 = config2.windowConfiguration;
final Configuration config3 = new Configuration();
final WindowConfiguration winConfig3 = config3.windowConfiguration;
assertEquals(ActivityInfo.CONFIG_SCREEN_SIZE, config.diff(config2));
assertEquals(0, config.diffPublicOnly(config2));
winConfig1.setAppBounds(0, 1, 1, 0);
winConfig2.setAppBounds(1, 2, 2, 1);
winConfig3.setAppBounds(winConfig1.getAppBounds());
assertEquals(CONFIG_WINDOW_CONFIGURATION, config1.diff(config2));
assertEquals(0, config1.diffPublicOnly(config2));
assertEquals(WINDOW_CONFIG_APP_BOUNDS,
winConfig1.diff(winConfig2, false /* compareUndefined */));
assertEquals(0, config1.diff(config3));
assertEquals(0, config1.diffPublicOnly(config3));
assertEquals(0, winConfig1.diff(winConfig3, false /* compareUndefined */));
}
/**
* Ensures the configuration app bounds at the root level match the app dimensions.
*/
/** Tests {@link android.app.WindowConfiguration#compareTo(WindowConfiguration)}. */
@Test
public void testRootConfigurationBounds() throws Exception {
public void testConfigurationCompareTo() throws Exception {
final Configuration blankConfig = new Configuration();
final WindowConfiguration blankWinConfig = new WindowConfiguration();
final Configuration config1 = new Configuration();
final WindowConfiguration winConfig1 = config1.windowConfiguration;
winConfig1.setAppBounds(1, 2, 3, 4);
final Configuration config2 = new Configuration(config1);
final WindowConfiguration winConfig2 = config2.windowConfiguration;
assertEquals(config1.compareTo(config2), 0);
assertEquals(winConfig1.compareTo(winConfig2), 0);
// Different bounds
winConfig2.setAppBounds(0, 2, 3, 4);
assertNotEquals(config1.compareTo(config2), 0);
assertNotEquals(winConfig1.compareTo(winConfig2), 0);
// No bounds
assertEquals(config1.compareTo(blankConfig), -1);
assertEquals(winConfig1.compareTo(blankWinConfig), -1);
assertEquals(blankConfig.compareTo(config1), 1);
assertEquals(blankWinConfig.compareTo(winConfig1), 1);
}
/** Ensures the configuration app bounds at the root level match the app dimensions. */
@Test
public void testAppBounds_RootConfigurationBounds() throws Exception {
final DisplayInfo info = mDisplayContent.getDisplayInfo();
info.appWidth = 1024;
info.appHeight = 768;
final Configuration config = sWm.computeNewConfiguration(mDisplayContent.getDisplayId());
final Rect appBounds = sWm.computeNewConfiguration(
mDisplayContent.getDisplayId()).windowConfiguration.getAppBounds();
// The bounds should always be positioned in the top left.
assertEquals(config.appBounds.left, 0);
assertEquals(config.appBounds.top, 0);
assertEquals(appBounds.left, 0);
assertEquals(appBounds.top, 0);
// The bounds should equal the defined app width and height
assertEquals(config.appBounds.width(), info.appWidth);
assertEquals(config.appBounds.height(), info.appHeight);
assertEquals(appBounds.width(), info.appWidth);
assertEquals(appBounds.height(), info.appHeight);
}
/**
* Ensures that bounds are clipped to their parent.
*/
/** Ensures that bounds are clipped to their parent. */
@Test
public void testBoundsClipping() throws Exception {
public void testAppBounds_BoundsClipping() throws Exception {
final Rect shiftedBounds = new Rect(mParentBounds);
shiftedBounds.offset(10, 10);
final Rect expectedBounds = new Rect(mParentBounds);
@@ -95,42 +135,34 @@ public class AppBoundsTests extends WindowTestsBase {
expectedBounds);
}
/**
* Ensures that empty bounds are not propagated to the configuration.
*/
/** Ensures that empty bounds are not propagated to the configuration. */
@Test
public void testEmptyBounds() throws Exception {
public void testAppBounds_EmptyBounds() throws Exception {
final Rect emptyBounds = new Rect();
testStackBoundsConfiguration(null /*stackId*/, mParentBounds, emptyBounds,
null /*ExpectedBounds*/);
}
/**
* Ensures that bounds on freeform stacks are not clipped.
*/
/** Ensures that bounds on freeform stacks are not clipped. */
@Test
public void testFreeFormBounds() throws Exception {
public void testAppBounds_FreeFormBounds() throws Exception {
final Rect freeFormBounds = new Rect(mParentBounds);
freeFormBounds.offset(10, 10);
testStackBoundsConfiguration(ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID,
mParentBounds, freeFormBounds, freeFormBounds);
testStackBoundsConfiguration(FREEFORM_WORKSPACE_STACK_ID, mParentBounds, freeFormBounds,
freeFormBounds);
}
/**
* Ensures that fully contained bounds are not clipped.
*/
/** Ensures that fully contained bounds are not clipped. */
@Test
public void testContainedBounds() throws Exception {
public void testAppBounds_ContainedBounds() throws Exception {
final Rect insetBounds = new Rect(mParentBounds);
insetBounds.inset(5, 5, 5, 5);
testStackBoundsConfiguration(null /*stackId*/, mParentBounds, insetBounds, insetBounds);
}
/**
* Ensures that full screen free form bounds are clipped
*/
/** Ensures that full screen free form bounds are clipped */
@Test
public void testFullScreenFreeFormBounds() throws Exception {
public void testAppBounds_FullScreenFreeFormBounds() throws Exception {
final Rect fullScreenBounds = new Rect(0, 0, mDisplayInfo.logicalWidth,
mDisplayInfo.logicalHeight);
testStackBoundsConfiguration(null /*stackId*/, mParentBounds, fullScreenBounds,
@@ -144,40 +176,17 @@ public class AppBoundsTests extends WindowTestsBase {
: createStackControllerOnDisplay(mDisplayContent);
final Configuration parentConfig = mDisplayContent.getConfiguration();
parentConfig.setAppBounds(parentBounds);
parentConfig.windowConfiguration.setAppBounds(parentBounds);
final Configuration config = new Configuration();
final WindowConfiguration winConfig = config.windowConfiguration;
stackController.adjustConfigurationForBounds(bounds, null /*insetBounds*/,
new Rect() /*nonDecorBounds*/, new Rect() /*stableBounds*/, false /*overrideWidth*/,
false /*overrideHeight*/, mDisplayInfo.logicalDensityDpi, config, parentConfig);
// Assert that both expected and actual are null or are equal to each other
assertTrue((expectedConfigBounds == null && config.appBounds == null)
|| expectedConfigBounds.equals(config.appBounds));
assertTrue((expectedConfigBounds == null && winConfig.getAppBounds() == null)
|| expectedConfigBounds.equals(winConfig.getAppBounds()));
}
/**
* Ensures appBounds are considered in {@link Configuration#compareTo(Configuration)}.
*/
@Test
public void testConfigurationCompareTo() throws Exception {
final Configuration blankConfig = new Configuration();
final Configuration config1 = new Configuration();
config1.appBounds = new Rect(1, 2, 3, 4);
final Configuration config2 = new Configuration(config1);
assertEquals(config1.compareTo(config2), 0);
config2.appBounds.left = 0;
// Different bounds
assertNotEquals(config1.compareTo(config2), 0);
// No bounds
assertEquals(config1.compareTo(blankConfig), -1);
assertEquals(blankConfig.compareTo(config1), 1);
}
}