Merge "DisplayCutout: Move emulation into resource overlay"
This commit is contained in:
committed by
Android (Google) Code Review
commit
7ac85a3b87
@@ -2784,6 +2784,11 @@
|
||||
the display's native orientation. -->
|
||||
<string translatable="false" name="config_mainBuiltInDisplayCutout"></string>
|
||||
|
||||
<!-- Whether the display cutout region of the main built-in display should be forced to
|
||||
black in software (to avoid aliasing or emulate a cutout that is not physically existent).
|
||||
-->
|
||||
<bool name="config_fillMainBuiltInDisplayCutout">false</bool>
|
||||
|
||||
<!-- Ultrasound support for Mic/speaker path -->
|
||||
<!-- Whether the default microphone audio source supports near-ultrasound frequencies
|
||||
(range of 18 - 21 kHz). -->
|
||||
|
||||
@@ -3203,6 +3203,7 @@
|
||||
|
||||
<java-symbol type="string" name="global_action_logout" />
|
||||
<java-symbol type="string" name="config_mainBuiltInDisplayCutout" />
|
||||
<java-symbol type="bool" name="config_fillMainBuiltInDisplayCutout" />
|
||||
<java-symbol type="drawable" name="ic_logout" />
|
||||
|
||||
<java-symbol type="array" name="config_autoBrightnessDisplayValuesNits" />
|
||||
|
||||
@@ -38,6 +38,9 @@ import android.view.ViewGroup.LayoutParams;
|
||||
import android.view.WindowInsets;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@@ -45,18 +48,28 @@ import java.util.List;
|
||||
* Emulates a display cutout by drawing its shape in an overlay as supplied by
|
||||
* {@link DisplayCutout}.
|
||||
*/
|
||||
public class EmulatedDisplayCutout extends SystemUI {
|
||||
public class EmulatedDisplayCutout extends SystemUI implements ConfigurationListener {
|
||||
private View mOverlay;
|
||||
private boolean mAttached;
|
||||
private WindowManager mWindowManager;
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
Dependency.get(ConfigurationController.class).addCallback(this);
|
||||
|
||||
mWindowManager = mContext.getSystemService(WindowManager.class);
|
||||
mContext.getContentResolver().registerContentObserver(
|
||||
Settings.Global.getUriFor(Settings.Global.EMULATE_DISPLAY_CUTOUT),
|
||||
false, mObserver, UserHandle.USER_ALL);
|
||||
mObserver.onChange(false);
|
||||
updateAttached();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOverlayChanged() {
|
||||
updateAttached();
|
||||
}
|
||||
|
||||
private void updateAttached() {
|
||||
boolean shouldAttach = mContext.getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout);
|
||||
setAttached(shouldAttach);
|
||||
}
|
||||
|
||||
private void setAttached(boolean attached) {
|
||||
@@ -94,17 +107,6 @@ public class EmulatedDisplayCutout extends SystemUI {
|
||||
return lp;
|
||||
}
|
||||
|
||||
private ContentObserver mObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
boolean emulateCutout = Settings.Global.getInt(
|
||||
mContext.getContentResolver(), Settings.Global.EMULATE_DISPLAY_CUTOUT,
|
||||
Settings.Global.EMULATE_DISPLAY_CUTOUT_OFF)
|
||||
!= Settings.Global.EMULATE_DISPLAY_CUTOUT_OFF;
|
||||
setAttached(emulateCutout);
|
||||
}
|
||||
};
|
||||
|
||||
private static class CutoutView extends View {
|
||||
private final Paint mPaint = new Paint();
|
||||
private final Path mBounds = new Path();
|
||||
|
||||
13
packages/overlays/DisplayCutoutEmulationOverlay/Android.mk
Normal file
13
packages/overlays/DisplayCutoutEmulationOverlay/Android.mk
Normal file
@@ -0,0 +1,13 @@
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_RRO_THEME := DisplayCutoutEmulation
|
||||
LOCAL_CERTIFICATE := platform
|
||||
|
||||
LOCAL_SRC_FILES := $(call all-subdir-java-files)
|
||||
|
||||
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
|
||||
|
||||
LOCAL_PACKAGE_NAME := DisplayCutoutEmulationOverlay
|
||||
|
||||
include $(BUILD_RRO_PACKAGE)
|
||||
@@ -0,0 +1,8 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.internal.display.cutout.emulation"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0">
|
||||
<overlay android:targetPackage="android" android:priority="1"/>
|
||||
|
||||
<application android:label="@string/display_cutout_emulation_overlay" android:hasCode="false"/>
|
||||
</manifest>
|
||||
@@ -0,0 +1,44 @@
|
||||
<!--
|
||||
~ Copyright (C) 2018 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
|
||||
<!-- The bounding path of the cutout region of the main built-in display.
|
||||
Must either be empty if there is no cutout region, or a string that is parsable by
|
||||
{@link android.util.PathParser}. -->
|
||||
<string translatable="false" name="config_mainBuiltInDisplayCutout">
|
||||
M 687.0,0
|
||||
l -66,50
|
||||
l 0,50
|
||||
l 66,50
|
||||
l 66,0
|
||||
l 66,-50
|
||||
l 0,-50
|
||||
l -66,-50
|
||||
z
|
||||
</string>
|
||||
|
||||
<!-- Whether the display cutout region of the main built-in display should be forced to
|
||||
black in software (to avoid aliasing or emulate a cutout that is not physically existent).
|
||||
-->
|
||||
<bool name="config_fillMainBuiltInDisplayCutout">true</bool>
|
||||
|
||||
<!-- Height of the status bar -->
|
||||
<dimen name="status_bar_height">150px</dimen>
|
||||
|
||||
</resources>
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
-->
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
|
||||
<string name="display_cutout_emulation_overlay">Display Cutout Emulation</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.server.display;
|
||||
|
||||
import android.app.ActivityThread;
|
||||
import android.content.res.Resources;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.lights.Light;
|
||||
@@ -392,7 +393,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
|
||||
| DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS;
|
||||
}
|
||||
|
||||
final Resources res = getContext().getResources();
|
||||
final Resources res = getOverlayContext().getResources();
|
||||
if (mBuiltInDisplayId == SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
|
||||
mInfo.name = res.getString(
|
||||
com.android.internal.R.string.display_manager_built_in_display_name);
|
||||
@@ -687,6 +688,11 @@ final class LocalDisplayAdapter extends DisplayAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
/** Supplies a context whose Resources apply runtime-overlays */
|
||||
Context getOverlayContext() {
|
||||
return ActivityThread.currentActivityThread().getSystemUiContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Keeps track of a display configuration.
|
||||
*/
|
||||
|
||||
@@ -623,8 +623,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
|
||||
PointerLocationView mPointerLocationView;
|
||||
|
||||
boolean mEmulateDisplayCutout = false;
|
||||
|
||||
// During layout, the layer at which the doc window is placed.
|
||||
int mDockLayer;
|
||||
// During layout, this is the layer of the status bar.
|
||||
@@ -983,9 +981,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
resolver.registerContentObserver(Settings.Global.getUriFor(
|
||||
Settings.Global.POLICY_CONTROL), false, this,
|
||||
UserHandle.USER_ALL);
|
||||
resolver.registerContentObserver(Settings.Global.getUriFor(
|
||||
Settings.Global.EMULATE_DISPLAY_CUTOUT), false, this,
|
||||
UserHandle.USER_ALL);
|
||||
updateSettings();
|
||||
}
|
||||
|
||||
@@ -2411,10 +2406,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
if (mImmersiveModeConfirmation != null) {
|
||||
mImmersiveModeConfirmation.loadSetting(mCurrentUserId);
|
||||
}
|
||||
mEmulateDisplayCutout = Settings.Global.getInt(resolver,
|
||||
Settings.Global.EMULATE_DISPLAY_CUTOUT,
|
||||
Settings.Global.EMULATE_DISPLAY_CUTOUT_OFF)
|
||||
!= Settings.Global.EMULATE_DISPLAY_CUTOUT_OFF;
|
||||
}
|
||||
synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
|
||||
PolicyControl.reloadFromSetting(mContext);
|
||||
@@ -4449,7 +4440,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {
|
||||
displayFrames.onBeginLayout(mEmulateDisplayCutout, mStatusBarHeight);
|
||||
displayFrames.onBeginLayout();
|
||||
// TODO(multi-display): This doesn't seem right...Maybe only apply to default display?
|
||||
mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
|
||||
mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();
|
||||
|
||||
@@ -101,7 +101,7 @@ public class DisplayFrames {
|
||||
/** During layout, the current screen borders along which input method windows are placed. */
|
||||
public final Rect mDock = new Rect();
|
||||
|
||||
/** The display cutout used for layout (after rotation and emulation) */
|
||||
/** The display cutout used for layout (after rotation) */
|
||||
@NonNull public DisplayCutout mDisplayCutout = DisplayCutout.NO_CUTOUT;
|
||||
|
||||
/** The cutout as supplied by display info */
|
||||
@@ -134,7 +134,7 @@ public class DisplayFrames {
|
||||
? info.displayCutout : DisplayCutout.NO_CUTOUT;
|
||||
}
|
||||
|
||||
public void onBeginLayout(boolean emulateDisplayCutout, int statusBarHeight) {
|
||||
public void onBeginLayout() {
|
||||
switch (mRotation) {
|
||||
case ROTATION_90:
|
||||
mRotatedDisplayInfoOverscan.left = mDisplayInfoOverscan.top;
|
||||
@@ -172,12 +172,8 @@ public class DisplayFrames {
|
||||
mStable.set(mUnrestricted);
|
||||
mStableFullscreen.set(mUnrestricted);
|
||||
mCurrent.set(mUnrestricted);
|
||||
mDisplayCutout = mDisplayInfoCutout;
|
||||
if (emulateDisplayCutout) {
|
||||
setEmulatedDisplayCutout((int) (statusBarHeight * 0.8));
|
||||
}
|
||||
mDisplayCutout = mDisplayCutout.calculateRelativeTo(mOverscan);
|
||||
|
||||
mDisplayCutout = mDisplayInfoCutout.calculateRelativeTo(mOverscan);
|
||||
mDisplayCutoutSafe.set(Integer.MIN_VALUE, Integer.MIN_VALUE,
|
||||
Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
if (!mDisplayCutout.isEmpty()) {
|
||||
@@ -201,51 +197,6 @@ public class DisplayFrames {
|
||||
return mDock.bottom - mCurrent.bottom;
|
||||
}
|
||||
|
||||
private void setEmulatedDisplayCutout(int height) {
|
||||
final boolean swappedDimensions = mRotation == ROTATION_90 || mRotation == ROTATION_270;
|
||||
|
||||
final int screenWidth = swappedDimensions ? mDisplayHeight : mDisplayWidth;
|
||||
final int screenHeight = swappedDimensions ? mDisplayWidth : mDisplayHeight;
|
||||
|
||||
final int widthTop = (int) (screenWidth * 0.3);
|
||||
final int widthBottom = widthTop - height;
|
||||
|
||||
switch (mRotation) {
|
||||
case ROTATION_90:
|
||||
mDisplayCutout = DisplayCutout.fromBoundingPolygon(Arrays.asList(
|
||||
new Point(0, (screenWidth - widthTop) / 2),
|
||||
new Point(height, (screenWidth - widthBottom) / 2),
|
||||
new Point(height, (screenWidth + widthBottom) / 2),
|
||||
new Point(0, (screenWidth + widthTop) / 2)
|
||||
));
|
||||
break;
|
||||
case ROTATION_180:
|
||||
mDisplayCutout = DisplayCutout.fromBoundingPolygon(Arrays.asList(
|
||||
new Point((screenWidth - widthTop) / 2, screenHeight),
|
||||
new Point((screenWidth - widthBottom) / 2, screenHeight - height),
|
||||
new Point((screenWidth + widthBottom) / 2, screenHeight - height),
|
||||
new Point((screenWidth + widthTop) / 2, screenHeight)
|
||||
));
|
||||
break;
|
||||
case ROTATION_270:
|
||||
mDisplayCutout = DisplayCutout.fromBoundingPolygon(Arrays.asList(
|
||||
new Point(screenHeight, (screenWidth - widthTop) / 2),
|
||||
new Point(screenHeight - height, (screenWidth - widthBottom) / 2),
|
||||
new Point(screenHeight - height, (screenWidth + widthBottom) / 2),
|
||||
new Point(screenHeight, (screenWidth + widthTop) / 2)
|
||||
));
|
||||
break;
|
||||
default:
|
||||
mDisplayCutout = DisplayCutout.fromBoundingPolygon(Arrays.asList(
|
||||
new Point((screenWidth - widthTop) / 2, 0),
|
||||
new Point((screenWidth - widthBottom) / 2, height),
|
||||
new Point((screenWidth + widthBottom) / 2, height),
|
||||
new Point((screenWidth + widthTop) / 2, 0)
|
||||
));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void writeToProto(ProtoOutputStream proto, long fieldId) {
|
||||
final long token = proto.start(fieldId);
|
||||
mStable.writeToProto(proto, STABLE_BOUNDS);
|
||||
|
||||
@@ -24,6 +24,8 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
|
||||
|
||||
import static com.android.server.wm.utils.CoordinateTransforms.transformPhysicalToLogicalCoordinates;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
@@ -31,6 +33,8 @@ import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.os.IBinder;
|
||||
@@ -38,6 +42,7 @@ import android.os.UserHandle;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.testing.TestableResources;
|
||||
import android.view.Display;
|
||||
import android.view.DisplayCutout;
|
||||
import android.view.DisplayInfo;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
@@ -65,6 +70,9 @@ public class PhoneWindowManagerTestBase {
|
||||
|
||||
FakeWindowState mStatusBar;
|
||||
FakeWindowState mNavigationBar;
|
||||
private boolean mHasDisplayCutout;
|
||||
private int mRotation = ROTATION_0;
|
||||
private final Matrix mTmpMatrix = new Matrix();
|
||||
|
||||
@Before
|
||||
public void setUpBase() throws Exception {
|
||||
@@ -80,16 +88,32 @@ public class PhoneWindowManagerTestBase {
|
||||
|
||||
mPolicy = TestablePhoneWindowManager.create(mContext);
|
||||
|
||||
setRotation(ROTATION_0);
|
||||
updateDisplayFrames();
|
||||
}
|
||||
|
||||
public void setRotation(int rotation) {
|
||||
mRotation = rotation;
|
||||
updateDisplayFrames();
|
||||
}
|
||||
|
||||
private void updateDisplayFrames() {
|
||||
DisplayInfo info = new DisplayInfo();
|
||||
|
||||
final boolean flippedDimensions = rotation == ROTATION_90 || rotation == ROTATION_270;
|
||||
final boolean flippedDimensions = mRotation == ROTATION_90 || mRotation == ROTATION_270;
|
||||
info.logicalWidth = flippedDimensions ? DISPLAY_HEIGHT : DISPLAY_WIDTH;
|
||||
info.logicalHeight = flippedDimensions ? DISPLAY_WIDTH : DISPLAY_HEIGHT;
|
||||
info.rotation = rotation;
|
||||
info.rotation = mRotation;
|
||||
if (mHasDisplayCutout) {
|
||||
Path p = new Path();
|
||||
p.addRect(DISPLAY_WIDTH / 4, 0, DISPLAY_WIDTH * 3 / 4, DISPLAY_CUTOUT_HEIGHT,
|
||||
Path.Direction.CCW);
|
||||
transformPhysicalToLogicalCoordinates(
|
||||
mRotation, DISPLAY_WIDTH, DISPLAY_HEIGHT, mTmpMatrix);
|
||||
p.transform(mTmpMatrix);
|
||||
info.displayCutout = DisplayCutout.fromBounds(p);
|
||||
} else {
|
||||
info.displayCutout = null;
|
||||
}
|
||||
|
||||
mFrames = new DisplayFrames(Display.DEFAULT_DISPLAY, info);
|
||||
}
|
||||
@@ -116,7 +140,8 @@ public class PhoneWindowManagerTestBase {
|
||||
}
|
||||
|
||||
public void addDisplayCutout() {
|
||||
mPolicy.mEmulateDisplayCutout = true;
|
||||
mHasDisplayCutout = true;
|
||||
updateDisplayFrames();
|
||||
}
|
||||
|
||||
/** Asserts that {@code actual} is inset by the given amounts from the full display rect. */
|
||||
|
||||
Reference in New Issue
Block a user