Merge "Add null check for MotionEvent#getDevice."
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index 8470798..2459cfa 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -268,9 +268,9 @@
                 // Cursor can be active at any location in the text while mouse pointer can start
                 // selection from a totally different location. Use LAST_TAP_DOWN span to ensure
                 // text selection will start from mouse pointer location.
+                final int startOffset = buffer.getSpanStart(LAST_TAP_DOWN);
                 if (isMouse && Touch.isSelectionStarted(buffer)) {
-                    int offset = buffer.getSpanStart(LAST_TAP_DOWN);
-                    Selection.setSelection(buffer, offset);
+                    Selection.setSelection(buffer, startOffset);
                 }
 
                 if (isTouchSelecting(isMouse, buffer) && handled) {
@@ -285,9 +285,9 @@
                     // Update selection as we're moving the selection area.
 
                     // Get the current touch position
-                    int offset = widget.getOffsetForPosition(event.getX(), event.getY());
-
-                    Selection.extendSelection(buffer, offset);
+                    final int offset = widget.getOffsetForPosition(event.getX(), event.getY());
+                    Selection.setSelection(buffer, Math.min(startOffset, offset),
+                            Math.max(startOffset, offset));
                     return true;
                 }
             } else if (action == MotionEvent.ACTION_UP) {
@@ -301,10 +301,12 @@
                     return true;
                 }
 
-                int offset = widget.getOffsetForPosition(event.getX(), event.getY());
                 if (wasTouchSelecting) {
+                    final int startOffset = buffer.getSpanStart(LAST_TAP_DOWN);
+                    final int endOffset = widget.getOffsetForPosition(event.getX(), event.getY());
+                    Selection.setSelection(buffer, Math.min(startOffset, endOffset),
+                            Math.max(startOffset, endOffset));
                     buffer.removeSpan(LAST_TAP_DOWN);
-                    Selection.extendSelection(buffer, offset);
                 }
 
                 MetaKeyKeyListener.adjustMetaAfterKeypress(buffer);
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
index 2c2d393..c5e2ae6 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
@@ -49,4 +49,17 @@
 
         onView(withId(R.id.textview)).check(hasSelection("llo wor"));
     }
+
+    @SmallTest
+    public void testSelectTextByDrag_reverse() throws Exception {
+        getActivity();
+
+        final String helloWorld = "Hello world!";
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+        onView(withId(R.id.textview)).perform(
+                mouseDragOnText( helloWorld.indexOf("ld!"), helloWorld.indexOf("llo")));
+
+        onView(withId(R.id.textview)).check(hasSelection("llo wor"));
+    }
 }
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
index 11e937b..df9d44a 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
@@ -2,6 +2,7 @@
 
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.res.Resources;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
@@ -30,10 +31,9 @@
 
     private static final String TABLE_MTP_DOCUMENTS = "MtpDocuments";
 
-    static final String COLUMN_DEVICE_ID = "deviceId";
-    static final String COLUMN_STORAGE_ID = "storageId";
-    static final String COLUMN_OBJECT_HANDLE = "objectHandle";
-    static final String COLUMN_FULL_PATH = "fullPath";
+    static final String COLUMN_DEVICE_ID = "device_id";
+    static final String COLUMN_STORAGE_ID = "storage_id";
+    static final String COLUMN_OBJECT_HANDLE = "object_handle";
 
     private static class OpenHelper extends SQLiteOpenHelper {
         private static final String CREATE_TABLE_QUERY =
@@ -43,7 +43,6 @@
                 COLUMN_DEVICE_ID + " INTEGER NOT NULL," +
                 COLUMN_STORAGE_ID + " INTEGER NOT NULL," +
                 COLUMN_OBJECT_HANDLE + " INTEGER," +
-                COLUMN_FULL_PATH + " TEXT NOT NULL," +
                 DocumentsContract.Document.COLUMN_MIME_TYPE + " TEXT," +
                 DocumentsContract.Document.COLUMN_DISPLAY_NAME + " TEXT NOT NULL," +
                 DocumentsContract.Document.COLUMN_SUMMARY + " TEXT," +
@@ -86,17 +85,15 @@
     }
 
     @VisibleForTesting
-    void putRootDocument(MtpRoot root) throws Exception {
+    void putRootDocument(Resources resources, MtpRoot root) throws Exception {
         database.beginTransaction();
         try {
             final ContentValues values = new ContentValues();
             values.put(COLUMN_DEVICE_ID, root.mDeviceId);
             values.put(COLUMN_STORAGE_ID, root.mStorageId);
             values.putNull(COLUMN_OBJECT_HANDLE);
-            values.put(
-                    COLUMN_FULL_PATH, "/" + root.mDeviceId + "/" + escape(root.mDescription));
             values.put(Document.COLUMN_MIME_TYPE, DocumentsContract.Document.MIME_TYPE_DIR);
-            values.put(Document.COLUMN_DISPLAY_NAME, root.mDescription);
+            values.put(Document.COLUMN_DISPLAY_NAME, root.getRootName(resources));
             values.putNull(Document.COLUMN_SUMMARY);
             values.putNull(Document.COLUMN_LAST_MODIFIED);
             values.putNull(Document.COLUMN_ICON);
@@ -113,7 +110,7 @@
     }
 
     @VisibleForTesting
-    void putDocument(int deviceId, String parentFullPath, MtpObjectInfo info) throws Exception {
+    void putDocument(int deviceId, MtpObjectInfo info) throws Exception {
         database.beginTransaction();
         try {
             final String mimeType = CursorHelper.formatTypeToMimeType(info.getFormat());
@@ -134,9 +131,7 @@
             values.put(COLUMN_DEVICE_ID, deviceId);
             values.put(COLUMN_STORAGE_ID, info.getStorageId());
             values.put(COLUMN_OBJECT_HANDLE, info.getObjectHandle());
-            values.put(COLUMN_FULL_PATH, parentFullPath + "/" + escape(info.getName()));
-            values.put(
-                    Document.COLUMN_MIME_TYPE, CursorHelper.formatTypeToMimeType(info.getFormat()));
+            values.put(Document.COLUMN_MIME_TYPE, mimeType);
             values.put(Document.COLUMN_DISPLAY_NAME, info.getName());
             values.putNull(Document.COLUMN_SUMMARY);
             values.put(
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
index 7ce32542..8e1335f 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
@@ -1,6 +1,5 @@
 package com.android.mtp;
 
-
 import android.database.Cursor;
 import android.mtp.MtpConstants;
 import android.mtp.MtpObjectInfo;
@@ -15,7 +14,6 @@
         MtpDatabase.COLUMN_DEVICE_ID,
         MtpDatabase.COLUMN_STORAGE_ID,
         MtpDatabase.COLUMN_OBJECT_HANDLE,
-        MtpDatabase.COLUMN_FULL_PATH,
         DocumentsContract.Document.COLUMN_MIME_TYPE,
         DocumentsContract.Document.COLUMN_DISPLAY_NAME,
         DocumentsContract.Document.COLUMN_SUMMARY,
@@ -25,6 +23,8 @@
         DocumentsContract.Document.COLUMN_SIZE
     };
 
+    private final TestResources resources = new TestResources();
+
     @Override
     public void tearDown() {
         MtpDatabase.deleteDatabase(getContext());
@@ -32,35 +32,10 @@
 
     public void testPutRootDocument() throws Exception {
         final MtpDatabase database = new MtpDatabase(getContext());
-        final MtpRoot root = new MtpRoot(
-                0,
-                1,
-                "Device A",
-                "Storage",
-                1000,
-                2000,
-                "");
-        database.putRootDocument(root);
-
-        final MtpRoot duplicatedNameRoot = new MtpRoot(
-                0,
-                2,
-                "Device A",
-                "Storage",
-                1000,
-                2000,
-                "");
-        database.putRootDocument(duplicatedNameRoot);
-
-        final MtpRoot strangeNameRoot = new MtpRoot(
-                0,
-                3,
-                "Device A",
-                "/@#%&<>Storage",
-                1000,
-                2000,
-                "");
-        database.putRootDocument(strangeNameRoot);
+        database.putRootDocument(resources, new MtpRoot(0, 1, "Device", "Storage", 1000, 2000, ""));
+        database.putRootDocument(resources, new MtpRoot(0, 2, "Device", "Storage", 1000, 2000, ""));
+        database.putRootDocument(
+                resources, new MtpRoot(0, 3, "Device", "/@#%&<>Storage", 1000, 2000, ""));
 
         final Cursor cursor = database.queryChildDocuments(COLUMN_NAMES);
         assertEquals(3, cursor.getCount());
@@ -70,22 +45,23 @@
         assertEquals("deviceId", 0, cursor.getInt(1));
         assertEquals("storageId", 1, cursor.getInt(2));
         assertTrue("objectHandle", cursor.isNull(3));
-        assertEquals("fullPath", "/0/Storage", cursor.getString(4));
-        assertEquals("mimeType", DocumentsContract.Document.MIME_TYPE_DIR, cursor.getString(5));
-        assertEquals("displayName", "Storage", cursor.getString(6));
-        assertTrue("summary", cursor.isNull(7));
-        assertTrue("lastModified", cursor.isNull(8));
-        assertTrue("icon", cursor.isNull(9));
-        assertEquals("flag", 0, cursor.getInt(10));
-        assertEquals("size", 1000, cursor.getInt(11));
+        assertEquals("mimeType", DocumentsContract.Document.MIME_TYPE_DIR, cursor.getString(4));
+        assertEquals("displayName", "Device Storage", cursor.getString(5));
+        assertTrue("summary", cursor.isNull(6));
+        assertTrue("lastModified", cursor.isNull(7));
+        assertTrue("icon", cursor.isNull(8));
+        assertEquals("flag", 0, cursor.getInt(9));
+        assertEquals("size", 1000, cursor.getInt(10));
 
         cursor.moveToNext();
         assertEquals("documentId", 2, cursor.getInt(0));
-        assertEquals("fullPath", "/0/Storage", cursor.getString(4));
+        assertEquals("displayName", "Device Storage", cursor.getString(5));
 
         cursor.moveToNext();
         assertEquals("documentId", 3, cursor.getInt(0));
-        assertEquals("fullPath", "/0/%2F%40%23%25%26%3C%3EStorage", cursor.getString(4));
+        assertEquals("displayName", "Device /@#%&<>Storage", cursor.getString(5));
+
+        cursor.close();
     }
 
     public void testPutDocument() throws Exception {
@@ -96,7 +72,7 @@
         builder.setStorageId(5);
         builder.setFormat(MtpConstants.FORMAT_TEXT);
         builder.setCompressedSize(1000);
-        database.putDocument(0, "/0/Storage", builder.build());
+        database.putDocument(0, builder.build());
 
         final Cursor cursor = database.queryChildDocuments(COLUMN_NAMES);
         assertEquals(1, cursor.getCount());
@@ -105,17 +81,16 @@
         assertEquals("deviceId", 0, cursor.getInt(1));
         assertEquals("storageId", 5, cursor.getInt(2));
         assertEquals("objectHandle", 100, cursor.getInt(3));
-        assertEquals("fullPath", "/0/Storage/test.txt", cursor.getString(4));
-        assertEquals("mimeType", "text/plain", cursor.getString(5));
-        assertEquals("displayName", "test.txt", cursor.getString(6));
-        assertTrue("summary", cursor.isNull(7));
-        assertTrue("lastModified", cursor.isNull(8));
-        assertTrue("icon", cursor.isNull(9));
+        assertEquals("mimeType", "text/plain", cursor.getString(4));
+        assertEquals("displayName", "test.txt", cursor.getString(5));
+        assertTrue("summary", cursor.isNull(6));
+        assertTrue("lastModified", cursor.isNull(7));
+        assertTrue("icon", cursor.isNull(8));
         assertEquals(
                 "flag",
                 DocumentsContract.Document.FLAG_SUPPORTS_DELETE |
                 DocumentsContract.Document.FLAG_SUPPORTS_WRITE,
-                cursor.getInt(10));
-        assertEquals("size", 1000, cursor.getInt(11));
+                cursor.getInt(9));
+        assertEquals("size", 1000, cursor.getInt(10));
     }
 }
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index 0c03814c..5765f0a 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -16,9 +16,6 @@
 
 package com.android.mtp;
 
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.content.res.Resources.NotFoundException;
 import android.database.Cursor;
 import android.mtp.MtpConstants;
 import android.mtp.MtpObjectInfo;
@@ -26,7 +23,6 @@
 import android.provider.DocumentsContract.Root;
 import android.provider.DocumentsContract;
 import android.test.AndroidTestCase;
-import android.test.mock.MockResources;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import java.io.FileNotFoundException;
@@ -39,16 +35,7 @@
     private TestContentResolver mResolver;
     private MtpDocumentsProvider mProvider;
     private TestMtpManager mMtpManager;
-    private final MockResources mResources = new MockResources() {
-        @Override
-        public String getString(int id) throws NotFoundException {
-            switch (id) {
-                case R.string.root_name:
-                    return "%1$s %2$s";
-            }
-            throw new NotFoundException();
-        }
-    };
+    private final TestResources mResources = new TestResources();
 
     @Override
     public void setUp() throws IOException {
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java
new file mode 100644
index 0000000..eb80e3b
--- /dev/null
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 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 com.android.mtp;
+
+import android.test.mock.MockResources;
+
+class TestResources extends MockResources {
+    @Override
+    public String getString(int id) throws NotFoundException {
+        switch (id) {
+            case R.string.root_name:
+                return "%1$s %2$s";
+        }
+        throw new NotFoundException();
+    }
+}