Merge "Fix off by one error in NetworkManagementService.isUsbRNDISStarted()"
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 90e8c14..179b807 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1632,12 +1632,20 @@
 
     /**
      * Broadcast Action:  External media is unmounted because it is being shared via USB mass storage.
-     * The path to the mount point for the removed media is contained in the Intent.mData field.
+     * The path to the mount point for the shared media is contained in the Intent.mData field.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_MEDIA_SHARED = "android.intent.action.MEDIA_SHARED";
 
     /**
+     * Broadcast Action:  External media is no longer being shared via USB mass storage.
+     * The path to the mount point for the previously shared media is contained in the Intent.mData field.
+     *
+     * @hide
+     */
+    public static final String ACTION_MEDIA_UNSHARED = "android.intent.action.MEDIA_UNSHARED";
+
+    /**
      * Broadcast Action:  External media was removed from SD card slot, but mount point was not unmounted.
      * The path to the mount point for the removed media is contained in the Intent.mData field.
      */
diff --git a/core/java/android/database/sqlite/DatabaseObjectNotClosedException.java b/core/java/android/database/sqlite/DatabaseObjectNotClosedException.java
new file mode 100644
index 0000000..8ac4c0f
--- /dev/null
+++ b/core/java/android/database/sqlite/DatabaseObjectNotClosedException.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2006 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.database.sqlite;
+
+/**
+ * An exception that indicates that garbage-collector is finalizing a database object
+ * that is not explicitly closed
+ * @hide
+ */
+public class DatabaseObjectNotClosedException extends RuntimeException
+{
+    private static final String s = "Application did not close the cursor or database object " +
+            "that was opened here";
+
+    public DatabaseObjectNotClosedException()
+    {
+        super(s);
+    }
+}
diff --git a/core/java/android/database/sqlite/SQLiteCompiledSql.java b/core/java/android/database/sqlite/SQLiteCompiledSql.java
index 486ad20..4ccf6b0 100644
--- a/core/java/android/database/sqlite/SQLiteCompiledSql.java
+++ b/core/java/android/database/sqlite/SQLiteCompiledSql.java
@@ -56,7 +56,7 @@
     /* package */ SQLiteCompiledSql(SQLiteDatabase db, String sql) {
         mDatabase = db;
         mSqlStmt = sql;
-        mStackTrace = new Exception().fillInStackTrace();
+        mStackTrace = new DatabaseObjectNotClosedException().fillInStackTrace();
         this.nHandle = db.mNativeHandle;
         compile(sql, true);
     }
diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java
index 96ed297..3f0fcb1 100644
--- a/core/java/android/database/sqlite/SQLiteCursor.java
+++ b/core/java/android/database/sqlite/SQLiteCursor.java
@@ -207,7 +207,7 @@
             String editTable, SQLiteQuery query) {
         // The AbstractCursor constructor needs to do some setup.
         super();
-        mStackTrace = new Exception().fillInStackTrace();
+        mStackTrace = new DatabaseObjectNotClosedException().fillInStackTrace();
         mDatabase = db;
         mDriver = driver;
         mEditTable = editTable;
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index d8ccf85..9fa9368 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -1749,7 +1749,7 @@
         mFlags = flags;
         mPath = path;
         mSlowQueryThreshold = SystemProperties.getInt(LOG_SLOW_QUERIES_PROPERTY, -1);
-        mStackTrace = new Exception().fillInStackTrace();
+        mStackTrace = new DatabaseObjectNotClosedException().fillInStackTrace();
         mFactory = factory;
         dbopen(mPath, mFlags);
         if (SQLiteDebug.DEBUG_SQL_CACHE) {
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index b28cf43..f363828 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -274,9 +274,11 @@
 
     private void onDeviceRemoved(String deviceObjectPath) {
         String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
-        if (address != null)
+        if (address != null) {
             mBluetoothService.getBondState().setBondState(address.toUpperCase(),
                     BluetoothDevice.BOND_NONE, BluetoothDevice.UNBOND_REASON_REMOVED);
+            mBluetoothService.setRemoteDeviceProperty(address, "UUIDs", null);
+        }
     }
 
     /*package*/ void onPropertyChanged(String[] propValues) {
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index db19bca..39edcad 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -822,8 +822,9 @@
                 break;
             case 1: // TEXT_AREA
                 single = false;
-                inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE
+                inputType = EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE
                         | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES
+                        | EditorInfo.TYPE_CLASS_TEXT
                         | EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT;
                 imeOptions |= EditorInfo.IME_ACTION_NONE;
                 break;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 72791fb..0739735 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2480,20 +2480,30 @@
      */
     public int findAll(String find) {
         if (0 == mNativeClass) return 0; // client isn't initialized
-        if (mFindIsUp == false) {
-            recordNewContentSize(mContentWidth, mContentHeight + mFindHeight,
-                    false);
-            mFindIsUp = true;
-        }
-        int result = nativeFindAll(find.toLowerCase(), find.toUpperCase());
+        int result = find != null ? nativeFindAll(find.toLowerCase(),
+                find.toUpperCase()) : 0;
         invalidate();
         mLastFind = find;
         return result;
     }
 
+    /**
+     * @hide
+     */
+    public void setFindIsUp(boolean isUp) {
+        mFindIsUp = isUp;
+        if (isUp) {
+            recordNewContentSize(mContentWidth, mContentHeight + mFindHeight,
+                    false);
+        }
+        if (0 == mNativeClass) return; // client isn't initialized
+        nativeSetFindIsUp(isUp);
+    }
+
     // Used to know whether the find dialog is open.  Affects whether
     // or not we draw the highlights for matches.
     private boolean mFindIsUp;
+
     private int mFindHeight;
     // Keep track of the last string sent, so we can search again after an
     // orientation change or the dismissal of the soft keyboard.
@@ -2553,14 +2563,21 @@
      * Clear the highlighting surrounding text matches created by findAll.
      */
     public void clearMatches() {
+        mLastFind = "";
         if (mNativeClass == 0)
             return;
-        if (mFindIsUp) {
-            recordNewContentSize(mContentWidth, mContentHeight - mFindHeight,
-                    false);
-            mFindIsUp = false;
-        }
-        nativeSetFindIsUp();
+        nativeSetFindIsEmpty();
+        invalidate();
+    }
+
+    /**
+     * @hide
+     */
+    public void notifyFindDialogDismissed() {
+        clearMatches();
+        setFindIsUp(false);
+        recordNewContentSize(mContentWidth, mContentHeight - mFindHeight,
+                false);
         // Now that the dialog has been removed, ensure that we scroll to a
         // location that is not beyond the end of the page.
         pinScrollTo(mScrollX, mScrollY, false, 0);
@@ -4477,12 +4494,12 @@
             y = getViewHeightWithTitle() - 1;
         }
 
-        // pass the touch events from UI thread to WebCore thread
-        if (mForwardTouchEvents
-                && (action != MotionEvent.ACTION_MOVE || eventTime
-                        - mLastSentTouchTime > mCurrentTouchInterval)
-                && (action == MotionEvent.ACTION_DOWN
-                        || mPreventDrag != PREVENT_DRAG_CANCEL)) {
+        // pass the touch events, except ACTION_MOVE which will be handled
+        // later, from UI thread to WebCore thread
+        if (mFullScreenHolder != null || (mForwardTouchEvents
+                && action != MotionEvent.ACTION_MOVE
+                && (action == MotionEvent.ACTION_DOWN || mPreventDrag
+                        != PREVENT_DRAG_CANCEL))) {
             WebViewCore.TouchEventData ted = new WebViewCore.TouchEventData();
             ted.mAction = action;
             ted.mX = viewToContentX((int) x + mScrollX);
@@ -4573,6 +4590,21 @@
                     if ((deltaX * deltaX + deltaY * deltaY) < mTouchSlopSquare) {
                         break;
                     }
+
+                    // pass the first ACTION_MOVE from UI thread to WebCore
+                    // thread after the distance is confirmed that it is a drag
+                    if (mFullScreenHolder == null && mForwardTouchEvents
+                            && mPreventDrag != PREVENT_DRAG_CANCEL) {
+                        WebViewCore.TouchEventData ted = new WebViewCore.TouchEventData();
+                        ted.mAction = action;
+                        ted.mX = viewToContentX((int) x + mScrollX);
+                        ted.mY = viewToContentY((int) y + mScrollY);
+                        ted.mEventTime = eventTime;
+                        ted.mMetaState = ev.getMetaState();
+                        mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
+                        mLastSentTouchTime = eventTime;
+                    }
+
                     if (mPreventDrag == PREVENT_DRAG_MAYBE_YES) {
                         // track mLastTouchTime as we may need to do fling at
                         // ACTION_UP
@@ -4629,6 +4661,20 @@
                                     Toast.LENGTH_LONG).show();
                         }
                     }
+                } else {
+                    // pass the touch events from UI thread to WebCore thread
+                    if (mFullScreenHolder == null && mForwardTouchEvents
+                            && eventTime - mLastSentTouchTime > mCurrentTouchInterval
+                            && mPreventDrag != PREVENT_DRAG_CANCEL) {
+                        WebViewCore.TouchEventData ted = new WebViewCore.TouchEventData();
+                        ted.mAction = action;
+                        ted.mX = viewToContentX((int) x + mScrollX);
+                        ted.mY = viewToContentY((int) y + mScrollY);
+                        ted.mEventTime = eventTime;
+                        ted.mMetaState = ev.getMetaState();
+                        mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
+                        mLastSentTouchTime = eventTime;
+                    }
                 }
 
                 // do pan
@@ -6863,7 +6909,8 @@
     private native void     nativeRecordButtons(boolean focused,
             boolean pressed, boolean invalidate);
     private native void     nativeSelectBestAt(Rect rect);
-    private native void     nativeSetFindIsUp();
+    private native void     nativeSetFindIsEmpty();
+    private native void     nativeSetFindIsUp(boolean isUp);
     private native void     nativeSetFollowedLink(boolean followed);
     private native void     nativeSetHeightCanMeasure(boolean measure);
     private native void     nativeSetRootLayer(int layer);
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 41f3850..3849023 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -523,6 +523,11 @@
 
         Intent in = null;
 
+        if (oldState == VolumeState.Shared && newState != oldState) {
+            mContext.sendBroadcast(new Intent(Intent.ACTION_MEDIA_UNSHARED,
+                                                Uri.parse("file://" + path)));
+        }
+
         if (newState == VolumeState.Init) {
         } else if (newState == VolumeState.NoMedia) {
             // NoMedia is handled via Disk Remove events