Merge "Fix issue #3362484: Can't dismiss activity picker by tapping outside dialog" into honeycomb
diff --git a/api/current.xml b/api/current.xml
index 4f566f6..76be208 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -10894,6 +10894,17 @@
visibility="public"
>
</field>
+<field name="windowCloseOnTouchOutside"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843611"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="windowContentOverlay"
type="int"
transient="false"
@@ -24300,6 +24311,19 @@
<parameter name="uri" type="android.net.Uri">
</parameter>
</method>
+<method name="setFinishOnTouchOutside"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="finish" type="boolean">
+</parameter>
+</method>
<method name="setIntent"
return="void"
abstract="false"
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 93ad17e..0a64070 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1808,6 +1808,14 @@
}
/**
+ * Sets whether this activity is finished when touched outside its window's
+ * bounds.
+ */
+ public void setFinishOnTouchOutside(boolean finish) {
+ mWindow.setCloseOnTouchOutside(finish);
+ }
+
+ /**
* Use with {@link #setDefaultKeyMode} to turn off default handling of
* keys.
*
@@ -2063,6 +2071,11 @@
* The default implementation always returns false.
*/
public boolean onTouchEvent(MotionEvent event) {
+ if (mWindow.shouldCloseOnTouch(this, event)) {
+ finish();
+ return true;
+ }
+
return false;
}
diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java
index 70e3616..428f4e3 100644
--- a/core/java/android/app/AlertDialog.java
+++ b/core/java/android/app/AlertDialog.java
@@ -64,11 +64,13 @@
protected AlertDialog(Context context, int theme) {
super(context, theme == 0 ? getDefaultDialogTheme(context) : theme);
+ mWindow.alwaysReadCloseOnTouchAttr();
mAlert = new AlertController(context, this, getWindow());
}
protected AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
super(context, getDefaultDialogTheme(context));
+ mWindow.alwaysReadCloseOnTouchAttr();
setCancelable(cancelable);
setOnCancelListener(cancelListener);
mAlert = new AlertController(context, this, getWindow());
@@ -81,25 +83,6 @@
return outValue.resourceId;
}
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- if (mCancelable) {
- final View decor = mWindow.getDecorView();
- final int width = decor.getWidth();
- final int height = decor.getHeight();
- final float x = ev.getX();
- final float y = ev.getY();
-
- if (mCancelable && (x < 0 || x > width || y < 0 || y > height)
- && mDecor != null && isShowing()) {
- cancel();
- return true;
- }
- }
-
- return super.onTouchEvent(ev);
- }
-
/**
* Gets one of the buttons used in the dialog.
* <p>
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 6791400..7365670 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -41,7 +41,6 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnCreateContextMenuListener;
-import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
@@ -90,12 +89,6 @@
private Message mDismissMessage;
private Message mShowMessage;
- /**
- * Whether to cancel the dialog when a touch is received outside of the
- * window's bounds.
- */
- private boolean mCanceledOnTouchOutside = false;
-
private OnKeyListener mOnKeyListener;
private boolean mCreated = false;
@@ -597,8 +590,7 @@
* happens outside of the window bounds.
*/
public boolean onTouchEvent(MotionEvent event) {
- if (mCancelable && mCanceledOnTouchOutside && event.getAction() == MotionEvent.ACTION_DOWN
- && isOutOfBounds(event) && mDecor != null && mShowing) {
+ if (mCancelable && mShowing && mWindow.shouldCloseOnTouch(mContext, event)) {
cancel();
return true;
}
@@ -606,16 +598,6 @@
return false;
}
- private boolean isOutOfBounds(MotionEvent event) {
- final int x = (int) event.getX();
- final int y = (int) event.getY();
- final int slop = ViewConfiguration.get(mContext).getScaledWindowTouchSlop();
- final View decorView = getWindow().getDecorView();
- return (x < -slop) || (y < -slop)
- || (x > (decorView.getWidth()+slop))
- || (y > (decorView.getHeight()+slop));
- }
-
/**
* Called when the trackball was moved and not handled by any of the
* views inside of the activity. So, for example, if the trackball moves
@@ -1021,7 +1003,7 @@
mCancelable = true;
}
- mCanceledOnTouchOutside = cancel;
+ mWindow.setCloseOnTouchOutside(cancel);
}
/**
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 2f27935..f1883dc 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -116,6 +116,8 @@
private Window mActiveChild;
private boolean mIsActive = false;
private boolean mHasChildren = false;
+ private boolean mCloseOnTouchOutside = false;
+ private boolean mSetCloseOnTouchOutside = false;
private int mForcedWindowFlags = 0;
private int mFeatures = DEFAULT_FEATURES;
@@ -786,6 +788,39 @@
return mHasSoftInputMode;
}
+ /** @hide */
+ public void setCloseOnTouchOutside(boolean close) {
+ mCloseOnTouchOutside = close;
+ mSetCloseOnTouchOutside = true;
+ }
+
+ /** @hide */
+ public boolean hasSetCloseOnTouchOutside() {
+ return mSetCloseOnTouchOutside;
+ }
+
+ /** @hide */
+ public abstract void alwaysReadCloseOnTouchAttr();
+
+ /** @hide */
+ public boolean shouldCloseOnTouch(Context context, MotionEvent event) {
+ if (mCloseOnTouchOutside && event.getAction() == MotionEvent.ACTION_DOWN
+ && isOutOfBounds(context, event) && peekDecorView() != null) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isOutOfBounds(Context context, MotionEvent event) {
+ final int x = (int) event.getX();
+ final int y = (int) event.getY();
+ final int slop = ViewConfiguration.get(context).getScaledWindowTouchSlop();
+ final View decorView = getDecorView();
+ return (x < -slop) || (y < -slop)
+ || (x > (decorView.getWidth()+slop))
+ || (y > (decorView.getHeight()+slop));
+ }
+
/**
* Enable extended screen features. This must be called before
* setContentView(). May be called as many times as desired as long as it
diff --git a/core/res/res/values-large/config.xml b/core/res/res/values-large/config.xml
index 05dd050..4449fd0 100644
--- a/core/res/res/values-large/config.xml
+++ b/core/res/res/values-large/config.xml
@@ -22,4 +22,6 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- see comment in values/config.xml -->
<dimen name="config_prefDialogWidth">440dp</dimen>
+ <!-- see comment in values/config.xml -->
+ <bool name="config_closeDialogWhenTouchOutside">true</bool>
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 6ca42e3..de233c8 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -362,6 +362,15 @@
pointer will go until that pointers go up thereby enabling touches
with multiple pointers to be split across multiple windows. -->
<attr name="windowEnableSplitTouch" format="boolean" />
+
+ <!-- Control whether a container should automatically close itself if
+ the user touches outside of it. This only applies to activities
+ and dialogs.
+
+ <p>Note: this attribute will only be respected for applications
+ that are targeting {@link android.os.Build.VERSION_CODES#HONEYCOMB}
+ or later. -->
+ <attr name="windowCloseOnTouchOutside" format="boolean" />
<!-- ============ -->
<!-- Alert Dialog styles -->
@@ -1342,6 +1351,7 @@
<attr name="windowActionModeOverlay" />
<attr name="windowActionBarOverlay" />
<attr name="windowEnableSplitTouch" />
+ <attr name="windowCloseOnTouchOutside" />
<!-- The minimum width the window is allowed to be, along the major
axis of the screen. That is, when in landscape. Can be either
an absolute dimension or a fraction of the screen size in that
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 25db21d..552c2f7 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -81,6 +81,11 @@
specified for -large and -xlarge configurations. -->
<dimen name="config_prefDialogWidth">0px</dimen>
+ <!-- Whether dialogs should close automatically when the user touches outside
+ of them. This should not normally be modified; the default value will
+ pick the correct behavior depending on the screen size. -->
+ <bool name="config_closeDialogWhenTouchOutside">false</bool>
+
<!-- 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>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index eabd457..1b47b54 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1425,6 +1425,7 @@
<public type="attr" name="queryHint" />
<public type="attr" name="fastScrollTextColor" />
<public type="attr" name="largeHeap" />
+ <public type="attr" name="windowCloseOnTouchOutside" />
<!-- A simple fade-in animation. -->
<public type="animator" name="fade_in" id="0x010b0000" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 506dd07..b257a73 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -138,6 +138,7 @@
<item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
<item name="windowActionBar">false</item>
<item name="windowActionModeOverlay">false</item>
+ <item name="windowCloseOnTouchOutside">false</item>
<!-- Dialog attributes -->
<item name="alertDialogStyle">@android:style/AlertDialog</item>
@@ -506,6 +507,7 @@
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
<item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item>
+ <item name="android:windowCloseOnTouchOutside">@bool/config_closeDialogWhenTouchOutside</item>
<item name="android:colorBackgroundCacheHint">@null</item>
@@ -547,6 +549,7 @@
<item name="android:backgroundDimEnabled">false</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowNoTitle">true</item>
+ <item name="android:windowCloseOnTouchOutside">false</item>
</style>
<!-- Default theme for alert dialog windows, which is used by the
@@ -687,6 +690,7 @@
<item name="windowIsFloating">true</item>
<item name="windowContentOverlay">@null</item>
<item name="textAppearance">@style/TextAppearance.Theme.Dialog.AppError</item>
+ <item name="android:windowCloseOnTouchOutside">false</item>
</style>
<!-- Special theme for the recent apps dialog, to allow customization
@@ -696,6 +700,7 @@
<item name="windowBackground">@android:color/transparent</item>
<item name="android:windowAnimationStyle">@android:style/Animation.RecentApplications</item>
<item name="android:textColor">@android:color/secondary_text_nofocus</item>
+ <item name="android:windowCloseOnTouchOutside">false</item>
</style>
<!-- Default theme for window that looks like a toast. -->
@@ -703,6 +708,7 @@
<item name="android:windowBackground">@android:drawable/toast_frame</item>
<item name="android:windowAnimationStyle">@android:style/Animation.Toast</item>
<item name="android:backgroundDimEnabled">false</item>
+ <item name="android:windowCloseOnTouchOutside">false</item>
</style>
<!-- Default theme with an Action Bar. -->
@@ -1291,6 +1297,7 @@
<item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item>
<item name="android:windowActionBar">false</item>
<item name="android:windowActionModeOverlay">true</item>
+ <item name="android:windowCloseOnTouchOutside">@bool/config_closeDialogWhenTouchOutside</item>
<item name="android:colorBackgroundCacheHint">@null</item>
@@ -1331,6 +1338,7 @@
<item name="android:backgroundDimEnabled">false</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowNoTitle">true</item>
+ <item name="android:windowCloseOnTouchOutside">false</item>
</style>
<!-- Holo theme for alert dialog windows, which is used by the
@@ -1377,6 +1385,7 @@
<item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item>
<item name="android:windowActionBar">false</item>
<item name="android:windowActionModeOverlay">true</item>
+ <item name="android:windowCloseOnTouchOutside">@bool/config_closeDialogWhenTouchOutside</item>
<item name="android:colorBackgroundCacheHint">@null</item>
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 68c1453..fb20e81 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -166,6 +166,8 @@
private int mTitleColor = 0;
+ private boolean mAlwaysReadCloseOnTouchAttr = false;
+
private ContextMenuBuilder mContextMenu;
private MenuDialogHelper mContextMenuHelper;
private ActionButtonSubmenu mActionButtonPopup;
@@ -2326,6 +2328,17 @@
addFlags(WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY);
}
+ if (mAlwaysReadCloseOnTouchAttr || getContext().getApplicationInfo().targetSdkVersion
+ >= android.os.Build.VERSION_CODES.HONEYCOMB) {
+ if (!hasSetCloseOnTouchOutside()) {
+ if (a.getBoolean(
+ com.android.internal.R.styleable.Window_windowCloseOnTouchOutside,
+ false)) {
+ setCloseOnTouchOutside(true);
+ }
+ }
+ }
+
WindowManager.LayoutParams params = getAttributes();
if (!hasSoftInputMode()) {
@@ -2479,6 +2492,11 @@
return contentParent;
}
+ /** @hide */
+ public void alwaysReadCloseOnTouchAttr() {
+ mAlwaysReadCloseOnTouchAttr = true;
+ }
+
private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor();