Fix issue #3225529: AlertDialogs are squishing their content views
ViewRoot is now smarter about measuring WRAP/WRAP windows.
Change-Id: I690fc78ddbe252d7c8070edb8e7352aec6c67ce9
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 2f110f0..935d234 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -91,6 +91,22 @@
*/
public int screenLayout;
+ /**
+ * Check if the Configuration's current {@link #screenLayout} is at
+ * least the given size.
+ *
+ * @param size The desired size, either {@link #SCREENLAYOUT_SIZE_SMALL},
+ * {@link #SCREENLAYOUT_SIZE_NORMAL}, {@link #SCREENLAYOUT_SIZE_LARGE}, or
+ * {@link #SCREENLAYOUT_SIZE_XLARGE}.
+ * @return Returns true if the current screen layout size is at least
+ * the given size.
+ */
+ public boolean isLayoutSizeAtLeast(int size) {
+ int cur = screenLayout&SCREENLAYOUT_SIZE_MASK;
+ if (cur == SCREENLAYOUT_SIZE_UNDEFINED) return false;
+ return size >= cur;
+ }
+
public static final int TOUCHSCREEN_UNDEFINED = 0;
public static final int TOUCHSCREEN_NOTOUCH = 1;
public static final int TOUCHSCREEN_STYLUS = 2;
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 1972692..761c5d9 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -53,6 +53,7 @@
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.TypedValue;
import android.view.InputQueue.FinishedCallback;
import android.view.View.MeasureSpec;
import android.view.accessibility.AccessibilityEvent;
@@ -87,7 +88,7 @@
/** @noinspection PointlessBooleanExpression*/
private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
- private static final boolean DEBUG_INPUT = true || LOCAL_LOGV;
+ private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV;
private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV;
private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV;
private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV;
@@ -125,6 +126,8 @@
final int[] mTmpLocation = new int[2];
+ final TypedValue mTmpValue = new TypedValue();
+
final InputMethodCallback mInputMethodCallback;
final SparseArray<Object> mPendingEvents = new SparseArray<Object>();
int mPendingEventSeq = 0;
@@ -405,7 +408,7 @@
}
mPendingContentInsets.set(mAttachInfo.mContentInsets);
mPendingVisibleInsets.set(0, 0, 0, 0);
- if (Config.LOGV) Log.v(TAG, "Added window " + mWindow);
+ if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow);
if (res < WindowManagerImpl.ADD_OKAY) {
mView = null;
mAttachInfo.mRootView = null;
@@ -639,7 +642,7 @@
mTraversalScheduled = false;
mWillDrawSoon = true;
- boolean windowResizesToFitContent = false;
+ boolean windowSizeMayChange = false;
boolean fullRedrawNeeded = mFullRedrawNeeded;
boolean newSurface = false;
boolean surfaceChanged = false;
@@ -696,7 +699,7 @@
"View " + host + " resized to: " + frame);
fullRedrawNeeded = true;
mLayoutRequested = true;
- windowResizesToFitContent = true;
+ windowSizeMayChange = true;
}
}
@@ -722,6 +725,8 @@
// enqueued an action after being detached
getRunQueue().executeActions(attachInfo.mHandler);
+ final Resources res = mView.getContext().getResources();
+
if (mFirst) {
host.fitSystemWindows(mAttachInfo.mContentInsets);
// make sure touch mode code executes by setting cached value
@@ -743,23 +748,69 @@
}
if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
|| lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
- windowResizesToFitContent = true;
+ windowSizeMayChange = true;
- DisplayMetrics packageMetrics =
- mView.getContext().getResources().getDisplayMetrics();
+ DisplayMetrics packageMetrics = res.getDisplayMetrics();
desiredWindowWidth = packageMetrics.widthPixels;
desiredWindowHeight = packageMetrics.heightPixels;
}
}
- childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
- childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
-
// Ask host how big it wants to be
if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(TAG,
"Measuring " + host + " in display " + desiredWindowWidth
+ "x" + desiredWindowHeight + "...");
- host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+
+ boolean goodMeasure = false;
+ if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
+ || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
+ // On large screens, we don't want to allow dialogs to just
+ // stretch to fill the entire width of the screen to display
+ // one line of text. First try doing the layout at a smaller
+ // size to see if it will fit.
+ final DisplayMetrics packageMetrics = res.getDisplayMetrics();
+ res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
+ int baseSize = 0;
+ if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
+ baseSize = (int)mTmpValue.getDimension(packageMetrics);
+ }
+ if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": baseSize=" + baseSize);
+ if (desiredWindowWidth > baseSize) {
+ int maxHeight = (desiredWindowHeight*2)/3;
+ childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
+ childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
+ host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+ if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
+ + host.getWidth() + "," + host.getHeight() + ")");
+ // Note: for now we are not taking into account height, since we
+ // can't distinguish between places where it would be useful to
+ // increase the width (text) vs. where it would not (a list).
+ // Maybe we can just try the next size up, and see if that reduces
+ // the height?
+ if (host.getWidth() <= baseSize /*&& host.getHeight() <= maxHeight*/) {
+ Log.v(TAG, "Good!");
+ goodMeasure = true;
+ } else {
+ // Didn't fit in that size... try expanding a bit.
+ baseSize = (baseSize+desiredWindowWidth)/2;
+ if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": next baseSize="
+ + baseSize);
+ host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+ if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
+ + host.getWidth() + "," + host.getHeight() + ")");
+ if (host.getWidth() <= baseSize /*&& host.getHeight() <= maxHeight*/) {
+ if (DEBUG_DIALOG) Log.v(TAG, "Good!");
+ goodMeasure = true;
+ }
+ }
+ }
+ }
+
+ if (!goodMeasure) {
+ childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
+ childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
+ host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+ }
if (DBG) {
System.out.println("======================================");
@@ -812,7 +863,7 @@
}
}
- boolean windowShouldResize = mLayoutRequested && windowResizesToFitContent
+ boolean windowShouldResize = mLayoutRequested && windowSizeMayChange
&& ((mWidth != host.mMeasuredWidth || mHeight != host.mMeasuredHeight)
|| (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
frame.width() < desiredWindowWidth && frame.width() != mWidth)
diff --git a/core/res/res/layout-xlarge/alert_dialog.xml b/core/res/res/layout-xlarge/alert_dialog.xml
index 82b4509..291e1c2 100644
--- a/core/res/res/layout-xlarge/alert_dialog.xml
+++ b/core/res/res/layout-xlarge/alert_dialog.xml
@@ -29,9 +29,7 @@
android:paddingLeft="3dip"
android:paddingRight="1dip"
android:majorWeightMin="0.45"
- android:minorWeightMin="0.72"
- android:majorWeightMax="0.45"
- android:minorWeightMax="0.72">
+ android:minorWeightMin="0.72">
<LinearLayout android:id="@+id/topPanel"
android:layout_width="match_parent"
diff --git a/core/res/res/layout-xlarge/alert_dialog_holo.xml b/core/res/res/layout-xlarge/alert_dialog_holo.xml
index a01e03a..72b1e31 100644
--- a/core/res/res/layout-xlarge/alert_dialog_holo.xml
+++ b/core/res/res/layout-xlarge/alert_dialog_holo.xml
@@ -28,9 +28,7 @@
android:paddingLeft="3dip"
android:paddingRight="1dip"
android:majorWeightMin="0.45"
- android:minorWeightMin="0.72"
- android:majorWeightMax="0.45"
- android:minorWeightMax="0.72">
+ android:minorWeightMin="0.72">
<LinearLayout android:id="@+id/topPanel"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/alert_dialog.xml b/core/res/res/layout/alert_dialog.xml
index e3ba634..fd20bd1 100644
--- a/core/res/res/layout/alert_dialog.xml
+++ b/core/res/res/layout/alert_dialog.xml
@@ -29,8 +29,7 @@
android:paddingLeft="3dip"
android:paddingRight="1dip"
android:majorWeightMin="0.65"
- android:minorWeightMin="0.9"
- android:majorWeightMax="0.65">
+ android:minorWeightMin="0.9">
<LinearLayout android:id="@+id/topPanel"
android:layout_width="match_parent"
diff --git a/core/res/res/values-large/config.xml b/core/res/res/values-large/config.xml
new file mode 100644
index 0000000..05dd050
--- /dev/null
+++ b/core/res/res/values-large/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2010, 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- see comment in values/config.xml -->
+ <dimen name="config_prefDialogWidth">440dp</dimen>
+</resources>
diff --git a/core/res/res/values-xlarge/config.xml b/core/res/res/values-xlarge/config.xml
index 8ed1c3e..2f1f4cf 100644
--- a/core/res/res/values-xlarge/config.xml
+++ b/core/res/res/values-xlarge/config.xml
@@ -33,5 +33,8 @@
<!-- see comment in values/config.xml -->
<integer name="config_longPressOnHomeBehavior">0</integer>
+ <!-- see comment in values/config.xml -->
+ <dimen name="config_prefDialogWidth">440dp</dimen>
+
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 03d581f..e655192 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -76,6 +76,11 @@
be an integer for a constant duration. -->
<fraction name="config_dimBehindFadeDuration">100%</fraction>
+ <!-- The maximum width we would prefer dialogs to be. 0 if there is no
+ maximum (let them grow as large as the screen). Actual values are
+ specified for -large and -xlarge configurations. -->
+ <dimen name="config_prefDialogWidth">0px</dimen>
+
<!-- The duration (in milliseconds) that the radio will scan for a signal
when there's no network connection. If the scan doesn't timeout, use zero -->
<integer name="config_radioScanningTimeout">0</integer>