Merge "Fix issue #17789629: PopupWindow overlaps with navigation bar." into lmp-mr1-dev

This commit is contained in:
Wale Ogunwale
2014-10-22 22:17:18 +00:00
committed by Android (Google) Code Review
8 changed files with 148 additions and 51 deletions

View File

@@ -34909,6 +34909,7 @@ package android.view {
field public static final int FLAG_HARDWARE_ACCELERATED = 16777216; // 0x1000000
field public static final int FLAG_IGNORE_CHEEK_PRESSES = 32768; // 0x8000
field public static final int FLAG_KEEP_SCREEN_ON = 128; // 0x80
field public static final int FLAG_LAYOUT_ATTACHED_IN_DECOR = 1073741824; // 0x40000000
field public static final int FLAG_LAYOUT_INSET_DECOR = 65536; // 0x10000
field public static final int FLAG_LAYOUT_IN_OVERSCAN = 33554432; // 0x2000000
field public static final int FLAG_LAYOUT_IN_SCREEN = 256; // 0x100
@@ -38172,6 +38173,7 @@ package android.widget {
method public int getSoftInputMode();
method public int getWidth();
method public boolean isAboveAnchor();
method public boolean isAttachedInDecor();
method public boolean isClippingEnabled();
method public boolean isFocusable();
method public boolean isOutsideTouchable();
@@ -38179,6 +38181,7 @@ package android.widget {
method public boolean isSplitTouchEnabled();
method public boolean isTouchable();
method public void setAnimationStyle(int);
method public void setAttachedInDecor(boolean);
method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
method public void setClippingEnabled(boolean);
method public void setContentView(android.view.View);

View File

@@ -24,7 +24,6 @@ import android.content.res.TypedArray;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
@@ -801,9 +800,6 @@ public abstract class Window {
public void setFlags(int flags, int mask) {
final WindowManager.LayoutParams attrs = getAttributes();
attrs.flags = (attrs.flags&~mask) | (flags&mask);
if ((mask&WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY) != 0) {
attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SET_NEEDS_MENU_KEY;
}
mForcedWindowFlags |= mask;
dispatchWindowAttributesChanged(attrs);
}
@@ -814,6 +810,15 @@ public abstract class Window {
dispatchWindowAttributesChanged(attrs);
}
/**
* {@hide}
*/
protected void setNeedsMenuKey(int value) {
final WindowManager.LayoutParams attrs = getAttributes();
attrs.needsMenuKey = value;
dispatchWindowAttributesChanged(attrs);
}
/**
* {@hide}
*/

View File

@@ -878,9 +878,6 @@ public interface WindowManager extends ViewManager {
*/
public static final int FLAG_TRANSLUCENT_NAVIGATION = 0x08000000;
// ----- HIDDEN FLAGS.
// These start at the high bit and go down.
/**
* Flag for a window in local focus mode.
* Window in local focus mode can control focus independent of window manager using
@@ -903,17 +900,12 @@ public interface WindowManager extends ViewManager {
public static final int FLAG_SLIPPERY = 0x20000000;
/**
* Flag for a window belonging to an activity that responds to {@link KeyEvent#KEYCODE_MENU}
* and therefore needs a Menu key. For devices where Menu is a physical button this flag is
* ignored, but on devices where the Menu key is drawn in software it may be hidden unless
* this flag is set.
*
* (Note that Action Bars, when available, are the preferred way to offer additional
* functions otherwise accessed via an options menu.)
*
* {@hide}
* Window flag: When requesting layout with an attached window, the attached window may
* overlap with the screen decorations of the parent window such as the navigation bar. By
* including this flag, the window manager will layout the attached window within the decor
* frame of the parent window such that it doesn't overlap with screen decorations.
*/
public static final int FLAG_NEEDS_MENU_KEY = 0x40000000;
public static final int FLAG_LAYOUT_ATTACHED_IN_DECOR = 0x40000000;
/**
* Flag indicating that this Window is responsible for drawing the background for the
@@ -1056,16 +1048,6 @@ public interface WindowManager extends ViewManager {
*/
public static final int PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS = 0x00000004;
/**
* This is set for a window that has explicitly specified its
* FLAG_NEEDS_MENU_KEY, so we know the value on this window is the
* appropriate one to use. If this is not set, we should look at
* windows behind it to determine the appropriate value.
*
* @hide
*/
public static final int PRIVATE_FLAG_SET_NEEDS_MENU_KEY = 0x00000008;
/** In a multiuser system if this flag is set and the owner is a system process then this
* window will appear on all user screens. This overrides the default behavior of window
* types that normally only appear on the owning user's screen. Refer to each window type
@@ -1112,6 +1094,45 @@ public interface WindowManager extends ViewManager {
*/
public int privateFlags;
/**
* Value for {@link #needsMenuKey} for a window that has not explicitly specified if it
* needs {@link #NEEDS_MENU_SET_TRUE} or doesn't need {@link #NEEDS_MENU_SET_FALSE} a menu
* key. For this case, we should look at windows behind it to determine the appropriate
* value.
*
* @hide
*/
public static final int NEEDS_MENU_UNSET = 0;
/**
* Value for {@link #needsMenuKey} for a window that has explicitly specified it needs a
* menu key.
*
* @hide
*/
public static final int NEEDS_MENU_SET_TRUE = 1;
/**
* Value for {@link #needsMenuKey} for a window that has explicitly specified it doesn't
* needs a menu key.
*
* @hide
*/
public static final int NEEDS_MENU_SET_FALSE = 2;
/**
* State variable for a window belonging to an activity that responds to
* {@link KeyEvent#KEYCODE_MENU} and therefore needs a Menu key. For devices where Menu is a
* physical button this variable is ignored, but on devices where the Menu key is drawn in
* software it may be hidden unless this variable is set to {@link #NEEDS_MENU_SET_TRUE}.
*
* (Note that Action Bars, when available, are the preferred way to offer additional
* functions otherwise accessed via an options menu.)
*
* {@hide}
*/
public int needsMenuKey = NEEDS_MENU_UNSET;
/**
* Given a particular set of window manager flags, determine whether
* such a window may be a target for an input method when it has
@@ -1120,9 +1141,9 @@ public interface WindowManager extends ViewManager {
* flags and returns true if the combination of the two corresponds
* to a window that needs to be behind the input method so that the
* user can type into it.
*
*
* @param flags The current window manager flags.
*
*
* @return Returns true if such a window should be behind/interact
* with an input method, false if not.
*/
@@ -1587,14 +1608,15 @@ public interface WindowManager extends ViewManager {
out.writeInt(surfaceInsets.top);
out.writeInt(surfaceInsets.right);
out.writeInt(surfaceInsets.bottom);
out.writeInt(needsMenuKey);
}
public static final Parcelable.Creator<LayoutParams> CREATOR
= new Parcelable.Creator<LayoutParams>() {
public LayoutParams createFromParcel(Parcel in) {
return new LayoutParams(in);
}
public LayoutParams[] newArray(int size) {
return new LayoutParams[size];
}
@@ -1634,8 +1656,9 @@ public interface WindowManager extends ViewManager {
surfaceInsets.top = in.readInt();
surfaceInsets.right = in.readInt();
surfaceInsets.bottom = in.readInt();
needsMenuKey = in.readInt();
}
@SuppressWarnings({"PointlessBitwiseExpression"})
public static final int LAYOUT_CHANGED = 1<<0;
public static final int TYPE_CHANGED = 1<<1;
@@ -1669,14 +1692,16 @@ public interface WindowManager extends ViewManager {
/** {@hide} */
public static final int PREFERRED_REFRESH_RATE_CHANGED = 1 << 21;
/** {@hide} */
public static final int NEEDS_MENU_KEY_CHANGED = 1 << 22;
/** {@hide} */
public static final int EVERYTHING_CHANGED = 0xffffffff;
// internal buffer to backup/restore parameters under compatibility mode.
private int[] mCompatibilityParamsBackup = null;
public final int copyFrom(LayoutParams o) {
int changes = 0;
if (width != o.width) {
width = o.width;
changes |= LAYOUT_CHANGED;
@@ -1813,9 +1838,14 @@ public interface WindowManager extends ViewManager {
changes |= SURFACE_INSETS_CHANGED;
}
if (needsMenuKey != o.needsMenuKey) {
needsMenuKey = o.needsMenuKey;
changes |= NEEDS_MENU_KEY_CHANGED;
}
return changes;
}
@Override
public String debug(String output) {
output += "Contents of " + this + ":";
@@ -1919,6 +1949,10 @@ public interface WindowManager extends ViewManager {
if (!surfaceInsets.equals(Insets.NONE)) {
sb.append(" surfaceInsets=").append(surfaceInsets);
}
if (needsMenuKey != NEEDS_MENU_UNSET) {
sb.append(" needsMenuKey=");
sb.append(needsMenuKey);
}
sb.append('}');
return sb.toString();
}

View File

@@ -97,9 +97,11 @@ public class PopupWindow {
private boolean mAllowScrollingAnchorParent = true;
private boolean mLayoutInsetDecor = false;
private boolean mNotTouchModal;
private boolean mAttachedInDecor = true;
private boolean mAttachedInDecorSet = false;
private OnTouchListener mTouchInterceptor;
private int mWidthMode;
private int mWidth;
private int mLastWidth;
@@ -316,6 +318,7 @@ public class PopupWindow {
mContext = contentView.getContext();
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
}
setContentView(contentView);
setWidth(width);
setHeight(height);
@@ -373,16 +376,16 @@ public class PopupWindow {
public int getAnimationStyle() {
return mAnimationStyle;
}
/**
* Set the flag on popup to ignore cheek press eventt; by default this flag
* Set the flag on popup to ignore cheek press event; by default this flag
* is set to false
* which means the pop wont ignore cheek press dispatch events.
*
*
* <p>If the popup is showing, calling this method will take effect only
* the next time the popup is shown or through a manual call to one of
* the {@link #update()} methods.</p>
*
*
* @see #update()
*/
public void setIgnoreCheekPress() {
@@ -443,6 +446,19 @@ public class PopupWindow {
if (mWindowManager == null && mContentView != null) {
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
}
// Setting the default for attachedInDecor based on SDK version here
// instead of in the constructor since we might not have the context
// object in the constructor. We only want to set default here if the
// app hasn't already set the attachedInDecor.
if (mContext != null && !mAttachedInDecorSet) {
// Attach popup window in decor frame of parent window by default for
// {@link Build.VERSION_CODES.LOLLIPOP_MR1} or greater. Keep current
// behavior of not attaching to decor frame for older SDKs.
setAttachedInDecor(mContext.getApplicationInfo().targetSdkVersion
>= Build.VERSION_CODES.LOLLIPOP_MR1);
}
}
/**
@@ -452,7 +468,7 @@ public class PopupWindow {
public void setTouchInterceptor(OnTouchListener l) {
mTouchInterceptor = l;
}
/**
* <p>Indicate whether the popup window can grab the focus.</p>
*
@@ -701,6 +717,36 @@ public class PopupWindow {
mLayoutInScreen = enabled;
}
/**
* <p>Indicates whether the popup window will be attached in the decor frame of its parent
* window.
*
* @return true if the window will be attached to the decor frame of its parent window.
*
* @see #setAttachedInDecor(boolean)
* @see WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR
*/
public boolean isAttachedInDecor() {
return mAttachedInDecor;
}
/**
* <p>This will attach the popup window to the decor frame of the parent window to avoid
* overlaping with screen decorations like the navigation bar. Overrides the default behavior of
* the flag {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR}.
*
* <p>By default the flag is set on SDK version {@link Build.VERSION_CODES#LOLLIPOP_MR1} or
* greater and cleared on lesser SDK versions.
*
* @param enabled true if the popup should be attached to the decor frame of its parent window.
*
* @see WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR
*/
public void setAttachedInDecor(boolean enabled) {
mAttachedInDecor = enabled;
mAttachedInDecorSet = true;
}
/**
* Allows the popup window to force the flag
* {@link WindowManager.LayoutParams#FLAG_LAYOUT_INSET_DECOR}, overriding default behavior.
@@ -1140,9 +1186,12 @@ public class PopupWindow {
if (mNotTouchModal) {
curFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
}
if (mAttachedInDecor) {
curFlags |= WindowManager.LayoutParams.FLAG_LAYOUT_ATTACHED_IN_DECOR;
}
return curFlags;
}
private int computeAnimationResource() {
if (mAnimationStyle == -1) {
if (mIsDropdown) {

View File

@@ -3342,9 +3342,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
final boolean noActionBar = !hasFeature(FEATURE_ACTION_BAR) || hasFeature(FEATURE_NO_TITLE);
if (targetPreHoneycomb || (targetPreIcs && targetHcNeedsOptions && noActionBar)) {
addFlags(WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY);
setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE);
} else {
clearFlags(WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY);
setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_FALSE);
}
// Non-floating windows on high end devices must put up decor beneath the system bars and

View File

@@ -3181,10 +3181,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// whether it is taking care of insetting its content. If not,
// we need to use the parent's content frame so that the entire
// window is positioned within that content. Otherwise we can use
// the display frame and let the attached window take care of
// the overscan frame and let the attached window take care of
// positioning its content appropriately.
if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
cf.set(attached.getOverscanFrameLw());
// Set the content frame of the attached window to the parent's decor frame
// (same as content frame when IME isn't present) if specifically requested by
// setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag.
// Otherwise, use the overscan frame.
cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0
? attached.getContentFrameLw() : attached.getOverscanFrameLw());
} else {
// If the window is resizing, then we want to base the content
// frame on our attached content frame to resize... however,

View File

@@ -26,6 +26,7 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.util.Slog;
import android.view.WindowManager;
import com.android.internal.statusbar.IStatusBar;
import com.android.internal.statusbar.IStatusBarService;
@@ -295,9 +296,10 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
}
}
/**
/**
* Hide or show the on-screen Menu key. Only call this from the window manager, typically in
* response to a window with FLAG_NEEDS_MENU_KEY set.
* response to a window with {@link android.view.WindowManager.LayoutParams#needsMenuKey} set
* to {@link android.view.WindowManager.LayoutParams#NEEDS_MENU_SET_TRUE}.
*/
@Override
public void topAppWindowChanged(final boolean menuVisible) {

View File

@@ -704,9 +704,8 @@ final class WindowState implements WindowManagerPolicy.WindowState {
WindowState ws = this;
WindowList windows = getWindowList();
while (true) {
if ((ws.mAttrs.privateFlags
& WindowManager.LayoutParams.PRIVATE_FLAG_SET_NEEDS_MENU_KEY) != 0) {
return (ws.mAttrs.flags & WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY) != 0;
if (ws.mAttrs.needsMenuKey != WindowManager.LayoutParams.NEEDS_MENU_UNSET) {
return ws.mAttrs.needsMenuKey == WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE;
}
// If we reached the bottom of the range of windows we are considering,
// assume no menu is needed.