Merge "Set insets on the virtual display to avoid IME covering the bubble."
This commit is contained in:
@@ -14191,13 +14191,16 @@ package android.graphics {
|
||||
field public static final int YV12 = 842094169; // 0x32315659
|
||||
}
|
||||
|
||||
public final class Insets {
|
||||
public final class Insets implements android.os.Parcelable {
|
||||
method @NonNull public static android.graphics.Insets add(@NonNull android.graphics.Insets, @NonNull android.graphics.Insets);
|
||||
method public int describeContents();
|
||||
method @NonNull public static android.graphics.Insets max(@NonNull android.graphics.Insets, @NonNull android.graphics.Insets);
|
||||
method @NonNull public static android.graphics.Insets min(@NonNull android.graphics.Insets, @NonNull android.graphics.Insets);
|
||||
method @NonNull public static android.graphics.Insets of(int, int, int, int);
|
||||
method @NonNull public static android.graphics.Insets of(@Nullable android.graphics.Rect);
|
||||
method @NonNull public static android.graphics.Insets subtract(@NonNull android.graphics.Insets, @NonNull android.graphics.Insets);
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator<android.graphics.Insets> CREATOR;
|
||||
field public static final android.graphics.Insets NONE;
|
||||
field public final int bottom;
|
||||
field public final int left;
|
||||
|
||||
@@ -26,6 +26,7 @@ import android.app.ActivityManager.StackInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Insets;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.hardware.display.VirtualDisplay;
|
||||
import android.os.RemoteException;
|
||||
@@ -84,6 +85,8 @@ public class ActivityView extends ViewGroup {
|
||||
/** The ActivityView is only allowed to contain one task. */
|
||||
private final boolean mSingleTaskInstance;
|
||||
|
||||
private Insets mForwardedInsets;
|
||||
|
||||
@UnsupportedAppUsage
|
||||
public ActivityView(Context context) {
|
||||
this(context, null /* attrs */);
|
||||
@@ -369,11 +372,13 @@ public class ActivityView extends ViewGroup {
|
||||
.build();
|
||||
|
||||
try {
|
||||
// TODO: Find a way to consolidate these calls to the server.
|
||||
wm.reparentDisplayContent(displayId, mRootSurfaceControl);
|
||||
wm.dontOverrideDisplayInfo(displayId);
|
||||
if (mSingleTaskInstance) {
|
||||
mActivityTaskManager.setDisplayToSingleTaskInstance(displayId);
|
||||
}
|
||||
wm.setForwardedInsets(displayId, mForwardedInsets);
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowAsRuntimeException();
|
||||
}
|
||||
@@ -453,6 +458,24 @@ public class ActivityView extends ViewGroup {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set forwarded insets on the virtual display.
|
||||
*
|
||||
* @see IWindowManager#setForwardedInsets
|
||||
*/
|
||||
public void setForwardedInsets(Insets insets) {
|
||||
mForwardedInsets = insets;
|
||||
if (mVirtualDisplay == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
|
||||
wm.setForwardedInsets(mVirtualDisplay.getDisplay().getDisplayId(), mForwardedInsets);
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowAsRuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A task change listener that detects background color change of the topmost stack on our
|
||||
* virtual display and updates the background of the surface view. This background will be shown
|
||||
|
||||
@@ -25,6 +25,7 @@ import android.content.res.CompatibilityInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.GraphicBuffer;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Region;
|
||||
@@ -379,6 +380,16 @@ interface IWindowManager
|
||||
*/
|
||||
void getStableInsets(int displayId, out Rect outInsets);
|
||||
|
||||
/**
|
||||
* Set the forwarded insets on the display.
|
||||
* <p>
|
||||
* This is only used in case a virtual display is displayed on another display that has insets,
|
||||
* and the bounds of the virtual display is overlapping with the insets from the host display.
|
||||
* In that case, the contents on the virtual display won't be placed over the forwarded insets.
|
||||
* Only the owner of the display is permitted to set the forwarded insets on it.
|
||||
*/
|
||||
void setForwardedInsets(int displayId, in Insets insets);
|
||||
|
||||
/**
|
||||
* Register shortcut key. Shortcut code is packed as:
|
||||
* (MetaState << Integer.SIZE) | KeyCode
|
||||
|
||||
20
graphics/java/android/graphics/Insets.aidl
Normal file
20
graphics/java/android/graphics/Insets.aidl
Normal file
@@ -0,0 +1,20 @@
|
||||
/* //device/java/android/android/graphics/Insets.aidl
|
||||
**
|
||||
** Copyright 2019, The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
|
||||
package android.graphics;
|
||||
|
||||
parcelable Insets;
|
||||
@@ -18,6 +18,8 @@ package android.graphics;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* An Insets instance holds four integer offsets which describe changes to the four
|
||||
@@ -27,7 +29,7 @@ import android.annotation.Nullable;
|
||||
* Insets are immutable so may be treated as values.
|
||||
*
|
||||
*/
|
||||
public final class Insets {
|
||||
public final class Insets implements Parcelable {
|
||||
public static final Insets NONE = new Insets(0, 0, 0, 0);
|
||||
|
||||
public final int left;
|
||||
@@ -73,7 +75,7 @@ public final class Insets {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Rect intance with the appropriate values.
|
||||
* Returns a Rect instance with the appropriate values.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@@ -168,4 +170,29 @@ public final class Insets {
|
||||
", bottom=" + bottom +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeInt(left);
|
||||
out.writeInt(top);
|
||||
out.writeInt(right);
|
||||
out.writeInt(bottom);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<Insets> CREATOR = new Parcelable.Creator<Insets>() {
|
||||
@Override
|
||||
public Insets createFromParcel(Parcel in) {
|
||||
return new Insets(in.readInt(), in.readInt(), in.readInt(), in.readInt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets[] newArray(int size) {
|
||||
return new Insets[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
@@ -32,6 +34,7 @@ import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowInsets;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
@@ -266,6 +269,24 @@ public class BubbleView extends FrameLayout implements BubbleTouchHandler.Floati
|
||||
}
|
||||
}
|
||||
});
|
||||
mActivityView.setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
|
||||
ActivityView activityView = (ActivityView) view;
|
||||
// Here we assume that the position of the ActivityView on the screen
|
||||
// remains regardless of IME status. When we move ActivityView, the
|
||||
// forwardedInsets should be computed not against the current location
|
||||
// and size, but against the post-moved location and size.
|
||||
Point displaySize = new Point();
|
||||
view.getContext().getDisplay().getSize(displaySize);
|
||||
int[] windowLocation = view.getLocationOnScreen();
|
||||
final int windowBottom = windowLocation[1] + view.getHeight();
|
||||
final int keyboardHeight = insets.getSystemWindowInsetBottom()
|
||||
- insets.getStableInsetBottom();
|
||||
final int insetsBottom = Math.max(0,
|
||||
windowBottom + keyboardHeight - displaySize.y);
|
||||
activityView.setForwardedInsets(Insets.of(0, 0, 0, insetsBottom));
|
||||
return view.onApplyWindowInsets(insets);
|
||||
});
|
||||
|
||||
}
|
||||
return mActivityView;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
||||
@@ -139,6 +138,7 @@ import android.content.pm.PackageManager;
|
||||
import android.content.res.CompatibilityInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
@@ -4946,4 +4946,19 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
portalWindowHandle.portalToDisplayId = mDisplayId;
|
||||
return portalWindowHandle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see IWindowManager#setForwardedInsets
|
||||
*/
|
||||
public void setForwardedInsets(Insets insets) {
|
||||
if (insets == null) {
|
||||
insets = Insets.NONE;
|
||||
}
|
||||
if (mDisplayPolicy.getForwardedInsets().equals(insets)) {
|
||||
return;
|
||||
}
|
||||
mDisplayPolicy.setForwardedInsets(insets);
|
||||
setLayoutNeeded();
|
||||
mWmService.mWindowPlacerLocked.requestTraversal();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +104,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
|
||||
import static com.android.server.wm.WindowManagerService.localLOGV;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityThread;
|
||||
@@ -111,6 +112,7 @@ import android.app.StatusBarManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.input.InputManager;
|
||||
import android.hardware.power.V1_0.PowerHint;
|
||||
@@ -341,6 +343,16 @@ public class DisplayPolicy {
|
||||
|
||||
private InputConsumer mInputConsumer = null;
|
||||
|
||||
/**
|
||||
* The area covered by system windows which belong to another display. Forwarded insets is set
|
||||
* in case this is a virtual display, this is displayed on another display that has insets, and
|
||||
* the bounds of this display is overlapping with the insets of the host display (e.g. IME is
|
||||
* displayed on the host display, and it covers a part of this virtual display.)
|
||||
* The forwarded insets is used to compute display frames of this virtual display, which will
|
||||
* be then used to layout windows in the virtual display.
|
||||
*/
|
||||
@NonNull private Insets mForwardedInsets = Insets.NONE;
|
||||
|
||||
// -------- PolicyHandler --------
|
||||
private static final int MSG_UPDATE_DREAMING_SLEEP_TOKEN = 1;
|
||||
private static final int MSG_REQUEST_TRANSIENT_BARS = 2;
|
||||
@@ -1364,6 +1376,15 @@ public class DisplayPolicy {
|
||||
displayFrames.mDisplayCutoutSafe.top = Math.max(displayFrames.mDisplayCutoutSafe.top,
|
||||
displayFrames.mStable.top);
|
||||
}
|
||||
|
||||
// In case this is a virtual display, and the host display has insets that overlap this
|
||||
// virtual display, apply the insets of the overlapped area onto the current and content
|
||||
// frame of this virtual display. This let us layout windows in the virtual display as
|
||||
// expected when the window needs to avoid overlap with the system windows.
|
||||
// TODO: Generalize the forwarded insets, so that we can handle system windows other than
|
||||
// IME.
|
||||
displayFrames.mCurrent.inset(mForwardedInsets);
|
||||
displayFrames.mContent.inset(mForwardedInsets);
|
||||
}
|
||||
|
||||
private void layoutScreenDecorWindows(DisplayFrames displayFrames) {
|
||||
@@ -2727,6 +2748,18 @@ public class DisplayPolicy {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see IWindowManager#setForwardedInsets
|
||||
*/
|
||||
public void setForwardedInsets(@NonNull Insets forwardedInsets) {
|
||||
mForwardedInsets = forwardedInsets;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Insets getForwardedInsets() {
|
||||
return mForwardedInsets;
|
||||
}
|
||||
|
||||
@NavigationBarPosition
|
||||
int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) {
|
||||
if (navigationBarCanMove() && displayWidth > displayHeight) {
|
||||
|
||||
@@ -134,6 +134,7 @@ import android.content.pm.PackageManagerInternal;
|
||||
import android.content.res.Configuration;
|
||||
import android.database.ContentObserver;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
@@ -6438,6 +6439,23 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setForwardedInsets(int displayId, Insets insets) throws RemoteException {
|
||||
synchronized (mGlobalLock) {
|
||||
final DisplayContent dc = mRoot.getDisplayContent(displayId);
|
||||
if (dc == null) {
|
||||
return;
|
||||
}
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
final int displayOwnerUid = dc.getDisplay().getOwnerUid();
|
||||
if (callingUid != displayOwnerUid) {
|
||||
throw new SecurityException(
|
||||
"Only owner of the display can set ForwardedInsets to it.");
|
||||
}
|
||||
dc.setForwardedInsets(insets);
|
||||
}
|
||||
}
|
||||
|
||||
void intersectDisplayInsetBounds(Rect display, Rect insets, Rect inOutBounds) {
|
||||
mTmpRect3.set(display);
|
||||
mTmpRect3.inset(insets);
|
||||
|
||||
@@ -28,6 +28,8 @@ import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
|
||||
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
|
||||
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
|
||||
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
|
||||
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
|
||||
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
||||
|
||||
@@ -37,6 +39,7 @@ import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
@@ -349,6 +352,48 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void layoutWindowLw_withForwardInset_SoftInputAdjustResize() {
|
||||
synchronized (mWm.mGlobalLock) {
|
||||
mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_RESIZE;
|
||||
addWindow(mWindow);
|
||||
|
||||
final int forwardedInsetBottom = 50;
|
||||
mDisplayPolicy.setForwardedInsets(Insets.of(0, 0, 0, forwardedInsetBottom));
|
||||
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
|
||||
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
|
||||
|
||||
assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
|
||||
assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
|
||||
assertInsetByTopBottom(mWindow.getContentFrameLw(),
|
||||
STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT + forwardedInsetBottom);
|
||||
assertInsetByTopBottom(mWindow.getVisibleFrameLw(),
|
||||
STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT + forwardedInsetBottom);
|
||||
assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
|
||||
assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void layoutWindowLw_withForwardInset_SoftInputAdjustNothing() {
|
||||
synchronized (mWm.mGlobalLock) {
|
||||
mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_NOTHING;
|
||||
addWindow(mWindow);
|
||||
|
||||
final int forwardedInsetBottom = 50;
|
||||
mDisplayPolicy.setForwardedInsets(Insets.of(0, 0, 0, forwardedInsetBottom));
|
||||
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
|
||||
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
|
||||
|
||||
assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
|
||||
assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
|
||||
assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
|
||||
assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
|
||||
assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
|
||||
assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void layoutHint_appWindow() {
|
||||
synchronized (mWm.mGlobalLock) {
|
||||
|
||||
Reference in New Issue
Block a user