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_HARDWARE_ACCELERATED = 16777216; // 0x1000000
field public static final int FLAG_IGNORE_CHEEK_PRESSES = 32768; // 0x8000 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_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_INSET_DECOR = 65536; // 0x10000
field public static final int FLAG_LAYOUT_IN_OVERSCAN = 33554432; // 0x2000000 field public static final int FLAG_LAYOUT_IN_OVERSCAN = 33554432; // 0x2000000
field public static final int FLAG_LAYOUT_IN_SCREEN = 256; // 0x100 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 getSoftInputMode();
method public int getWidth(); method public int getWidth();
method public boolean isAboveAnchor(); method public boolean isAboveAnchor();
method public boolean isAttachedInDecor();
method public boolean isClippingEnabled(); method public boolean isClippingEnabled();
method public boolean isFocusable(); method public boolean isFocusable();
method public boolean isOutsideTouchable(); method public boolean isOutsideTouchable();
@@ -38179,6 +38181,7 @@ package android.widget {
method public boolean isSplitTouchEnabled(); method public boolean isSplitTouchEnabled();
method public boolean isTouchable(); method public boolean isTouchable();
method public void setAnimationStyle(int); method public void setAnimationStyle(int);
method public void setAttachedInDecor(boolean);
method public void setBackgroundDrawable(android.graphics.drawable.Drawable); method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
method public void setClippingEnabled(boolean); method public void setClippingEnabled(boolean);
method public void setContentView(android.view.View); 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.PixelFormat;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.media.session.MediaController; import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
@@ -801,9 +800,6 @@ public abstract class Window {
public void setFlags(int flags, int mask) { public void setFlags(int flags, int mask) {
final WindowManager.LayoutParams attrs = getAttributes(); final WindowManager.LayoutParams attrs = getAttributes();
attrs.flags = (attrs.flags&~mask) | (flags&mask); 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; mForcedWindowFlags |= mask;
dispatchWindowAttributesChanged(attrs); dispatchWindowAttributesChanged(attrs);
} }
@@ -814,6 +810,15 @@ public abstract class Window {
dispatchWindowAttributesChanged(attrs); dispatchWindowAttributesChanged(attrs);
} }
/**
* {@hide}
*/
protected void setNeedsMenuKey(int value) {
final WindowManager.LayoutParams attrs = getAttributes();
attrs.needsMenuKey = value;
dispatchWindowAttributesChanged(attrs);
}
/** /**
* {@hide} * {@hide}
*/ */

View File

@@ -878,9 +878,6 @@ public interface WindowManager extends ViewManager {
*/ */
public static final int FLAG_TRANSLUCENT_NAVIGATION = 0x08000000; 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. * Flag for a window in local focus mode.
* Window in local focus mode can control focus independent of window manager using * 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; public static final int FLAG_SLIPPERY = 0x20000000;
/** /**
* Flag for a window belonging to an activity that responds to {@link KeyEvent#KEYCODE_MENU} * Window flag: When requesting layout with an attached window, the attached window may
* and therefore needs a Menu key. For devices where Menu is a physical button this flag is * overlap with the screen decorations of the parent window such as the navigation bar. By
* ignored, but on devices where the Menu key is drawn in software it may be hidden unless * including this flag, the window manager will layout the attached window within the decor
* this flag is set. * frame of the parent window such that it doesn't overlap with screen decorations.
*
* (Note that Action Bars, when available, are the preferred way to offer additional
* functions otherwise accessed via an options menu.)
*
* {@hide}
*/ */
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 * 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; 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 /** 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 * 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 * 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; 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 * Given a particular set of window manager flags, determine whether
* such a window may be a target for an input method when it has * such a window may be a target for an input method when it has
@@ -1587,6 +1608,7 @@ public interface WindowManager extends ViewManager {
out.writeInt(surfaceInsets.top); out.writeInt(surfaceInsets.top);
out.writeInt(surfaceInsets.right); out.writeInt(surfaceInsets.right);
out.writeInt(surfaceInsets.bottom); out.writeInt(surfaceInsets.bottom);
out.writeInt(needsMenuKey);
} }
public static final Parcelable.Creator<LayoutParams> CREATOR public static final Parcelable.Creator<LayoutParams> CREATOR
@@ -1634,6 +1656,7 @@ public interface WindowManager extends ViewManager {
surfaceInsets.top = in.readInt(); surfaceInsets.top = in.readInt();
surfaceInsets.right = in.readInt(); surfaceInsets.right = in.readInt();
surfaceInsets.bottom = in.readInt(); surfaceInsets.bottom = in.readInt();
needsMenuKey = in.readInt();
} }
@SuppressWarnings({"PointlessBitwiseExpression"}) @SuppressWarnings({"PointlessBitwiseExpression"})
@@ -1669,6 +1692,8 @@ public interface WindowManager extends ViewManager {
/** {@hide} */ /** {@hide} */
public static final int PREFERRED_REFRESH_RATE_CHANGED = 1 << 21; public static final int PREFERRED_REFRESH_RATE_CHANGED = 1 << 21;
/** {@hide} */ /** {@hide} */
public static final int NEEDS_MENU_KEY_CHANGED = 1 << 22;
/** {@hide} */
public static final int EVERYTHING_CHANGED = 0xffffffff; public static final int EVERYTHING_CHANGED = 0xffffffff;
// internal buffer to backup/restore parameters under compatibility mode. // internal buffer to backup/restore parameters under compatibility mode.
@@ -1813,6 +1838,11 @@ public interface WindowManager extends ViewManager {
changes |= SURFACE_INSETS_CHANGED; changes |= SURFACE_INSETS_CHANGED;
} }
if (needsMenuKey != o.needsMenuKey) {
needsMenuKey = o.needsMenuKey;
changes |= NEEDS_MENU_KEY_CHANGED;
}
return changes; return changes;
} }
@@ -1919,6 +1949,10 @@ public interface WindowManager extends ViewManager {
if (!surfaceInsets.equals(Insets.NONE)) { if (!surfaceInsets.equals(Insets.NONE)) {
sb.append(" surfaceInsets=").append(surfaceInsets); sb.append(" surfaceInsets=").append(surfaceInsets);
} }
if (needsMenuKey != NEEDS_MENU_UNSET) {
sb.append(" needsMenuKey=");
sb.append(needsMenuKey);
}
sb.append('}'); sb.append('}');
return sb.toString(); return sb.toString();
} }

View File

@@ -97,6 +97,8 @@ public class PopupWindow {
private boolean mAllowScrollingAnchorParent = true; private boolean mAllowScrollingAnchorParent = true;
private boolean mLayoutInsetDecor = false; private boolean mLayoutInsetDecor = false;
private boolean mNotTouchModal; private boolean mNotTouchModal;
private boolean mAttachedInDecor = true;
private boolean mAttachedInDecorSet = false;
private OnTouchListener mTouchInterceptor; private OnTouchListener mTouchInterceptor;
@@ -316,6 +318,7 @@ public class PopupWindow {
mContext = contentView.getContext(); mContext = contentView.getContext();
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
} }
setContentView(contentView); setContentView(contentView);
setWidth(width); setWidth(width);
setHeight(height); setHeight(height);
@@ -375,7 +378,7 @@ public class PopupWindow {
} }
/** /**
* 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 * is set to false
* which means the pop wont ignore cheek press dispatch events. * which means the pop wont ignore cheek press dispatch events.
* *
@@ -443,6 +446,19 @@ public class PopupWindow {
if (mWindowManager == null && mContentView != null) { if (mWindowManager == null && mContentView != null) {
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); 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);
}
} }
/** /**
@@ -701,6 +717,36 @@ public class PopupWindow {
mLayoutInScreen = enabled; 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 * Allows the popup window to force the flag
* {@link WindowManager.LayoutParams#FLAG_LAYOUT_INSET_DECOR}, overriding default behavior. * {@link WindowManager.LayoutParams#FLAG_LAYOUT_INSET_DECOR}, overriding default behavior.
@@ -1140,6 +1186,9 @@ public class PopupWindow {
if (mNotTouchModal) { if (mNotTouchModal) {
curFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; curFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
} }
if (mAttachedInDecor) {
curFlags |= WindowManager.LayoutParams.FLAG_LAYOUT_ATTACHED_IN_DECOR;
}
return curFlags; return curFlags;
} }

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); final boolean noActionBar = !hasFeature(FEATURE_ACTION_BAR) || hasFeature(FEATURE_NO_TITLE);
if (targetPreHoneycomb || (targetPreIcs && targetHcNeedsOptions && noActionBar)) { if (targetPreHoneycomb || (targetPreIcs && targetHcNeedsOptions && noActionBar)) {
addFlags(WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY); setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE);
} else { } 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 // 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, // whether it is taking care of insetting its content. If not,
// we need to use the parent's content frame so that the entire // we need to use the parent's content frame so that the entire
// window is positioned within that content. Otherwise we can use // 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. // positioning its content appropriately.
if (adjust != SOFT_INPUT_ADJUST_RESIZE) { 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 { } else {
// If the window is resizing, then we want to base the content // If the window is resizing, then we want to base the content
// frame on our attached content frame to resize... however, // 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.pm.PackageManager;
import android.content.res.Resources; import android.content.res.Resources;
import android.util.Slog; import android.util.Slog;
import android.view.WindowManager;
import com.android.internal.statusbar.IStatusBar; import com.android.internal.statusbar.IStatusBar;
import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.IStatusBarService;
@@ -297,7 +298,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
/** /**
* Hide or show the on-screen Menu key. Only call this from the window manager, typically in * 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 @Override
public void topAppWindowChanged(final boolean menuVisible) { public void topAppWindowChanged(final boolean menuVisible) {

View File

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