Merge "Add default code reviewers into OWNERS"
diff --git a/Android.mk b/Android.mk
index 349d78e..a0b633a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,37 +1,44 @@
 LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
 
-LOCAL_MODULE_TAGS := optional
-LOCAL_PRIVILEGED_MODULE := true
+########################
+# Complete DocumentsUI app:
+include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_STATIC_JAVA_LIBRARIES += guava
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-
-LOCAL_STATIC_ANDROID_LIBRARIES := \
-        android-support-v4 \
-        android-support-v7-appcompat \
-        android-support-v13 \
-        android-support-design \
-        android-support-transition \
-        android-support-v7-recyclerview
-
-LOCAL_USE_AAPT2 := true
-
-LOCAL_JACK_FLAGS := \
-  -D jack.optimization.inner-class.accessors=true
-
-# Only enable asserts on userdebug/eng builds
-ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
-LOCAL_JACK_FLAGS += -D jack.assert.policy=always
-endif
-
 LOCAL_PACKAGE_NAME := DocumentsUI
 LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := platform
-LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_FULL_MANIFEST_FILE := $(LOCAL_PATH)/AndroidManifest.xml
 
-include $(BUILD_PACKAGE)
+include $(LOCAL_PATH)/build_apk.mk
+
+########################
+# Minimal DocumentsUI app (supports Scoped Directory Access only):
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+        src/com/android/documentsui/ScopedAccessActivity.java \
+        src/com/android/documentsui/ScopedAccessPackageReceiver.java \
+        src/com/android/documentsui/ScopedAccessProvider.java \
+        src/com/android/documentsui/ScopedAccessMetrics.java \
+        src/com/android/documentsui/archives/Archive.java \
+        src/com/android/documentsui/archives/ArchiveId.java \
+        src/com/android/documentsui/archives/ArchivesProvider.java \
+        src/com/android/documentsui/archives/Loader.java \
+        src/com/android/documentsui/archives/Proxy.java \
+        src/com/android/documentsui/archives/ReadableArchive.java \
+        src/com/android/documentsui/archives/WriteableArchive.java \
+        src/com/android/documentsui/base/Providers.java \
+        src/com/android/documentsui/base/SharedMinimal.java \
+        src/com/android/documentsui/prefs/ScopedAccessLocalPreferences.java
+
+LOCAL_PACKAGE_NAME := DocumentsUIMinimal
+LOCAL_PRIVATE_PLATFORM_APIS := true
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/minimal/res
+LOCAL_FULL_MANIFEST_FILE := $(LOCAL_PATH)/minimal/AndroidManifest.xml
+
+include $(LOCAL_PATH)/build_apk.mk
+
+# Include makefiles for tests and libraries under the current path
 include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index cadb431..c264285 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1,9 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2007-2017 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.
+ */
+-->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.documentsui">
 
     <uses-permission android:name="android.permission.GET_APP_GRANTED_URI_PERMISSIONS" />
+    <uses-permission android:name="android.permission.FORCE_PERSISTABLE_URI_PERMISSIONS" />
     <uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
     <uses-permission android:name="android.permission.REMOVE_TASKS" />
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-permission android:name="android.permission.CACHE_CONTENT" />
     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
@@ -61,7 +81,7 @@
 
         <activity
             android:name=".inspector.InspectorActivity"
-            android:label="@string/menu_inspector"
+            android:label="@string/menu_inspect"
             android:icon="@drawable/launcher_icon"
             android:theme="@style/DocumentsTheme">
         </activity>
@@ -109,7 +129,7 @@
         </activity-alias>
 
         <activity
-            android:name=".OpenExternalDirectoryActivity"
+            android:name=".ScopedAccessActivity"
             android:theme="@android:style/Theme.Translucent.NoTitleBar">
             <intent-filter>
                 <action android:name="android.os.storage.action.OPEN_EXTERNAL_DIRECTORY" />
@@ -118,6 +138,13 @@
         </activity>
 
         <provider
+            android:name=".ScopedAccessProvider"
+            android:authorities="com.android.documentsui.scopedAccess"
+            android:permission="android.permission.MANAGE_SCOPED_ACCESS_DIRECTORY_PERMISSIONS"
+            android:exported="true">
+        </provider>
+
+        <provider
             android:name=".picker.LastAccessedProvider"
             android:authorities="com.android.documentsui.lastAccessed"
             android:exported="false"/>
@@ -155,5 +182,15 @@
             android:exported="false"
             android:process=":com.android.documentsui.services">
         </service>
+
+        <activity
+            android:name=".selection.demo.SelectionDemoActivity"
+            android:label="Selection Demo"
+            android:theme="@style/Theme.AppCompat.Light.NoActionBar">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+            </intent-filter>
+        </activity>
+
     </application>
 </manifest>
diff --git a/app-perf-tests/Android.mk b/app-perf-tests/Android.mk
index 2a59f64..f7d67fd 100644
--- a/app-perf-tests/Android.mk
+++ b/app-perf-tests/Android.mk
@@ -7,17 +7,18 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) \
 
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
 LOCAL_STATIC_ANDROID_LIBRARIES := android-support-v4
 LOCAL_STATIC_JAVA_LIBRARIES := \
     mockito-target \
-    ub-uiautomator \
-    legacy-android-test
+    ub-uiautomator
 
 LOCAL_USE_AAPT2 := true
 LOCAL_PACKAGE_NAME := DocumentsUIAppPerfTests
 LOCAL_INSTRUMENTATION_FOR := DocumentsUI
 
+LOCAL_COMPATIBILITY_SUITE += device-tests
+
 LOCAL_CERTIFICATE := platform
 
 include $(BUILD_PACKAGE)
diff --git a/app-perf-tests/AndroidTest.xml b/app-perf-tests/AndroidTest.xml
new file mode 100644
index 0000000..c8dd9a1
--- /dev/null
+++ b/app-perf-tests/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+<configuration description="Runs DocumentsUIAppPerfTests metric instrumentation.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-metric-instrumentation" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="DocumentsUIAppPerfTests.apk" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="runner" value="android.test.InstrumentationTestRunner" />
+        <option name="package" value="com.android.documentsui.appperftests" />
+    </test>
+</configuration>
diff --git a/build_apk.mk b/build_apk.mk
new file mode 100644
index 0000000..19d9c62
--- /dev/null
+++ b/build_apk.mk
@@ -0,0 +1,28 @@
+LOCAL_MODULE_TAGS := optional
+LOCAL_PRIVILEGED_MODULE := true
+
+LOCAL_STATIC_JAVA_LIBRARIES += guava
+
+LOCAL_STATIC_ANDROID_LIBRARIES := \
+        android-support-core-ui \
+        android-support-v4 \
+        android-support-v7-appcompat \
+        android-support-v13 \
+        $(ANDROID_SUPPORT_DESIGN_TARGETS) \
+        android-support-transition \
+        android-support-v7-recyclerview
+
+LOCAL_USE_AAPT2 := true
+
+LOCAL_JACK_FLAGS := \
+  -D jack.optimization.inner-class.accessors=true
+
+# Only enable asserts on userdebug/eng builds
+ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
+LOCAL_JACK_FLAGS += -D jack.assert.policy=always
+endif
+
+LOCAL_CERTIFICATE := platform
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+include $(BUILD_PACKAGE)
diff --git a/minimal/AndroidManifest.xml b/minimal/AndroidManifest.xml
new file mode 100644
index 0000000..33df1ba
--- /dev/null
+++ b/minimal/AndroidManifest.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2007-2017 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.documentsui">
+
+    <uses-permission android:name="android.permission.GET_APP_GRANTED_URI_PERMISSIONS" />
+    <uses-permission android:name="android.permission.FORCE_PERSISTABLE_URI_PERMISSIONS" />
+    <uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
+    <uses-permission android:name="android.permission.CACHE_CONTENT" />
+
+    <!-- This is a minimal version of the DocumentsUI app supporting ScopedDirectoryAccess
+         only. It is part of the Android TV build. -->
+    <application
+        android:label="@string/app_label"
+        android:icon="@drawable/app_icon"
+        android:supportsRtl="true"
+        android:allowBackup="false"
+        android:fullBackupOnly="false">
+
+        <activity
+            android:name=".ScopedAccessActivity"
+            android:theme="@android:style/Theme.Translucent.NoTitleBar">
+            <intent-filter>
+                <action android:name="android.os.storage.action.OPEN_EXTERNAL_DIRECTORY" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <receiver android:name=".ScopedAccessPackageReceiver">
+            <intent-filter>
+                <action android:name="android.intent.action.PACKAGE_FULLY_REMOVED" />
+                <action android:name="android.intent.action.PACKAGE_DATA_CLEARED" />
+                <data android:scheme="package" />
+            </intent-filter>
+        </receiver>
+
+        <provider
+            android:name=".ScopedAccessProvider"
+            android:authorities="com.android.documentsui.scopedAccess"
+            android:permission="android.permission.MANAGE_SCOPED_ACCESS_DIRECTORY_PERMISSIONS"
+            android:exported="true">
+        </provider>
+
+    </application>
+</manifest>
diff --git a/minimal/res/layout/dialog_open_scoped_directory.xml b/minimal/res/layout/dialog_open_scoped_directory.xml
new file mode 100644
index 0000000..cb39206
--- /dev/null
+++ b/minimal/res/layout/dialog_open_scoped_directory.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2017 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:theme="@style/Theme.AppCompat.Light.Dialog.Alert"
+    android:orientation="vertical"
+    android:paddingEnd="24dp"
+    android:paddingStart="24dp" >
+
+    <TextView
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/message"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:paddingEnd="24dp"
+        android:paddingStart="32dp"
+        android:paddingTop="24dp">
+    </TextView>
+
+    <CheckBox
+        android:id="@+id/do_not_ask_checkbox"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="16dip"
+        android:text="@string/never_ask_again"
+        android:textColor="?android:attr/textColorSecondary"
+        android:visibility="gone" />
+</LinearLayout>
diff --git a/minimal/res/mipmap-anydpi/ic_app_icon.xml b/minimal/res/mipmap-anydpi/ic_app_icon.xml
new file mode 100644
index 0000000..cd4fa58
--- /dev/null
+++ b/minimal/res/mipmap-anydpi/ic_app_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@color/app_icon_background"/>
+    <foreground android:drawable="@mipmap/ic_launcher_icon_foreground"/>
+</adaptive-icon>
diff --git a/minimal/res/mipmap-hdpi/ic_launcher_icon_foreground.png b/minimal/res/mipmap-hdpi/ic_launcher_icon_foreground.png
new file mode 100644
index 0000000..992c44e
--- /dev/null
+++ b/minimal/res/mipmap-hdpi/ic_launcher_icon_foreground.png
Binary files differ
diff --git a/minimal/res/mipmap-mdpi/ic_launcher_icon_foreground.png b/minimal/res/mipmap-mdpi/ic_launcher_icon_foreground.png
new file mode 100644
index 0000000..4639ff0
--- /dev/null
+++ b/minimal/res/mipmap-mdpi/ic_launcher_icon_foreground.png
Binary files differ
diff --git a/minimal/res/mipmap-xhdpi/ic_launcher_icon_foreground.png b/minimal/res/mipmap-xhdpi/ic_launcher_icon_foreground.png
new file mode 100644
index 0000000..b992944
--- /dev/null
+++ b/minimal/res/mipmap-xhdpi/ic_launcher_icon_foreground.png
Binary files differ
diff --git a/minimal/res/mipmap-xxhdpi/ic_launcher_icon_foreground.png b/minimal/res/mipmap-xxhdpi/ic_launcher_icon_foreground.png
new file mode 100644
index 0000000..ae44b2f
--- /dev/null
+++ b/minimal/res/mipmap-xxhdpi/ic_launcher_icon_foreground.png
Binary files differ
diff --git a/minimal/res/mipmap-xxxhdpi/ic_launcher_icon_foreground.png b/minimal/res/mipmap-xxxhdpi/ic_launcher_icon_foreground.png
new file mode 100644
index 0000000..85150eb
--- /dev/null
+++ b/minimal/res/mipmap-xxxhdpi/ic_launcher_icon_foreground.png
Binary files differ
diff --git a/minimal/res/values/colors.xml b/minimal/res/values/colors.xml
new file mode 100644
index 0000000..61a8150
--- /dev/null
+++ b/minimal/res/values/colors.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<resources>
+    <color name="app_icon_background">#ff4688f2</color>
+</resources>
diff --git a/minimal/res/values/drawables.xml b/minimal/res/values/drawables.xml
new file mode 100644
index 0000000..2e5e77d
--- /dev/null
+++ b/minimal/res/values/drawables.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<resources>
+    <item name="app_icon" type="drawable">@mipmap/ic_app_icon</item>
+    <item name="launcher_icon" type="drawable">@mipmap/ic_app_icon</item>
+</resources>
diff --git a/minimal/res/values/strings.xml b/minimal/res/values/strings.xml
new file mode 100644
index 0000000..bcffd6b
--- /dev/null
+++ b/minimal/res/values/strings.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Title of the Files application [CHAR LIMIT=32] -->
+    <string name="files_label">Files</string>
+
+    <!-- Title of the documents application [CHAR LIMIT=32] -->
+    <string name="app_label">@string/files_label</string>
+
+    <!-- Title of the documents application [CHAR LIMIT=32] -->
+    <string name="launcher_label">@string/files_label</string>
+
+    <!-- Text in an alert dialog asking user to grant app access to a given directory in an external storage volume -->
+    <string name="open_external_dialog_request">Grant <xliff:g id="appName" example="System Settings"><b>^1</b></xliff:g>
+        access to <xliff:g id="directory" example="Pictures"><i>^2</i></xliff:g> directory on
+        <xliff:g id="storage" example="SD Card"><i>^3</i></xliff:g>?</string>
+    <!-- Text in an alert dialog asking user to grant app access to a given directory in the internal storage -->
+    <string name="open_external_dialog_request_primary_volume">Grant <xliff:g id="appName" example="System Settings"><b>^1</b></xliff:g>
+        access to <xliff:g id="directory" example="Pictures"><i>^2</i></xliff:g> directory?</string>
+    <!-- Text in an alert dialog asking user to grant app access to all data in an external storage volume -->
+    <string name="open_external_dialog_root_request">Grant <xliff:g id="appName" example="System Settings"><b>^1</b></xliff:g>
+        access to your data, including photos and videos, on <xliff:g id="storage" example="SD Card"><i>^2</i></xliff:g>?</string>
+    <!-- Checkbox that allows user to not be questioned about the directory access request again -->
+    <string name="never_ask_again">Don\'t ask again</string>
+    <!-- Text in the button asking user to allow access to a given directory. -->
+    <string name="allow">Allow</string>
+    <!-- Text in the button asking user to deny access to a given directory. -->
+    <string name="deny">Deny</string>
+
+    <!-- Error message shown when an archive fails to load -->
+    <string name="archive_loading_failed">Unable to open archive for browsing. File is either corrupt, or an unsupported format.</string>
+
+</resources>
diff --git a/perf-tests/Android.mk b/perf-tests/Android.mk
index 54131ef..731a8fa 100644
--- a/perf-tests/Android.mk
+++ b/perf-tests/Android.mk
@@ -8,14 +8,13 @@
     $(call all-java-files-under, ../tests/common/com/android/documentsui) \
     ../tests/functional/com/android/documentsui/ActivityTest.java
 
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base android.test.mock
 LOCAL_STATIC_ANDROID_LIBRARIES := android-support-v4
 LOCAL_STATIC_JAVA_LIBRARIES := \
     mockito-target \
     ub-uiautomator \
     ub-janktesthelper \
-    espresso-core \
-    legacy-android-test
+    espresso-core
 
 LOCAL_USE_AAPT2 := true
 LOCAL_PACKAGE_NAME := DocumentsUIPerfTests
diff --git a/res/color/selection_demo_item_selector.xml b/res/color/selection_demo_item_selector.xml
new file mode 100644
index 0000000..bd87b4c
--- /dev/null
+++ b/res/color/selection_demo_item_selector.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:state_activated="true"
+        android:color="?android:attr/colorForeground"
+        />
+    <item
+        android:state_activated="false"
+        android:color="?android:attr/colorForeground"
+        android:alpha=".3"
+        />
+</selector>
diff --git a/res/drawable-hdpi/ic_menu_share_alpha.png b/res/drawable-hdpi/ic_menu_share_am_alpha.png
similarity index 100%
rename from res/drawable-hdpi/ic_menu_share_alpha.png
rename to res/drawable-hdpi/ic_menu_share_am_alpha.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_share_alpha.png b/res/drawable-mdpi/ic_menu_share_am_alpha.png
similarity index 100%
rename from res/drawable-mdpi/ic_menu_share_alpha.png
rename to res/drawable-mdpi/ic_menu_share_am_alpha.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_share_alpha.png b/res/drawable-xhdpi/ic_menu_share_am_alpha.png
similarity index 100%
rename from res/drawable-xhdpi/ic_menu_share_alpha.png
rename to res/drawable-xhdpi/ic_menu_share_am_alpha.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_share_alpha.png b/res/drawable-xxhdpi/ic_menu_share_am_alpha.png
similarity index 100%
rename from res/drawable-xxhdpi/ic_menu_share_alpha.png
rename to res/drawable-xxhdpi/ic_menu_share_am_alpha.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_menu_share_alpha.png b/res/drawable-xxxhdpi/ic_menu_share_am_alpha.png
similarity index 100%
rename from res/drawable-xxxhdpi/ic_menu_share_alpha.png
rename to res/drawable-xxxhdpi/ic_menu_share_am_alpha.png
Binary files differ
diff --git a/res/drawable/cabinet.xml b/res/drawable/cabinet.xml
deleted file mode 100644
index 843ffc7..0000000
--- a/res/drawable/cabinet.xml
+++ /dev/null
@@ -1,81 +0,0 @@
-<!--
-Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="672dp"
-        android:height="921dp"
-        android:viewportWidth="672.0"
-        android:viewportHeight="921.0">
-    <path
-        android:pathData="M286,0c5,0,10,0,15,0c0.1,1.8,1.5,1.8,2.8,2.1c11.1,2,22.1,4,33.2,6.1c31.8,6.1,63.7,12.3,95.5,18.5  c16.1,3.1,32.1,6.2,48.2,9.3c26,4.9,52.1,9.3,78,14.6c10.8,2.2,21.6,4.6,32.3,6.5c11.3,2,22.6,4.7,34,6c7.9,0.9,7.9,1.1,7.9,9.2  c0,237.3,0,474.5,0,711.8c-1.5,0.9,-3,2,-4.6,2.8c-18.3,8.3,-36.6,16.6,-54.8,25c-29.3,13.4,-58.5,26.8,-87.8,40.3  c-23.5,10.9,-47,21.8,-70.4,32.8c-2.1,1,-4.2,1.5,-6.3,1.1c-6.8,-1.3,-13.6,-2.5,-20.1,-4.9c5.9,-0.3,11.4,1.9,17.1,2.9c5.9,1.1,5.9,1,5.9,-4.9  c0,-17.1,0.1,-34.3,0,-51.4c-0.3,-68.9,-0.7,-137.8,-1,-206.7c0,-35.8,0,-71.6,0.1,-107.4c0,-3.8,-0.6,-5.2,-4.7,-3.7c-7.9,2.9,-16,5.4,-24.1,7.8  c-14.1,4.3,-27.8,10,-42.2,13.2c0,-64,0,-127.9,-0.1,-191.9c0,-4.1,1.3,-5.9,5.1,-7c21,-6.6,42,-13.4,63,-20.2c2.3,-0.8,4.4,-1.8,4,-4.9  c0,-59.3,0,-118.7,0,-178c0,-1.3,-0.7,-2,-2,-2c-2.6,-0.4,-5.2,-0.7,-7.8,-1.2c-30.2,-5.3,-60.5,-10.6,-90.7,-16c-31.9,-5.6,-63.7,-11.3,-95.6,-16.9  c-24.9,-4.4,-49.8,-8.7,-74.6,-13.1C117.1,75.6,93.1,71.3,69,67c-0.3,-0.3,-0.7,-0.7,-1,-1c17.4,-5.3,34.8,-10.7,52.3,-15.9  c29.4,-8.7,58.8,-17.2,88.2,-25.8c24.3,-7.1,48.6,-14.2,72.9,-21.4C283.1,2.4,285.6,2.7,286,0z"
-        android:fillColor="#EFEFEE"/>
-    <path
-        android:pathData="M412,307c0.4,3,-1.7,4.1,-4,4.9c-21,6.8,-42,13.6,-63,20.2c-3.8,1.2,-5.1,3,-5.1,7C340,403.1,340,467,340,531  c-11.8,-1.2,-23.3,-4.5,-34.9,-6.5c-10,-1.7,-19.9,-4.6,-30.1,-5.5c-0.7,-0.3,-1.4,-0.9,-2.2,-1c-19.8,-4,-39.5,-8,-59.3,-12c-12.2,-2.4,-24.3,-4.7,-36.5,-7  c-0.9,-0.3,-1.8,-0.8,-2.8,-1c-24.5,-4.9,-48.9,-9.9,-73.5,-14.6C89.3,481.3,78,477.1,66,478c-0.7,-1.6,-2.1,-1.8,-3.6,-2.1  c-11.1,-2.2,-22.2,-4.7,-33.3,-6.7c-9.7,-1.7,-19.1,-4.9,-29.1,-5.3c0,-64.3,0,-128.7,0,-193c0.8,-0.2,1.6,-0.4,2.4,-0.7c19,-7.8,37.9,-15.9,57.1,-23.4  c5.4,-2.1,6.7,-4.8,6.6,-10.2c-0.2,-55.1,-0.1,-110.2,-0.1,-165.4c0,-1.9,-1.4,-4.6,1.9,-5.4c0.3,0.3,0.7,0.7,1,1c-1.3,4.9,-1,9.9,-1,14.9  c0,51.1,0,102.3,0,153.4c0,1.2,0,2.3,0,3.5c0.1,3.5,1.2,5.9,5.3,6.5c7,1.1,14,2.6,21,3.9c22.1,4.3,44.1,8.6,66.2,12.8  c27.3,5.2,54.6,10.1,81.9,15.3c21.8,4.1,43.5,8.5,65.2,12.6c28.1,5.4,56.2,10.8,84.3,15.8C398.4,306.8,405.1,310.5,412,307z   M105,329c0,3.3,0,6.7,-0.1,10c-0.1,2.5,0.4,3.6,3.4,4.2c30,5.3,59.9,10.9,89.8,16.5c3.4,0.6,5.1,0.2,4.9,-3.7  c-0.2,-3.3,-0.1,-6.7,-0.1,-10c0.5,-3.6,-0.1,-6.3,-4.7,-6.1c-1.1,0.1,-2.2,-0.6,-3.4,-0.8c-28.3,-5,-56.6,-9.9,-84.9,-14.9  C105.6,323.4,104.5,325.2,105,329z M65.9,280.8c13.7,2.5,27.4,4.9,41.1,7.4c32.6,5.9,65.2,11.8,97.8,17.8  c41.4,7.6,82.8,15.2,124.2,22.8c6.8,1.2,13.3,1.4,20,-1.3c9.3,-3.6,18.9,-6.3,28.4,-9.4c6.4,-2.1,12.8,-4.2,19.2,-6.4  c-4.2,-2,-8.3,-3,-12.4,-3.8c-22.6,-4.2,-45.3,-8,-67.9,-12.6c-14.6,-3,-29.2,-5.6,-43.8,-8.5c-24,-4.6,-48,-9.2,-72,-13.7c-15.9,-3,-31.8,-6.2,-47.8,-9.2  c-19,-3.6,-38,-7.3,-57,-10.6c-9.9,-1.7,-19.6,-4.5,-29.7,-5.2C48,255.6,30.1,263,12.2,270.4c0,0.4,0,0.7,0,1.1  C30.1,274.6,48,277.7,65.9,280.8z"
-        android:fillColor="#EAEAEA"/>
-    <path
-        android:pathData="M672,782c-6,0.9,-11.1,4.3,-16.4,6.9c-30.8,15,-61.5,30.3,-92.3,45.4c-34.8,17.1,-69.5,34.3,-104.5,51.1  c-13,6.3,-26,12.8,-39,19.1c-1.5,0.7,-3.7,1,-3.9,3.4c-3.7,0,-7.3,0,-11,0c-0.4,-3,-3.1,-2.3,-4.7,-2.7c-19.3,-4.8,-38.6,-9.5,-57.9,-14.1  c-27.5,-6.5,-55.2,-12.7,-82.6,-19.4c-30.9,-7.5,-61.8,-15,-92.7,-22.1c-24.8,-5.8,-49.5,-12,-74.3,-18C70.8,826.5,48.9,821.3,27,816  c-1.1,-0.3,-2.3,-0.5,-3.3,-1c-3.2,-1.3,-3.5,-3.3,-0.7,-5.4c0.9,-0.7,2,-1.2,3.1,-1.7c12,-5.3,24,-10.7,36,-16c0.4,-0.2,0.9,-0.2,1.9,-0.3  c0,3.6,0,7,0,10.5c0,1.6,-0.5,3.5,2,3.9c0.7,2.8,3.2,2.5,5.2,3c39.3,9,78.7,18.1,118.1,27c43.9,10,87.7,20,131.6,29.9  c9.7,2.2,19.2,4.9,29.1,6c1.1,1.5,2.6,0.9,4,1l0,0c4.1,2,8.5,2.6,13,3l0,0c7.2,2.4,14.4,4.3,22,5l0,0c6.5,2.5,13.3,3.6,20.1,4.9  c2.1,0.4,4.2,-0.1,6.3,-1.1c23.5,-11,46.9,-21.9,70.4,-32.8c29.2,-13.5,58.5,-26.9,87.8,-40.3c18.3,-8.4,36.6,-16.6,54.8,-25  c1.6,-0.7,3.1,-1.9,4.6,-2.8c2,-2.9,1.1,-6.2,0.9,-9.2c-0.3,-4.7,1.9,-5.5,5.7,-4.7c10.8,2.2,21.6,4.6,32.5,6.9C672,778.7,672,780.3,672,782z  "
-        android:fillColor="#E6E4E4"/>
-    <path
-        android:pathData="M350,872c-9.9,-1.1,-19.4,-3.9,-29.1,-6C277,856,233.1,846,189.2,836c-39.4,-9,-78.7,-18,-118.1,-27  c-2,-0.4,-4.5,-0.2,-5.2,-3c0,-85.7,0,-171.4,0.1,-257.1c6.5,0.1,12.7,2.3,19,3.6c26.4,5.4,52.8,10.9,79.2,16.5c25.9,5.4,51.8,11,77.7,16.4  c26.2,5.5,52.5,11,78.7,16.5c30.1,6.3,60.2,12.6,90.3,19c0.3,68.9,0.7,137.8,1,206.7c0.1,17.1,0,34.3,0,51.4c0,5.9,0,6,-5.9,4.9  c-5.7,-1.1,-11.2,-3.2,-17.1,-2.9c0,0,0,0,0,0c-7,-3.1,-14.2,-5.4,-22,-5c0,0,0,0,0,0c-3.9,-2.9,-8.4,-2.9,-13,-3c0,0,0,0,0,0  C352.9,871.5,351.4,872.1,350,872z M177,687c0,3.2,0.1,6.3,0,9.5c-0.1,2.7,0.7,4,3.8,4.6c29.7,5.8,59.3,11.7,89,17.7  c2.4,0.5,4.7,0.1,4.9,-2.6c0.4,-3.7,1.2,-7.6,-0.6,-11.2c1,-3,1.2,-5.3,-3,-6c-29.6,-5.4,-59.2,-10.8,-88.7,-16.5C177.7,681.6,176.5,682.8,177,687  z"
-        android:fillColor="#E5E5E5"/>
-    <path
-        android:pathData="M411,621c-30.1,-6.3,-60.2,-12.6,-90.3,-19c-26.2,-5.5,-52.5,-11,-78.7,-16.5c-25.9,-5.5,-51.8,-11,-77.7,-16.4  c-26.4,-5.5,-52.8,-11.1,-79.2,-16.5c-6.3,-1.3,-12.5,-3.5,-19,-3.6c0,-23.6,0,-47.3,0,-70.9c12,-0.9,23.2,3.3,34.7,5.5c24.5,4.6,49,9.7,73.5,14.6  c1,0.2,1.9,0.6,2.8,1c0,3.3,0.7,6.7,0.7,9.9c0,5.6,2.4,7.5,7.5,8.4c15.3,2.7,30.5,5.8,45.8,8.7c12,2.3,24,4.4,36.1,6.6  c1.9,0.3,4.8,1.5,4.7,-1.4c-0.2,-4.6,1.7,-8.2,3.3,-12.1c10.2,0.9,20,3.8,30.1,5.5c11.7,2,23.1,5.3,34.9,6.5  c14.5,-3.2,28.1,-8.9,42.2,-13.2c8.1,-2.5,16.2,-5,24.1,-7.8c4.1,-1.5,4.8,-0.1,4.7,3.7C411,549.4,411,585.2,411,621z"
-        android:fillColor="#D9D9D9"/>
-    <path
-        android:pathData="M412,307c-6.9,3.5,-13.6,-0.2,-20.1,-1.3c-28.2,-5,-56.2,-10.4,-84.3,-15.8c-21.8,-4.1,-43.5,-8.5,-65.2,-12.6  c-27.3,-5.2,-54.6,-10.1,-81.9,-15.3c-22.1,-4.2,-44.1,-8.5,-66.2,-12.8c-7,-1.3,-13.9,-2.9,-21,-3.9c-4.1,-0.6,-5.2,-3,-5.3,-6.5c0,-1.2,0,-2.3,0,-3.5  c0,-51.1,0,-102.3,0,-153.4c0,-5,-0.3,-10,1,-14.9c24.1,4.3,48.1,8.6,72.2,12.8c24.9,4.4,49.8,8.7,74.6,13.1c31.9,5.6,63.7,11.3,95.6,16.9  c30.2,5.3,60.5,10.6,90.7,16c2.6,0.5,5.2,0.8,7.8,1.2c0,1.3,0.7,2,2,2C412,188.3,412,247.7,412,307z M409,217.4c0,-25.5,0,-51,0,-76.5  c0,-10.9,0.1,-11.2,-10.7,-13.2c-23.4,-4.4,-46.8,-8.5,-70.3,-12.6c-24.1,-4.3,-48.2,-8.4,-72.3,-12.6c-17.7,-3.1,-35.5,-6.3,-53.2,-9.4  c-22.1,-3.9,-44.3,-7.6,-66.4,-11.5c-20,-3.5,-40,-7.1,-60.1,-10.5c-6,-1,-6.1,-0.8,-6.1,5.6c0,53,0,105.9,0,158.9c0,1,0,2,0,3  c0.2,2.6,1,4.1,4,4.6c10.1,1.7,20.1,3.9,30.2,5.8c27.3,5.1,54.6,10.1,81.9,15.2c22.1,4.2,44.1,8.6,66.2,12.8  c27.3,5.2,54.6,10.2,81.9,15.3c22.7,4.3,45.5,8.6,68.2,12.8c6.5,1.2,6.5,1.1,6.5,-5.7C409,272,409,244.7,409,217.4z"
-        android:fillColor="#E8E8E8"/>
-    <path
-        android:pathData="M412,129c-1.3,0,-2,-0.7,-2,-2C411.3,127,412,127.7,412,129z"
-        android:fillColor="#EAEAEA"/>
-    <path
-        android:pathData="M65.8,248.3c10.1,0.7,19.8,3.5,29.7,5.2c19,3.3,38,7,57,10.6c15.9,3,31.8,6.2,47.8,9.2  c24,4.6,48,9.1,72,13.7c14.6,2.8,29.3,5.5,43.8,8.5c22.5,4.6,45.3,8.4,67.9,12.6c4.1,0.8,8.2,1.8,12.4,3.8  c-6.4,2.1,-12.8,4.3,-19.2,6.4c-9.5,3.1,-19.1,5.8,-28.4,9.4c-6.7,2.6,-13.3,2.5,-20,1.3c-41.4,-7.6,-82.8,-15.2,-124.2,-22.8  c-32.6,-6,-65.2,-11.9,-97.8,-17.8c-13.7,-2.5,-27.4,-4.9,-41.1,-7.4C65.9,270,65.9,259.1,65.8,248.3z"
-        android:fillColor="#E6A3A3"/>
-    <path
-        android:pathData="M275,519c-1.5,3.9,-3.5,7.5,-3.3,12.1c0.1,2.9,-2.8,1.7,-4.7,1.4c-12,-2.2,-24.1,-4.3,-36.1,-6.6  c-15.3,-2.9,-30.5,-6,-45.8,-8.7c-5.1,-0.9,-7.5,-2.8,-7.5,-8.4c0,-3.2,-0.8,-6.5,-0.7,-9.9c12.2,2.3,24.4,4.6,36.5,7c19.8,3.9,39.5,8,59.3,12  C273.6,518.2,274.3,518.7,275,519z"
-        android:fillColor="#CBCBCA"/>
-    <path
-        android:pathData="M202.9,345.9c0,3.3,-0.1,6.7,0.1,10c0.2,3.9,-1.4,4.3,-4.9,3.7c-29.9,-5.6,-59.8,-11.2,-89.8,-16.5  c-3,-0.5,-3.5,-1.7,-3.4,-4.2c0.1,-3.3,0.1,-6.7,0.1,-10c21.7,3.9,43.4,7.9,65.2,11.6C181.1,342.4,191.8,345.3,202.9,345.9z"
-        android:fillColor="#CFCFCE"/>
-    <path
-        android:pathData="M65.8,248.3c0,10.9,0,21.7,0,32.6c-17.9,-3.1,-35.8,-6.2,-53.7,-9.3c0,-0.4,0,-0.7,0,-1.1  C30.1,263,48,255.6,65.8,248.3z"
-        android:fillColor="#E57474"/>
-    <path
-        android:pathData="M202.9,345.9c-11.1,-0.6,-21.8,-3.5,-32.6,-5.4c-21.8,-3.7,-43.5,-7.7,-65.2,-11.6c-0.6,-3.8,0.6,-5.6,4.8,-4.8  c28.3,5,56.6,9.9,84.9,14.9c1.1,0.2,2.3,0.8,3.4,0.8C202.8,339.6,203.4,342.3,202.9,345.9z"
-        android:fillColor="#BDBDBD"/>
-    <path
-        android:pathData="M367,876c7.8,-0.4,15,1.9,22,5C381.4,880.3,374.2,878.4,367,876z"
-        android:fillColor="#EFEFEE"/>
-    <path
-        android:pathData="M354,873c4.5,0.1,9.1,0.1,13,3C362.5,875.6,358.1,875,354,873z"
-        android:fillColor="#EFEFEE"/>
-    <path
-        android:pathData="M350,872c1.4,0.1,3,-0.5,4,1C352.6,872.9,351,873.5,350,872z"
-        android:fillColor="#EFEFEE"/>
-    <path
-        android:pathData="M274.1,705c1.9,3.6,1,7.5,0.6,11.2c-0.3,2.8,-2.5,3.1,-4.9,2.6c-29.7,-5.9,-59.3,-11.9,-89,-17.7  c-3.1,-0.6,-3.9,-1.9,-3.8,-4.6c0.1,-3.2,0,-6.3,0,-9.5c1.2,0,2.4,-0.1,3.5,0.1c19.2,3.8,38.4,7.7,57.6,11.4  C250.1,700.8,261.9,703.8,274.1,705z"
-        android:fillColor="#D6D6D5"/>
-    <path
-        android:pathData="M274.1,705c-12.1,-1.2,-24,-4.2,-35.9,-6.5c-19.2,-3.7,-38.4,-7.6,-57.6,-11.4c-1.1,-0.2,-2.3,-0.1,-3.5,-0.1  c-0.5,-4.2,0.7,-5.4,5.3,-4.5c29.5,5.7,59.1,11.1,88.7,16.5C275.3,699.7,275.1,702,274.1,705z"
-        android:fillColor="#C9C9C8"/>
-    <path
-        android:pathData="M409,217.4c0,27.3,0,54.6,0,82c0,6.8,0,6.9,-6.5,5.7c-22.7,-4.2,-45.5,-8.6,-68.2,-12.8  c-27.3,-5.1,-54.6,-10.1,-81.9,-15.3c-22.1,-4.2,-44.1,-8.6,-66.2,-12.8c-27.3,-5.2,-54.6,-10.1,-81.9,-15.2c-10.1,-1.9,-20.1,-4.1,-30.2,-5.8  c-3,-0.5,-3.9,-2.1,-4,-4.6c-0.1,-1,0,-2,0,-3c0,-53,0,-105.9,0,-158.9c0,-6.4,0,-6.6,6.1,-5.6c20,3.4,40,7,60.1,10.5c22.1,3.9,44.3,7.6,66.4,11.5  c17.7,3.1,35.5,6.3,53.2,9.4c24.1,4.2,48.2,8.4,72.3,12.6c23.4,4.1,46.9,8.2,70.3,12.6c10.8,2,10.7,2.3,10.7,13.2  C409,166.4,409,191.9,409,217.4z M283.9,146.9c0.4,-3.2,-0.2,-5.3,-4,-6c-29.7,-5,-59.4,-9.9,-89,-15.3c-4.8,-0.9,-5.2,0.7,-4.8,4.4  c0,3.5,-0.1,7,0,10.5c0,1.3,-0.4,3.2,1.4,3.3c2.9,0.1,5.3,1.8,8.1,2.3c13.8,2.4,27.6,4.9,41.4,7.4c13.3,2.4,26.5,5.1,39.8,7.4  c6.6,1.2,7.3,0.4,7.3,-6.5C284,151.9,283.9,149.4,283.9,146.9z"
-        android:fillColor="#E8E7E7"/>
-    <path
-        android:pathData="M283.9,146.9c0,2.5,0.1,5,0.1,7.5c0,6.9,-0.7,7.7,-7.3,6.5c-13.3,-2.4,-26.5,-5,-39.8,-7.4  c-13.8,-2.5,-27.6,-5.1,-41.4,-7.4c-2.8,-0.5,-5.2,-2.2,-8.1,-2.3c-1.8,-0.1,-1.4,-2,-1.4,-3.3c0,-3.5,0,-7,0,-10.5c1.9,0.3,3.9,0.7,5.8,1  c21.6,4,43.1,8.1,64.7,11.8C265.6,144.4,274.5,147.1,283.9,146.9z"
-        android:fillColor="#CFCFCE"/>
-    <path
-        android:pathData="M283.9,146.9c-9.3,0.2,-18.3,-2.5,-27.3,-4.1c-21.6,-3.7,-43.1,-7.8,-64.7,-11.8c-1.9,-0.4,-3.9,-0.7,-5.8,-1  c-0.4,-3.6,-0.1,-5.2,4.8,-4.4c29.6,5.4,59.3,10.4,89,15.3C283.7,141.6,284.3,143.7,283.9,146.9z"
-        android:fillColor="#BDBDBD"/>
-</vector>
diff --git a/res/drawable/empty.xml b/res/drawable/empty.xml
new file mode 100644
index 0000000..73d4ffd
--- /dev/null
+++ b/res/drawable/empty.xml
@@ -0,0 +1,51 @@
+<!--
+Copyright (C) 2018 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="210dp"
+        android:height="210dp"
+        android:viewportWidth="210"
+        android:viewportHeight="210">
+
+    <path
+        android:fillColor="#DADCE0"
+        android:pathData="M115,109.44H95c-1.1,0-2-0.9-2-2s0.9-2,2-2h20c1.1,0,2,0.9,2,2S116.1,109.44,115,109.44z" />
+    <path
+        android:fillColor="#DADCE0"
+        android:pathData="M62.67,85.14l3-0.11L62.67,85.14c-0.04-0.74-0.06-1.48-0.06-2.22c0-0.69,0.02-1.37,0.05-2.05l5.99,0.29 c-0.03,0.58-0.04,1.17-0.04,1.76c0,0.64,0.02,1.28,0.05,1.92l-2.99,0.2L62.67,85.14z" />
+    <path
+        android:fillColor="#DADCE0"
+        android:pathData="M147.35,84.94l-5.99-0.28c0.03-0.56,0.04-1.12,0.04-1.69c0-0.64-0.02-1.28-0.05-1.92l-0.01-0.13l5.99-0.3 l0,0.08c0.04,0.77,0.06,1.52,0.06,2.26C147.39,83.64,147.38,84.29,147.35,84.94z" />
+    <path
+        android:fillColor="#EA4335"
+        android:pathData="M72.56,66.45l-5.35-2.72c0.65-1.28,1.38-2.54,2.16-3.75l5.04,3.25C73.74,64.27,73.12,65.35,72.56,66.45z" />
+    <path
+        android:fillColor="#EA4335"
+        android:pathData="M137.35,66.27c-0.56-1.09-1.19-2.17-1.87-3.21l5.02-3.28c0.79,1.21,1.52,2.46,2.18,3.74L137.35,66.27z" />
+    <path
+        android:fillColor="#DADCE0"
+        android:pathData="M85.15,52.44l-3.28-5.03c1.2-0.79,2.46-1.52,3.74-2.18l2.75,5.33C87.26,51.14,86.18,51.77,85.15,52.44z" />
+    <path
+        android:fillColor="#DADCE0"
+        android:pathData="M124.69,52.34c-1.04-0.67-2.12-1.29-3.22-1.85l2.72-5.35c1.28,0.65,2.54,1.38,3.75,2.15L124.69,52.34z" />
+    <path
+        android:fillColor="#EA4335"
+        android:pathData="M103.12,46.61l-0.4-5.99l0.08,0c1.45-0.07,2.85-0.08,4.25-0.01l-0.28,5.99 C105.56,46.54,104.34,46.54,103.12,46.61z" />
+    <path
+        android:fillColor="#DADCE0"
+        android:pathData="M154,95.44v70H56v-70H154 M154,91.44H56c-2.21,0-4,1.79-4,4v70c0,2.21,1.79,4,4,4h98c2.21,0,4-1.79,4-4 v-70C158,93.24,156.21,91.44,154,91.44L154,91.44z" />
+    <path
+        android:pathData="M 0 0 H 210 V 210 H 0 V 0 Z" />
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_menu_share.xml b/res/drawable/ic_menu_share.xml
index 927e7d3..d4a92c5 100644
--- a/res/drawable/ic_menu_share.xml
+++ b/res/drawable/ic_menu_share.xml
@@ -1,4 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_menu_share_alpha"
-    android:tint="?android:attr/colorControlNormal" />
+    android:src="@drawable/ic_menu_share_am_alpha"
+    android:tint="?android:attr/colorControlNormal"
+    android:autoMirrored="true" />
diff --git a/res/drawable/inspector_separator.xml b/res/drawable/inspector_separator.xml
new file mode 100644
index 0000000..6a35283
--- /dev/null
+++ b/res/drawable/inspector_separator.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:insetTop="10dp"
+    android:insetBottom="10dp" >
+    <shape xmlns:android="http://schemas.android.com/apk/res/android">
+        <size android:height="1dp"/>
+        <solid android:color="@color/inspector_section_divider"/>
+    </shape>
+</inset>
\ No newline at end of file
diff --git a/res/drawable/selection_demo_band_overlay.xml b/res/drawable/selection_demo_band_overlay.xml
new file mode 100644
index 0000000..adf2b27
--- /dev/null
+++ b/res/drawable/selection_demo_band_overlay.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+        android:shape="rectangle">
+    <solid android:color="#339999ff" />
+    <stroke android:width="1dp" android:color="#44000000" />
+</shape>
diff --git a/res/drawable/selection_demo_item_background.xml b/res/drawable/selection_demo_item_background.xml
new file mode 100644
index 0000000..de5c142
--- /dev/null
+++ b/res/drawable/selection_demo_item_background.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_activated="true">
+        <color android:color="?android:attr/colorControlHighlight"></color>
+    </item>
+</selector>
diff --git a/res/layout/dropdown_sort_widget.xml b/res/layout/dropdown_sort_widget.xml
index 4744c49..395f52b 100644
--- a/res/layout/dropdown_sort_widget.xml
+++ b/res/layout/dropdown_sort_widget.xml
@@ -36,7 +36,7 @@
         android:paddingEnd="12dp"
         android:gravity="center"
         android:fontFamily="sans-serif-medium"
-        android:textSize="14sp"
+        android:textSize="@dimen/dropdown_sort_text_size"
         android:textColor="@color/sort_widget_text_color"/>
 
     <ImageView
diff --git a/res/layout/inspector_action_view.xml b/res/layout/inspector_action_view.xml
index 91418ae..4226383 100644
--- a/res/layout/inspector_action_view.xml
+++ b/res/layout/inspector_action_view.xml
@@ -23,8 +23,8 @@
 
     <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
         android:id="@+id/default_app_info"
-	    android:paddingLeft="16dp"
-	    android:paddingRight="16dp"
+        android:paddingLeft="16dp"
+        android:paddingRight="16dp"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:paddingBottom="10dp"
@@ -33,12 +33,13 @@
         <ImageView
             android:id="@+id/app_icon"
             android:paddingLeft="5dp"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content" />
+            android:layout_width="50dp"
+            android:layout_height="50dp" />
 
         <TextView
             android:id="@+id/app_name"
             android:paddingLeft="16dp"
+            android:paddingBottom="10dp"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_toRightOf="@id/app_icon"
@@ -46,8 +47,8 @@
 
         <ImageButton
             android:id="@+id/inspector_action_button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
+            android:layout_width="50dp"
+            android:layout_height="50dp"
             android:layout_alignParentRight="true"
             android:layout_centerVertical="true"
             android:background="@null"/>
diff --git a/res/layout/document_inspector_activity.xml b/res/layout/inspector_activity.xml
similarity index 96%
rename from res/layout/document_inspector_activity.xml
rename to res/layout/inspector_activity.xml
index 65361de..f48bc92 100644
--- a/res/layout/document_inspector_activity.xml
+++ b/res/layout/inspector_activity.xml
@@ -21,7 +21,7 @@
 
     <Toolbar
         android:id="@+id/toolbar"
-        android:title="Properties"
+        android:title="@string/inspector_title"
         android:layout_width="match_parent"
         android:layout_height="?android:attr/actionBarSize"
         android:background="?android:attr/colorPrimary"
diff --git a/res/layout/document_inspector_fragment.xml b/res/layout/inspector_fragment.xml
similarity index 89%
rename from res/layout/document_inspector_fragment.xml
rename to res/layout/inspector_fragment.xml
index 5edb5e0..24f0fdb 100644
--- a/res/layout/document_inspector_fragment.xml
+++ b/res/layout/inspector_fragment.xml
@@ -37,8 +37,13 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"/>
 
+        <com.android.documentsui.inspector.MediaView
+            android:id="@+id/inspector_media_view"
+            android:orientation="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"/>
+
         <com.android.documentsui.inspector.actions.ActionView
-            android:paddingTop="10dp"
             android:id="@+id/inspector_show_in_provider_view"
             android:orientation="vertical"
             android:layout_width="match_parent"
@@ -46,7 +51,6 @@
             android:visibility="gone"/>
 
         <com.android.documentsui.inspector.actions.ActionView
-            android:paddingTop="10dp"
             android:id="@+id/inspector_app_defaults_view"
             android:orientation="vertical"
             android:layout_width="match_parent"
@@ -58,6 +62,8 @@
             android:orientation="vertical"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
+            android:paddingTop="20dp"
             android:visibility="gone" />
+
     </LinearLayout>
 </ScrollView>
diff --git a/res/layout/inspector_header.xml b/res/layout/inspector_header.xml
index e293c12..d621801 100644
--- a/res/layout/inspector_header.xml
+++ b/res/layout/inspector_header.xml
@@ -23,15 +23,22 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:alpha="0.0"
-        android:background="@android:color/black" />
+        android:background="@android:color/white" />
 
     <TextView
         android:id="@+id/inspector_file_title"
-        android:layout_width="wrap_content"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:textSize="20dp"
-        android:layout_alignBottom="@+id/inspector_thumbnail"
-        android:paddingBottom="20dp"
-        android:paddingLeft="18dp"
-        android:textColor="@android:color/white" />
-</RelativeLayout>
\ No newline at end of file
+        android:textSize="20sp"
+        android:paddingTop="5dp"
+        android:paddingBottom="5dp"
+        android:paddingStart="16dp"
+        android:paddingEnd="16dp"
+        android:textColor="@android:color/white"
+        android:layout_gravity="center_vertical"
+        android:background="@color/inspector_title_background"
+        android:textIsSelectable="true"
+        android:textAlignment="viewStart"
+        android:layout_alignBottom="@+id/inspector_thumbnail" />
+
+</RelativeLayout>
diff --git a/res/layout/inspector_section_title.xml b/res/layout/inspector_section_title.xml
index 2804811..33889a8 100644
--- a/res/layout/inspector_section_title.xml
+++ b/res/layout/inspector_section_title.xml
@@ -14,16 +14,26 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<TextView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_height="match_parent"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="wrap_content"
     android:layout_width="match_parent"
-    android:paddingTop="10dp"
-    android:paddingBottom="10dp"
-    android:paddingLeft="16dp"
-    android:layout_gravity="center_vertical"
-    android:fontFamily="sans-serif-medium"
-    android:textSize="14sp"
-    android:textColor="@color/inspector_section_title">
+    android:orientation="vertical"
+    android:divider="@drawable/inspector_separator"
+    android:showDividers="beginning"
+    android:paddingStart="10dp"
+    android:paddingEnd="10dp">
 
-</TextView>
+    <TextView
+        android:layout_height="match_parent"
+        android:layout_width="match_parent"
+        android:id="@+id/inspector_header_title"
+        android:paddingStart="6dp"
+        android:paddingEnd="6dp"
+        android:paddingTop="5dp"
+        android:paddingBottom="5dp"
+        android:layout_gravity="center_vertical"
+        android:fontFamily="sans-serif-medium"
+        android:textSize="15sp"
+        android:textAlignment="viewStart"
+        android:textColor="@color/inspector_section_title"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/selection_demo_layout.xml b/res/layout/selection_demo_layout.xml
new file mode 100644
index 0000000..c4ed360
--- /dev/null
+++ b/res/layout/selection_demo_layout.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+       android:layout_width="match_parent"
+       android:layout_height="match_parent"
+       android:orientation="vertical">
+
+  <android.support.v7.widget.Toolbar
+     android:id="@+id/toolbar"
+     android:layout_width="match_parent"
+     android:layout_height="?attr/actionBarSize"
+     android:background="?attr/colorPrimary"
+     android:elevation="4dp"
+     android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
+     />
+
+  <android.support.v7.widget.RecyclerView
+      android:id="@+id/list"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+      android:paddingStart="0dp"
+      android:paddingEnd="0dp"
+      android:paddingTop="5dp"
+      android:paddingBottom="5dp"
+      android:clipToPadding="false"
+      android:scrollbars="none"
+      android:drawSelectorOnTop="true"
+      />
+
+</LinearLayout>
diff --git a/res/layout/selection_demo_list_item.xml b/res/layout/selection_demo_list_item.xml
new file mode 100644
index 0000000..0d4b718
--- /dev/null
+++ b/res/layout/selection_demo_list_item.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:paddingStart="10dp"
+    android:paddingEnd="10dp"
+    android:paddingTop="5dp"
+    android:paddingBottom="5dp"
+    android:layout_height="50dp">
+  <LinearLayout
+      android:id="@+id/container"
+      xmlns:android="http://schemas.android.com/apk/res/android"
+      android:layout_height="match_parent"
+      android:layout_width="match_parent"
+      android:background="@drawable/selection_demo_item_background">
+      <TextView
+          android:id="@+id/selector"
+          android:textSize="20sp"
+          android:textStyle="bold"
+          android:gravity="center"
+          android:layout_height="match_parent"
+          android:layout_width="40dp"
+          android:textColor="@color/selection_demo_item_selector"
+          android:pointerIcon="hand"
+          android:text="✕">
+      </TextView>
+      <TextView
+          android:id="@+id/label"
+          android:textSize="20sp"
+          android:textStyle="bold"
+          android:gravity="center_vertical"
+          android:paddingStart="10dp"
+          android:paddingEnd="10dp"
+          android:layout_height="match_parent"
+          android:layout_width="match_parent">
+      </TextView>
+  </LinearLayout>
+</LinearLayout>
diff --git a/res/layout/table_key_value_row.xml b/res/layout/table_key_value_row.xml
index 2bc8cf6..b45cda4 100644
--- a/res/layout/table_key_value_row.xml
+++ b/res/layout/table_key_value_row.xml
@@ -21,15 +21,18 @@
     android:layout_height="match_parent"
     android:paddingTop="10dp"
     android:paddingBottom="10dp"
-    android:paddingLeft="16dp">
+    android:paddingStart="16dp"
+    android:paddingEnd="16dp">
 
     <TextView
         android:id="@+id/table_row_key"
         android:layout_height="wrap_content"
         android:layout_width="0dp"
         android:layout_weight="1"
+        android:paddingEnd="5dp"
         android:textColor="@android:color/black"
-        android:textSize="14dp">
+        android:textSize="14sp"
+        android:textAlignment="viewStart">
     </TextView>
 
     <TextView
@@ -38,7 +41,9 @@
         android:layout_width="0dp"
         android:layout_weight="1"
         android:textColor="@color/inspector_value"
-        android:textSize="14dp">
+        android:textSize="14sp"
+        android:textIsSelectable="true"
+        android:textAlignment="viewStart">
     </TextView>
 
 </com.android.documentsui.inspector.KeyValueRow>
diff --git a/res/menu/action_mode_menu.xml b/res/menu/action_mode_menu.xml
index ba23816..1952285 100644
--- a/res/menu/action_mode_menu.xml
+++ b/res/menu/action_mode_menu.xml
@@ -63,8 +63,8 @@
         android:showAsAction="never"
         android:visible="false" />
     <item
-        android:id="@+id/action_menu_inspector"
-        android:title="@string/menu_inspector"
+        android:id="@+id/action_menu_inspect"
+        android:title="@string/menu_inspect"
         android:showAsAction="never"
         android:visible="false" />
     <item
diff --git a/res/menu/activity.xml b/res/menu/activity.xml
index ce51e75..0c1e68c 100644
--- a/res/menu/activity.xml
+++ b/res/menu/activity.xml
@@ -77,5 +77,10 @@
             android:title="@string/menu_settings"
             android:showAsAction="never"
             android:visible="false" />
+       <item
+           android:id="@+id/option_menu_inspect"
+           android:title="@string/menu_inspect"
+           android:showAsAction="never"
+           android:visible="false" />
     </group>
 </menu>
diff --git a/res/menu/container_context_menu.xml b/res/menu/container_context_menu.xml
index 08b0de8..2f70d82 100644
--- a/res/menu/container_context_menu.xml
+++ b/res/menu/container_context_menu.xml
@@ -35,4 +35,10 @@
             android:id="@+id/dir_menu_select_all"
             android:title="@string/menu_select_all" />
     </group>
+    <group
+        android:id="@+id/menu_extras_group">
+        <item
+            android:id="@+id/dir_menu_inspect"
+            android:title="@string/menu_inspect" />
+    </group>
 </menu>
\ No newline at end of file
diff --git a/res/menu/dir_context_menu.xml b/res/menu/dir_context_menu.xml
index 2950b53..383841a 100644
--- a/res/menu/dir_context_menu.xml
+++ b/res/menu/dir_context_menu.xml
@@ -47,4 +47,10 @@
             android:id="@+id/dir_menu_delete"
             android:title="@string/menu_delete" />
     </group>
+    <group
+        android:id="@+id/menu_extras_group">
+        <item
+            android:id="@+id/dir_menu_inspect"
+            android:title="@string/menu_inspect" />
+    </group>
 </menu>
diff --git a/res/menu/file_context_menu.xml b/res/menu/file_context_menu.xml
index 325bed9..9e786f1 100644
--- a/res/menu/file_context_menu.xml
+++ b/res/menu/file_context_menu.xml
@@ -50,7 +50,10 @@
             android:title="@string/menu_delete" />
     </group>
     <group
-        android:id="@+id/menu_settings_group">
+        android:id="@+id/menu_extras_group">
+        <item
+            android:id="@+id/dir_menu_inspect"
+            android:title="@string/menu_inspect" />
         <item
             android:id="@+id/dir_menu_view_in_owner"
             android:title="@string/menu_view_in_owner" />
diff --git a/res/menu/mixed_context_menu.xml b/res/menu/mixed_context_menu.xml
index aa6d7f5..cb6b4fd 100644
--- a/res/menu/mixed_context_menu.xml
+++ b/res/menu/mixed_context_menu.xml
@@ -34,4 +34,10 @@
             android:id="@+id/dir_menu_delete"
             android:title="@string/menu_delete" />
     </group>
+    <group
+        android:id="@+id/menu_extras_group">
+        <item
+            android:id="@+id/dir_menu_inspect"
+            android:title="@string/menu_inspect" />
+    </group>
 </menu>
\ No newline at end of file
diff --git a/res/menu/selection_demo_actions.xml b/res/menu/selection_demo_actions.xml
new file mode 100644
index 0000000..e07c06b
--- /dev/null
+++ b/res/menu/selection_demo_actions.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+   <item
+       android:id="@+id/option_menu_add_column"
+       android:title="Add column"
+       android:showAsAction="always" />
+   <item
+       android:id="@+id/option_menu_remove_column"
+       android:title="Remove column"
+       android:showAsAction="always" />
+</menu>
diff --git a/res/values-af/inspector_strings.xml b/res/values-af/inspector_strings.xml
new file mode 100644
index 0000000..24dcc70
--- /dev/null
+++ b/res/values-af/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Inligting"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Lêerinligting kon nie gelaai word nie"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Ontfoutinligting (net ontwikkeling)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Onverwerkte metadata: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Mediabesonderhede"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Hierdie soort lêer maak oop met"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Hierdie lêer word voorsien deur"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Nie gekies nie"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Onbekend"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Afmetings"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> – <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Koördinate"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Hoogte bo seespieël"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Kamera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Lensopening"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Sluiterspoed"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Tydsduur"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Geneem op"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Fokuslengte"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO-ekwivalent"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Kunstenaar"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Komponis"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Album"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Ligging"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Stroomtipes"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Onverwerkte grootte (grepe)"</string>
+</resources>
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 7763f07..4aa5072 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Pers saam"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Onttrek na …"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Hernoem"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Kry inligting"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Kry inligting"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Bekyk in <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Nuwe venster"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Sny"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Skuif"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Maak toe"</string>
     <string name="button_retry" msgid="4011461781916631389">"Probeer weer"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Vee uit"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Wys in verskaffer"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Nie gerangskik nie"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Naam"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Opsomming"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Grootte"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Gewysig"</string>
     <string name="directory_items" msgid="6645621978998614003">"Aantal items"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Hierdie tipe lêer maak oop met"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Hierdie lêer behoort aan"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Ander programme kan hierdie tipe lêer oopmaak. Verwyder"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"as die verstek."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Vee uit"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Wys in verskaffer"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Nie gekies nie"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Onbekend"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Stygend"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Dalend"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Wys wortels"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Kan lêer nie oopmaak nie"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Kan nie lêers in argiewe oopmaak nie"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Kan sommige dokumente nie uitvee nie"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Eienskappe kon nie gelaai word nie"</string>
     <string name="share_via" msgid="8725082736005677161">"Deel via"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Kopieer tans lêers"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Pers tans lêers saam"</string>
@@ -119,11 +112,11 @@
       <item quantity="one">Vee tans <xliff:g id="COUNT_0">%1$d</xliff:g> item uit.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Ontdoen"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Maak tans gereed om te kopieer …"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Berei tans voor om saam te pers …"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Maak tans gereed om te onttrek …"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Maak tans gereed om te skuif …"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Maak tans gereed om uit te vee …"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Berei tans voor …"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Berei tans voor …"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Berei tans voor …"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Berei tans voor …"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Berei tans voor …"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other">Kon <xliff:g id="COUNT_1">%1$d</xliff:g> items nie kopieer nie</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"argief<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Skryf oor <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Gaan op die agtergrond voort"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Ontfout-inligting (net ontwikkeling)"</string>
 </resources>
diff --git a/res/values-am/inspector_strings.xml b/res/values-am/inspector_strings.xml
new file mode 100644
index 0000000..423b6da
--- /dev/null
+++ b/res/values-am/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"መረጃ"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"የፋይል መረጃ ሊጫን አልቻለም"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"የማረሚያ መረጃ (ለገንቢ ብቻ)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"ጥሬ ዲበ ውሂብ፦ <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"የሚዲያ ዝርዝሮች"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"እንዲህ ዓይነቱ ፋይል በዚህ ይከፈታል፦"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"ይህ ፋይል የቀረበው በ"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"አልተመረጠም"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"ያልታወቀ"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"ልኬቶች"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> ሜፒ"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"መጋጠሚያዎች"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>፣ <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"ከፍታ"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"ካሜራ"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"የካሜራ ሌንስ መከለያ"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"የካሜራ ሌንስ መከለያ ፍጥነት"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"የቆይታ ጊዜ"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"የተነሳበት ቀን"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"የትክተት ርቀት"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> ሚሜ"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"የአይኤስኦ እኩያ"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"አይኤስኦ <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"አርቲስት"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"የሙዚቃ ደራሲ"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"አልበም"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"አካባቢ"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"የዥረት አይነቶች"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"የጥሬ መጠን (ባይት)"</string>
+</resources>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 92f037a..1a3303f 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"ጭመቅ"</string>
     <string name="menu_extract" msgid="8171946945982532262">"አውጣ ወደ…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"ዳግም ሰይም"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"መረጃ አግኝ"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"መረጃ አግኝ"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"በ<xliff:g id="SOURCE">%1$s</xliff:g> ይመልከቱ"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"አዲሰ መስኮት"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"ቁረጥ"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"ውሰድ"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"አሰናብት"</string>
     <string name="button_retry" msgid="4011461781916631389">"እንደገና ይሞክሩ"</string>
+    <string name="button_clear" msgid="5412304437764369441">"አጽዳ"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"በአቅራቢ ውስጥ አሳይ"</string>
     <string name="not_sorted" msgid="7813496644889115530">"አልተደረደረም"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"ስም"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"ማጠቃለያ"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"መጠን"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"የተቀየረበት ጊዜ"</string>
     <string name="directory_items" msgid="6645621978998614003">"የንጥሎች ብዛት"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"እንዲህ ዓይነቱ ፋይል በዚህ ይከፈታል፦"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"የዚህ ፋይል ባለቤት ይህ ነው፦"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"ሌሎች መተግበሪያዎች ይህን የፋይል ዓይነት መክፈት ይችላሉ። አጽዳ"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"እንደ ነባሪ።"</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"አጽዳ"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"በአቅራቢ ውስጥ አሳይ"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"አልተመረጠም"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"ያልታወቀ"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"ሽቅብታ"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"አቆልቋይ"</string>
     <string name="drawer_open" msgid="8071673398187261741">"ስሮችን አሳይ"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"ፋይሉን መክፈት አይቻልም"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"በማህደሮች ውስጥ ያሉ ፋይሎችን መክፈት አይቻልም"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"አንዳንድ ሰነዶችን መሰረዝ አልተቻለም"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"ባህሪዎቹ ሊጫኑ አልቻሉም"</string>
     <string name="share_via" msgid="8725082736005677161">"በዚህ በኩል ያጋሩ፦"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"ፋይሎችን በመቅዳት ላይ"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"ፋይሎችን በመጭመቅ ላይ"</string>
@@ -119,11 +112,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ንጥሎችን በመሰረዝ ላይ።</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"ቀልብስ"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"ለመቅዳት በመዘጋጀት ላይ…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"ለመጭመቅ በመዘጋጀት ላይ…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"ሰርስሮ ለማውጣት በማዘጋጀት ላይ…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"ለመውሰድ በመዘጋጀት ላይ…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"ለመሰረዝ በመዘጋጀት ላይ…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"በማዘጋጀት ላይ..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"በማዘጋጀት ላይ..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"በማዘጋጀት ላይ..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"በማዘጋጀት ላይ..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"በማዘጋጀት ላይ..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ንጥሎችን መቅዳት አልተቻለም</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"ማህደር<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"<xliff:g id="NAME">%1$s</xliff:g> ይተካ?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"በበስተጀርባ ውስጥ ቀጥል"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"የማረሚያ መረጃ (ለገንቢ ብቻ)"</string>
 </resources>
diff --git a/res/values-ar/inspector_strings.xml b/res/values-ar/inspector_strings.xml
new file mode 100644
index 0000000..ffae9de
--- /dev/null
+++ b/res/values-ar/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"المعلومات"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"تعذّر تحميل معلومات الملف"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"معلومات تصحيح الأخطاء (المطوّر فقط)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"البيانات الوصفية الأولية: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"تفاصيل الوسائط"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"يتم فتح هذا النوع من الملفات باستخدام"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"تم تقديم هذا الملف من خلال"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"غير محدّد"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"غير معروف"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"الأبعاد"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> × <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> ميغا بكسل"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"إحداثيات"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>، <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"الارتفاع"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"الكاميرا"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"فتحة العدسة"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"سرعة مصراع الكاميرا"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"المدة"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"تم الالتقاط في"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"البعد البؤري"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> ملليمتر"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"‏مكافئ ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"‏سرعة ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"الفنان"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"الملحّن"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"الألبوم"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"الموقع الجغرافي"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"أنواع سلسلة البطاقات"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"الحجم الأولي (بالبايت)"</string>
+</resources>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 6de3ee5..31ab0ad 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"ضغط"</string>
     <string name="menu_extract" msgid="8171946945982532262">"الاستخراج إلى…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"إعادة تسمية"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"الحصول على المعلومات"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"الحصول على المعلومات"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"العرض في <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"نافذة جديدة"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"قص"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"نقل"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"تجاهل"</string>
     <string name="button_retry" msgid="4011461781916631389">"إعادة المحاولة"</string>
+    <string name="button_clear" msgid="5412304437764369441">"محو"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"عرض في مقدم الخدمة"</string>
     <string name="not_sorted" msgid="7813496644889115530">"بدون ترتيب"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"الاسم"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"الملخص"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"الحجم"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"آخر تعديل"</string>
     <string name="directory_items" msgid="6645621978998614003">"عدد العناصر"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"يتم فتح هذا النوع من الملفات باستخدام"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"ينتمي هذا الملف إلى"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"يمكن لتطبيقات أخرى فتح نوع الملف هذا. إيقاف استخدامه"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"كخيار افتراضي."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"إيقاف استخدامه"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"عرض في مقدم خدمة"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"غير محدّد"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"غير معروف"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"تصاعدي"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"تنازلي"</string>
     <string name="drawer_open" msgid="8071673398187261741">"عرض الجذور"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"يتعذر فتح الملف"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"يتعذر فتح الملفات في الأرشيف"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"تعذر حذف بعض المستندات"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"تعذَّر تحميل الخصائص"</string>
     <string name="share_via" msgid="8725082736005677161">"مشاركة عبر"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"جارٍ نسخ الملفات"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"ضغط الملفات"</string>
@@ -139,11 +132,11 @@
       <item quantity="one">جارٍ حذف ملف واحد (<xliff:g id="COUNT_0">%1$d</xliff:g>).</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"تراجع"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"جارٍ التحضير للنسخ ..."</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"جارٍ التحضير للضغط…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"جارٍ الإعداد للاستخلاص…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"جارٍ التحضير للنقل…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"جارٍ الإعداد للحذف…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"جارٍ التحضير..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"جارٍ التحضير..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"جارٍ التحضير..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"جارٍ التحضير..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"جارٍ التحضير..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="zero">تعذَّر نسخ <xliff:g id="COUNT_1">%1$d</xliff:g> ملف</item>
@@ -242,7 +235,7 @@
     <string name="notification_copy_files_converted_title" msgid="6916768494891833365">"تم تحويل بعض الملفات"</string>
     <string name="open_external_dialog_request" msgid="8173558471322861268">"هل تريد منح التطبيق <xliff:g id="APPNAME"><b>^1</b></xliff:g> حق الوصول إلى الدليل <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> على <xliff:g id="STORAGE"><i>^3</i></xliff:g>؟"</string>
     <string name="open_external_dialog_request_primary_volume" msgid="2240992164087948176">"هل تريد منح <xliff:g id="APPNAME"><b>^1</b></xliff:g> حق الوصول إلى دليل <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>؟"</string>
-    <string name="open_external_dialog_root_request" msgid="6776729293982633">"هل تريد منح <xliff:g id="APPNAME"><b>^1</b></xliff:g> حق الوصول إلى بياناتك، بما في ذلك الصور ومقاطع الفيديو على <xliff:g id="STORAGE"><i>^2</i></xliff:g>؟"</string>
+    <string name="open_external_dialog_root_request" msgid="6776729293982633">"هل تريد منح <xliff:g id="APPNAME"><b>^1</b></xliff:g> حق الوصول إلى بياناتك، بما في ذلك الصور والفيديوهات على <xliff:g id="STORAGE"><i>^2</i></xliff:g>؟"</string>
     <string name="never_ask_again" msgid="525908236522201138">"عدم السؤال مرة أخرى"</string>
     <string name="allow" msgid="1275746941353040309">"السماح"</string>
     <string name="deny" msgid="5127201668078153379">"رفض"</string>
@@ -297,5 +290,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"أرشيف<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"هل تريد استبدال <xliff:g id="NAME">%1$s</xliff:g>؟"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"المتابعة في الخلفية"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"معلومات تصحيح الأخطاء (المطوّر فقط)"</string>
 </resources>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
new file mode 100644
index 0000000..4a93e16
--- /dev/null
+++ b/res/values-as/strings.xml
@@ -0,0 +1,279 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="files_label" msgid="771781190045103748">"ফাইলবোৰ"</string>
+    <!-- no translation found for downloads_label (5462789470049501103) -->
+    <skip />
+    <!-- no translation found for app_label (8089292432455111409) -->
+    <skip />
+    <!-- no translation found for launcher_label (799410258349837668) -->
+    <skip />
+    <!-- no translation found for title_open (3165686459158020921) -->
+    <skip />
+    <!-- no translation found for title_save (4384490653102710025) -->
+    <skip />
+    <!-- no translation found for menu_create_dir (2413624798689091042) -->
+    <skip />
+    <!-- no translation found for menu_grid (1453636521731880680) -->
+    <skip />
+    <!-- no translation found for menu_list (6714267452146410402) -->
+    <skip />
+    <!-- no translation found for menu_search (1876699106790719849) -->
+    <skip />
+    <!-- no translation found for menu_settings (6520844520117939047) -->
+    <skip />
+    <!-- no translation found for menu_open (9092138100049759315) -->
+    <skip />
+    <!-- no translation found for menu_open_with (5507647065467520229) -->
+    <skip />
+    <!-- no translation found for menu_open_in_new_window (6686563636123311276) -->
+    <skip />
+    <!-- no translation found for menu_save (5195367497138965168) -->
+    <skip />
+    <!-- no translation found for menu_share (4307140947108068356) -->
+    <skip />
+    <!-- no translation found for menu_delete (1022254131543256626) -->
+    <skip />
+    <!-- no translation found for menu_select_all (7600576812185570403) -->
+    <skip />
+    <!-- no translation found for menu_copy (7404820171352314754) -->
+    <skip />
+    <!-- no translation found for menu_move (2310760789561129882) -->
+    <skip />
+    <string name="menu_compress" msgid="37539111904724188">"সংকুচিত কৰক"</string>
+    <string name="menu_extract" msgid="8171946945982532262">"ইয়ালৈ আহৰণ কৰক…"</string>
+    <!-- no translation found for menu_rename (1883113442688817554) -->
+    <skip />
+    <!-- no translation found for menu_inspect (7279855349299446224) -->
+    <skip />
+    <string name="menu_view_in_owner" msgid="7228948660557554770">"<xliff:g id="SOURCE">%1$s</xliff:g>ত চাওক"</string>
+    <!-- no translation found for menu_new_window (2947837751796109126) -->
+    <skip />
+    <!-- no translation found for menu_cut_to_clipboard (2878752142015026229) -->
+    <skip />
+    <!-- no translation found for menu_copy_to_clipboard (5064081159073330776) -->
+    <skip />
+    <!-- no translation found for menu_paste_from_clipboard (360947260414135827) -->
+    <skip />
+    <!-- no translation found for menu_paste_into_folder (8000644546983240101) -->
+    <skip />
+    <!-- no translation found for menu_advanced_show (7558626506462906726) -->
+    <skip />
+    <!-- no translation found for menu_advanced_hide (6488381508009246334) -->
+    <skip />
+    <!-- no translation found for button_select (240863497069321364) -->
+    <skip />
+    <!-- no translation found for button_copy (8219059853840996027) -->
+    <skip />
+    <string name="button_compress" msgid="8951561310857223966">"সংকুচিত কৰক"</string>
+    <string name="button_extract" msgid="1038674453689912247">"আহৰণ কৰক"</string>
+    <!-- no translation found for button_move (8596460499325291272) -->
+    <skip />
+    <!-- no translation found for button_dismiss (7235249361023803349) -->
+    <skip />
+    <!-- no translation found for button_retry (4011461781916631389) -->
+    <skip />
+    <!-- no translation found for button_clear (5412304437764369441) -->
+    <skip />
+    <!-- no translation found for button_show_provider (6905880493806292753) -->
+    <skip />
+    <!-- no translation found for not_sorted (7813496644889115530) -->
+    <skip />
+    <!-- no translation found for sort_dimension_name (6325591541414177579) -->
+    <skip />
+    <!-- no translation found for sort_dimension_summary (7724534446881397860) -->
+    <skip />
+    <!-- no translation found for sort_dimension_file_type (5779709622922085381) -->
+    <skip />
+    <!-- no translation found for sort_dimension_size (2190547351159472884) -->
+    <skip />
+    <!-- no translation found for sort_dimension_date (4231005651895254033) -->
+    <skip />
+    <!-- no translation found for directory_items (6645621978998614003) -->
+    <skip />
+    <!-- no translation found for sort_direction_ascending (5882787683763248102) -->
+    <skip />
+    <!-- no translation found for sort_direction_descending (1729187589765894076) -->
+    <skip />
+    <!-- no translation found for drawer_open (8071673398187261741) -->
+    <skip />
+    <!-- no translation found for drawer_close (4263880768630848848) -->
+    <skip />
+    <!-- no translation found for save_error (8631128801982095782) -->
+    <skip />
+    <!-- no translation found for create_error (3092144450044861994) -->
+    <skip />
+    <!-- no translation found for query_error (6625421453613879336) -->
+    <skip />
+    <!-- no translation found for root_recent (1080156975424341623) -->
+    <skip />
+    <!-- no translation found for root_available_bytes (8269870862691408864) -->
+    <skip />
+    <!-- no translation found for root_type_service (6521366147466512289) -->
+    <skip />
+    <!-- no translation found for root_type_shortcut (6059343175525442279) -->
+    <skip />
+    <!-- no translation found for root_type_device (1713604128005476585) -->
+    <skip />
+    <!-- no translation found for root_type_apps (8646073235029886342) -->
+    <skip />
+    <!-- no translation found for empty (5300254272613103004) -->
+    <skip />
+    <!-- no translation found for no_results (2371026325236359209) -->
+    <skip />
+    <!-- no translation found for toast_no_application (7555319548595113121) -->
+    <skip />
+    <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"আৰ্কাইভত থকা ফাইলবোৰ খুলিব নোৱাৰি"</string>
+    <!-- no translation found for toast_failed_delete (3453846588205817591) -->
+    <skip />
+    <!-- no translation found for share_via (8725082736005677161) -->
+    <skip />
+    <!-- no translation found for copy_notification_title (52256435625098456) -->
+    <skip />
+    <string name="compress_notification_title" msgid="6830195148113751021">"ফাইলবোৰ সংকুচিত কৰি থকা হৈছে"</string>
+    <!-- no translation found for extract_notification_title (5067393961754430469) -->
+    <skip />
+    <!-- no translation found for move_notification_title (3173424987049347605) -->
+    <skip />
+    <!-- no translation found for delete_notification_title (2512757431856830792) -->
+    <skip />
+    <!-- no translation found for copy_remaining (5390517377265177727) -->
+    <skip />
+    <plurals name="copy_begin" formatted="false" msgid="151184708996738192">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টা বস্তু প্ৰতিলিপি কৰি থকা হৈছে।</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টা বস্তু প্ৰতিলিপি কৰি থকা হৈছে।</item>
+    </plurals>
+    <plurals name="compress_begin" formatted="false" msgid="3534158317098678895">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টা ফাইল সংকুচিত কৰি থকা হৈছে।</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টা ফাইল সংকুচিত কৰি থকা হৈছে।</item>
+    </plurals>
+    <plurals name="extract_begin" formatted="false" msgid="1006380679562903749">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টা ফাইল আহৰণ কৰি থকা হৈছে।</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টা ফাইল আহৰণ কৰি থকা হৈছে।</item>
+    </plurals>
+    <plurals name="move_begin" formatted="false" msgid="1464229874265756956">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টা বস্তু স্থানান্তৰ কৰি থকা হৈছে।</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টা বস্তু স্থানান্তৰ কৰি থকা হৈছে।</item>
+    </plurals>
+    <plurals name="deleting" formatted="false" msgid="1729138001178158901">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টা বস্তু মচি থকা হৈছে।</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টা বস্তু মচি থকা হৈছে।</item>
+    </plurals>
+    <!-- no translation found for undo (2902438994196400565) -->
+    <skip />
+    <!-- no translation found for copy_preparing (5326063807006898223) -->
+    <skip />
+    <string name="compress_preparing" msgid="6650018601382062672">"সংকুচিত কৰিবলৈ প্ৰস্তুত কৰি থকা হৈছে…"</string>
+    <string name="extract_preparing" msgid="58266275455027829">"আহৰণ কৰিবলৈ সাজু কৰি থকা হৈছে…"</string>
+    <!-- no translation found for move_preparing (8742573245485449429) -->
+    <skip />
+    <!-- no translation found for delete_preparing (6513863752916028147) -->
+    <skip />
+    <!-- no translation found for delete_progress (2627631054702306423) -->
+    <skip />
+    <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টা বস্তু প্ৰতিলিপি কৰিব পৰা নগ\'ল</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টা বস্তু প্ৰতিলিপি কৰিব পৰা নগ\'ল</item>
+    </plurals>
+    <plurals name="compress_error_notification_title" formatted="false" msgid="3043630066678213644">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টা ফাইল সংকুচিত কৰিব পৰা নগ\'ল</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টা ফাইল সংকুচিত কৰিব পৰা নগ\'ল</item>
+    </plurals>
+    <plurals name="move_error_notification_title" formatted="false" msgid="2185736082411854754">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টা বস্তু স্থানান্তৰ কৰিব পৰা নগ\'ল</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টা বস্তু স্থানান্তৰ কৰিব পৰা নগ\'ল</item>
+    </plurals>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7568122018481625267">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টা বস্তু মচিব পৰা নগ\'ল</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টা বস্তু মচিব পৰা নগ\'ল</item>
+    </plurals>
+    <!-- no translation found for notification_touch_for_details (2385563502445129570) -->
+    <skip />
+    <!-- no translation found for close (905969391788869975) -->
+    <skip />
+    <plurals name="copy_failure_alert_content" formatted="false" msgid="5570549471912990536">
+      <item quantity="one">এই ফাইলবোৰ প্ৰতিলিপি কৰা নহ\'ল: <xliff:g id="LIST_1">%1$s</xliff:g></item>
+      <item quantity="other">এই ফাইলবোৰ প্ৰতিলিপি কৰা নহ\'ল: <xliff:g id="LIST_1">%1$s</xliff:g></item>
+    </plurals>
+    <plurals name="compress_failure_alert_content" formatted="false" msgid="5760632881868842400">
+      <item quantity="one">এই ফাইলবোৰ সংকুচিত কৰিব পৰা নগ\'ল: <xliff:g id="LIST_1">%1$s</xliff:g></item>
+      <item quantity="other">এই ফাইলবোৰ সংকুচিত কৰিব পৰা নগ\'ল: <xliff:g id="LIST_1">%1$s</xliff:g></item>
+    </plurals>
+    <plurals name="extract_failure_alert_content" formatted="false" msgid="7572748127571720803">
+      <item quantity="one">এই ফাইলবোৰ আহৰণ কৰা নহ\'ল: <xliff:g id="LIST_1">%1$s</xliff:g></item>
+      <item quantity="other">এই ফাইলবোৰ আহৰণ কৰা নহ\'ল: <xliff:g id="LIST_1">%1$s</xliff:g></item>
+    </plurals>
+    <plurals name="move_failure_alert_content" formatted="false" msgid="2747390342670799196">
+      <item quantity="one">এই ফাইলবোৰ স্থানান্তৰ কৰা নহ\'ল: <xliff:g id="LIST_1">%1$s</xliff:g></item>
+      <item quantity="other">এই ফাইলবোৰ স্থানান্তৰ কৰা নহ\'ল: <xliff:g id="LIST_1">%1$s</xliff:g></item>
+    </plurals>
+    <plurals name="delete_failure_alert_content" formatted="false" msgid="6122372614839711711">
+      <item quantity="one">এই ফাইলবোৰ মচা নহ\'ল: <xliff:g id="LIST_1">%1$s</xliff:g></item>
+      <item quantity="other">এই ফাইলবোৰ মচা নহ\'ল: <xliff:g id="LIST_1">%1$s</xliff:g></item>
+    </plurals>
+    <plurals name="copy_converted_warning_content" formatted="false" msgid="7433742181712126588">
+      <item quantity="one">এই ফাইলবোৰ অন্য এটা ফৰ্মেটলৈ সলনি কৰা হ\'ল: <xliff:g id="LIST_1">%1$s</xliff:g></item>
+      <item quantity="other">এই ফাইলবোৰ অন্য এটা ফৰ্মেটলৈ সলনি কৰা হ\'ল: <xliff:g id="LIST_1">%1$s</xliff:g></item>
+    </plurals>
+    <plurals name="clipboard_files_clipped" formatted="false" msgid="4847061634862926902">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টা বস্তু ক্লিপব\'ৰ্ডত প্ৰতিলিপি কৰা হ\'ল।</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টা বস্তু ক্লিপব\'ৰ্ডত প্ৰতিলিপি কৰা হ\'ল।</item>
+    </plurals>
+    <string name="file_operation_rejected" msgid="4301554203329008794">"ফাইলত কাৰ্য কৰিব নোৱাৰি।"</string>
+    <string name="file_operation_error" msgid="2234357335716533795">"ফাইলত কাৰ্য কৰিব পৰা নগ\'ল।"</string>
+    <!-- no translation found for rename_error (6700093173508118635) -->
+    <skip />
+    <!-- no translation found for menu_eject_root (9215040039374893613) -->
+    <skip />
+    <!-- no translation found for notification_copy_files_converted_title (6916768494891833365) -->
+    <skip />
+    <!-- no translation found for open_external_dialog_request (8173558471322861268) -->
+    <skip />
+    <!-- no translation found for open_external_dialog_request_primary_volume (2240992164087948176) -->
+    <skip />
+    <!-- no translation found for open_external_dialog_root_request (6776729293982633) -->
+    <skip />
+    <!-- no translation found for never_ask_again (525908236522201138) -->
+    <skip />
+    <!-- no translation found for allow (1275746941353040309) -->
+    <skip />
+    <!-- no translation found for deny (5127201668078153379) -->
+    <skip />
+    <!-- no translation found for elements_selected (4448165978637163692) -->
+    <!-- no translation found for elements_dragged (5932571296037626279) -->
+    <!-- no translation found for delete_filename_confirmation_message (8338069763240613258) -->
+    <skip />
+    <!-- no translation found for delete_foldername_confirmation_message (9084085260877704140) -->
+    <skip />
+    <!-- no translation found for delete_files_confirmation_message (4866664063250034142) -->
+    <!-- no translation found for delete_folders_confirmation_message (1028946402799686388) -->
+    <!-- no translation found for delete_items_confirmation_message (7285090426511028179) -->
+    <string name="images_shortcut_label" msgid="2545168016070493574">"প্ৰতিচ্ছবিবোৰ"</string>
+    <string name="archive_loading_failed" msgid="7243436722828766996">"ব্ৰাউজ কৰিবলৈ আৰ্কাইভ খুলিব পৰা নগ\'ল। ফাইলটো হয় ব্যৱহাৰযোগ্য হৈ থকা নাই বা ব্যৱহাৰ কৰিব পৰা ফৰ্মেটত নাই।"</string>
+    <string name="name_conflict" msgid="28407269328862986">"এই নামৰ অইন এটা ফাইল ইতিমধ্যে আছে।"</string>
+    <!-- no translation found for authentication_required (8030880723643436099) -->
+    <skip />
+    <!-- no translation found for cant_display_content (8633226333229417237) -->
+    <skip />
+    <!-- no translation found for sign_in (6253762676723505592) -->
+    <skip />
+    <string name="new_archive_file_name" msgid="1604650338077249838">"আৰ্কাইভ<xliff:g id="EXTENSION">%s</xliff:g>"</string>
+    <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"<xliff:g id="NAME">%1$s</xliff:g>ক অভাৰৰাইট কৰিবনে?"</string>
+    <!-- no translation found for continue_in_background (1974214559047793331) -->
+    <skip />
+</resources>
diff --git a/res/values-az/inspector_strings.xml b/res/values-az/inspector_strings.xml
new file mode 100644
index 0000000..2ae8084
--- /dev/null
+++ b/res/values-az/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Məlumat"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Fayl məlumatını yükləmək mümkün olmadı"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Sazlama haqqında məlumat (yalnız dev)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Sətir metadatası: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Media haqqında məlumat"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Bu fayl növü bele açılmalıdır"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Bu fayl təmin edilib"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Seçilməyib"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Naməlum"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Ölçülər"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Koordinatlar"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Yüksəklik"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Kamera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Dəlik"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Sürgü sürəti"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Müddət:"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Şəkil çəkilib"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Fokal uzunluq"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO ekvivalenti"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"İfaçı"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Bəstəkar"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Albom"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Məkan"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Axın növləri"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Sətir ölçüsü (bayt)"</string>
+</resources>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 357ef0e..9f8ecca 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Sıxışdırın"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Çıxarın…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Adını dəyişdirin"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Məlumat əldə edin"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Məlumat əldə edin"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"<xliff:g id="SOURCE">%1$s</xliff:g> mənbəsində baxın"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Yeni pəncərə"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Kəsin"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Köçürün"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Yığışdırın"</string>
     <string name="button_retry" msgid="4011461781916631389">"Yenidən cəhd edin"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Silin"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Provayderdə göstərin"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Sıralanmayıb"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Ad"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Yekun"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Ölçü"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Dəyişmiş"</string>
     <string name="directory_items" msgid="6645621978998614003">"Elementlərin sayı"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Bu fayl növü bele açılmalıdır"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Faylın məxsus olduğu provayder"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Digər tətbiqlər bu fayl növünü aça bilər. Silin"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"defolt olaraq."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Silin"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Provayderdə göstərin"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Seçilməyib"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Naməlum"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Artan sıra ilə"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Azalan sıra ilə"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Kökləri göstərin"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Fayl açılmır"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Arxivdəki faylları açmaq olmur"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Bəzi sənədləri silə bilmir"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Xüsusiyyətləri yükləmək mümkün olmadı"</string>
     <string name="share_via" msgid="8725082736005677161">"Bunun vasitəsilə paylaş:"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Fayllar kopyalanır"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Faylların sıxılması"</string>
@@ -119,11 +112,11 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> element silinir.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Geri qaytarın"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Kopyalanmaq üçün hazırlanır..."</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Sıxılma üçün hazırlanır…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Çıxarmaq üçün hazırlanır…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Köçürmə üçün hazırlanır..."</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Silmək üçün hazırlanır..."</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Hazırlanır..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Hazırlanır..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Hazırlanır..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Hazırlanır..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Hazırlanır..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> element kopyalana bilmədi</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"arxiv<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"<xliff:g id="NAME">%1$s</xliff:g> yenidən yazılsın?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Arxa fonda davam edin"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Sazlama haqqında məlumat (yalnız dev)"</string>
 </resources>
diff --git a/res/values-b+sr+Latn/inspector_strings.xml b/res/values-b+sr+Latn/inspector_strings.xml
new file mode 100644
index 0000000..133f533
--- /dev/null
+++ b/res/values-b+sr+Latn/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Informacije"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Učitavanje podataka o datoteci nije uspelo"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Podaci o otklanjanju grešaka (samo za programere)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Metapodaci RAW datoteke: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Detalji o medijima"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Ova vrsta datoteke se otvara pomoću:"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Ovu datoteku pruža"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Nije izabrano"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Nepoznato"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Dimenzije"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g>×<xliff:g id="HEIGHT">%2$d</xliff:g> – <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> megapiksela"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Koordinate"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Nadmorska visina"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Kamera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Otvor blende"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Brzina zatvarača"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Trajanje"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Snimljeno"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Žižna daljina"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO ekvivalent"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Izvođač"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Kompozitor"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Album"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Lokacija"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Tipovi strimova"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Veličina RAW datoteke (u bajtovima)"</string>
+</resources>
diff --git a/res/values-b+sr+Latn/mimes.xml b/res/values-b+sr+Latn/mimes.xml
new file mode 100644
index 0000000..a4e7bda
--- /dev/null
+++ b/res/values-b+sr+Latn/mimes.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2017 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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="generic_extention_file_type" msgid="5947398320635880291">"<xliff:g id="EXTENSION">%1$s</xliff:g> datoteka"</string>
+    <string name="generic_file_type" msgid="1415477154743494280">"Datoteka"</string>
+    <string name="image_file_type" msgid="3011633523704887793">"Slika"</string>
+    <string name="image_extension_file_type" msgid="992617216367594851">"<xliff:g id="FILETYPE">%1$s</xliff:g> slika"</string>
+    <string name="audio_file_type" msgid="3790525543519624632">"Audio"</string>
+    <string name="audio_extension_file_type" msgid="6334293531796491314">"<xliff:g id="FILETYPE">%1$s</xliff:g> audio"</string>
+    <string name="video_file_type" msgid="7290473366042482095">"Video"</string>
+    <string name="video_extension_file_type" msgid="6352763029831291433">"<xliff:g id="FILETYPE">%1$s</xliff:g> video"</string>
+    <string name="archive_file_type" msgid="1463432996680398798">"<xliff:g id="FILETYPE">%1$s</xliff:g> arhiva"</string>
+    <string name="apk_file_type" msgid="6004275470389462277">"Android aplikacija"</string>
+    <string name="txt_file_type" msgid="4677767777860724696">"Običan tekst"</string>
+    <string name="html_file_type" msgid="2034229603117527970">"HTML dokument"</string>
+    <string name="pdf_file_type" msgid="3382260303795039988">"PDF dokument"</string>
+    <string name="word_file_type" msgid="2366349268129894972">"Word dokument"</string>
+    <string name="ppt_file_type" msgid="2570841599899893925">"PowerPoint prezentacija"</string>
+    <string name="excel_file_type" msgid="8363932635044575463">"Excel tabela"</string>
+    <string name="gdoc_file_type" msgid="242328101061228382">"Google dokument"</string>
+    <string name="gsheet_file_type" msgid="8055591929133067952">"Google tabela"</string>
+    <string name="gslides_file_type" msgid="8359750985956690177">"Google prezentacija"</string>
+    <string name="gdraw_file_type" msgid="655688091676820371">"Google crtež"</string>
+    <string name="gtable_file_type" msgid="7332773878374650335">"Google tabela"</string>
+    <string name="gform_file_type" msgid="4803176103746107611">"Google upitnik"</string>
+    <string name="gmap_file_type" msgid="6684180781808007016">"Google mapa"</string>
+    <string name="gsite_file_type" msgid="3742812051249149526">"Google sajt"</string>
+    <string name="directory_type" msgid="2702987727566226354">"Direktorijum"</string>
+</resources>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index f6b43e2..adfd814 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Komprimuj"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Izdvoj u…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Preimenuj"</string>
-    <string name="menu_inspector" msgid="8633147986551632467">"Svojstva"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Prikaži informacije"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Prikaži u: <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Novi prozor"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Iseci"</string>
@@ -57,13 +57,15 @@
     <string name="button_move" msgid="8596460499325291272">"Premesti"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Odbaci"</string>
     <string name="button_retry" msgid="4011461781916631389">"Probaj ponovo"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Obriši"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Prikaži u aplikaciji dobavljača"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Nisu sortirani"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Naziv"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Rezime"</string>
     <string name="sort_dimension_file_type" msgid="5779709622922085381">"Tip"</string>
     <string name="sort_dimension_size" msgid="2190547351159472884">"Veličina"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Izmenjeno"</string>
-    <string name="directory_children" msgid="8115290268549503262">"Broj dece"</string>
+    <string name="directory_items" msgid="6645621978998614003">"Broj stavki"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Rastuće"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Opadajuće"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Prikaži osnovne direktorijume"</string>
@@ -82,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Otvaranje datoteke nije uspelo"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Ne možete da otvarate datoteke u arhivama"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Nije moguće izbrisati neke dokumente"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Učitavanje svojstava nije uspelo"</string>
     <string name="share_via" msgid="8725082736005677161">"Deljenje preko"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Kopiramo datoteke"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Datoteke se komprimuju"</string>
@@ -116,11 +117,11 @@
       <item quantity="other">Briše se <xliff:g id="COUNT_1">%1$d</xliff:g> stavki.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Opozovi"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Pripremamo kopiranje…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Pripremaju se za komprimovanje…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Izdvajanje se priprema…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Pripremamo premeštanje…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Pripremamo brisanje…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Priprema se..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Priprema se..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Priprema se..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Priprema se..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Priprema se..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one">Kopiranje <xliff:g id="COUNT_1">%1$d</xliff:g> stavke nije uspelo</item>
diff --git a/res/values-be/inspector_strings.xml b/res/values-be/inspector_strings.xml
new file mode 100644
index 0000000..79cd4f2
--- /dev/null
+++ b/res/values-be/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Інфармацыя"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Не атрымалася загрузіць звесткі пра файл"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Адладачная інф-цыя (толькі для распрацоўшчыкаў)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Неапрацаваныя метаданыя: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Падрабязная інфармацыя пра мультымедыя"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Такія файлы адкрываюцца з дапамогай"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Гэты файл паходзіць з:"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Не выбрана"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Невядома"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Памеры"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> – <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> Мп"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Каардынаты"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Вышыня"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Камера"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Апертура"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Хуткасць затвора"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Працягласць"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Знята"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Фокусная адлегласць"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> мм"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Эквівалент ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Выканаўца"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Кампазітар"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Альбом"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Месцазнаходжанне"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Тыпы плыні"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Памер файла RAW (у байтах)"</string>
+</resources>
diff --git a/res/values-be/mimes.xml b/res/values-be/mimes.xml
new file mode 100644
index 0000000..42495bb
--- /dev/null
+++ b/res/values-be/mimes.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2017 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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="generic_extention_file_type" msgid="5947398320635880291">"Файл <xliff:g id="EXTENSION">%1$s</xliff:g>"</string>
+    <string name="generic_file_type" msgid="1415477154743494280">"Файл"</string>
+    <string name="image_file_type" msgid="3011633523704887793">"Відарыс"</string>
+    <string name="image_extension_file_type" msgid="992617216367594851">"Відарыс <xliff:g id="FILETYPE">%1$s</xliff:g>"</string>
+    <string name="audio_file_type" msgid="3790525543519624632">"Аўдыя"</string>
+    <string name="audio_extension_file_type" msgid="6334293531796491314">"Аўдыя <xliff:g id="FILETYPE">%1$s</xliff:g>"</string>
+    <string name="video_file_type" msgid="7290473366042482095">"Відэа"</string>
+    <string name="video_extension_file_type" msgid="6352763029831291433">"Відэа <xliff:g id="FILETYPE">%1$s</xliff:g>"</string>
+    <string name="archive_file_type" msgid="1463432996680398798">"Архіў <xliff:g id="FILETYPE">%1$s</xliff:g>"</string>
+    <string name="apk_file_type" msgid="6004275470389462277">"Праграма Android"</string>
+    <string name="txt_file_type" msgid="4677767777860724696">"Просты тэкст"</string>
+    <string name="html_file_type" msgid="2034229603117527970">"Дакумент HTML"</string>
+    <string name="pdf_file_type" msgid="3382260303795039988">"Дакумент PDF"</string>
+    <string name="word_file_type" msgid="2366349268129894972">"Дакумент Word"</string>
+    <string name="ppt_file_type" msgid="2570841599899893925">"Прэзентацыя PowerPoint"</string>
+    <string name="excel_file_type" msgid="8363932635044575463">"Электр. табліца Excel"</string>
+    <string name="gdoc_file_type" msgid="242328101061228382">"Дакумент Google"</string>
+    <string name="gsheet_file_type" msgid="8055591929133067952">"Электр. табліца Google"</string>
+    <string name="gslides_file_type" msgid="8359750985956690177">"Прэзентацыя Google"</string>
+    <string name="gdraw_file_type" msgid="655688091676820371">"Рысунак Google"</string>
+    <string name="gtable_file_type" msgid="7332773878374650335">"Табліца Google"</string>
+    <string name="gform_file_type" msgid="4803176103746107611">"Форма Google"</string>
+    <string name="gmap_file_type" msgid="6684180781808007016">"Карта Google"</string>
+    <string name="gsite_file_type" msgid="3742812051249149526">"Сайт Google"</string>
+    <string name="directory_type" msgid="2702987727566226354">"Папка"</string>
+</resources>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 9b13fce..e9e0747 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Сціснуць"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Выняць у…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Перайменаваць"</string>
-    <string name="menu_inspector" msgid="8633147986551632467">"Уласцівасці"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Атрымаць інфармацыю"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Праглядзець тут: <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Новае акно"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Выразаць"</string>
@@ -57,13 +57,15 @@
     <string name="button_move" msgid="8596460499325291272">"Перамясціць"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Адхіліць"</string>
     <string name="button_retry" msgid="4011461781916631389">"Паўтарыць спробу"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Выдаліць"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Паказаць у Правадніку"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Не адсартаваны"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Назва"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Кароткае апісанне"</string>
     <string name="sort_dimension_file_type" msgid="5779709622922085381">"Тып"</string>
     <string name="sort_dimension_size" msgid="2190547351159472884">"Памер"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Зменены"</string>
-    <string name="directory_children" msgid="8115290268549503262">"Колькасць дзяцей"</string>
+    <string name="directory_items" msgid="6645621978998614003">"Колькасць элементаў"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Па ўзрастанні"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Па ўбыванні"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Паказаць каранёвыя папкі"</string>
@@ -82,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Немагчыма адкрыць файл"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Немагчыма адкрыць файлы ў архівах"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Немагчыма выдаліць некаторыя дакументы"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Не атрымалася загрузіць уласцівасці"</string>
     <string name="share_via" msgid="8725082736005677161">"Абагуліць праз"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Капіраванне файлаў"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Ідзе сцісканне файлаў"</string>
@@ -121,11 +122,11 @@
       <item quantity="other">Ідзе выдаленне <xliff:g id="COUNT_1">%1$d</xliff:g> элемента.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Адрабіць"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Ідзе падрыхтоўка да капіравання…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Ідзе падрыхтоўка да сціскання…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Ідзе падрыхтоўка да вымання…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Падрыхтоўваецца перамяшчэнне…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Ідзе падрыхтоўка да выдалення…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Падрыхтоўка…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Падрыхтоўка…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Падрыхтоўка…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Падрыхтоўка…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Падрыхтоўка…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one">Не атрымалася скапіраваць <xliff:g id="COUNT_1">%1$d</xliff:g> элемент</item>
diff --git a/res/values-bg/inspector_strings.xml b/res/values-bg/inspector_strings.xml
new file mode 100644
index 0000000..9e6b1e6
--- /dev/null
+++ b/res/values-bg/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Информация"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Информацията за файла не можа да се зареди"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Инф. за отстр. на грешки (само за програмисти)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Необработени метаданни: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Подробности за мултимедията"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Този тип файл се отваря с/ъс"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Този файл е предоставен от"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Не е избрано"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Неизвестно"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Размери"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> – <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> мегапиксела"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Координати"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Надморска височина"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Камера"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MODEL">%2$s</xliff:g> от <xliff:g id="MAKE">%1$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Бленда"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Скорост на затвора"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Продължителност"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Заснето на"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Дължина на фокуса"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> мм"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Еквивалент на ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO: <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Изпълнител"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Композитор"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Албум"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Местоположение"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Типове поточно предаване"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Необработен размер (байтове)"</string>
+</resources>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 4c4f7a8..17c4c22 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Компресиране"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Извличане в/ъв…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Преименуване"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Получаване на информация"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Получаване на информация"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Преглед в/ъв <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Нов прозорец"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Изрязване"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Преместване"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Отхвърляне"</string>
     <string name="button_retry" msgid="4011461781916631389">"Нов опит"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Изчистване"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Показване чрез доставчик"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Несортирани"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Име"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Обобщена информация"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Размер"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Променено"</string>
     <string name="directory_items" msgid="6645621978998614003">"Брой елементи"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Този тип файл се отваря с/ъс"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Този файл принадлежи на"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Други приложения могат да отварят този тип файлове. Изчистване"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"на стандартното."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Изчистване"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Показване чрез доставчик"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Не е избрано"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Неизвестно"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Възходящ ред"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Низходящ ред"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Показване на основните елементи"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Файлът не може да се отвори"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Файловете в архиви не могат да се отварят"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Някои документи не могат да бъдат изтрити"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Свойствата не можаха да се заредят"</string>
     <string name="share_via" msgid="8725082736005677161">"Споделяне чрез"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Копиране на файлове"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Файловете се компресират"</string>
@@ -119,11 +112,11 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> елемент се изтрива.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Отмяна"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Подготвя се за копиране…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Подготвя се за компресиране…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Извличането се подготвя…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Преместването се подготвя…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Подготвя се за изтриване..."</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Подготвя се..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Подготвя се..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Подготвя се..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Подготвя се..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Подготвя се..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> елемента не можаха да бъдат копирани</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"<xliff:g id="EXTENSION">%s</xliff:g> архивен файл"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Да се презапише ли <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Продължаване на заден план"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Инф. за отстр. на грешки (само за програмисти)"</string>
 </resources>
diff --git a/res/values-bn/inspector_strings.xml b/res/values-bn/inspector_strings.xml
new file mode 100644
index 0000000..a9d1049
--- /dev/null
+++ b/res/values-bn/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"তথ্য"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"ফাইলের তথ্য লোড করা যায়নি"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"ত্রুটি সারানোর তথ্য (শুধুমাত্র ডেভেলপারের জন্য)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"RAW মেটাডেটা: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"মিডিয়ার বিশদ বিবরণ"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"এই ধরনের ফাইল এই অ্যাপ দিয়ে খোলা যায়"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"এই ফাইলের সরবরাহকারী"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"বেছে নেওয়া হয়নি"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"অজানা"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"দৈর্ঘ্য-প্রস্থ"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"স্থানাঙ্ক"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"সমুদ্রপৃষ্ঠ থেকে উচ্চতা"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"ক্যামেরা"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"অ্যাপারচার"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"শাটার স্পিড"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"সময়কাল"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"তোলার তারিখ"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"ফোকাল লেংথ"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO ইকুইভ্যালেন্ট"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"শিল্পী"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"সুরকার"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"অ্যালবাম"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"লোকেশন"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"স্ট্রিমের ধরন"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"RAW এর সাইজ (বাইট)"</string>
+</resources>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index a356399..c154558 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"সঙ্কুচিত করুন"</string>
     <string name="menu_extract" msgid="8171946945982532262">"এখানে রাখুন…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"পুনঃনামকরণ"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"তথ্য পান"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"তথ্য পান"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"<xliff:g id="SOURCE">%1$s</xliff:g> এ দেখুন"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"নতুন উইন্ডো"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"কাট করুন"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"সরান"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"খারিজ করুন"</string>
     <string name="button_retry" msgid="4011461781916631389">"আবার চেষ্টা করুন"</string>
+    <string name="button_clear" msgid="5412304437764369441">"সাফ করুন"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"প্রদানকারীতে দেখুন"</string>
     <string name="not_sorted" msgid="7813496644889115530">"সাজানো নেই"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"নাম"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"সারাংশ"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"আকার"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"শেষ সংশোধিত"</string>
     <string name="directory_items" msgid="6645621978998614003">"আইটেমের সংখ্যা"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"এই ধরণের ফাইল এই অ্যাপ দিয়ে খোলা যায়"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"এই ফাইলটি এখানকার"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"এই ধরণের ফাইল অন্য অ্যাপ দিয়েও খোলা যাবে। এই অ্যাপটি ডিফল্ট"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"অ্যাপের জায়গা থেকে সরান।"</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"সরান"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"প্রদানকারীতে দেখুন"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"বেছে নেওয়া হয়নি"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"অজানা"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"ঊর্ধ্বক্রম"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"নিম্নক্রম"</string>
     <string name="drawer_open" msgid="8071673398187261741">"রুটগুলি দেখান"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"ফাইল খোলা যাবে না"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"আর্কাইভের ফাইলগুলি খোলা যাচ্ছে না"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"কিছু দস্তাবেজ মোছা গেল না"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"বৈশিষ্ট্যগুলি লোড করা যায়নি"</string>
     <string name="share_via" msgid="8725082736005677161">"এর মাধ্যমে শেয়ার করুন"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"ফাইলগুলি কপি করা হচ্ছে"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"ফাইলগুলি"</string>
@@ -119,11 +112,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টি আইটেম মুছে দেওয়া হচ্ছে।</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"পূর্বাবস্থায় ফিরুন"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"কপি করার জন্য প্রস্তুত হচ্ছে…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"সঙ্কুচিত করার জন্য প্রস্তুত করা হচ্ছে…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"বের করার জন্য প্রস্তুতি চলছে…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"সরানোর জন্য প্রস্তুত হচ্ছে…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"মোছার জন্য প্রস্তুত হচ্ছে…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"প্রস্তুত হচ্ছে…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"প্রস্তুত হচ্ছে…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"প্রস্তুত হচ্ছে…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"প্রস্তুত হচ্ছে…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"প্রস্তুত হচ্ছে…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টি আইটেম কপি করা হয়নি</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"সংরক্ষণ<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"<xliff:g id="NAME">%1$s</xliff:g> ওভাররাইট করবেন?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"পটভূমিতে চালিয়ে যান"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"ত্রুটি সারানোর তথ্য (শুধুমাত্র ডেভেলপারের জন্য)"</string>
 </resources>
diff --git a/res/values-bs/inspector_strings.xml b/res/values-bs/inspector_strings.xml
new file mode 100644
index 0000000..3668ec8
--- /dev/null
+++ b/res/values-bs/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Informacije"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Informacije o fajlu nisu učitane"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Informacije o otklanjanju grešaka (samo dev)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Raw metapodaci: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Detalji o medijima"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Ovu vrstu fajlova otvara aplikacija"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Fajl pruža"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Nije odabrano"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Nepoznato"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Dimenzije"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Koordinate"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Visina"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Kamera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Blenda"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Brzina zatvarača"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Trajanje"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Vrijeme snimanja"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Žižna daljina"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO ekvivalent"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Umjetnik"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Kompozitor"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Album"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Lokacija"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Vrste prijenosa"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Raw veličina (bajta)"</string>
+</resources>
diff --git a/res/values-bs/mimes.xml b/res/values-bs/mimes.xml
new file mode 100644
index 0000000..ab0aecf
--- /dev/null
+++ b/res/values-bs/mimes.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2017 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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="generic_extention_file_type" msgid="5947398320635880291">"<xliff:g id="EXTENSION">%1$s</xliff:g> fajl"</string>
+    <string name="generic_file_type" msgid="1415477154743494280">"Fajl"</string>
+    <string name="image_file_type" msgid="3011633523704887793">"Slika"</string>
+    <string name="image_extension_file_type" msgid="992617216367594851">"<xliff:g id="FILETYPE">%1$s</xliff:g> slika"</string>
+    <string name="audio_file_type" msgid="3790525543519624632">"Zvuk"</string>
+    <string name="audio_extension_file_type" msgid="6334293531796491314">"<xliff:g id="FILETYPE">%1$s</xliff:g> audio"</string>
+    <string name="video_file_type" msgid="7290473366042482095">"Videozapis"</string>
+    <string name="video_extension_file_type" msgid="6352763029831291433">"<xliff:g id="FILETYPE">%1$s</xliff:g> videozapis"</string>
+    <string name="archive_file_type" msgid="1463432996680398798">"<xliff:g id="FILETYPE">%1$s</xliff:g> arhiva"</string>
+    <string name="apk_file_type" msgid="6004275470389462277">"Android aplikacija"</string>
+    <string name="txt_file_type" msgid="4677767777860724696">"Obični tekst"</string>
+    <string name="html_file_type" msgid="2034229603117527970">"HTML dokument"</string>
+    <string name="pdf_file_type" msgid="3382260303795039988">"PDF dokument"</string>
+    <string name="word_file_type" msgid="2366349268129894972">"Word dokument"</string>
+    <string name="ppt_file_type" msgid="2570841599899893925">"PowerPoint prezentacija"</string>
+    <string name="excel_file_type" msgid="8363932635044575463">"Tabela u Excelu"</string>
+    <string name="gdoc_file_type" msgid="242328101061228382">"Google dokument"</string>
+    <string name="gsheet_file_type" msgid="8055591929133067952">"Google tabela"</string>
+    <string name="gslides_file_type" msgid="8359750985956690177">"Google prezentacija"</string>
+    <string name="gdraw_file_type" msgid="655688091676820371">"Google crtež"</string>
+    <string name="gtable_file_type" msgid="7332773878374650335">"Google tabela"</string>
+    <string name="gform_file_type" msgid="4803176103746107611">"Google obrazac"</string>
+    <string name="gmap_file_type" msgid="6684180781808007016">"Google Mapa"</string>
+    <string name="gsite_file_type" msgid="3742812051249149526">"Google web lokacija"</string>
+    <string name="directory_type" msgid="2702987727566226354">"Folder"</string>
+</resources>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index de60404..8625c7e 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -33,15 +33,15 @@
     <string name="menu_open_with" msgid="5507647065467520229">"Otvori koristeći"</string>
     <string name="menu_open_in_new_window" msgid="6686563636123311276">"Otvori u novom prozoru"</string>
     <string name="menu_save" msgid="5195367497138965168">"Sačuvaj"</string>
-    <string name="menu_share" msgid="4307140947108068356">"Podijeli"</string>
+    <string name="menu_share" msgid="4307140947108068356">"Dijeli"</string>
     <string name="menu_delete" msgid="1022254131543256626">"Izbriši"</string>
     <string name="menu_select_all" msgid="7600576812185570403">"Odaberi sve"</string>
-    <string name="menu_copy" msgid="7404820171352314754">"Kopiraj na…"</string>
+    <string name="menu_copy" msgid="7404820171352314754">"Kopiraj u…"</string>
     <string name="menu_move" msgid="2310760789561129882">"Premjesti u…"</string>
     <string name="menu_compress" msgid="37539111904724188">"Kompresiraj"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Izdvoji u…"</string>
-    <string name="menu_rename" msgid="1883113442688817554">"Preimenuj"</string>
-    <string name="menu_inspector" msgid="8633147986551632467">"Svojstva"</string>
+    <string name="menu_rename" msgid="1883113442688817554">"Promijeni naziv"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Prikaži informacije"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Prikaži u usluzi <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Novi prozor"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Izreži"</string>
@@ -57,13 +57,15 @@
     <string name="button_move" msgid="8596460499325291272">"Premjesti"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Odbaci"</string>
     <string name="button_retry" msgid="4011461781916631389">"Pokušajte ponovo"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Obriši"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Prikaži u pružaocu"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Nije poredano"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Ime"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Sažetak"</string>
     <string name="sort_dimension_file_type" msgid="5779709622922085381">"Vrsta"</string>
     <string name="sort_dimension_size" msgid="2190547351159472884">"Veličina"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Izmijenjeno"</string>
-    <string name="directory_children" msgid="8115290268549503262">"Broj djece"</string>
+    <string name="directory_items" msgid="6645621978998614003">"Broj stavki"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Rastuće"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Opadajuće"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Prikaži korijenske fordere"</string>
@@ -82,8 +84,7 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Nije moguće otvoriti fajl"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Nije moguće otvoriti fajlove u arhivama"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Nije moguće izbrisati neke dokumente"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Svojstva nisu učitana"</string>
-    <string name="share_via" msgid="8725082736005677161">"Podijeli koristeći aplikaciju"</string>
+    <string name="share_via" msgid="8725082736005677161">"Dijeli pomoću aplikacije"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Kopiraju se fajlovi"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Kompresovanje fajlova"</string>
     <string name="extract_notification_title" msgid="5067393961754430469">"Izdvajanje fajlova"</string>
@@ -116,11 +117,11 @@
       <item quantity="other">Briše se <xliff:g id="COUNT_1">%1$d</xliff:g> stavki.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Opozovi radnju"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Priprema se kopiranje…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Priprema za kompresiranje…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Priprema za izdvajanje…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Priprema za premještanje…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Priprema za brisanje…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Pripremanje…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Pripremanje…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Pripremanje…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Pripremanje…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Pripremanje…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one">Kopiranje <xliff:g id="COUNT_1">%1$d</xliff:g> stavke nije uspjelo</item>
@@ -181,7 +182,7 @@
     </plurals>
     <string name="file_operation_rejected" msgid="4301554203329008794">"Nije podržana operacija za fajl."</string>
     <string name="file_operation_error" msgid="2234357335716533795">"Operacija za fajl nije uspjela."</string>
-    <string name="rename_error" msgid="6700093173508118635">"Dokument nije preimenovan"</string>
+    <string name="rename_error" msgid="6700093173508118635">"Promjena naziva dokumenta nije uspjela"</string>
     <string name="menu_eject_root" msgid="9215040039374893613">"Izbaci"</string>
     <string name="notification_copy_files_converted_title" msgid="6916768494891833365">"Neki fajlovi su pretvoreni u drugi format"</string>
     <string name="open_external_dialog_request" msgid="8173558471322861268">"Želite li aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> odobriti pristup direktoriju <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> na pohrani <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
diff --git a/res/values-ca/inspector_strings.xml b/res/values-ca/inspector_strings.xml
new file mode 100644
index 0000000..329f950
--- /dev/null
+++ b/res/values-ca/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Informació"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"No s\'ha pogut carregar la informació del fitxer"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Informació de depuració (per a desenvolupadors)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Metadades sense processar: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Dades multimèdia"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Aquest tipus de fitxer s\'obre amb"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Aquest fitxer prové de:"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"No s\'ha seleccionat"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Desconeguda"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Dimensions"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>: <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> Mpx"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Coordenades"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Altitud"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Càmera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Obertura"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Velocitat de l\'obturador"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Durada"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Data de la foto:"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Distància focal"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Equivalent d\'ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Artista"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Compositor"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Àlbum"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Ubicació"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Tipus de fluxos"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Mida sense processar (bytes)"</string>
+</resources>
diff --git a/res/values-ca/mimes.xml b/res/values-ca/mimes.xml
index ab35d69..e856a9a 100644
--- a/res/values-ca/mimes.xml
+++ b/res/values-ca/mimes.xml
@@ -40,6 +40,6 @@
     <string name="gtable_file_type" msgid="7332773878374650335">"Taula de Google"</string>
     <string name="gform_file_type" msgid="4803176103746107611">"Formulari de Google"</string>
     <string name="gmap_file_type" msgid="6684180781808007016">"Mapa de Google"</string>
-    <string name="gsite_file_type" msgid="3742812051249149526">"Lloc web de Google"</string>
+    <string name="gsite_file_type" msgid="3742812051249149526">"Lloc de Google"</string>
     <string name="directory_type" msgid="2702987727566226354">"Carpeta"</string>
 </resources>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 3f80655..eaad34e 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Comprimeix"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Extreu a…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Canvia el nom"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Obtén informació"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Obtén informació"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Mostra a <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Finestra nova"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Retalla"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Mou"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Ignora"</string>
     <string name="button_retry" msgid="4011461781916631389">"Torna-ho a provar"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Esborra"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Mostra al proveïdor"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Sense ordenar"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Nom"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Resum"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Mida"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Modificat"</string>
     <string name="directory_items" msgid="6645621978998614003">"Nombre d\'elements"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Aquest tipus de fitxer s\'obre amb"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Aquest fitxer pertany a"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Hi ha altres aplicacions que poden obrir aquest tipus de fitxer. Esborra"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"com a aplicació predeterminada."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Esborra"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Mostra al proveïdor"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"No s\'ha seleccionat"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Desconeguda"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Ascendent"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Descendent"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Mostra les arrels"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"No es pot obrir el fitxer"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"No es poden obrir els fitxers dels arxius"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"No es poden suprimir alguns documents"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"No s\'han pogut carregar les propietats"</string>
     <string name="share_via" msgid="8725082736005677161">"Comparteix mitjançant"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"S\'estan copiant fitxers"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Comprimint els fitxers"</string>
@@ -119,11 +112,11 @@
       <item quantity="one">S\'està suprimint <xliff:g id="COUNT_0">%1$d</xliff:g> element.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Desfés"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"S\'està preparant per copiar…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"S\'està preparant la compressió…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Preparant per a l\'extracció…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"S\'està preparant per moure\'ls…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"S\'està preparant per suprimir…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"S\'està preparant..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"S\'està preparant..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"S\'està preparant..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"S\'està preparant..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"S\'està preparant..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other">No s\'han pogut copiar <xliff:g id="COUNT_1">%1$d</xliff:g> elements</item>
@@ -179,7 +172,7 @@
     <string name="open_external_dialog_request" msgid="8173558471322861268">"Vols que l\'aplicació <xliff:g id="APPNAME"><b>^1</b></xliff:g> tingui accés al directori <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> de <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
     <string name="open_external_dialog_request_primary_volume" msgid="2240992164087948176">"Vols que l\'aplicació <xliff:g id="APPNAME"><b>^1</b></xliff:g> tingui accés al directori <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
     <string name="open_external_dialog_root_request" msgid="6776729293982633">"Vols que l\'aplicació <xliff:g id="APPNAME"><b>^1</b></xliff:g> tingui accés a les dades de <xliff:g id="STORAGE"><i>^2</i></xliff:g>, incloses les fotos i els vídeos?"</string>
-    <string name="never_ask_again" msgid="525908236522201138">"No m\'ho demanis més"</string>
+    <string name="never_ask_again" msgid="525908236522201138">"No m\'ho tornis a preguntar"</string>
     <string name="allow" msgid="1275746941353040309">"Permet"</string>
     <string name="deny" msgid="5127201668078153379">"Denega"</string>
     <plurals name="elements_selected" formatted="false" msgid="4448165978637163692">
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"fitxer<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Vols sobreescriure <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Continua en segon pla"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Informació de depuració (per a desenvolupadors)"</string>
 </resources>
diff --git a/res/values-cs/inspector_strings.xml b/res/values-cs/inspector_strings.xml
new file mode 100644
index 0000000..95705e1
--- /dev/null
+++ b/res/values-cs/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Informace"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Informace o souboru nelze načíst"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Informace o ladění (pouze vývojáři)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Metadata souboru RAW: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Podrobnosti o mediálním obsahu"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Tento typ souborů se otevírá pomocí aplikace"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Poskytovatel souboru:"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Nevybráno"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Neznámé"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Rozměry"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> × <xliff:g id="HEIGHT">%2$d</xliff:g> – <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> Mpx"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Souřadnice"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Výška"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Fotoaparát"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Clona"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Rychlost závěrky"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Doba trvání"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Pořízeno"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Ohnisková vzdálenost"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Ekvivalent ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Interpret"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Skladatel"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Album"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Místo"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Typy streamů"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Velikost souboru RAW (bajty)"</string>
+</resources>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 2482b27..ac50d49 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Zkomprimovat"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Rozbalit do…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Přejmenovat"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Zobrazit informace"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Zobrazit informace"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Zobrazit ve službě <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Nové okno"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Vyjmout"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Přesunout"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Zavřít"</string>
     <string name="button_retry" msgid="4011461781916631389">"Zkusit znovu"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Vymazat"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Zobrazit u poskytovatele"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Neřazeno"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Název"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Souhrn"</string>
@@ -64,21 +66,13 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Velikost"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Změněno"</string>
     <string name="directory_items" msgid="6645621978998614003">"Počet položek"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Tento typ souborů se otevírá pomocí aplikace"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Tento soubor patří do:"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Tento typ souboru mohou otevřít i jiné aplikace. Vymazat"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"jako výchozí."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Vymazat"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Zobrazit u poskytovatele"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Nevybráno"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Neznámé"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Vzestupně"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Sestupně"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Zobrazit kořeny"</string>
     <string name="drawer_close" msgid="4263880768630848848">"Skrýt kořeny"</string>
     <string name="save_error" msgid="8631128801982095782">"Uložení dokumentu se nezdařilo"</string>
     <string name="create_error" msgid="3092144450044861994">"Složku se nepodařilo vytvořit"</string>
-    <string name="query_error" msgid="6625421453613879336">"Obsah nyní nelze načíst"</string>
+    <string name="query_error" msgid="6625421453613879336">"Obsah teď nelze načíst"</string>
     <string name="root_recent" msgid="1080156975424341623">"Nedávné"</string>
     <string name="root_available_bytes" msgid="8269870862691408864">"Volný prostor: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
     <string name="root_type_service" msgid="6521366147466512289">"Služby úložiště"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Soubor nelze otevřít"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Soubory v archivu nelze otevírat"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Některé dokumenty nelze smazat"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Vlastnosti nelze načíst"</string>
     <string name="share_via" msgid="8725082736005677161">"Sdílet pomocí"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Kopírování souborů"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Komprimace souborů"</string>
@@ -129,11 +122,11 @@
       <item quantity="one">Mazání <xliff:g id="COUNT_0">%1$d</xliff:g> položky</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Vrátit zpět"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Příprava na kopírování…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Příprava na komprimaci…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Příprava na rozbalení…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Příprava na přesunutí…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Příprava na mazání…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Příprava..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Příprava..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Příprava..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Příprava..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Příprava..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="few"> <xliff:g id="COUNT_1">%1$d</xliff:g> položky nebylo možné zkopírovat</item>
@@ -255,5 +248,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"archiv<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Přepsat soubor <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Pokračovat na pozadí"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Informace o ladění (pouze vývojáři)"</string>
 </resources>
diff --git a/res/values-da/inspector_strings.xml b/res/values-da/inspector_strings.xml
new file mode 100644
index 0000000..582e9d1
--- /dev/null
+++ b/res/values-da/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Oplysninger"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Filoplysningerne kunne ikke indlæses"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Oplysninger om fejlretning (kun på enheden)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"RAW-metadata: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Medieoplysninger"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Denne filtype åbnes med"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Denne fil leveres af"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Ikke valgt"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Ukendt"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Mål"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> – <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Koordinater"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Højde"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Kamera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Blænde"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Lukkertid"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Varighed"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Taget den"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Fokuslængde"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Tilsvarende ISO-hastighed"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Musiker"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Komponist"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Album"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Placering"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Streamingtyper"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"RAW-størrelse (i bytes)"</string>
+</resources>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 4fb0579..af1488e 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Komprimer"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Pak ud i…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Omdøb"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Få oplysninger"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Få oplysninger"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Se i <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Nyt vindue"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Klip"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Flyt"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Afvis"</string>
     <string name="button_retry" msgid="4011461781916631389">"Prøv igen"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Ryd"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Vis i udbyders tjeneste"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Ikke sorteret"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Navn"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Oversigt"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Størrelse"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Ændret"</string>
     <string name="directory_items" msgid="6645621978998614003">"Antal elementer"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Denne slags fil åbnes med"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Denne fil tilhører"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Andre apps, der kan åbne denne filtype. Ryd"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"som standard."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Ryd"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Vis i udbyder"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Ikke valgt"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Ukendt"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Stigende rækkefølge"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Faldende rækkefølge"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Vis rødder"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Filen kan ikke åbnes"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Filer i arkiver kan ikke åbnes"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Nogle dokumenter kan ikke slettes"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Ejendommene kunne ikke indlæses"</string>
     <string name="share_via" msgid="8725082736005677161">"Del via"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Kopierer filer"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Komprimerer filer"</string>
@@ -119,11 +112,11 @@
       <item quantity="other">Sletter <xliff:g id="COUNT_1">%1$d</xliff:g> elementer.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Fortryd"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Forbereder kopiering…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Gør klar til komprimering…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Forbereder udpakningen…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Forbereder flytning…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Forbereder til sletning…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Forbereder…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Forbereder…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Forbereder…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Forbereder…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Forbereder…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> af <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> element kunne ikke kopieres</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"arkiv<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Vil du overskrive <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Fortsæt i baggrunden"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Oplysninger om fejlretning (kun på enheden)"</string>
 </resources>
diff --git a/res/values-de/inspector_strings.xml b/res/values-de/inspector_strings.xml
new file mode 100644
index 0000000..9a8356d
--- /dev/null
+++ b/res/values-de/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Informationen"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Dateiinformationen konnten nicht geladen werden"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Infos zur Fehlersuche (nur für Entwickler)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Unkomprimierte Metadaten: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Mediendetails"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Dieser Dateityp wird mit der folgenden App geöffnet:"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Diese Datei wird bereitgestellt von"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Nicht ausgewählt"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Unbekannt"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Abmessungen"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> – <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Koordinaten"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Höhe"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Kamera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Blende"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Belichtungszeit"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Dauer"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Aufgenommen am"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Brennweite"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO-Äquivalent"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Interpret"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Komponist"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Album"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Standort"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Streamingtypen"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Unkomprimierte Größe (Byte)"</string>
+</resources>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 35f7c97..ecfb105 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Komprimieren"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Extrahieren nach…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Umbenennen"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Weitere Informationen"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Weitere Informationen"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"In <xliff:g id="SOURCE">%1$s</xliff:g> ansehen"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Neues Fenster"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Ausschneiden"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Verschieben"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Schließen"</string>
     <string name="button_retry" msgid="4011461781916631389">"Wiederholen"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Löschen"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"In App des Anbieters anzeigen"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Nicht sortiert"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Name"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Zusammenfassung"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Größe"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Geändert"</string>
     <string name="directory_items" msgid="6645621978998614003">"Anzahl der Elemente"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Dieser Dateityp wird mit der folgenden App geöffnet:"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Diese Datei gehört zu"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Dieser Dateityp kann von anderen Apps geöffnet werden. Mit dieser Einstellung wird festgelegt, dass"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"nicht mehr die Standardapp ist."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Löschen"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"In Anbieter anzeigen"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Nicht ausgewählt"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Unbekannt"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Aufsteigend"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Absteigend"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Root-Verzeichnis anzeigen"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Datei kann nicht geöffnet werden"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Dateien in Archiven können nicht geöffnet werden"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Einige Dokumente konnten nicht gelöscht werden"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Eigenschaften konnten nicht geladen werden"</string>
     <string name="share_via" msgid="8725082736005677161">"Teilen über"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Dateien werden kopiert"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Dateien werden komprimiert"</string>
@@ -119,11 +112,11 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> Element wird gelöscht.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Rückgängig"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Kopieren wird vorbereitet…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Vorbereitung für Komprimierung…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Dekomprimierung wird vorbereitet"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Verschieben wird vorbereitet…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Löschen wird vorbereitet…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Wird vorbereitet…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Wird vorbereitet…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Wird vorbereitet…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Wird vorbereitet…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Wird vorbereitet…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> Elemente konnten nicht kopiert werden</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"archiv<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"<xliff:g id="NAME">%1$s</xliff:g> überschreiben?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Im Hintergrund fortsetzen"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Fehlerbehebungs-Infos (nur für Entwickler)"</string>
 </resources>
diff --git a/res/values-el/inspector_strings.xml b/res/values-el/inspector_strings.xml
new file mode 100644
index 0000000..7731009
--- /dev/null
+++ b/res/values-el/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Πληροφορίες"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Δεν ήταν δυνατή η φόρτωση των πληροφοριών αρχείου"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Πληροφορίες εντοπισμού σφαλμάτων (μόνο προγρ.)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Μη επεξεργασμένα μεταδεδομένα: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Λεπτομέρειες μέσων"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Αυτός ο τύπος αρχείου ανοίγει με"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Αυτό το αρχείο παρέχεται από"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Δεν έχει επιλεγεί"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Άγνωστη"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Διαστάσεις"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Συντεταγμένες"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Υψόμετρο"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Κάμερα"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Διάφραγμα"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Ταχύτητα κλείστρου"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Διάρκεια"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Λήψη στις"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Εστιακό μήκος"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> χλστ."</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Ισοδύναμο ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Καλλιτέχνης"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Συνθέτης"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Άλμπουμ"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Τοποθεσία"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Τύποι ροής"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Μη επεξεργασμένο μέγεθος (byte)"</string>
+</resources>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 8ab9c78..c0ac823 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Συμπίεση"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Εξαγωγή σε…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Μετονομασία"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Λήψη πληροφοριών"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Λήψη πληροφοριών"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Προβολή σε <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Νέο παράθυρο"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Αποκοπή"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Μετακίνηση"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Παράβλεψη"</string>
     <string name="button_retry" msgid="4011461781916631389">"Δοκιμάστε ξανά"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Διαγραφή"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Εμφάνιση στον πάροχο"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Χωρίς ταξινόμηση"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Όνομα"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Σύνοψη"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Μέγεθος"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Τροποποιημένα"</string>
     <string name="directory_items" msgid="6645621978998614003">"Αριθμός στοιχείων"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Αυτός ο τύπος αρχείου ανοίγει με"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Αυτό το αρχείο ανήκει σε"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Είναι δυνατό το άνοιγμα αυτού του τύπου αρχείου από άλλες εφαρμογές. Διαγραφή"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"ως προεπιλογή."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Διαγραφή"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Εμφάνιση στον πάροχο"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Δεν έχει επιλεγεί"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Άγνωστη"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Αύξουσα"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Φθίνουσα"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Εμφάνιση ριζών"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Δεν είναι δυνατό το άνοιγμα του αρχείου"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Αδύνατο άνοιγμα αρχείων σε αρχειοθήκες"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Δεν είναι δυνατή η διαγραφή ορισμένων εγγράφων"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Η φόρτωση των ιδιοτήτων δεν ήταν δυνατή"</string>
     <string name="share_via" msgid="8725082736005677161">"Κοινοποίηση μέσω"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Αντιγραφή αρχείων"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Συμπίεση αρχείων"</string>
@@ -119,11 +112,11 @@
       <item quantity="one">Διαγραφή <xliff:g id="COUNT_0">%1$d</xliff:g> στοιχείου.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Αναίρεση"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Προετοιμασία για αντιγραφή…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Προετοιμασία για συμπίεση…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Προετοιμασία για εξαγωγή…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Προετοιμασία για μετακίνηση…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Προετοιμασία για διαγραφή…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Προετοιμασία…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Προετοιμασία…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Προετοιμασία…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Προετοιμασία…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Προετοιμασία…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other">Δεν ήταν δυνατή η αντιγραφή <xliff:g id="COUNT_1">%1$d</xliff:g> στοιχείων</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"αρχειοθέτηση<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Αντικατάσταση <xliff:g id="NAME">%1$s</xliff:g>;"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Συνέχεια στο παρασκήνιο"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Πληροφορίες εντοπισμού σφαλμάτων (μόνο προγρ.)"</string>
 </resources>
diff --git a/res/values-en-rAU/inspector_strings.xml b/res/values-en-rAU/inspector_strings.xml
new file mode 100644
index 0000000..89d9e75
--- /dev/null
+++ b/res/values-en-rAU/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Info"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"File info could not be loaded"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Debug info (dev only)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Raw metadata: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Media details"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"This kind of file opens with"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"This file is supplied by"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Not selected"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Unknown"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Dimensions"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Coordinates"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Altitude"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Camera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Aperture"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Shutter speed"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Duration"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Taken on"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Focal length"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO equivalent"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Artist"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Composer"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Album"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Location"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Stream types"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Raw size (bytes)"</string>
+</resources>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 9008852..315a5af 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Compress"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Extract to…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Rename"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Get info"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Get info"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"View in <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"New window"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Cut"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Move"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Dismiss"</string>
     <string name="button_retry" msgid="4011461781916631389">"Try again"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Clear"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Show in provider"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Not sorted"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Name"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Summary"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Size"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Modified"</string>
     <string name="directory_items" msgid="6645621978998614003">"Number of items"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"This kind of file opens with"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"This file belongs to"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Other apps can open this file type. Clear"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"as the default."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Clear"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Show in provider"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Not selected"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Unknown"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Ascending"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Descending"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Show roots"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Can’t open file"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Cannot open files in archives"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Unable to delete some documents"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Properties could not be loaded"</string>
     <string name="share_via" msgid="8725082736005677161">"Share via"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Copying files"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Compressing files"</string>
@@ -119,11 +112,11 @@
       <item quantity="one">Deleting <xliff:g id="COUNT_0">%1$d</xliff:g> item.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Undo"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Preparing for copy…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Preparing for compress…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Preparing for extract…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Preparing for move…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Preparing to delete…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Preparing..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Preparing..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Preparing..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Preparing..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Preparing..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other">Couldn’t copy <xliff:g id="COUNT_1">%1$d</xliff:g> items</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"archive<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Overwrite <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Continue in background"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Debug info (dev only)"</string>
 </resources>
diff --git a/res/values-en-rCA/inspector_strings.xml b/res/values-en-rCA/inspector_strings.xml
new file mode 100644
index 0000000..89d9e75
--- /dev/null
+++ b/res/values-en-rCA/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Info"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"File info could not be loaded"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Debug info (dev only)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Raw metadata: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Media details"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"This kind of file opens with"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"This file is supplied by"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Not selected"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Unknown"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Dimensions"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Coordinates"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Altitude"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Camera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Aperture"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Shutter speed"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Duration"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Taken on"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Focal length"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO equivalent"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Artist"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Composer"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Album"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Location"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Stream types"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Raw size (bytes)"</string>
+</resources>
diff --git a/res/values-en-rCA/mimes.xml b/res/values-en-rCA/mimes.xml
new file mode 100644
index 0000000..7b10dd4
--- /dev/null
+++ b/res/values-en-rCA/mimes.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2017 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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="generic_extention_file_type" msgid="5947398320635880291">"<xliff:g id="EXTENSION">%1$s</xliff:g> file"</string>
+    <string name="generic_file_type" msgid="1415477154743494280">"File"</string>
+    <string name="image_file_type" msgid="3011633523704887793">"Image"</string>
+    <string name="image_extension_file_type" msgid="992617216367594851">"<xliff:g id="FILETYPE">%1$s</xliff:g> image"</string>
+    <string name="audio_file_type" msgid="3790525543519624632">"Audio"</string>
+    <string name="audio_extension_file_type" msgid="6334293531796491314">"<xliff:g id="FILETYPE">%1$s</xliff:g> audio"</string>
+    <string name="video_file_type" msgid="7290473366042482095">"Video"</string>
+    <string name="video_extension_file_type" msgid="6352763029831291433">"<xliff:g id="FILETYPE">%1$s</xliff:g> video"</string>
+    <string name="archive_file_type" msgid="1463432996680398798">"<xliff:g id="FILETYPE">%1$s</xliff:g> archive"</string>
+    <string name="apk_file_type" msgid="6004275470389462277">"Android application"</string>
+    <string name="txt_file_type" msgid="4677767777860724696">"Plain text"</string>
+    <string name="html_file_type" msgid="2034229603117527970">"HTML document"</string>
+    <string name="pdf_file_type" msgid="3382260303795039988">"PDF document"</string>
+    <string name="word_file_type" msgid="2366349268129894972">"Word document"</string>
+    <string name="ppt_file_type" msgid="2570841599899893925">"PowerPoint presentation"</string>
+    <string name="excel_file_type" msgid="8363932635044575463">"Excel spreadsheet"</string>
+    <string name="gdoc_file_type" msgid="242328101061228382">"Google document"</string>
+    <string name="gsheet_file_type" msgid="8055591929133067952">"Google spreadsheet"</string>
+    <string name="gslides_file_type" msgid="8359750985956690177">"Google presentation"</string>
+    <string name="gdraw_file_type" msgid="655688091676820371">"Google drawing"</string>
+    <string name="gtable_file_type" msgid="7332773878374650335">"Google table"</string>
+    <string name="gform_file_type" msgid="4803176103746107611">"Google form"</string>
+    <string name="gmap_file_type" msgid="6684180781808007016">"Google map"</string>
+    <string name="gsite_file_type" msgid="3742812051249149526">"Google site"</string>
+    <string name="directory_type" msgid="2702987727566226354">"Folder"</string>
+</resources>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..8ffcdbc
--- /dev/null
+++ b/res/values-en-rCA/strings.xml
@@ -0,0 +1,209 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="files_label" msgid="771781190045103748">"Files"</string>
+    <string name="downloads_label" msgid="5462789470049501103">"Downloads"</string>
+    <!-- no translation found for app_label (8089292432455111409) -->
+    <skip />
+    <!-- no translation found for launcher_label (799410258349837668) -->
+    <skip />
+    <string name="title_open" msgid="3165686459158020921">"Open from"</string>
+    <string name="title_save" msgid="4384490653102710025">"Save to"</string>
+    <string name="menu_create_dir" msgid="2413624798689091042">"New folder"</string>
+    <string name="menu_grid" msgid="1453636521731880680">"Grid view"</string>
+    <string name="menu_list" msgid="6714267452146410402">"List View"</string>
+    <string name="menu_search" msgid="1876699106790719849">"Search"</string>
+    <string name="menu_settings" msgid="6520844520117939047">"Storage settings"</string>
+    <string name="menu_open" msgid="9092138100049759315">"Open"</string>
+    <string name="menu_open_with" msgid="5507647065467520229">"Open with"</string>
+    <string name="menu_open_in_new_window" msgid="6686563636123311276">"Open in new window"</string>
+    <string name="menu_save" msgid="5195367497138965168">"Save"</string>
+    <string name="menu_share" msgid="4307140947108068356">"Shared"</string>
+    <string name="menu_delete" msgid="1022254131543256626">"Delete"</string>
+    <string name="menu_select_all" msgid="7600576812185570403">"Select all"</string>
+    <string name="menu_copy" msgid="7404820171352314754">"Copy to…"</string>
+    <string name="menu_move" msgid="2310760789561129882">"Move to…"</string>
+    <string name="menu_compress" msgid="37539111904724188">"Compress"</string>
+    <string name="menu_extract" msgid="8171946945982532262">"Extract to…"</string>
+    <string name="menu_rename" msgid="1883113442688817554">"Rename"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Get info"</string>
+    <string name="menu_view_in_owner" msgid="7228948660557554770">"View in <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+    <string name="menu_new_window" msgid="2947837751796109126">"New window"</string>
+    <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Cut"</string>
+    <string name="menu_copy_to_clipboard" msgid="5064081159073330776">"Copy"</string>
+    <string name="menu_paste_from_clipboard" msgid="360947260414135827">"Paste"</string>
+    <string name="menu_paste_into_folder" msgid="8000644546983240101">"Paste into folder"</string>
+    <string name="menu_advanced_show" msgid="7558626506462906726">"Show internal storage"</string>
+    <string name="menu_advanced_hide" msgid="6488381508009246334">"Hide internal storage"</string>
+    <string name="button_select" msgid="240863497069321364">"Select"</string>
+    <string name="button_copy" msgid="8219059853840996027">"Copy"</string>
+    <string name="button_compress" msgid="8951561310857223966">"Compress"</string>
+    <string name="button_extract" msgid="1038674453689912247">"Extract"</string>
+    <string name="button_move" msgid="8596460499325291272">"Move"</string>
+    <string name="button_dismiss" msgid="7235249361023803349">"Dismiss"</string>
+    <string name="button_retry" msgid="4011461781916631389">"Try again"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Clear"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Show in provider"</string>
+    <string name="not_sorted" msgid="7813496644889115530">"Not sorted"</string>
+    <string name="sort_dimension_name" msgid="6325591541414177579">"Name"</string>
+    <string name="sort_dimension_summary" msgid="7724534446881397860">"Summary"</string>
+    <string name="sort_dimension_file_type" msgid="5779709622922085381">"Type:"</string>
+    <string name="sort_dimension_size" msgid="2190547351159472884">"Size"</string>
+    <string name="sort_dimension_date" msgid="4231005651895254033">"Modified"</string>
+    <string name="directory_items" msgid="6645621978998614003">"Number of items"</string>
+    <string name="sort_direction_ascending" msgid="5882787683763248102">"Ascending"</string>
+    <string name="sort_direction_descending" msgid="1729187589765894076">"Descending"</string>
+    <string name="drawer_open" msgid="8071673398187261741">"Show roots"</string>
+    <string name="drawer_close" msgid="4263880768630848848">"Hide roots"</string>
+    <string name="save_error" msgid="8631128801982095782">"Failed to save document"</string>
+    <string name="create_error" msgid="3092144450044861994">"Failed to create folder"</string>
+    <string name="query_error" msgid="6625421453613879336">"Can’t load content at the moment"</string>
+    <string name="root_recent" msgid="1080156975424341623">"Recent"</string>
+    <string name="root_available_bytes" msgid="8269870862691408864">"<xliff:g id="SIZE">%1$s</xliff:g> free"</string>
+    <string name="root_type_service" msgid="6521366147466512289">"Storage services"</string>
+    <string name="root_type_shortcut" msgid="6059343175525442279">"Shortcuts"</string>
+    <string name="root_type_device" msgid="1713604128005476585">"Devices"</string>
+    <string name="root_type_apps" msgid="8646073235029886342">"More apps"</string>
+    <string name="empty" msgid="5300254272613103004">"No items"</string>
+    <string name="no_results" msgid="2371026325236359209">"No matches in %1$s"</string>
+    <string name="toast_no_application" msgid="7555319548595113121">"Can’t open file"</string>
+    <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Cannot open files in archives"</string>
+    <string name="toast_failed_delete" msgid="3453846588205817591">"Unable to delete some documents"</string>
+    <string name="share_via" msgid="8725082736005677161">"Share via"</string>
+    <string name="copy_notification_title" msgid="52256435625098456">"Copying files"</string>
+    <string name="compress_notification_title" msgid="6830195148113751021">"Compressing files"</string>
+    <string name="extract_notification_title" msgid="5067393961754430469">"Extracting files"</string>
+    <string name="move_notification_title" msgid="3173424987049347605">"Moving files"</string>
+    <string name="delete_notification_title" msgid="2512757431856830792">"Deleting files"</string>
+    <string name="copy_remaining" msgid="5390517377265177727">"<xliff:g id="DURATION">%s</xliff:g> left"</string>
+    <plurals name="copy_begin" formatted="false" msgid="151184708996738192">
+      <item quantity="other">Copying <xliff:g id="COUNT_1">%1$d</xliff:g> items.</item>
+      <item quantity="one">Copying <xliff:g id="COUNT_0">%1$d</xliff:g> item.</item>
+    </plurals>
+    <plurals name="compress_begin" formatted="false" msgid="3534158317098678895">
+      <item quantity="other">Compressing <xliff:g id="COUNT_1">%1$d</xliff:g> files.</item>
+      <item quantity="one">Compressing <xliff:g id="COUNT_0">%1$d</xliff:g> file.</item>
+    </plurals>
+    <plurals name="extract_begin" formatted="false" msgid="1006380679562903749">
+      <item quantity="other">Extracting <xliff:g id="COUNT_1">%1$d</xliff:g> files.</item>
+      <item quantity="one">Extracting <xliff:g id="COUNT_0">%1$d</xliff:g> file.</item>
+    </plurals>
+    <plurals name="move_begin" formatted="false" msgid="1464229874265756956">
+      <item quantity="other">Moving <xliff:g id="COUNT_1">%1$d</xliff:g> items.</item>
+      <item quantity="one">Moving <xliff:g id="COUNT_0">%1$d</xliff:g> item.</item>
+    </plurals>
+    <plurals name="deleting" formatted="false" msgid="1729138001178158901">
+      <item quantity="other">Deleting <xliff:g id="COUNT_1">%1$d</xliff:g> items.</item>
+      <item quantity="one">Deleting <xliff:g id="COUNT_0">%1$d</xliff:g> item.</item>
+    </plurals>
+    <string name="undo" msgid="2902438994196400565">"Undo"</string>
+    <string name="copy_preparing" msgid="5326063807006898223">"Preparing for copy…"</string>
+    <string name="compress_preparing" msgid="6650018601382062672">"Preparing for compress…"</string>
+    <string name="extract_preparing" msgid="58266275455027829">"Preparing for extract…"</string>
+    <string name="move_preparing" msgid="8742573245485449429">"Preparing for move…"</string>
+    <string name="delete_preparing" msgid="6513863752916028147">"Preparing to delete…"</string>
+    <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
+    <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
+      <item quantity="other">Couldn’t copy <xliff:g id="COUNT_1">%1$d</xliff:g> items</item>
+      <item quantity="one">Couldn’t copy <xliff:g id="COUNT_0">%1$d</xliff:g> item</item>
+    </plurals>
+    <plurals name="compress_error_notification_title" formatted="false" msgid="3043630066678213644">
+      <item quantity="other">Couldn’t compress <xliff:g id="COUNT_1">%1$d</xliff:g> files</item>
+      <item quantity="one">Couldn’t compress <xliff:g id="COUNT_0">%1$d</xliff:g> file</item>
+    </plurals>
+    <plurals name="move_error_notification_title" formatted="false" msgid="2185736082411854754">
+      <item quantity="other">Couldn’t move <xliff:g id="COUNT_1">%1$d</xliff:g> items</item>
+      <item quantity="one">Couldn’t move <xliff:g id="COUNT_0">%1$d</xliff:g> item</item>
+    </plurals>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7568122018481625267">
+      <item quantity="other">Couldn’t delete <xliff:g id="COUNT_1">%1$d</xliff:g> items</item>
+      <item quantity="one">Couldn’t delete <xliff:g id="COUNT_0">%1$d</xliff:g> item</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="2385563502445129570">"Tap to view details"</string>
+    <string name="close" msgid="905969391788869975">"Close"</string>
+    <plurals name="copy_failure_alert_content" formatted="false" msgid="5570549471912990536">
+      <item quantity="other">These files weren’t copied: <xliff:g id="LIST_1">%1$s</xliff:g></item>
+      <item quantity="one">This file wasn’t copied: <xliff:g id="LIST_0">%1$s</xliff:g></item>
+    </plurals>
+    <plurals name="compress_failure_alert_content" formatted="false" msgid="5760632881868842400">
+      <item quantity="other">These files weren’t compressed: <xliff:g id="LIST_1">%1$s</xliff:g></item>
+      <item quantity="one">This file wasn’t compressed: <xliff:g id="LIST_0">%1$s</xliff:g></item>
+    </plurals>
+    <plurals name="extract_failure_alert_content" formatted="false" msgid="7572748127571720803">
+      <item quantity="other">These files weren’t extracted: <xliff:g id="LIST_1">%1$s</xliff:g></item>
+      <item quantity="one">This file wasn’t extracted: <xliff:g id="LIST_0">%1$s</xliff:g></item>
+    </plurals>
+    <plurals name="move_failure_alert_content" formatted="false" msgid="2747390342670799196">
+      <item quantity="other">These files weren’t moved: <xliff:g id="LIST_1">%1$s</xliff:g></item>
+      <item quantity="one">This file wasn’t moved: <xliff:g id="LIST_0">%1$s</xliff:g></item>
+    </plurals>
+    <plurals name="delete_failure_alert_content" formatted="false" msgid="6122372614839711711">
+      <item quantity="other">These files weren’t deleted: <xliff:g id="LIST_1">%1$s</xliff:g></item>
+      <item quantity="one">This file wasn’t deleted: <xliff:g id="LIST_0">%1$s</xliff:g></item>
+    </plurals>
+    <plurals name="copy_converted_warning_content" formatted="false" msgid="7433742181712126588">
+      <item quantity="other">These files were converted to another format: <xliff:g id="LIST_1">%1$s</xliff:g></item>
+      <item quantity="one">This file was converted to another format: <xliff:g id="LIST_0">%1$s</xliff:g></item>
+    </plurals>
+    <plurals name="clipboard_files_clipped" formatted="false" msgid="4847061634862926902">
+      <item quantity="other">Copied <xliff:g id="COUNT_1">%1$d</xliff:g> items to clipboard.</item>
+      <item quantity="one">Copied <xliff:g id="COUNT_0">%1$d</xliff:g> item to clipboard.</item>
+    </plurals>
+    <string name="file_operation_rejected" msgid="4301554203329008794">"File operation is not supported."</string>
+    <string name="file_operation_error" msgid="2234357335716533795">"File operation failed."</string>
+    <string name="rename_error" msgid="6700093173508118635">"Failed to rename document"</string>
+    <string name="menu_eject_root" msgid="9215040039374893613">"Eject"</string>
+    <string name="notification_copy_files_converted_title" msgid="6916768494891833365">"Some files were converted"</string>
+    <string name="open_external_dialog_request" msgid="8173558471322861268">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> directory on <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="2240992164087948176">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> directory?"</string>
+    <string name="open_external_dialog_root_request" msgid="6776729293982633">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to your data, including photos and videos, on <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="never_ask_again" msgid="525908236522201138">"Don\'t ask again"</string>
+    <string name="allow" msgid="1275746941353040309">"Allow"</string>
+    <string name="deny" msgid="5127201668078153379">"Deny"</string>
+    <plurals name="elements_selected" formatted="false" msgid="4448165978637163692">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selected</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selected</item>
+    </plurals>
+    <plurals name="elements_dragged" formatted="false" msgid="5932571296037626279">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> items</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> item</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="8338069763240613258">"Delete \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="9084085260877704140">"Delete folder \"<xliff:g id="NAME">%1$s</xliff:g>\" and its contents?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="4866664063250034142">
+      <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> files?</item>
+      <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="1028946402799686388">
+      <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> folders and their contents?</item>
+      <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> folder and its contents?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="7285090426511028179">
+      <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> items?</item>
+      <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> item?</item>
+    </plurals>
+    <string name="images_shortcut_label" msgid="2545168016070493574">"Images"</string>
+    <string name="archive_loading_failed" msgid="7243436722828766996">"Unable to open archive for browsing. File is either corrupt or an unsupported format."</string>
+    <string name="name_conflict" msgid="28407269328862986">"A file with this name already exists."</string>
+    <string name="authentication_required" msgid="8030880723643436099">"To view this directory, sign in to <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="cant_display_content" msgid="8633226333229417237">"Can’t display contents"</string>
+    <string name="sign_in" msgid="6253762676723505592">"Sign in"</string>
+    <string name="new_archive_file_name" msgid="1604650338077249838">"archive<xliff:g id="EXTENSION">%s</xliff:g>"</string>
+    <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Overwrite <xliff:g id="NAME">%1$s</xliff:g>?"</string>
+    <string name="continue_in_background" msgid="1974214559047793331">"Continue in background"</string>
+</resources>
diff --git a/res/values-en-rGB/inspector_strings.xml b/res/values-en-rGB/inspector_strings.xml
new file mode 100644
index 0000000..89d9e75
--- /dev/null
+++ b/res/values-en-rGB/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Info"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"File info could not be loaded"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Debug info (dev only)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Raw metadata: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Media details"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"This kind of file opens with"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"This file is supplied by"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Not selected"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Unknown"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Dimensions"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Coordinates"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Altitude"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Camera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Aperture"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Shutter speed"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Duration"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Taken on"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Focal length"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO equivalent"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Artist"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Composer"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Album"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Location"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Stream types"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Raw size (bytes)"</string>
+</resources>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 9008852..315a5af 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Compress"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Extract to…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Rename"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Get info"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Get info"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"View in <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"New window"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Cut"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Move"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Dismiss"</string>
     <string name="button_retry" msgid="4011461781916631389">"Try again"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Clear"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Show in provider"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Not sorted"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Name"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Summary"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Size"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Modified"</string>
     <string name="directory_items" msgid="6645621978998614003">"Number of items"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"This kind of file opens with"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"This file belongs to"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Other apps can open this file type. Clear"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"as the default."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Clear"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Show in provider"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Not selected"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Unknown"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Ascending"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Descending"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Show roots"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Can’t open file"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Cannot open files in archives"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Unable to delete some documents"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Properties could not be loaded"</string>
     <string name="share_via" msgid="8725082736005677161">"Share via"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Copying files"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Compressing files"</string>
@@ -119,11 +112,11 @@
       <item quantity="one">Deleting <xliff:g id="COUNT_0">%1$d</xliff:g> item.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Undo"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Preparing for copy…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Preparing for compress…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Preparing for extract…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Preparing for move…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Preparing to delete…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Preparing..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Preparing..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Preparing..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Preparing..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Preparing..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other">Couldn’t copy <xliff:g id="COUNT_1">%1$d</xliff:g> items</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"archive<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Overwrite <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Continue in background"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Debug info (dev only)"</string>
 </resources>
diff --git a/res/values-en-rIN/inspector_strings.xml b/res/values-en-rIN/inspector_strings.xml
new file mode 100644
index 0000000..89d9e75
--- /dev/null
+++ b/res/values-en-rIN/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Info"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"File info could not be loaded"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Debug info (dev only)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Raw metadata: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Media details"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"This kind of file opens with"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"This file is supplied by"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Not selected"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Unknown"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Dimensions"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Coordinates"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Altitude"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Camera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Aperture"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Shutter speed"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Duration"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Taken on"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Focal length"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO equivalent"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Artist"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Composer"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Album"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Location"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Stream types"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Raw size (bytes)"</string>
+</resources>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 9008852..315a5af 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Compress"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Extract to…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Rename"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Get info"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Get info"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"View in <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"New window"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Cut"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Move"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Dismiss"</string>
     <string name="button_retry" msgid="4011461781916631389">"Try again"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Clear"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Show in provider"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Not sorted"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Name"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Summary"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Size"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Modified"</string>
     <string name="directory_items" msgid="6645621978998614003">"Number of items"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"This kind of file opens with"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"This file belongs to"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Other apps can open this file type. Clear"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"as the default."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Clear"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Show in provider"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Not selected"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Unknown"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Ascending"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Descending"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Show roots"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Can’t open file"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Cannot open files in archives"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Unable to delete some documents"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Properties could not be loaded"</string>
     <string name="share_via" msgid="8725082736005677161">"Share via"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Copying files"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Compressing files"</string>
@@ -119,11 +112,11 @@
       <item quantity="one">Deleting <xliff:g id="COUNT_0">%1$d</xliff:g> item.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Undo"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Preparing for copy…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Preparing for compress…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Preparing for extract…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Preparing for move…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Preparing to delete…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Preparing..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Preparing..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Preparing..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Preparing..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Preparing..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other">Couldn’t copy <xliff:g id="COUNT_1">%1$d</xliff:g> items</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"archive<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Overwrite <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Continue in background"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Debug info (dev only)"</string>
 </resources>
diff --git a/res/values-en-rXC/inspector_strings.xml b/res/values-en-rXC/inspector_strings.xml
new file mode 100644
index 0000000..ace8d48
--- /dev/null
+++ b/res/values-en-rXC/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‏‎‏‏‎‎‎‎‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‎‎‏‎‎‎‏‏‏‎‏‎‏‏‎‎‏‏‎‎‎‎‏‎‎‏‏‏‎‎Info‎‏‎‎‏‎"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‎‎‏‎‎‎‎‏‏‎‎‎‎‎‎‏‎‏‏‎‎‎‎‎‎‏‏‏‏‏‎‎‎‏‏‏‎‎‏‎‎‏‏‎‏‎‎‎‎‏‎‏‏‎File info could not be loaded‎‏‎‎‏‎"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‎‏‏‏‏‏‏‎‎‏‏‎‎‏‎‎‏‎‎‎‏‎‏‎Debug info (dev only)‎‏‎‎‏‎"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‎‏‎‎‎‏‎‏‏‎‎‎‏‎‏‎‏‎‎‎‏‎‎‎‎‏‏‏‎‏‎‏‎‎‎‎‏‏‎‎‎‎‎‎‏‏‎‎‎‏‏‏‎‎Raw metadata: ‎‏‎‎‏‏‎<xliff:g id="METADATATYPE">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‏‎‏‏‎‎‎‎‎‎‎‏‏‎‏‎‏‏‏‏‎‏‎‎‎‏‎‎‎‎‏‎‎‎‎‏‏‏‎‎‏‎‎‏‎‏‏‏‎‏‏‏‏‏‏‎Media details‎‏‎‎‏‎"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‏‎‏‎‏‏‎‎‎‏‎‎‏‏‏‏‎‏‎‏‏‎‎‏‏‎‏‎‏‎‎‎‎‎‎‎‎‎‎‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎This kind of file opens with‎‏‎‎‏‎"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‎‏‏‏‎‏‏‎‎‎‏‏‎‏‎‎‏‎‎‎‏‏‏‎‏‏‏‎‎‎‎‏‎‎‎‎‏‏‎‎‏‎‎‏‎‎‎‏‏‎‎‎‏‎This file is supplied by‎‏‎‎‏‎"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎‏‏‎‏‎‎‏‎‏‎‏‏‎‏‎‏‏‏‏‎‎‎‏‎‎‎‏‏‏‎‎‏‏‏‎‏‏‎‎‏‎‎Not selected‎‏‎‎‏‎"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‎‏‎‏‎‎‏‏‏‎‎‎‎‏‏‎‏‎‏‏‏‎‎‏‏‏‎‏‏‎‏‎‏‏‎‎‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‏‏‎Unknown‎‏‎‎‏‎"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‎‏‎‏‎‏‏‎‏‎‎‏‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎‎‎‏‎‎‏‎‏‏‎‏‎‏‎‏‏‎‎‏‎Dimensions‎‏‎‎‏‎"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‏‎‎‎‏‎‏‎‎‎‏‏‏‎‎‎‎‏‎‎‏‎‎‎‏‎‏‎‎‏‏‎‎‏‏‎‏‏‏‎‎‏‏‎‎‎‏‎‎‏‎‏‎‎‎‏‎‎‏‏‎<xliff:g id="WIDTH">%1$d</xliff:g>‎‏‎‎‏‏‏‎ x ‎‏‎‎‏‏‎<xliff:g id="HEIGHT">%2$d</xliff:g>‎‏‎‎‏‏‏‎ - ‎‏‎‎‏‏‎<xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>‎‏‎‎‏‏‏‎MP‎‏‎‎‏‎"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‎‏‏‎‏‏‎‎‎‎‎‎‎‎‏‎‏‏‎‏‏‎‎‏‎‏‎‏‏‎‎‎‎‎‏‏‏‏‎‎‎‏‏‏‎‎Coordinates‎‏‎‎‏‎"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‎‏‏‏‎‏‏‏‎‏‏‏‏‎‏‎‏‎‎‏‎‏‏‎‏‎‏‏‏‎‏‏‏‏‎‏‏‎‏‎‏‎‎‏‏‎‏‎‏‎‏‏‎‎‎‏‎‎‏‎‎‏‏‎<xliff:g id="LATITUDE">%1$,.3f</xliff:g>‎‏‎‎‏‏‏‎, ‎‏‎‎‏‏‎<xliff:g id="LONGITUDE">%2$,.3f</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‏‎‎‎‎‎‏‏‎‏‏‏‎‏‎‏‎‎‏‎‎‏‏‏‎‏‏‎‎‎‏‎‏‎‎‏‏‎‏‏‎‏‏‎‎Altitude‎‏‎‎‏‎"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‎‎‏‎‏‏‎‎‎‏‏‎‎‎‏‏‎‏‎‏‎‏‎‎‎‎‏‏‎‎‎‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‎‎‏‎‎‏‏‏‎Camera‎‏‎‎‏‎"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‏‏‏‎‏‎‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‏‏‎‏‏‏‏‎‏‎‏‏‎‏‏‏‏‏‎‏‏‎‎‏‎‎‏‏‏‏‎‎‎‎‏‎‎‏‏‎<xliff:g id="MAKE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ ‎‏‎‎‏‏‎<xliff:g id="MODEL">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‏‏‏‏‏‎‎‏‎‎‎‏‏‏‎‎‏‎‏‎‎‏‏‎‎‎‏‎‎‎‏‎‎‏‎‎‎‎‎‏‏‎‏‎‎‎‎‎‏‏‏‏‎‏‎Aperture‎‏‎‎‏‎"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‏‎‎‎‏‎‏‏‏‎‏‏‏‎‏‎‎‎‏‏‏‎‏‏‎‎‎‎‏‎‎‎‎‎‎‏‎‎‎‏‏‏‎‏‏‎‎‏‏‎Shutter speed‎‏‎‎‏‎"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‎‎‏‏‏‏‎‎‎‏‏‏‎‏‎‏‏‎‏‎‏‎‏‏‏‎‎‏‎‏‏‎‎‏‎‏‎‎‏‏‏‏‎‎‏‏‏‎‎‏‎‎‏‎‏‏‎Duration‎‏‎‎‏‎"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎‎‏‎‎‎‎‏‏‎‏‏‎‏‎‎‏‎‏‎‎‎‏‏‏‎‎‎‎‏‏‏‏‎‎‏‏‎‏‎‏‏‏‎‎‎‏‎‏‏‏‎‎‏‏‎‎Taken on‎‏‎‎‏‎"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‎‏‏‏‏‏‎‏‏‏‎‏‏‎‏‎‏‎Focal length‎‏‎‎‏‎"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‏‎‎‎‎‎‎‏‎‎‎‎‏‎‎‏‎‏‎‎‎‏‏‎‎‎‏‎‏‎‎‎‏‏‏‎‏‏‎‏‏‏‏‏‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="LENGTH">%1$.2f </xliff:g>‎‏‎‎‏‏‏‎mm‎‏‎‎‏‎"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‏‎‏‏‎‏‏‎‏‎‏‏‎‎‎‎‎‏‎‏‏‎‎‏‎‏‏‏‎‏‏‏‏‎‏‎‏‎‏‏‎‎‎‏‏‏‏‎‏‎‎‏‎‎ISO equivalent‎‏‎‎‏‎"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‏‎‎‎‏‏‎‏‏‎‏‏‏‎‏‏‏‎‎‎‏‏‎‏‎‏‎‏‎‎‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‎ISO ‎‏‎‎‏‏‎<xliff:g id="ISO_SPEED">%1$d</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‎‎‎‏‏‏‎‎‎‏‏‏‎‎‏‏‎‏‏‎‏‎‎‏‎‏‏‏‏‎‏‏‏‎‏‎‏‏‎‎‎‎‏‏‏‏‏‏‎‎‎Artist‎‏‎‎‏‎"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‏‎‏‏‏‎‏‏‎‏‎‏‏‎‎‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‎‎‏‎‎‎‎‏‏‎‏‎‎‏‏‏‎‎‎‎Composer‎‏‎‎‏‎"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‎‎‎‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‏‎‏‎‏‏‎‏‏‎‏‎‎‏‎‏‏‏‏‏‎‎‏‎‎‎‏‏‎‎‏‏‏‎‏‏‎‎‎Album‎‏‎‎‏‎"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‏‎‏‎‏‏‎‎‎‎‏‏‏‏‎‏‎‏‎‏‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‎‎‎‎‏‎‎‎‏‎‎‏‏‎‎‎‎‎‎‎‎Location‎‏‎‎‏‎"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‏‏‏‏‏‎‎‎‎‎‏‎‎‏‏‎‎‎‎‏‏‏‎‏‎‎‎‏‎‏‎‎‎‎‏‎‏‎‎‏‎‎‎‏‎‏‎‎‏‎‎‎‏‎‏‎Stream types‎‏‎‎‏‎"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‏‎‎‏‏‏‎‏‎‏‎‏‏‎‎‎‏‏‎‎‎‏‏‎‏‎‏‎‎‏‏‎‎‏‎‏‏‎‎‎‏‎‎‏‎Raw size (bytes)‎‏‎‎‏‎"</string>
+</resources>
diff --git a/res/values-en-rXC/mimes.xml b/res/values-en-rXC/mimes.xml
new file mode 100644
index 0000000..43489a9
--- /dev/null
+++ b/res/values-en-rXC/mimes.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2017 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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="generic_extention_file_type" msgid="5947398320635880291">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‎‏‎‎‏‎‏‏‎‎‏‏‏‎‏‎‎‎‎‏‏‎‎‎‎‏‏‏‏‎‏‎‎‎‎‎‏‏‎‏‎‎‎‏‏‎‏‏‎‎‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="EXTENSION">%1$s</xliff:g>‎‏‎‎‏‏‏‎ file‎‏‎‎‏‎"</string>
+    <string name="generic_file_type" msgid="1415477154743494280">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‏‎‏‎‎‏‎‎‏‏‎‎‏‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‎‏‎‎‎‎‏‎‏‎‏‎‏‎‏‎‎‏‏‎‏‎‎‎‏‎‎‎‎File‎‏‎‎‏‎"</string>
+    <string name="image_file_type" msgid="3011633523704887793">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‎‎‏‎‏‏‎‏‏‏‏‎‎‎‏‎‏‏‏‎‏‏‏‏‎‎‎‏‏‎‎‎‎‏‎‏‏‎‎‏‏‏‏‎‎‏‏‏‏‏‎‎‎‏‎Image‎‏‎‎‏‎"</string>
+    <string name="image_extension_file_type" msgid="992617216367594851">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‏‏‎‎‎‏‏‎‎‏‏‏‏‏‎‎‎‎‎‏‏‎‎‏‎‏‏‎‎‎‏‏‏‎‎‎‎‏‏‏‎‎‎‎‏‏‎‏‎‏‏‎‎‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="FILETYPE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ image‎‏‎‎‏‎"</string>
+    <string name="audio_file_type" msgid="3790525543519624632">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‎‏‏‎‏‎‏‎‏‎‎‏‏‎‏‏‏‎‎‏‏‎‎‎‎‏‎‏‎‏‏‎‎‎‏‎‎‎‎‎‎‏‏‏‎‏‏‎‏‏‏‎‎‎‎Audio‎‏‎‎‏‎"</string>
+    <string name="audio_extension_file_type" msgid="6334293531796491314">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‏‎‎‎‎‎‎‏‏‎‎‏‏‏‎‎‏‎‎‎‏‏‎‎‏‏‎‎‎‎‏‏‎‎‏‎‎‎‏‎‎‏‏‎<xliff:g id="FILETYPE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ audio‎‏‎‎‏‎"</string>
+    <string name="video_file_type" msgid="7290473366042482095">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‎‏‏‎‎‏‏‏‏‎‏‏‎‏‏‏‎‎‏‏‎‎‏‎‏‏‎‏‏‎‏‏‎‏‎‎‎‏‎‎‏‎‏‎‏‏‎‏‎‏‏‏‏‎Video‎‏‎‎‏‎"</string>
+    <string name="video_extension_file_type" msgid="6352763029831291433">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‏‎‎‏‏‎‎‎‏‏‎‎‎‏‎‏‎‎‎‏‎‎‏‏‎‏‏‏‎‏‎‏‎‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‎‎‏‎‎‏‎‎‏‏‎<xliff:g id="FILETYPE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ video‎‏‎‎‏‎"</string>
+    <string name="archive_file_type" msgid="1463432996680398798">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‎‏‏‏‏‎‎‏‎‏‎‎‎‏‎‎‎‏‏‏‎‏‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‏‎‏‏‏‏‏‎‎‏‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="FILETYPE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ archive‎‏‎‎‏‎"</string>
+    <string name="apk_file_type" msgid="6004275470389462277">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‎‏‎‎‏‏‎‏‏‏‏‎‎‎‏‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‎‎‏‎‎‏‏‏‏‏‎‎‎‏‎‏‎‎‎‎‎‏‎‏‎Android application‎‏‎‎‏‎"</string>
+    <string name="txt_file_type" msgid="4677767777860724696">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‏‎‏‎‏‎‏‏‎‎‎‏‎‏‎‎‎‎‎‎‏‎‏‎‎‏‎‏‎‏‎‎‏‎‏‎‎‎‎‎‏‎‎‏‏‏‏‏‎‏‏‎‎‎‎Plain text‎‏‎‎‏‎"</string>
+    <string name="html_file_type" msgid="2034229603117527970">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‎‎‏‏‏‎‏‏‎‎‎‎‏‎‎‏‎‎‎‎‏‎‏‏‏‏‎‏‎‏‎‏‎‏‏‎‎‏‏‏‎‏‏‏‎‎‏‏‏‎‏‎‎‎‏‎‎HTML document‎‏‎‎‏‎"</string>
+    <string name="pdf_file_type" msgid="3382260303795039988">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‏‏‎‎‎‎‎‎‏‏‎‎‏‏‏‏‎‏‎‎‏‏‏‎‎‎‏‎‎‏‏‎‎‏‏‎‏‏‏‎‏‎‏‏‏‎‏‏‏‏‎‏‎‎‎PDF document‎‏‎‎‏‎"</string>
+    <string name="word_file_type" msgid="2366349268129894972">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‎‏‎‏‏‎‏‏‏‏‎‏‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‎‏‎‏‏‎‎‎‏‏‎‏‎‏‎‎‏‎‎‎‏‏‏‏‎‎‎Word document‎‏‎‎‏‎"</string>
+    <string name="ppt_file_type" msgid="2570841599899893925">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‏‎‏‏‎‏‎‏‏‏‎‏‏‎‏‏‎‏‎‎‎‎‎‏‏‎‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‎‎‎‎‎‏‎‏‎‎‏‎‏‎PowerPoint presentation‎‏‎‎‏‎"</string>
+    <string name="excel_file_type" msgid="8363932635044575463">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‏‎‏‎‏‎‏‎‎‎‎‏‏‎‏‎‏‎‏‏‏‎‎‏‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‎‎‎‏‏‏‎‎‏‏‏‎Excel spreadsheet‎‏‎‎‏‎"</string>
+    <string name="gdoc_file_type" msgid="242328101061228382">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‏‎‏‏‏‎‎‏‏‏‎‏‏‎‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‏‏‏‎‏‏‏‎‏‎‏‏‏‏‎‎Google document‎‏‎‎‏‎"</string>
+    <string name="gsheet_file_type" msgid="8055591929133067952">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‏‎‏‏‎‎‏‏‎‏‏‎‎‎‏‎‏‏‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‏‎‏‏‏‎‏‎‏‏‎‎‎‎‎Google spreadsheet‎‏‎‎‏‎"</string>
+    <string name="gslides_file_type" msgid="8359750985956690177">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‎‏‏‏‏‎‎‏‏‎‏‎‎‏‏‏‎‏‎‏‏‎‏‏‎‎‎‏‎‏‎‏‎‏‏‏‎‎‎‏‎‎‏‎‎‎‎‎‎‎‏‎Google presentation‎‏‎‎‏‎"</string>
+    <string name="gdraw_file_type" msgid="655688091676820371">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‏‎‎‏‎‏‏‏‏‎‎‎‏‏‎‏‏‎‎‎‎‏‏‎‏‎‏‏‏‏‎‏‏‎‎‏‏‏‎‎‎‎‏‏‏‎‎‏‎‎‏‏‎Google drawing‎‏‎‎‏‎"</string>
+    <string name="gtable_file_type" msgid="7332773878374650335">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‎‎‏‏‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‏‏‏‎‏‏‎‎‏‎‎‎‏‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎Google table‎‏‎‎‏‎"</string>
+    <string name="gform_file_type" msgid="4803176103746107611">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‏‎‏‎‎‎‎‏‎‎‏‏‏‏‎‎‏‏‎‏‏‏‏‏‎‏‎‎‎‏‎‏‏‎‏‏‏‎‎‏‏‏‏‎‎‎‏‏‎‏‏‎‏‏‎Google form‎‏‎‎‏‎"</string>
+    <string name="gmap_file_type" msgid="6684180781808007016">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‎‏‎‏‏‏‏‏‎‏‏‎‎‎‎‎‎‎‏‏‎‏‏‏‎‏‎‎‎‏‎‏‎‎‎‏‎‏‏‎‏‏‏‎‏‏‎‏‎‎‎‎Google map‎‏‎‎‏‎"</string>
+    <string name="gsite_file_type" msgid="3742812051249149526">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‏‏‎‎‎‏‎‎‏‎‎‎‏‏‏‎‏‏‏‎‏‎‏‏‏‏‎‏‏‏‏‏‎‎‎‎‎‏‏‎‏‏‎‏‏‎‎‏‎‏‎‏‏‎‎Google site‎‏‎‎‏‎"</string>
+    <string name="directory_type" msgid="2702987727566226354">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‎‎‎‏‎‏‏‏‏‎‎‎‏‎‎‎‎‎‏‎‎‎‏‏‎‎‏‎‏‏‏‎‏‎‎‏‏‎‏‎‎‎‎‏‏‏‎‏‏‎‎‏‎‎Folder‎‏‎‎‏‎"</string>
+</resources>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..9e727f9
--- /dev/null
+++ b/res/values-en-rXC/strings.xml
@@ -0,0 +1,209 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="files_label" msgid="771781190045103748">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‏‎‏‏‎‏‎‏‏‏‏‎‏‎‏‎‏‏‏‎‎‏‏‏‎‎‏‏‏‏‎‎‏‏‏‏‎‏‏‏‎‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎‎Files‎‏‎‎‏‎"</string>
+    <string name="downloads_label" msgid="5462789470049501103">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‏‎‏‎‎‎‎‏‎‏‎‎‎‏‏‏‎‏‎‏‎‎‎‎‏‎‏‏‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎Downloads‎‏‎‎‏‎"</string>
+    <!-- no translation found for app_label (8089292432455111409) -->
+    <skip />
+    <!-- no translation found for launcher_label (799410258349837668) -->
+    <skip />
+    <string name="title_open" msgid="3165686459158020921">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‏‏‎‏‏‏‎‏‏‎‎‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‎‎‎‎‎‏‏‎‎‎‎‏‏‎‎‏‏‏‎‎‏‎Open from‎‏‎‎‏‎"</string>
+    <string name="title_save" msgid="4384490653102710025">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‏‏‎‎‎‏‏‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‏‎‏‏‎‏‏‎‎‏‏‎‏‎‏‎‎‎‏‏‏‎‏‎‎‎‎‏‎‎‏‎Save to‎‏‎‎‏‎"</string>
+    <string name="menu_create_dir" msgid="2413624798689091042">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‏‏‏‎‏‏‏‎‏‏‎‏‎‏‎‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‏‏‏‎‎‎‏‎‎New folder‎‏‎‎‏‎"</string>
+    <string name="menu_grid" msgid="1453636521731880680">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‏‏‎‎‎‏‎‏‏‎‏‎‏‎‏‏‎‏‏‎‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‏‏‏‏‎‏‏‎‏‏‏‎‏‎‎‎‎Grid view‎‏‎‎‏‎"</string>
+    <string name="menu_list" msgid="6714267452146410402">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‎‏‏‎‏‏‏‎‏‏‏‏‎‏‎‏‎‏‏‎‎‏‎‎‎‏‏‎‎‎‎‏‎‎‏‏‏‎‏‏‎‎‎‏‏‏‎‏‎‎‎‏‎‎List view‎‏‎‎‏‎"</string>
+    <string name="menu_search" msgid="1876699106790719849">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‎‎‎‎‏‎‏‏‎‏‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‏‎‏‎‏‎‎‎‏‏‎‏‏‏‎‎‎‎‎‏‎‏‏‎‏‎‎‏‎Search‎‏‎‎‏‎"</string>
+    <string name="menu_settings" msgid="6520844520117939047">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‏‎‎‎‏‎‏‎‏‏‎‎‏‎‎‏‎‎‏‎‏‏‏‎‏‎‏‎‏‎‏‏‎‏‏‎‎‏‏‏‎Storage settings‎‏‎‎‏‎"</string>
+    <string name="menu_open" msgid="9092138100049759315">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‏‏‎‎‎‎‏‏‎‏‏‎‏‏‏‎‎‎‎‎‎‏‏‎‎‏‎‎‎‎‏‎‏‏‎‎‏‏‎‎‎‏‎‏‎‎‏‏‎Open‎‏‎‎‏‎"</string>
+    <string name="menu_open_with" msgid="5507647065467520229">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‏‏‎‏‏‏‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‏‏‎‏‎‎‎‏‎‏‎‏‏‎‏‎‏‎‎‎‎‎‎‏‎‎‏‏‏‎‎‏‎‏‎Open with‎‏‎‎‏‎"</string>
+    <string name="menu_open_in_new_window" msgid="6686563636123311276">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‎‏‏‎‏‏‏‎‎‏‎‎‎‏‏‎‎‏‏‎‎‏‏‏‎‏‏‎‎‏‎‏‏‎‎‏‎‎‏‏‏‎‎‏‎‏‎‏‏‎‎‎Open in new window‎‏‎‎‏‎"</string>
+    <string name="menu_save" msgid="5195367497138965168">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‏‏‎‎‏‏‎‏‎‎‏‏‏‎‎‏‏‎‏‏‎‎‏‏‎‎‎‎‎‏‎‎‏‎‏‎‎‎‎‎‎‏‎‏‎‏‎‏‏‎‎‎‎‎Save‎‏‎‎‏‎"</string>
+    <string name="menu_share" msgid="4307140947108068356">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‏‏‎‎‎‏‏‎‎‎‎‎‏‎‎‏‏‏‎‏‏‏‏‏‎‎‎‎‎‏‎‏‏‏‏‎‏‎‏‎‎‏‏‏‏‏‎‎‎‎‎‎‎‏‎‎‎Share‎‏‎‎‏‎"</string>
+    <string name="menu_delete" msgid="1022254131543256626">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‎‎‏‎‏‏‏‏‏‏‎‎‎‏‏‎‏‎‏‏‎‏‏‏‎‏‏‎‏‏‎‎‏‏‎‎‏‏‏‏‏‎‏‎‏‏‏‎‎‎‏‏‎‎‏‎‎Delete‎‏‎‎‏‎"</string>
+    <string name="menu_select_all" msgid="7600576812185570403">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‏‎‏‎‏‎‏‎‏‏‎‎‎‏‎‏‎‏‏‏‎‏‎‏‎‎‏‎‎‏‏‎‎‏‎‎‎‏‎‎‏‏‎‎‎‏‏‎‎‎‏‏‎Select all‎‏‎‎‏‎"</string>
+    <string name="menu_copy" msgid="7404820171352314754">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‎‎‎‎‏‏‎‎‏‏‎‏‎‎‏‎‏‏‎‏‏‎‏‎‏‎‎‎‏‏‎‎‎‏‏‎‏‎‎‎‎‏‎‎‏‏‏‎‎‎‎‎‏‎‎Copy to…‎‏‎‎‏‎"</string>
+    <string name="menu_move" msgid="2310760789561129882">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‎‏‎‎‎‏‎‏‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‎‏‎‎‏‏‏‎‏‏‏‎‎‏‏‎‏‎‎Move to…‎‏‎‎‏‎"</string>
+    <string name="menu_compress" msgid="37539111904724188">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‎‎‎‎‏‎‏‎‏‎‏‏‏‎‏‏‎‎‏‏‏‏‏‏‎‎‏‎‏‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‎‎‏‏‎‏‏‏‎‎‎Compress‎‏‎‎‏‎"</string>
+    <string name="menu_extract" msgid="8171946945982532262">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‎‎‎‏‎‎‏‎‏‏‎‎‏‏‏‎‎‏‏‎‏‎‏‎‏‏‎‏‎‏‎‎‎‎‎‏‎‎‎‏‎‏‎‏‎‏‎‎‏‏‎‎Extract to…‎‏‎‎‏‎"</string>
+    <string name="menu_rename" msgid="1883113442688817554">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‎‎‏‎‎‎‏‎‎‎‏‎‏‎‎‏‏‎‏‏‎‎‏‎‏‏‏‎‏‏‏‏‎‎‏‏‏‎‏‎‏‏‎‏‏‎‎‏‏‎‎‏‎‎‏‎‎Rename‎‏‎‎‏‎"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎‎‏‏‏‎‎‏‏‏‏‎‏‏‏‎‏‏‏‏‎‏‎‏‎‏‏‏‏‎‎‏‏‏‎‎‎‏‎‎‎‎‎‎‏‏‏‎‏‎‎‎‎‎Get info‎‏‎‎‏‎"</string>
+    <string name="menu_view_in_owner" msgid="7228948660557554770">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‎‏‏‎‎‎‏‎‏‎‎‎‎‎‎‏‏‎‎‏‎‏‎‎‎‎‎‏‎‎‎‏‏‎‏‎‎‏‎‎‎‏‎‏‎‎‏‎‎View in ‎‏‎‎‏‏‎<xliff:g id="SOURCE">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="menu_new_window" msgid="2947837751796109126">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‏‏‏‎‏‎‎‎‏‏‎‏‎‎‏‎‏‏‎‏‎‎‎‏‎‎‏‎‎‎‏‏‎‏‎‎‏‎‏‏‎‎‎‎‏‏‏‏‎‏‎‎‎‏‏‎‎New window‎‏‎‎‏‎"</string>
+    <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‏‏‎‎‏‏‎‏‏‎‎‎‎‏‏‏‎‏‎‎‏‎‎‎‏‎‎‏‎‏‎‎‏‏‎‎‏‏‎‏‎‏‎‏‎‎‎‎‏‏‎‏‎‏‎Cut‎‏‎‎‏‎"</string>
+    <string name="menu_copy_to_clipboard" msgid="5064081159073330776">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‎‎‏‏‏‎‎‏‏‏‎‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‎‎‏‎‏‎‎‎‎‎‏‏‏‎‏‏‎‎‏‎‏‏‎‎‎‎Copy‎‏‎‎‏‎"</string>
+    <string name="menu_paste_from_clipboard" msgid="360947260414135827">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‎‎‎‎‎‎‏‎‎‏‎‏‎‏‏‏‏‎‎‏‏‏‏‎‏‏‏‏‎‏‏‏‏‎‏‎‎‎‏‎‏‎‎‎‏‏‏‎‎‎‎‏‎‎‏‏‎Paste‎‏‎‎‏‎"</string>
+    <string name="menu_paste_into_folder" msgid="8000644546983240101">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‎‎‏‎‏‎‎‎‏‏‎‏‎‎‎‏‎‎‎‎‏‏‎‏‎‎‏‎‏‎Paste into folder‎‏‎‎‏‎"</string>
+    <string name="menu_advanced_show" msgid="7558626506462906726">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‎‏‎‏‏‎‏‎‎‎‏‎‏‏‎‎‎‎‏‎‏‎‏‎‎‎‏‏‏‎‎‏‎‎‏‎‏‏‎‎‏‎‎‏‎‏‏‎‎‏‏‎‎Show internal storage‎‏‎‎‏‎"</string>
+    <string name="menu_advanced_hide" msgid="6488381508009246334">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‏‎‏‏‎‏‎‏‏‏‎‎‏‎‎‏‏‎‏‎‏‏‎‎‏‎‎‎‎‎‎‏‏‎‏‎‏‎‏‏‏‏‏‎‎‏‏‏‏‏‏‎‎Hide internal storage‎‏‎‎‏‎"</string>
+    <string name="button_select" msgid="240863497069321364">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‏‎‏‎‏‏‏‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‏‎‎‎‎‏‏‏‎‎‎‏‎‏‏‎‎‏‏‎‏‏‏‎‎‏‎‎‏‎‏‎‎‎Select‎‏‎‎‏‎"</string>
+    <string name="button_copy" msgid="8219059853840996027">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‏‎‏‏‎‏‎‏‏‏‎‏‏‎Copy‎‏‎‎‏‎"</string>
+    <string name="button_compress" msgid="8951561310857223966">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‏‎‎‏‎‏‎‏‎‏‏‎‎‏‎‏‎‏‏‎‏‏‎‏‏‎‏‏‎‎‎‏‏‎‎‏‎‏‏‏‏‏‎‎‎‏‏‏‏‎‎Compress‎‏‎‎‏‎"</string>
+    <string name="button_extract" msgid="1038674453689912247">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‎‏‏‎‏‎‏‎‎‎‎‏‏‏‎‎‏‏‏‎‏‎‎‏‏‎‎‏‏‎‎‏‎‏‏‏‎‏‎‏‏‏‎‎‏‎‏‏‏‎‏‏‎‏‏‏‎Extract‎‏‎‎‏‎"</string>
+    <string name="button_move" msgid="8596460499325291272">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‎‎‏‏‎‎‎‎‏‏‎‏‎‎‎‏‏‏‎‎‏‏‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‏‏‎‎‎‎‏‎‎‎‎Move‎‏‎‎‏‎"</string>
+    <string name="button_dismiss" msgid="7235249361023803349">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‎‏‎‎‎‏‏‎‎‎‏‎‎‏‏‏‏‎‏‎‏‏‎‏‏‏‎‎‏‎‎‏‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‎‏‎‏‎‏‎Dismiss‎‏‎‎‏‎"</string>
+    <string name="button_retry" msgid="4011461781916631389">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‏‎‏‎‏‏‏‎‎‏‎‎‏‏‎‎‏‏‏‏‎‎‏‎‏‎‏‏‎‏‎‎‏‏‎‎‏‎‎‏‎‎‎‎‎‏‎‏‎‏‏‏‎‏‎Try Again‎‏‎‎‏‎"</string>
+    <string name="button_clear" msgid="5412304437764369441">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‎‎‏‏‏‎‎‎‏‎‏‏‏‏‎‎‎‏‏‎‏‎‏‏‏‏‎‎‏‎‏‎‎‏‏‎‏‏‏‎‎‏‎‏‏‎‎‎‎‏‎‎‎‎‏‎Clear‎‏‎‎‏‎"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‎‏‏‏‎‏‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‎‏‎‎‏‏‏‏‏‏‎‎‎‏‏‏‏‎‎‎‏‎‎‎‏‎Show in provider‎‏‎‎‏‎"</string>
+    <string name="not_sorted" msgid="7813496644889115530">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‎‏‏‎‏‎‎‎‎‎‏‎‎‎‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‏‎‎‎‏‎‏‎‎Not sorted‎‏‎‎‏‎"</string>
+    <string name="sort_dimension_name" msgid="6325591541414177579">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‏‎‎‏‎‎‏‎‎‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‎‎‎‏‏‎‏‎‏‎‎‏‎‏‎‏‏‎‎‏‎‏‎‏‏‎Name‎‏‎‎‏‎"</string>
+    <string name="sort_dimension_summary" msgid="7724534446881397860">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‏‏‎‎‏‏‎‎‎‎‏‏‏‏‎‎‏‎‎‏‏‏‎‎‏‏‎‎‎‏‏‎‏‎‎‎‏‎‎‏‎‏‏‏‎‎‎‏‏‎‎‏‎‎‎Summary‎‏‎‎‏‎"</string>
+    <string name="sort_dimension_file_type" msgid="5779709622922085381">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‎‏‎‏‏‎‏‎‎‏‏‏‎‏‎‎‎‏‏‏‏‎‏‎‎‎‏‏‎‎‏‎‏‏‎‏‏‎‎‎‎‏‎‎‎‎‎‎‎‏‎‏‎Type‎‏‎‎‏‎"</string>
+    <string name="sort_dimension_size" msgid="2190547351159472884">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‏‎‎‏‏‎‎‎‏‏‎‎‏‏‎‏‎‏‏‎‏‏‏‎‎‏‏‎‎‎‏‎‎‎‏‎‎‎‎‎‏‎‏‏‏‏‎‏‎‎‎Size‎‏‎‎‏‎"</string>
+    <string name="sort_dimension_date" msgid="4231005651895254033">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‏‎‏‏‏‏‎‎‎‏‏‎‏‎‎‏‏‏‎‎‏‎‎‏‏‏‎‏‏‏‏‏‎‎‎‏‎‏‏‏‏‏‏‎‎‎‎‎‏‎‎‎‏‎Modified‎‏‎‎‏‎"</string>
+    <string name="directory_items" msgid="6645621978998614003">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‏‎‎‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‏‎‏‏‏‏‎‏‏‎‏‎‎‏‏‏‏‏‏‏‎‎‏‏‎Number of items‎‏‎‎‏‎"</string>
+    <string name="sort_direction_ascending" msgid="5882787683763248102">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‏‎‎‎‏‏‏‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‏‏‏‎‎‎‏‏‏‏‎‎‎‎‎‎‎‏‎‏‏‎‏‏‏‏‏‎‎‏‏‎‎Ascending‎‏‎‎‏‎"</string>
+    <string name="sort_direction_descending" msgid="1729187589765894076">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‏‏‏‎‎‏‏‏‎‎‎‎‏‏‎‎‎‎‎‎‎‏‎‏‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‎Descending‎‏‎‎‏‎"</string>
+    <string name="drawer_open" msgid="8071673398187261741">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‎‏‎‎‎‏‎‏‏‎‎‎‎‎‏‏‎‎‎‎‏‎‏‎‏‎‎‏‏‏‏‎‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎Show roots‎‏‎‎‏‎"</string>
+    <string name="drawer_close" msgid="4263880768630848848">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‎‎‏‎‏‏‎‎‎‏‎‏‏‎‎‎‏‏‏‏‎‏‏‏‏‏‎‏‎‎‏‎‏‏‎‏‏‏‎‎‎‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎Hide roots‎‏‎‎‏‎"</string>
+    <string name="save_error" msgid="8631128801982095782">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‎‎‏‏‎‎‏‎‎‏‎‎‏‎‎‎‎‏‏‎‏‎‎‏‏‎‎Failed to save document‎‏‎‎‏‎"</string>
+    <string name="create_error" msgid="3092144450044861994">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‏‎‏‎‎‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‎‏‏‏‏‎‏‎‎‏‏‏‏‎‎‎‏‎‏‎‏‎‎Failed to create folder‎‏‎‎‏‎"</string>
+    <string name="query_error" msgid="6625421453613879336">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‎‎‏‎‎‎‏‏‏‎‎‏‏‎‏‏‎‏‎‏‏‎‎‎‎‏‎‏‏‏‏‎‏‎‎‎‎‏‎‏‎‎‎‎‎‎‏‎‏‎‎‎‎Can’t load content at the moment‎‏‎‎‏‎"</string>
+    <string name="root_recent" msgid="1080156975424341623">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‏‏‏‏‏‎‏‎‏‏‏‏‏‎‏‎‎‎‎‏‎‏‏‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‎‎‎‎‎‎‏‏‎‎‏‏‏‎‏‏‏‎Recent‎‏‎‎‏‎"</string>
+    <string name="root_available_bytes" msgid="8269870862691408864">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‎‎‏‎‎‎‏‏‏‏‎‏‏‏‎‏‏‏‎‏‏‏‏‏‎‎‏‎‏‎‎‎‏‎‎‏‏‎‎‎‏‏‎‏‏‏‏‏‎‎‎‎‎‎‎‏‎‎‏‏‎<xliff:g id="SIZE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ free‎‏‎‎‏‎"</string>
+    <string name="root_type_service" msgid="6521366147466512289">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‎‎‎‎‎‏‎‎‎‏‎‏‏‏‏‏‏‎‏‎‏‏‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‎‏‎‎‎‎‏‎Storage services‎‏‎‎‏‎"</string>
+    <string name="root_type_shortcut" msgid="6059343175525442279">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‏‏‎‎‏‎‎‎‎‎‏‏‏‎‏‎‏‏‎‏‎‏‏‎‎‎‎‏‏‎‏‎‎‎‏‎‏‏‏‎‎‏‏‏‎Shortcuts‎‏‎‎‏‎"</string>
+    <string name="root_type_device" msgid="1713604128005476585">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‏‎‎‎‏‏‏‏‏‏‏‎‎‎‏‏‏‏‎‎‎‎‎‎‎‎‏‎‏‏‏‎‏‏‎‏‎‎‎‏‏‎‏‎‎‎‎‏‏‏‎‏‎‎‏‎Devices‎‏‎‎‏‎"</string>
+    <string name="root_type_apps" msgid="8646073235029886342">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‏‏‏‎‎‏‏‎‎‎‏‏‎‎‎‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‏‎‏‏‎‎‎‎‏‏‎‎More apps‎‏‎‎‏‎"</string>
+    <string name="empty" msgid="5300254272613103004">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‎‎‏‏‏‎‎‏‎‎‏‎‎‏‎‎‏‎‏‏‎‏‏‏‎‏‎‎‏‎‎‏‎‏‏‎‎‏‏‎‏‏‎‏‎‏‏‎‎‏‏‏‎‎‎No items‎‏‎‎‏‎"</string>
+    <string name="no_results" msgid="2371026325236359209">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‎‎‏‏‏‏‎‎‏‎‎‏‏‏‏‏‎‎‎‎‏‎‏‏‎‏‏‎‎‏‏‎‏‎‎‎‎‎‎‏‎‎‎‎‎‎‎‏‎‏‎‎‏‎No matches in %1$s‎‏‎‎‏‎"</string>
+    <string name="toast_no_application" msgid="7555319548595113121">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‏‏‎‎‏‏‏‏‎‎‎‏‏‎‎‎‏‏‎‎‏‏‎‎‎‎‎‏‎‏‎‎‏‎‎‏‏‏‎‎‎‏‏‎‎‏‎‏‎‎‎‎‏‎Can’t open file‎‏‎‎‏‎"</string>
+    <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‏‎‎‎‎‏‎‏‎‎‏‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‎‏‏‎‎‏‎‎‏‎‏‏‎‎‎‎‏‏‎‏‏‎‏‏‎‏‎Cannot open files in archives‎‏‎‎‏‎"</string>
+    <string name="toast_failed_delete" msgid="3453846588205817591">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‎‏‏‏‎‎‏‎‏‏‎‎‎‎‏‏‎‏‏‎‏‎‏‏‎‎‏‏‏‏‎‏‏‏‏‎‏‏‏‏‎‏‏‏‎Unable to delete some documents‎‏‎‎‏‎"</string>
+    <string name="share_via" msgid="8725082736005677161">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‎‏‎‏‏‎‏‏‏‎‎‎‏‎‎‎‎‏‎‏‎‏‎‏‏‎‏‏‏‎‎‎‎‎‏‏‎‎‎‎‎‎‎‎‎‏‏‎‏‎‎‏‎Share via‎‏‎‎‏‎"</string>
+    <string name="copy_notification_title" msgid="52256435625098456">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‎‏‏‏‎‎‏‏‎‏‎‎‏‏‎‏‏‏‏‎‎‏‏‏‎‎‎‏‎‏‎‏‎‏‎‏‎‎‏‎‏‏‏‏‏‎‎‏‏‎‏‏‎‎‎‎Copying files‎‏‎‎‏‎"</string>
+    <string name="compress_notification_title" msgid="6830195148113751021">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‏‎‎‏‏‎‏‏‏‎‏‎‎‏‎‎‏‏‎‎‏‎‎‏‏‏‎‏‏‏‏‎‏‎‏‎‏‎‏‎‏‎‏‏‏‏‏‎‏‏‎‏‎Compressing files‎‏‎‎‏‎"</string>
+    <string name="extract_notification_title" msgid="5067393961754430469">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‏‎‎‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‎‎‎‏‏‎‏‎‏‎‏‎‏‎‎‎‎‏‏‎‎‎‎‎‎‎‏‎‏‎Extracting files‎‏‎‎‏‎"</string>
+    <string name="move_notification_title" msgid="3173424987049347605">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‎‎‎‎‏‎‏‎‎‏‎‎‎‏‎‏‎‎‏‏‎‏‏‎‎‏‎‏‎‎‏‎‎‏‏‎‏‏‎‎‏‏‎‎‏‎‏‎‎‎‎‏‎‏‎‏‎Moving files‎‏‎‎‏‎"</string>
+    <string name="delete_notification_title" msgid="2512757431856830792">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‎‏‏‎‏‏‏‏‏‎‎‎‏‏‎‏‏‏‎‎‏‎‎‏‎‎‎‏‏‎‏‎‎‏‎‎‎‏‏‎‎‏‎‎‏‏‎‎‏‎‏‎‎‏‎‎‎‎Deleting files‎‏‎‎‏‎"</string>
+    <string name="copy_remaining" msgid="5390517377265177727">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‎‏‏‏‎‏‏‏‏‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‏‏‏‎‏‏‎‎‎‎‏‎‏‎‎‎‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="DURATION">%s</xliff:g>‎‏‎‎‏‏‏‎ left‎‏‎‎‏‎"</string>
+    <plurals name="copy_begin" formatted="false" msgid="151184708996738192">
+      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‎‎‎‏‏‎‎‏‎‎‎‏‏‏‎‏‏‎‏‏‎‎‎‏‎‎‎‏‏‎‏‏‎‎‏‏‏‎‎‎‏‎‏‎‏‏‎‎‏‎‎‏‎‎‎‎‎Copying ‎‏‎‎‏‏‎<xliff:g id="COUNT_1">%1$d</xliff:g>‎‏‎‎‏‏‏‎ items.‎‏‎‎‏‎</item>
+      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‎‎‎‏‏‎‎‏‎‎‎‏‏‏‎‏‏‎‏‏‎‎‎‏‎‎‎‏‏‎‏‏‎‎‏‏‏‎‎‎‏‎‏‎‏‏‎‎‏‎‎‏‎‎‎‎‎Copying ‎‏‎‎‏‏‎<xliff:g id="COUNT_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ item.‎‏‎‎‏‎</item>
+    </plurals>
+    <plurals name="compress_begin" formatted="false" msgid="3534158317098678895">
+      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‎‎‏‎‏‏‏‏‎‏‏‎‏‎‎‏‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‏‏‎‏‎‎‏‏‎‏‏‏‏‎Compressing ‎‏‎‎‏‏‎<xliff:g id="COUNT_1">%1$d</xliff:g>‎‏‎‎‏‏‏‎ files.‎‏‎‎‏‎</item>
+      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‎‎‏‎‏‏‏‏‎‏‏‎‏‎‎‏‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‏‏‎‏‎‎‏‏‎‏‏‏‏‎Compressing ‎‏‎‎‏‏‎<xliff:g id="COUNT_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ file.‎‏‎‎‏‎</item>
+    </plurals>
+    <plurals name="extract_begin" formatted="false" msgid="1006380679562903749">
+      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‏‏‏‏‎‏‏‏‎‏‏‎‎‎‎‏‏‏‏‎‎‏‎‏‎‏‏‎‎‎‏‎‎‎‏‎‏‎‎‏‏‏‎‎‎‎‎‎‏‏‎‎‎‏‎‏‎Extracting ‎‏‎‎‏‏‎<xliff:g id="COUNT_1">%1$d</xliff:g>‎‏‎‎‏‏‏‎ files.‎‏‎‎‏‎</item>
+      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‏‏‏‏‎‏‏‏‎‏‏‎‎‎‎‏‏‏‏‎‎‏‎‏‎‏‏‎‎‎‏‎‎‎‏‎‏‎‎‏‏‏‎‎‎‎‎‎‏‏‎‎‎‏‎‏‎Extracting ‎‏‎‎‏‏‎<xliff:g id="COUNT_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ file.‎‏‎‎‏‎</item>
+    </plurals>
+    <plurals name="move_begin" formatted="false" msgid="1464229874265756956">
+      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‎‎‎‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‎‎‏‎‏‎‏‎‎‏‎‎‎‎‎‎‎‎‏‎‏‎‏‎‎‎‏‏‏‎‎‎Moving ‎‏‎‎‏‏‎<xliff:g id="COUNT_1">%1$d</xliff:g>‎‏‎‎‏‏‏‎ items.‎‏‎‎‏‎</item>
+      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‎‎‎‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‎‎‏‎‏‎‏‎‎‏‎‎‎‎‎‎‎‎‏‎‏‎‏‎‎‎‏‏‏‎‎‎Moving ‎‏‎‎‏‏‎<xliff:g id="COUNT_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ item.‎‏‎‎‏‎</item>
+    </plurals>
+    <plurals name="deleting" formatted="false" msgid="1729138001178158901">
+      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‏‏‎‏‏‎‎‏‏‏‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‏‏‎‎‏‏‏‎‎‏‏‎‏‎‏‎Deleting ‎‏‎‎‏‏‎<xliff:g id="COUNT_1">%1$d</xliff:g>‎‏‎‎‏‏‏‎ items.‎‏‎‎‏‎</item>
+      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‏‏‎‏‏‎‎‏‏‏‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‏‏‎‎‏‏‏‎‎‏‏‎‏‎‏‎Deleting ‎‏‎‎‏‏‎<xliff:g id="COUNT_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ item.‎‏‎‎‏‎</item>
+    </plurals>
+    <string name="undo" msgid="2902438994196400565">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‎‎‎‏‏‏‏‎‎‎‏‎‎‎‏‏‏‎‎‎‏‏‎‎‏‎‏‏‏‏‎‏‎‏‎‎‎‏‏‎‎‎‏‎‎‏‏‎‏‏‎‏‎‏‎Undo‎‏‎‎‏‎"</string>
+    <string name="copy_preparing" msgid="5326063807006898223">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‎‏‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‎‎‎‎‎‏‎‏‎‎‏‏‏‎‏‏‎‏‎‏‏‏‏‏‏‎‎‎‎‎‏‎‏‏‏‏‎Preparing for copy…‎‏‎‎‏‎"</string>
+    <string name="compress_preparing" msgid="6650018601382062672">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‏‎‎‏‏‎‎‏‏‏‎‎‏‎‏‎‏‏‏‏‎‏‎‎‎‏‎‏‎‎‎‏‏‏‏‎‎‎‏‎‏‎‏‎‎‏‎‏‎‎‎‎‎Preparing for compress…‎‏‎‎‏‎"</string>
+    <string name="extract_preparing" msgid="58266275455027829">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‎‎‏‏‏‏‎‎‎‎‎‎‎‎‏‏‎‏‏‏‏‎‎‏‏‎‏‎‏‎‏‏‏‎‎‎‎‏‏‏‎‎‏‎‏‎‎‏‏‏‎‏‎‏‎Preparing for extract…‎‏‎‎‏‎"</string>
+    <string name="move_preparing" msgid="8742573245485449429">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‎‎‏‏‏‏‎‏‏‏‎‎‎‎‎‎‏‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‏‏‎‏‎‏‎‏‎Preparing for move…‎‏‎‎‏‎"</string>
+    <string name="delete_preparing" msgid="6513863752916028147">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‎‎‏‎‏‏‏‏‎‎‏‎‎‏‎‎‏‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‎‏‎‎‏‎‎‏‎‏‎‏‏‏‏‎‎‏‏‎Preparing for delete…‎‏‎‎‏‎"</string>
+    <string name="delete_progress" msgid="2627631054702306423">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‏‏‎‏‏‏‎‎‏‏‏‎‎‎‏‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‎‏‎‏‎‎‎‎‏‏‏‎‎‏‎‎‎‏‏‏‎‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="COUNT_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ / ‎‏‎‎‏‏‎<xliff:g id="TOTALCOUNT">%2$d</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
+      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‎‎‏‏‏‏‏‏‏‎‎‏‎‏‏‎‎‏‏‎‏‎‏‏‏‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‏‎‎‏‏‎Couldn’t copy ‎‏‎‎‏‏‎<xliff:g id="COUNT_1">%1$d</xliff:g>‎‏‎‎‏‏‏‎ items‎‏‎‎‏‎</item>
+      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‎‎‏‏‏‏‏‏‏‎‎‏‎‏‏‎‎‏‏‎‏‎‏‏‏‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‏‎‎‏‏‎Couldn’t copy ‎‏‎‎‏‏‎<xliff:g id="COUNT_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ item‎‏‎‎‏‎</item>
+    </plurals>
+    <plurals name="compress_error_notification_title" formatted="false" msgid="3043630066678213644">
+      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‏‏‏‏‎‏‎‎‏‎‎‏‎‏‎‏‏‎‏‎‏‏‎‏‏‏‏‎‎‎‎‎‎‎‏‏‎‏‏‎‏‎‏‏‎‎‎‎‎‎‏‏‎‎‎Couldn’t compress ‎‏‎‎‏‏‎<xliff:g id="COUNT_1">%1$d</xliff:g>‎‏‎‎‏‏‏‎ files‎‏‎‎‏‎</item>
+      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‏‏‏‏‎‏‎‎‏‎‎‏‎‏‎‏‏‎‏‎‏‏‎‏‏‏‏‎‎‎‎‎‎‎‏‏‎‏‏‎‏‎‏‏‎‎‎‎‎‎‏‏‎‎‎Couldn’t compress ‎‏‎‎‏‏‎<xliff:g id="COUNT_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ file‎‏‎‎‏‎</item>
+    </plurals>
+    <plurals name="move_error_notification_title" formatted="false" msgid="2185736082411854754">
+      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‎‏‎‏‎‏‎‏‎‎‏‎‏‏‎‏‏‎‎‎‏‎‏‏‏‎‏‏‎‎‏‏‏‎‏‎‎‏‏‎‎‏‏‎‏‏‏‎‏‎‎‎‏‎‎Couldn’t move ‎‏‎‎‏‏‎<xliff:g id="COUNT_1">%1$d</xliff:g>‎‏‎‎‏‏‏‎ items‎‏‎‎‏‎</item>
+      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‎‏‎‏‎‏‎‏‎‎‏‎‏‏‎‏‏‎‎‎‏‎‏‏‏‎‏‏‎‎‏‏‏‎‏‎‎‏‏‎‎‏‏‎‏‏‏‎‏‎‎‎‏‎‎Couldn’t move ‎‏‎‎‏‏‎<xliff:g id="COUNT_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ item‎‏‎‎‏‎</item>
+    </plurals>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7568122018481625267">
+      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‎‏‏‏‎‏‎‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‎‏‎‎‎‎‎‏‏‎‏‎‎‎‏‏‎‏‏‎‎‎‏‎‏‏‎‎‏‏‎Couldn’t delete ‎‏‎‎‏‏‎<xliff:g id="COUNT_1">%1$d</xliff:g>‎‏‎‎‏‏‏‎ items‎‏‎‎‏‎</item>
+      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‎‏‏‏‎‏‎‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‎‏‎‎‎‎‎‏‏‎‏‎‎‎‏‏‎‏‏‎‎‎‏‎‏‏‎‎‏‏‎Couldn’t delete ‎‏‎‎‏‏‎<xliff:g id="COUNT_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ item‎‏‎‎‏‎</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="2385563502445129570">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‎‏‏‎‏‏‎‎‏‏‏‎‎‏‎‏‎‏‏‏‎‏‏‏‎‎‎‎‎‎‎‏‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‏‏‎‎‎‏‎‎Tap to view details‎‏‎‎‏‎"</string>
+    <string name="close" msgid="905969391788869975">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‏‎‎‏‎‎‏‎‏‎‏‎‎‏‏‎‎‏‎‏‏‏‎‎‏‎‎‏‏‏‏‎‏‏‏‏‎‎‏‏‏‏‎‎‏‎‎‏‎‏‎‏‎‏‏‏‎Close‎‏‎‎‏‎"</string>
+    <plurals name="copy_failure_alert_content" formatted="false" msgid="5570549471912990536">
+      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‎‎‏‏‏‎‏‎‎‏‎‎‎‏‎‎‏‏‏‎‏‏‎‎‎‎‏‏‎‏‎‎‎‏‏‏‎‏‎‎‎‏‎‏‏‏‎‏‎‎‏‎‎‎‎These files weren’t copied: ‎‏‎‎‏‏‎<xliff:g id="LIST_1">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎</item>
+      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‎‎‏‏‏‎‏‎‎‏‎‎‎‏‎‎‏‏‏‎‏‏‎‎‎‎‏‏‎‏‎‎‎‏‏‏‎‏‎‎‎‏‎‏‏‏‎‏‎‎‏‎‎‎‎This file wasn’t copied: ‎‏‎‎‏‏‎<xliff:g id="LIST_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎</item>
+    </plurals>
+    <plurals name="compress_failure_alert_content" formatted="false" msgid="5760632881868842400">
+      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‎‎‎‎‏‎‎‎‏‎‏‎‏‏‎‏‏‏‏‎‏‎‎‏‏‏‎‏‎‎‎‏‎‎‏‎‏‏‎‏‎‎‎‎‎‎These files weren’t compressed: ‎‏‎‎‏‏‎<xliff:g id="LIST_1">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎</item>
+      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‎‎‎‎‏‎‎‎‏‎‏‎‏‏‎‏‏‏‏‎‏‎‎‏‏‏‎‏‎‎‎‏‎‎‏‎‏‏‎‏‎‎‎‎‎‎This file wasn’t compressed: ‎‏‎‎‏‏‎<xliff:g id="LIST_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎</item>
+    </plurals>
+    <plurals name="extract_failure_alert_content" formatted="false" msgid="7572748127571720803">
+      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‏‏‎‎‏‏‎‎‎‏‎‏‎‏‏‎‏‎‏‎‏‎‏‏‏‎‏‎‎‏‏‎‎‎‏‏‎These files weren’t extracted: ‎‏‎‎‏‏‎<xliff:g id="LIST_1">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎</item>
+      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‏‏‎‎‏‏‎‎‎‏‎‏‎‏‏‎‏‎‏‎‏‎‏‏‏‎‏‎‎‏‏‎‎‎‏‏‎This file wasn’t extracted: ‎‏‎‎‏‏‎<xliff:g id="LIST_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎</item>
+    </plurals>
+    <plurals name="move_failure_alert_content" formatted="false" msgid="2747390342670799196">
+      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‏‎‎‎‎‎‏‎‏‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‎‏‏‎‏‎‎‎‏‏‏‎‏‏‎‏‎‏‎‎‎‏‎‏‎‏‏‏‎‎‎These files weren’t moved: ‎‏‎‎‏‏‎<xliff:g id="LIST_1">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎</item>
+      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‏‎‎‎‎‎‏‎‏‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‎‏‏‎‏‎‎‎‏‏‏‎‏‏‎‏‎‏‎‎‎‏‎‏‎‏‏‏‎‎‎This file wasn’t moved: ‎‏‎‎‏‏‎<xliff:g id="LIST_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎</item>
+    </plurals>
+    <plurals name="delete_failure_alert_content" formatted="false" msgid="6122372614839711711">
+      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‏‎‏‏‏‎‎‎‎‏‎‎‏‎‏‏‏‎‏‎‎‏‎‎‏‏‎‏‎‎‎‎‏‏‎‎‏‏‎‏‏‎‏‏‏‏‏‎‏‏‏‏‏‎These files weren’t deleted: ‎‏‎‎‏‏‎<xliff:g id="LIST_1">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎</item>
+      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‏‎‏‏‏‎‎‎‎‏‎‎‏‎‏‏‏‎‏‎‎‏‎‎‏‏‎‏‎‎‎‎‏‏‎‎‏‏‎‏‏‎‏‏‏‏‏‎‏‏‏‏‏‎This file wasn’t deleted: ‎‏‎‎‏‏‎<xliff:g id="LIST_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎</item>
+    </plurals>
+    <plurals name="copy_converted_warning_content" formatted="false" msgid="7433742181712126588">
+      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‎‎‏‏‏‏‏‎‏‎‏‎‎‏‎‎‎‎‎‏‏‏‎‏‏‎‎‏‏‎‎‏‎‎‏‏‏‏‎‎‎‏‎‎‏‏‏‏‏‎‎‎These files were converted to another format: ‎‏‎‎‏‏‎<xliff:g id="LIST_1">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎</item>
+      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‎‎‏‏‏‏‏‎‏‎‏‎‎‏‎‎‎‎‎‏‏‏‎‏‏‎‎‏‏‎‎‏‎‎‏‏‏‏‎‎‎‏‎‎‏‏‏‏‏‎‎‎This file was converted to another format: ‎‏‎‎‏‏‎<xliff:g id="LIST_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎</item>
+    </plurals>
+    <plurals name="clipboard_files_clipped" formatted="false" msgid="4847061634862926902">
+      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‎‎‎‏‎‎‎‎‏‏‏‎‎‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‎‏‏‎‏‏‎‏‏‏‎‎‏‏‎‎‎‎‏‏‎‏‏‎‎Copied ‎‏‎‎‏‏‎<xliff:g id="COUNT_1">%1$d</xliff:g>‎‏‎‎‏‏‏‎ items to clipboard.‎‏‎‎‏‎</item>
+      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‎‎‎‏‎‎‎‎‏‏‏‎‎‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‎‏‏‎‏‏‎‏‏‏‎‎‏‏‎‎‎‎‏‏‎‏‏‎‎Copied ‎‏‎‎‏‏‎<xliff:g id="COUNT_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ item to clipboard.‎‏‎‎‏‎</item>
+    </plurals>
+    <string name="file_operation_rejected" msgid="4301554203329008794">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‏‏‎‎‏‎‎‎‏‏‎‎‎‎‏‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‎‎‎‎‎‏‏‏‎‎‏‎‏‎‎‏‎‎‏‏‎‏‎‎File operation is not supported.‎‏‎‎‏‎"</string>
+    <string name="file_operation_error" msgid="2234357335716533795">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‎‎‎‏‎‎‎‎‎‏‎‎‎‎‎‏‎‏‎‎‎‏‎‏‎‎‎‎‎‏‎‏‎‏‏‎‎‎‎‎‏‎‏‏‎‎‎‏‎‎‎‏‏‎File operation failed.‎‏‎‎‏‎"</string>
+    <string name="rename_error" msgid="6700093173508118635">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‎‎‏‏‏‏‏‎‎‎‏‎‎‎‎‎‏‏‏‏‏‎‎‎‏‎‎‏‏‎‎‎‎‏‏‎‏‎‏‏‎Failed to rename document‎‏‎‎‏‎"</string>
+    <string name="menu_eject_root" msgid="9215040039374893613">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‏‎‏‎‎‏‏‏‏‏‎‎‎‏‎‎‏‏‎‎‏‎‎‎‏‎‏‏‎‏‎Eject‎‏‎‎‏‎"</string>
+    <string name="notification_copy_files_converted_title" msgid="6916768494891833365">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‎‎‏‎‎‏‏‎‎‏‎‏‎‏‎‏‏‏‎‏‎‎‏‎‎‎‎‎‏‏‎‎‎‎‎‎‏‎‏‎‏‎Some files were converted‎‏‎‎‏‎"</string>
+    <string name="open_external_dialog_request" msgid="8173558471322861268">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‏‏‎‎‏‎‏‎‎‎‎‎‎‎‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‏‎‏‎‏‎‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‎Grant ‎‏‎‎‏‏‎<xliff:g id="APPNAME"><b>^1</b></xliff:g>‎‏‎‎‏‏‏‎ access to ‎‏‎‎‏‏‎<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>‎‏‎‎‏‏‏‎ directory on ‎‏‎‎‏‏‎<xliff:g id="STORAGE"><i>^3</i></xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="2240992164087948176">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‏‎‎‏‏‎‎‏‏‎‏‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‎‏‏‎‎‎‏‏‏‎‎‏‎‎‎‎‎Grant ‎‏‎‎‏‏‎<xliff:g id="APPNAME"><b>^1</b></xliff:g>‎‏‎‎‏‏‏‎ access to ‎‏‎‎‏‏‎<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>‎‏‎‎‏‏‏‎ directory?‎‏‎‎‏‎"</string>
+    <string name="open_external_dialog_root_request" msgid="6776729293982633">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‏‎‏‏‎‎‏‏‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‏‎‏‎‎‎‏‎‏‏‏‎‏‎‏‎‎‏‎Grant ‎‏‎‎‏‏‎<xliff:g id="APPNAME"><b>^1</b></xliff:g>‎‏‎‎‏‏‏‎ access to your data, including photos and videos, on ‎‏‎‎‏‏‎<xliff:g id="STORAGE"><i>^2</i></xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
+    <string name="never_ask_again" msgid="525908236522201138">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‎‏‎‎‏‏‎‎‎‏‏‎‎‏‏‎‏‏‎‎‎‎‎‏‎‎‏‏‎‏‏‎‎‏‎‏‏‎‏‏‏‎‏‎‎‎‎‎‎‎‏‏‎‎‏‎‎Don\'t ask again‎‏‎‎‏‎"</string>
+    <string name="allow" msgid="1275746941353040309">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‏‎‏‎‎‎‏‎‏‏‏‎‏‎‎‎‏‎‏‎‏‎‏‏‏‏‏‏‎‏‎‏‎‎‎‏‏‏‎‎‏‏‎‎‏‏‎‏‏‎‏‎‏‎Allow‎‏‎‎‏‎"</string>
+    <string name="deny" msgid="5127201668078153379">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‎‏‎‎‏‏‏‎‏‏‏‏‎‏‎‏‏‎‎‎‎‎‎‏‎‎‎‎‏‎‏‏‎‎‏‎‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‎‎‏‏‎Deny‎‏‎‎‏‎"</string>
+    <plurals name="elements_selected" formatted="false" msgid="4448165978637163692">
+      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‏‏‏‎‏‏‎‎‎‎‏‏‏‏‎‏‏‎‎‎‏‏‏‏‏‎‎‎‏‎‏‎‏‎‎‏‎‏‎‏‎‏‏‏‎‎‏‎‏‎‏‏‎‎‎‎‏‎‎‏‏‎<xliff:g id="COUNT_1">%1$d</xliff:g>‎‏‎‎‏‏‏‎ selected‎‏‎‎‏‎</item>
+      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‏‏‏‎‏‏‎‎‎‎‏‏‏‏‎‏‏‎‎‎‏‏‏‏‏‎‎‎‏‎‏‎‏‎‎‏‎‏‎‏‎‏‏‏‎‎‏‎‏‎‏‏‎‎‎‎‏‎‎‏‏‎<xliff:g id="COUNT_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ selected‎‏‎‎‏‎</item>
+    </plurals>
+    <plurals name="elements_dragged" formatted="false" msgid="5932571296037626279">
+      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‏‎‏‎‎‏‎‏‏‏‎‏‎‎‎‏‎‏‎‎‏‎‏‏‎‎‎‎‏‎‎‎‎‎‎‎‎‎‏‏‎‎‎‎‏‏‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="COUNT_1">%1$d</xliff:g>‎‏‎‎‏‏‏‎ items‎‏‎‎‏‎</item>
+      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‏‎‏‎‎‏‎‏‏‏‎‏‎‎‎‏‎‏‎‎‏‎‏‏‎‎‎‎‏‎‎‎‎‎‎‎‎‎‏‏‎‎‎‎‏‏‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="COUNT_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ item‎‏‎‎‏‎</item>
+    </plurals>
+    <string name="delete_filename_confirmation_message" msgid="8338069763240613258">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‎‏‏‎‏‏‎‎‎‏‏‎‎‏‎‎‎‏‎‏‏‏‎‎‏‏‏‎‎‏‏‎‎‎‎‏‏‏‎‏‎‏‎‏‏‎‎‎‏‎‏‎‎Delete \"‎‏‎‎‏‏‎<xliff:g id="NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎\"?‎‏‎‎‏‎"</string>
+    <string name="delete_foldername_confirmation_message" msgid="9084085260877704140">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‎‏‎‎‏‎‎‏‏‏‎‏‏‎‏‎‏‎‎‏‎‎‏‎‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‎‏‏‏‏‎‎‏‏‎‎‎Delete folder \"‎‏‎‎‏‏‎<xliff:g id="NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎\" and its contents?‎‏‎‎‏‎"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="4866664063250034142">
+      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‎‎‏‎‎‏‏‏‎‏‏‏‎‏‎‎‏‎‏‏‏‎‎‏‎‎‏‎‏‏‎‎‏‎‏‏‎‏‎‏‏‎‏‏‎‏‏‏‎‏‏‏‏‎‎Delete ‎‏‎‎‏‏‎<xliff:g id="COUNT_1">%1$d</xliff:g>‎‏‎‎‏‏‏‎ files?‎‏‎‎‏‎</item>
+      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‎‎‏‎‎‏‏‏‎‏‏‏‎‏‎‎‏‎‏‏‏‎‎‏‎‎‏‎‏‏‎‎‏‎‏‏‎‏‎‏‏‎‏‏‎‏‏‏‎‏‏‏‏‎‎Delete ‎‏‎‎‏‏‎<xliff:g id="COUNT_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ file?‎‏‎‎‏‎</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="1028946402799686388">
+      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‎‏‏‏‏‎‎‎‏‏‎‏‎‏‎‎‏‏‎‏‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‎‎‏‎‎‏‎‏‏‏‏‎‏‎‎‎Delete ‎‏‎‎‏‏‎<xliff:g id="COUNT_1">%1$d</xliff:g>‎‏‎‎‏‏‏‎ folders and their contents?‎‏‎‎‏‎</item>
+      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‎‏‏‏‏‎‎‎‏‏‎‏‎‏‎‎‏‏‎‏‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‎‎‏‎‎‏‎‏‏‏‏‎‏‎‎‎Delete ‎‏‎‎‏‏‎<xliff:g id="COUNT_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ folder and its contents?‎‏‎‎‏‎</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="7285090426511028179">
+      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‏‏‎‎‏‏‏‎‏‎‏‏‏‎‎‏‎‎‏‎‏‎‎‎‏‎‏‎‎‏‏‎‎‏‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‎‎‏‏‎Delete ‎‏‎‎‏‏‎<xliff:g id="COUNT_1">%1$d</xliff:g>‎‏‎‎‏‏‏‎ items?‎‏‎‎‏‎</item>
+      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‏‏‎‎‏‏‏‎‏‎‏‏‏‎‎‏‎‎‏‎‏‎‎‎‏‎‏‎‎‏‏‎‎‏‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‎‎‏‏‎Delete ‎‏‎‎‏‏‎<xliff:g id="COUNT_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ item?‎‏‎‎‏‎</item>
+    </plurals>
+    <string name="images_shortcut_label" msgid="2545168016070493574">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‎‏‎‏‎‎‏‎‎‏‎‎‎‎‎‎‏‏‎‏‎‎‏‏‎‏‏‎‎‎‏‏‏‎‎‏‎‎‎‏‎‏‎‎‎‏‎‏‏‎‎‎‎‏‏‎‎Images‎‏‎‎‏‎"</string>
+    <string name="archive_loading_failed" msgid="7243436722828766996">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‎‏‎‏‏‏‎‏‏‎‏‏‎‏‎‏‎‎‏‎‎‏‏‏‎‎‎‏‎‎‏‏‏‎‏‎‎‏‏‎‏‏‏‏‎‎‎‏‎‏‎‎‎Unable to open archive for browsing. File is either corrupt, or an unsupported format.‎‏‎‎‏‎"</string>
+    <string name="name_conflict" msgid="28407269328862986">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‎‏‏‏‏‏‎‎‏‎‎‏‏‏‎‏‏‎‎‎‏‎‎‎‎‏‎‏‏‎‎‏‏‎‏‎‏‏‎‎‎‏‎‏‎‏‏‏‏‏‏‎‎‎‎‏‎‏‎‎A file with this name already exists.‎‏‎‎‏‎"</string>
+    <string name="authentication_required" msgid="8030880723643436099">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‎‏‏‎‏‏‎‏‎‏‏‎‏‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‎‎‎‏‏‎‎‎‏‎‎‎‎‏‏‎To view this directory, sign in to ‎‏‎‎‏‏‎<xliff:g id="NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="cant_display_content" msgid="8633226333229417237">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‏‏‎‏‏‏‏‏‏‏‎‎‏‏‎‏‏‎‎‎‎‎‎‎‎‎‎‏‏‎‎‎‏‎‏‎‏‎Can’t display contents‎‏‎‎‏‎"</string>
+    <string name="sign_in" msgid="6253762676723505592">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‎‎‏‏‏‎‏‎‏‎‎‎‎‎‎‎‏‎‏‎‏‎‎‎‏‏‏‏‎‏‏‎‎‏‏‎‏‎‏‏‎‎‏‏‎‏‏‏‎‎‎‎Sign in‎‏‎‎‏‎"</string>
+    <string name="new_archive_file_name" msgid="1604650338077249838">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‎‎‏‎‎‏‏‎‏‏‏‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‏‏‏‎‎‏‏‏‎‎‎‎‏‎‎‎‏‎‎‏‎‏‏‏‎‎archive‎‏‎‎‏‏‎<xliff:g id="EXTENSION">%s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‎‏‎‏‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‎‎‎‏‎‏‎‏‏‎‏‎‏‏‎‎‎‏‏‎‏‏‎‏‏‏‏‏‏‏‎‎‎Overwrite ‎‏‎‎‏‏‎<xliff:g id="NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
+    <string name="continue_in_background" msgid="1974214559047793331">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‏‎‏‏‎‎‏‎‏‏‏‎‏‎‎‎‏‏‎‏‎‏‏‏‎‎‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‎‏‏‏‎‏‎‏‎‏‏‎‎‏‏‎Continue in background‎‏‎‎‏‎"</string>
+</resources>
diff --git a/res/values-es-rUS/inspector_strings.xml b/res/values-es-rUS/inspector_strings.xml
new file mode 100644
index 0000000..e82d604
--- /dev/null
+++ b/res/values-es-rUS/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Información"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"No se pudo cargar la información del archivo"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Información de depuración (solo programadores)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Metadatos RAW: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Detalles del contenido multimedia"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Este tipo de archivo se abre con"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Proveedor del archivo:"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Sin seleccionar"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Desconocido"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Dimensiones"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> (<xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP)"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Coordenadas"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Altitud"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Cámara"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Apertura"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Velocidad del obturador"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Duración"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Fecha de la foto"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Longitud focal"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Equivalente ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Artista"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Compositor"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Álbum"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Ubicación"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Tipos de flujo"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Tamaño del archivo RAW (bytes)"</string>
+</resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index f90bafe..2352107 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Comprimir"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Extraer en…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Cambiar nombre"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Obtener información"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Obtener información"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Ver en <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Ventana nueva"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Cortar"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Mover"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Descartar"</string>
     <string name="button_retry" msgid="4011461781916631389">"Volver a intentar"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Borrar"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Mostrar en el proveedor"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Sin ordernar"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Nombre"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Resumen"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Tamaño"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Modificación"</string>
     <string name="directory_items" msgid="6645621978998614003">"Cantidad de elementos"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Este tipo de archivo se abre con"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Este archivo pertenece a"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Otras apps pueden abrir este tipo de archivo. Haz que"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"deje de ser la app predeterminada."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Borrar"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Mostrar en el proveedor"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Sin seleccionar"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Desconocida"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Ascendente"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Descendente"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Mostrar raíces"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"No se puede abrir el archivo"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"No se pueden abrir los documentos en Archivos"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"No es posible borrar algunos documentos"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"No se pudieron cargar las propiedades"</string>
     <string name="share_via" msgid="8725082736005677161">"Compartir con"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Copiando archivos"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Comprimiendo archivos"</string>
@@ -119,11 +112,11 @@
       <item quantity="one">Borrando <xliff:g id="COUNT_0">%1$d</xliff:g> elemento</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Deshacer"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Preparando para copiar…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Preparando la compresión…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Preparando para la extracción…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Preparación para mover archivos…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Preparando para borrar…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Preparando…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Preparando…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Preparando…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Preparando…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Preparando…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other">No se pudieron copiar <xliff:g id="COUNT_1">%1$d</xliff:g> elementos</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"archivo<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"¿Deseas sobrescribir <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Continuar en segundo plano"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Información de depuración (solo del dispositivo)"</string>
 </resources>
diff --git a/res/values-es/inspector_strings.xml b/res/values-es/inspector_strings.xml
new file mode 100644
index 0000000..fcd3d88
--- /dev/null
+++ b/res/values-es/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Información"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"No se ha podido cargar la información del archivo"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Información de depuración (solo desarrolladores)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Metadatos sin procesar: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Detalles de contenido multimedia"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Este tipo de archivo se abre con"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Proveedor del archivo:"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"No se ha seleccionado"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Desconocida"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Dimensiones"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g>x<xliff:g id="HEIGHT">%2$d</xliff:g> (<xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP)"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Coordenadas"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Altitud"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Cámara"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Apertura"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Velocidad del obturador"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Duración"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Fecha de la foto"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Longitud focal"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Equivalente ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Artista"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Compositor"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Álbum"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Ubicación"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Stream types"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Tamaño del archivo RAW (bytes)"</string>
+</resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index dc010a8..b53638e 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Comprimir"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Extraer a…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Cambiar nombre"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Obtener información"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Obtener información"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Ver en <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Nueva ventana"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Cortar"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Mover"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Descartar"</string>
     <string name="button_retry" msgid="4011461781916631389">"Volver a intentarlo"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Borrar"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Mostrar en el proveedor"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Sin ordenar"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Nombre"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Resumen"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Tamaño"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Modificado"</string>
     <string name="directory_items" msgid="6645621978998614003">"Número de elementos"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Este tipo de archivo se abre con"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Procedencia del archivo:"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Otras aplicaciones pueden abrir este tipo de archivo. Haz que"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"deje de ser la aplicación predeterminada."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Borrar"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Mostrar en el proveedor"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"No se ha seleccionado"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Desconocida"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Ascendente"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Descendente"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Mostrar raíces"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"No se puede abrir el archivo"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"No se pueden abrir los elementos archivados"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Error al eliminar algunos documentos"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"No se han podido cargar las propiedades"</string>
     <string name="share_via" msgid="8725082736005677161">"Compartir a través de"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Copiando archivos"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Comprimiendo archivos"</string>
@@ -119,11 +112,11 @@
       <item quantity="one">Eliminando <xliff:g id="COUNT_0">%1$d</xliff:g> elemento.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Deshacer"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Preparando para copiar..."</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Preparando para comprimir…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Preparando para extracción…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Preparando para mover…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Preparando para eliminar…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Preparando..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Preparando..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Preparando..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Preparando..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Preparando..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> de <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other">No se han podido copiar <xliff:g id="COUNT_1">%1$d</xliff:g> elementos</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"archivo<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"¿Sobrescribir <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Continuar en segundo plano"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Información de depuración (solo del dispositivo)"</string>
 </resources>
diff --git a/res/values-et/inspector_strings.xml b/res/values-et/inspector_strings.xml
new file mode 100644
index 0000000..010cf9a
--- /dev/null
+++ b/res/values-et/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Teave"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Faili teavet ei saanud laadida"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Silumisteave (ainult arendajatele)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Toormetaandmed: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Meedia üksikasjad"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Seda tüüpi faile saab avada rakendusega"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Selle faili allikas on"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Pole valitud"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Teadmata"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Mõõtmed"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> – <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Koordinaadid"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Kõrgus"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Kaamera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Ava"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Säriaeg"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Kestus"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Jäädvustatud"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Fookuskaugus"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO ekvivalent"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Esitaja"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Helilooja"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Album"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Asukoht"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Voo tüübid"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Toorandmete maht (baitides)"</string>
+</resources>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index d42b404..37442c0 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Tihenda"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Ekstrakti …"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Nimeta ümber"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Teabe hankimine"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Teabe hankimine"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Kuva allikas <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Uus aken"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Lõika"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Teisalda"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Loobu"</string>
     <string name="button_retry" msgid="4011461781916631389">"Proovi uuesti"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Kustuta"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Kuva teenuses"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Sortimata"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Nimi"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Kokkuvõte"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Suurus"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Muudetud"</string>
     <string name="directory_items" msgid="6645621978998614003">"Üksuste arv"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Seda tüüpi faile saab avada rakendusega"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"See fail kuulub teenusesse"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Teised rakendused saavad seda tüüpi faile avada. Kustuta"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"vaikevalikuna."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Kustuta"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Kuva teenuses"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Pole valitud"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Teadmata"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Kasvav"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Kahanev"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Kuva juured"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Faili ei saa avada"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Arhiivides olevaid faile ei saa avada"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Mõnda dokumenti ei saa kustutada"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Atribuute ei saanud laadida"</string>
     <string name="share_via" msgid="8725082736005677161">"Jaga rakendusega"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Failide kopeerimine"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Failide tihendamine"</string>
@@ -119,11 +112,11 @@
       <item quantity="one">Kustutatakse <xliff:g id="COUNT_0">%1$d</xliff:g> üksus.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Võta tagasi"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Kopeerimise ettevalmistamine …"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Tihendamiseks ettevalmistamine …"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Ekstraktimise ettevalmistamine …"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Teisaldamise ettevalmistamine …"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Kustutamise ettevalmistamine …"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Ettevalmistamine …"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Ettevalmistamine …"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Ettevalmistamine …"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Ettevalmistamine …"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Ettevalmistamine …"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> üksust ei saanud kopeerida</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"arhiiv<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Kas kirjutada üle üksus <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Jätka taustal"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Silumisteave (ainult arendajatele)"</string>
 </resources>
diff --git a/res/values-eu/inspector_strings.xml b/res/values-eu/inspector_strings.xml
new file mode 100644
index 0000000..9f51a8c
--- /dev/null
+++ b/res/values-eu/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Informazioa"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Ezin izan da kargatu fitxategiaren informazioa"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Arazketa-informazioa (garatzaileentzat soilik)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Prozesatu gabeko metadatuak: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Multimedia-elementuaren xehetasunak"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Mota honetako fitxategiak aplikazio honekin ireki daitezke:"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Fitxategiaren hornitzailea:"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Hautatu gabe"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Ezezaguna"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Dimentsioak"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Koordenatuak"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Altitudea"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Kamera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Irekidura"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Kliskagailuaren abiadura"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Iraupena"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Data"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Foku-distantzia"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO baliokidea"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Artista"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Konpositorea"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Albuma"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Kokapena"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Jario motak"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Prozesatu gabeko tamaina (byte-tan)"</string>
+</resources>
diff --git a/res/values-eu/mimes.xml b/res/values-eu/mimes.xml
index 470c6cc..45294b7 100644
--- a/res/values-eu/mimes.xml
+++ b/res/values-eu/mimes.xml
@@ -40,6 +40,6 @@
     <string name="gtable_file_type" msgid="7332773878374650335">"Google taula"</string>
     <string name="gform_file_type" msgid="4803176103746107611">"Google inprimakia"</string>
     <string name="gmap_file_type" msgid="6684180781808007016">"Google mapa"</string>
-    <string name="gsite_file_type" msgid="3742812051249149526">"Google gunea"</string>
+    <string name="gsite_file_type" msgid="3742812051249149526">"Google webgunea"</string>
     <string name="directory_type" msgid="2702987727566226354">"Karpeta"</string>
 </resources>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 28c5461..37e0b67 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Konprimatu"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Atera hona…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Aldatu izena"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Lortu informazioa"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Lortu informazioa"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Ikusi <xliff:g id="SOURCE">%1$s</xliff:g> zerbitzuan"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Leiho berria"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Ebaki"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Mugitu"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Baztertu"</string>
     <string name="button_retry" msgid="4011461781916631389">"Saiatu berriro"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Garbitu"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Erakutsi hornitzailean"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Ordenatu gabe"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Izena"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Laburpena"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Tamaina"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Aldatze-ordua"</string>
     <string name="directory_items" msgid="6645621978998614003">"Elementu kopurua"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Mota honetako fitxategiak aplikazio honekin ireki daitezke:"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Fitxategiaren jabea:"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Beste aplikazio batzuekin ere ireki daitezke mota honetako fitxategiak. Garbitu"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"aplikazioaren lehenespena."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Garbitu"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Erakutsi hornitzailean"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Hautatu gabe"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Ezezaguna"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Gorantz"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Beherantz"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Erakutsi erroko karpetak"</string>
@@ -89,8 +83,7 @@
     <string name="no_results" msgid="2371026325236359209">"Ez da aurkitu ezer %1$s atalean"</string>
     <string name="toast_no_application" msgid="7555319548595113121">"Ezin da ireki fitxategia"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Ezin dira ireki artxiboetako fitxategiak"</string>
-    <string name="toast_failed_delete" msgid="3453846588205817591">"Ezin izan dira ezabatu dokumentu batzuk"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Ezin izan dira kargatu propietateak"</string>
+    <string name="toast_failed_delete" msgid="3453846588205817591">"Ezin dira ezabatu dokumentu batzuk"</string>
     <string name="share_via" msgid="8725082736005677161">"Partekatu honekin:"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Kopiatu fitxategiak"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Fitxategiak konprimatzen"</string>
@@ -119,11 +112,11 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> elementu ezabatzen.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Desegin"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Kopiatzeko prestatzen…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Konprimatzeko prestatzen…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Ateratzeko prestatzen…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Mugitzeko prestatzen…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Ezabatzeko prestatzen…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Prestatzen…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Prestatzen…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Prestatzen…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Prestatzen…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Prestatzen…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other">Ezin izan dira kopiatu <xliff:g id="COUNT_1">%1$d</xliff:g> elementu</item>
@@ -176,7 +169,7 @@
     <string name="rename_error" msgid="6700093173508118635">"Ezin izan zaio aldatu izena dokumentuari"</string>
     <string name="menu_eject_root" msgid="9215040039374893613">"Atera"</string>
     <string name="notification_copy_files_converted_title" msgid="6916768494891833365">"Artxibo batzuk bihurtu dira"</string>
-    <string name="open_external_dialog_request" msgid="8173558471322861268">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> aplikazioari <xliff:g id="STORAGE"><i>^3</i></xliff:g> unitateko <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> direktorioa atzitzeko baimena eman nahi diozu?"</string>
+    <string name="open_external_dialog_request" msgid="8173558471322861268">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> aplikazioari <xliff:g id="STORAGE"><i>^3</i></xliff:g> unitateko <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> direktoriorako sarbidea eman nahi diozu?"</string>
     <string name="open_external_dialog_request_primary_volume" msgid="2240992164087948176">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> aplikazioari <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> direktoriorako sarbidea eman nahi diozu?"</string>
     <string name="open_external_dialog_root_request" msgid="6776729293982633">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> aplikazioari zure datuak atzitzea baimendu nahi diozu, besteak beste, <xliff:g id="STORAGE"><i>^2</i></xliff:g> biltegian dituzun argazkiak eta bideoak?"</string>
     <string name="never_ask_again" msgid="525908236522201138">"Ez galdetu berriro"</string>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"artxiboa<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"<xliff:g id="NAME">%1$s</xliff:g> gainidatzi nahi duzu?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Jarraitu atzeko planoan"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Arazte-informazioa (garatzaileentzat soilik)"</string>
 </resources>
diff --git a/res/values-fa/inspector_strings.xml b/res/values-fa/inspector_strings.xml
new file mode 100644
index 0000000..e6daea3
--- /dev/null
+++ b/res/values-fa/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"اطلاعات"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"اطلاعات فایل بارگیری نشد"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"اطلاعات اشکال‌زدایی (فقط برنامه‌نویس)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"‏فراداده فایل Raw: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"جزئیات رسانه"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"این نوع فایل با این برنامه باز می‌شود"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"ارائه‌دهنده این فایل"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"انتخاب نشده است"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"نامشخص"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"ابعاد"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"‏<xliff:g id="WIDTH">%1$d</xliff:g> x‏ <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>مگاپیکسل"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"مختصات"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>، <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"ارتفاع"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"دوربین"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"دیافراگم"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"سرعت شاتر"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"مدت‌زمان"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"گرفته‌شده در"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"فیلم کامل"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>میلی‌متر"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"‏معادل ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"‏<xliff:g id="ISO_SPEED">%1$d</xliff:g> ‏ISO"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"هنرمند"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"آهنگ‌ساز"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"آلبوم"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"مکان"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"انواع پخش جریانی"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"‏حجم فایل RAW (بایت)"</string>
+</resources>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index f89ca80..bc9f500 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"فشرده کردن"</string>
     <string name="menu_extract" msgid="8171946945982532262">"استخراج در…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"تغییر نام"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"دریافت اطلاعات"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"دریافت اطلاعات"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"مشاهده در <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"پنجره جدید"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"برش"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"انتقال"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"رد کردن"</string>
     <string name="button_retry" msgid="4011461781916631389">"دوباره امتحان کنید"</string>
+    <string name="button_clear" msgid="5412304437764369441">"پاک کردن"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"نمایش در برنامه ارائه‌دهنده"</string>
     <string name="not_sorted" msgid="7813496644889115530">"مرتب‌سازی نشده است"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"نام"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"خلاصه"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"اندازه"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"آخرین تغییر"</string>
     <string name="directory_items" msgid="6645621978998614003">"تعداد موارد"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"این نوع فایل با این برنامه باز می‌شود"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"این فایل متعلق است به"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"برنامه‌های دیگر می‌توانند این نوع فایل را باز کند. پاک کردن"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"به‌عنوان پیش‌فرض."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"پاک کردن"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"نمایش در ارائه‌دهنده"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"انتخاب نشده است"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"نامشخص"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"صعودی"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"نزولی"</string>
     <string name="drawer_open" msgid="8071673398187261741">"نمایش ریشه‌ها"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"فایل باز نمی‌شود"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"فایل‌های موجود در بایگانی‌ها باز نمی‌شوند"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"برخی از اسناد حذف نمی‌شوند"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"مشخصات بار نشدند"</string>
     <string name="share_via" msgid="8725082736005677161">"اشتراک‌گذاری از طریق"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"در حال کپی کردن فایل‌ها"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"درحال فشرده‌سازی فایل‌ها"</string>
@@ -119,11 +112,11 @@
       <item quantity="other">درحال حذف <xliff:g id="COUNT_1">%1$d</xliff:g> مورد.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"واگرد"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"در حال آماده‌سازی برای کپی..."</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"آماده شدن برای فشرده‌سازی…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"درحال آماده‌سازی برای استخراج…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"درحال آماده‌سازی برای انتقال…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"درحال آماده‌سازی برای حذف…‏"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"در حال آماده‌سازی..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"در حال آماده‌سازی..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"در حال آماده‌سازی..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"در حال آماده‌سازی..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"در حال آماده‌سازی..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> مورد کپی نشد</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"بایگانی <xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"<xliff:g id="NAME">%1$s</xliff:g> رونویسی شود؟"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"ادامه در پس‌زمینه"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"اطلاعات اشکال‌زدایی (فقط برنامه‌نویس)"</string>
 </resources>
diff --git a/res/values-fi/inspector_strings.xml b/res/values-fi/inspector_strings.xml
new file mode 100644
index 0000000..1e18204
--- /dev/null
+++ b/res/values-fi/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Tietoja"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Tiedoston tietojen lataus epäonnistui."</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Vianetsintätiedot (vain kehittäjät)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Raa\'at sisällönkuvaustiedot: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Median tiedot"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Sovellus, jolla tiedostotyyppi avataan"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Tiedoston lähde"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Ei valittu"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Tuntematon"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Mitat"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> – <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Koordinaatit"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Korkeus"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Kamera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Aukko"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Suljinaika"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Kesto"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Kuvaushetki"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Polttoväli"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO-vastine"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Artisti"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Säveltäjä"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Albumi"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Sijainti"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Striimaustyypit"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Raaka koko (tavua)"</string>
+</resources>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index b846d12..27e76a4 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Pakkaa"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Pura kohteeseen…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Nimeä uudelleen"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Näytä tiedot"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Näytä tiedot"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Avaa sovelluksella <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Uusi ikkuna"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Leikkaa"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Siirrä"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Hylkää"</string>
     <string name="button_retry" msgid="4011461781916631389">"Yritä uudelleen"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Tyhjennä"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Näytä palveluntarjoajan sovelluksessa"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Ei lajittelua"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Nimi"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Yhteenveto"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Koko"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Muokattu"</string>
     <string name="directory_items" msgid="6645621978998614003">"Kohteiden määrä"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Tällainen tiedosto avataan sovelluksella"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Tämän tiedoston omistaa"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Muut sovellukset voivat avata tämän tiedostotyypin. Tyhjennä"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"oletuksena."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Tyhjennä"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Näytä palveluntarjoajallasi"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Ei valittu"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Tuntematon"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Nouseva"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Laskeva"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Näytä juuret"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Tiedoston avaaminen epäonnistui."</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Arkistoissa olevia tiedostoja ei voi avata."</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Joidenkin dokumenttien poistaminen epäonnistui."</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Ominaisuuksien lataaminen epäonnistui."</string>
     <string name="share_via" msgid="8725082736005677161">"Jaa sovelluksessa"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Kopioidaan tiedostoja"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Pakataan tiedostoja"</string>
@@ -119,11 +112,11 @@
       <item quantity="one">Poistetaan <xliff:g id="COUNT_0">%1$d</xliff:g> kohde.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Kumoa"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Valmistellaan kopiointia…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Valmistaudutaan pakkaamiseen…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Valmistellaan purkamista…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Valmistellaan siirtämistä…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Valmistellaan poistamista…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Valmistellaan…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Valmistellaan…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Valmistellaan…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Valmistellaan…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Valmistellaan…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> kohteen kopiointi epäonnistui.</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"arkisto<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Korvataanko <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Jatka taustalla"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Vianetsintätiedot (vain kehittäjät)"</string>
 </resources>
diff --git a/res/values-fr-rCA/inspector_strings.xml b/res/values-fr-rCA/inspector_strings.xml
new file mode 100644
index 0000000..d4de841
--- /dev/null
+++ b/res/values-fr-rCA/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Renseignements"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Impossible de charger les renseignements sur le fichier"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Données de débogage (concepteurs uniquement)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Métadonnées brutes : <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Détails des médias"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Ce type de fichier s\'ouvre avec"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Ce fichier est fourni par"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Non sélectionné"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Inconnu"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Dimensions"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> Mpx"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Coordonnées"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Altitude"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Appareil photo"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MODEL">%2$s</xliff:g> de <xliff:g id="MAKE">%1$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Ouverture"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Vitesse de l\'obturateur"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Durée"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Prise le"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Distance focale"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Équivalent ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Artiste"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Compositeur"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Album"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Localisation"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Types de flux"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Taille brute (en octets)"</string>
+</resources>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index f547b54..5181811 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -41,14 +41,14 @@
     <string name="menu_compress" msgid="37539111904724188">"Compresser"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Extraire vers…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Renommer"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"En savoir plus"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"En savoir plus"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Afficher dans <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Nouvelle fenêtre"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Couper"</string>
     <string name="menu_copy_to_clipboard" msgid="5064081159073330776">"Copier"</string>
     <string name="menu_paste_from_clipboard" msgid="360947260414135827">"Coller"</string>
     <string name="menu_paste_into_folder" msgid="8000644546983240101">"Coller dans le dossier"</string>
-    <string name="menu_advanced_show" msgid="7558626506462906726">"Aff. mém. stock. interne"</string>
+    <string name="menu_advanced_show" msgid="7558626506462906726">"Aff. mémoire stockage int."</string>
     <string name="menu_advanced_hide" msgid="6488381508009246334">"Masquer mém. stock. int."</string>
     <string name="button_select" msgid="240863497069321364">"Sélectionner"</string>
     <string name="button_copy" msgid="8219059853840996027">"Copier"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Déplacer"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Fermer"</string>
     <string name="button_retry" msgid="4011461781916631389">"Réessayer"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Effacer"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Afficher dans l\'application du fournisseur"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Non trié"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Nom"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Résumé"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Taille"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Dernière modification"</string>
     <string name="directory_items" msgid="6645621978998614003">"Nombre d\'éléments"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Ce type de fichier s\'ouvre avec"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Ce fichier appartient à"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"D\'autres applications peuvent ouvrir ce type de fichier. Effacer"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"comme valeur par défaut."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Effacer"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Afficher dans le fournisseur"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Non sélectionné"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Inconnu"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Par ordre croissant"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Par ordre décroissant"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Afficher les racines"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Impossible d\'ouvrir le fichier"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Impossible d\'ouvrir des fichiers dans les archives"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Impossible de supprimer certains documents"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Les propriétés n\'ont pas pu être chargées"</string>
     <string name="share_via" msgid="8725082736005677161">"Partager via"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Copie de fichiers…"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Compression des fichiers"</string>
@@ -119,11 +112,11 @@
       <item quantity="other">Suppression de <xliff:g id="COUNT_1">%1$d</xliff:g> éléments en cours.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Annuler"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Préparation de la copie en cours"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Préparation de la compression en cours…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Préparation pour l\'extraction…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Préparation du déplacement…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Préparation de la suppression…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Préparation en cours…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Préparation en cours…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Préparation en cours…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Préparation en cours…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Préparation en cours…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> sur <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one">Impossible de copier <xliff:g id="COUNT_1">%1$d</xliff:g> élément</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"archive<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Remplacer <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Continuer en arrière-plan"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Données de débogage (concepteurs uniquement)"</string>
 </resources>
diff --git a/res/values-fr/inspector_strings.xml b/res/values-fr/inspector_strings.xml
new file mode 100644
index 0000000..b2fa481
--- /dev/null
+++ b/res/values-fr/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Informations"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Impossible de charger les informations relatives au fichier"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Informations de débogage (développeur seulement)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Métadonnées brutes : <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Informations sur les médias"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Ce type de fichier s\'ouvre avec"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Ce fichier est fourni par"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Non sélectionnée"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Inconnue"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Dimensions"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> – <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> Mpx"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Coordonnées"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Altitude"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Appareil photo"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Ouverture"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Vitesse d\'obturation"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Durée"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Prise le"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Longueur focale"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Équivalent ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Artiste"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Compositeur"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Album"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Localisation"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Types de flux"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Taille brute (octets)"</string>
+</resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 7d828fb..ebcaae1 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -41,14 +41,14 @@
     <string name="menu_compress" msgid="37539111904724188">"Compresser"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Extraire sur…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Renommer"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Obtenir les informations"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Obtenir les informations"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Afficher dans <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Nouvelle fenêtre"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Couper"</string>
     <string name="menu_copy_to_clipboard" msgid="5064081159073330776">"Copier"</string>
     <string name="menu_paste_from_clipboard" msgid="360947260414135827">"Coller"</string>
     <string name="menu_paste_into_folder" msgid="8000644546983240101">"Coller dans le dossier"</string>
-    <string name="menu_advanced_show" msgid="7558626506462906726">"Aff. mém. stock. interne"</string>
+    <string name="menu_advanced_show" msgid="7558626506462906726">"Aff. mémoire stockage interne"</string>
     <string name="menu_advanced_hide" msgid="6488381508009246334">"Masquer mém. stock. int."</string>
     <string name="button_select" msgid="240863497069321364">"Sélectionner"</string>
     <string name="button_copy" msgid="8219059853840996027">"Copier"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Déplacer"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Ignorer"</string>
     <string name="button_retry" msgid="4011461781916631389">"Réessayer"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Effacer"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Afficher dans le fournisseur"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Non triés"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Nom"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Résumé"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Taille"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Dernière modif."</string>
     <string name="directory_items" msgid="6645621978998614003">"Nombre d\'éléments"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Ce type de fichier s\'ouvre avec"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Ce fichier appartient à"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"D\'autres applications peuvent ouvrir ce type de fichier. Désactiver"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"pour qu\'elle ne soit plus l\'application par défaut."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Désactiver"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Afficher dans le fournisseur"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Non sélectionnée"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Inconnue"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Croissant"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Décroissant"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Afficher les répertoires racines"</string>
@@ -80,7 +74,7 @@
     <string name="create_error" msgid="3092144450044861994">"Échec de la création du dossier"</string>
     <string name="query_error" msgid="6625421453613879336">"Impossible de charger le contenu pour le moment"</string>
     <string name="root_recent" msgid="1080156975424341623">"Récents"</string>
-    <string name="root_available_bytes" msgid="8269870862691408864">"Espace disponible : <xliff:g id="SIZE">%1$s</xliff:g>"</string>
+    <string name="root_available_bytes" msgid="8269870862691408864">"<xliff:g id="SIZE">%1$s</xliff:g> disponible(s)"</string>
     <string name="root_type_service" msgid="6521366147466512289">"Services de stockage"</string>
     <string name="root_type_shortcut" msgid="6059343175525442279">"Raccourcis"</string>
     <string name="root_type_device" msgid="1713604128005476585">"Appareils"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Impossible d\'ouvrir le fichier"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Impossible d\'ouvrir un fichier dans une archive"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Impossible de supprimer certains documents"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Impossible de charger les propriétés"</string>
     <string name="share_via" msgid="8725082736005677161">"Partager via"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Copie de fichiers…"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Compression de fichiers"</string>
@@ -119,11 +112,11 @@
       <item quantity="other">Suppression de <xliff:g id="COUNT_1">%1$d</xliff:g> éléments…</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Annuler"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Préparation à la copie…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Préparation à la compression…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Préparation de l\'extraction…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Préparation au déplacement…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Préparation à la suppression…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Préparation..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Préparation..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Préparation..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Préparation..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Préparation..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one">Impossible de copier <xliff:g id="COUNT_1">%1$d</xliff:g> élément</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"archive<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Remplacer <xliff:g id="NAME">%1$s</xliff:g> ?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Continuer en arrière-plan"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Informations de débogage (développeur seulement)"</string>
 </resources>
diff --git a/res/values-gl/inspector_strings.xml b/res/values-gl/inspector_strings.xml
new file mode 100644
index 0000000..a33b561
--- /dev/null
+++ b/res/values-gl/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Información"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Non se puido cargar a información do ficheiro"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Datos de depuración (só para programadores)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Metadatos sen procesar: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Datos multimedia"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Este tipo de ficheiro ábrese con"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Provedor do ficheiro"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Non seleccionada"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Descoñecida"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Dimensións"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> (<xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> Mpx)"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Coordenadas"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Altitude"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Cámara"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MODEL">%2$s</xliff:g> de <xliff:g id="MAKE">%1$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Abertura"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Velocidade do obturador"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Duración"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Data da foto"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Distancia focal"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Equivalente ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Artista"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Compositor"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Álbum"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Localización"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Tipos de emisión"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Tamaño sen procesar (bytes)"</string>
+</resources>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 43a941e..aaea38a 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Comprimir"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Extraer en..."</string>
     <string name="menu_rename" msgid="1883113442688817554">"Cambiar nome"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Obter información"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Obter información"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Ver en <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Nova ventá"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Cortar"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Mover"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Ignorar"</string>
     <string name="button_retry" msgid="4011461781916631389">"Tentar de novo"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Borrar"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Mostrar no provedor"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Sen ordenar"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Nome"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Resumo"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Tamaño"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Modificado"</string>
     <string name="directory_items" msgid="6645621978998614003">"Número de elementos"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Este tipo de ficheiro ábrese con"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Procedencia do ficheiro:"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Outras aplicacións poden abrir este tipo de ficheiro. Borrar"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"como predeterminada."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Borrar"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Mostrar no provedor"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Non seleccionada"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Descoñecida"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Ascendente"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Descendente"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Mostrar raíces"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Non se pode abrir o ficheiro"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Non se poden abrir ficheiros dentro de arquivos"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Non se poden eliminar algúns documentos"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Non se puideron cargar as propiedades"</string>
     <string name="share_via" msgid="8725082736005677161">"Compartir a través de"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Copiando ficheiros"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Comprimindo ficheiros"</string>
@@ -119,11 +112,11 @@
       <item quantity="one">Eliminando <xliff:g id="COUNT_0">%1$d</xliff:g> elemento.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Desfacer"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Preparando para copiar…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Preparándose para comprimir..."</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Preparándose para a extracción…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Preparándose para mover..."</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Preparando para eliminar…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Preparando…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Preparando…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Preparando…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Preparando…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Preparando…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other">Non se puideron copiar <xliff:g id="COUNT_1">%1$d</xliff:g> elementos</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"arquivo<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Queres sobrescribir <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Continuar coa operación en segundo plano"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Datos de depuración (só para programadores)"</string>
 </resources>
diff --git a/res/values-gu/inspector_strings.xml b/res/values-gu/inspector_strings.xml
new file mode 100644
index 0000000..97e0b8a
--- /dev/null
+++ b/res/values-gu/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"માહિતી"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"ફાઇલની માહિતી લોડ કરી શકાતી નથી"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"ડિબગ માહિતી (માત્ર વિકાસકર્તા)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Raw મેટાડેટા: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"મીડિયા વિગતો"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"આની સાથે આ પ્રકારની ફાઇલ ખૂલે છે"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"આ ફાઇલ આમના દ્વારા પૂરી પાડવામાં આવી"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"પસંદ કર્યું નથી"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"અજાણ"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"પરિમાણો"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"કોઓર્ડિનેટ્સ"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"ઊંચાઈ"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"કૅમેરા"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"ઍપર્ચર"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"શટરની સ્પીડ"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"અવધિ"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"ના રોજ લીધેલો"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"ફોકલ લંબાઈ"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>મિમી"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO સમકક્ષ"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"કલાકાર"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"સંગીતકાર"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"આલ્બમ"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"સ્થાન"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"સ્ટ્રીમના પ્રકારો"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Rawનું કદ (બાઇટ)"</string>
+</resources>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 3f3b61c..c2e178d 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"સંકુચિત કરો"</string>
     <string name="menu_extract" msgid="8171946945982532262">"આમાં એક્સટ્રેક્ટ કરો…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"નામ બદલો"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"માહિતી મેળવો"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"માહિતી મેળવો"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"<xliff:g id="SOURCE">%1$s</xliff:g>માં જુઓ"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"નવી વિંડો"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"કાપો"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"ખસેડો"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"છોડી દો"</string>
     <string name="button_retry" msgid="4011461781916631389">"ફરી પ્રયાસ કરો"</string>
+    <string name="button_clear" msgid="5412304437764369441">"સાફ કરો"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"પ્રદાતા સેવામાં બતાવો"</string>
     <string name="not_sorted" msgid="7813496644889115530">"સૉર્ટ કરેલ નથી"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"નામ"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"સારાંશ"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"કદ"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"સંશોધિત"</string>
     <string name="directory_items" msgid="6645621978998614003">"આઇટમની સંખ્યા:"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"આની સાથે આ પ્રકારની ફાઇલ ખૂલે છે"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"આ ફાઇલ આમના માલિકીની છે"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"અન્ય ઍપ્લિકેશનો આ પ્રકારની ફાઇલ ખોલી શકે છે. સાફ કરો"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"ડિફૉલ્ટ તરીકે."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"સાફ કરો"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"પ્રદાતામાં બતાવો"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"પસંદ કર્યું નથી"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"અજાણ"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"ચઢતાં ક્રમમાં"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"ઉતરતા ક્રમમાં"</string>
     <string name="drawer_open" msgid="8071673398187261741">"રૂટ્સ બતાવો"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"ફાઇલ ખોલી શકતાં નથી"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"આર્કાઇવમાંની ફાઇલો ખોલી શકાતી નથી"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"કેટલાક દસ્તાવેજો કાઢી નાખવામાં અસમર્થ"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"પ્રોપર્ટી લોડ કરી શકાઈ નથી"</string>
     <string name="share_via" msgid="8725082736005677161">"આના દ્વારા શેર કરો"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"ફાઇલો કૉપિ કરી રહ્યાં છે"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"ફાઇલોને સંકુચિત કરવી"</string>
@@ -119,11 +112,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> આઇટમ કાઢી નાખી રહ્યા છીએ.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"પૂર્વવત્ કરો"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"કૉપિ કરવા માટે તૈયારી કરે છે…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"સંકુચિત કરવાની તૈયારી કરી રહ્યા છીએ…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"કાઢવાની તૈયારી કરી રહ્યાં છીએ…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"ખસેડવા માટે તૈયાર કરી રહ્યું છે…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"કાઢી નાખવાની તૈયારી કરે છે…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"તૈયારી કરી રહ્યાં છીએ…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"તૈયારી કરી રહ્યાં છીએ…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"તૈયારી કરી રહ્યાં છીએ…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"તૈયારી કરી રહ્યાં છીએ…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"તૈયારી કરી રહ્યાં છીએ…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> આઇટમની કૉપિ કરી ન શક્યા</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"આર્કાઇવ<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"<xliff:g id="NAME">%1$s</xliff:g> અધિલેખિત કરીએ?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"પૃષ્ઠભૂમિમાં ચાલુ રાખો"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"ડિબગ માહિતી (માત્ર વિકાસકર્તા)"</string>
 </resources>
diff --git a/res/values-hi/inspector_strings.xml b/res/values-hi/inspector_strings.xml
new file mode 100644
index 0000000..e18a792
--- /dev/null
+++ b/res/values-hi/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"जानकारी"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"फ़ाइल की जानकारी लोड नहीं हो सकी"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"डीबग जानकारी (केवल डेवलपर)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"अपरिष्कृत मेटाडेटा: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"मीडिया की जानकारी"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"इस तरह की फ़ाइल इसमें खुलती है:"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"यह फ़ाइल यहां से उपलब्ध कराई गई है"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"नहीं चुना गया"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"अज्ञात"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"आयाम"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>एमपी"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"निर्देशांक"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"ऊंचाई"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"कैमरा"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"एपर्चर"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"शटर की गति"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"अवधि"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"फ़ोटो लिए जाने का समय"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"फ़ोकल लंबाई"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> मिमी"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO के बराबर"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"कलाकार"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"संगीतकार"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"एल्बम"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"जगह"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"प्रसारण के प्रकार"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"अपरिष्कृत आकार (बाइट)"</string>
+</resources>
diff --git a/res/values-hi/mimes.xml b/res/values-hi/mimes.xml
index ffff6e9..f5a78ae 100644
--- a/res/values-hi/mimes.xml
+++ b/res/values-hi/mimes.xml
@@ -39,7 +39,7 @@
     <string name="gdraw_file_type" msgid="655688091676820371">"Google आरेखण"</string>
     <string name="gtable_file_type" msgid="7332773878374650335">"Google टेबल"</string>
     <string name="gform_file_type" msgid="4803176103746107611">"Google फ़ॉर्म"</string>
-    <string name="gmap_file_type" msgid="6684180781808007016">"Google मानचित्र"</string>
+    <string name="gmap_file_type" msgid="6684180781808007016">"Google मैप"</string>
     <string name="gsite_file_type" msgid="3742812051249149526">"Google साइट"</string>
     <string name="directory_type" msgid="2702987727566226354">"फ़ोल्डर"</string>
 </resources>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 931fe4e..f40bce7 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -27,7 +27,7 @@
     <string name="menu_create_dir" msgid="2413624798689091042">"नया फ़ोल्डर"</string>
     <string name="menu_grid" msgid="1453636521731880680">"ग्रिड दृश्य"</string>
     <string name="menu_list" msgid="6714267452146410402">"सूची दृश्य"</string>
-    <string name="menu_search" msgid="1876699106790719849">"सर्च करें"</string>
+    <string name="menu_search" msgid="1876699106790719849">"खोजें"</string>
     <string name="menu_settings" msgid="6520844520117939047">"जगह सेटिंग"</string>
     <string name="menu_open" msgid="9092138100049759315">"खोलें"</string>
     <string name="menu_open_with" msgid="5507647065467520229">"इसमें खोलें"</string>
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"कंप्रेस करें"</string>
     <string name="menu_extract" msgid="8171946945982532262">"यहां निकालें…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"नाम बदलें"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"जानकारी पाएं"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"जानकारी पाएं"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"<xliff:g id="SOURCE">%1$s</xliff:g> में देखें"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"नई विंडो"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"काटें"</string>
@@ -57,21 +57,15 @@
     <string name="button_move" msgid="8596460499325291272">"ले जाएं"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"खारिज करें"</string>
     <string name="button_retry" msgid="4011461781916631389">"फिर से कोशिश करें"</string>
+    <string name="button_clear" msgid="5412304437764369441">"साफ़ करें"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"प्रदाता में दिखाएं"</string>
     <string name="not_sorted" msgid="7813496644889115530">"क्रमबद्ध नहीं हैं"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"नाम"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"सारांश"</string>
     <string name="sort_dimension_file_type" msgid="5779709622922085381">"प्रकार"</string>
     <string name="sort_dimension_size" msgid="2190547351159472884">"आकार"</string>
-    <string name="sort_dimension_date" msgid="4231005651895254033">"बदलनेे का समय"</string>
+    <string name="sort_dimension_date" msgid="4231005651895254033">"बदले जाने का समय"</string>
     <string name="directory_items" msgid="6645621978998614003">"आइटम की संख्या"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"इस तरह की फ़ाइल इसमें खुलती है:"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"यह फ़ाइल इसकी है:"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"दूसरे ऐप्लिकेशन इस फ़ाइल प्रकार को खोल सकते हैं. साफ़ करें"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"डिफ़ॉल्ट रूप से."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"साफ़ करें"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"प्रदाता में दिखाएं"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"नहीं चुना गया"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"अज्ञात"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"बढ़ते क्रम में"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"घटते क्रम में"</string>
     <string name="drawer_open" msgid="8071673398187261741">"रूट दिखाएं"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"फ़ाइल नहीं खोली जा सकती"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"संग्रह में मौजूद फ़ाइलें नहीं खोली जा सकतीं"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"कुछ दस्तावेज़ों को हटाने में असमर्थ"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"प्रॉपर्टी लोड नहीं हो सकीं"</string>
     <string name="share_via" msgid="8725082736005677161">"इसके ज़रिए शेयर करें"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"फ़ाइलें कॉपी हो रही हैं"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"फ़ाइलें कंप्रेस करना"</string>
@@ -119,11 +112,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> आइटम मिटाए जा रहे हैं.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"पूर्ववत करें"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"कॉपी करने की तैयारी हो रही है…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"कंप्रेस की तैयार हो रही है..."</string>
-    <string name="extract_preparing" msgid="58266275455027829">"निकालने की तैयारी हो रही है…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"ले जाने की तैयारी हो रही है…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"हटाने के लिए तैयार हो रहा है…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"तैयार किया जा रहा है..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"तैयार किया जा रहा है..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"तैयार किया जा रहा है..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"तैयार किया जा रहा है..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"तैयार किया जा रहा है..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> आइटम कॉपी नहीं किए जा सके</item>
@@ -179,7 +172,7 @@
     <string name="open_external_dialog_request" msgid="8173558471322861268">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> को <xliff:g id="STORAGE"><i>^3</i></xliff:g> पर <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> डिक्शनरी तक पहुंचने देना चाहते हैं?"</string>
     <string name="open_external_dialog_request_primary_volume" msgid="2240992164087948176">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> को <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> डिक्शनरी तक पहुंचने देना चाहते हैं?"</string>
     <string name="open_external_dialog_root_request" msgid="6776729293982633">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> को <xliff:g id="STORAGE"><i>^2</i></xliff:g> पर मौजूद फ़ोटो और वीडियो के साथ, अपने डेटा तक पहुंचने देना चाहते हैं?"</string>
-    <string name="never_ask_again" msgid="525908236522201138">"फिर से ना पूछें"</string>
+    <string name="never_ask_again" msgid="525908236522201138">"फिर से न पूछें"</string>
     <string name="allow" msgid="1275746941353040309">"अनुमति दें"</string>
     <string name="deny" msgid="5127201668078153379">"अस्वीकार करें"</string>
     <plurals name="elements_selected" formatted="false" msgid="4448165978637163692">
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"संग्रह<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"<xliff:g id="NAME">%1$s</xliff:g> को ओवरराइट करना चाहते हैं?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"बैकग्राउंड में जारी रखें"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"डीबग जानकारी (केवल डेवलपर)"</string>
 </resources>
diff --git a/res/values-hr/inspector_strings.xml b/res/values-hr/inspector_strings.xml
new file mode 100644
index 0000000..3101ae1
--- /dev/null
+++ b/res/values-hr/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Informacije"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Učitavanje informacija o datoteci nije uspjelo"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Podaci o otklanjanju pogrešaka (samo razvoj)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Neobrađeni metapodaci: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Pojedinosti o medijma"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Ova se vrsta datoteke otvara aplikacijom"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Datoteku pruža"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Nije odabrano"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Nepoznato"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Dimenzije"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> – <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Koordinate"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Nadmorska visina"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Fotoaparat"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Otvor blende"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Brzina zatvarača"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Trajanje"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Snimljeno"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Žarišna duljina"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO ekvivalent"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Izvođač"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Skladatelj"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Album"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Lokacija"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Vrste strujanja"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Neobrađena veličina (u bajtovima)"</string>
+</resources>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 195fc00..62714e5 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Sažmi"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Izdvoji u…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Promijeni naziv"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Pogledajte informacije"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Pogledajte informacije"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Prikaži na usluzi <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Novi prozor"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Izreži"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Premjesti"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Odbaci"</string>
     <string name="button_retry" msgid="4011461781916631389">"Pokušaj ponovo"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Izbriši"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Prikaži na davatelju usluga"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Nije poredano"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Naziv"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Sažetak"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Veličina"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Izmijenjeno"</string>
     <string name="directory_items" msgid="6645621978998614003">"Broj stavki"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Ova se vrsta datoteke otvara aplikacijom"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Ova datoteka pripada"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Druge aplikacije mogu otvoriti ovu vrstu datoteke. Izbriši"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"kao zadano."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Izbriši"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Prikaži na davatelju usluga"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Nije odabrano"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Nepoznato"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Uzlazno"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Silazno"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Prikaži korijene"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Datoteka se ne može otvoriti"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Nije moguće otvoriti datoteke u arhivama"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Nije moguće izbrisati neke dokumente"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Učitavanje svojstava nije uspjelo"</string>
     <string name="share_via" msgid="8725082736005677161">"Dijeli putem"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Kopiranje datoteka"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Sažimanje datoteka"</string>
@@ -124,11 +117,11 @@
       <item quantity="other">Briše se <xliff:g id="COUNT_1">%1$d</xliff:g> stavki.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Poništi"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Priprema za kopiranje…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Priprema za sažimanje…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Priprema za izdvajanje…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Priprema za premještanje…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Priprema za brisanje…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Pripremanje..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Pripremanje..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Pripremanje..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Pripremanje..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Pripremanje..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one">Kopiranje <xliff:g id="COUNT_1">%1$d</xliff:g> stavke nije uspjelo</item>
@@ -234,5 +227,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"arhiva<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Prebrisati <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Nastavi u pozadini"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Podaci o otklanjanju pogrešaka (samo razvoj)"</string>
 </resources>
diff --git a/res/values-hu/inspector_strings.xml b/res/values-hu/inspector_strings.xml
new file mode 100644
index 0000000..b27149f
--- /dev/null
+++ b/res/values-hu/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Információ"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Nem sikerült betölteni a fájl információit"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Hibakeresési információ (csak fejlesztőknek)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"RAW-metaadatok: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Médiainformációk"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Ezt a fájltípust a következő alkalmazás nyitja meg:"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"A fájlt a következő biztosítja:"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Nincs kiválasztva"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Ismeretlen"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Méretek"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> × <xliff:g id="HEIGHT">%2$d</xliff:g> – <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Koordináták"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Magasság"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Fényképezőgép"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Rekesz"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Záridő"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Időtartam"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Felvétel ideje:"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Fókusztávolság"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO-egyenérték"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Előadó"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Zeneszerző"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Album"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Helyadatok"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Streamtípusok"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"RAW-méret (bájt)"</string>
+</resources>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 5180080..04f0b69 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Tömörítés"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Kicsomagolás ide…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Átnevezés"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Információ megjelenítése"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Információ megjelenítése"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Megtekintés a következőben: <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Új ablak"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Kivágás"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Áthelyezés"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Elvetés"</string>
     <string name="button_retry" msgid="4011461781916631389">"Próbálja újra"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Törlés"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Megjelenítés a szolgáltatónál"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Nincs rendezve"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Név"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Összefoglalás"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Méret"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Módosítva"</string>
     <string name="directory_items" msgid="6645621978998614003">"Elemek száma"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Ezt a fájltípust a következő alkalmazás nyitja meg:"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"A fájl a következőhöz tartozik:"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Ezt a fájltípust más alkalmazások is meg tudják nyitni. Törlés"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"mint alapértelmezett alkalmazás."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Törlés"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Megjelenítés a szolgáltatónál"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Nincs kiválasztva"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Ismeretlen"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Növekvő"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Csökkenő"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Gyökérszint megjelenítése"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"A fájlt nem lehet megnyitni"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Az archívumban nem lehet fájlokat megnyitni"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Néhány dokumentumot nem lehet törölni"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Nem sikerült betölteni a tulajdonságokat"</string>
     <string name="share_via" msgid="8725082736005677161">"Megosztás itt:"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Fájlok másolása"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Fájlok tömörítése"</string>
@@ -119,11 +112,11 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> elem törlése folyamatban.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Visszavonás"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Felkészülés a másolásra…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Felkészülés a tömörítésre…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Kicsomagolás előkészítése…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Áthelyezés előkészítése…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Törlés előkészítése…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Előkészítés…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Előkészítés…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Előkészítés…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Előkészítés…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Előkészítés…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="TOTALCOUNT">%2$d</xliff:g>/<xliff:g id="COUNT_0">%1$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> elem másolása sikertelen</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"archive<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Felülírja a következő fájlt: <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Folytatás a háttérben"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Hibakeresési információ (csak fejlesztőknek)"</string>
 </resources>
diff --git a/res/values-hy/inspector_strings.xml b/res/values-hy/inspector_strings.xml
new file mode 100644
index 0000000..c13b686
--- /dev/null
+++ b/res/values-hy/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Տեղեկություններ"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Չհաջողվեց բեռնել ֆայլի տվյալները"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Վրիպազերծման տեղեկություններ (միայն մշակող)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Raw մետատվյալներ՝ <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Մեդիա տվյալներ"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Այս տեսակի ֆայլերի բացման հավելվածը"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Այս ֆայլի մատակարարը"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Ընտրված չէ"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Անհայտ է"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Չափեր"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$.1f</xliff:g> ՄՊ"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Կոորդինատներ"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Բարձրություն"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Տեսախցիկ"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Բացվածք"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Պահաժամ"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Տևողությունը"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Լուսանկարվել է՝"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Ֆոկուսային հեռավորությունը"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> մմ"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO-ի համարժեք"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Կատարող"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Կոմպոզիտոր"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Ալբոմ"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Գտնվելու վայրը"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Հոսքի տեսակներ"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Raw ֆայլի չափ (բայթ)"</string>
+</resources>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index a59dfe4..b37edda 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Սեղմել"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Արտահանել…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Վերանվանել"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Ստանալ տեղեկություններ"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Տեղեկություններ"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Դիտել <xliff:g id="SOURCE">%1$s</xliff:g>-ում"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Նոր պատուհան"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Կտրել"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Տեղափոխել"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Փակել"</string>
     <string name="button_retry" msgid="4011461781916631389">"Փորձել նորից"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Մաքրել"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Ցուցադրել մատակարարում"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Տեսակավորված չեն"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Անունը"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Ամփոփագիր"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Չափը"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Փոփոխվել է"</string>
     <string name="directory_items" msgid="6645621978998614003">"Տարրերի քանակ"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Այս տեսակի ֆայլերի բացման հավելված"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Ֆայլի գտնվելու վայր"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Այլ հավելվածներ կարող են բացել ֆայլի այս տեսակը։ Մաքրել"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"որպես կանխադրված։"</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Մաքրել"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Ցուցադրել մատակարարում"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Ընտրված չէ"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Անհայտ"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Աճման կարգով"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Նվազման կարգով"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Ցույց տալ արմատները"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Հնարավոր չէ բացել ֆայլը"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Հնարավոր չէ բացել արխիվացված ֆայլերը"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Հնարավոր չէ ջնջել որոշ փաստաթղթեր"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Հատկությունները հնարավոր չէ բեռնել"</string>
     <string name="share_via" msgid="8725082736005677161">"Կիսվել"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Ֆայլերի պատճենում"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Ֆայլերի սեղմում"</string>
@@ -119,11 +112,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> տարրի ջնջում:</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Հետարկել"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Պատճենման նախապատրաստում…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Սեղմելու նախապատրաստում…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Պատրաստվում է արտահանել…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Տեղափոխման նախապատրաստում…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Պատրաստվում է ջնջել…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Նախապատրաստում..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Նախապատրաստում..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Նախապատրաստում..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Նախապատրաստում..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Նախապատրաստում..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one">Couldn’t copy <xliff:g id="COUNT_1">%1$d</xliff:g> items</item>
@@ -168,7 +161,7 @@
       <item quantity="other">Այս ֆայլը փոխարկվել են այլ ձևաչափի՝ <xliff:g id="LIST_1">%1$s</xliff:g></item>
     </plurals>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="4847061634862926902">
-      <item quantity="one">Copied <xliff:g id="COUNT_1">%1$d</xliff:g> items to clipboard.</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> տարր պատճենվեց սեղմատախտակին։</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> տարր պատճենվեց սեղմատախտակին:</item>
     </plurals>
     <string name="file_operation_rejected" msgid="4301554203329008794">"Ֆայլի աշխատանքը չի աջակցվում:"</string>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"archive<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Փոխարինե՞լ <xliff:g id="NAME">%1$s</xliff:g> ֆայլը։"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Շարունակել ֆոնում"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Վրիպազերծման տեղեկություններ (միայն մշակող)"</string>
 </resources>
diff --git a/res/values-in/inspector_strings.xml b/res/values-in/inspector_strings.xml
new file mode 100644
index 0000000..0964060
--- /dev/null
+++ b/res/values-in/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Info"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Info file tidak dapat dimuat"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Info debug (khusus dev)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Metadata raw: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Detail media"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"File jenis ini dibuka dengan"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"File ini diberikan oleh"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Tidak dipilih"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Tidak diketahui"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Dimensi"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Koordinat"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Ketinggian"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Kamera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Bukaan"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Kecepatan rana"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Durasi"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Diambil pada"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Panjang fokal"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Setara ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Artis"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Komposer"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Album"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Lokasi"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Jenis streaming"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Ukuran raw (byte)"</string>
+</resources>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index e9402a2..02f4cc5 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Kompresi"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Ekstrak ke…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Ganti nama"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Dapatkan info"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Dapatkan info"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Lihat di <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Jendela baru"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Potong"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Pindahkan"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Tutup"</string>
     <string name="button_retry" msgid="4011461781916631389">"Coba Lagi"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Hapus"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Tampilkan di provider"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Tidak diurutkan"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Nama"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Ringkasan"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Ukuran"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Diubah"</string>
     <string name="directory_items" msgid="6645621978998614003">"Jumlah item"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"File jenis ini dibuka dengan"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"File ini termasuk di"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Aplikasi lain dapat membuka file jenis ini. Hapus"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"sebagai default."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Hapus"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Tampilkan di provider"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Tidak dipilih"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Tidak diketahui"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Naik"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Turun"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Tampilkan root"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Tidak dapat membuka file"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Tidak dapat membuka file dalam arsip"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Tidak dapat menghapus beberapa dokumen"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Properti tidak dapat dimuat"</string>
     <string name="share_via" msgid="8725082736005677161">"Bagikan melalui"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Menyalin file"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Mengompres file"</string>
@@ -119,11 +112,11 @@
       <item quantity="one">Menghapus <xliff:g id="COUNT_0">%1$d</xliff:g> item.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Urungkan"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Bersiap untuk menyalin…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Bersiap untuk mengompres..."</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Bersiap mengekstrak…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Bersiap memindahkan…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Bersiap menghapus…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Menyiapkan..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Menyiapkan..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Menyiapkan..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Menyiapkan..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Menyiapkan..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other">Tidak dapat menyalin <xliff:g id="COUNT_1">%1$d</xliff:g> item</item>
@@ -141,7 +134,7 @@
       <item quantity="other">Tidak dapat menghapus <xliff:g id="COUNT_1">%1$d</xliff:g> item</item>
       <item quantity="one">Tidak dapat menghapus <xliff:g id="COUNT_0">%1$d</xliff:g> item</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="2385563502445129570">"Ketuk untuk melihat detail"</string>
+    <string name="notification_touch_for_details" msgid="2385563502445129570">"Tap untuk melihat detail"</string>
     <string name="close" msgid="905969391788869975">"Tutup"</string>
     <plurals name="copy_failure_alert_content" formatted="false" msgid="5570549471912990536">
       <item quantity="other">File ini tidak disalin: <xliff:g id="LIST_1">%1$s</xliff:g></item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"arsip<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Timpa <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Lanjutkan di background"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Info debug (khusus dev)"</string>
 </resources>
diff --git a/res/values-is/inspector_strings.xml b/res/values-is/inspector_strings.xml
new file mode 100644
index 0000000..72dc56b
--- /dev/null
+++ b/res/values-is/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Upplýsingar"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Ekki var hægt að hlaða skráarupplýsingar"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Kembiupplýsingar (aðeins þróunaraðilar)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Óunnin lýsigögn: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Efnisupplýsingar"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Þessi tegund af skrá opnast með"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Veita þessarar skráar er:"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Ekki valið"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Óþekkt"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Stærð"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> – <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Hnit"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Hæð"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Myndavél"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Ljósop"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Lokarahraði"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Tímalengd"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Tekin"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Brennivídd"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO-jafngildi"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Flytjandi"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Höfundur"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Plata"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Staðsetning"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Streymisgerðir"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Óunnin stærð (bæti)"</string>
+</resources>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index e2188ac..5bb4b0f 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Þjappa"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Flytja út í…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Endurnefna"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Sækja upplýsingar"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Sækja upplýsingar"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Opna í <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Nýr gluggi"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Klippa"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Færa"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Hunsa"</string>
     <string name="button_retry" msgid="4011461781916631389">"Reyna aftur"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Hreinsa"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Sýna í þjónustu"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Ekki flokkuð"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Heiti"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Samantekt"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Stærð"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Breytt"</string>
     <string name="directory_items" msgid="6645621978998614003">"Fjöldi atriða"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Þessi tegund af skrá opnast með"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Þessi skrá tilheyrir"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Önnur forrit geta opnað þessa skráartegund. Hreinsa"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"sem sjálfgefið."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Hreinsa"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Sýna í þjónustu"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Ekki valið"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Óþekkt"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Hækkandi"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Lækkandi"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Sýna rótarsöfn"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Ekki hægt að opna skrá"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Ekki er hægt að opna skrár í geymslu"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Ekki hægt að eyða einhverjum skjölum"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Ekki tókst að sækja eiginleika"</string>
     <string name="share_via" msgid="8725082736005677161">"Deila í gegnum"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Afritar skrár"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Þjappar skrám"</string>
@@ -119,11 +112,11 @@
       <item quantity="other">Eyðir <xliff:g id="COUNT_1">%1$d</xliff:g> atriðum.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Afturkalla"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Undirbúningur fyrir afritun…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Undirbýr þjöppun…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Undirbýr að draga út…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Flutningur undirbúinn…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Býr sig undir að eyða…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Undirbýr..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Undirbýr..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Undirbýr..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Undirbýr..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Undirbýr..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one">Gat ekki afritað <xliff:g id="COUNT_1">%1$d</xliff:g> atriði</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"geymsla<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Skrifa yfir <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Halda áfram í bakgrunni"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Kembiupplýsingar (aðeins þróunaraðilar)"</string>
 </resources>
diff --git a/res/values-it/inspector_strings.xml b/res/values-it/inspector_strings.xml
new file mode 100644
index 0000000..fcc7c83
--- /dev/null
+++ b/res/values-it/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Informazioni"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Impossibile caricare le informazioni del file"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Informazioni di debug (solo sviluppatori)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Metadati non elaborati: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Dettagli contenuti multimediali"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Questo tipo di file viene aperto con"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Questo file è fornito da"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Non selezionata"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Sconosciuto"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Dimensioni"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Coordinate"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Altitudine"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Fotocamera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Apertura"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Velocità otturatore"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Durata"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Data/ora"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Lunghezza focale"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO equivalenti"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Artista"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Compositore"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Album"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Geolocalizzazione"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Tipi di stream"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Dimensioni file non elaborato (byte)"</string>
+</resources>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index f0ff409..02d3237 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Comprimi"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Estrai in…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Rinomina"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Informazioni"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Informazioni"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Visualizza in <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Nuova finestra"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Taglia"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Sposta"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Ignora"</string>
     <string name="button_retry" msgid="4011461781916631389">"Riprova"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Cancella"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Mostra in provider"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Nessun ordine"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Nome"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Riepilogo"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Dimensioni"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Ultima modifica"</string>
     <string name="directory_items" msgid="6645621978998614003">"Numero di elementi"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Questo tipo di file viene aperto con"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Questo file appartiene a"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Altre app possono aprire questo tipo di file. Cancella"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"come predefinita."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Cancella"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Mostra in provider"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Non selezionata"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Sconosciuta"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Crescente"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Decrescente"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Mostra nodi principali"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Impossibile aprire il file."</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Impossibile aprire i file negli archivi"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Impossibile eliminare alcuni documenti."</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Impossibile caricare le proprietà"</string>
     <string name="share_via" msgid="8725082736005677161">"Condividi tramite"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Copia dei file in corso"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Compressione di file"</string>
@@ -119,11 +112,11 @@
       <item quantity="one">Eliminazione di <xliff:g id="COUNT_0">%1$d</xliff:g> elemento.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Annulla"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Preparazione alla copia…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Preparazione alla compressione…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Preparazione all\'estrazione…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Preparazione dello spostamento…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Preparazione eliminazione…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Preparazione…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Preparazione…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Preparazione…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Preparazione…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Preparazione…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other">Copia di <xliff:g id="COUNT_1">%1$d</xliff:g> elementi non riuscita</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"archivio<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Sovrascrivere <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Continua in background"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Informazioni di debug (solo sviluppatori)"</string>
 </resources>
diff --git a/res/values-iw/inspector_strings.xml b/res/values-iw/inspector_strings.xml
new file mode 100644
index 0000000..e47dd80
--- /dev/null
+++ b/res/values-iw/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"מאפיינים"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"לא ניתן היה לטעון את פרטי הקובץ"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"מידע על ניפוי באגים (פיתוח בלבד)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"‏סוג המטא נתונים של קובץ ה-RAW: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"פרטי הקבצים"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"אפשר לפתוח קבצים מהסוג הזה באמצעות"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"הקובץ סופק על ידי"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"לא נבחרה"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"לא ידועה"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"מידות"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"‏<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>‏ - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"קואורדינטות"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"גובה"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"מצלמה"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"צמצם"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"מהירות תריס"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"משך"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"צולם ב-"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"אורך מוקד"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> מ\"מ"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"‏רגישות לאור (שווה ערך ל-ISO)"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>‎"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"אמן"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"מלחין"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"אלבום"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"מיקום"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Stream types"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"‏גודל קובץ RAW (בייט)"</string>
+</resources>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 517a353..ede6479 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"דחוס"</string>
     <string name="menu_extract" msgid="8171946945982532262">"חלץ לתיקייה…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"שנה שם"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"מידע על המסמך"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"מידע על המסמך"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"הצג ב-<xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"חלון חדש"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"גזור"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"העבר"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"ביטול"</string>
     <string name="button_retry" msgid="4011461781916631389">"נסה שנית"</string>
+    <string name="button_clear" msgid="5412304437764369441">"ניקוי"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"הצג באפליקציה של הספק"</string>
     <string name="not_sorted" msgid="7813496644889115530">"לא ממוין"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"שם"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"סיכום"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"גודל"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"שינוי אחרון"</string>
     <string name="directory_items" msgid="6645621978998614003">"מספר הפריטים"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"אפשר לפתוח קבצים מהסוג הזה באמצעות"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"הקובץ הזה שייך ל-"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"אפליקציות אחרות יכולות לפתוח קבצים מהסוג הזה. בטל את ההגדרה של"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"כברירת המחדל."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"ביטול"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"הצג בספק"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"לא נבחרה"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"לא ידועה"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"סדר עולה"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"סדר יורד"</string>
     <string name="drawer_open" msgid="8071673398187261741">"הצג שורשים"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"לא ניתן לפתוח את הקובץ"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"לא ניתן לפתוח קבצים בארכיונים"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"לא ניתן למחוק חלק מהמסמכים"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"לא ניתן היה לטעון מאפיינים"</string>
     <string name="share_via" msgid="8725082736005677161">"שתף באמצעות"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"מעתיק קבצים"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"דוחס קבצים"</string>
@@ -129,11 +122,11 @@
       <item quantity="one">מוחק פריט <xliff:g id="COUNT_0">%1$d</xliff:g>.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"ביטול"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"מתכונן להעתקה..."</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"מתכונן לדחיסה..."</string>
-    <string name="extract_preparing" msgid="58266275455027829">"מתכונן לשליפה…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"מתכונן להעברה…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"מתכונן למחיקה…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"בהכנה…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"בהכנה…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"בהכנה…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"בהכנה…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"בהכנה…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="two">לא ניתן היה להעתיק <xliff:g id="COUNT_1">%1$d</xliff:g> פריטים</item>
@@ -213,7 +206,7 @@
     <string name="open_external_dialog_root_request" msgid="6776729293982633">"האם להעניק לאפליקציה <xliff:g id="APPNAME"><b>^1</b></xliff:g> גישה לנתונים שלך, כולל תמונות וסרטונים, השמורים ב<xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
     <string name="never_ask_again" msgid="525908236522201138">"ראיתי פעם אחת, זה מספיק"</string>
     <string name="allow" msgid="1275746941353040309">"כן, זה בסדר"</string>
-    <string name="deny" msgid="5127201668078153379">"לא, אין מצב"</string>
+    <string name="deny" msgid="5127201668078153379">"לא, תודה"</string>
     <plurals name="elements_selected" formatted="false" msgid="4448165978637163692">
       <item quantity="two"><xliff:g id="COUNT_1">%1$d</xliff:g> נבחרו</item>
       <item quantity="many"><xliff:g id="COUNT_1">%1$d</xliff:g> נבחרו</item>
@@ -255,5 +248,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"archive<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"להחליף את <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"המשך ברקע"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"מידע על ניפוי באגים (פיתוח בלבד)"</string>
 </resources>
diff --git a/res/values-ja/inspector_strings.xml b/res/values-ja/inspector_strings.xml
new file mode 100644
index 0000000..eb9737a
--- /dev/null
+++ b/res/values-ja/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"情報"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"ファイル情報を読み込めませんでした"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"デバッグ情報(デベロッパーのみ)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"未加工のメタデータ: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"メディアの詳細"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"このファイル形式を開けるアプリ"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"このファイルの提供元"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"未選択"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"不明"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"サイズ"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"座標"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"高度"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"カメラ"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"絞り"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"シャッター スピード"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"時間"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"撮影"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"レンズ焦点距離"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO 相当"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"アーティスト"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"作曲者"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"アルバム"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"場所"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"ストリーム タイプ"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"未加工のサイズ(バイト)"</string>
+</resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 8fdb5b7..8c4d5db 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"圧縮"</string>
     <string name="menu_extract" msgid="8171946945982532262">"次の場所に解凍…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"名前を変更"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"情報を見る"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"情報を見る"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"<xliff:g id="SOURCE">%1$s</xliff:g>に表示"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"新しいウィンドウ"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"切り取り"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"移動"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"非表示"</string>
     <string name="button_retry" msgid="4011461781916631389">"再試行"</string>
+    <string name="button_clear" msgid="5412304437764369441">"削除"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"プロバイダで表示"</string>
     <string name="not_sorted" msgid="7813496644889115530">"並べ替えなし"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"名前"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"概要"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"サイズ"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"最終変更"</string>
     <string name="directory_items" msgid="6645621978998614003">"アイテム数"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"このファイル形式を開けるアプリ"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"このファイルのプロバイダ"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"このファイル形式は他のアプリでも開けます。デフォルトのアプリ"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"を削除します。"</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"削除"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"プロバイダで表示"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"選択されていません"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"不明"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"昇順"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"降順"</string>
     <string name="drawer_open" msgid="8071673398187261741">"ルートを表示する"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"ファイルを開けません"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"アーカイブ内のファイルを開くことはできません"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"一部のドキュメントを削除できません"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"プロパティを読み込めませんでした"</string>
     <string name="share_via" msgid="8725082736005677161">"共有ツール"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"ファイルのコピー中"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"ファイルの圧縮中"</string>
@@ -119,11 +112,11 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> 件のアイテムを削除しています。</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"元に戻す"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"コピーの準備をしています…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"圧縮の準備をしています…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"解凍を準備しています…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"移動の準備をしています…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"削除の準備をしています…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"準備しています…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"準備しています…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"準備しています…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"準備しています…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"準備しています…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> 件のアイテムをコピーできませんでした</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"archive<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"<xliff:g id="NAME">%1$s</xliff:g> を上書きしますか?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"バックグラウンドで続行"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"デバッグ情報(デベロッパーのみ)"</string>
 </resources>
diff --git a/res/values-ka/inspector_strings.xml b/res/values-ka/inspector_strings.xml
new file mode 100644
index 0000000..bb3cab1
--- /dev/null
+++ b/res/values-ka/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"ინფორმაცია"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"ფაილის ინფორმაციის ჩატვირთვა ვერ მოხერხდა"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"შეცდომების გამართვის ინფორმაცია (მხოლოდ დეველ.)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"ნედლი მეტა-მონაცემები: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"მედიის დეტალები"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"ამ ტიპის ფაილი იხსნება"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"ფაილის მომწოდებელი:"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"არ არის არჩეული"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"უცნობი"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"ზომები"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> — <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>მეგაპიქსელი"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"კოორდინატები"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"სიმაღლე"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"კამერა"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g>, <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"აპერტურა"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"ობიექტივის საკეტის სისწრაფე"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"ხანგრძლივობა"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"გადაღებულია:"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"ფოკუსური მანძილი"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>მმ"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO-ს ეკვივალენტი"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO: <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"შემსრულებელი"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"კომპოზიტორი"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"ალბომი"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"მდებარეობა"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"სტრიმინგის ტიპები"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"ნედლი ზომა (ბაიტები)"</string>
+</resources>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index c4bf019..424dda0 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"შეკუმშვა"</string>
     <string name="menu_extract" msgid="8171946945982532262">"ამოღება…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"გადარქმევა"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"ინფორმაციის მიღება"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"ინფორმაციის მიღება"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"<xliff:g id="SOURCE">%1$s</xliff:g>-ში ნახვა"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"ახალი ფანჯარა"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"ამოჭრა"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"გადაადგილება"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"უარყოფა"</string>
     <string name="button_retry" msgid="4011461781916631389">"ხელახლა ცდა"</string>
+    <string name="button_clear" msgid="5412304437764369441">"გასუფთავება"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"პროვაიდერში ჩვენება"</string>
     <string name="not_sorted" msgid="7813496644889115530">"დაულაგებელი"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"სახელი"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"რეზიუმე"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"ზომა"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"ცვლილება"</string>
     <string name="directory_items" msgid="6645621978998614003">"ერთეულების რაოდენობა"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"ამ ტიპის ფაილი იხსნება"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"ეს ფაილი ეკუთვნის"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"ფაილის ამ ტიპის გახსნა სხვა აპებითაც შეიძლება. გასუფთავება"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"როგორც ნაგულისხმევი."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"გასუფთავება"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"პროვაიდერში ჩვენება"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"არ არის არჩეული"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"უცნობი"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"ზრდადი"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"კლებადი"</string>
     <string name="drawer_open" msgid="8071673398187261741">"ფესვების ჩვენება"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"ფაილის გახსნა ვერ ხერხდება"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"არქივებში განთავსებული ფაილების გახსნა ვერ მოხერხდა"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"ზოგიერთი დოკუმენტის წაშლა ვერ ხერხდება"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"მახასიათებლების ჩატვირთვა ვერ მოხერხდა"</string>
     <string name="share_via" msgid="8725082736005677161">"გაზიარება…"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"ფაილების კოპირება…"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"მიმდინარეობს ფაილების შეკუმშვა"</string>
@@ -119,11 +112,11 @@
       <item quantity="one">მიმდინარეობს <xliff:g id="COUNT_0">%1$d</xliff:g> ერთეულის წაშლა.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"მოქმედების გაუქმება"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"მზადდება კოპირებისთვის…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"მზადდება შესაკუმშად…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"მზადდება ამოღებისთვის…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"მზადდება გადაადგილებისთვის..."</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"მზადდება წასაშლელად…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"მზადდება..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"მზადდება..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"მზადდება..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"მზადდება..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"მზადდება..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>-დან"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ერთეული ვერ დაკოპირდა</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"არქივი<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"გსურთ <xliff:g id="NAME">%1$s</xliff:g>-ზე გადაწერა?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"ფონურ რეჟიმში გაგრძელება"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"შეცდომების გამართვის ინფორმაცია (მხოლოდ დეველ.)"</string>
 </resources>
diff --git a/res/values-kk/inspector_strings.xml b/res/values-kk/inspector_strings.xml
new file mode 100644
index 0000000..88991f3
--- /dev/null
+++ b/res/values-kk/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Ақпарат"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Файл ақпараты жүктелмеді"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Түзету туралы ақпарат (тек әзірлеуші)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"RAW метадеректері: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Медиамазмұн деректері"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Мұндай файл түрі келесі қолданбамен ашылады"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Файлды ұсынушы"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Таңдалмады"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Белгісіз"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Өлшемдер"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> МП"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Координаталар"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Биіктік"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Камера"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Aпертура"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Ысырма жылдамдығы"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Ұзақтығы"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Түсірілді"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Фокус қашықтығы"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> мм"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO баламасы"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO жылдамдығы: <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Орындаушы"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Композитор"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Альбом"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Орын"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Трансляция түрлері"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"RAW файлының өлшемі (байт)"</string>
+</resources>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 1aa311d..60ed5e8 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Сығу"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Алынуда…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Атауын өзгерту"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Ақпарат алу"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Ақпарат алу"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"<xliff:g id="SOURCE">%1$s</xliff:g> ішінде көру"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Жаңа терезе"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Қиып алу"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Тасымалдау"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Жабу"</string>
     <string name="button_retry" msgid="4011461781916631389">"Әрекетті қайталау"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Өшіру"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Провайдерде көрсету"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Сұрыпталмаған"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Аты"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Жиынтық мәлімет"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Көлемі"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Өзгертілген уақыты"</string>
     <string name="directory_items" msgid="6645621978998614003">"Элементтер саны"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Файлдың бұл түрі келесі арқылы ашылады"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Бұл файл келесіге жатады"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Бұл файл түрін басқа қолданбалар аша алады. Әдепкі"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"ретінде тазалау."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Тазалау"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Провайдерде көрсету"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Таңдалмады"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Белгісіз"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Арту ретімен"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Кему ретімен"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Түбір қалтаны көрсету"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Файл ашылмады"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Мұрағаттағы файлдар ашылмайды"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Кейбір құжаттар жойылмады"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Сипаттар жүктелмеді"</string>
     <string name="share_via" msgid="8725082736005677161">"Бөлісу әдісі"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Файлдар көшірілуде"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Файлдар сығу"</string>
@@ -119,11 +112,11 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> файл жойылуда.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Қайтару"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Көшіруге дайындау…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Сығуға дайындалуда…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Шығарып алуға дайындалуда…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Тасымалдауға дайындау..."</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Жоюға дайындалуда…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Дайындалуда…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Дайындалуда…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Дайындалуда…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Дайындалуда…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Дайындалуда…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файл көшірілмеді</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"archive<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"<xliff:g id="NAME">%1$s</xliff:g> қайта жазылсын ба?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Фонда жалғастыру"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Түзету туралы ақпарат (тек әзірлеуші)"</string>
 </resources>
diff --git a/res/values-km/inspector_strings.xml b/res/values-km/inspector_strings.xml
new file mode 100644
index 0000000..a199a86
--- /dev/null
+++ b/res/values-km/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"ព័ត៌មាន"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"មិនអាច​ផ្ទុកព័ត៌មាន​ឯកសារបានទេ"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"ព័ត៌មាន​អំពីការ​ជួសជុល (dev ប៉ុណ្ណោះ)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"ទិន្នន័យមេតា​ដើម៖ <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"ព័ត៌មាន​លម្អិតអំពី​មេឌៀ"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"ប្រភេទ​ឯកសារ​នេះបើក​ដោយប្រើ"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"ឯកសារនេះ​ត្រូវបានផ្ដល់ដោយ"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"មិនបាន​ជ្រើសរើស"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"មិន​ស្គាល់"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"ទំហំ"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"កូអរដោណេ"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"រយៈកម្ពស់"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"កាមេរ៉ា"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"ជម្រៅ​រូបភាព"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"ល្បឿនពន្លឺរូបថត"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"រយៈពេល"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"ថត​នៅថ្ងៃទី"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"ប្រវែង​ផ្ដោត"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ល្បឿន ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"សិល្បករ"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"អ្នកតាក់តែង"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"អាល់ប៊ុម"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"ទីកន្លែង"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"ប្រភេទការផ្សាយ"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"ទំហំដើម (បៃ)"</string>
+</resources>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 59df358..974257f 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"បង្ហាប់"</string>
     <string name="menu_extract" msgid="8171946945982532262">"ស្រង់​ទៅ…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"ប្ដូរឈ្មោះ"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"ទទួល​ព័ត៌មាន"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"ទទួល​ព័ត៌មាន"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"មើល​នៅក្នុង <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"ផ្ទាំងវិនដូថ្មី"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"កាត់"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"ផ្លាស់ទី"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"បដិសេធ"</string>
     <string name="button_retry" msgid="4011461781916631389">"ព្យាយាម​ម្តង​ទៀត"</string>
+    <string name="button_clear" msgid="5412304437764369441">"សម្អាត"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"បង្ហាញ​នៅក្នុង​ក្រុមហ៊ុន​ផ្តល់សេវា"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Not sorted"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"ឈ្មោះ"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"សេចក្តីសង្ខេប"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"ទំហំ"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"បានកែសម្រួល"</string>
     <string name="directory_items" msgid="6645621978998614003">"ចំនួន​ធាតុ"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"ប្រភេទ​ឯកសារ​នេះបើក​ដោយប្រើ"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"ឯកសារ​នេះជា​កម្មសិទ្ធិ​របស់"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"កម្មវិធីផ្សេងទៀតអាចបើកប្រភេទឯកសារនេះបាន។ សម្អាត"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"ជា​លំនាំដើម។"</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"សម្អាត"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"បង្ហាញ​នៅក្នុង​ក្រុមហ៊ុន​ផ្តល់សេវា"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"មិនបាន​ជ្រើសរើស"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"មិន​ស្គាល់"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"ឡើង"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"ចុះ"</string>
     <string name="drawer_open" msgid="8071673398187261741">"បង្ហាញ roots"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"មិនអាចបើកឯកសារបានទេ"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"មិនអាចបើក​ឯកសារ​នៅក្នុងបណ្ណសារបានទេ"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"មិនអាចលុបឯកសារមួយចំនួន"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"មិន​អាចផ្ទុក​លក្ខណសម្បត្តិបានទេ"</string>
     <string name="share_via" msgid="8725082736005677161">"ចែករំលែក​តាម"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"កំពុងចម្លងឯកសារ"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"កំពុង​បង្ហាប់​ឯកសារ"</string>
@@ -119,11 +112,11 @@
       <item quantity="one">កំពុង​លុបធាតុ <xliff:g id="COUNT_0">%1$d</xliff:g> ។</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"មិនធ្វើវិញ"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"កំពុងរៀបចំចម្លង…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"កំពុង​រៀបចំ​បង្ហាប់…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"កំពុង​រៀបចំ​ស្រង់…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"កំពុងរៀបចំផ្លាស់ទី…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"កំពុងរៀបចំលុប…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"កំពុងរៀបចំ..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"កំពុងរៀបចំ..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"កំពុងរៀបចំ..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"កំពុងរៀបចំ..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"កំពុងរៀបចំ..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other">មិនអាច​ចម្លងធាតុ <xliff:g id="COUNT_1">%1$d</xliff:g> បានទេ</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"បណ្ណសារ<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"ចម្លងជាន់ពីលើ <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"បន្ត​នៅផ្ទៃ​ខាងក្រោយ"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"ព័ត៌មាន​អំពីការ​ជួសជុល (dev ប៉ុណ្ណោះ)"</string>
 </resources>
diff --git a/res/values-kn/inspector_strings.xml b/res/values-kn/inspector_strings.xml
new file mode 100644
index 0000000..29481bb
--- /dev/null
+++ b/res/values-kn/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"ಮಾಹಿತಿ"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"ಫೈಲ್ ಮಾಹಿತಿಯನ್ನು ಲೋಡ್ ಮಾಡಲಾಗಲಿಲ್ಲ"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"ಡೀಬಗ್‌ ಮಾಹಿತಿ (dev ಮಾತ್ರ)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Raw ಮೆಟಾಡೇಟಾ: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"ಮಾಧ್ಯಮ ವಿವರಗಳು"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"ಈ ಪ್ರಕಾರದ ಫೈಲ್ ಇದರ ಮೂಲಕ ತೆರೆಯುತ್ತದೆ"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"ಈ ಫೈಲ್ ಅನ್ನು ವಿತರಿಸಿದವರು"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"ಆಯ್ಕೆಮಾಡಲಾಗಿಲ್ಲ"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"ಅಪರಿಚಿತ"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"ಅಳತೆಗಳು"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>ಎಮ್‌ಪಿ"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"ಅಕ್ಷಾಂಶಗಳು"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"ಎತ್ತರ"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"ಕ್ಯಾಮರಾ"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"ಅಪರ್ಚರ್‌‌"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"ಶಟರ್ ವೇಗ"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"ಅವಧಿ"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"ತೆಗೆದುಕೊಂಡಾಗ"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"ಫೋಕಲ್ ಅಂತರ"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>ಮಿಮೀ"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO ಸಮಾನ"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"ಕಲಾವಿದರು"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"ಸಂಯೋಜಕ"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"ಆಲ್ಬಮ್‌"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"ಸ್ಥಳ"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"ಸ್ಟ್ರೀಮ್ ವಿಧಗಳು"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"RAW ಗಾತ್ರ (ಬೈಟ್‌ಗಳು)"</string>
+</resources>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index c57939b..279e2c9 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"ಕುಗ್ಗಿಸಿ"</string>
     <string name="menu_extract" msgid="8171946945982532262">"ಇದಕ್ಕೆ ಬೇರ್ಪಡಿಸಲಾಗಿದೆ…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"ಮರುಹೆಸರಿಸು"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"ಮಾಹಿತಿಯನ್ನು ಪಡೆಯಿರಿ"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"ಮಾಹಿತಿಯನ್ನು ಪಡೆಯಿರಿ"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"<xliff:g id="SOURCE">%1$s</xliff:g> ನಲ್ಲಿ ವೀಕ್ಷಿಸಿ"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"ಹೊಸ ವಿಂಡೋ"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"ಕತ್ತರಿಸು"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"ಸರಿಸು"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"ವಜಾಗೊಳಿಸಿ"</string>
     <string name="button_retry" msgid="4011461781916631389">"ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ"</string>
+    <string name="button_clear" msgid="5412304437764369441">"ತೆರವುಗೊಳಿಸಿ"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"ಒದಗಿಸುವವರಲ್ಲಿ ತೋರಿಸಿ"</string>
     <string name="not_sorted" msgid="7813496644889115530">"ವಿಂಗಡಿಸಲಾಗಿಲ್ಲ"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"ಹೆಸರು"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"ಸಾರಾಂಶ"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"ಗಾತ್ರ"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"ಮಾರ್ಪಾಡು"</string>
     <string name="directory_items" msgid="6645621978998614003">"ಐಟಂಗಳ ಸಂಖ್ಯೆ"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"ಈ ಪ್ರಕಾರದ ಫೈಲ್ ಇದರ ಮೂಲಕ ತೆರೆಯುತ್ತದೆ"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"ಈ ಫೈಲ್ ಇದಕ್ಕೆ ಸೇರಿದೆ:"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"ಇತರ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಈ ಫೈಲ್ ಪ್ರಕಾರವನ್ನು ತೆರೆಯಬಹುದು. ತೆರವುಗೊಳಿಸಿ"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"ಡಿಫಾಲ್ಟ್‌ನಂತೆ"</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"ತೆರವುಗೊಳಿಸಿ"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"ಒದಗಿಸುವವರಲ್ಲಿ ತೋರಿಸಿ"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"ಆಯ್ಕೆಮಾಡಲಾಗಿಲ್ಲ"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"ಅಪರಿಚಿತ"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"ಆರೋಹಣ"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"ಅವರೋಹಣ"</string>
     <string name="drawer_open" msgid="8071673398187261741">"ರೂಟ್‌ಗಳನ್ನು ತೋರಿಸು"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"ಫೈಲ್ ತೆರೆಯಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"ಆರ್ಕೈವ್‌ಗಳಲ್ಲಿ ಫೈಲ್‌ಗಳನ್ನು ತೆರೆಯಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"ಕೆಲವು ಡಾಕ್ಯುಮೆಂಟ್‌ಗಳನ್ನು ಅಳಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"ಗುಣಲಕ್ಷಣಗಳನ್ನು ಲೋಡ್ ಮಾಡುವುದು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string>
     <string name="share_via" msgid="8725082736005677161">"ಈ ಮೂಲಕ ಹಂಚಿಕೊಳ್ಳಿ"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"ಫೈಲ್‌ಗಳನ್ನು ನಕಲಿಸಲಾಗುತ್ತಿದೆ"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"ಫೈಲ್‌ ಕುಗ್ಗಿಸಲಾಗುತ್ತಿದೆ"</string>
@@ -119,11 +112,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>ಐಟಂಗಳನ್ನು ಅಳಿಸಲಾಗುತ್ತಿದೆ.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"ರದ್ದುಮಾಡಿ"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"ನಕಲಿಸಲು ಸಿದ್ಧಪಡಿಸಲಾಗುತ್ತಿದೆ..."</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"ಕುಗ್ಗಿಸಲು ತಯಾರಿ ಮಾಡಲಾಗುತ್ತಿದೆ..."</string>
-    <string name="extract_preparing" msgid="58266275455027829">"ಹೊರತೆಗೆಯಲು ಸಿದ್ಧವಾಗುತ್ತಿದೆ..."</string>
-    <string name="move_preparing" msgid="8742573245485449429">"ಸರಿಸಲು ಸಿದ್ಧಪಡಿಸಲಾಗುತ್ತಿದೆ…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"ಅಳಿಸಲು ಸಿದ್ಧಪಡಿಸಲಾಗುತ್ತಿದೆ…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"ಸಿದ್ಧಪಡಿಸಲಾಗುತ್ತಿದೆ..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"ಸಿದ್ಧಪಡಿಸಲಾಗುತ್ತಿದೆ..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"ಸಿದ್ಧಪಡಿಸಲಾಗುತ್ತಿದೆ..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"ಸಿದ್ಧಪಡಿಸಲಾಗುತ್ತಿದೆ..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"ಸಿದ್ಧಪಡಿಸಲಾಗುತ್ತಿದೆ..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>ಐಟಂ ಅನ್ನು ನಕಲು ಮಾಡಲಾಗಲಿಲ್ಲ</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"archive<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"<xliff:g id="NAME">%1$s</xliff:g> ಅನ್ನು ತಿದ್ದಿಬರೆಯಬೇಕೇ?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"ಹಿನ್ನೆಲೆಯಲ್ಲಿ ಮುಂದುವರಿಯಿರಿ"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"ಡೀಬಗ್‌ ಮಾಹಿತಿ (dev ಮಾತ್ರ)"</string>
 </resources>
diff --git a/res/values-ko/inspector_strings.xml b/res/values-ko/inspector_strings.xml
new file mode 100644
index 0000000..97acd80
--- /dev/null
+++ b/res/values-ko/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"정보"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"파일 정보를 로드할 수 없습니다"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"디버그 정보(개발자 전용)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"원본 메타데이터: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"미디어 세부정보"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"이 유형의 파일에 연결된 앱"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"파일 제공자:"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"선택되지 않음"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"알 수 없음"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"크기"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g>x<xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"좌표"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"고도"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"카메라"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"조리개"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"셔터 속도"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"시간"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"촬영 일시"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"초점 거리"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO 등급"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"아티스트"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"작곡가"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"앨범"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"위치"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"스트림 유형"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"원본 크기(바이트)"</string>
+</resources>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index fe7a251..4eb0d51 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"압축"</string>
     <string name="menu_extract" msgid="8171946945982532262">"다음 위치에 추출..."</string>
     <string name="menu_rename" msgid="1883113442688817554">"이름 바꾸기"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"정보 확인"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"정보 확인"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"<xliff:g id="SOURCE">%1$s</xliff:g>에서 보기"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"새 창"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"잘라내기"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"이동"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"닫기"</string>
     <string name="button_retry" msgid="4011461781916631389">"다시 시도"</string>
+    <string name="button_clear" msgid="5412304437764369441">"삭제"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"제공업체 앱에서 보기"</string>
     <string name="not_sorted" msgid="7813496644889115530">"정렬되지 않음"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"이름"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"요약"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"크기"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"마지막 수정 시간"</string>
     <string name="directory_items" msgid="6645621978998614003">"항목 수"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"이 유형의 파일을 여는 앱"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"파일 제공업체"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"다른 앱에서 이 파일 유형을 열 수 있습니다."</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"을(를) 더 이상 기본 앱으로 사용하지 않습니다."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"삭제"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"제공업체에서 표시"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"선택되지 않음"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"알 수 없음"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"오름차순"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"내림차순"</string>
     <string name="drawer_open" msgid="8071673398187261741">"루트 표시"</string>
@@ -79,7 +73,7 @@
     <string name="save_error" msgid="8631128801982095782">"문서를 저장하지 못했습니다."</string>
     <string name="create_error" msgid="3092144450044861994">"폴더를 만들지 못했습니다."</string>
     <string name="query_error" msgid="6625421453613879336">"현재 콘텐츠를 로드할 수 없습니다."</string>
-    <string name="root_recent" msgid="1080156975424341623">"최근순"</string>
+    <string name="root_recent" msgid="1080156975424341623">"최근"</string>
     <string name="root_available_bytes" msgid="8269870862691408864">"<xliff:g id="SIZE">%1$s</xliff:g> 남음"</string>
     <string name="root_type_service" msgid="6521366147466512289">"저장용량 서비스"</string>
     <string name="root_type_shortcut" msgid="6059343175525442279">"바로가기"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"파일을 열 수 없습니다."</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"보관 파일 안에 있는 파일은 열 수 없습니다."</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"일부 문서를 삭제할 수 없습니다."</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"속성을 로드할 수 없습니다."</string>
     <string name="share_via" msgid="8725082736005677161">"공유에 사용할 앱"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"파일 복사"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"파일 압축 중"</string>
@@ -119,11 +112,11 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g>개의 항목을 삭제 중입니다.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"실행취소"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"사본 준비 중…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"압축 준비 중…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"추출 준비 중…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"이동 준비 중…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"삭제 준비 중..."</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"준비 중..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"준비 중..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"준비 중..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"준비 중..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"준비 중..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>개의 항목을 복사할 수 없음</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"보관처리<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"<xliff:g id="NAME">%1$s</xliff:g>을(를) 덮어쓰시겠습니까?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"백그라운드에서 계속"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"디버그 정보(개발자 전용)"</string>
 </resources>
diff --git a/res/values-ky/inspector_strings.xml b/res/values-ky/inspector_strings.xml
new file mode 100644
index 0000000..a120911
--- /dev/null
+++ b/res/values-ky/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Маалымат"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Файл жөнүндө маалымат жүктөлбөй койду"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Мүчүлүштүктөрдү оңдоо маалыматы (түзм. гана)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Баштапкы метадата: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Медиа маалымат"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Файлдын мындай түрү төмөнкү колдонмо менен ачылат"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Бул файлды жасаган тутум"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Тандалган жок"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Белгисиз"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Чен-өлчөмү"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>Мпикс."</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Координаталар"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Бийиктик"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Камера"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Апертура"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Жапкычтын ылдамдыгы"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Узактыгы"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Тартылган күнү"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Фокустук аралык"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>мм"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO эквиваленти"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Аткаруучу"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Композитор"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Альбом"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Жайгашкан жер"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Агымдын түрү"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Баштапкы өлчөмү (байт)"</string>
+</resources>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 44df1b0..6ac6b2a 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Кысуу"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Төмөнкүгө чыгаруу…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Аталышын өзгөртүү"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Маалымат алуу"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Маалымат алуу"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"<xliff:g id="SOURCE">%1$s</xliff:g> аркылуу көрүү"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Жаңы терезе"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Кесүү"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Жылдыруу"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Көз жаздымда калтыруу"</string>
     <string name="button_retry" msgid="4011461781916631389">"Кайра аракет кылыңыз"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Тазалоо"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Демейки колдонмодон көрсөтүү"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Ылганган эмес"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Аты"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Жыйынтыгы"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Өлчөмү"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Өзгөрүлгөн"</string>
     <string name="directory_items" msgid="6645621978998614003">"Элементтердин саны"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Файлдын мындай түрү төмөнкү колдонмо менен ачылат"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Бул файл төмөнкүгө таандык"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Башка колдонмолор файлдын бул түрүн ача алышат. Тазалоо"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"демейки катары."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Тазалоо"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Демейки колдонмодон көрсөтүү"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Тандалган жок"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Белгисиз"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Чоңойгон ыраатта"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Кичирейген ыраатта"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Папкаларды көрсөтүү"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Файл ачылбай жатат"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Архивделген файлдарды ачуу мүмкүн эмес"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Кээ бир документтерди өчүрүү мүмкүн болбой жатат"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Касиеттери жүктөлбөй койду"</string>
     <string name="share_via" msgid="8725082736005677161">"Бул аркылуу бөлүшүү"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Файлдар көчүрүлүүдө"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Файлдар кысылууда"</string>
@@ -119,11 +112,11 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> нерсе жок кылынууда.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Кайтаруу"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Көчүрүүгө даярдалууда…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Кысууга даярдалууда…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Чыгарууга даярдалууда…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Жылдырууга даярдалууда…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Жок кылууга даярдалууда…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Даярдалууда…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Даярдалууда…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Даярдалууда…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Даярдалууда…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Даярдалууда…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> нерсе көчүрүлбөй койду</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"архив<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"<xliff:g id="NAME">%1$s</xliff:g> файлынын үстүнөн жазылсынбы?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Фондо улантуу"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Мүчүлүштүктөрдү оңдоо маалыматы (түзм. гана)"</string>
 </resources>
diff --git a/res/values-lo/inspector_strings.xml b/res/values-lo/inspector_strings.xml
new file mode 100644
index 0000000..6d02420
--- /dev/null
+++ b/res/values-lo/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"ຂໍ້ມູນ"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"ບໍ່ສາມາດໂຫຼດຂໍ້ມູນໄຟລ໌ໄດ້"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"ຂໍ້ມູນດີບັກ (ນັກພັດທະນາເທົ່ານັ້ນ)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"ເມເຕເດຕາ Raw: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"ລາຍລະອຽດມີເດຍ"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"ໄຟລ໌ປະເພດນີ້ເປີດດ້ວຍ"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"ໄຟລ໌ນີ້ຖືກຈຳໜ່າຍໃຫ້ໂດຍ"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"ບໍ່ໄດ້ເລືອກ"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"ບໍ່ຮູ້ຈັກ"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"ຂະໜາດພາບ"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"ພິກັດ"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"ຄວາມສູງ"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"ກ້ອງຖ່າຍຮູບ"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"ຮູຮັບແສງ"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"ຄວາມໄວຊັດເຕີ"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"ໄລຍະເວລາ"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"ຖ່າຍເມື່ອ"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"ທາງຍາວໂຟກັສ"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO ທຽບເທົ່າ"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"ສິນລະປິນ"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"ຜູ້ແຕ່ງ"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"ອະລະບໍ້າ"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"ສະຖານທີ່"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"ປະເພດສະຕຣີມ"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"ຂະໜາດ Raw (ໄບຕ໌)"</string>
+</resources>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index c327482..fc9cfe8 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"ບີບອັດ"</string>
     <string name="menu_extract" msgid="8171946945982532262">"ແຕກໄຟລ໌ໄປ…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"ປ່ຽນຊື່"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"ຂໍຂໍ້ມູນ"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"ຂໍຂໍ້ມູນ"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"ເບິ່ງໃນ <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"ໜ້າຈໍໃໝ່"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"ຕັດ"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"ຍ້າຍ"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"ປິດໄວ້"</string>
     <string name="button_retry" msgid="4011461781916631389">"ລອງໃໝ່ອີກເທື່ອໜຶ່ງ"</string>
+    <string name="button_clear" msgid="5412304437764369441">"ລຶບລ້າງ"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"ສະແດງໃນຜູ້ໃຫ້ບລິການ"</string>
     <string name="not_sorted" msgid="7813496644889115530">"ບໍ່ໄດ້ຈັດຮຽງ"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"ຊື່"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"ສະຫຼຸບ"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"ຂະໜາດ"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"ແກ້ໄຂເມື່ອ"</string>
     <string name="directory_items" msgid="6645621978998614003">"ຈໍານວນລາຍການ"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"ໄຟລ໌ປະເພດນີ້ເປີດດ້ວຍ"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"This file belongs to"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"ແອັບອື່ນສາມາດເປີດໄຟລ໌ປະເພດນີ້ໄດ້. ລຶບລ້າງ"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"ຕັ້ງເປັນຄ່າເລີ່ມຕົ້ນ."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"ລຶບລ້າງ"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"ສະແດງໃນຜູ້ໃຫ້ບລິການ"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"ບໍ່ໄດ້ເລືອກ"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"ບໍ່ຮູ້ຈັກ"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"ໃຫຍ່ຫານ້ອຍ"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"ນ້ອຍຫາໃຫຍ່"</string>
     <string name="drawer_open" msgid="8071673398187261741">"ສະແດງ roots"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"ບໍ່ສາມາດເປີດໄຟລ໌ໄດ້"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"ບໍ່ສາມາດເປີດໄຟລ໌ໃນແຟ້ມຈັດເກັບໄດ້"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"ບໍ່ສາມາດລຶບບາງເອກະສານໄດ້"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"ບໍ່ສາມາດໂຫຼດຄຸນສົມບັດໄດ້"</string>
     <string name="share_via" msgid="8725082736005677161">"ແບ່ງປັນຜ່ານ"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"ກຳລັງສຳເນົາໄຟລ໌"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"ກຳລັງບີບອັດໄຟລ໌"</string>
@@ -119,11 +112,11 @@
       <item quantity="one">ກຳ​ລັງ​ລຶບ <xliff:g id="COUNT_0">%1$d</xliff:g> ໄຟ​ລ໌.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"ຍົກເລີກ"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"ກຳລັງກຽມການສຳເນົາ…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"ກຳລັງກຽມບີບໄຟລ໌…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"ກຳລັງກະກຽມແຕກໄຟລ໌..."</string>
-    <string name="move_preparing" msgid="8742573245485449429">"ກຳລັງກະກຽມຍ້າຍ…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"ກຳລັງກະກຽມການລຶບ…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"ກຳລັງກະກຽມ..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"ກຳລັງກະກຽມ..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"ກຳລັງກະກຽມ..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"ກຳລັງກະກຽມ..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"ກຳລັງກະກຽມ..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other">ບໍ່ສາມາດສຳເນົາໄຟລ໌ <xliff:g id="COUNT_1">%1$d</xliff:g> ໄຟລ໌ໄດ້.</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"archive<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"ຂຽນທັບ <xliff:g id="NAME">%1$s</xliff:g> ບໍ?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"ສືບຕໍ່ໃນພື້ນຫຼັງ"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"ຂໍ້ມູນດີບັກ (ນັກພັດທະນາເທົ່ານັ້ນ)"</string>
 </resources>
diff --git a/res/values-lt/inspector_strings.xml b/res/values-lt/inspector_strings.xml
new file mode 100644
index 0000000..20c28bb
--- /dev/null
+++ b/res/values-lt/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Informacija"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Nepavyko įkelti failo"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Derinimo informacija (tik kūrėjams)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Neapdoroto failo metaduomenys: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Išsami medijos informacija"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Šio tipo failas atidaromas naudojant"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Šį failą teikia"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Nepasirinkta"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Nežinoma"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Matmenys"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> – <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Koordinatės"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Aukštis virš jūros lygio"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Fotoaparatas"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Diafragma"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Užrakto greitis"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Trukmė"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Nufotografuota"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Židinio nuotolis"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO ekvivalentas"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Atlikėjas"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Kompozitorius"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Albumas"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Vieta"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Srautų tipai"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Neapdoroto failo dydis (baitais)"</string>
+</resources>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 4326dc8..3fa9553 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Suglaudinti"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Išskleisti į..."</string>
     <string name="menu_rename" msgid="1883113442688817554">"Pervardyti"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Gauti informacijos"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Gauti informacijos"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Žr. <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Naujas langas"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Iškirpti"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Perkelti"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Atsisakyti"</string>
     <string name="button_retry" msgid="4011461781916631389">"Bandyti dar kartą"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Išvalyti"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Rodyti naudojant teikėjo programą"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Nerūšiuota"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Pavadinimas"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Suvestinė"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Dydis"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Pakeista"</string>
     <string name="directory_items" msgid="6645621978998614003">"Elementų skaičius"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Šio tipo failas atidaromas naudojant"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Šis failas priklauso"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Šio tipo failą galima atidaryti kitomis programomis. Išvalykite"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"kaip numatytąją."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Išvalyti"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Rodyti naudojant teikėjo programą"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Nepasirinkta"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Nežinoma"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Didėjimo tvarka"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Mažėjimo tvarka"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Rodyti šaknis"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Nepavyksta atidaryti failo"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Negalima atidaryti failų archyvuose"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Nepavyko ištrinti kai kurių dokumentų"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Nepavyko įkelti nuosavybių"</string>
     <string name="share_via" msgid="8725082736005677161">"Bendrinti naudojant"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Kopijuojami failai"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Glaudinami failai"</string>
@@ -129,11 +122,11 @@
       <item quantity="other">Ištrinama <xliff:g id="COUNT_1">%1$d</xliff:g> elementų.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Anuliuoti"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Ruošiamasi kopijuoti…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Ruošiamasi glaudinti…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Ruošiamasi išskleisti…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Ruošiamasi perkelti…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Ruošiama ištrinti…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Ruošiama..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Ruošiama..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Ruošiama..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Ruošiama..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Ruošiama..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one">Nepavyko nukopijuoti <xliff:g id="COUNT_1">%1$d</xliff:g> elemento</item>
@@ -255,5 +248,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"archyvas<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Perrašyti „<xliff:g id="NAME">%1$s</xliff:g>“?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Tęsti fone"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Derinimo informacija (tik kūrėjams)"</string>
 </resources>
diff --git a/res/values-lv/inspector_strings.xml b/res/values-lv/inspector_strings.xml
new file mode 100644
index 0000000..739d519
--- /dev/null
+++ b/res/values-lv/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Informācija"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Nevarēja ielādēt faila informāciju"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Atkļūdošanas informācija (tikai izstrādātājiem)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Neapstrādāti metadati: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Multivides informācija"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Šāda veida failu var atvērt lietotnē"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Šis fails ir nodrošināts lietotnē"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Nav atlasīta"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Nezināma"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Izmēri"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> — <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Koordinātas"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Augstums"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Kamera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Diafragmas atvērums"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Slēdža ātrums"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Ilgums"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Uzņemts:"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Fokusa attālums"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO ekvivalents"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Izpildītājs"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Komponists"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Albums"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Atrašanās vieta"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Straumes veidi"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Neapstrādāta faila lielums (baiti)"</string>
+</resources>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 1bef42a..d4141f0 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Saspiest"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Izvilkt..."</string>
     <string name="menu_rename" msgid="1883113442688817554">"Pārdēvēt"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Saņemt informāciju"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Iegūt informāciju"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Skatīt, izmantojot <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Jauns logs"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Izgriezt"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Pārvietot"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Nerādīt"</string>
     <string name="button_retry" msgid="4011461781916631389">"Mēģināt vēlreiz"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Dzēst"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Rādīt nodrošinātājā"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Nav kārtoti"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Nosaukums"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Kopsavilkums"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Lielums"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Izmaiņas"</string>
     <string name="directory_items" msgid="6645621978998614003">"Vienumu skaits"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Šāda veida failu var atvērt lietotnē"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Šis fails pieder:"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Citas lietotnes var atvērt šī tipa failu. Dzēst"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"kā noklusējumu."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Dzēst"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Rādīt nodrošinātājā"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Nav atlasīta"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Nezināma"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Augošā secībā"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Dilstošā secībā"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Rādīt saknes"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Nevar atvērt failu."</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Nevar atvērt arhīvos esošos failus"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Nevar izdzēst dažus dokumentus."</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Nevarēja ielādēt rekvizītus"</string>
     <string name="share_via" msgid="8725082736005677161">"Kopīgošanas veids"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Failu kopēšana"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Failu saspiešana"</string>
@@ -124,11 +117,11 @@
       <item quantity="other">Tiek dzēsti <xliff:g id="COUNT_1">%1$d</xliff:g> vienumi.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Atsaukt"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Notiek sagatavošanās kopēšanai…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Notiek gatavošanās saspiešanai…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Tiek sagatavoti izvilkšanai paredzētie dati."</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Sagatavošanās pārvietošanai…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Notiek sagatavošanās dzēšanai…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Notiek sagatavošana..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Notiek sagatavošana..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Notiek sagatavošana..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Notiek sagatavošana..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Notiek sagatavošana..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> no <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="zero">Nevarēja nokopēt <xliff:g id="COUNT_1">%1$d</xliff:g> vienumus</item>
@@ -234,5 +227,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"arhivs<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Vai pārrakstīt failu <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Turpināt izpildi fonā"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Atkļūdot informāciju (tikai izstrādātājiem)"</string>
 </resources>
diff --git a/res/values-mk/inspector_strings.xml b/res/values-mk/inspector_strings.xml
new file mode 100644
index 0000000..66cc7b6
--- /dev/null
+++ b/res/values-mk/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Информации"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Не можеше да се вчитаат информациите за датотеката"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Информации за отстранување грешки (само за DEV)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Необработени метаподатоци: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Детали за аудиовизуелните содржини"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Овој вид датотека се отвора со"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Датотекава е обезбедена од"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Не е избрана"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Непозната"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Димензии"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> х <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Координати"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Надморска височина"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Камера"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Апертура"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Брзина на блендата"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Времетраење"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Фотографирано на"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Фокусна должина"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> мм"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Еквивалент на ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Изведувач"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Композитор"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Албум"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Локација"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Типови пренос"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Големина на необработена (бајти)"</string>
+</resources>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 03c80e6..fa7e87d 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -41,14 +41,14 @@
     <string name="menu_compress" msgid="37539111904724188">"Компресирај"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Отпакувај во…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Преименувај"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Добијте информации"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Добијте информации"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Прикажи во <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Нов прозорец"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Исечи"</string>
     <string name="menu_copy_to_clipboard" msgid="5064081159073330776">"Копирај"</string>
     <string name="menu_paste_from_clipboard" msgid="360947260414135827">"Залепи"</string>
     <string name="menu_paste_into_folder" msgid="8000644546983240101">"Залепи во папка"</string>
-    <string name="menu_advanced_show" msgid="7558626506462906726">"Прикажи внатр. меморија"</string>
+    <string name="menu_advanced_show" msgid="7558626506462906726">"Прикажи внатрешен капацитет"</string>
     <string name="menu_advanced_hide" msgid="6488381508009246334">"Сокриј внатр. меморија"</string>
     <string name="button_select" msgid="240863497069321364">"Избери"</string>
     <string name="button_copy" msgid="8219059853840996027">"Копирај"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Премести"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Отфрли"</string>
     <string name="button_retry" msgid="4011461781916631389">"Обидете се повторно"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Исчисти"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Прикажи во услугата на операторот"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Неподредени"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Име"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Краток преглед"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Големина"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Изменето"</string>
     <string name="directory_items" msgid="6645621978998614003">"Број на ставки"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Овој вид датотека се отвора со"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Датотекава припаѓа на"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Други апликации може да го отворат овој вид датотека. Избришете ја"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"како стандардна апликација."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Избриши"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Прикажи во услугата"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Не е избрана"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Непозната"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Растечко"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Опаѓачко"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Прикажи корени"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Датотеката не може да се отвори"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Не може да се отвораат датотеките во архивите"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Некои документи не може да се избришат"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Не можеше да се вчитаат својствата"</string>
     <string name="share_via" msgid="8725082736005677161">"Споделете преку"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Се копираат датотеки"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Компримирање датотеки"</string>
@@ -119,11 +112,11 @@
       <item quantity="other">Се бришат <xliff:g id="COUNT_1">%1$d</xliff:g> ставки.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Врати"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Се подготвува за копирање…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Се подготвува за компримирање…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Се подготвува за извлекување…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Се подготвува за преместување…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Се подготвува за бришење…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Се подготвува…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Се подготвува…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Се подготвува…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Се подготвува…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Се подготвува…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one">Не можеше да се копира <xliff:g id="COUNT_1">%1$d</xliff:g> ставка</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"архива<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Да се презапише <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Продолжи во заднина"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Информации за отстранување грешки (само за DEV)"</string>
 </resources>
diff --git a/res/values-ml/inspector_strings.xml b/res/values-ml/inspector_strings.xml
new file mode 100644
index 0000000..0537230
--- /dev/null
+++ b/res/values-ml/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"വിവരം"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"ഫയൽ വിവരം ലോഡുചെയ്യാനായില്ല"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"ഡീബഗ് ‌വിവരങ്ങൾ (dev മാത്രം)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"റോ മെറ്റാഡാറ്റാ: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"മീഡിയ വിശദാംശങ്ങള്‍"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"ഇത്തരത്തിലുള്ള ‌ഫയലുകൾ ‌തുറക്കുന്നു"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"ഈ ഫയൽ വിതരണം ചെയ്യുന്നത്"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"തിരഞ്ഞെടുത്തില്ല"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"അറിയില്ല"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"തലങ്ങൾ"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"കോർഡിനേറ്റുകൾ"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"ഉയരം"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"ക്യാമറ"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"അപ്‌റേച്ചർ"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"ഷട്ടര്‍ വേഗത"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"ദൈര്‍ഘ്യം"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"എടുത്തത്"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"ഫോക്കൽ ദൈർഘ്യം"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>മി.മീ"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO തത്തുല്യം"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"ആർട്ടിസ്‌റ്റ്"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"കമ്പോസർ"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"ആല്‍‌ബം"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"ലൊക്കേഷൻ"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"സ്‌ട്രീം തരങ്ങൾ"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"റോ വലുപ്പം (ബൈറ്റുകൾ)"</string>
+</resources>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 20ecacd..30aae11 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"കംപ്രസ്സുചെയ്യുക"</string>
     <string name="menu_extract" msgid="8171946945982532262">"എക്സ്ട്രാക്റ്റുചെയ്യുക…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"പേരുമാറ്റുക"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"വിവരങ്ങൾ സ്വന്തമാക്കൂ"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"വിവരങ്ങൾ സ്വന്തമാക്കൂ"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"<xliff:g id="SOURCE">%1$s</xliff:g> എന്നതിൽ കാണുക"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"പുതിയ വിന്‍‍ഡോ"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"മുറിക്കുക"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"നീക്കുക"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"ഡിസ്മിസ് ചെയ്യുക"</string>
     <string name="button_retry" msgid="4011461781916631389">"വീണ്ടും ശ്രമിക്കുക"</string>
+    <string name="button_clear" msgid="5412304437764369441">"മായ്‌ക്കുക"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"ദാതാവിൽ കാണിക്കുക"</string>
     <string name="not_sorted" msgid="7813496644889115530">"അടുക്കിയിട്ടില്ല"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"പേര്"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"ചുരുക്കം"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"വലുപ്പം"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"പരിഷ്‌ക്കരിച്ചു"</string>
     <string name="directory_items" msgid="6645621978998614003">"ഇനങ്ങളുടെ എണ്ണം"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"ഇത്തരത്തിലുള്ള ‌ഫയലുകൾ ‌തുറക്കുന്നു"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"ഈ ഫയൽ ഈ ഉപയോക്താവിന്റേതാണ്"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"ഈ ഫയൽ തരം ‌മറ്റ് അപ്പുകൾക്ക് തുറക്കാനാവും. മനസ്സിലായോ"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"ഡിഫോൾട്ടായി."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"മായ്‌ക്കുക"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"ദാതാവിൽ കാണിക്കുക"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"തിരഞ്ഞെടുത്തില്ല"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"അറിയില്ല"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"ആരോഹണം"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"അവരോഹണം"</string>
     <string name="drawer_open" msgid="8071673398187261741">"റൂട്ടുകൾ ദൃശ്യമാക്കുക"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"ഫയൽ തുറക്കാൻ കഴിയില്ല"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"ആർക്കൈവുകളിലെ ഫയലുകൾ തുറക്കാൻ കഴിയില്ല"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"ചില പ്രമാണങ്ങൾ ഇല്ലാതാക്കാനായില്ല"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"പ്രോപ്പർട്ടികൾ ലോഡുചെയ്യാനായില്ല"</string>
     <string name="share_via" msgid="8725082736005677161">"ഇതുവഴി പങ്കിടുക"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"ഫയലുകൾ പകർത്തുന്നു"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"ഫയലുകൾ കംപ്രസ്സുചെയ്യുന്നു"</string>
@@ -119,11 +112,11 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ഇനം ‌ഇല്ലാതാക്കുന്നു.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"പഴയപടിയാക്കുക"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"പകർപ്പിനായി തയ്യാറെടുക്കുന്നു…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"കംപ്രസ്സിന് തയ്യാറെടുക്കുന്നു…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"എക്‌സ്ട്രാക്റ്റിന് തയ്യാറെടുക്കുന്നു…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"നീക്കാനൊരുങ്ങുന്നു…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"ഇല്ലാതാക്കാൻ തയ്യാറെടുക്കുന്നു..."</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"തയ്യാറെടുക്കുന്നു..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"തയ്യാറെടുക്കുന്നു..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"തയ്യാറെടുക്കുന്നു..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"തയ്യാറെടുക്കുന്നു..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"തയ്യാറെടുക്കുന്നു..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ഇനങ്ങൾ ‌പകർത്താനായില്ല</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"ആർക്കൈവ്<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"<xliff:g id="NAME">%1$s</xliff:g> മാറ്റിയെഴുതണോ?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"പശ്ചാത്തലത്തിൽ തുടരുക"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"ഡീബഗ് ‌വിവരങ്ങൾ (dev മാത്രം)"</string>
 </resources>
diff --git a/res/values-mn/inspector_strings.xml b/res/values-mn/inspector_strings.xml
new file mode 100644
index 0000000..a06af5a
--- /dev/null
+++ b/res/values-mn/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Мэдээлэл"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Файлын мэдээллийг ачааллаж чадсангүй"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Дебаг хийх мэдээлэл (зөвхөн хөгжүүлэгчид)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"RAW мета өгөгдөл: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Медианы дэлгэрэнгүй"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Ийм төрлийн файлыг дараахаар нээдэг"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Энэ файлыг дараахаас хангасан"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Сонгоогүй"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Тодорхойгүй"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Хэмжээс"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Координат"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Өндөр"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Камер"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Өрц"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Зураг дарах хурд"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Хугацаа"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Авсан огноо"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Фокусын урт"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO дүйцэх"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Уран бүтээлч"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Хөгжмийн зохиолч"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Цомог"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Байршил"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Цацалтын төрөл"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"RAW-н хэмжээ (байт)"</string>
+</resources>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 972e993..f407d55 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Шахах"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Дараахад задлах…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Нэр өөрчлөх"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Мэдээлэл авах"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Мэдээлэл авах"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"<xliff:g id="SOURCE">%1$s</xliff:g>-д харах"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Шинэ цонх"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Таслах"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Зөөх"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Хаах"</string>
     <string name="button_retry" msgid="4011461781916631389">"Дахин оролдох"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Устгах"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Үйлчилгээ үзүүлэгчид харуулах"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Эрэмбэлээгүй"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Нэр"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Хураангуй"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Хэмжээ"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Өөрчилсөн"</string>
     <string name="directory_items" msgid="6645621978998614003">"Зүйлийн тоо"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Ийм төрлийн файлыг дараахаар нээдэг"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Энэ файл дараахад хамааралтай"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Бусад апп энэ файлын төрлийг нээх боломжтой. Устгах"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"өгөгдмөлөөр."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Устгах"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Үйлчилгээ үзүүлэгчээр харуулах"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Сонгоогүй"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Тодорхойгүй"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Дээшилж буй"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Буурч буй"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Документын санг харуулах"</string>
@@ -85,12 +79,11 @@
     <string name="root_type_shortcut" msgid="6059343175525442279">"Товчлол"</string>
     <string name="root_type_device" msgid="1713604128005476585">"Төхөөрөмж"</string>
     <string name="root_type_apps" msgid="8646073235029886342">"Бусад апп"</string>
-    <string name="empty" msgid="5300254272613103004">"Зүйл алга"</string>
+    <string name="empty" msgid="5300254272613103004">"Хоосон"</string>
     <string name="no_results" msgid="2371026325236359209">"%1$s-д тохирох зүйл алга"</string>
     <string name="toast_no_application" msgid="7555319548595113121">"Файлыг нээх боломжгүй байна"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Архивын файлыг нээх боломжгүй"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Зарим документыг устгах боломжгүй"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Документын мэдээллийг ачааллаж чадсангүй"</string>
     <string name="share_via" msgid="8725082736005677161">"Дараахаар хуваалцах"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Файлыг хуулж байна"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Файлыг шахаж байна"</string>
@@ -119,11 +112,11 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> зүйлийг устгаж байна.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Буцаах"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Хуулахад бэлдэж байна..."</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Шахахад бэлдэж байна..."</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Задлахад бэлдэж байна..."</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Зөөхөд бэлтгэж байна..."</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Устгахад бэлдэж байна..."</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Бэлтгэж байна..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Бэлтгэж байна..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Бэлтгэж байна..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Бэлтгэж байна..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Бэлтгэж байна..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> зүйлийг хуулж чадсангүй</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"архив<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"<xliff:g id="NAME">%1$s</xliff:g>-г дарж бичих үү?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Цаана үргэлжлүүлэх"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Дебаг хийх мэдээлэл (зөвхөн хөгжүүлэгчид)"</string>
 </resources>
diff --git a/res/values-mr/inspector_strings.xml b/res/values-mr/inspector_strings.xml
new file mode 100644
index 0000000..d933b56
--- /dev/null
+++ b/res/values-mr/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"माहिती"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"फाइलची माहिती लोड करता आली नाही"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"डीबग माहिती (फक्त डेव्हलपरसाठी)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"अविश्लेषित मेटाडेटा: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"मीडिया तपशील"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"या प्रकारची फाइल ज्याने उघडेल ते"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"कडून ही फाइल पुरवण्यात आली"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"निवडलेले नाही"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"अज्ञात"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"आकारमान"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"अक्षांश रेखांश"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"उंची"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"कॅमेरा"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"अ‍ॅपर्चर"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"शटर गती"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"कालावधी"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"रोजी घेतला"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"केंद्रावरून लांबी"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>मिमी"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO सारखे"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"कलाकार"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"रचनाकार"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"अल्बम"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"स्थान"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"स्ट्रीम प्रकार"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"रॉ आकार (बाइट)"</string>
+</resources>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index bac45c6..ada11e0 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -28,12 +28,12 @@
     <string name="menu_grid" msgid="1453636521731880680">"ग्रिड दृश्य"</string>
     <string name="menu_list" msgid="6714267452146410402">"सूची"</string>
     <string name="menu_search" msgid="1876699106790719849">"शोधा"</string>
-    <string name="menu_settings" msgid="6520844520117939047">"संचय सेटिंग्ज"</string>
+    <string name="menu_settings" msgid="6520844520117939047">"स्टोरेज सेटिंग्ज"</string>
     <string name="menu_open" msgid="9092138100049759315">"उघडा"</string>
     <string name="menu_open_with" msgid="5507647065467520229">"यासह उघडा"</string>
     <string name="menu_open_in_new_window" msgid="6686563636123311276">"नवीन विंडोमध्ये उघडा"</string>
     <string name="menu_save" msgid="5195367497138965168">"सेव्ह करा"</string>
-    <string name="menu_share" msgid="4307140947108068356">"सामायिक करा"</string>
+    <string name="menu_share" msgid="4307140947108068356">"शेअर करा"</string>
     <string name="menu_delete" msgid="1022254131543256626">"हटवा"</string>
     <string name="menu_select_all" msgid="7600576812185570403">"सर्व निवडा"</string>
     <string name="menu_copy" msgid="7404820171352314754">"यावर कॉपी करा…"</string>
@@ -41,15 +41,15 @@
     <string name="menu_compress" msgid="37539111904724188">"संकुचित करा"</string>
     <string name="menu_extract" msgid="8171946945982532262">"मध्ये काढा..."</string>
     <string name="menu_rename" msgid="1883113442688817554">"पुनर्नामित करा"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"माहिती मिळवा"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"माहिती मिळवा"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"<xliff:g id="SOURCE">%1$s</xliff:g> मध्ये पहा"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"नवीन विंडो"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"कट करा"</string>
     <string name="menu_copy_to_clipboard" msgid="5064081159073330776">"कॉपी करा"</string>
     <string name="menu_paste_from_clipboard" msgid="360947260414135827">"पेस्ट करा"</string>
     <string name="menu_paste_into_folder" msgid="8000644546983240101">"फोल्डरमध्ये पेस्ट करा"</string>
-    <string name="menu_advanced_show" msgid="7558626506462906726">"अंतर्गत संचय दर्शवा"</string>
-    <string name="menu_advanced_hide" msgid="6488381508009246334">"अंतर्गत संचय लपवा"</string>
+    <string name="menu_advanced_show" msgid="7558626506462906726">"अंतर्गत स्टोरेज दर्शवा"</string>
+    <string name="menu_advanced_hide" msgid="6488381508009246334">"अंतर्गत स्टोरेज लपवा"</string>
     <string name="button_select" msgid="240863497069321364">"निवडा"</string>
     <string name="button_copy" msgid="8219059853840996027">"कॉपी करा"</string>
     <string name="button_compress" msgid="8951561310857223966">"संकुचित करा"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"हलवा"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"डिसमिस करा"</string>
     <string name="button_retry" msgid="4011461781916631389">"पुन्हा प्रयत्न करा"</string>
+    <string name="button_clear" msgid="5412304437764369441">"साफ करा"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"पुरवठादारामध्ये दाखवा"</string>
     <string name="not_sorted" msgid="7813496644889115530">"क्रमवारी लावलेली नाही"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"नाव"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"सारांश"</string>
@@ -64,24 +66,16 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"आकार"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"सुधारित"</string>
     <string name="directory_items" msgid="6645621978998614003">"आयटमची संख्या"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"या प्रकारची फाइल याच्यासोबत उघडेल"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"ही फाइल यांच्या मालकीची आहे"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"इतर अॅप्स हा फाइल प्रकार उघडू शकतात. साफ करा"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"डीफॉल्ट म्हणून."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"साफ करा"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"पुरवठादारामध्ये दाखवा"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"निवडलेले नाही"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"अज्ञात"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"चढत्या क्रमाने"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"उतरत्या क्रमाने"</string>
     <string name="drawer_open" msgid="8071673398187261741">"रूट दर्शवा"</string>
     <string name="drawer_close" msgid="4263880768630848848">"रूट लपवा"</string>
-    <string name="save_error" msgid="8631128801982095782">"दस्तऐवज जतन करणे अयशस्वी झाले"</string>
+    <string name="save_error" msgid="8631128801982095782">"दस्तऐवज सेव्ह करणे अयशस्वी झाले"</string>
     <string name="create_error" msgid="3092144450044861994">"फोल्डर तयार करण्यात अयशस्वी झाले"</string>
     <string name="query_error" msgid="6625421453613879336">"याक्षणी सामग्री लोड करू शकत नाही"</string>
     <string name="root_recent" msgid="1080156975424341623">"अलीकडील"</string>
     <string name="root_available_bytes" msgid="8269870862691408864">"<xliff:g id="SIZE">%1$s</xliff:g> विनामूल्‍य"</string>
-    <string name="root_type_service" msgid="6521366147466512289">"संचय सेवा"</string>
+    <string name="root_type_service" msgid="6521366147466512289">"स्टोरेज सेवा"</string>
     <string name="root_type_shortcut" msgid="6059343175525442279">"शॉर्टकट"</string>
     <string name="root_type_device" msgid="1713604128005476585">"डिव्हाइसेस"</string>
     <string name="root_type_apps" msgid="8646073235029886342">"अधिक अ‍ॅप्‍स"</string>
@@ -90,8 +84,7 @@
     <string name="toast_no_application" msgid="7555319548595113121">"फाईल उघडू शकत नाही"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"संग्रहणांमध्‍ये फायली उघडू शकत नाही"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"काही दस्‍तऐवज हटविण्‍यात अक्षम"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"गुणधर्म लोड करू शकत नाही"</string>
-    <string name="share_via" msgid="8725082736005677161">"द्वारे सामायिक करा"</string>
+    <string name="share_via" msgid="8725082736005677161">"द्वारे शेअर करा"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"फायली कॉपी करणे"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"फायली संकुचित करत आहे"</string>
     <string name="extract_notification_title" msgid="5067393961754430469">"फायली काढत आहे"</string>
@@ -119,11 +112,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> आयटम हटवत आहे.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"पूर्ववत करा"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"कॉपी करण्‍यासाठी तयार करत आहे…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"संकुचित करण्‍यासाठी तयार होत आहे…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"काढण्यासाठी तयार करत आहे..."</string>
-    <string name="move_preparing" msgid="8742573245485449429">"हलविण्‍यास तयार होत आहे…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"हटविण्‍यासाठी तयार करत आहे..."</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"तयार करत आहे…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"तयार करत आहे…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"तयार करत आहे…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"तयार करत आहे…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"तयार करत आहे…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> आयटम कॉपी करु शकलो नाही</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"संग्रहण<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"<xliff:g id="NAME">%1$s</xliff:g> अधिलिखित करायचे?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"पार्श्वभूमीमध्ये सुरू ठेवा"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"डीबग माहिती (फक्त डेव्हलपरची)"</string>
 </resources>
diff --git a/res/values-ms/inspector_strings.xml b/res/values-ms/inspector_strings.xml
new file mode 100644
index 0000000..c6f214b
--- /dev/null
+++ b/res/values-ms/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Maklumat"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Maklumat fail tidak dapat dimuatkan"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Maklumat nyahpepijat (pembangun sahaja)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Metadata mentah: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Butiran media"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Jenis fail ini dibuka menggunakan"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Fail ini dibekalkan oleh"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Tidak dipilih"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Tidak diketahui"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Dimensi"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Koordinat"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Altitud"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Kamera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Bukaan"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Kelajuan pengatup"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Tempoh"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Diambil pada"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Jarak fokus"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Setara ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Artis"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Komposer"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Album"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Lokasi"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Jenis strim"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Saiz mentah (bait)"</string>
+</resources>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 6ca6c7b..6ac306d 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Mampatkan"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Ekstrak ke…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Namakan semula"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Dapatkan maklumat"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Dapatkan maklumat"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Lihat dalam <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Tetingkap baharu"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Potong"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Alih"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Ketepikan"</string>
     <string name="button_retry" msgid="4011461781916631389">"Cuba Lagi"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Kosongkan"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Tunjukkan dalam pembekal"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Tidak diisih"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Nama"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Ringkasan"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Saiz"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Diubah suai"</string>
     <string name="directory_items" msgid="6645621978998614003">"Bilangan item"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Jenis fail ini dibuka menggunakan"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Fail ini milik"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Apl lain boleh membuka jenis fail ini. Kosongkan"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"sebagai lalai."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Kosongkan"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Tunjukkan dalam pembekal"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Tidak dipilih"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Tidak diketahui"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Menaik"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Menurun"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Tunjukkan akar"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Tidak dapat membuka fail"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Tidak dapat membuka fail dalam arkib"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Tidak dapat memadamkan sesetengah dokumen"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Sifat tidak dapat dimuatkan"</string>
     <string name="share_via" msgid="8725082736005677161">"Kongsi melalui"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Menyalin fail"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Memampatkan fail"</string>
@@ -119,11 +112,11 @@
       <item quantity="one">Memadamkan <xliff:g id="COUNT_0">%1$d</xliff:g> item.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Buat asal"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Bersedia untuk menyalin…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Bersedia untuk memampat…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Bersedia untuk mengestrak…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Bersedia untuk mengalih…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Bersedia untuk memadam…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Menyediakan…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Menyediakan…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Menyediakan…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Menyediakan…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Menyediakan…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other">Tidak dapat menyalin <xliff:g id="COUNT_1">%1$d</xliff:g> item</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"archive<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Tulis ganti <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Teruskan di latar belakang"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Maklumat nyahpepijat (pembangun sahaja)"</string>
 </resources>
diff --git a/res/values-my/inspector_strings.xml b/res/values-my/inspector_strings.xml
new file mode 100644
index 0000000..af368f3
--- /dev/null
+++ b/res/values-my/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"အချက်အလက်"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"ဖိုင်အချက်အလက်များကို ဖွင့်၍မရပါ"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"အမှားရှာပြင်ရန် အချက်အလက် (ဆော့ဖ်ဝဲအင်ဂျင်နီယာသာ)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"အကြမ်းထည် မက်တာဒေတာ− <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"မီဒီယာ အသေးစိတ်များ"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"၎င်းဖိုင်အမျိုးအစားကို ဖွင့်နိုင်သည့်အက်ပ်−"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"ဤဖိုင်အား ဝန်ဆောင်ပေးသူ−"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"ရွေးမထားပါ"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"အမျိုးအမည်မသိ"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"အတိုင်းအတာများ"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> − <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"ကိုဩဒိနိတ်များ"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>၊ <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"အမြင့်"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"ကင်မရာ"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"အလင်းဝင်ပေါက်"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"ရှပ်တာအမြန်နှုန်း"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"ကြာချိန်"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"ရိုက်ထားသည့်အချိန်−"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"ဆုံတာ"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO နှုန်း"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"အနုပညာရှင်"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"ရေးစပ်သူ"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"အယ်လ်ဘမ်"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"တည်နေရာ"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"ထုတ်လွှင့်မှုအမျိုးအစားများ"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"အကြမ်းထည် အရွယ်အစား (ဘိုက်)"</string>
+</resources>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index b21eb0d..0540d4f 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"ချုံ့ရန်"</string>
     <string name="menu_extract" msgid="8171946945982532262">"ရွှေးချယ်ထည့်သွင်းရန်…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"အမည်ပြောင်းပါ"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"အချက်အလက် ရယူရန်"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"အချက်အလက် ရယူရန်"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"<xliff:g id="SOURCE">%1$s</xliff:g> တွင် ကြည့်ရန်"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"ဝင်းဒိုးသစ်"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"ဖြတ်ယူပါ"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"ရွှေ့ရန်"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"ပယ်ရန်"</string>
     <string name="button_retry" msgid="4011461781916631389">"ပြန်စမ်းကြည့်ပါ"</string>
+    <string name="button_clear" msgid="5412304437764369441">"ရှင်းထုတ်ရန်"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"ပံ့ပိုးပေးသူတွင် ပြရန်"</string>
     <string name="not_sorted" msgid="7813496644889115530">"စီမထားပါ"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"အမည်"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"အနှစ်ချုပ်"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"အရွယ်အစား"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"မွမ်းမံပြီး"</string>
     <string name="directory_items" msgid="6645621978998614003">"ပစ္စည်းအရေအတွက်"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"၎င်းဖိုင်အမျိုးအစားကို ဖွင့်နိုင်သည့်အက်ပ်−"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"ဤဖိုင်ကို ပိုင်ဆိုင်သူ−"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"ဤဖိုင်အမျိုးအစားကို အခြားအက်ပ်များဖြင့် ဖွင့်နိုင်သည်။ ရှင်းရန်"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"မူရင်း အဖြစ်။"</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"ရှင်းရန်"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"ပံ့ပိုးပေးသူတွင် ပြရန်"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"ရွေးမထားပါ"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"အမျိုးအမည်မသိ"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"ငယ်စဉ်ကြီးလိုက်"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"ကြီးစဉ်ငယ်လိုက်"</string>
     <string name="drawer_open" msgid="8071673398187261741">"ပင်မဖိုင်တွဲများကို ပြပါ"</string>
@@ -85,12 +79,11 @@
     <string name="root_type_shortcut" msgid="6059343175525442279">"အမြန်နည်းများ"</string>
     <string name="root_type_device" msgid="1713604128005476585">"စက်ပစ္စည်းများ"</string>
     <string name="root_type_apps" msgid="8646073235029886342">"နောက်ထပ်အက်ပ်များ"</string>
-    <string name="empty" msgid="5300254272613103004">"ဘာမှ မရှိပါ"</string>
+    <string name="empty" msgid="5300254272613103004">"ဘာမျှ မရှိပါ"</string>
     <string name="no_results" msgid="2371026325236359209">"%1$s တွင် ကိုက်ညီသည့်အရာ မရှိပါ"</string>
     <string name="toast_no_application" msgid="7555319548595113121">"ဖိုင်ကို ဖွင့်၍မရပါ"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"မှတ်တမ်းဟောင်းထဲမှ ဖိုင်များကို ဖွင့်၍မရပါ"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"အချို့စာဖိုင်များကို ဖျက်၍မရပါ"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"သတ်မှတ်ချက်များကို ဖွင့်၍မရပါ"</string>
     <string name="share_via" msgid="8725082736005677161">"အောက်ပါနည်းလမ်းဖြင့် မျှဝေပါ"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"ဖိုင်များကူးယူနေသည်"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"ဖိုင်များကို ချုံ့နေသည်"</string>
@@ -119,11 +112,11 @@
       <item quantity="one">ဖိုင်<xliff:g id="COUNT_0">%1$d</xliff:g> ဖိုင်ကို ဖျက်နေသည်။</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"တစ်ဆင့်နောက်ပြန်ပါ"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"မိတ္တူကူးရန် ပြင်ဆင်နေသည်…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"ချုံ့ရန် ပြင်ဆင်နေသည်…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"ထုတ်ယူရန် ပြင်ဆင်နေသည်…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"ရွှေ့ရန် ပြင်ဆင်နေသည်…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"ဖျက်ရန် ပြင်ဆင်နေသည်…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"အသင့်ပြင်နေပါသည်..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"အသင့်ပြင်နေပါသည်..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"အသင့်ပြင်နေပါသည်..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"အသင့်ပြင်နေပါသည်..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"အသင့်ပြင်နေပါသည်..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other">ဖိုင်<xliff:g id="COUNT_1">%1$d</xliff:g> ဖိုင်ကို မိတ္တူကူး၍ မရပါ</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"မှတ်တမ်းဟောင်း<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"<xliff:g id="NAME">%1$s</xliff:g> ကို အစားထိုးလိုပါသလား။"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"နောက်ခံတွင် ဆက်လုပ်ရန်"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"အမှားရှာပြင်ရန် အချက်အလက်(ဆော့ဖ်ဝဲအင်ဂျင်နီယာသာ)"</string>
 </resources>
diff --git a/res/values-nb/inspector_strings.xml b/res/values-nb/inspector_strings.xml
new file mode 100644
index 0000000..cd315e6
--- /dev/null
+++ b/res/values-nb/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Informasjon"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Kunne ikke laste inn filinformasjonen"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Feilsøkingsinfo (bare for utviklere)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Råmetadata: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Mediadetaljer"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Denne filtypen åpnes med"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Denne filen leveres av"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Ikke valgt"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Ukjent"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Dimensjoner"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> – <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Koordinater"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Høyde over havet"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Kamera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Blender"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Lukkerhastighet"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Varighet"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Tatt"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Brennvidde"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Tilsvarende ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Artist"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Komponist"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Album"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Posisjon"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Strømtyper"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Råstørrelse (byte)"</string>
+</resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 06fda56..b3fcaad 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Komprimer"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Pakk ut til …"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Gi nytt navn"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Hent inn informasjon"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Hent inn informasjon"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Se i <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Nytt vindu"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Klipp ut"</string>
@@ -55,8 +55,10 @@
     <string name="button_compress" msgid="8951561310857223966">"Komprimer"</string>
     <string name="button_extract" msgid="1038674453689912247">"Pakk ut"</string>
     <string name="button_move" msgid="8596460499325291272">"Flytt"</string>
-    <string name="button_dismiss" msgid="7235249361023803349">"Avvis"</string>
+    <string name="button_dismiss" msgid="7235249361023803349">"Lukk"</string>
     <string name="button_retry" msgid="4011461781916631389">"Prøv på nytt"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Fjern"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Vis i leverandøren"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Ikke sortert"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Navn"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Sammendrag"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Størrelse"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Endret"</string>
     <string name="directory_items" msgid="6645621978998614003">"Antall elementer"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Denne filtypen åpnes med"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Denne filen tilhører"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Andre apper kan åpne denne filtypen. Fjern"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"som standard."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Fjern"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Vis i leverandøren"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Ikke valgt"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Ukjent"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Stigende"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Synkende"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Vis røtter"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Kan ikke åpne filen"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Kan ikke åpne filer i arkiver"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Kunne ikke slette enkelte dokumenter"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Kunne ikke laste inn egenskapene"</string>
     <string name="share_via" msgid="8725082736005677161">"Del via"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Kopierer filer"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Komprimerer filer"</string>
@@ -119,11 +112,11 @@
       <item quantity="one">Sletter <xliff:g id="COUNT_0">%1$d</xliff:g> element.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Angre"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Forbereder kopiering …"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Forbereder komprimering …"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Forbereder utpakking …"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Forbereder flytting …"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Forbereder sletting …"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Forbereder …"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Forbereder …"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Forbereder …"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Forbereder …"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Forbereder …"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other">Kunne ikke kopiere <xliff:g id="COUNT_1">%1$d</xliff:g> element</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"arkiv<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Vil du overskrive <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Fortsett i bakgrunnen"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Feilsøkingsinfo (bare for utviklere)"</string>
 </resources>
diff --git a/res/values-ne/inspector_strings.xml b/res/values-ne/inspector_strings.xml
new file mode 100644
index 0000000..41102e4
--- /dev/null
+++ b/res/values-ne/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"जानकारी"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"फाइलसम्बन्धी जानकारी लोड गर्न सकिएन"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"डिबगसम्बन्धी जानकारी (विकासकर्ताका लागि मात्र)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"अप्रशोधित मेटाडेटा: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"मिडियासम्बन्धी विवरणहरू"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"यस प्रकारको फाइल निम्न अनुप्रयोगमार्फत खुल्छ"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"यो फाइलको प्रदायक"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"चयन गरिएको छैन"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"अज्ञात"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"उचाइ तथा चौडाइ"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> एम. पि."</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"तस्बिर खिचेको स्थानका भौगोलिक स्थितिहरू"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"उचाइ"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"क्यामेरा"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"अपार्चर"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"सटरको गति"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"अवधि"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"तस्बिर खिचेको समय"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"फोकल लम्बाइ"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> मि. मि."</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO बराबर"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"कलाकार"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"रचनाकार"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"एल्बम"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"स्थान"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"स्ट्रिमका प्रकारहरू"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"अप्रशोधित आकार (बाइट)"</string>
+</resources>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 0b1c759..90d778d 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"कम्प्रेस गर्नुहोस्"</string>
     <string name="menu_extract" msgid="8171946945982532262">"यसमा एकस्ट्र्याक्ट गर्नुहोस्…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"पुनःनामाकरण गर्नुहोस्"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"जानकारी प्राप्त गर्नुहोस्"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"जानकारी प्राप्त गर्नुहोस्"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"<xliff:g id="SOURCE">%1$s</xliff:g> मा हेर्नुहोस्"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"नयाँ विन्डो"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"काट्नुहोस्"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"सार्नुहोस्"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"खारेज गर्नुहोस्"</string>
     <string name="button_retry" msgid="4011461781916631389">"फेरि प्रयास गर्नुहोस्"</string>
+    <string name="button_clear" msgid="5412304437764369441">"खाली गर्नुहोस्"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"प्रदायकको सेवामा देखाउनुहोस्"</string>
     <string name="not_sorted" msgid="7813496644889115530">"क्रमबद्ध गरिएको छैन"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"नाम"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"सारांश"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"आकार"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"परिमार्जित"</string>
     <string name="directory_items" msgid="6645621978998614003">"वस्तुहरूको संख्या"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"यस प्रकारको फाइल निम्न अनुप्रयोगमार्फत खुल्छ"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"यो फाइल निम्नको स्वामित्वमा छ"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"अन्य अनुप्रयोगहरूले यस प्रकारको फाइल खोल्न सक्छन्। खाली गर्नुहोस्"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"पूर्वनिर्धारित रूपमा।"</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"खाली गर्नुहोस्"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"प्रदायकमा देखाउनुहोस्"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"चयन गरिएको छैन"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"अज्ञात"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"बढ्दो क्रम"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"घट्दो क्रम"</string>
     <string name="drawer_open" msgid="8071673398187261741">"मूल ठाउँहरू देखाउनुहोस्"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"फाइल खोल्न सकिँदैन"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"अभिलेखहरूमा भएका फाइलहरू खोल्न सकिँदैन"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"केही कागजातहरूलाई मेट्न सकिएन"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"विशेषताहरू लोड गर्न सकिएन"</string>
     <string name="share_via" msgid="8725082736005677161">"निम्न मार्फत साझेदारी गर्नुहोस्"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"फाइलहरूका प्रतिलिपि बनाउँदै"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"फाइलहरू कम्प्रेस गर्दै"</string>
@@ -119,11 +112,11 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> वस्तु मेटाउँदै।</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"अनडू गर्नुहोस्"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"प्रतिलिपि बनाउने तयारी गर्दै…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"कम्प्रेस गर्ने तयारी गर्दै…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"एक्स्ट्र्याक्ट गर्ने तयारी गर्दै…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"सार्ने तयारी गर्दै…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"मेट्ने तयारी गर्दै…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"तयार पार्दै..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"तयार पार्दै..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"तयार पार्दै..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"तयार पार्दै..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"तयार पार्दै..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> वस्तुहरूलाई प्रतिलिपि गर्न सकिएन</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"अभिलेख राख्नुहोस्<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"<xliff:g id="NAME">%1$s</xliff:g> को अधिलेखन गर्ने हो?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"पृष्ठभूमिमा जारी राख्नुहोस्"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"डिबगसम्बन्धी जानकारी (विकासकर्ताका लागि मात्र)"</string>
 </resources>
diff --git a/res/values-nl/inspector_strings.xml b/res/values-nl/inspector_strings.xml
new file mode 100644
index 0000000..51e438e
--- /dev/null
+++ b/res/values-nl/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Informatie"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Bestandsgegevens kunnen niet worden geladen"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Foutopsporingsinfo (alleen ontwikkelaars)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Onbewerkte metadata: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Mediagegevens"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Dit type bestand wordt geopend met"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Dit bestand wordt geleverd door"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Niet geselecteerd"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Onbekend"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Afmetingen"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Coördinaten"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Hoogte"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Camera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Diafragma"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Sluitersnelheid"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Duur"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Gemaakt op"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Focuslengte"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO-equivalent"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Artiest"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Componist"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Album"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Locatie"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Streamtypen"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Onbewerkte grootte (bytes)"</string>
+</resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 8d2a35b..eb498d9 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Comprimeren"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Uitpakken naar…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Naam wijzigen"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Informatie bekijken"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Informatie bekijken"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Bekijken in <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Nieuw venster"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Knippen"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Verplaatsen"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Sluiten"</string>
     <string name="button_retry" msgid="4011461781916631389">"Opnieuw proberen"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Wissen"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Weergeven in provider"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Niet gesorteerd"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Naam"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Overzicht"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Grootte"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Aangepast"</string>
     <string name="directory_items" msgid="6645621978998614003">"Aantal items"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Dit type bestand wordt geopend met"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Dit bestand hoort bij"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Er zijn andere apps die dit bestandstype kunnen openen. Wis"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"als de standaard-app."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Wissen"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Weergeven in provider"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Niet geselecteerd"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Onbekend"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Oplopend"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Aflopend"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Roots weergeven"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Kan bestand niet openen"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Kan bestanden in archieven niet openen"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Kan bepaalde documenten niet verwijderen"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Eigenschappen kunnen niet worden geladen"</string>
     <string name="share_via" msgid="8725082736005677161">"Delen via"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Bestanden kopiëren"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Bestanden comprimeren"</string>
@@ -119,11 +112,11 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> item verwijderen.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Ongedaan maken"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Kopiëren voorbereiden…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Comprimeren voorbereiden…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Uitpakken voorbereiden…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Verplaatsen voorbereiden…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Verwijderen voorbereiden…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Voorbereiden..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Voorbereiden..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Voorbereiden..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Voorbereiden..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Voorbereiden..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other">Kan <xliff:g id="COUNT_1">%1$d</xliff:g> items niet kopiëren</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"archief<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"<xliff:g id="NAME">%1$s</xliff:g> overschrijven?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Doorgaan op de achtergrond"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Foutopsporingsinfo (alleen ontwikkelaars)"</string>
 </resources>
diff --git a/res/values-pa/inspector_strings.xml b/res/values-pa/inspector_strings.xml
new file mode 100644
index 0000000..117a840
--- /dev/null
+++ b/res/values-pa/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"ਜਾਣਕਾਰੀ"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"ਫ਼ਾਈਲ ਜਾਣਕਾਰੀ ਲੋਡ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕੀ"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"ਡੀਬੱਗ ਜਾਣਕਾਰੀ (ਸਿਰਫ਼ ਵਿਕਾਸਕਾਰ)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"ਰਾਅ ਮੈਟਾਡਾਟਾ: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"ਮੀਡੀਆ ਦੇ ਵੇਰਵੇ"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"ਇਸ ਕਿਸਮ ਦੀ ਫ਼ਾਈਲ ਇਸ ਨਾਲ ਖੁੱਲ੍ਹਦੀ ਹੈ:"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"ਇਹ ਫ਼ਾਈਲ ਇਹਨਾਂ ਵੱਲੋਂ ਦਿੱਤੀ ਗਈ ਹੈ:"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"ਚੁਣੀ ਨਹੀਂ ਗਈ"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"ਅਗਿਆਤ"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"ਮਾਪ"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> ਮੈਗਾ ਪਿਕਸਲ"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"ਲੰਬਕਾਰ ਅਤੇ ਵਿਥਕਾਰ"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"ਉਚਾਈ"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"ਕੈਮਰਾ"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"ਕੈਮਰੇ ਦੀ ਮੋਰੀ"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"ਸ਼ਟਰ ਦੀ ਗਤੀ"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"ਮਿਆਦ"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"ਇਸ ਮਿਤੀ ਨੂੰ ਖਿੱਚੀ ਗਈ:"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"ਫੋਕਲ ਲੰਬਾਈ"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>ਮਿ.ਮੀ."</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO ਦੇ ਬਰਾਬਰ"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"ਕਲਾਕਾਰ"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"ਗੀਤਕਾਰ"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"ਐਲਬਮ"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"ਟਿਕਾਣਾ"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"ਸਟ੍ਰੀਮ ਦੀਆਂ ਕਿਸਮਾਂ"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Raw ਆਕਾਰ (ਬਾਈਟ)"</string>
+</resources>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 0e4c6ba..452e4a0 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"ਆਕਾਰ ਛੋਟਾ ਕਰੋ"</string>
     <string name="menu_extract" msgid="8171946945982532262">"ਇਸ ਵਿੱਚ ਐਕਸਟ੍ਰੈਕਟ ਕਰੋ…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"ਮੁੜ-ਨਾਮਕਰਨ ਕਰੋ"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"ਜਾਣਕਾਰੀ ਪ੍ਰਾਪਤ ਕਰੋ"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"ਜਾਣਕਾਰੀ ਪ੍ਰਾਪਤ ਕਰੋ"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"<xliff:g id="SOURCE">%1$s</xliff:g> ਵਿੱਚ ਦੇਖੋ"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"ਨਵੀਂ ਵਿੰਡੋ"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"ਕੱਟੋ"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"ਤਬਦੀਲ ਕਰੋ"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"ਖਾਰਜ ਕਰੋ"</string>
     <string name="button_retry" msgid="4011461781916631389">"ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string>
+    <string name="button_clear" msgid="5412304437764369441">"ਕਲੀਅਰ ਕਰੋ"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"ਪ੍ਰਦਾਨਕ ਸੇਵਾ ਵਿੱਚ ਦਿਖਾਓ"</string>
     <string name="not_sorted" msgid="7813496644889115530">"ਛਾਂਟੀ ਨਹੀਂ ਕੀਤੀ ਗਈ"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"ਨਾਮ"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"ਸਾਰਾਂਸ਼"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"ਆਕਾਰ"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"ਸੋਧਣ ਦਾ ਸਮਾਂ"</string>
     <string name="directory_items" msgid="6645621978998614003">"ਆਈਟਮਾਂ ਦੀ ਗਿਣਤੀ"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"ਇਸ ਕਿਸਮ ਦੀ ਫ਼ਾਈਲ ਇਸ ਨਾਲ ਖੁੱਲ੍ਹਦੀ ਹੈ:"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"ਇਹ ਫ਼ਾਈਲ ਇਸ ਨਾਲ ਸਬੰਧਿਤ ਹੈ:"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"ਦੂਜੀਆਂ ਐਪਾਂ ਇਸ ਫ਼ਾਈਲ ਕਿਸਮ ਨੂੰ ਖੋਲ੍ਹ ਸਕਦੀਆਂ ਹਨ। ਕਲੀਅਰ ਕਰੋ"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"ਪੂਰਵ-ਨਿਰਧਾਰਤ ਵਜੋਂ।"</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"ਕਲੀਅਰ ਕਰੋ"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"ਪ੍ਰਦਾਨਕ ਵਿੱਚ ਦਿਖਾਓ"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"ਚੁਣੀ ਨਹੀਂ ਗਈ"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"ਅਗਿਆਤ"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"ਵਧਦਾ ਕ੍ਰਮ"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"ਘਟਦਾ ਕ੍ਰਮ"</string>
     <string name="drawer_open" msgid="8071673398187261741">"ਰੂਟਾਂ ਨੂੰ  ਦਿਖਾਓ"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"ਫ਼ਾਈਲ ਨੂੰ ਖੋਲ੍ਹਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"ਪੁਰਾਲੇਖਾਂ ਵਿੱਚ ਫ਼ਾਈਲਾਂ ਨੂੰ ਖੋਲ੍ਹਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"ਕੁਝ ਦਸਤਾਵੇਜ਼ਾਂ ਨੂੰ ਮਿਟਾਉਣ ਦੇ ਅਯੋਗ"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਲੋਡ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ"</string>
     <string name="share_via" msgid="8725082736005677161">"ਇਸ ਰਾਹੀਂ ਸਾਂਝਾ ਕਰੋ"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"ਫ਼ਾਈਲਾਂ ਕਾਪੀ ਕਰ ਰਿਹਾ ਹੈ"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"ਆਕਾਰ ਛੋਟਾ ਕੀਤਾ ਜਾ ਰਿਹਾ"</string>
@@ -119,11 +112,11 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ਆਈਟਮਾਂ ਨੂੰ ਮਿਟਾਇਆ ਜਾ ਰਿਹਾ ਹੈ।</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"ਅਣਕੀਤਾ ਕਰੋ"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"ਕਾਪੀ ਕਰਨ ਦੀ ਤਿਆਰੀ ਹੋ ਰਹੀ ਹੈ…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"ਆਕਾਰ ਛੋਟਾ ਕਰਨ ਦੀ ਤਿਆਰੀ ਅਧੀਨ…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"ਐਕਸਟ੍ਰੈਕਟ ਕਰਨ ਦੀ ਤਿਆਰੀ…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"ਤਬਦੀਲ ਕਰਨ ਦੀ ਤਿਆਰੀ ਹੋ ਰਹੀ ਹੈ…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"ਮਿਟਾਉਣ ਦੀ ਤਿਆਰੀ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"ਤਿਆਰ ਕੀਤੀਆਂ ਜਾ ਰਹੀਆਂ ਹਨ..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"ਤਿਆਰ ਕੀਤੀਆਂ ਜਾ ਰਹੀਆਂ ਹਨ..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"ਤਿਆਰ ਕੀਤੀਆਂ ਜਾ ਰਹੀਆਂ ਹਨ..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"ਤਿਆਰ ਕੀਤੀਆਂ ਜਾ ਰਹੀਆਂ ਹਨ..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"ਤਿਆਰ ਕੀਤੀਆਂ ਜਾ ਰਹੀਆਂ ਹਨ..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ਆਈਟਮਾਂ ਨੂੰ ਕਾਪੀ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"ਪੁਰਾਲੇਖ<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"<xliff:g id="NAME">%1$s</xliff:g> ਉੱਤੇ ਲਿਖੀਏ?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਜਾਰੀ ਰੱਖੋ"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"ਡੀਬੱਗ ਜਾਣਕਾਰੀ (ਸਿਰਫ਼ ਵਿਕਾਸਕਾਰ)"</string>
 </resources>
diff --git a/res/values-pl/inspector_strings.xml b/res/values-pl/inspector_strings.xml
new file mode 100644
index 0000000..e17ccd9
--- /dev/null
+++ b/res/values-pl/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Informacje"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Nie udało się załadować informacji o pliku"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Informacje o debugowaniu (tylko programiści)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Metadane pliku RAW: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Informacje o pliku multimedialnym"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Ten rodzaj pliku możesz otworzyć w:"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Dostawca pliku:"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Nie wybrano"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Nieznana"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Wymiary"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> – <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Współrzędne"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Wysokość"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Aparat"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Przysłona"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Szybkość migawki"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Czas"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Data wykonania"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Ogniskowa"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Równoważnik ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Wykonawca"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Kompozytor"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Album"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Lokalizacja"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Typy strumienia"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Rzeczywisty rozmiar pliku (bajty)"</string>
+</resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 076c836..f495015 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Skompresuj"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Rozpakuj do…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Zmień nazwę"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Zobacz informacje"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Zobacz informacje"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Zobacz w: <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Nowe okno"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Wytnij"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Przenieś"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Odrzuć"</string>
     <string name="button_retry" msgid="4011461781916631389">"Spróbuj jeszcze raz"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Zrezygnuj"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Pokaż w usłudze"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Brak sortowania"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Nazwa"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Podsumowanie"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Rozmiar"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Zmieniono"</string>
     <string name="directory_items" msgid="6645621978998614003">"Liczba elementów"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Ten rodzaj pliku możesz otworzyć w:"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Źródłem tego pliku jest"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Inne aplikacje też mogą otwierać ten typ pliku. Zrezygnuj z używania aplikacji"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"jako domyślnej."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Zrezygnuj"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Pokaż w usłudze"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Nie wybrano"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Brak informacji"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Rosnąco"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Malejąco"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Pokaż elementy główne"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Nie można otworzyć pliku"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Nie można otworzyć plików w archiwum"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Nie można usunąć niektórych dokumentów"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Nie udało się załadować właściwości"</string>
     <string name="share_via" msgid="8725082736005677161">"Udostępnij przez"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Kopiowanie plików"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Kompresuję pliki"</string>
@@ -129,11 +122,11 @@
       <item quantity="one">Usuwam <xliff:g id="COUNT_0">%1$d</xliff:g> element.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Cofnij"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Przygotowuję do kopiowania…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Przygotowuję do skompresowania…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Przygotowuję do wypakowania…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Przygotowuję przenoszenie…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Przygotowuję do usunięcia…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Przygotowuję..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Przygotowuję..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Przygotowuję..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Przygotowuję..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Przygotowuję..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="few">Nie udało się skopiować <xliff:g id="COUNT_1">%1$d</xliff:g> elementów</item>
@@ -255,5 +248,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"archiwum<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Zastąpić plik <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Kontynuuj w tle"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Informacje o debugowaniu (tylko programiści)"</string>
 </resources>
diff --git a/res/values-pt-rBR/inspector_strings.xml b/res/values-pt-rBR/inspector_strings.xml
new file mode 100644
index 0000000..03d2545
--- /dev/null
+++ b/res/values-pt-rBR/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Informações"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Não foi possível carregar as informações do arquivo"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Info de depuração (apenas desenvolvimento)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Metadados brutos: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Detalhes de mídia"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Este tipo de arquivo é aberto no app"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Este arquivo é fornecido por"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Não selecionado"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Desconhecido"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Dimensões"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Coordenadas"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Altitude"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Câmera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Abertura"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Velocidade do obturador"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Duração"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Tirada em"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Distância focal:"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Equivalente de ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Artista"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Compositor"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Álbum"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Localização"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Tipos de stream"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Tamanho bruto (bytes)"</string>
+</resources>
diff --git a/res/values-pt-rBR/strings.xml b/res/values-pt-rBR/strings.xml
index 74b2234..b6b5738 100644
--- a/res/values-pt-rBR/strings.xml
+++ b/res/values-pt-rBR/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Compactar"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Extrair para…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Renomear"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Ver informações"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Ver informações"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Ver em <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Nova janela"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Recortar"</string>
@@ -57,21 +57,15 @@
     <string name="button_move" msgid="8596460499325291272">"Mover"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Dispensar"</string>
     <string name="button_retry" msgid="4011461781916631389">"Tentar novamente"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Limpar"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Mostrar no provedor"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Sem classificação"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Nome"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Resumo"</string>
     <string name="sort_dimension_file_type" msgid="5779709622922085381">"Tipo"</string>
     <string name="sort_dimension_size" msgid="2190547351159472884">"Tamanho"</string>
-    <string name="sort_dimension_date" msgid="4231005651895254033">"Modificação"</string>
+    <string name="sort_dimension_date" msgid="4231005651895254033">"Modificado"</string>
     <string name="directory_items" msgid="6645621978998614003">"Número de itens"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Este tipo de arquivo é aberto no app"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Este arquivo pertence a"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Outros apps podem abrir esse tipo de arquivo. Limpar"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"como padrão."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Limpar"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Mostrar no provedor"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Não selecionado"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Desconhecido"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Crescente"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Decrescente"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Mostrar raízes"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Não é possível abrir o arquivo"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Não é possível abrir itens arquivados"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Não foi possível excluir alguns documentos"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Não foi possível carregar as propriedades"</string>
     <string name="share_via" msgid="8725082736005677161">"Compartilhar via"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Copiando arquivos"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Compactando arquivos"</string>
@@ -119,11 +112,11 @@
       <item quantity="other">Excluindo <xliff:g id="COUNT_1">%1$d</xliff:g> itens</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Desfazer"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Preparando para copiar..."</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Preparando para compactar…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Preparando para extrair…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Preparando para mover..."</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Preparando-se para excluir..."</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Preparando..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Preparando..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Preparando..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Preparando..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Preparando..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one">Não foi possível copiar <xliff:g id="COUNT_1">%1$d</xliff:g> item</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"arquivo<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Substituir <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Continuar em segundo plano"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Info de depuração (apenas desenvolvimento)"</string>
 </resources>
diff --git a/res/values-pt-rPT/inspector_strings.xml b/res/values-pt-rPT/inspector_strings.xml
new file mode 100644
index 0000000..2b63c49
--- /dev/null
+++ b/res/values-pt-rPT/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Informações"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Não foi possível carregar as informações do ficheiro"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Informação de depuração (apenas programadores)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Metadados não processados: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Detalhes de multimédia"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Este tipo de ficheiro abre com a aplicação"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Este ficheiro é fornecido por"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Não selecionada"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Desconhecida"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Dimensões"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> – <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Coordenadas"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Altitude"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Câmara"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Abertura"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Velocidade do obturador"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Duração"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Tirada em"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Distância focal"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Equivalente de ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Artista"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Compositor"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Álbum"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Localização"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Tipos de transmissão"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Tamanho não processado (bytes)"</string>
+</resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 0cb37a8..f78601b 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -41,14 +41,14 @@
     <string name="menu_compress" msgid="37539111904724188">"Comprimir"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Extrair para…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Mudar o nome"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Obter informações"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Obter informações"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Ver no <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Nova janela"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Cortar"</string>
     <string name="menu_copy_to_clipboard" msgid="5064081159073330776">"Copiar"</string>
     <string name="menu_paste_from_clipboard" msgid="360947260414135827">"Colar"</string>
     <string name="menu_paste_into_folder" msgid="8000644546983240101">"Colar na pasta"</string>
-    <string name="menu_advanced_show" msgid="7558626506462906726">"Mostrar mem. armaz. int."</string>
+    <string name="menu_advanced_show" msgid="7558626506462906726">"Mostrar armaz. interno"</string>
     <string name="menu_advanced_hide" msgid="6488381508009246334">"Ocultar mem. armaz. int."</string>
     <string name="button_select" msgid="240863497069321364">"Selecionar"</string>
     <string name="button_copy" msgid="8219059853840996027">"Copiar"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Mover"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Ignorar"</string>
     <string name="button_retry" msgid="4011461781916631389">"Tentar novamente"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Limpar"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Mostrar no fornecedor"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Não ordenados"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Nome"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Resumo"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Tamanho"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Modificado"</string>
     <string name="directory_items" msgid="6645621978998614003">"Número de itens"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Este tipo de ficheiro abre com a aplicação"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Este ficheiro pertence a"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Não é possível abrir este tipo de ficheiro com outras aplicações. Limpar"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"como predefinição."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Limpar"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Mostrar no fornecedor"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Não selecionada"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Desconhecida"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Ascendente"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Descendente"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Mostrar raízes"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Não é possível abrir o ficheiro"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Não é possível abrir ficheiros nos arquivos"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Não é possível eliminar alguns documentos"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Não foi possível carregar as propriedades"</string>
     <string name="share_via" msgid="8725082736005677161">"Partilhar através de"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"A copiar ficheiros"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"A comprimir ficheiros…"</string>
@@ -99,77 +92,77 @@
     <string name="delete_notification_title" msgid="2512757431856830792">"A eliminar ficheiros"</string>
     <string name="copy_remaining" msgid="5390517377265177727">"Faltam <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="151184708996738192">
-      <item quantity="one">A copiar <xliff:g id="COUNT_0">%1$d</xliff:g> item…</item>
       <item quantity="other">A copiar <xliff:g id="COUNT_1">%1$d</xliff:g> itens…</item>
+      <item quantity="one">A copiar <xliff:g id="COUNT_0">%1$d</xliff:g> item…</item>
     </plurals>
     <plurals name="compress_begin" formatted="false" msgid="3534158317098678895">
-      <item quantity="one">A comprimir <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro…</item>
       <item quantity="other">A comprimir <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros…</item>
+      <item quantity="one">A comprimir <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro…</item>
     </plurals>
     <plurals name="extract_begin" formatted="false" msgid="1006380679562903749">
-      <item quantity="one">A extrair <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro…</item>
       <item quantity="other">A extrair <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros…</item>
+      <item quantity="one">A extrair <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro…</item>
     </plurals>
     <plurals name="move_begin" formatted="false" msgid="1464229874265756956">
-      <item quantity="one">A mover <xliff:g id="COUNT_0">%1$d</xliff:g> item…</item>
       <item quantity="other">A mover <xliff:g id="COUNT_1">%1$d</xliff:g> itens…</item>
+      <item quantity="one">A mover <xliff:g id="COUNT_0">%1$d</xliff:g> item…</item>
     </plurals>
     <plurals name="deleting" formatted="false" msgid="1729138001178158901">
-      <item quantity="one">A eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> item…</item>
       <item quantity="other">A eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> itens…</item>
+      <item quantity="one">A eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> item…</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Anular"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"A preparar para copiar…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"A preparar para comprimir…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"A preparar para extrair…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"A preparar para mover…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"A preparar para eliminar…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"A preparar…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"A preparar…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"A preparar…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"A preparar…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"A preparar…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
-      <item quantity="one">Não foi possível copiar <xliff:g id="COUNT_0">%1$d</xliff:g> item</item>
       <item quantity="other">Não foi possível copiar <xliff:g id="COUNT_1">%1$d</xliff:g> itens</item>
+      <item quantity="one">Não foi possível copiar <xliff:g id="COUNT_0">%1$d</xliff:g> item</item>
     </plurals>
     <plurals name="compress_error_notification_title" formatted="false" msgid="3043630066678213644">
-      <item quantity="one">Não foi possível comprimir <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro</item>
       <item quantity="other">Não foi possível comprimir <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros</item>
+      <item quantity="one">Não foi possível comprimir <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro</item>
     </plurals>
     <plurals name="move_error_notification_title" formatted="false" msgid="2185736082411854754">
-      <item quantity="one">Não foi possível mover <xliff:g id="COUNT_0">%1$d</xliff:g> item</item>
       <item quantity="other">Não foi possível mover <xliff:g id="COUNT_1">%1$d</xliff:g> itens</item>
+      <item quantity="one">Não foi possível mover <xliff:g id="COUNT_0">%1$d</xliff:g> item</item>
     </plurals>
     <plurals name="delete_error_notification_title" formatted="false" msgid="7568122018481625267">
-      <item quantity="one">Não foi possível eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> item</item>
       <item quantity="other">Não foi possível eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> itens</item>
+      <item quantity="one">Não foi possível eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> item</item>
     </plurals>
     <string name="notification_touch_for_details" msgid="2385563502445129570">"Tocar para ver detalhes"</string>
     <string name="close" msgid="905969391788869975">"Fechar"</string>
     <plurals name="copy_failure_alert_content" formatted="false" msgid="5570549471912990536">
-      <item quantity="one">Este ficheiro não foi copiado: <xliff:g id="LIST_0">%1$s</xliff:g></item>
       <item quantity="other">Estes ficheiros não foram copiados: <xliff:g id="LIST_1">%1$s</xliff:g></item>
+      <item quantity="one">Este ficheiro não foi copiado: <xliff:g id="LIST_0">%1$s</xliff:g></item>
     </plurals>
     <plurals name="compress_failure_alert_content" formatted="false" msgid="5760632881868842400">
-      <item quantity="one">Este ficheiro não foi comprimido: <xliff:g id="LIST_0">%1$s</xliff:g></item>
       <item quantity="other">Estes ficheiros não foram comprimidos: <xliff:g id="LIST_1">%1$s</xliff:g></item>
+      <item quantity="one">Este ficheiro não foi comprimido: <xliff:g id="LIST_0">%1$s</xliff:g></item>
     </plurals>
     <plurals name="extract_failure_alert_content" formatted="false" msgid="7572748127571720803">
-      <item quantity="one">Este ficheiro não foi extraído: <xliff:g id="LIST_0">%1$s</xliff:g></item>
       <item quantity="other">Estes ficheiros não foram extraídos: <xliff:g id="LIST_1">%1$s</xliff:g></item>
+      <item quantity="one">Este ficheiro não foi extraído: <xliff:g id="LIST_0">%1$s</xliff:g></item>
     </plurals>
     <plurals name="move_failure_alert_content" formatted="false" msgid="2747390342670799196">
-      <item quantity="one">Este ficheiro não foi movido: <xliff:g id="LIST_0">%1$s</xliff:g></item>
       <item quantity="other">Estes ficheiros não foram movidos: <xliff:g id="LIST_1">%1$s</xliff:g></item>
+      <item quantity="one">Este ficheiro não foi movido: <xliff:g id="LIST_0">%1$s</xliff:g></item>
     </plurals>
     <plurals name="delete_failure_alert_content" formatted="false" msgid="6122372614839711711">
-      <item quantity="one">Este ficheiro não foi eliminado: <xliff:g id="LIST_0">%1$s</xliff:g></item>
       <item quantity="other">Estes ficheiros não foram eliminados: <xliff:g id="LIST_1">%1$s</xliff:g></item>
+      <item quantity="one">Este ficheiro não foi eliminado: <xliff:g id="LIST_0">%1$s</xliff:g></item>
     </plurals>
     <plurals name="copy_converted_warning_content" formatted="false" msgid="7433742181712126588">
-      <item quantity="one">Este ficheiro foi convertido para outro formato: <xliff:g id="LIST_0">%1$s</xliff:g></item>
       <item quantity="other">Estes ficheiros foram convertidos para outro formato: <xliff:g id="LIST_1">%1$s</xliff:g></item>
+      <item quantity="one">Este ficheiro foi convertido para outro formato: <xliff:g id="LIST_0">%1$s</xliff:g></item>
     </plurals>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="4847061634862926902">
-      <item quantity="one">Copiou <xliff:g id="COUNT_0">%1$d</xliff:g> item para a área de transferência.</item>
       <item quantity="other">Copiou <xliff:g id="COUNT_1">%1$d</xliff:g> itens para a área de transferência.</item>
+      <item quantity="one">Copiou <xliff:g id="COUNT_0">%1$d</xliff:g> item para a área de transferência.</item>
     </plurals>
     <string name="file_operation_rejected" msgid="4301554203329008794">"O ficheiro não permite a operação."</string>
     <string name="file_operation_error" msgid="2234357335716533795">"Falha na operação do ficheiro."</string>
@@ -183,26 +176,26 @@
     <string name="allow" msgid="1275746941353040309">"Permitir"</string>
     <string name="deny" msgid="5127201668078153379">"Recusar"</string>
     <plurals name="elements_selected" formatted="false" msgid="4448165978637163692">
-      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selecionado</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selecionado</item>
     </plurals>
     <plurals name="elements_dragged" formatted="false" msgid="5932571296037626279">
-      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> item</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> itens</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> item</item>
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="8338069763240613258">"Pretende eliminar \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
     <string name="delete_foldername_confirmation_message" msgid="9084085260877704140">"Pretende eliminar a pasta \"<xliff:g id="NAME">%1$s</xliff:g>\" e os respetivos conteúdos?"</string>
     <plurals name="delete_files_confirmation_message" formatted="false" msgid="4866664063250034142">
-      <item quantity="one">Pretende eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro?</item>
       <item quantity="other">Pretende eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros?</item>
+      <item quantity="one">Pretende eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro?</item>
     </plurals>
     <plurals name="delete_folders_confirmation_message" formatted="false" msgid="1028946402799686388">
-      <item quantity="one">Pretende eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> pasta e os respetivos conteúdos?</item>
       <item quantity="other">Pretende eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> pastas e os respetivos conteúdos?</item>
+      <item quantity="one">Pretende eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> pasta e os respetivos conteúdos?</item>
     </plurals>
     <plurals name="delete_items_confirmation_message" formatted="false" msgid="7285090426511028179">
-      <item quantity="one">Pretende eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> item?</item>
       <item quantity="other">Pretende eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> itens?</item>
+      <item quantity="one">Pretende eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> item?</item>
     </plurals>
     <string name="images_shortcut_label" msgid="2545168016070493574">"Imagens"</string>
     <string name="archive_loading_failed" msgid="7243436722828766996">"Não é possível abrir o arquivo para navegação. O ficheiro está danificado ou está num formato que não é suportado."</string>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"arquivo<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Pretende substituir <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Continuar em segundo plano"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Informação de depuração (apenas programadores)"</string>
 </resources>
diff --git a/res/values-pt/inspector_strings.xml b/res/values-pt/inspector_strings.xml
new file mode 100644
index 0000000..03d2545
--- /dev/null
+++ b/res/values-pt/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Informações"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Não foi possível carregar as informações do arquivo"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Info de depuração (apenas desenvolvimento)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Metadados brutos: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Detalhes de mídia"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Este tipo de arquivo é aberto no app"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Este arquivo é fornecido por"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Não selecionado"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Desconhecido"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Dimensões"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Coordenadas"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Altitude"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Câmera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Abertura"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Velocidade do obturador"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Duração"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Tirada em"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Distância focal:"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Equivalente de ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Artista"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Compositor"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Álbum"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Localização"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Tipos de stream"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Tamanho bruto (bytes)"</string>
+</resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 74b2234..b6b5738 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Compactar"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Extrair para…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Renomear"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Ver informações"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Ver informações"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Ver em <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Nova janela"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Recortar"</string>
@@ -57,21 +57,15 @@
     <string name="button_move" msgid="8596460499325291272">"Mover"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Dispensar"</string>
     <string name="button_retry" msgid="4011461781916631389">"Tentar novamente"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Limpar"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Mostrar no provedor"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Sem classificação"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Nome"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Resumo"</string>
     <string name="sort_dimension_file_type" msgid="5779709622922085381">"Tipo"</string>
     <string name="sort_dimension_size" msgid="2190547351159472884">"Tamanho"</string>
-    <string name="sort_dimension_date" msgid="4231005651895254033">"Modificação"</string>
+    <string name="sort_dimension_date" msgid="4231005651895254033">"Modificado"</string>
     <string name="directory_items" msgid="6645621978998614003">"Número de itens"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Este tipo de arquivo é aberto no app"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Este arquivo pertence a"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Outros apps podem abrir esse tipo de arquivo. Limpar"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"como padrão."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Limpar"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Mostrar no provedor"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Não selecionado"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Desconhecido"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Crescente"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Decrescente"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Mostrar raízes"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Não é possível abrir o arquivo"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Não é possível abrir itens arquivados"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Não foi possível excluir alguns documentos"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Não foi possível carregar as propriedades"</string>
     <string name="share_via" msgid="8725082736005677161">"Compartilhar via"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Copiando arquivos"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Compactando arquivos"</string>
@@ -119,11 +112,11 @@
       <item quantity="other">Excluindo <xliff:g id="COUNT_1">%1$d</xliff:g> itens</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Desfazer"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Preparando para copiar..."</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Preparando para compactar…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Preparando para extrair…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Preparando para mover..."</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Preparando-se para excluir..."</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Preparando..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Preparando..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Preparando..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Preparando..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Preparando..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one">Não foi possível copiar <xliff:g id="COUNT_1">%1$d</xliff:g> item</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"arquivo<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Substituir <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Continuar em segundo plano"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Info de depuração (apenas desenvolvimento)"</string>
 </resources>
diff --git a/res/values-ro/inspector_strings.xml b/res/values-ro/inspector_strings.xml
new file mode 100644
index 0000000..f37e07c
--- /dev/null
+++ b/res/values-ro/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Informații"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Informațiile despre fișier nu au putut fi încărcate"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Informații remediere (numai pentru dezvoltatori)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Metadate brute: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Detalii despre conținutul media"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Acest tip de fișier se deschide cu"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Acest fișier este furnizat de"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Nu ați selectat"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Necunoscut"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Dimensiuni"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Coordonate"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Altitudine"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Camera foto"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Diafragmă"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Viteza de declanșare"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Durată"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Realizată pe"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Distanța focală"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Echivalent ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Artist"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Compozitor"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Album"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Locație"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Tipuri de flux"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Dimensiune brută (octeți)"</string>
+</resources>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 5ca0833..769709c 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Comprimați"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Extrageți în…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Redenumiți"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Obțineți informații"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Obțineți informații"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Afișați în <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Fereastră nouă"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Decupați"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Mutați"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Închideți"</string>
     <string name="button_retry" msgid="4011461781916631389">"Încercați din nou"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Ștergeți"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Afișați în furnizor"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Nesortate"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Nume"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Rezumat"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Dimensiune"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Ultima modificare"</string>
     <string name="directory_items" msgid="6645621978998614003">"Numărul de articole"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Acest tip de fișier se deschide cu"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Acest fișier aparține"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Alte aplicații pot deschide acest tip de fișier. Dezactivați"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"ca aplicație prestabilită."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Dezactivați"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Afișați în furnizor"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Nu ați selectat"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Necunoscut"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"În ordine crescătoare"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"În ordine descrescătoare"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Afișați directoarele rădăcină"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Fișierul nu poate fi deschis"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Nu se pot deschide fișierele în arhive"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Anumite documente nu au putut fi șterse"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Proprietățile nu au putut fi încărcate"</string>
     <string name="share_via" msgid="8725082736005677161">"Trimiteți prin"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Se copiază fișierele"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Se comprimă fișierele"</string>
@@ -124,11 +117,11 @@
       <item quantity="one">Se șterge <xliff:g id="COUNT_0">%1$d</xliff:g> articol.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Anulați"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Se pregătește copierea…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Se pregătește comprimarea…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Se pregătește extragerea…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Se pregătește mutarea…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Se pregătește ștergerea…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Se pregătește..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Se pregătește..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Se pregătește..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Se pregătește..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Se pregătește..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="few">Nu s-au putut copia <xliff:g id="COUNT_1">%1$d</xliff:g> articole</item>
@@ -234,5 +227,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"arhivă<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Suprascrieți <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Continuați în fundal"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Informații remediere (numai pentru dezvoltatori)"</string>
 </resources>
diff --git a/res/values-ru/inspector_strings.xml b/res/values-ru/inspector_strings.xml
new file mode 100644
index 0000000..614b3fa
--- /dev/null
+++ b/res/values-ru/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Информация"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Не удалось загрузить сведения о файле"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Сведения об отладке (только для разработчиков)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Исходные метаданные: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Медиаданные"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"В каком приложении открываются файлы этого типа"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Где находится файл"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Не выбрано"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Неизвестное приложение"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Размер"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> (<xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> Мпикс.)"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Координаты"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Высота"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Камера"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Диафрагма"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Выдержка"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Продолжительность"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Дата съемки"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Фокусное расстояние"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> мм"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Эквивалент ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Исполнитель"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Композитор"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Альбом"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Место съемки"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Типы потоков"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Исходный размер (в байтах)"</string>
+</resources>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index d7a9072..4d11378 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Сжать"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Извлечь"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Переименовать"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Информация о файле"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Сведения о файле"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Открыть в приложении \"<xliff:g id="SOURCE">%1$s</xliff:g>\""</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Новое окно"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Вырезать"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Переместить"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Скрыть"</string>
     <string name="button_retry" msgid="4011461781916631389">"Повторить"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Сбросить"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Открыть в приложении по умолчанию"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Документы не отсортированы"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Имя"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Сведения"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Размер"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Изменено"</string>
     <string name="directory_items" msgid="6645621978998614003">"Количество объектов"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"В каком приложении открываются файлы этого типа"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Где находится файл"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Другие приложения могут открывать файлы такого типа. Если нажать эту кнопку,"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"больше не будет приложением по умолчанию."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Сбросить"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Открыть в приложении по умолчанию"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Не выбрано"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Неизвестное приложение"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"По возрастанию"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"По убыванию"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Показать корневые папки"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Не удалось открыть файл"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Нельзя открывать файлы в архивах"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Не удалось удалить некоторые документы"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Не удалось загрузить свойства"</string>
     <string name="share_via" msgid="8725082736005677161">"Поделиться"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Копирование файлов"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Сжатие файлов"</string>
@@ -129,11 +122,11 @@
       <item quantity="other">Удаление <xliff:g id="COUNT_1">%1$d</xliff:g> файла…</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Отменить"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Подготовка к копированию…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Подготовка к сжатию…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Подготовка к извлечению…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Подготовка к перемещению…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Подготовка к удалению…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Подготовка…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Подготовка…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Подготовка…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Подготовка…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Подготовка…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> из <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one">Не удалось скопировать <xliff:g id="COUNT_1">%1$d</xliff:g> файл</item>
@@ -255,5 +248,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"Архив<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Заменить файл <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Продолжить в фоновом режиме"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Сведения об отладке (только для разработчиков)"</string>
 </resources>
diff --git a/res/values-si/inspector_strings.xml b/res/values-si/inspector_strings.xml
new file mode 100644
index 0000000..cbfab14
--- /dev/null
+++ b/res/values-si/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"තොරතුරු"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"ගොනු තොරතුරු පූරණය කළ නොහැකි විය"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"දෝෂ නිරාකරණ තොරතුරු (සංවර්ධක පමණි)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"අමු පාරදත්ත: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"මාධ්‍ය විස්තර"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"මෙම ආකාරයේ ගොනුව මේ සමගින් විවෘත වේ"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"මෙම ගොනුව සපයනු ලබන්නේ"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"තෝරා නොමැත"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"නොදනී"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"මාන"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"ඛණ්ඩාංක"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"උන්නතාංශය"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"කැමරාව"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"විවරය"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"සංවාරක වේගය"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"කාල සීමාව"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"ගන්නා ලද්දේ"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"නාභි දුර"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO තුල්‍ය"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"කලාකරු"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"සංගීතඥ"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"ඇල්බමය"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"ස්ථානය"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"ප්‍රවාහ වර්ග"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"අමු තරම (බයිට්)"</string>
+</resources>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 5d1cd17..1b61510 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"සම්පීඩනය කරන්න"</string>
     <string name="menu_extract" msgid="8171946945982532262">"උපුටා ගන්න…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"යළි නම් කරන්න"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"තොරතුරු ලබා ගන්න"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"තොරතුරු ලබා ගන්න"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"<xliff:g id="SOURCE">%1$s</xliff:g> තුළ බලන්න"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"නව කවුළුව"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"කපන්න"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"ගෙන යන්න"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"අස් කරන්න"</string>
     <string name="button_retry" msgid="4011461781916631389">"නැවත උත්සාහ කරන්න"</string>
+    <string name="button_clear" msgid="5412304437764369441">"හිස් කරන්න"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"සැපයුම්කරු තුළ පෙන්වන්න"</string>
     <string name="not_sorted" msgid="7813496644889115530">"අනුපිළිවෙළට සකසා නැත"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"නම‍"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"සාරාංශය"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"තරම"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"වෙනස් කළේ"</string>
     <string name="directory_items" msgid="6645621978998614003">"අයිතම ගණන:"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"මෙම ආකාරයේ ගොනුව මේ සමගින් විවෘත වේ"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"මෙම ගොනුව අයත් වන්නේ"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"වෙනත් යෙදුම් මෙම ගොනු වර්ගය විවෘත කළ හැකිය. හිස් කරන්න"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"පෙරනිමිය ලෙස."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"හිස් කරන්න"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"සැපයුම්කරු තුළ පෙන්වන්න"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"තෝරා නොමැත"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"නොදනී"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"ආරෝහණ"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"අවරෝහණ"</string>
     <string name="drawer_open" msgid="8071673398187261741">"මුල් පෙන්වන්න"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"ගොනුව විවෘත කළ නොහැකිය"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"සංරක්ෂිත තුළ ඇති ගොනු විවෘත කළ නොහැකිය"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"සමහර ලේඛන මැකීමට නොහැකිය"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"ගුණාංග පූරණය කිරීමට නොහැකි විය"</string>
     <string name="share_via" msgid="8725082736005677161">"බෙදාගන්නේ"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"ගොනු පිටපත් කරමින්"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"ගොනු සම්පීඩනය කරමින්"</string>
@@ -119,11 +112,11 @@
       <item quantity="other">අයිතම <xliff:g id="COUNT_1">%1$d</xliff:g>ක් මකමින්.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"අස් කරන්න"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"පිටපතක් සඳහා සූදානම් කරමින්..."</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"සම්පීඩනය කිරීම සඳහා සූදානම් කරමින්…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"උද්ධෘත කිරීමට ලෑස්ති වෙමින්…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"ගෙන යාම සඳහා පිළියෙළ කරමින් ..."</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"මැකීම සඳහා සූදානම් කරමින්..."</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"සූදානම් කරමින්…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"සූදානම් කරමින්…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"සූදානම් කරමින්…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"සූදානම් කරමින්…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"සූදානම් කරමින්…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one">අයිතම <xliff:g id="COUNT_1">%1$d</xliff:g>ක් පිටපත් කළ නොහැකි විය</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"සංරක්ෂිත<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"<xliff:g id="NAME">%1$s</xliff:g> උඩින් ලියන්නද?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"පසුබිමෙහි කරන්න"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"දෝෂ නිරාකරණ තොරතුරු (සංවර්ධක පමණි)"</string>
 </resources>
diff --git a/res/values-sk/inspector_strings.xml b/res/values-sk/inspector_strings.xml
new file mode 100644
index 0000000..d187051
--- /dev/null
+++ b/res/values-sk/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Informácie"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Informácie o súbore sa nepodarilo načítať"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Informácie o ladení (iba pre vývojárov)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Nespracované metadáta: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Podrobnosti o médiách"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Tento typ súboru sa otvára v aplikácii"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Poskytovateľ tohto súboru:"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Nie je vybraná"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Neznáme"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Rozmery"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> – <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MPx"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Súradnice"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Nadmorská výška"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Fotoaparát"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Clona"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Rýchlosť uzávierky"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Trvanie"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Nasnímané"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Ohnisková vzdialenosť"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Ekvivalent ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Interpret"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Skladateľ"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Album"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Poloha"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Typy streamu"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Nespracovaná veľkosť (v bajtoch)"</string>
+</resources>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 79047fb..1e2522c 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Komprimovať"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Rozbaliť do…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Premenovať"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Ďalšie informácie"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Zobraziť informácie"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Zobraziť v službe <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Nové okno"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Vystrihnúť"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Presunúť"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Odmietnuť"</string>
     <string name="button_retry" msgid="4011461781916631389">"Skúsiť znova"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Vymazať"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Zobraziť u poskytovateľa"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Nezoradené"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Názov"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Súhrn"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Veľkosť"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Upravené"</string>
     <string name="directory_items" msgid="6645621978998614003">"Počet položiek"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Tento typ súboru sa otvára v aplikácii"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Vlastník súboru:"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Tento typ súboru môžu otvoriť ďalšie aplikácie. Vymazať predvolenú aplikáciu"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Vymazať"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Zobraziť v aplikácii"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Nie je vybratá"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Neznáma"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Vzostupne"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Zostupne"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Zobraziť korene"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Súbor nie je možné otvoriť"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Súbory sa nedajú otvoriť v archívoch"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Niektoré dokumenty sa nepodarilo odstrániť"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Vlastníctva sa nepodarilo načítať"</string>
     <string name="share_via" msgid="8725082736005677161">"Zdieľať prostredníctvom"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Kopírovanie súborov"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Komprimujú sa súbory"</string>
@@ -129,11 +122,11 @@
       <item quantity="one">Odstraňujte sa <xliff:g id="COUNT_0">%1$d</xliff:g> položka.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Späť"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Pripravuje sa na kopírovanie..."</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Prebieha príprava komprimovania…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Pripravuje sa extrahovanie…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Prebieha príprava na presunutie…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Príprava na odstránenie…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Pripravuje sa…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Pripravuje sa…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Pripravuje sa…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Pripravuje sa…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Pripravuje sa…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="few">Nepodarilo sa skopírovať <xliff:g id="COUNT_1">%1$d</xliff:g> položky</item>
@@ -255,5 +248,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"archív<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Prepísať názov <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Pokračovať na pozadí"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Informácie o ladení (iba pre vývojárov)"</string>
 </resources>
diff --git a/res/values-sl/inspector_strings.xml b/res/values-sl/inspector_strings.xml
new file mode 100644
index 0000000..94ff443
--- /dev/null
+++ b/res/values-sl/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Podatki"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Podatkov o datoteki ni bilo mogoče naložiti"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Podatki za odpravljanje napak (samo za razvijalce)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Neobdelani metapodatki: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Podrobnosti o predstavnosti"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Za odpiranje te vrste datoteke se uporablja"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"To datoteko je posredoval"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Ni izbrano"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Neznano"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Mere"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> – <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Koordinate"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Višina"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Fotoaparat"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Zaslonka"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Hitrost zaslonke"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Trajanje"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Posneto"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Goriščna razdalja"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Ekvivalent ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Izvajalec"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Skladatelj"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Album"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Lokacija"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Vrste toka"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Neobdelana velikost (bajti)"</string>
+</resources>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index d0d9934..a5841d2 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Stisni"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Razširi v …"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Preimenuj"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Prikaži informacije"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Prikaži informacije"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Prikaži v aplikaciji <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Novo okno"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Izreži"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Premakni"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Opusti"</string>
     <string name="button_retry" msgid="4011461781916631389">"Poskusi znova"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Izbriši"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Prikaži na izvorni lokaciji"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Ni razvrščeno"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Ime"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Povzetek"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Velikost"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Spremenjeno"</string>
     <string name="directory_items" msgid="6645621978998614003">"Število elementov"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Za odpiranje te vrste datoteke se uporablja"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Izvorna lokacija datoteke"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Druge aplikacije lahko odprejo to vrsto datoteke. Izbriši"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"kot privzeto aplikacijo."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Izbriši"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Prikaži na izvorni lokaciji"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Ni izbrano"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Neznana"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Naraščajoče"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Padajoče"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Pokaži korene"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Datoteke ni mogoče odpreti"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Datotek ni mogoče odpreti v arhivih"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Nekaterih dokumentov ni mogoče izbrisati"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Lastnosti ni bilo mogoče naložiti"</string>
     <string name="share_via" msgid="8725082736005677161">"Deli z drugimi prek"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Kopiranje datotek"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Stiskanje datotek"</string>
@@ -129,11 +122,11 @@
       <item quantity="other">Brisanje <xliff:g id="COUNT_1">%1$d</xliff:g> elementov.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Razveljavi"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Pripravljanje na kopiranje …"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Pripravljanje na stiskanje …"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Priprava na ekstrahiranje …"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Priprava na premikanje …"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Pripravljanje na izbris …"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Pripravljanje …"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Pripravljanje …"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Pripravljanje …"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Pripravljanje …"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Pripravljanje …"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> elementa ni bilo mogoče kopirati</item>
@@ -255,5 +248,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"arhiv<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Želite prepisati <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Nadaljuj v ozadju"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Podatki za odpravljanje napak (samo za razvijalce)"</string>
 </resources>
diff --git a/res/values-sq/inspector_strings.xml b/res/values-sq/inspector_strings.xml
new file mode 100644
index 0000000..2ab36dc
--- /dev/null
+++ b/res/values-sq/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Informacione"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Informacioni i skedarit nuk mund të ngarkohej"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Informacioni i korrigjimit (vetëm zhvilluesit)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Të dhënat meta të papërpunuara: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Detajet e medias"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Ky lloj skedari hapet me"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Ky skedar ofrohet nga"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"I pazgjedhur"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"I panjohur"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Përmasat"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Koordinatat"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Lartësia"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Kamera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Hapja e diafragmës"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Shpejtësia e obturatorit"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Kohëzgjatja"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Shkrepur në"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Gjatësia fokale"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO ekuivalente"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Artisti"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Kompozitori"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Albumi"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Vendndodhja"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Llojet e transmetimit"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Madhësia e papërpunuar (bajte)"</string>
+</resources>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 623bc8d..b91404c 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Ngjish"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Nxirre te…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Riemërto"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Merr informacion"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Merr informacione"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Shikoje në <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Dritare e re"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Prit"</string>
@@ -57,21 +57,15 @@
     <string name="button_move" msgid="8596460499325291272">"Lëviz"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Hiqe"</string>
     <string name="button_retry" msgid="4011461781916631389">"Provo përsëri"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Pastro"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Shfaq te ofruesi"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Nuk janë të renditura"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Emri"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Përmbledhja"</string>
     <string name="sort_dimension_file_type" msgid="5779709622922085381">"Lloji"</string>
     <string name="sort_dimension_size" msgid="2190547351159472884">"Madhësia"</string>
-    <string name="sort_dimension_date" msgid="4231005651895254033">"U modifikua"</string>
+    <string name="sort_dimension_date" msgid="4231005651895254033">"Modifikuar"</string>
     <string name="directory_items" msgid="6645621978998614003">"Numri i artikujve"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Ky lloj skedari hapet me"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Ky skedar i përket"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Aplikacionet e tjera mund ta hapin këtë lloj skedari. Pastro"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"si parazgjedhje."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Pastro"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Shfaq te ofruesi"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"I pazgjedhur"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"I panjohur"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Në rritje"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Në zbritje"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Trego rrënjët"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Skedari nuk mund të hapet"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Skedarët në arkiva nuk mund të hapen"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"E pamundur të fshihen disa dokumente"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Karakteristikat nuk mund të ngarkoheshin"</string>
     <string name="share_via" msgid="8725082736005677161">"Shpërnda nëpërmjet"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Po kopjon skedarët"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Skedarët po ngjishen"</string>
@@ -119,11 +112,11 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> artikull po fshihet.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Zhbëj"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Po përgatitet për kopjimin…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Po përgatitet për ngjeshjen…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Për përgatitet për nxjerrje…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Po përgatitet për zhvendosjen…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Po përgatitet për fshirje…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Po përgatitet…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Po përgatitet…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Po përgatitet…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Po përgatitet…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Po përgatitet…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> artikuj nuk mund të kopjoheshin</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"arkiva<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Të mbishkruhet <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Vazhdo në sfond"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Informacioni i korrigjimit (vetëm zhvilluesit)"</string>
 </resources>
diff --git a/res/values-sr/inspector_strings.xml b/res/values-sr/inspector_strings.xml
new file mode 100644
index 0000000..c5d9aff
--- /dev/null
+++ b/res/values-sr/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Информације"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Учитавање података о датотеци није успело"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Подаци о отклањању грешака (само за програмере)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Метаподаци RAW датотеке: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Детаљи о медијима"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Ова врста датотеке се отвара помоћу:"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Ову датотеку пружа"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Није изабрано"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Непознато"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Димензије"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g>×<xliff:g id="HEIGHT">%2$d</xliff:g> – <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> мегапиксела"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Координате"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Надморска висина"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Камера"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Отвор бленде"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Брзина затварача"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Трајање"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Снимљено"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Жижна даљина"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO еквивалент"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Извођач"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Композитор"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Албум"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Локација"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Типови стримова"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Величина RAW датотеке (у бајтовима)"</string>
+</resources>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 5966215..4e256e6 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Компримуј"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Издвој у…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Преименуј"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Прикажи информације"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Прикажи информације"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Прикажи у: <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Нови прозор"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Исеци"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Премести"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Одбаци"</string>
     <string name="button_retry" msgid="4011461781916631389">"Пробај поново"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Обриши"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Прикажи у апликацији добављача"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Нису сортирани"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Назив"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Резиме"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Величина"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Измењено"</string>
     <string name="directory_items" msgid="6645621978998614003">"Број ставки"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Ова врста датотеке се отвара помоћу:"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Ова датотека припада:"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Друге апликације могу да отварају овај тип датотеке. Обришите апликацију"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"као подразумевану."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Обриши"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Прикажи у програму добављача"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Није изабрано"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Непознато"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Растуће"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Опадајуће"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Прикажи основне директоријуме"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Отварање датотеке није успело"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Не можете да отварате датотеке у архивама"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Није могуће избрисати неке документе"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Учитавање својстава није успело"</string>
     <string name="share_via" msgid="8725082736005677161">"Дељење преко"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Копирамо датотеке"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Датотеке се компримују"</string>
@@ -124,11 +117,11 @@
       <item quantity="other">Брише се <xliff:g id="COUNT_1">%1$d</xliff:g> ставки.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Опозови"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Припремамо копирање…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Припремају се за компримовање…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Издвајање се припрема…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Припремамо премештање…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Припремамо брисање…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Припрема се..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Припрема се..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Припрема се..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Припрема се..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Припрема се..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one">Копирање <xliff:g id="COUNT_1">%1$d</xliff:g> ставке није успело</item>
@@ -234,5 +227,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"архива<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Желите да замените <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Настави у позадини"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Подаци о отклањању грешака (само за програмере)"</string>
 </resources>
diff --git a/res/values-sv/inspector_strings.xml b/res/values-sv/inspector_strings.xml
new file mode 100644
index 0000000..bb15919
--- /dev/null
+++ b/res/values-sv/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Information"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Det gick inte att läsa in filinformationen"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Felsökningsinformation (endast utvecklare)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Rå metadata: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Medieuppgifter"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Den här filtypen öppnas med"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Den här filen tillhandahålls av"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Ingen har valts"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Okänd"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Mått"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> – <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Koordinater"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Höjd"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Kamera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Bländare"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Slutarhastighet"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Varaktighet"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Taget den"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Brännvidd"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO-motsvarighet"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Artist"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Kompositör"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Album"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Plats"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Flödestyper"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Råstorlek (byte)"</string>
+</resources>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 853a5f0..e0d73c5 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Komprimera"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Extrahera till …"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Byt namn"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Hämta information"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Hämta information"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Visa i <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Nytt fönster"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Klipp ut"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Flytta"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Ta bort"</string>
     <string name="button_retry" msgid="4011461781916631389">"Försök igen"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Ta bort"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Visa hos leverantören"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Inte sorterade"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Namn"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Översikt"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Storlek"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Ändrades senast"</string>
     <string name="directory_items" msgid="6645621978998614003">"Antal objekt"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Den här filtypen öppnas med"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Den här filen tillhör"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Den här filen kan öppnas av andra appar. Ta bort"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"som standardapp."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Ta bort"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Visa hos leverantören"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Ingen har valts"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Okänt"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Stigande"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Fallande"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Visa rötter"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Det går inte att öppna filen"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Det går inte att öppna filer i arkiv"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Det gick inte att radera vissa dokument"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Det gick inte att läsa in egenskaper"</string>
     <string name="share_via" msgid="8725082736005677161">"Dela via"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Kopierar filer"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Filerna komprimeras"</string>
@@ -119,11 +112,11 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> objekt raderas.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Ångra"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Kopieringen förbereds"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Komprimeringen förbereds"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Extraheringen förbereds …"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Förbereder för att flytta …"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Radering förbereds …"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Förbereder …"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Förbereder …"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Förbereder …"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Förbereder …"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Förbereder …"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> objekt gick inte att kopiera.</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"arkiv<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Vill du skriva över <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Fortsätt i bakgrunden"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Felsökningsinformation (endast utvecklare)"</string>
 </resources>
diff --git a/res/values-sw/inspector_strings.xml b/res/values-sw/inspector_strings.xml
new file mode 100644
index 0000000..d6d8e37
--- /dev/null
+++ b/res/values-sw/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Maelezo"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Imeshindwa kupakia maelezo ya faili"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Maelezo ya utatuzi (usanidi pekee)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Metadata ghafi: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Maelezo ya faili"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Aina hii ya faili inafunguka kwa kutumia"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Faili hii imetoka kwenye"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Haijachaguliwa"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Haijulikani"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Vipimo"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"MP <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Maeneo"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Mwinuko"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Kamera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Kitundu cha kamera"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Kasi ya kilango cha kamera"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Muda"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Ilipigwa"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Urefu wa fokasi"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"mm <xliff:g id="LENGTH">%1$.2f </xliff:g>"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Inayolingana na ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Msanii"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Mtunzi"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Albamu"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Mahali"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Aina za mipasho"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Ukubwa wa faili ghafi (baiti)"</string>
+</resources>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 8366dee..8e823e1 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Bana"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Weka kwenye…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Badilisha jina"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Pata maelezo zaidi"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Pata maelezo zaidi"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Angalia katika <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Dirisha jipya"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Kata"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Hamisha"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Ondoa"</string>
     <string name="button_retry" msgid="4011461781916631389">"Jaribu Tena"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Futa"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Onyesha kwenye programu ya mtoa huduma"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Hazijapangwa"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Jina"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Muhtasari"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Ukubwa"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Ilibadilishwa"</string>
     <string name="directory_items" msgid="6645621978998614003">"Idadi ya vipengee"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Aina hii ya faili inafunguka kwa kutumia"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Faili hii ni ya"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Programu zingine zinaweza kufungua aina hii ya faili. Futa"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"kama chaguo-msingi."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Futa"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Onyesha kwenye mtoa huduma"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Haijachaguliwa"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Haijulikani"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Kupanga kwa kupanda"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Kupanga kwa kushuka"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Onyesha nyenzo"</string>
@@ -90,11 +84,10 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Haiwezi kufungua faili"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Haiwezi kufungua faili zilizo kwenye kumbukumbu"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Imeshindwa kufuta baadhi ya hati"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Imeshindwa kupakia vipengee vya faili"</string>
     <string name="share_via" msgid="8725082736005677161">"Shiriki kupitia"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Inanakili faili"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Inabana faili"</string>
-    <string name="extract_notification_title" msgid="5067393961754430469">"Inatoa faili"</string>
+    <string name="extract_notification_title" msgid="5067393961754430469">"Faili zinatolewa"</string>
     <string name="move_notification_title" msgid="3173424987049347605">"Inahamisha faili"</string>
     <string name="delete_notification_title" msgid="2512757431856830792">"Inafuta faili"</string>
     <string name="copy_remaining" msgid="5390517377265177727">"Zimesalia <xliff:g id="DURATION">%s</xliff:g>"</string>
@@ -107,8 +100,8 @@
       <item quantity="one">Inabana faili <xliff:g id="COUNT_0">%1$d</xliff:g>.</item>
     </plurals>
     <plurals name="extract_begin" formatted="false" msgid="1006380679562903749">
-      <item quantity="other">Inatoa faili <xliff:g id="COUNT_1">%1$d</xliff:g>.</item>
-      <item quantity="one">Inatoa faili <xliff:g id="COUNT_0">%1$d</xliff:g>.</item>
+      <item quantity="other">Faili <xliff:g id="COUNT_1">%1$d</xliff:g> zinatolewa.</item>
+      <item quantity="one">Faili <xliff:g id="COUNT_0">%1$d</xliff:g> inatolewa.</item>
     </plurals>
     <plurals name="move_begin" formatted="false" msgid="1464229874265756956">
       <item quantity="other">Inahamisha vipengee <xliff:g id="COUNT_1">%1$d</xliff:g>.</item>
@@ -119,15 +112,15 @@
       <item quantity="one">Inafuta kipengee <xliff:g id="COUNT_0">%1$d</xliff:g>.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Tendua"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Inaanda kunakili..."</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Inaandaa kubana faili…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Inajitayarisha kutoa…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Inatayarisha kuhamisha..."</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Inajitayarisha kufuta..."</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Inaandaa..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Inaandaa..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Inaandaa..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Inaandaa..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Inaandaa..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
-      <item quantity="other">Imeshindwa kunakili vipengee <xliff:g id="COUNT_1">%1$d</xliff:g></item>
-      <item quantity="one">Imeshindwa kunakili kipengee <xliff:g id="COUNT_0">%1$d</xliff:g></item>
+      <item quantity="other">Imeshindwa kunakili faili <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="one">Imeshindwa kunakili faili <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
     <plurals name="compress_error_notification_title" formatted="false" msgid="3043630066678213644">
       <item quantity="other">Haikuweza kubana faili <xliff:g id="COUNT_1">%1$d</xliff:g></item>
@@ -211,7 +204,6 @@
     <string name="cant_display_content" msgid="8633226333229417237">"Imeshindwa kuonyesha maudhui"</string>
     <string name="sign_in" msgid="6253762676723505592">"Ingia katika akaunti"</string>
     <string name="new_archive_file_name" msgid="1604650338077249838">"weka <xliff:g id="EXTENSION">%s</xliff:g> kwenye kumbukumbu"</string>
-    <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Ungependa kufuta <xliff:g id="NAME">%1$s</xliff:g>?"</string>
+    <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Ungependa kubadili <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Endelea shughuli chini chini"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Maelezo ya utatuzi (usanidi pekee)"</string>
 </resources>
diff --git a/res/values-ta/inspector_strings.xml b/res/values-ta/inspector_strings.xml
new file mode 100644
index 0000000..41bad8a
--- /dev/null
+++ b/res/values-ta/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"தகவல்"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"கோப்புத் தகவலை ஏற்ற முடியவில்லை"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"பிழைத்திருத்தத் தகவல் (டெவெலப்பர்கள் மட்டும்)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"அசல் மீத்தரவு: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"மீடியா விவரங்கள்"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"இந்தக் கோப்பு வகையை, பின்வரும் பயன்பாடு திறக்கும்:"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"இந்தக் கோப்பை வழங்குவது:"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"தேர்ந்தெடுக்கவில்லை"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"தெரியாதது"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"பரிமாணங்கள்"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"ஆயத்தொலைவுகள்"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"உயரம்"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"கேமரா"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"அபெர்ச்சர்"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"ஷட்டர் வேகம்"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"கால அளவு"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"படமெடுத்தது:"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"குவியத்தூரம்"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>மிமீ"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO சமதிறன்"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"கலைஞர்"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"இசையமைப்பாளர்"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"ஆல்பம்"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"இருப்பிடம்"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"ஸ்ட்ரீம் வகைகள்"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"அசல் அளவு (பைட்டுகள்)"</string>
+</resources>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index c0e1dd6..7fcf333 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"அளவைக் குறை"</string>
     <string name="menu_extract" msgid="8171946945982532262">"இங்கு பிரி…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"மறுபெயரிடு"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"தகவலைப் பெறு"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"தகவலைப் பெறு"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"<xliff:g id="SOURCE">%1$s</xliff:g> இல் காட்டு"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"புதிய சாளரம்"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"வெட்டு"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"நகர்த்து"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"நிராகரி"</string>
     <string name="button_retry" msgid="4011461781916631389">"மீண்டும் முயலவும்"</string>
+    <string name="button_clear" msgid="5412304437764369441">"அழி"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"வழங்குநரில் காட்டு"</string>
     <string name="not_sorted" msgid="7813496644889115530">"வரிசைப்படுத்தப்படவில்லை"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"பெயர்"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"சுருக்க விவரம்"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"அளவு"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"மாற்றியது"</string>
     <string name="directory_items" msgid="6645621978998614003">"உருப்படிகளின் எண்ணிக்கை"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"இந்த வகை கோப்பை இதன் மூலம் திறக்கலாம்"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"இந்தக் கோப்பு இதற்குச் சொந்தமானது:"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"இந்தக் கோப்பு வகையைப் பிற பயன்பாடுகள் திறக்கலாம். இயல்புப்"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"பயன்பாட்டை அழிக்கும்."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"அழி"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"வழங்குநரில் காட்டு"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"தேர்ந்தெடுக்கவில்லை"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"தெரியாதது"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"ஏறுவரிசையில்"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"இறங்குவரிசையில்"</string>
     <string name="drawer_open" msgid="8071673398187261741">"சேமித்த இடத்தைக் காட்டு"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"கோப்பைத் திறக்க முடியாது"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"காப்பகங்களில் உள்ள கோப்புகளைத் திறக்க முடியாது"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"சில ஆவணங்களை நீக்க முடியவில்லை"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"பண்புகளை ஏற்ற முடியவில்லை"</string>
     <string name="share_via" msgid="8725082736005677161">"இதன் வழியாகப் பகிர்"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"கோப்புகளை நகலெடுத்தல்"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"அளவைக் குறைக்கிறது"</string>
@@ -119,11 +112,11 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> கோப்பை நீக்குகிறது.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"செயல்தவிர்"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"நகலெடுக்க, தயார்படுத்துகிறது…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"அளவைக் குறைக்க தயாராகிறது…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"பிரிப்பதற்குத் தயாராகிறது…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"நகர்த்த, தயார்படுத்துகிறது…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"நீக்க, தயார்படுத்துகிறது…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"தயாராகிறது..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"தயாராகிறது..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"தயாராகிறது..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"தயாராகிறது..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"தயாராகிறது..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> உருப்படிகளை நகலெடுக்க முடியவில்லை</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"காப்பகம்<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"<xliff:g id="NAME">%1$s</xliff:g>ஐ மேலெழுதவா?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"பின்னணியில் தொடர்க"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"பிழைத்திருத்தத் தகவல் (டெவெலப்பர்கள் மட்டும்)"</string>
 </resources>
diff --git a/res/values-te/inspector_strings.xml b/res/values-te/inspector_strings.xml
new file mode 100644
index 0000000..97dd812
--- /dev/null
+++ b/res/values-te/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"సమాచారం"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"ఫైల్ సమాచారాన్ని లోడ్ చేయడం సాధ్యపడలేదు"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"డీబగ్ సమాచారం (డెవలపర్ మాత్రమే)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"ప్రాసెస్ చేయని మెటాడేటా: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"మీడియా వివరాలు"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"ఈ రకమైన ఫైల్ దీనితో తెరవబడుతుంది"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"ఇది ఈ ఫైల్‌ని అందించింది"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"ఎంచుకోబడలేదు"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"తెలియదు"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"కొలతలు"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"అక్షాంశాలు"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"ఎత్తు"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"కెమెరా"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"ఎపర్చర్"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"షట్టర్ వేగం"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"వ్యవధి"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"ఫోటో ఈ తేదీన తీయబడింది"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"ఫోకల్ పొడవు"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>మి.మీ"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO సమానమైనది"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"కళాకారుడు"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"కంపోజర్"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"ఆల్బమ్"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"స్థానం"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"ప్రసార రకాలు"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"ప్రాసెస్ చేయని పరిమాణం (బైట్‌లు)"</string>
+</resources>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 49295e6..c843707 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"కుదించు"</string>
     <string name="menu_extract" msgid="8171946945982532262">"దీనిలోకి సంగ్రహించు…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"పేరు మార్చు"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"సమాచారాన్ని పొందండి"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"సమాచారాన్ని పొందండి"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"<xliff:g id="SOURCE">%1$s</xliff:g>లో వీక్షించు"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"కొత్త విండో"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"కత్తిరించు"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"తరలించు"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"తీసివేయి"</string>
     <string name="button_retry" msgid="4011461781916631389">"మళ్లీ ప్రయత్నించు"</string>
+    <string name="button_clear" msgid="5412304437764369441">"తీసివేయండి"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"ప్రదాతలో చూపించండి"</string>
     <string name="not_sorted" msgid="7813496644889115530">"క్రమబద్ధీకరించలేదు"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"పేరు"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"సారాంశం"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"పరిమాణం"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"సవరించిన సమయం"</string>
     <string name="directory_items" msgid="6645621978998614003">"అంశాల సంఖ్య"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"ఈ రకమైన ఫైల్ దీనితో తెరవబడుతుంది"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"ఈ ఫైల్ దీనికి చెందినది:"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"ఇతర యాప్‌లు ఈ ఫైల్ రకాన్ని తెరవగలవు. తీసివేయి"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"డిఫాల్ట్‌గా."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"తీసివేయండి"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"ప్రదాతలో చూపించండి"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"ఎంచుకోబడలేదు"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"తెలియదు"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"ఆరోహణ"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"అవరోహణ"</string>
     <string name="drawer_open" msgid="8071673398187261741">"మూలాలను చూపు"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"ఫైల్‌ను తెరవడం సాధ్యపడదు"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"ఆర్కైవ్‌లలో ఉన్న ఫైల్‌లను తెరవడం సాధ్యం కాదు"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"కొన్ని పత్రాలను తొలగించడం సాధ్యపడలేదు"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"లక్షణాలను లోడ్ చేయలేకపోయింది"</string>
     <string name="share_via" msgid="8725082736005677161">"దీనితో భాగస్వామ్యం చేయండి"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"ఫైల్‌లు కాపీ అవుతున్నాయి"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"ఫైల్‌లను కుదిస్తోంది"</string>
@@ -119,11 +112,11 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> అంశాన్ని తొలగిస్తోంది.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"చర్య రద్దు చేయి"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"కాపీ చేయడానికి సిద్ధం చేస్తోంది…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"కుదించడానికి సిద్ధం చేస్తోంది…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"సంగ్రహించడానికి సిద్ధం చేస్తోంది..."</string>
-    <string name="move_preparing" msgid="8742573245485449429">"తరలించడానికి సిద్ధమవుతోంది…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"తొలగించడానికి సిద్ధం చేస్తోంది…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"సిద్ధం చేస్తోంది..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"సిద్ధం చేస్తోంది..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"సిద్ధం చేస్తోంది..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"సిద్ధం చేస్తోంది..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"సిద్ధం చేస్తోంది..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> అంశాలను కాపీ చేయడం సాధ్యపడలేదు</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"ఆర్కైవ్ చేయి<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"<xliff:g id="NAME">%1$s</xliff:g>ని భర్తీ చేయాలా?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"నేపథ్యంలో కొనసాగించు"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"డీబగ్ సమాచారం (డెవలపర్ మాత్రమే)"</string>
 </resources>
diff --git a/res/values-th/inspector_strings.xml b/res/values-th/inspector_strings.xml
new file mode 100644
index 0000000..855b581
--- /dev/null
+++ b/res/values-th/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"ข้อมูล"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"ไม่สามารถโหลดข้อมูลไฟล์"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"ข้อมูลการแก้ไขข้อบกพร่อง (dev only)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"ข้อมูลเมตา Raw: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"รายละเอียดสื่อ"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"ไฟล์ประเภทนี้เปิดด้วย"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"ไฟล์นี้จัดหาโดย"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"ไม่ได้เลือก"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"ไม่ทราบ"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"ขนาด"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"พิกัด"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"ระดับความสูง"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"กล้อง"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"รูรับแสง"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"ความเร็วชัตเตอร์"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"ระยะเวลา"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"ถ่ายเมื่อ"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"ความยาวโฟกัส"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> มม."</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO เทียบเท่า"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"ศิลปิน"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"ผู้ประพันธ์เพลง"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"อัลบั้ม"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"ตำแหน่ง"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"ประเภทสตรีม"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"ขนาด Raw (ไบต์)"</string>
+</resources>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index d4e9524..9ca10a9 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"บีบอัด"</string>
     <string name="menu_extract" msgid="8171946945982532262">"แตกข้อมูลไปยัง…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"เปลี่ยนชื่อ"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"รับข้อมูล"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"รับข้อมูล"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"ดูใน <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"หน้าต่างใหม่"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"ตัด"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"ย้าย"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"ปิด"</string>
     <string name="button_retry" msgid="4011461781916631389">"ลองใหม่"</string>
+    <string name="button_clear" msgid="5412304437764369441">"ล้าง"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"แสดงในแอปผู้ให้บริการ"</string>
     <string name="not_sorted" msgid="7813496644889115530">"ไม่ได้จัดเรียง"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"ชื่อ"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"สรุป"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"ขนาด"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"แก้ไข"</string>
     <string name="directory_items" msgid="6645621978998614003">"จำนวนรายการ"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"ไฟล์ประเภทนี้เปิดด้วย"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"ไฟล์นี้เป็นของ"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"แอปอื่นๆ สามารถเปิดไฟล์ประเภทนี้ได้ ล้าง"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"เป็นค่าเริ่มต้น"</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"ล้าง"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"แสดงในผู้ให้บริการ"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"ไม่ได้เลือก"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"ไม่ทราบ"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"จากน้อยไปมาก"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"จากมากไปน้อย"</string>
     <string name="drawer_open" msgid="8071673398187261741">"แสดงราก"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"เปิดไฟล์ไม่ได้"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"เปิดไฟล์ในที่เก็บถาวรไม่ได้"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"ไม่สามารถลบเอกสารบางรายการ"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"ไม่สามารถโหลดพร็อพเพอร์ตี้"</string>
     <string name="share_via" msgid="8725082736005677161">"แชร์ผ่าน"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"กำลังคัดลอกไฟล์"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"กำลังบีบอัดไฟล์"</string>
@@ -119,11 +112,11 @@
       <item quantity="one">กำลังลบ <xliff:g id="COUNT_0">%1$d</xliff:g> รายการ</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"เลิกทำ"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"กำลังเตรียมการคัดลอก…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"กำลังเตรียมบีบอัด…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"เตรียมแตกไฟล์…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"กำลังเตรียมการย้าย…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"กำลังเตรียมลบ…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"กำลังเตรียม..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"กำลังเตรียม..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"กำลังเตรียม..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"กำลังเตรียม..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"กำลังเตรียม..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other">ไม่สามารถคัดลอก <xliff:g id="COUNT_1">%1$d</xliff:g> รายการ</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"ที่เก็บถาวร<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"เขียนทับ <xliff:g id="NAME">%1$s</xliff:g> ไหม"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"ดำเนินการต่อในพื้นหลัง"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"ข้อมูลการแก้ไขข้อบกพร่อง (dev only)"</string>
 </resources>
diff --git a/res/values-tl/inspector_strings.xml b/res/values-tl/inspector_strings.xml
new file mode 100644
index 0000000..a18fe5a
--- /dev/null
+++ b/res/values-tl/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Impormasyon"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Hindi ma-load ang impormasyon ng file"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Impormasyon ng debug (dev lang)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Raw na metadata: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Mga detalye ng media"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Nabubuksan ang ganitong uri ng file sa"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Ang file na ito ay ibinigay ng"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Hindi napili"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Hindi Alam"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Mga Dimensyon"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Mga Coordinate"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Altitude"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Camera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Aperture"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Bilis ng shutter"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Tagal"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Kinunan noong"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Focal length"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Katumbas sa ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Artist"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Composer"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Album"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Lokasyon"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Mga uri ng stream"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Raw na laki (mga byte)"</string>
+</resources>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index cbf38f5..5d6415a 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"I-compress"</string>
     <string name="menu_extract" msgid="8171946945982532262">"I-extract sa…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Palitan ang pangalan"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Kumuha ng impormasyon"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Kumuha ng impormasyon"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Tingnan sa <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Bagong window"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"I-cut"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Ilipat"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"I-dismiss"</string>
     <string name="button_retry" msgid="4011461781916631389">"Subukang Muli"</string>
+    <string name="button_clear" msgid="5412304437764369441">"I-clear"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Ipakita sa provider"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Hindi napagbukud-bukod"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Pangalan"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Buod"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Laki"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Binago"</string>
     <string name="directory_items" msgid="6645621978998614003">"Bilang ng mga item"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Nabubuksan ang ganitong uri ng file sa"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Nabibilang ang file na ito sa"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Mabubuksan ng iba pang app ang uring ito ng file. I-clear ang"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"bilang ang default."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"I-clear"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Ipakita sa provider"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Hindi napili"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Hindi Alam"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Pataas"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Pababa"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Ipakita ang mga root"</string>
@@ -85,12 +79,11 @@
     <string name="root_type_shortcut" msgid="6059343175525442279">"Mga Shortcut"</string>
     <string name="root_type_device" msgid="1713604128005476585">"Mga Device"</string>
     <string name="root_type_apps" msgid="8646073235029886342">"Higit pang mga app"</string>
-    <string name="empty" msgid="5300254272613103004">"Walang mga item"</string>
+    <string name="empty" msgid="5300254272613103004">"Walang item"</string>
     <string name="no_results" msgid="2371026325236359209">"Walang mga katugma sa %1$s"</string>
     <string name="toast_no_application" msgid="7555319548595113121">"Hindi mabuksan ang file"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Hindi mabuksan ang mga file sa mga archive"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Hindi ma-delete ang ilang dokumento"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Hindi ma-load ang mga property"</string>
     <string name="share_via" msgid="8725082736005677161">"Ibahagi gamit ang"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Kinokopya ang mga file"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Kino-compress ang files"</string>
@@ -119,11 +112,11 @@
       <item quantity="other">Dine-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> na item.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"I-undo"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Naghahanda para sa pagkopya…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Inihahandang i-compress…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Inihahanda para sa pag-extract…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Naghahanda para sa paglilipat…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Naghahanda para sa pag-delete…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Inihahanda..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Inihahanda..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Inihahanda..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Inihahanda..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Inihahanda..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one">Hindi makopya ang <xliff:g id="COUNT_1">%1$d</xliff:g> item</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"archive<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"I-overwrite ang <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Magpatuloy sa background"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Impormasyon ng debug (dev lang)"</string>
 </resources>
diff --git a/res/values-tr/inspector_strings.xml b/res/values-tr/inspector_strings.xml
new file mode 100644
index 0000000..23e01c0
--- /dev/null
+++ b/res/values-tr/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Bilgi"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Dosya bilgisi yüklenemedi"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Hata ayıklama bilgileri (yalnızca geliştirici)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"İşlenmemiş meta veri: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Medya ayrıntıları"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Bu tür dosyalar şu uygulamayla açılır:"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Bu dosyayı sağlayan:"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Seçili değil"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Bilinmiyor"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Boyutlar"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Koordinatlar"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Rakım"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Kamera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Diyafram açıklığı"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Deklanşör hızı"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Süre"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Çekim zamanı:"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Odak uzaklığı"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO karşılığı"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Sanatçı"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Besteci"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Albüm"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Konum"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Akış türleri"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"İşlenmemiş boyut (bayt)"</string>
+</resources>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index eb62627..440d117 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Sıkıştır"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Şuraya çıkar:"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Yeniden Adlandır"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Bilgi al"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Bilgi al"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"<xliff:g id="SOURCE">%1$s</xliff:g> içinde görüntüle"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Yeni pencere"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Kes"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Taşı"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Kapat"</string>
     <string name="button_retry" msgid="4011461781916631389">"Tekrar Dene"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Temizle"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Sağlayıcıda göster"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Sıralanmadı"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Ad"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Özet"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Boyut"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Değiştirilme zamanı"</string>
     <string name="directory_items" msgid="6645621978998614003">"Ürün sayısı"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Bu tür dosyalar şu uygulamayla açılır:"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Bu dosyanın sahibi:"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Diğer uygulamalar bu dosya türünü açabilir. Varsayılan"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"uygulamasını temizle."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Temizle"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Sağlayıcıda göster"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Seçili değil"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Bilinmiyor"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Artan"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Azalan"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Kök dizinleri göster"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Dosya açılamıyor"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Arşivlerdeki dosyalar açılamaz"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Bazı dokümanlar silinemiyor"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Özellikler yüklenemedi"</string>
     <string name="share_via" msgid="8725082736005677161">"Şunu kullanarak paylaşın:"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Dosyalar kopyalanıyor"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Dosyalar sıkıştırılıyor"</string>
@@ -119,11 +112,11 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> öğe siliniyor.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Geri al"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Kopyalamak için hazırlanıyor…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Sıkıştırma için hazırlanıyor…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Çıkarılmaya hazırlanıyor…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Taşıma için hazırlanıyor…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Silmek için hazırlanıyor…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Hazırlanıyor..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Hazırlanıyor..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Hazırlanıyor..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Hazırlanıyor..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Hazırlanıyor..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> öğe kopyalanamadı</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"arşiv<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"<xliff:g id="NAME">%1$s</xliff:g> dosyasının üzerine yazılsın mı?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Arka planda devam et"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Hata ayıklama bilgileri (yalnızca geliştirici)"</string>
 </resources>
diff --git a/res/values-uk/inspector_strings.xml b/res/values-uk/inspector_strings.xml
new file mode 100644
index 0000000..319b598
--- /dev/null
+++ b/res/values-uk/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Інформація"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Не вдалося завантажити інформацію про файл"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Дані про налагодження (лише для розробників)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Метадані файлу RAW: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Деталі медіа-вмісту"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Цей тип файлу відкривається в додатку"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Цей файл надає"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Не вибрано"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Невідомо"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Розміри"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> – <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> Мпікс."</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Координати"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Висота"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Камера"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Апертура"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Швидкість затвора"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Тривалість"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Знято"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Фокусна відстань"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> мм"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Еквівалент ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"Швидкість ISO: <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Виконавець"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Композитор"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Альбом"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Місцезнаходження"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Типи потоків"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Розмір файлу RAW (байти)"</string>
+</resources>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 6660a98..efdfa37 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Стиснути"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Розпакувати…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Перейменувати"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Переглянути інформацію"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Переглянути інформацію"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Переглянути в службі <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Нове вікно"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Вирізати"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Перемістити"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Відхилити"</string>
     <string name="button_retry" msgid="4011461781916631389">"Повторити"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Очистити"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Показати в сервісі постачальника"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Не сортовано"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Назва"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Короткий опис"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Розмір"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Змінено"</string>
     <string name="directory_items" msgid="6645621978998614003">"Кількість елементів"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Цей тип файлу відкривається за допомогою додатка"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Власник цього файлу"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Цей тип файлу можуть відкривати інші додатки. Видалити"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"як додаток за умовчанням."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Видалити"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Показати через постачальника"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Не вибрано"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Невідомо"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"За зростанням"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"За спаданням"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Показати кореневі каталоги"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Не вдалося відкрити файл"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Не вдалося відкрити файли в архівах"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Не вдалося видалити деякі документи"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Не вдалося завантажити параметри"</string>
     <string name="share_via" msgid="8725082736005677161">"Надіслати через"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Копіювання файлів"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Файли стискаються"</string>
@@ -129,11 +122,11 @@
       <item quantity="other">Видаляються <xliff:g id="COUNT_1">%1$d</xliff:g> файлу.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Скасувати"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Підготовка до копіювання…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Підготовка до стискання…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Підготовка до отримання…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Підготовка до переміщення…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Підготовка до видалення…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Підготовка…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Підготовка…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Підготовка…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Підготовка…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Підготовка…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> з <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one">Не вдалося скопіювати <xliff:g id="COUNT_1">%1$d</xliff:g> файл</item>
@@ -255,5 +248,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"archive<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Замінити назву \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Продовжити у фоновому режимі"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Дані про налагодження (лише для розробників)"</string>
 </resources>
diff --git a/res/values-ur/inspector_strings.xml b/res/values-ur/inspector_strings.xml
new file mode 100644
index 0000000..bfe1b66
--- /dev/null
+++ b/res/values-ur/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"معلومات"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"فائل کى معلومات لوڈ نہیں کی جا سکی"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"ڈیبگ کی معلومات (ڈیولپر فقط)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"خام میٹا ڈیٹا: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"میڈیا کی تفصیلات"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"اس قسم کی فائل اس کے ساتھ کُھلتی ہے"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"یہ فائل فراہم کی جاتی ہے"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"غیر منتخب کردہ"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"نامعلوم"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"ابعاد"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"کوآرڈینیٹس"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>، <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"اونچائی"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"کیمرا"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"اپرچر"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"شٹر کی رفتار"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"مدت"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"تصویر لے لی گئی"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"ماسکہ کی طوالت"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>ملی میٹر"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"‏ISO کے مساوی"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"فنکار"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"کمپوزر"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"البم"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"مقام"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"سلسلہ کی قسمیں"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"خام سائز (بائٹس)"</string>
+</resources>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index a5d2794..0ca60b6 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"کمپریس کریں"</string>
     <string name="menu_extract" msgid="8171946945982532262">"اس میں کھولیں۔۔۔"</string>
     <string name="menu_rename" msgid="1883113442688817554">"نام تبدیل کریں"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"معلومات حاصل کریں"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"معلومات حاصل کریں"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"<xliff:g id="SOURCE">%1$s</xliff:g> میں دیکھیں"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"نئی ونڈو"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"کٹ کریں"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"منتقل کریں"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"کالعدم کریں"</string>
     <string name="button_retry" msgid="4011461781916631389">"دوبارہ کوشش کریں"</string>
+    <string name="button_clear" msgid="5412304437764369441">"صاف کریں"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"فراہم کنندہ میں دکھائیں"</string>
     <string name="not_sorted" msgid="7813496644889115530">"ترتیب میں نہیں ہیں"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"نام"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"خلاصہ"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"سائز"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"ترمیم ہوئی"</string>
     <string name="directory_items" msgid="6645621978998614003">"آئٹمز کی تعداد"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"اس قسم کی فائل اس کے ساتھ کھلتی ہے:"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"یہ فائل اس سے تعلق رکھتی ہے:"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"دیگر ایپس اس قسم کی فائل کو کھول سکتی ہیں۔ صاف کریں"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"ڈیفالٹ کے طور پر۔"</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"صاف کریں"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"فراہم کنندہ میں دکھائیں"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"غیر منتخب کردہ"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"نامعلوم"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"صعودی"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"نزولی"</string>
     <string name="drawer_open" msgid="8071673398187261741">"روٹس دکھائیں"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"فائل نہیں کھل سکتی"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"فائلوں کو آرکائیوز میں کھولا نہیں جا سکتا"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"کچھ دستاویزات کو حذف کرنے سے قاصر"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"خصوصیات کو لوڈ نہیں کیا جا سکا"</string>
     <string name="share_via" msgid="8725082736005677161">"اشتراک کریں بذریعہ"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"فائلیں کاپی ہو رہی ہیں"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"فائلز کمپریس ہو رہی ہیں"</string>
@@ -119,11 +112,11 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> آئٹم حذف ہو رہا ہے۔</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"کالعدم کریں"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"کاپی کیلئے تیار ہو رہا ہے…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"کمپریس کیلئے تیار ہو رہا ہے…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"فائلیں نکالنے کی تیاری ہو رہی ہے…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"منتقلی کیلئے تیار ہو رہی ہیں…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"حذف کرنے کیلئے تیاری ہو رہی ہے…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"تیار ہو رہا ہے…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"تیار ہو رہا ہے…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"تیار ہو رہا ہے…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"تیار ہو رہا ہے…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"تیار ہو رہا ہے…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> آئٹمز کاپی نہیں ہو سکے</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"آرکائیو<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"<xliff:g id="NAME">%1$s</xliff:g> کو اوور رائٹ کریں؟"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"پس منظر میں جاری رکھیں"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"ڈیبگ کی معلومات (ڈیولپر فقط)"</string>
 </resources>
diff --git a/res/values-uz/inspector_strings.xml b/res/values-uz/inspector_strings.xml
new file mode 100644
index 0000000..1a791f3
--- /dev/null
+++ b/res/values-uz/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Ma’lumot"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Fayl haqida ma’lumotni yuklab bo‘lmadi"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Xatoliklarni tuzatish (faqat dasturchilar uchun)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"RAW fayli meta-axboroti: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Media tafsilotlari"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Bu turdagi fayl quyidagilar bilan ochiladi"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Bu fayl ta’minotchisi"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Tanlanmagan"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Noma’lum"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"O‘lchamlar"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> – <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Koordinatalari"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Dengiz sathidan balandligi"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Kamera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Diafragma"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Zatvor tezligi"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Davomiyligi"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Yaratilgan sanasi"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Fokus masofasi"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO ekvivalenti"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Ijrochi"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Bastakor"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Albom"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Joylashuv"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Strim turlari"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"RAW fayl hajmi (bayt)"</string>
+</resources>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 9b1766d..3cfa1d2 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="files_label" msgid="771781190045103748">"Fayllar"</string>
-    <string name="downloads_label" msgid="5462789470049501103">"Yuklanishlar"</string>
+    <string name="downloads_label" msgid="5462789470049501103">"Yuklanmalar"</string>
     <!-- no translation found for app_label (8089292432455111409) -->
     <skip />
     <!-- no translation found for launcher_label (799410258349837668) -->
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Arxivlash"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Arxivdan chiqarish"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Qayta nomlash"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Ma’lumot olish"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Ma’lumot olish"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"<xliff:g id="SOURCE">%1$s</xliff:g> orqali ochish"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Yangi oyna"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Kesish"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Ko‘chirib o‘tkazish"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Yopish"</string>
     <string name="button_retry" msgid="4011461781916631389">"Qayta urinib ko‘rish"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Tozalash"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Ta’minotchi orqali ko‘rsatish"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Saralanmagan"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Nomi"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Qisqacha tavsif"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Hajmi"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Tahrirlangan"</string>
     <string name="directory_items" msgid="6645621978998614003">"Elementlar soni"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Bu turdagi fayl quyidagilar bilan ochiladi"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Mazkur fayl bunga tegishli"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Boshqa ilovalar bu fayl turini ocha olishadi."</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"Asliga qaytaring."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Tozalash"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Ta’minotchi orqali ko‘rsatish"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Tanlanmagan"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Noma’lum"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"O‘sish bo‘yicha"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Kamayish bo‘yicha"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Ko‘rsatish"</string>
@@ -85,12 +79,11 @@
     <string name="root_type_shortcut" msgid="6059343175525442279">"Tezkor tugmalar"</string>
     <string name="root_type_device" msgid="1713604128005476585">"Qurilmalar"</string>
     <string name="root_type_apps" msgid="8646073235029886342">"Boshqa ilovalar"</string>
-    <string name="empty" msgid="5300254272613103004">"Hech narsa yo‘q"</string>
+    <string name="empty" msgid="5300254272613103004">"Hech narsa topilmadi"</string>
     <string name="no_results" msgid="2371026325236359209">"%1$s jildidan topilmadi"</string>
     <string name="toast_no_application" msgid="7555319548595113121">"Faylni ochib bo‘lmadi"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Arxivdagi fayllarni ochib bo‘lmadi"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Ba’zi hujjatlarni o‘chirib bo‘lmadi"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Xususiyatlarni yuklab bo‘lmadi"</string>
     <string name="share_via" msgid="8725082736005677161">"Ulashish"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Fayllar nusxalanmoqda"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Fayllar arxivlanmoqda"</string>
@@ -119,11 +112,11 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta element o‘chirib tashlanmoqda.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Bekor qilish"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Nuxsa olishga tayyorgarlik..."</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Arxivga tayyorlanmoqda…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Tayyorlanmoqda…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Ko‘chirishga tayyorgarlik…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"O‘chirishga tayyorlanmoqda…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Tayyorlanmoqda…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Tayyorlanmoqda…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Tayyorlanmoqda…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Tayyorlanmoqda…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Tayyorlanmoqda…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta elementdan nusxa olib bo‘lmadi</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"arxiv<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"<xliff:g id="NAME">%1$s</xliff:g> fayli almashtirilsinmi?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Fonda davom ettirish"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Xatoliklarni tuzatish (faqat dasturchilar uchun)"</string>
 </resources>
diff --git a/res/values-vi/inspector_strings.xml b/res/values-vi/inspector_strings.xml
new file mode 100644
index 0000000..c540bff
--- /dev/null
+++ b/res/values-vi/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Thông tin"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Không thể tải thông tin tệp"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Thông tin gỡ lỗi (chỉ dành cho nhà phát triển)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Siêu dữ liệu Raw: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Chi tiết về phương tiện"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Loại tệp này mở bằng"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Tệp này được cung cấp bởi"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Chưa chọn"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Không xác định"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Kích thước"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Tọa độ"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Độ cao"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Máy ảnh"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Khẩu độ"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Tốc độ chụp"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Thời lượng"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Chụp vào"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Tiêu cự"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO tương đương"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Nghệ sĩ"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Nhà soạn nhạc"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"Album"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Địa điểm"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Loại luồng"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Kích thước tệp Raw (byte)"</string>
+</resources>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 8b88bba..8738885 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Nén"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Trích xuất sang…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Đổi tên"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Xem thông tin"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Xem thông tin"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Xem trong <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Cửa sổ mới"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Cắt"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Chuyển"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Loại bỏ"</string>
     <string name="button_retry" msgid="4011461781916631389">"Thử lại"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Xóa"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Hiển thị trong nhà cung cấp"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Chưa được sắp xếp"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Tên"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Tóm tắt"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Kích thước"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Đã sửa đổi"</string>
     <string name="directory_items" msgid="6645621978998614003">"Số mục"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Loại tệp này mở bằng"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Tệp này thuộc về"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Các ứng dụng khác có thể mở loại tệp này. Xóa"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"dưới dạng ứng dụng mặc định."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Xóa"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Hiển thị trong nhà cung cấp"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Chưa chọn"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Không xác định"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Tăng dần"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Giảm dần"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Hiển thị gốc"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Không thể mở tệp"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Không thể mở tệp trong lưu trữ"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Không thể xóa một số tài liệu"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Không thể tải các thuộc tính"</string>
     <string name="share_via" msgid="8725082736005677161">"Chia sẻ qua"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Đang sao chép tệp"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Nén tệp"</string>
@@ -119,11 +112,11 @@
       <item quantity="one">Đang xóa <xliff:g id="COUNT_0">%1$d</xliff:g> mục.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Hoàn tác"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Đang chuẩn bị sao chép…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Đang chuẩn bị nén…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Đang chuẩn bị giải nén…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Đang chuẩn bị di chuyển…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Đang chuẩn bị xóa…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Đang chuẩn bị…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Đang chuẩn bị…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Đang chuẩn bị…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Đang chuẩn bị…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Đang chuẩn bị…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other">Không thể sao chép <xliff:g id="COUNT_1">%1$d</xliff:g> mục</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"lưu trữ<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Ghi đè <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Tiếp tục ở chế độ nền"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Thông tin gỡ lỗi (chỉ dành cho nhà phát triển)"</string>
 </resources>
diff --git a/res/values-zh-rCN/inspector_strings.xml b/res/values-zh-rCN/inspector_strings.xml
new file mode 100644
index 0000000..312f3db
--- /dev/null
+++ b/res/values-zh-rCN/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"信息"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"无法加载文件信息"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"调试信息(仅限开发者)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"原始元数据:<xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"媒体详情"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"使用以下应用打开这类文件:"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"此文件的提供方:"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"未选择"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"未知"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"尺寸"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> 百万像素"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"坐标"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>,<xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"海拔"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"相机"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"光圈"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"快门速度"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"时长"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"拍摄时间"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"焦距"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> 毫米"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO 等效感光度"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"音乐人"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"作曲家"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"专辑"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"位置"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"流式传输类型"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"原始大小(字节)"</string>
+</resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 67f3164..ee56816 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -41,15 +41,15 @@
     <string name="menu_compress" msgid="37539111904724188">"压缩"</string>
     <string name="menu_extract" msgid="8171946945982532262">"解压到…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"重命名"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"获取信息"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"获取信息"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"在“<xliff:g id="SOURCE">%1$s</xliff:g>”中查看"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"新建窗口"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"剪切"</string>
     <string name="menu_copy_to_clipboard" msgid="5064081159073330776">"复制"</string>
     <string name="menu_paste_from_clipboard" msgid="360947260414135827">"粘贴"</string>
     <string name="menu_paste_into_folder" msgid="8000644546983240101">"粘贴到文件夹中"</string>
-    <string name="menu_advanced_show" msgid="7558626506462906726">"显示内部存储设备"</string>
-    <string name="menu_advanced_hide" msgid="6488381508009246334">"隐藏内部存储设备"</string>
+    <string name="menu_advanced_show" msgid="7558626506462906726">"显示内部存储空间"</string>
+    <string name="menu_advanced_hide" msgid="6488381508009246334">"隐藏内部存储空间"</string>
     <string name="button_select" msgid="240863497069321364">"选择"</string>
     <string name="button_copy" msgid="8219059853840996027">"复制"</string>
     <string name="button_compress" msgid="8951561310857223966">"压缩"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"移动"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"关闭"</string>
     <string name="button_retry" msgid="4011461781916631389">"重试"</string>
+    <string name="button_clear" msgid="5412304437764369441">"清除"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"在提供程序中显示"</string>
     <string name="not_sorted" msgid="7813496644889115530">"未排序"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"名称"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"摘要"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"大小"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"上次修改时间"</string>
     <string name="directory_items" msgid="6645621978998614003">"项数"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"这类文件可使用以下应用打开:"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"此文件属于"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"其他应用可以打开这种文件类型。清除"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"设为默认值。"</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"清除"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"在提供程序中显示"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"未选择"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"未知"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"升序"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"降序"</string>
     <string name="drawer_open" msgid="8071673398187261741">"显示根目录"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"无法打开文件"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"无法打开归档文件"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"无法删除部分文档"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"无法加载属性"</string>
     <string name="share_via" msgid="8725082736005677161">"分享方式"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"正在复制文件"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"正在压缩文件"</string>
@@ -99,8 +92,8 @@
     <string name="delete_notification_title" msgid="2512757431856830792">"正在删除文件"</string>
     <string name="copy_remaining" msgid="5390517377265177727">"剩余时间:<xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="151184708996738192">
-      <item quantity="other">正在复制 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件。</item>
-      <item quantity="one">正在复制 <xliff:g id="COUNT_0">%1$d</xliff:g> 个文件。</item>
+      <item quantity="other">正在复制 <xliff:g id="COUNT_1">%1$d</xliff:g> 项。</item>
+      <item quantity="one">正在复制 <xliff:g id="COUNT_0">%1$d</xliff:g> 项。</item>
     </plurals>
     <plurals name="compress_begin" formatted="false" msgid="3534158317098678895">
       <item quantity="other">正在压缩 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件。</item>
@@ -111,19 +104,19 @@
       <item quantity="one">正在解压 <xliff:g id="COUNT_0">%1$d</xliff:g> 个文件。</item>
     </plurals>
     <plurals name="move_begin" formatted="false" msgid="1464229874265756956">
-      <item quantity="other">正在移动 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件。</item>
-      <item quantity="one">正在移动 <xliff:g id="COUNT_0">%1$d</xliff:g> 个文件。</item>
+      <item quantity="other">正在移动 <xliff:g id="COUNT_1">%1$d</xliff:g> 项。</item>
+      <item quantity="one">正在移动 <xliff:g id="COUNT_0">%1$d</xliff:g> 项。</item>
     </plurals>
     <plurals name="deleting" formatted="false" msgid="1729138001178158901">
-      <item quantity="other">正在删除 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件。</item>
-      <item quantity="one">正在删除 <xliff:g id="COUNT_0">%1$d</xliff:g> 个文件。</item>
+      <item quantity="other">正在删除 <xliff:g id="COUNT_1">%1$d</xliff:g> 项。</item>
+      <item quantity="one">正在删除 <xliff:g id="COUNT_0">%1$d</xliff:g> 项。</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"撤消"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"正在准备复制…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"正准备压缩…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"正在准备解压缩…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"正在准备移动…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"正在准备删除…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"正在准备…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"正在准备…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"正在准备…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"正在准备…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"正在准备…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other">无法复制 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"归档<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"要覆盖 <xliff:g id="NAME">%1$s</xliff:g> 吗?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"继续在后台执行"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"调试信息(仅限开发者)"</string>
 </resources>
diff --git a/res/values-zh-rHK/inspector_strings.xml b/res/values-zh-rHK/inspector_strings.xml
new file mode 100644
index 0000000..8b7e48f
--- /dev/null
+++ b/res/values-zh-rHK/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"資訊"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"無法載入檔案資訊"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"偵錯資料 (只限開發人員)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"原始元數據:<xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"媒體詳情"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"使用以下應用程式開啟這種檔案:"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"這個檔案的提供者:"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"未選取"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"不明"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"尺寸"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> 百萬像素"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"座標"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>,<xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"高度"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"相機"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"光圈"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"快門速度"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"時間長度"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"拍攝時間"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"焦距"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> 毫米"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"ISO 等效感光度"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"歌手"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"作曲者"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"專輯"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"位置"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"串流類型"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"原始大小 (字節)"</string>
+</resources>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 4b1f9a5..bdde0e5 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"壓縮"</string>
     <string name="menu_extract" msgid="8171946945982532262">"壓縮至…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"重新命名"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"獲取資訊"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"顯示資訊"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"在「<xliff:g id="SOURCE">%1$s</xliff:g>」中查看"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"新視窗"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"剪下"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"移動"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"關閉"</string>
     <string name="button_retry" msgid="4011461781916631389">"再試一次"</string>
+    <string name="button_clear" msgid="5412304437764369441">"清除"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"在供應商的應用程式中顯示"</string>
     <string name="not_sorted" msgid="7813496644889115530">"尚未排序"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"名稱"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"摘要"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"大小"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"上次修改時間"</string>
     <string name="directory_items" msgid="6645621978998614003">"項目數量"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"開啟這類型檔案的應用程式:"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"此檔案的提供者"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"其他應用程式可開啟這種檔案類型。清除"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"作為預設。"</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"清除"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"在提供者中顯示"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"未選取"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"不明"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"遞增"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"遞減"</string>
     <string name="drawer_open" msgid="8071673398187261741">"顯示根目錄"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"無法開啟檔案"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"無法開啟封存中的檔案"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"無法刪除部分文件"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"無法載入屬性"</string>
     <string name="share_via" msgid="8725082736005677161">"透過以下應用程式分享:"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"正在複製檔案"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"正在壓縮檔案"</string>
@@ -119,11 +112,11 @@
       <item quantity="one">正在刪除 <xliff:g id="COUNT_0">%1$d</xliff:g> 個項目。</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"復原"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"正在準備複製…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"正在準備壓縮檔案…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"正在準備解壓縮檔案…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"正在準備移動…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"正在準備刪除…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"正在準備…"</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"正在準備…"</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"正在準備…"</string>
+    <string name="move_preparing" msgid="6504239656430530761">"正在準備…"</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"正在準備…"</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other">無法複製 <xliff:g id="COUNT_1">%1$d</xliff:g> 個項目。</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"archive<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"要覆寫「<xliff:g id="NAME">%1$s</xliff:g>」嗎?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"繼續在背景執行"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"偵錯資料 (只限開發人員)"</string>
 </resources>
diff --git a/res/values-zh-rTW/inspector_strings.xml b/res/values-zh-rTW/inspector_strings.xml
new file mode 100644
index 0000000..8c17e39
--- /dev/null
+++ b/res/values-zh-rTW/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"資訊"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"無法載入檔案資訊"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"偵錯資訊 (開發人員專用)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"原始中繼資料:<xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"媒體詳細資料"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"使用以下應用程式開啟這種檔案:"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"這個檔案的提供者:"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"未選取"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"不明"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"尺寸"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g> 百萬像素"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"座標"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>,<xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"高度"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"相機"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"光圈"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"快門速度"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"時間長度"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"拍攝時間"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"焦距"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> 毫米"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"等效 ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"演出者"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"作曲者"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"專輯"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"位置"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"串流類型"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"原始大小 (位元組)"</string>
+</resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 631d47e..500f1b2 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"壓縮"</string>
     <string name="menu_extract" msgid="8171946945982532262">"解壓縮到…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"重新命名"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"取得資訊"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"取得資訊"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"在「<xliff:g id="SOURCE">%1$s</xliff:g>」中查看"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"新視窗"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"剪下"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"移動"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"關閉"</string>
     <string name="button_retry" msgid="4011461781916631389">"再試一次"</string>
+    <string name="button_clear" msgid="5412304437764369441">"清除"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"在供應商的應用程式中顯示"</string>
     <string name="not_sorted" msgid="7813496644889115530">"未排序"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"名稱"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"摘要"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"大小"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"上次修改時間"</string>
     <string name="directory_items" msgid="6645621978998614003">"項目數量"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"使用以下應用程式開啟這種檔案"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"這個檔案的提供者"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"其他應用程式可開啟這種檔案類型。清除"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"設為預設值。"</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"清除"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"在提供者中顯示"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"未選取"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"不明"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"遞增"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"遞減"</string>
     <string name="drawer_open" msgid="8071673398187261741">"顯示根目錄"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"無法開啟檔案"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"無法開啟已封存的檔案"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"無法刪除部分文件"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"無法載入屬性"</string>
     <string name="share_via" msgid="8725082736005677161">"分享方式:"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"複製檔案"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"正在壓縮檔案"</string>
@@ -119,11 +112,11 @@
       <item quantity="one">正在刪除 <xliff:g id="COUNT_0">%1$d</xliff:g> 個項目。</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"復原"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"正在準備複製…"</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"正在準備壓縮…"</string>
-    <string name="extract_preparing" msgid="58266275455027829">"正在準備解壓縮檔案…"</string>
-    <string name="move_preparing" msgid="8742573245485449429">"正在準備移動…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"正在準備刪除…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"準備中..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"準備中..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"準備中..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"準備中..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"準備中..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="other">無法複製 <xliff:g id="COUNT_1">%1$d</xliff:g> 個項目</item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"archive<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"要覆寫「<xliff:g id="NAME">%1$s</xliff:g>」嗎?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"繼續在背景執行"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"偵錯資訊 (僅限開發人員)"</string>
 </resources>
diff --git a/res/values-zu/inspector_strings.xml b/res/values-zu/inspector_strings.xml
new file mode 100644
index 0000000..3cb972d
--- /dev/null
+++ b/res/values-zu/inspector_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="inspector_title" msgid="1924760928091740238">"Ulwazi"</string>
+    <string name="inspector_load_error" msgid="7522190243413249291">"Ulwazi lwefayela alikwazanga ukulayishwa"</string>
+    <string name="inspector_debug_section" msgid="2576052661505700421">"Ulwazi lokususa iphutha (i-dev kuphela)"</string>
+    <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Imethadatha e-Raw: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string>
+    <string name="inspector_metadata_section" msgid="6077622515328240575">"Imininingwane yemidiya"</string>
+    <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Lolu hlobo lwefayela luvuleka nge-"</string>
+    <string name="handler_app_belongs_to" msgid="5444507329303253553">"Leli fayela linikezelwe yi-"</string>
+    <string name="handler_app_not_selected" msgid="1294439257183908786">"Abangakhethiwe"</string>
+    <string name="handler_app_unknown" msgid="5911661530593229287">"Akwaziwa"</string>
+    <string name="metadata_dimensions" msgid="6112907724016659801">"Ubukhulu"</string>
+    <string name="metadata_dimensions_format" msgid="6138765871412005962">"<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g> - <xliff:g id="MEGAPIXELS">%3$,.1f</xliff:g>MP"</string>
+    <string name="metadata_coordinates" msgid="6897383227370702734">"Ukuxhumanisa"</string>
+    <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string>
+    <string name="metadata_altitude" msgid="8063792127436794294">"Ukuphakama"</string>
+    <string name="metadata_camera" msgid="2363009732801281319">"Ikhamera"</string>
+    <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string>
+    <string name="metadata_aperture" msgid="6538741952698935357">"Imbobo"</string>
+    <string name="metadata_shutter_speed" msgid="8204739885103326131">"Isivinini seshutha"</string>
+    <string name="metadata_duration" msgid="3115494422055472715">"Ubude besikhathi"</string>
+    <string name="metadata_date_time" msgid="1090351199248114406">"Ithathwe ngezi"</string>
+    <string name="metadata_focal_length" msgid="3440735161407699893">"Ubude befokhali"</string>
+    <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g>mm"</string>
+    <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Okulinganayo kwe-ISO"</string>
+    <string name="metadata_iso_format" msgid="4153285204012694861">"I-ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string>
+    <string name="metadata_artist" msgid="8972421485694988540">"Umculi"</string>
+    <string name="metadata_composer" msgid="4696926808308256056">"Umqambi"</string>
+    <string name="metadata_album" msgid="1661699531214720236">"I-albhamu"</string>
+    <string name="metadata_address" msgid="1849921023707744640">"Indawo"</string>
+    <string name="debug_stream_types" msgid="2088565280360139333">"Izinhlobo zokusakaza"</string>
+    <string name="debug_raw_size" msgid="7487139640175650185">"Usayizi we-Raw (amabhayithi)"</string>
+</resources>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index cf1e7b7..e469fa3 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -41,7 +41,7 @@
     <string name="menu_compress" msgid="37539111904724188">"Cindezela"</string>
     <string name="menu_extract" msgid="8171946945982532262">"Khiphela ku…"</string>
     <string name="menu_rename" msgid="1883113442688817554">"Qamba kabusha"</string>
-    <string name="menu_inspector" msgid="8217713416277319588">"Thola ulwazi"</string>
+    <string name="menu_inspect" msgid="7279855349299446224">"Thola ulwazi"</string>
     <string name="menu_view_in_owner" msgid="7228948660557554770">"Buka ku-<xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="menu_new_window" msgid="2947837751796109126">"Iwindi elisha"</string>
     <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Sika"</string>
@@ -57,6 +57,8 @@
     <string name="button_move" msgid="8596460499325291272">"Hambisa"</string>
     <string name="button_dismiss" msgid="7235249361023803349">"Cashisa"</string>
     <string name="button_retry" msgid="4011461781916631389">"Zama Futhi"</string>
+    <string name="button_clear" msgid="5412304437764369441">"Sula"</string>
+    <string name="button_show_provider" msgid="6905880493806292753">"Bonisa kumhlinzeki"</string>
     <string name="not_sorted" msgid="7813496644889115530">"Akuhlungiwe"</string>
     <string name="sort_dimension_name" msgid="6325591541414177579">"Igama"</string>
     <string name="sort_dimension_summary" msgid="7724534446881397860">"Isifinyezo"</string>
@@ -64,14 +66,6 @@
     <string name="sort_dimension_size" msgid="2190547351159472884">"Usayizi"</string>
     <string name="sort_dimension_date" msgid="4231005651895254033">"Kulungisiwe"</string>
     <string name="directory_items" msgid="6645621978998614003">"Inombolo yezinto"</string>
-    <string name="handler_app_file_opens_with" msgid="2667097605117000751">"Lolu hlobo lwefayela luvuleka nge-"</string>
-    <string name="handler_app_belongs_to" msgid="5956928604521893459">"Leli fayela elaka-"</string>
-    <string name="handler_app_button_info_1" msgid="4271199640671067569">"Ezinye izinhlelo zokusebenza zingavula lolu hlobo lwefayela. Sula"</string>
-    <string name="handler_app_button_info_2" msgid="4299969771512815898">"setha njengokuzenzakalelayo."</string>
-    <string name="handler_app_clear" msgid="206579047716445033">"Sula"</string>
-    <string name="handler_app_show_in" msgid="7923573101129079048">"Bonisa kumhlinzeki"</string>
-    <string name="handler_app_not_selected" msgid="8178393676227130360">"Abangakhethiwe"</string>
-    <string name="handler_app_unknown" msgid="56574249066388341">"Akwaziwa"</string>
     <string name="sort_direction_ascending" msgid="5882787683763248102">"Iyanyuka"</string>
     <string name="sort_direction_descending" msgid="1729187589765894076">"Iyehla"</string>
     <string name="drawer_open" msgid="8071673398187261741">"Bonisa izimpande"</string>
@@ -90,7 +84,6 @@
     <string name="toast_no_application" msgid="7555319548595113121">"Ayikwazanga ukuvula ifayela"</string>
     <string name="toast_view_in_archives_unsupported" msgid="1923221390170964845">"Ayikwazi ukuvula amafayela kuzingobo zomlando"</string>
     <string name="toast_failed_delete" msgid="3453846588205817591">"Ayikwazi ukususa amanye amadokhumenti"</string>
-    <string name="file_inspector_load_error" msgid="1226344446677541109">"Izakhiwo azikwazanga ukulayishwa"</string>
     <string name="share_via" msgid="8725082736005677161">"Abelana nge-"</string>
     <string name="copy_notification_title" msgid="52256435625098456">"Ikopisha amafayela"</string>
     <string name="compress_notification_title" msgid="6830195148113751021">"Icindezela amafayela"</string>
@@ -119,11 +112,11 @@
       <item quantity="other">Isusa izinto ezingu-<xliff:g id="COUNT_1">%1$d</xliff:g>.</item>
     </plurals>
     <string name="undo" msgid="2902438994196400565">"Hlehlisa"</string>
-    <string name="copy_preparing" msgid="5326063807006898223">"Ilungiselela ukukopisha..."</string>
-    <string name="compress_preparing" msgid="6650018601382062672">"Ilungiselela ukucindezela..."</string>
-    <string name="extract_preparing" msgid="58266275455027829">"Ilungiselela ukukhipha..."</string>
-    <string name="move_preparing" msgid="8742573245485449429">"Ilungiselela ukuhambisa…"</string>
-    <string name="delete_preparing" msgid="6513863752916028147">"Ilungiselela ukususa…"</string>
+    <string name="copy_preparing" msgid="4759516490222449324">"Iyalungiselela..."</string>
+    <string name="compress_preparing" msgid="7401605598969019696">"Iyalungiselela..."</string>
+    <string name="extract_preparing" msgid="4796626960061745796">"Iyalungiselela..."</string>
+    <string name="move_preparing" msgid="6504239656430530761">"Iyalungiselela..."</string>
+    <string name="delete_preparing" msgid="7339349837842802508">"Iyalungiselela..."</string>
     <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963">
       <item quantity="one">Ayikwazanga ukukopisha izinto ezingu-<xliff:g id="COUNT_1">%1$d</xliff:g></item>
@@ -213,5 +206,4 @@
     <string name="new_archive_file_name" msgid="1604650338077249838">"ingobo yomlando<xliff:g id="EXTENSION">%s</xliff:g>"</string>
     <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Faka ngaphezulu i-<xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="continue_in_background" msgid="1974214559047793331">"Qhubeka ngemuva"</string>
-    <string name="inspector_debug_section" msgid="3447621501565766900">"Ulwazi lokususa iphutha (dev kuphela)"</string>
 </resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index e7801b9..c500261 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -25,8 +25,8 @@
     <color name="menu_search_background">@android:color/transparent</color>
 
     <color name="primary_dark">#ff254FAE</color>
-    <color name="primary">@*android:color/Blue_700</color>
-    <color name="accent">@*android:color/Blue_700</color>
+    <color name="primary">@color/tool_bar_color</color>
+    <color name="accent">@color/tool_bar_color</color>
     <color name="accent_dark">@*android:color/accent_device_default_dark</color>
 
     <color name="text_cursor">@*android:color/white</color>
@@ -48,6 +48,7 @@
     <color name="root_icon_color">#ff5a5a5a</color>
     <item name="root_icon_disabled_alpha" format="float" type="dimen">@*android:dimen/disabled_alpha_material_light</item>
     <color name="doc_icon_color">#ff5a5a5a</color>
+    <color name="tool_bar_color">#ff1A73E8</color>
 
     <!-- TODO: Would be nice to move this to a color-set, but not sure how to support animation -->
     <color name="item_doc_title">#ff333333</color>
@@ -76,5 +77,8 @@
     <color name="scroll_track">#fff0f0f0</color>
 
     <color name="inspector_value">#ff939393</color>
+    <color name="inspector_link">#6633b5e5</color>
     <color name="inspector_section_title">#ff939393</color>
+    <color name="inspector_section_divider">#E0E0E0</color>
+    <color name="inspector_title_background">#40000000</color>
 </resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index 978cc5f..8e3a943 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -30,6 +30,9 @@
 
     <string name="default_root_uri" translatable="false">content://com.android.providers.downloads.documents/root/downloads</string>
 
+    <string name="datetime_format_12" translatable="false">MMM dd, yyyy, h:mm a</string>
+    <string name="datetime_format_24" translatable="false">MMM dd, yyyy, H:mm</string>
+
     <!--
         New features must be added behind a boolean flag prefixed w/ "feature_".
         Please add them in alphabetical order. Same goes for accessor
@@ -48,7 +51,7 @@
     <bool name="feature_remote_actions">true</bool>
     <bool name="feature_system_keyboard_navigation">true</bool>
     <bool name="feature_virtual_files_sharing">true</bool>
-    <bool name="feature_inspector">false</bool>
+    <bool name="feature_inspector">true</bool>
     <bool name="feature_debug_mode">false</bool>
 
     <!-- Indicates if internal storage is shown as default or not. -->
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 7eadccc..b720c33 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -52,7 +52,8 @@
     <dimen name="doc_header_height">60dp</dimen>
 
     <dimen name="dropdown_sort_widget_margin">12dp</dimen>
-    <dimen name="dropdown_sort_widget_size">36dp</dimen>
+    <dimen name="dropdown_sort_widget_size">48dp</dimen>
+    <dimen name="dropdown_sort_text_size">18sp</dimen>
 
     <dimen name="drop_icon_height">14dp</dimen>
     <dimen name="drop_icon_width">14dp</dimen>
diff --git a/res/values/inspector_strings.xml b/res/values/inspector_strings.xml
new file mode 100644
index 0000000..a70a274
--- /dev/null
+++ b/res/values/inspector_strings.xml
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- File properties dialog title. This dialog show fine grained details about a file. -->
+    <string name="inspector_title">Info</string>
+
+    <!-- File properties dialog error shown when information about a file could not be loaded-->
+    <string name="inspector_load_error">File info could not be loaded</string>
+
+    <!-- Title of inspector's debug information section. The contents of this section
+         features detailed "internal" information useful primarily to developers.
+         This section is only visible to developers or people running debug builds. [CHAR LIMIT=48] -->
+    <string name="inspector_debug_section">Debug info (dev only)</string>
+
+    <!-- Title of inspector's debug info metadata sub-section. [CHAR LIMIT=48] -->
+    <string name="inspector_debug_metadata_section">Raw metadata: <xliff:g id="metadataType" example="EXIF">%1$s</xliff:g></string>
+
+    <!-- Title of inspector's media details info section. Shows information related to camera, dimensions, and authors. -->
+    <string name="inspector_metadata_section">Media details</string>
+
+    <!-- File properties dialog section title. In this section we show information about the default handler application for this type of file.-->
+    <string name="handler_app_file_opens_with">This kind of file opens with</string>
+    <!-- File properties dialog section title. In this section we show information about the applicaiton that provides the file.
+         Examples of such applicaitons are: Box, Microsoft OneDrive, and Google Drive, etc)-->
+    <string name="handler_app_belongs_to">This file is supplied by</string>
+
+    <!-- File properties dialog user message if a default app has not been selected-->
+    <string name="handler_app_not_selected">Not selected</string>
+    <!-- File properties dialog user message if the default app is unknown-->
+    <string name="handler_app_unknown">Unknown</string>
+
+    <!-- The height and width of a photo. -->
+    <string name="metadata_dimensions">Dimensions</string>
+    <!-- The width and height of a photo, followed by a the "megapixel rating".
+         Cameras are frequently rated by "megapixels". In U.S. English the "megapixels" rating
+         of a camera is denoted by a number followed by "MP". E.g. 12.2MP or 8MP. -->
+    <string name="metadata_dimensions_format"><xliff:g id="width" example="1280">%1$d</xliff:g> x <xliff:g id="height" example="1024">%2$d</xliff:g> - <xliff:g id="megapixels" example="12.2">%3$,.1f</xliff:g>MP</string>
+    <!-- The location of where a photo was taken. -->
+    <string name="metadata_coordinates">Coordinates</string>
+    <!-- The location a photo was taken in the form of latitude/longitude coordinates. -->
+    <string name="metadata_coordinates_format"><xliff:g id="latitude" example="33.996">%1$,.3f</xliff:g>, <xliff:g id="longitude" example="-118.476">%2$,.3f</xliff:g></string>
+    <!-- The elevation a photo was taken. -->
+    <string name="metadata_altitude">Altitude</string>
+    <!-- The camera make and model. -->
+    <string name="metadata_camera">Camera</string>
+    <!-- The camera make and model. Where make is usually the company, and model is the individual camera model name. -->
+    <string name="metadata_camera_format"><xliff:g id="make" example="Sony">%1$s</xliff:g> <xliff:g id="model" example="Snazzy Snapper">%2$s</xliff:g></string>
+    <!-- The value of a photos aperture. Note that this is probably camera EXIF data.-->
+    <string name="metadata_aperture">Aperture</string>
+    <!-- The value of a photos shutter speed. Note that this is probably camera EXIF data.-->
+    <string name="metadata_shutter_speed">Shutter speed</string>
+    <!-- How long a video/audio file is.-->
+    <string name="metadata_duration">Duration</string>
+    <!-- When a photo was taken. Note that this is probably camera EXIF data.-->
+    <string name="metadata_date_time">Taken on</string>
+    <!-- Message presenting EXIF aperture information in the tradition "f/2.0" format familiar to users. This format is basically an industry standard that shouldn't be translated, so it is marked as not translatable. -->
+    <string name="metadata_aperture_format" translatable="false">f/<xliff:g id="aperture" example="2.0">%1$,.1f</xliff:g></string>
+    <!--The tag for the focal length of a camera. Note that this is probably camera EXIF data-->
+    <string name="metadata_focal_length">Focal length</string>
+    <!--The format for displaying the focal length of a camera. Note that this is probably camera EXIF data-->
+    <string name="metadata_focal_format"><xliff:g id="length" example="24">%1$.2f </xliff:g>mm</string>
+    <!--The tag for the ISO Speed of a camera. Note that this is probably camera EXIF data-->
+    <string name="metadata_iso_speed_ratings">ISO equivalent</string>
+    <!--The format for displaying ISO speed. Note that this is probably camera EXIF data-->
+    <string name="metadata_iso_format">ISO <xliff:g id="iso_speed" example="35">%1$d</xliff:g></string>
+    <!--The title of the audio file, Note this is probably MP3 ID3 tags.-->
+    <string name="metadata_artist">Artist</string>
+    <!--The composer for the audio file, Note this is probably MP3 ID3 tags-->
+    <string name="metadata_composer">Composer</string>
+    <!--The title of the album (i.e. collection of recordings) the song belongs to. Note this is probably MP3 ID3 tags-->
+    <string name="metadata_album">Album</string>
+    <!-- The address nearest to where a photo was taken -->
+    <string name="metadata_address">Location</string>
+
+    <!-- String label for developer/debug file details, specifying which stream types are available. -->
+    <string name="debug_stream_types">Stream types</string>
+    <!-- String label for developer/debug file details, specifying the size of the file in bytes. -->
+    <string name="debug_raw_size">Raw size (bytes)</string>
+    <!-- String label for developer/debug file details, specifying a file's uri/content address. -->
+    <string name="debug_content_uri" translatable="false">Uri</string>
+    <!-- String label for developer/debug file details, specifying document id. -->
+    <string name="debug_document_id" translatable="false">Document id</string>
+    <!-- String label for developer/debug file details, specifying mimetype. -->
+    <string name="debug_raw_mimetype" translatable="false">Raw mimetype</string>
+    <!-- String label for developer/debug file details, specifying that a file is an archive. -->
+    <string name="debug_is_archive" translatable="false">Is archive</string>
+    <!-- String label for developer/debug file details, specifying that a file is a container (like a folder or an archive). -->
+    <string name="debug_is_container" translatable="false">Is container</string>
+    <!-- String label for developer/debug file details, specifying that a file is partial (being downloaded). -->
+    <string name="debug_is_partial" translatable="false">Is partial</string>
+    <!-- String label for developer/debug file details, specifying that a file is virtual (has no byte representation). -->
+    <string name="debug_is_virtual" translatable="false">Is virtual</string>
+    <!-- String label for developer/debug file details, specifying that a file supports creating files within it. -->
+    <string name="debug_supports_create" translatable="false">Supports create</string>
+    <!-- String label for developer/debug file details, specifying that a file is deletable. -->
+    <string name="debug_supports_delete" translatable="false">Supports delete</string>
+    <!-- String label for developer/debug file details, specifying that a file has associated metadata. -->
+    <string name="debug_supports_metadata" translatable="false">Supports metadata</string>
+    <!-- String label for developer/debug file details, specifying that a file can be removed. -->
+    <string name="debug_supports_remove" translatable="false">Supports remove</string>
+    <!-- String label for developer/debug file details, specifying that a file can be renamed. -->
+    <string name="debug_supports_rename" translatable="false">Supports rename</string>
+    <!-- String label for developer/debug file details, specifying that a file supports the "settings" feature. -->
+    <string name="debug_supports_settings" translatable="false">Supports settings</string>
+    <!-- String label for developer/debug file details, specifying that a file has a viewable thumbnail. -->
+    <string name="debug_supports_thumbnail" translatable="false">Supports thumbnail</string>
+    <!-- String label for developer/debug file details, specifying that a file supports the "weblink" feature. -->
+    <string name="debug_supports_weblink" translatable="false">Supports weblink</string>
+    <!-- String label for developer/debug file details, specifying that a file is writable. -->
+    <string name="debug_supports_write" translatable="false">Supports write</string>
+
+</resources>
diff --git a/res/values/mimes.xml b/res/values/mimes.xml
index 6823ed9..0559741 100644
--- a/res/values/mimes.xml
+++ b/res/values/mimes.xml
@@ -16,54 +16,54 @@
   -->
 
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- Generic file type with an extention shown in type column in list view. [CHAR LIMIT=24] -->
+    <!-- Generic file type with an extention shown in type column in list view. [CHAR LIMIT=30] -->
     <string name="generic_extention_file_type"><xliff:g id="extension" example="APE">%1$s</xliff:g> file</string>
-    <!-- Generic file type without an extention shown in type column in list view. [CHAR LIMIT=24] -->
+    <!-- Generic file type without an extention shown in type column in list view. [CHAR LIMIT=30] -->
     <string name="generic_file_type">File</string>
-    <!-- Generic image file type shown in type column in list view. [CHAR LIMIT=24] -->
+    <!-- Generic image file type shown in type column in list view. [CHAR LIMIT=30] -->
     <string name="image_file_type">Image</string>
-    <!-- Image file type shown in type column in list view. [CHAR LIMIT=24] -->
+    <!-- Image file type shown in type column in list view. [CHAR LIMIT=30] -->
     <string name="image_extension_file_type"><xliff:g id="fileType" example="JPG">%1$s</xliff:g> image</string>
-    <!-- Generic audio file type shown in type column in list view. [CHAR LIMIT=24] -->
+    <!-- Generic audio file type shown in type column in list view. [CHAR LIMIT=30] -->
     <string name="audio_file_type">Audio</string>
-    <!-- Audio file type shown in type column in list view. [CHAR LIMIT=24] -->
+    <!-- Audio file type shown in type column in list view. [CHAR LIMIT=30] -->
     <string name="audio_extension_file_type"><xliff:g id="fileType" example="MP3">%1$s</xliff:g> audio</string>
-    <!-- Generic video file type shown in type column in list view. [CHAR LIMIT=24] -->
+    <!-- Generic video file type shown in type column in list view. [CHAR LIMIT=30] -->
     <string name="video_file_type">Video</string>
-    <!-- Video file type shown in type column in list view. [CHAR LIMIT=24] -->
+    <!-- Video file type shown in type column in list view. [CHAR LIMIT=30] -->
     <string name="video_extension_file_type"><xliff:g id="fileType" example="AVI">%1$s</xliff:g> video</string>
-    <!-- Archive file type shown in type column in list view. [CHAR LIMIT=24] -->
+    <!-- Archive file type shown in type column in list view. [CHAR LIMIT=30] -->
     <string name="archive_file_type"><xliff:g id="fileType" example="Zip">%1$s</xliff:g> archive</string>
-    <!-- Android application file type shown in type column in list view. [CHAR LIMIT=24] -->
+    <!-- Android application file type shown in type column in list view. [CHAR LIMIT=30] -->
     <string name="apk_file_type">Android application</string>
-    <!-- Plain text file type shown in type column in list view. [CHAR LIMIT=24] -->
+    <!-- Plain text file type shown in type column in list view. [CHAR LIMIT=30] -->
     <string name="txt_file_type">Plain text</string>
-    <!-- HTML file type shown in type column in list view. [CHAR LIMIT=24] -->
+    <!-- HTML file type shown in type column in list view. [CHAR LIMIT=30] -->
     <string name="html_file_type">HTML document</string>
-    <!-- PDF file type shown in type column in list view. [CHAR LIMIT=24] -->
+    <!-- PDF file type shown in type column in list view. [CHAR LIMIT=30] -->
     <string name="pdf_file_type">PDF document</string>
-    <!-- Word document file type shown in type column in list view. [CHAR LIMIT=24] -->
+    <!-- Word document file type shown in type column in list view. [CHAR LIMIT=30] -->
     <string name="word_file_type">Word document</string>
-    <!-- PowerPoint presentation file type shown in type column in list view. [CHAR LIMIT=24] -->
+    <!-- PowerPoint presentation file type shown in type column in list view. [CHAR LIMIT=30] -->
     <string name="ppt_file_type">PowerPoint presentation</string>
-    <!-- Excel spreadsheet file type shown in type column in list view. [CHAR LIMIT=24] -->
+    <!-- Excel spreadsheet file type shown in type column in list view. [CHAR LIMIT=30] -->
     <string name="excel_file_type">Excel spreadsheet</string>
-    <!-- Google document file type shown in type column in list view. [CHAR LIMIT=24] -->
+    <!-- Google document file type shown in type column in list view. [CHAR LIMIT=30] -->
     <string name="gdoc_file_type">Google document</string>
-    <!-- Google spreadsheet file type shown in type column in list view. [CHAR LIMIT=24] -->
+    <!-- Google spreadsheet file type shown in type column in list view. [CHAR LIMIT=30] -->
     <string name="gsheet_file_type">Google spreadsheet</string>
-    <!-- Google presentation file type shown in type column in list view. [CHAR LIMIT=24] -->
+    <!-- Google presentation file type shown in type column in list view. [CHAR LIMIT=30] -->
     <string name="gslides_file_type">Google presentation</string>
-    <!-- Google drawing file type shown in type column in list view. [CHAR LIMIT=24] -->
+    <!-- Google drawing file type shown in type column in list view. [CHAR LIMIT=30] -->
     <string name="gdraw_file_type">Google drawing</string>
-    <!-- Google table file type shown in type column in list view. [CHAR LIMIT=24] -->
+    <!-- Google table file type shown in type column in list view. [CHAR LIMIT=30] -->
     <string name="gtable_file_type">Google table</string>
-    <!-- Google form file type shown in type column in list view. [CHAR LIMIT=24] -->
+    <!-- Google form file type shown in type column in list view. [CHAR LIMIT=30] -->
     <string name="gform_file_type">Google form</string>
-    <!-- Google map file type shown in type column in list view. [CHAR LIMIT=24] -->
+    <!-- Google map file type shown in type column in list view. [CHAR LIMIT=30] -->
     <string name="gmap_file_type">Google map</string>
-    <!-- Google site file type shown in type column in list view. [CHAR LIMIT=24] -->
+    <!-- Google site file type shown in type column in list view. [CHAR LIMIT=30] -->
     <string name="gsite_file_type">Google site</string>
     <!-- Generic directory type shown when viewing a folder in the properties view -->
     <string name="directory_type">Folder</string>
-</resources>
\ No newline at end of file
+</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a5ecfac..d671960 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -18,7 +18,7 @@
     <!-- Title of the Files application [CHAR LIMIT=32] -->
     <string name="files_label">Files</string>
 
-    <!-- Title of the Downloads application, which sometimes Files is known as [CHAR LIMIT=32] -->
+    <!-- Title of the Downloads application, which sometimes Files is known as [CHAR LIMIT=16] -->
     <string name="downloads_label">Downloads</string>
 
     <!-- Title of the documents application [CHAR LIMIT=32] -->
@@ -67,8 +67,8 @@
     <string name="menu_extract">Extract to\u2026</string>
     <!-- Menu item that renames the selected document [CHAR LIMIT=28] -->
     <string name="menu_rename">Rename</string>
-    <!--Menu item that displays properties about the selected document [CHAR LIMIT=28] -->
-    <string name="menu_inspector">Get info</string>
+    <!-- Menu item that displays properties about the selected document [CHAR LIMIT=28] -->
+    <string name="menu_inspect">Get info</string>
     <!-- Menu item that renames the selected document [CHAR LIMIT=28] -->
     <string name="menu_view_in_owner">View in <xliff:g id="source" example="Google Drive">%1$s</xliff:g></string>
 
@@ -103,6 +103,11 @@
     <!-- Button label that hides the error bar [CHAR LIMIT=24] -->
     <string name="button_dismiss">Dismiss</string>
     <string name="button_retry">Try Again</string>
+    <!-- Button label that removes the default application to open a file. -->
+    <string name="button_clear">Clear</string>
+    <!-- Button label that show in the providers service. Many providers have their own app such
+     as google drive. Pressing this button would open in the file in the providers app. -->
+    <string name="button_show_provider">Show in provider</string>
 
     <!-- A string used to show user that currently documents are not sorted in any given order. [CHAR_LIMIT=30] -->
     <string name="not_sorted">Not sorted</string>
@@ -120,26 +125,6 @@
     <!--Table header for number of items in a folder.-->
     <string name="directory_items">Number of items</string>
 
-    <!--File properties dialog section title. In this section we show information about the default handler application for this type of file.-->
-    <string name="handler_app_file_opens_with">This kind of file opens with</string>
-    <!--File properties dialog section title. In this section we show information about a files provider. (e.g. system, drive, dropbox, etc)-->
-    <string name="handler_app_belongs_to">This file belongs to</string>
-
-    <!--File properties dialog button description for clearing the default app. the name of the app
-     will be inserted programmatically inbetween these two strings-->
-    <string name="handler_app_button_info_1">Other apps can open this file type. Clear</string>
-    <string name="handler_app_button_info_2">as the default.</string>
-
-    <!--File properties dialog button label to clear the default app-->
-    <string name="handler_app_clear">Clear</string>
-    <!--File properties dialog button label to show a document in a provider-->
-    <string name="handler_app_show_in">Show in provider</string>
-
-    <!--File properties dialog user message if a default app has not been selected-->
-    <string name="handler_app_not_selected">Not selected</string>
-    <!--File properties dialog user message if the default app is unknown-->
-    <string name="handler_app_unknown">Unknown</string>
-
     <!-- content description to describe ascending sorting used with upward arrow in table header. -->
     <string name="sort_direction_ascending">Ascending</string>
     <!-- content description to describe descending sorting used with downward arrow in table header. -->
@@ -183,9 +168,6 @@
     <!-- Toast shown when some of the selected documents failed to be deleted [CHAR LIMIT=48] -->
     <string name="toast_failed_delete">Unable to delete some documents</string>
 
-    <!-- Toast shown when a files document info fails to load-->
-    <string name="file_inspector_load_error">Properties could not be loaded</string>
-
     <!-- Title of dialog when prompting user to select an app to share documents with [CHAR LIMIT=32] -->
     <string name="share_via">Share via</string>
 
@@ -229,15 +211,15 @@
     <!-- Text shown for the undo button -->
     <string name="undo">Undo</string>
     <!-- Text shown on the notification while DocumentsUI performs setup in preparation for copying files [CHAR LIMIT=32] -->
-    <string name="copy_preparing">Preparing for copy\u2026</string>
+    <string name="copy_preparing">Preparing...</string>
     <!-- Text shown on the notification while DocumentsUI performs setup in preparation for compressing files [CHAR LIMIT=32] -->
-    <string name="compress_preparing">Preparing for compress\u2026</string>
+    <string name="compress_preparing">Preparing...</string>
     <!-- Text shown on the notification while DocumentsUI performs setup in preparation for extracting files [CHAR LIMIT=32] -->
-    <string name="extract_preparing">Preparing for extract\u2026</string>
+    <string name="extract_preparing">Preparing...</string>
     <!-- Text shown on the notification while DocumentsUI performs setup in preparation for moving files [CHAR LIMIT=32] -->
-    <string name="move_preparing">Preparing for move\u2026</string>
+    <string name="move_preparing">Preparing...</string>
     <!-- Text shown on the notification while DocumentsUI performs setup in preparation for deleting files [CHAR LIMIT=32] -->
-    <string name="delete_preparing">Preparing for delete\u2026</string>
+    <string name="delete_preparing">Preparing...</string>
     <!-- Text progress shown on the notification while DocumentsUI is deleting files. -->
     <string name="delete_progress"><xliff:g id="count" example="3">%1$d</xliff:g> / <xliff:g id="totalCount" example="5">%2$d</xliff:g></string>
     <!-- Title of the copy error notification [CHAR LIMIT=48] -->
@@ -386,8 +368,4 @@
 
     <!-- Button for continuing a file operation in background, eg. copying, moving or extracting. [CHAR LIMIT=48] -->
     <string name="continue_in_background">Continue in background</string>
-
-    <!-- Title of inspector's debug info section. [CHAR LIMIT=48] -->
-    <string name="inspector_debug_section">Debug info (dev only)</string>
-
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 37659d4..ec06169 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -17,11 +17,13 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
 
     <style name="ActionBarTheme" parent="@*android:style/ThemeOverlay.Material.Dark.ActionBar">
+        <item name="android:colorControlNormal">@android:color/white</item>
         <item name="android:textSelectHandle">@drawable/text_select_handle_middle</item>
         <item name="android:textSelectHandleLeft">@drawable/text_select_handle_left</item>
         <item name="android:textSelectHandleRight">@drawable/text_select_handle_right</item>
         <item name="android:textCursorDrawable">@drawable/text_cursor</item>
         <item name="android:textColorHighlight">@color/text_highlight</item>
+        <item name="android:textColorPrimary">@android:color/white</item>
     </style>
     <style name="ActionBarPopupTheme" parent="@*android:style/ThemeOverlay.Material.Light" />
 
diff --git a/src/com/android/documentsui/AbstractActionHandler.java b/src/com/android/documentsui/AbstractActionHandler.java
index 0faab6e..15425a8 100644
--- a/src/com/android/documentsui/AbstractActionHandler.java
+++ b/src/com/android/documentsui/AbstractActionHandler.java
@@ -18,7 +18,7 @@
 
 import static com.android.documentsui.base.DocumentInfo.getCursorInt;
 import static com.android.documentsui.base.DocumentInfo.getCursorString;
-import static com.android.documentsui.base.Shared.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
 
 import android.app.Activity;
 import android.app.LoaderManager.LoaderCallbacks;
@@ -51,15 +51,16 @@
 import com.android.documentsui.base.State;
 import com.android.documentsui.dirlist.AnimationView;
 import com.android.documentsui.dirlist.AnimationView.AnimationType;
-import com.android.documentsui.dirlist.DocumentDetails;
 import com.android.documentsui.dirlist.FocusHandler;
 import com.android.documentsui.files.LauncherActivity;
 import com.android.documentsui.queries.SearchViewManager;
 import com.android.documentsui.roots.GetRootDocumentTask;
 import com.android.documentsui.roots.LoadRootTask;
 import com.android.documentsui.roots.ProvidersAccess;
-import com.android.documentsui.selection.Selection;
-import com.android.documentsui.selection.SelectionManager;
+import com.android.documentsui.selection.ContentLock;
+import com.android.documentsui.selection.MutableSelection;
+import com.android.documentsui.selection.SelectionHelper;
+import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
 import com.android.documentsui.sidebar.EjectRootTask;
 import com.android.documentsui.ui.Snackbars;
 
@@ -92,7 +93,7 @@
     protected final ProvidersAccess mProviders;
     protected final DocumentsAccess mDocs;
     protected final FocusHandler mFocusHandler;
-    protected final SelectionManager mSelectionMgr;
+    protected final SelectionHelper mSelectionMgr;
     protected final SearchViewManager mSearchMgr;
     protected final Lookup<String, Executor> mExecutors;
     protected final Injector<?> mInjector;
@@ -101,7 +102,7 @@
 
     private Runnable mDisplayStateChangedListener;
 
-    private DirectoryReloadLock mDirectoryReloadLock;
+    private ContentLock mContentLock;
 
     @Override
     public void registerDisplayStateChangedListener(Runnable l) {
@@ -226,10 +227,11 @@
     }
 
     @Override
-    public boolean openDocument(DocumentDetails doc, @ViewType int type, @ViewType int fallback) {
+    public boolean openItem(ItemDetails doc, @ViewType int type, @ViewType int fallback) {
         throw new UnsupportedOperationException("Can't open document.");
     }
 
+    @Override
     public void showInspector(DocumentInfo doc) {
         throw new UnsupportedOperationException("Can't open properties.");
     }
@@ -356,6 +358,13 @@
                         + mState.stack.getRoot());
             }
 
+            final DocumentInfo top = stack.peek();
+            if (top.isArchive()) {
+                // Swap the zip file in original provider and the one provided by ArchiveProvider.
+                stack.pop();
+                stack.push(mDocs.getArchiveDocument(top.derivedUri));
+            }
+
             mState.stack.reset();
             // Update navigator to give horizontal breadcrumb a chance to update documents. It
             // doesn't update its content if the size of document stack doesn't change.
@@ -524,13 +533,15 @@
         loadRoot(Shared.getDefaultRootUri(mActivity));
     }
 
-    protected Selection getStableSelection() {
-        return mSelectionMgr.getSelection(new Selection());
+    protected MutableSelection getStableSelection() {
+        MutableSelection selection = new MutableSelection();
+        mSelectionMgr.copySelection(selection);
+        return selection;
     }
 
     @Override
-    public ActionHandler reset(DirectoryReloadLock reloadLock) {
-        mDirectoryReloadLock = reloadLock;
+    public ActionHandler reset(ContentLock reloadLock) {
+        mContentLock = reloadLock;
         mActivity.getLoaderManager().destroyLoader(LOADER_ID);
         return this;
     }
@@ -578,7 +589,7 @@
                         contentsUri,
                         mState.sortModel,
                         mInjector.fileTypeLookup,
-                        mDirectoryReloadLock,
+                        mContentLock,
                         mSearchMgr.isSearching());
             }
         }
diff --git a/src/com/android/documentsui/ActionHandler.java b/src/com/android/documentsui/ActionHandler.java
index 6b0e077..ba20f34 100644
--- a/src/com/android/documentsui/ActionHandler.java
+++ b/src/com/android/documentsui/ActionHandler.java
@@ -19,7 +19,6 @@
 import android.annotation.IntDef;
 import android.app.PendingIntent;
 import android.content.ContentProvider;
-import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ResolveInfo;
 import android.net.Uri;
@@ -29,8 +28,8 @@
 import com.android.documentsui.base.DocumentInfo;
 import com.android.documentsui.base.DocumentStack;
 import com.android.documentsui.base.RootInfo;
-import com.android.documentsui.dirlist.DocumentDetails;
-import com.android.documentsui.selection.Selection;
+import com.android.documentsui.selection.ContentLock;
+import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -111,7 +110,7 @@
      * If container, then opens the container, otherwise views using the specified type of view.
      * If the primary view type is unavailable, then fallback to the alternative type of view.
      */
-    boolean openDocument(DocumentDetails doc, @ViewType int type, @ViewType int fallback);
+    boolean openItem(ItemDetails doc, @ViewType int type, @ViewType int fallback);
 
     /**
      * This is called when user hovers over a doc for enough time during a drag n' drop, to open a
@@ -158,5 +157,5 @@
      * Allow action handler to be initialized in a new scope.
      * @return this
      */
-    <T extends ActionHandler> T reset(DirectoryReloadLock reloadLock);
+    <T extends ActionHandler> T reset(ContentLock contentLock);
 }
diff --git a/src/com/android/documentsui/ActionModeController.java b/src/com/android/documentsui/ActionModeController.java
index 7c5ad63..dc453b7 100644
--- a/src/com/android/documentsui/ActionModeController.java
+++ b/src/com/android/documentsui/ActionModeController.java
@@ -16,7 +16,7 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.base.Shared.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
 
 import android.annotation.IdRes;
 import android.annotation.Nullable;
@@ -24,7 +24,6 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.ActionMode;
-import android.view.HapticFeedbackConstants;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
@@ -35,22 +34,20 @@
 import com.android.documentsui.base.EventHandler;
 import com.android.documentsui.base.Menus;
 import com.android.documentsui.selection.Selection;
-import com.android.documentsui.selection.SelectionManager;
+import com.android.documentsui.selection.SelectionHelper;
+import com.android.documentsui.selection.SelectionHelper.SelectionObserver;
 import com.android.documentsui.ui.MessageBuilder;
 
-import java.util.function.Consumer;
-import java.util.function.IntConsumer;
-
 /**
  * A controller that listens to selection changes and manages life cycles of action modes.
  */
-public class ActionModeController
-        implements SelectionManager.Callback, ActionMode.Callback, ActionModeAddons {
+public class ActionModeController extends SelectionObserver
+        implements ActionMode.Callback, ActionModeAddons {
 
     private static final String TAG = "ActionModeController";
 
     private final Activity mActivity;
-    private final SelectionManager mSelectionMgr;
+    private final SelectionHelper mSelectionMgr;
     private final MenuManager mMenuManager;
     private final MessageBuilder mMessages;
 
@@ -62,7 +59,7 @@
 
     public ActionModeController(
             Activity activity,
-            SelectionManager selectionMgr,
+            SelectionHelper selectionMgr,
             MenuManager menuManager,
             MessageBuilder messages) {
 
@@ -74,7 +71,7 @@
 
     @Override
     public void onSelectionChanged() {
-        mSelectionMgr.getSelection(mSelected);
+        mSelectionMgr.copySelection(mSelected);
         if (mSelected.size() > 0) {
             if (mActionMode == null) {
                 if (DEBUG) Log.d(TAG, "Starting action mode.");
@@ -99,27 +96,7 @@
 
     @Override
     public void onSelectionRestored() {
-        mSelectionMgr.getSelection(mSelected);
-        if (mSelected.size() > 0) {
-            if (mActionMode == null) {
-                if (DEBUG) Log.d(TAG, "Starting action mode.");
-                mActionMode = mActivity.startActionMode(this);
-            }
-            updateActionMenu();
-        } else {
-            if (mActionMode != null) {
-                if (DEBUG) Log.d(TAG, "Finishing action mode.");
-                mActionMode.finish();
-            }
-        }
-
-        if (mActionMode != null) {
-            assert(!mSelected.isEmpty());
-            final String title = mMessages.getQuantityString(
-                    R.plurals.elements_selected, mSelected.size());
-            mActionMode.setTitle(title);
-            mActivity.getWindow().setTitle(title);
-        }
+        onSelectionChanged();
     }
 
     // Called when the user exits the action mode
@@ -135,9 +112,7 @@
         mActionMode = null;
         mMenu = null;
 
-        // clear selection
         mSelectionMgr.clearSelection();
-        mSelected.clear();
 
         // Reset window title back to activity title, i.e. Root name
         mActivity.getWindow().setTitle(mActivity.getTitle());
diff --git a/src/com/android/documentsui/BaseActivity.java b/src/com/android/documentsui/BaseActivity.java
index 290dd63..bab713f 100644
--- a/src/com/android/documentsui/BaseActivity.java
+++ b/src/com/android/documentsui/BaseActivity.java
@@ -16,7 +16,7 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.base.Shared.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
 import static com.android.documentsui.base.Shared.EXTRA_BENCHMARK;
 import static com.android.documentsui.base.State.MODE_GRID;
 
@@ -383,6 +383,13 @@
                 && !root.isRecents();
     }
 
+    /**
+     * Returns true if a directory can be inspected.
+     */
+    protected boolean canInspectDirectory() {
+        return false;
+    }
+
     // TODO: make navigator listen to state
     @Override
     public final void updateNavigator() {
@@ -425,12 +432,10 @@
         }
 
         mNavigator.update();
+
         // Causes talkback to announce the activity's new title
-        if (mState.stack.isRecents()) {
-            setTitle(mProviders.getRecentsRoot().title);
-        } else {
-            setTitle(mState.stack.getTitle());
-        }
+        setTitle(mState.stack.getTitle());
+
         invalidateOptionsMenu();
     }
 
diff --git a/src/com/android/documentsui/CreateDirectoryFragment.java b/src/com/android/documentsui/CreateDirectoryFragment.java
index e7a33a0..ab31544 100644
--- a/src/com/android/documentsui/CreateDirectoryFragment.java
+++ b/src/com/android/documentsui/CreateDirectoryFragment.java
@@ -16,7 +16,7 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.base.Shared.TAG;
+import static com.android.documentsui.base.SharedMinimal.TAG;
 
 import android.app.AlertDialog;
 import android.app.Dialog;
diff --git a/src/com/android/documentsui/DirectoryLoader.java b/src/com/android/documentsui/DirectoryLoader.java
index 30a447c..55900e6 100644
--- a/src/com/android/documentsui/DirectoryLoader.java
+++ b/src/com/android/documentsui/DirectoryLoader.java
@@ -16,7 +16,7 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.base.Shared.VERBOSE;
+import static com.android.documentsui.base.SharedMinimal.VERBOSE;
 
 import android.content.AsyncTaskLoader;
 import android.content.ContentProviderClient;
@@ -43,6 +43,7 @@
 import com.android.documentsui.base.Lookup;
 import com.android.documentsui.base.RootInfo;
 import com.android.documentsui.roots.RootCursorWrapper;
+import com.android.documentsui.selection.ContentLock;
 import com.android.documentsui.sorting.SortModel;
 
 import libcore.io.IoUtils;
@@ -74,7 +75,7 @@
             Uri uri,
             SortModel model,
             Lookup<String, String> fileTypeLookup,
-            DirectoryReloadLock lock,
+            ContentLock lock,
             boolean inSearchMode) {
 
         super(context, ProviderExecutor.forAuthority(root.authority));
@@ -226,10 +227,10 @@
     }
 
     private static final class LockingContentObserver extends ContentObserver {
-        private final DirectoryReloadLock mLock;
+        private final ContentLock mLock;
         private final Runnable mContentChangedCallback;
 
-        public LockingContentObserver(DirectoryReloadLock lock, Runnable contentChangedCallback) {
+        public LockingContentObserver(ContentLock lock, Runnable contentChangedCallback) {
             super(new Handler(Looper.getMainLooper()));
             mLock = lock;
             mContentChangedCallback = contentChangedCallback;
@@ -242,7 +243,7 @@
 
         @Override
         public void onChange(boolean selfChange) {
-            mLock.tryUpdate(mContentChangedCallback);
+            mLock.runWhenUnlocked(mContentChangedCallback);
         }
     }
 }
diff --git a/src/com/android/documentsui/DirectoryReloadLock.java b/src/com/android/documentsui/DirectoryReloadLock.java
deleted file mode 100644
index 4299914..0000000
--- a/src/com/android/documentsui/DirectoryReloadLock.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui;
-
-import static com.android.documentsui.base.Shared.VERBOSE;
-
-import android.annotation.MainThread;
-import android.annotation.Nullable;
-import android.util.Log;
-
-import com.android.documentsui.base.Shared;
-import com.android.documentsui.selection.BandController;
-
-/**
- * A lock used by {@link DirectoryLoader} and {@link BandController} to ensure refresh is blocked
- * while Band Selection is active.
- */
-public final class DirectoryReloadLock {
-    private static final String TAG = "DirectoryReloadLock";
-
-    private int mPauseCount = 0;
-    private @Nullable Runnable mCallback;
-
-    /**
-     * Increment the block count by 1
-     */
-    @MainThread
-    public void block() {
-        Shared.checkMainLoop();
-        mPauseCount++;
-        if (VERBOSE) Log.v(TAG, "Block count increments to " + mPauseCount + ".");
-    }
-
-    /**
-     * Decrement the block count by 1; If no other object is trying to block and there exists some
-     * callback, that callback will be run
-     */
-    @MainThread
-    public void unblock() {
-        Shared.checkMainLoop();
-        assert(mPauseCount > 0);
-        mPauseCount--;
-        if (VERBOSE) Log.v(TAG, "Block count decrements to " + mPauseCount + ".");
-        if (mPauseCount == 0 && mCallback != null) {
-            mCallback.run();
-            mCallback = null;
-        }
-    }
-
-    /**
-     * Attempts to run the given Runnable if not-blocked, or else the Runnable is set to be ran next
-     * (replacing any previous set Runnables).
-     */
-    public void tryUpdate(Runnable update) {
-        if (mPauseCount == 0) {
-            update.run();
-        } else {
-            mCallback = update;
-        }
-    }
-}
diff --git a/src/com/android/documentsui/DocsSelectionHelper.java b/src/com/android/documentsui/DocsSelectionHelper.java
new file mode 100644
index 0000000..ebdfc9b
--- /dev/null
+++ b/src/com/android/documentsui/DocsSelectionHelper.java
@@ -0,0 +1,289 @@
+/*
+ * 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.documentsui;
+
+import android.support.annotation.VisibleForTesting;
+import android.support.v7.widget.RecyclerView;
+
+import com.android.documentsui.selection.DefaultSelectionHelper;
+import com.android.documentsui.selection.DefaultSelectionHelper.SelectionMode;
+import com.android.documentsui.selection.MutableSelection;
+import com.android.documentsui.selection.Selection;
+import com.android.documentsui.selection.SelectionHelper;
+
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * DocumentsUI SelectManager implementation that creates delegate instances
+ * each time reset is called.
+ */
+public final class DocsSelectionHelper extends SelectionHelper {
+
+    private final DelegateFactory mFactory;
+    private final @SelectionMode int mSelectionMode;
+
+    // initialize to a dummy object incase we get some input
+    // event drive calls before we're properly initialized.
+    // See: b/69306667.
+    private SelectionHelper mDelegate = new DummySelectionHelper();
+
+    @VisibleForTesting
+    DocsSelectionHelper(DelegateFactory factory, @SelectionMode int mode) {
+        mFactory = factory;
+        mSelectionMode = mode;
+    }
+
+    public SelectionHelper reset(
+            RecyclerView.Adapter<?> adapter,
+            StableIdProvider stableIds,
+            SelectionPredicate canSetState) {
+
+        if (mDelegate != null) {
+            mDelegate.clearSelection();
+        }
+
+        mDelegate = mFactory.create(mSelectionMode, adapter, stableIds, canSetState);
+        return this;
+    }
+
+    @Override
+    public void addObserver(SelectionObserver listener) {
+        mDelegate.addObserver(listener);
+    }
+
+    @Override
+    public boolean hasSelection() {
+        return mDelegate.hasSelection();
+    }
+
+    @Override
+    public Selection getSelection() {
+        return mDelegate.getSelection();
+    }
+
+    @Override
+    public void copySelection(Selection dest) {
+        mDelegate.copySelection(dest);
+    }
+
+    @Override
+    public boolean isSelected(String id) {
+        return mDelegate.isSelected(id);
+    }
+
+    @VisibleForTesting
+    public void replaceSelection(Iterable<String> ids) {
+        mDelegate.clearSelection();
+        mDelegate.setItemsSelected(ids, true);
+    }
+
+    @Override
+    public void restoreSelection(Selection other) {
+        mDelegate.restoreSelection(other);
+    }
+
+    @Override
+    public boolean setItemsSelected(Iterable<String> ids, boolean selected) {
+        return mDelegate.setItemsSelected(ids, selected);
+    }
+
+    @Override
+    public void clearSelection() {
+        mDelegate.clearSelection();
+    }
+
+    @Override
+    public boolean select(String modelId) {
+        return mDelegate.select(modelId);
+    }
+
+    @Override
+    public boolean deselect(String modelId) {
+        return mDelegate.deselect(modelId);
+    }
+
+    @Override
+    public void startRange(int pos) {
+        mDelegate.startRange(pos);
+    }
+
+    @Override
+    public void extendRange(int pos) {
+        mDelegate.extendRange(pos);
+    }
+
+    @Override
+    public void extendProvisionalRange(int pos) {
+        mDelegate.extendProvisionalRange(pos);
+    }
+
+    @Override
+    public void clearProvisionalSelection() {
+        mDelegate.clearProvisionalSelection();
+    }
+
+    @Override
+    public void setProvisionalSelection(Set<String> newSelection) {
+        mDelegate.setProvisionalSelection(newSelection);
+    }
+
+    @Override
+    public void mergeProvisionalSelection() {
+        mDelegate.mergeProvisionalSelection();
+    }
+
+    @Override
+    public void endRange() {
+        mDelegate.endRange();
+    }
+
+    @Override
+    public boolean isRangeActive() {
+        return mDelegate.isRangeActive();
+    }
+
+    @Override
+    public void anchorRange(int position) {
+        mDelegate.anchorRange(position);
+    }
+
+    public static DocsSelectionHelper createMultiSelect() {
+        return new DocsSelectionHelper(
+                DelegateFactory.INSTANCE,
+                DefaultSelectionHelper.MODE_MULTIPLE);
+    }
+
+    public static DocsSelectionHelper createSingleSelect() {
+        return new DocsSelectionHelper(
+                DelegateFactory.INSTANCE,
+                DefaultSelectionHelper.MODE_SINGLE);
+    }
+
+    /**
+     * Use of a factory to create selection manager instances allows testable instances to
+     * be inject from tests.
+     */
+    @VisibleForTesting
+    static class DelegateFactory {
+        static final DelegateFactory INSTANCE = new DelegateFactory();
+
+        SelectionHelper create(
+                @SelectionMode int mode,
+                RecyclerView.Adapter<?> adapter,
+                StableIdProvider stableIds,
+                SelectionPredicate canSetState) {
+
+            return new DefaultSelectionHelper(mode, adapter, stableIds, canSetState);
+        }
+    }
+
+    /**
+     * A dummy SelectHelper used by DocsSelectionHelper before a real
+     * SelectionHelper has been initialized by DirectoryFragment.
+     */
+    private static final class DummySelectionHelper extends SelectionHelper {
+
+        @Override
+        public void addObserver(SelectionObserver listener) {
+        }
+
+        @Override
+        public boolean hasSelection() {
+            return false;
+        }
+
+        @Override
+        public Selection getSelection() {
+            return new MutableSelection();
+        }
+
+        @Override
+        public void copySelection(Selection dest) {
+        }
+
+        @Override
+        public boolean isSelected(String id) {
+            return false;
+        }
+
+        @VisibleForTesting
+        public void replaceSelection(Iterable<String> ids) {
+        }
+
+        @Override
+        public void restoreSelection(Selection other) {
+        }
+
+        @Override
+        public boolean setItemsSelected(Iterable<String> ids, boolean selected) {
+            return false;
+        }
+
+        @Override
+        public void clearSelection() {
+        }
+
+        @Override
+        public boolean select(String modelId) {
+            return false;
+        }
+
+        @Override
+        public boolean deselect(String modelId) {
+            return false;
+        }
+
+        @Override
+        public void startRange(int pos) {
+        }
+
+        @Override
+        public void extendRange(int pos) {
+        }
+
+        @Override
+        public void extendProvisionalRange(int pos) {
+        }
+
+        @Override
+        public void clearProvisionalSelection() {
+        }
+
+        @Override
+        public void setProvisionalSelection(Set<String> newSelection) {
+        }
+
+        @Override
+        public void mergeProvisionalSelection() {
+        }
+
+        @Override
+        public void endRange() {
+        }
+
+        @Override
+        public boolean isRangeActive() {
+            return false;
+        }
+
+        @Override
+        public void anchorRange(int position) {
+        }
+    }
+}
diff --git a/src/com/android/documentsui/DrawerController.java b/src/com/android/documentsui/DrawerController.java
index d8c679a..1a69363 100644
--- a/src/com/android/documentsui/DrawerController.java
+++ b/src/com/android/documentsui/DrawerController.java
@@ -16,7 +16,7 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.base.Shared.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
 
 import android.annotation.IntDef;
 import android.app.Activity;
diff --git a/src/com/android/documentsui/FocusManager.java b/src/com/android/documentsui/FocusManager.java
index 609d127..676ffa2 100644
--- a/src/com/android/documentsui/FocusManager.java
+++ b/src/com/android/documentsui/FocusManager.java
@@ -17,7 +17,7 @@
 package com.android.documentsui;
 
 import static com.android.documentsui.base.DocumentInfo.getCursorString;
-import static com.android.documentsui.base.Shared.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
 import static com.android.internal.util.Preconditions.checkNotNull;
 
 import android.annotation.ColorRes;
@@ -47,8 +47,8 @@
 import com.android.documentsui.dirlist.DocumentHolder;
 import com.android.documentsui.dirlist.DocumentsAdapter;
 import com.android.documentsui.dirlist.FocusHandler;
+import com.android.documentsui.selection.SelectionHelper;
 import com.android.documentsui.Model.Update;
-import com.android.documentsui.selection.SelectionManager;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -61,7 +61,7 @@
     private final ContentScope mScope = new ContentScope();
 
     private final Features mFeatures;
-    private final SelectionManager mSelectionMgr;
+    private final SelectionHelper mSelectionMgr;
     private final DrawerController mDrawer;
     private final Procedure mRootsFocuser;
     private final TitleSearchHelper mSearchHelper;
@@ -70,7 +70,7 @@
 
     public FocusManager(
             Features features,
-            SelectionManager selectionMgr,
+            SelectionHelper selectionMgr,
             DrawerController drawer,
             Procedure rootsFocuser,
             @ColorRes int color) {
@@ -153,6 +153,10 @@
         final int focusPos = (mScope.lastFocusPosition != RecyclerView.NO_POSITION)
                 ? mScope.lastFocusPosition
                 : mScope.layout.findFirstVisibleItemPosition();
+        if (focusPos == RecyclerView.NO_POSITION) {
+            return false;
+        }
+
         focusItem(focusPos);
         return true;
     }
@@ -167,7 +171,7 @@
             return;
         }
 
-        int pos = mScope.adapter.getModelIds().indexOf(mScope.pendingFocusId);
+        int pos = mScope.adapter.getStableIds().indexOf(mScope.pendingFocusId);
         if (pos != -1) {
             focusItem(pos);
         }
@@ -558,7 +562,7 @@
             int itemCount = mScope.adapter.getItemCount();
             List<String> index = new ArrayList<>(itemCount);
             for (int i = 0; i < itemCount; i++) {
-                String modelId = mScope.adapter.getModelId(i);
+                String modelId = mScope.adapter.getStableId(i);
                 Cursor cursor = mScope.model.getItem(modelId);
                 if (modelId != null && cursor != null) {
                     String title = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME);
diff --git a/src/com/android/documentsui/Injector.java b/src/com/android/documentsui/Injector.java
index 30d1d4b..7f9edd4 100644
--- a/src/com/android/documentsui/Injector.java
+++ b/src/com/android/documentsui/Injector.java
@@ -28,11 +28,12 @@
 import com.android.documentsui.base.Features;
 import com.android.documentsui.base.Lookup;
 import com.android.documentsui.base.RootInfo;
+import com.android.documentsui.dirlist.DocsStableIdProvider;
 import com.android.documentsui.dirlist.DocumentsAdapter;
 import com.android.documentsui.prefs.ScopedPreferences;
 import com.android.documentsui.queries.SearchViewManager;
-import com.android.documentsui.selection.SelectionManager;
-import com.android.documentsui.selection.SelectionManager.SelectionPredicate;
+import com.android.documentsui.selection.ContentLock;
+import com.android.documentsui.selection.SelectionHelper;
 import com.android.documentsui.ui.DialogController;
 import com.android.documentsui.ui.MessageBuilder;
 import com.android.internal.annotations.VisibleForTesting;
@@ -70,7 +71,7 @@
     public FocusManager focusManager;
 
     @ContentScoped
-    public SelectionManager selectionMgr;
+    public DocsSelectionHelper selectionMgr;
 
     private final Model mModel;
 
@@ -119,9 +120,9 @@
         return focusManager.reset(view, model);
     }
 
-    public SelectionManager getSelectionManager(
-            DocumentsAdapter adapter, SelectionPredicate canSetState) {
-        return selectionMgr.reset(adapter, canSetState);
+    public SelectionHelper getSelectionManager(
+            DocumentsAdapter adapter, SelectionHelper.SelectionPredicate canSetState) {
+        return selectionMgr.reset(adapter, new DocsStableIdProvider(adapter), canSetState);
     }
 
     public final ActionModeController getActionModeController(
@@ -131,20 +132,22 @@
 
     /**
      * Obtains action handler and resets it if necessary.
-     * @param reloadLock the lock held by {@link com.android.documentsui.selection.BandController}
-     *                   to prevent loader from updating result during band selection. May be
-     *                   {@code null} if called from
-     *                   {@link com.android.documentsui.sidebar.RootsFragment}.
+     *
+     * @param contentLock the lock held by
+     *            {@link com.android.documentsui.selection.BandSelectionHelper} and
+     *            {@link com.android.documentsui.selection.GestureSelectionHelper} to prevent
+     *            loader from updating result during band/gesture selection. May be {@code null} if
+     *            called from {@link com.android.documentsui.sidebar.RootsFragment}.
      * @return the action handler
      */
-    public T getActionHandler(@Nullable DirectoryReloadLock reloadLock) {
+    public T getActionHandler(@Nullable ContentLock contentLock) {
 
         // provide our friend, RootsFragment, early access to this special feature!
-        if (reloadLock == null) {
+        if (contentLock == null) {
             return actions;
         }
 
-        return actions.reset(reloadLock);
+        return actions.reset(contentLock);
     }
 
     /**
diff --git a/src/com/android/documentsui/LoadDocStackTask.java b/src/com/android/documentsui/LoadDocStackTask.java
index 1ce4630..af10693 100644
--- a/src/com/android/documentsui/LoadDocStackTask.java
+++ b/src/com/android/documentsui/LoadDocStackTask.java
@@ -60,7 +60,6 @@
 
     @Override
     public @Nullable DocumentStack run(Uri... uris) {
-        // assert(Features.OMC_RUNTIME);
         if (mDocs.isDocumentUri(uris[0])) {
             final Uri docUri;
             if (DocumentsContract.isTreeUri(uris[0])) {
diff --git a/src/com/android/documentsui/MenuManager.java b/src/com/android/documentsui/MenuManager.java
index a8c9767..705c35a 100644
--- a/src/com/android/documentsui/MenuManager.java
+++ b/src/com/android/documentsui/MenuManager.java
@@ -62,8 +62,8 @@
         updateCopyTo(menu.findItem(R.id.action_menu_copy_to), selection);
         updateCompress(menu.findItem(R.id.action_menu_compress), selection);
         updateExtractTo(menu.findItem(R.id.action_menu_extract_to), selection);
+        updateInspect(menu.findItem(R.id.action_menu_inspect), selection);
         updateViewInOwner(menu.findItem(R.id.action_menu_view_in_owner), selection);
-        updateInspector(menu.findItem(R.id.action_menu_inspector), selection);
 
         Menus.disableHiddenItems(menu);
     }
@@ -78,7 +78,7 @@
                 menu.findItem(R.id.option_menu_list));
         updateAdvanced(menu.findItem(R.id.option_menu_advanced));
         updateDebug(menu.findItem(R.id.option_menu_debug));
-
+        updateInspect(menu.findItem(R.id.option_menu_inspect));
         Menus.disableHiddenItems(menu);
     }
 
@@ -115,7 +115,7 @@
      */
     @VisibleForTesting
     public void updateContextMenuForFiles(Menu menu, SelectionDetails selectionDetails) {
-        assert(selectionDetails != null);
+        assert selectionDetails != null;
 
         MenuItem share = menu.findItem(R.id.dir_menu_share);
         MenuItem open = menu.findItem(R.id.dir_menu_open);
@@ -144,7 +144,7 @@
      */
     @VisibleForTesting
     public void updateContextMenuForDirs(Menu menu, SelectionDetails selectionDetails) {
-        assert(selectionDetails != null);
+        assert selectionDetails != null;
 
         MenuItem openInNewWindow = menu.findItem(R.id.dir_menu_open_in_new_window);
         MenuItem rename = menu.findItem(R.id.dir_menu_rename);
@@ -164,11 +164,12 @@
      */
     @VisibleForTesting
     public void updateContextMenu(Menu menu, SelectionDetails selectionDetails) {
-        assert(selectionDetails != null);
+        assert selectionDetails != null;
 
         MenuItem cut = menu.findItem(R.id.dir_menu_cut_to_clipboard);
         MenuItem copy = menu.findItem(R.id.dir_menu_copy_to_clipboard);
         MenuItem delete = menu.findItem(R.id.dir_menu_delete);
+        MenuItem inspect = menu.findItem(R.id.dir_menu_inspect);
 
         final boolean canCopy =
                 selectionDetails.size() > 0 && !selectionDetails.containsPartialFiles();
@@ -176,6 +177,8 @@
         cut.setEnabled(canCopy && canDelete);
         copy.setEnabled(canCopy);
         delete.setEnabled(canDelete);
+
+        inspect.setEnabled(selectionDetails.size() == 1);
     }
 
     /**
@@ -188,10 +191,12 @@
         MenuItem paste = menu.findItem(R.id.dir_menu_paste_from_clipboard);
         MenuItem selectAll = menu.findItem(R.id.dir_menu_select_all);
         MenuItem createDir = menu.findItem(R.id.dir_menu_create_dir);
+        MenuItem inspect = menu.findItem(R.id.dir_menu_inspect);
 
         paste.setEnabled(mDirDetails.hasItemsToPaste() && mDirDetails.canCreateDoc());
         updateSelectAll(selectAll);
         updateCreateDir(createDir);
+        updateInspect(inspect);
     }
 
     /**
@@ -273,8 +278,19 @@
         rename.setVisible(false);
     }
 
-    protected void updateInspector(MenuItem properties, SelectionDetails selectionDetails) {
-        properties.setVisible(false);
+    /**
+     * This method is called for standard activity option menu as opposed
+     * to when there is a selection.
+     */
+    protected void updateInspect(MenuItem inspector) {
+        inspector.setVisible(false);
+    }
+
+    /**
+     * This method is called for action mode, when a selection exists.
+     */
+    protected void updateInspect(MenuItem inspect, SelectionDetails selectionDetails) {
+        inspect.setVisible(false);
     }
 
     protected void updateViewInOwner(MenuItem view, SelectionDetails selectionDetails) {
@@ -365,5 +381,9 @@
         public boolean canCreateDirectory() {
             return mActivity.canCreateDirectory();
         }
+
+        public boolean canInspectDirectory() {
+            return mActivity.canInspectDirectory();
+        }
     }
 }
diff --git a/src/com/android/documentsui/Metrics.java b/src/com/android/documentsui/Metrics.java
index f421906..fba24be 100644
--- a/src/com/android/documentsui/Metrics.java
+++ b/src/com/android/documentsui/Metrics.java
@@ -16,14 +16,11 @@
 
 package com.android.documentsui;
 
-import static android.os.Environment.STANDARD_DIRECTORIES;
 import static com.android.documentsui.DocumentsApplication.acquireUnstableProviderOrThrow;
-import static com.android.documentsui.base.Shared.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
 
 import android.annotation.IntDef;
 import android.annotation.Nullable;
-import android.annotation.StringDef;
-import android.app.Activity;
 import android.content.ContentProviderClient;
 import android.content.Context;
 import android.content.Intent;
@@ -45,13 +42,14 @@
 import com.android.documentsui.services.FileOperationService;
 import com.android.documentsui.services.FileOperationService.OpType;
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.List;
 
-/** @hide */
+/**
+ * Methods for logging metrics.
+ */
 public final class Metrics {
     private static final String TAG = "Metrics";
 
@@ -689,102 +687,6 @@
         logHistogram(context, histogram, getOpCode(operationType, PROVIDER_INTRA));
     }
 
-    // Types for logInvalidScopedAccessRequest
-    public static final String SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS =
-            "docsui_scoped_directory_access_invalid_args";
-    public static final String SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY =
-            "docsui_scoped_directory_access_invalid_dir";
-    public static final String SCOPED_DIRECTORY_ACCESS_ERROR =
-            "docsui_scoped_directory_access_error";
-
-    @StringDef(value = {
-            SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS,
-            SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY,
-            SCOPED_DIRECTORY_ACCESS_ERROR
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface InvalidScopedAccess{}
-
-    public static void logInvalidScopedAccessRequest(Context context,
-            @InvalidScopedAccess String type) {
-        switch (type) {
-            case SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS:
-            case SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY:
-            case SCOPED_DIRECTORY_ACCESS_ERROR:
-                logCount(context, type);
-                break;
-            default:
-                Log.wtf(TAG, "invalid InvalidScopedAccess: " + type);
-        }
-    }
-
-    // Types for logValidScopedAccessRequest
-    public static final int SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED = 0;
-    public static final int SCOPED_DIRECTORY_ACCESS_GRANTED = 1;
-    public static final int SCOPED_DIRECTORY_ACCESS_DENIED = 2;
-    public static final int SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST = 3;
-    public static final int SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED = 4;
-
-    @IntDef(flag = true, value = {
-            SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED,
-            SCOPED_DIRECTORY_ACCESS_GRANTED,
-            SCOPED_DIRECTORY_ACCESS_DENIED,
-            SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST,
-            SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface ScopedAccessGrant {}
-
-    public static void logValidScopedAccessRequest(Activity activity, String directory,
-            @ScopedAccessGrant int type) {
-        int index = -1;
-        if (OpenExternalDirectoryActivity.DIRECTORY_ROOT.equals(directory)) {
-            index = -2;
-        } else {
-            for (int i = 0; i < STANDARD_DIRECTORIES.length; i++) {
-                if (STANDARD_DIRECTORIES[i].equals(directory)) {
-                    index = i;
-                    break;
-                }
-            }
-        }
-        final String packageName = activity.getCallingPackage();
-        switch (type) {
-            case SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED:
-                MetricsLogger.action(activity, MetricsEvent
-                        .ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED_BY_PACKAGE, packageName);
-                MetricsLogger.action(activity, MetricsEvent
-                        .ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED_BY_FOLDER, index);
-                break;
-            case SCOPED_DIRECTORY_ACCESS_GRANTED:
-                MetricsLogger.action(activity, MetricsEvent
-                        .ACTION_SCOPED_DIRECTORY_ACCESS_GRANTED_BY_PACKAGE, packageName);
-                MetricsLogger.action(activity, MetricsEvent
-                        .ACTION_SCOPED_DIRECTORY_ACCESS_GRANTED_BY_FOLDER, index);
-                break;
-            case SCOPED_DIRECTORY_ACCESS_DENIED:
-                MetricsLogger.action(activity, MetricsEvent
-                        .ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_BY_PACKAGE, packageName);
-                MetricsLogger.action(activity, MetricsEvent
-                        .ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_BY_FOLDER, index);
-                break;
-            case SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST:
-                MetricsLogger.action(activity, MetricsEvent
-                        .ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST_BY_PACKAGE, packageName);
-                MetricsLogger.action(activity, MetricsEvent
-                        .ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST_BY_FOLDER, index);
-                break;
-            case SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED:
-                MetricsLogger.action(activity, MetricsEvent
-                        .ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED_BY_PACKAGE, packageName);
-                MetricsLogger.action(activity, MetricsEvent
-                        .ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED_BY_FOLDER, index);
-                break;
-            default:
-                Log.wtf(TAG, "invalid ScopedAccessGrant: " + type);
-        }
-    }
-
     /**
      * Logs the action that was started by user.
      * @param context
diff --git a/src/com/android/documentsui/Model.java b/src/com/android/documentsui/Model.java
index 7b19e63..16284ea 100644
--- a/src/com/android/documentsui/Model.java
+++ b/src/com/android/documentsui/Model.java
@@ -17,8 +17,8 @@
 package com.android.documentsui;
 
 import static com.android.documentsui.base.DocumentInfo.getCursorString;
-import static com.android.documentsui.base.Shared.DEBUG;
-import static com.android.documentsui.base.Shared.VERBOSE;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.VERBOSE;
 
 import android.annotation.IntDef;
 import android.app.AuthenticationRequiredException;
diff --git a/src/com/android/documentsui/NavigationViewManager.java b/src/com/android/documentsui/NavigationViewManager.java
index e476224..fdaba38 100644
--- a/src/com/android/documentsui/NavigationViewManager.java
+++ b/src/com/android/documentsui/NavigationViewManager.java
@@ -16,7 +16,7 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.base.Shared.VERBOSE;
+import static com.android.documentsui.base.SharedMinimal.VERBOSE;
 
 import android.annotation.Nullable;
 import android.graphics.drawable.Drawable;
diff --git a/src/com/android/documentsui/OpenExternalDirectoryActivity.java b/src/com/android/documentsui/OpenExternalDirectoryActivity.java
deleted file mode 100644
index 74af224..0000000
--- a/src/com/android/documentsui/OpenExternalDirectoryActivity.java
+++ /dev/null
@@ -1,510 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui;
-
-import static android.os.Environment.isStandardDirectory;
-import static android.os.storage.StorageVolume.EXTRA_DIRECTORY_NAME;
-import static android.os.storage.StorageVolume.EXTRA_STORAGE_VOLUME;
-import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED;
-import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED;
-import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_DENIED;
-import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST;
-import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_ERROR;
-import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_GRANTED;
-import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS;
-import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY;
-import static com.android.documentsui.Metrics.logInvalidScopedAccessRequest;
-import static com.android.documentsui.Metrics.logValidScopedAccessRequest;
-import static com.android.documentsui.base.Shared.DEBUG;
-import static com.android.documentsui.prefs.LocalPreferences.PERMISSION_ASK_AGAIN;
-import static com.android.documentsui.prefs.LocalPreferences.PERMISSION_NEVER_ASK;
-import static com.android.documentsui.prefs.LocalPreferences.getScopedAccessPermissionStatus;
-import static com.android.documentsui.prefs.LocalPreferences.setScopedAccessPermissionStatus;
-
-import android.annotation.SuppressLint;
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.DialogFragment;
-import android.app.FragmentManager;
-import android.app.FragmentTransaction;
-import android.content.ContentProviderClient;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
-import android.content.Intent;
-import android.content.UriPermission;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.os.storage.StorageManager;
-import android.os.storage.StorageVolume;
-import android.os.storage.VolumeInfo;
-import android.provider.DocumentsContract;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.View;
-import android.widget.CheckBox;
-import android.widget.CompoundButton;
-import android.widget.CompoundButton.OnCheckedChangeListener;
-import android.widget.TextView;
-
-import com.android.documentsui.base.Providers;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-
-/**
- * Activity responsible for handling {@link Intent#ACTION_OPEN_EXTERNAL_DOCUMENT}.
- */
-public class OpenExternalDirectoryActivity extends Activity {
-    private static final String TAG = "OpenExternalDirectory";
-    private static final String FM_TAG = "open_external_directory";
-    private static final String EXTRA_FILE = "com.android.documentsui.FILE";
-    private static final String EXTRA_APP_LABEL = "com.android.documentsui.APP_LABEL";
-    private static final String EXTRA_VOLUME_LABEL = "com.android.documentsui.VOLUME_LABEL";
-    private static final String EXTRA_VOLUME_UUID = "com.android.documentsui.VOLUME_UUID";
-    private static final String EXTRA_IS_ROOT = "com.android.documentsui.IS_ROOT";
-    private static final String EXTRA_IS_PRIMARY = "com.android.documentsui.IS_PRIMARY";
-    // Special directory name representing the full volume
-    static final String DIRECTORY_ROOT = "ROOT_DIRECTORY";
-
-    private ContentProviderClient mExternalStorageClient;
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        if (savedInstanceState != null) {
-            if (DEBUG) Log.d(TAG, "activity.onCreateDialog(): reusing instance");
-            return;
-        }
-
-        final Intent intent = getIntent();
-        if (intent == null) {
-            if (DEBUG) Log.d(TAG, "missing intent");
-            logInvalidScopedAccessRequest(this, SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS);
-            setResult(RESULT_CANCELED);
-            finish();
-            return;
-        }
-        final Parcelable storageVolume = intent.getParcelableExtra(EXTRA_STORAGE_VOLUME);
-        if (!(storageVolume instanceof StorageVolume)) {
-            if (DEBUG)
-                Log.d(TAG, "extra " + EXTRA_STORAGE_VOLUME + " is not a StorageVolume: "
-                        + storageVolume);
-            logInvalidScopedAccessRequest(this, SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS);
-            setResult(RESULT_CANCELED);
-            finish();
-            return;
-        }
-        String directoryName = intent.getStringExtra(EXTRA_DIRECTORY_NAME );
-        if (directoryName == null) {
-            directoryName = DIRECTORY_ROOT;
-        }
-        final StorageVolume volume = (StorageVolume) storageVolume;
-        if (getScopedAccessPermissionStatus(getApplicationContext(), getCallingPackage(),
-                volume.getUuid(), directoryName) == PERMISSION_NEVER_ASK) {
-            logValidScopedAccessRequest(this, directoryName,
-                    SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED);
-            setResult(RESULT_CANCELED);
-            finish();
-            return;
-        }
-
-        final int userId = UserHandle.myUserId();
-        if (!showFragment(this, userId, volume, directoryName)) {
-            setResult(RESULT_CANCELED);
-            finish();
-            return;
-        }
-    }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        if (mExternalStorageClient != null) {
-            mExternalStorageClient.close();
-        }
-    }
-
-    /**
-     * Validates the given path (volume + directory) and display the appropriate dialog asking the
-     * user to grant access to it.
-     */
-    private static boolean showFragment(OpenExternalDirectoryActivity activity, int userId,
-            StorageVolume storageVolume, String directoryName) {
-        if (DEBUG)
-            Log.d(TAG, "showFragment() for volume " + storageVolume.dump() + ", directory "
-                    + directoryName + ", and user " + userId);
-        final boolean isRoot = directoryName.equals(DIRECTORY_ROOT);
-        final boolean isPrimary = storageVolume.isPrimary();
-
-        if (isRoot && isPrimary) {
-            if (DEBUG) Log.d(TAG, "root access requested on primary volume");
-            return false;
-        }
-
-        final File volumeRoot = storageVolume.getPathFile();
-        File file;
-        try {
-            file = isRoot ? volumeRoot : new File(volumeRoot, directoryName).getCanonicalFile();
-        } catch (IOException e) {
-            Log.e(TAG, "Could not get canonical file for volume " + storageVolume.dump()
-                    + " and directory " + directoryName);
-            logInvalidScopedAccessRequest(activity, SCOPED_DIRECTORY_ACCESS_ERROR);
-            return false;
-        }
-        final StorageManager sm =
-                (StorageManager) activity.getSystemService(Context.STORAGE_SERVICE);
-
-        final String root, directory;
-        if (isRoot) {
-            root = volumeRoot.getAbsolutePath();
-            directory = ".";
-        } else {
-            root = file.getParent();
-            directory = file.getName();
-            // Verify directory is valid.
-            if (TextUtils.isEmpty(directory) || !isStandardDirectory(directory)) {
-                if (DEBUG)
-                    Log.d(TAG, "Directory '" + directory + "' is not standard (full path: '"
-                            + file.getAbsolutePath() + "')");
-                logInvalidScopedAccessRequest(activity, SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY);
-                return false;
-            }
-        }
-
-        // Gets volume label and converted path.
-        String volumeLabel = null;
-        String volumeUuid = null;
-        final List<VolumeInfo> volumes = sm.getVolumes();
-        if (DEBUG) Log.d(TAG, "Number of volumes: " + volumes.size());
-        File internalRoot = null;
-        boolean found = true;
-        for (VolumeInfo volume : volumes) {
-            if (isRightVolume(volume, root, userId)) {
-                found = true;
-                internalRoot = volume.getInternalPathForUser(userId);
-                // Must convert path before calling getDocIdForFileCreateNewDir()
-                if (DEBUG) Log.d(TAG, "Converting " + root + " to " + internalRoot);
-                file = isRoot ? internalRoot : new File(internalRoot, directory);
-                volumeUuid = storageVolume.getUuid();
-                volumeLabel = sm.getBestVolumeDescription(volume);
-                if (TextUtils.isEmpty(volumeLabel)) {
-                    volumeLabel = storageVolume.getDescription(activity);
-                }
-                if (TextUtils.isEmpty(volumeLabel)) {
-                    volumeLabel = activity.getString(android.R.string.unknownName);
-                    Log.w(TAG, "No volume description  for " + volume + "; using " + volumeLabel);
-                }
-                break;
-            }
-        }
-        if (internalRoot == null) {
-            // Should not happen on normal circumstances, unless app crafted an invalid volume
-            // using reflection or the list of mounted volumes changed.
-            Log.e(TAG, "Didn't find right volume for '" + storageVolume.dump() + "' on " + volumes);
-            return false;
-        }
-
-        // Checks if the user has granted the permission already.
-        final Intent intent = getIntentForExistingPermission(activity, isRoot, internalRoot, file);
-        if (intent != null) {
-            logValidScopedAccessRequest(activity, directory,
-                    SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED);
-            activity.setResult(RESULT_OK, intent);
-            activity.finish();
-            return true;
-        }
-
-        if (!found) {
-            Log.e(TAG, "Could not get volume for " + file);
-            logInvalidScopedAccessRequest(activity, SCOPED_DIRECTORY_ACCESS_ERROR);
-            return false;
-        }
-
-        // Gets the package label.
-        final String appLabel = getAppLabel(activity);
-        if (appLabel == null) {
-            // Error already logged.
-            return false;
-        }
-
-        // Sets args that will be retrieve on onCreate()
-        final Bundle args = new Bundle();
-        args.putString(EXTRA_FILE, file.getAbsolutePath());
-        args.putString(EXTRA_VOLUME_LABEL, volumeLabel);
-        args.putString(EXTRA_VOLUME_UUID, volumeUuid);
-        args.putString(EXTRA_APP_LABEL, appLabel);
-        args.putBoolean(EXTRA_IS_ROOT, isRoot);
-        args.putBoolean(EXTRA_IS_PRIMARY, isPrimary);
-
-        final FragmentManager fm = activity.getFragmentManager();
-        final FragmentTransaction ft = fm.beginTransaction();
-        final OpenExternalDirectoryDialogFragment fragment =
-                new OpenExternalDirectoryDialogFragment();
-        fragment.setArguments(args);
-        ft.add(fragment, FM_TAG);
-        ft.commitAllowingStateLoss();
-
-        return true;
-    }
-
-    private static String getAppLabel(Activity activity) {
-        final String packageName = activity.getCallingPackage();
-        final PackageManager pm = activity.getPackageManager();
-        try {
-            return pm.getApplicationLabel(pm.getApplicationInfo(packageName, 0)).toString();
-        } catch (NameNotFoundException e) {
-            logInvalidScopedAccessRequest(activity, SCOPED_DIRECTORY_ACCESS_ERROR);
-            Log.w(TAG, "Could not get label for package " + packageName);
-            return null;
-        }
-    }
-
-    private static boolean isRightVolume(VolumeInfo volume, String root, int userId) {
-        final File userPath = volume.getPathForUser(userId);
-        final String path = userPath == null ? null : volume.getPathForUser(userId).getPath();
-        final boolean isMounted = volume.isMountedReadable();
-        if (DEBUG)
-            Log.d(TAG, "Volume: " + volume
-                    + "\n\tuserId: " + userId
-                    + "\n\tuserPath: " + userPath
-                    + "\n\troot: " + root
-                    + "\n\tpath: " + path
-                    + "\n\tisMounted: " + isMounted);
-
-        return isMounted && root.equals(path);
-    }
-
-    private static Uri getGrantedUriPermission(Context context, ContentProviderClient provider,
-            File file) {
-        // Calls ExternalStorageProvider to get the doc id for the file
-        final Bundle bundle;
-        try {
-            bundle = provider.call("getDocIdForFileCreateNewDir", file.getPath(), null);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Did not get doc id from External Storage provider for " + file, e);
-            logInvalidScopedAccessRequest(context, SCOPED_DIRECTORY_ACCESS_ERROR);
-            return null;
-        }
-        final String docId = bundle == null ? null : bundle.getString("DOC_ID");
-        if (docId == null) {
-            Log.e(TAG, "Did not get doc id from External Storage provider for " + file);
-            logInvalidScopedAccessRequest(context, SCOPED_DIRECTORY_ACCESS_ERROR);
-            return null;
-        }
-        if (DEBUG) Log.d(TAG, "doc id for " + file + ": " + docId);
-
-        final Uri uri = DocumentsContract.buildTreeDocumentUri(Providers.AUTHORITY_STORAGE, docId);
-        if (uri == null) {
-            Log.e(TAG, "Could not get URI for doc id " + docId);
-            return null;
-        }
-        if (DEBUG) Log.d(TAG, "URI for " + file + ": " + uri);
-        return uri;
-    }
-
-    private static Intent createGrantedUriPermissionsIntent(Context context,
-            ContentProviderClient provider, File file) {
-        final Uri uri = getGrantedUriPermission(context, provider, file);
-        return createGrantedUriPermissionsIntent(uri);
-    }
-
-    private static Intent createGrantedUriPermissionsIntent(Uri uri) {
-        final Intent intent = new Intent();
-        intent.setData(uri);
-        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
-                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
-                | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
-                | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
-        return intent;
-    }
-
-    private static Intent getIntentForExistingPermission(OpenExternalDirectoryActivity activity,
-            boolean isRoot, File root, File file) {
-        final String packageName = activity.getCallingPackage();
-        final ContentProviderClient storageClient = activity.getExternalStorageClient();
-        final Uri grantedUri = getGrantedUriPermission(activity, storageClient, file);
-        final Uri rootUri = root.equals(file) ? grantedUri
-                : getGrantedUriPermission(activity, storageClient, root);
-
-        if (DEBUG)
-            Log.d(TAG, "checking if " + packageName + " already has permission for " + grantedUri
-                    + " or its root (" + rootUri + ")");
-        final ActivityManager am =
-                (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
-        for (UriPermission uriPermission : am.getGrantedUriPermissions(packageName).getList()) {
-            final Uri uri = uriPermission.getUri();
-            if (uri == null) {
-                Log.w(TAG, "null URI for " + uriPermission);
-                continue;
-            }
-            if (uri.equals(grantedUri) || uri.equals(rootUri)) {
-                if (DEBUG) Log.d(TAG, packageName + " already has permission: " + uriPermission);
-                return createGrantedUriPermissionsIntent(grantedUri);
-            }
-        }
-        if (DEBUG) Log.d(TAG, packageName + " does not have permission for " + grantedUri);
-        return null;
-    }
-
-    public static class OpenExternalDirectoryDialogFragment extends DialogFragment {
-
-        private File mFile;
-        private String mVolumeUuid;
-        private String mVolumeLabel;
-        private String mAppLabel;
-        private boolean mIsRoot;
-        private boolean mIsPrimary;
-        private CheckBox mDontAskAgain;
-        private OpenExternalDirectoryActivity mActivity;
-        private AlertDialog mDialog;
-
-        @Override
-        public void onCreate(Bundle savedInstanceState) {
-            super.onCreate(savedInstanceState);
-            setRetainInstance(true);
-            final Bundle args = getArguments();
-            if (args != null) {
-                mFile = new File(args.getString(EXTRA_FILE));
-                mVolumeUuid = args.getString(EXTRA_VOLUME_UUID);
-                mVolumeLabel = args.getString(EXTRA_VOLUME_LABEL);
-                mAppLabel = args.getString(EXTRA_APP_LABEL);
-                mIsRoot = args.getBoolean(EXTRA_IS_ROOT);
-                mIsPrimary= args.getBoolean(EXTRA_IS_PRIMARY);
-            }
-            mActivity = (OpenExternalDirectoryActivity) getActivity();
-        }
-
-        @Override
-        public void onDestroyView() {
-            // Workaround for https://code.google.com/p/android/issues/detail?id=17423
-            if (mDialog != null && getRetainInstance()) {
-                mDialog.setDismissMessage(null);
-            }
-            super.onDestroyView();
-        }
-
-        @Override
-        public Dialog onCreateDialog(Bundle savedInstanceState) {
-            if (mDialog != null) {
-                if (DEBUG) Log.d(TAG, "fragment.onCreateDialog(): reusing dialog");
-                return mDialog;
-            }
-            if (mActivity != getActivity()) {
-                // Sanity check.
-                Log.wtf(TAG, "activity references don't match on onCreateDialog(): mActivity = "
-                        + mActivity + " , getActivity() = " + getActivity());
-                mActivity = (OpenExternalDirectoryActivity) getActivity();
-            }
-            final String directory = mFile.getName();
-            final String directoryName = mIsRoot ? DIRECTORY_ROOT : directory;
-            final Context context = mActivity.getApplicationContext();
-            final OnClickListener listener = new OnClickListener() {
-
-                @Override
-                public void onClick(DialogInterface dialog, int which) {
-                    Intent intent = null;
-                    if (which == DialogInterface.BUTTON_POSITIVE) {
-                        intent = createGrantedUriPermissionsIntent(mActivity,
-                                mActivity.getExternalStorageClient(), mFile);
-                    }
-                    if (which == DialogInterface.BUTTON_NEGATIVE || intent == null) {
-                        logValidScopedAccessRequest(mActivity, directoryName,
-                                SCOPED_DIRECTORY_ACCESS_DENIED);
-                        final boolean checked = mDontAskAgain.isChecked();
-                        if (checked) {
-                            logValidScopedAccessRequest(mActivity, directory,
-                                    SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST);
-                            setScopedAccessPermissionStatus(context, mActivity.getCallingPackage(),
-                                    mVolumeUuid, directoryName, PERMISSION_NEVER_ASK);
-                        } else {
-                            setScopedAccessPermissionStatus(context, mActivity.getCallingPackage(),
-                                    mVolumeUuid, directoryName, PERMISSION_ASK_AGAIN);
-                        }
-                        mActivity.setResult(RESULT_CANCELED);
-                    } else {
-                        logValidScopedAccessRequest(mActivity, directory,
-                                SCOPED_DIRECTORY_ACCESS_GRANTED);
-                        mActivity.setResult(RESULT_OK, intent);
-                    }
-                    mActivity.finish();
-                }
-            };
-
-            @SuppressLint("InflateParams")
-            // It's ok pass null ViewRoot on AlertDialogs.
-            final View view = View.inflate(mActivity, R.layout.dialog_open_scoped_directory, null);
-            final CharSequence message;
-            if (mIsRoot) {
-                message = TextUtils.expandTemplate(getText(
-                        R.string.open_external_dialog_root_request), mAppLabel, mVolumeLabel);
-            } else {
-                message = TextUtils.expandTemplate(
-                        getText(mIsPrimary ? R.string.open_external_dialog_request_primary_volume
-                                : R.string.open_external_dialog_request),
-                                mAppLabel, directory, mVolumeLabel);
-            }
-            final TextView messageField = (TextView) view.findViewById(R.id.message);
-            messageField.setText(message);
-            mDialog = new AlertDialog.Builder(mActivity, R.style.Theme_AppCompat_Light_Dialog_Alert)
-                    .setView(view)
-                    .setPositiveButton(R.string.allow, listener)
-                    .setNegativeButton(R.string.deny, listener)
-                    .create();
-
-            mDontAskAgain = (CheckBox) view.findViewById(R.id.do_not_ask_checkbox);
-            if (getScopedAccessPermissionStatus(context, mActivity.getCallingPackage(),
-                    mVolumeUuid, directoryName) == PERMISSION_ASK_AGAIN) {
-                mDontAskAgain.setVisibility(View.VISIBLE);
-                mDontAskAgain.setOnCheckedChangeListener(new OnCheckedChangeListener() {
-
-                    @Override
-                    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-                        mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(!isChecked);
-                    }
-                });
-            }
-
-            return mDialog;
-        }
-
-        @Override
-        public void onCancel(DialogInterface dialog) {
-            super.onCancel(dialog);
-            final Activity activity = getActivity();
-            logValidScopedAccessRequest(activity, mFile.getName(), SCOPED_DIRECTORY_ACCESS_DENIED);
-            activity.setResult(RESULT_CANCELED);
-            activity.finish();
-        }
-    }
-
-    private synchronized ContentProviderClient getExternalStorageClient() {
-        if (mExternalStorageClient == null) {
-            mExternalStorageClient =
-                    getContentResolver().acquireContentProviderClient(Providers.AUTHORITY_STORAGE);
-        }
-        return mExternalStorageClient;
-    }
-}
diff --git a/src/com/android/documentsui/PackageReceiver.java b/src/com/android/documentsui/PackageReceiver.java
index 5cb2827..e917369 100644
--- a/src/com/android/documentsui/PackageReceiver.java
+++ b/src/com/android/documentsui/PackageReceiver.java
@@ -23,10 +23,11 @@
 import android.net.Uri;
 
 import com.android.documentsui.picker.LastAccessedProvider;
-import com.android.documentsui.prefs.LocalPreferences;
+import com.android.documentsui.prefs.ScopedAccessLocalPreferences;
 
 /**
- * Clean up {@link LastAccessedProvider} and {@link LocalPreferences} when packages are removed.
+ * Clean up {@link LastAccessedProvider} and {@link ScopedAccessLocalPreferences} when packages
+ * are removed.
  */
 public class PackageReceiver extends BroadcastReceiver {
     @Override
@@ -44,7 +45,7 @@
                     null,
                     null);
             if (packageName != null) {
-                LocalPreferences.clearPackagePreferences(context, packageName);
+                ScopedAccessLocalPreferences.clearPackagePreferences(context, packageName);
             }
         } else if (Intent.ACTION_PACKAGE_DATA_CLEARED.equals(action)) {
             if (packageName != null) {
@@ -52,7 +53,7 @@
                         LastAccessedProvider.buildLastAccessed(packageName),
                         LastAccessedProvider.METHOD_PURGE_PACKAGE,
                         packageName, null);
-                LocalPreferences.clearPackagePreferences(context, packageName);
+                ScopedAccessLocalPreferences.clearPackagePreferences(context, packageName);
             }
         }
     }
diff --git a/src/com/android/documentsui/RecentsLoader.java b/src/com/android/documentsui/RecentsLoader.java
index 38a3cfa..bb0115d 100644
--- a/src/com/android/documentsui/RecentsLoader.java
+++ b/src/com/android/documentsui/RecentsLoader.java
@@ -16,8 +16,8 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.base.Shared.DEBUG;
-import static com.android.documentsui.base.Shared.TAG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.TAG;
 
 import android.app.ActivityManager;
 import android.content.AsyncTaskLoader;
diff --git a/src/com/android/documentsui/RefreshTask.java b/src/com/android/documentsui/RefreshTask.java
index fc9bc4d..5e0a1a1 100644
--- a/src/com/android/documentsui/RefreshTask.java
+++ b/src/com/android/documentsui/RefreshTask.java
@@ -16,7 +16,7 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.base.Shared.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
 
 import android.annotation.Nullable;
 import android.content.ContentProviderClient;
diff --git a/src/com/android/documentsui/RootsMonitor.java b/src/com/android/documentsui/RootsMonitor.java
index 82b3781..f1200ed 100644
--- a/src/com/android/documentsui/RootsMonitor.java
+++ b/src/com/android/documentsui/RootsMonitor.java
@@ -32,7 +32,6 @@
 import com.android.documentsui.dirlist.AnimationView;
 import com.android.documentsui.queries.SearchViewManager;
 import com.android.documentsui.roots.ProvidersAccess;
-import com.android.documentsui.selection.SelectionManager;
 
 import java.util.Collection;
 
@@ -57,7 +56,7 @@
         mReceiver = new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
-                new HandleRootsChangedTask<T>(
+                new HandleRootsChangedTask<>(
                         activity,
                         actions,
                         providers,
diff --git a/src/com/android/documentsui/ScopedAccessActivity.java b/src/com/android/documentsui/ScopedAccessActivity.java
new file mode 100644
index 0000000..eca9127
--- /dev/null
+++ b/src/com/android/documentsui/ScopedAccessActivity.java
@@ -0,0 +1,389 @@
+/*
+ * Copyright (C) 2016 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.documentsui;
+
+import static android.os.Environment.isStandardDirectory;
+import static android.os.storage.StorageVolume.EXTRA_DIRECTORY_NAME;
+import static android.os.storage.StorageVolume.EXTRA_STORAGE_VOLUME;
+
+import static com.android.documentsui.ScopedAccessMetrics.SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED;
+import static com.android.documentsui.ScopedAccessMetrics.SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED;
+import static com.android.documentsui.ScopedAccessMetrics.SCOPED_DIRECTORY_ACCESS_DENIED;
+import static com.android.documentsui.ScopedAccessMetrics.SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST;
+import static com.android.documentsui.ScopedAccessMetrics.SCOPED_DIRECTORY_ACCESS_ERROR;
+import static com.android.documentsui.ScopedAccessMetrics.SCOPED_DIRECTORY_ACCESS_GRANTED;
+import static com.android.documentsui.ScopedAccessMetrics.SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS;
+import static com.android.documentsui.ScopedAccessMetrics.SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY;
+import static com.android.documentsui.ScopedAccessMetrics.logInvalidScopedAccessRequest;
+import static com.android.documentsui.ScopedAccessMetrics.logValidScopedAccessRequest;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DIRECTORY_ROOT;
+import static com.android.documentsui.base.SharedMinimal.getUriPermission;
+import static com.android.documentsui.base.SharedMinimal.getInternalDirectoryName;
+import static com.android.documentsui.prefs.ScopedAccessLocalPreferences.PERMISSION_ASK_AGAIN;
+import static com.android.documentsui.prefs.ScopedAccessLocalPreferences.PERMISSION_NEVER_ASK;
+import static com.android.documentsui.prefs.ScopedAccessLocalPreferences.getScopedAccessPermissionStatus;
+import static com.android.documentsui.prefs.ScopedAccessLocalPreferences.setScopedAccessPermissionStatus;
+
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.app.GrantedUriPermission;
+import android.content.ContentProviderClient;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
+import android.content.UriPermission;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageVolume;
+import android.os.storage.VolumeInfo;
+import android.provider.DocumentsContract;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.TextView;
+
+import com.android.documentsui.base.Providers;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Activity responsible for handling {@link StorageVolume#createAccessIntent(String)}.
+ */
+public class ScopedAccessActivity extends Activity {
+    private static final String TAG = "ScopedAccessActivity";
+    private static final String FM_TAG = "open_external_directory";
+    private static final String EXTRA_FILE = "com.android.documentsui.FILE";
+    private static final String EXTRA_APP_LABEL = "com.android.documentsui.APP_LABEL";
+    private static final String EXTRA_VOLUME_LABEL = "com.android.documentsui.VOLUME_LABEL";
+    private static final String EXTRA_VOLUME_UUID = "com.android.documentsui.VOLUME_UUID";
+    private static final String EXTRA_IS_ROOT = "com.android.documentsui.IS_ROOT";
+    private static final String EXTRA_IS_PRIMARY = "com.android.documentsui.IS_PRIMARY";
+
+    private ContentProviderClient mExternalStorageClient;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        if (savedInstanceState != null) {
+            if (DEBUG) Log.d(TAG, "activity.onCreateDialog(): reusing instance");
+            return;
+        }
+
+        final Intent intent = getIntent();
+        if (intent == null) {
+            if (DEBUG) Log.d(TAG, "missing intent");
+            logInvalidScopedAccessRequest(this, SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS);
+            setResult(RESULT_CANCELED);
+            finish();
+            return;
+        }
+        final Parcelable storageVolume = intent.getParcelableExtra(EXTRA_STORAGE_VOLUME);
+        if (!(storageVolume instanceof StorageVolume)) {
+            if (DEBUG)
+                Log.d(TAG, "extra " + EXTRA_STORAGE_VOLUME + " is not a StorageVolume: "
+                        + storageVolume);
+            logInvalidScopedAccessRequest(this, SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS);
+            setResult(RESULT_CANCELED);
+            finish();
+            return;
+        }
+        String directoryName =
+                getInternalDirectoryName(intent.getStringExtra(EXTRA_DIRECTORY_NAME));
+        final StorageVolume volume = (StorageVolume) storageVolume;
+        final String uuid = volume.isPrimary() ? null : volume.getUuid();
+        if (getScopedAccessPermissionStatus(getApplicationContext(), getCallingPackage(),
+                uuid, directoryName) == PERMISSION_NEVER_ASK) {
+            logValidScopedAccessRequest(this, directoryName,
+                    SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED);
+            setResult(RESULT_CANCELED);
+            finish();
+            return;
+        }
+
+        final int userId = UserHandle.myUserId();
+        if (!showFragment(this, userId, volume, directoryName)) {
+            setResult(RESULT_CANCELED);
+            finish();
+            return;
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        if (mExternalStorageClient != null) {
+            mExternalStorageClient.close();
+        }
+    }
+
+    /**
+     * Validates the given path (volume + directory) and display the appropriate dialog asking the
+     * user to grant access to it.
+     */
+    private static boolean showFragment(ScopedAccessActivity activity, int userId,
+            StorageVolume storageVolume, String directoryName) {
+        return getUriPermission(activity,
+                activity.getExternalStorageClient(), storageVolume, directoryName, userId, true,
+                (file, volumeLabel, isRoot, isPrimary, grantedUri, rootUri) -> {
+                    // Checks if the user has granted the permission already.
+                    final Intent intent = getIntentForExistingPermission(activity,
+                            activity.getCallingPackage(), grantedUri, rootUri);
+                    if (intent != null) {
+                        logValidScopedAccessRequest(activity, isRoot ? "." : directoryName,
+                                SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED);
+                        activity.setResult(RESULT_OK, intent);
+                        activity.finish();
+                        return true;
+                    }
+
+                    // Gets the package label.
+                    final String appLabel = getAppLabel(activity);
+                    if (appLabel == null) {
+                        // Error already logged.
+                        return false;
+                    }
+
+                    // Sets args that will be retrieve on onCreate()
+                    final Bundle args = new Bundle();
+                    args.putString(EXTRA_FILE, file.getAbsolutePath());
+                    args.putString(EXTRA_VOLUME_LABEL, volumeLabel);
+                    args.putString(EXTRA_VOLUME_UUID, isPrimary ? null : storageVolume.getUuid());
+                    args.putString(EXTRA_APP_LABEL, appLabel);
+                    args.putBoolean(EXTRA_IS_ROOT, isRoot);
+                    args.putBoolean(EXTRA_IS_PRIMARY, isPrimary);
+
+                    final FragmentManager fm = activity.getFragmentManager();
+                    final FragmentTransaction ft = fm.beginTransaction();
+                    final ScopedAccessDialogFragment fragment = new ScopedAccessDialogFragment();
+                    fragment.setArguments(args);
+                    ft.add(fragment, FM_TAG);
+                    ft.commitAllowingStateLoss();
+
+                    return true;
+                });
+    }
+
+    private static String getAppLabel(Activity activity) {
+        final String packageName = activity.getCallingPackage();
+        final PackageManager pm = activity.getPackageManager();
+        try {
+            return pm.getApplicationLabel(pm.getApplicationInfo(packageName, 0)).toString();
+        } catch (NameNotFoundException e) {
+            logInvalidScopedAccessRequest(activity, SCOPED_DIRECTORY_ACCESS_ERROR);
+            Log.w(TAG, "Could not get label for package " + packageName);
+            return null;
+        }
+    }
+
+    private static Intent createGrantedUriPermissionsIntent(Context context,
+            ContentProviderClient provider, File file) {
+        final Uri uri = getUriPermission(context, provider, file);
+        return createGrantedUriPermissionsIntent(uri);
+    }
+
+    private static Intent createGrantedUriPermissionsIntent(Uri uri) {
+        final Intent intent = new Intent();
+        intent.setData(uri);
+        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
+                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+                | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
+                | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
+        return intent;
+    }
+
+    private static Intent getIntentForExistingPermission(Context context, String packageName,
+            Uri grantedUri, Uri rootUri) {
+        if (DEBUG) {
+            Log.d(TAG, "checking if " + packageName + " already has permission for " + grantedUri
+                    + " or its root (" + rootUri + ")");
+        }
+        final ActivityManager am = context.getSystemService(ActivityManager.class);
+        for (GrantedUriPermission uriPermission : am.getGrantedUriPermissions(packageName)
+                .getList()) {
+            final Uri uri = uriPermission.uri;
+            if (uri == null) {
+                Log.w(TAG, "null URI for " + uriPermission);
+                continue;
+            }
+            if (uri.equals(grantedUri) || uri.equals(rootUri)) {
+                if (DEBUG) Log.d(TAG, packageName + " already has permission: " + uriPermission);
+                return createGrantedUriPermissionsIntent(grantedUri);
+            }
+        }
+        if (DEBUG) Log.d(TAG, packageName + " does not have permission for " + grantedUri);
+        return null;
+    }
+
+    public static class ScopedAccessDialogFragment extends DialogFragment {
+
+        private File mFile;
+        private String mVolumeUuid;
+        private String mVolumeLabel;
+        private String mAppLabel;
+        private boolean mIsRoot;
+        private boolean mIsPrimary;
+        private CheckBox mDontAskAgain;
+        private ScopedAccessActivity mActivity;
+        private AlertDialog mDialog;
+
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            setRetainInstance(true);
+            final Bundle args = getArguments();
+            if (args != null) {
+                mFile = new File(args.getString(EXTRA_FILE));
+                mVolumeUuid = args.getString(EXTRA_VOLUME_UUID);
+                mVolumeLabel = args.getString(EXTRA_VOLUME_LABEL);
+                mAppLabel = args.getString(EXTRA_APP_LABEL);
+                mIsRoot = args.getBoolean(EXTRA_IS_ROOT);
+                mIsPrimary= args.getBoolean(EXTRA_IS_PRIMARY);
+            }
+            mActivity = (ScopedAccessActivity) getActivity();
+        }
+
+        @Override
+        public void onDestroyView() {
+            // Workaround for https://code.google.com/p/android/issues/detail?id=17423
+            if (mDialog != null && getRetainInstance()) {
+                mDialog.setDismissMessage(null);
+            }
+            super.onDestroyView();
+        }
+
+        @Override
+        public Dialog onCreateDialog(Bundle savedInstanceState) {
+            if (mDialog != null) {
+                if (DEBUG) Log.d(TAG, "fragment.onCreateDialog(): reusing dialog");
+                return mDialog;
+            }
+            if (mActivity != getActivity()) {
+                // Sanity check.
+                Log.wtf(TAG, "activity references don't match on onCreateDialog(): mActivity = "
+                        + mActivity + " , getActivity() = " + getActivity());
+                mActivity = (ScopedAccessActivity) getActivity();
+            }
+            final String directory = mFile.getName();
+            final String directoryName = mIsRoot ? DIRECTORY_ROOT : directory;
+            final Context context = mActivity.getApplicationContext();
+            final OnClickListener listener = new OnClickListener() {
+
+                @Override
+                public void onClick(DialogInterface dialog, int which) {
+                    Intent intent = null;
+                    if (which == DialogInterface.BUTTON_POSITIVE) {
+                        intent = createGrantedUriPermissionsIntent(mActivity,
+                                mActivity.getExternalStorageClient(), mFile);
+                    }
+                    if (which == DialogInterface.BUTTON_NEGATIVE || intent == null) {
+                        logValidScopedAccessRequest(mActivity, directoryName,
+                                SCOPED_DIRECTORY_ACCESS_DENIED);
+                        final boolean checked = mDontAskAgain.isChecked();
+                        if (checked) {
+                            logValidScopedAccessRequest(mActivity, directory,
+                                    SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST);
+                            setScopedAccessPermissionStatus(context, mActivity.getCallingPackage(),
+                                    mVolumeUuid, directoryName, PERMISSION_NEVER_ASK);
+                        } else {
+                            setScopedAccessPermissionStatus(context, mActivity.getCallingPackage(),
+                                    mVolumeUuid, directoryName, PERMISSION_ASK_AGAIN);
+                        }
+                        mActivity.setResult(RESULT_CANCELED);
+                    } else {
+                        logValidScopedAccessRequest(mActivity, directory,
+                                SCOPED_DIRECTORY_ACCESS_GRANTED);
+                        mActivity.setResult(RESULT_OK, intent);
+                    }
+                    mActivity.finish();
+                }
+            };
+
+            @SuppressLint("InflateParams")
+            // It's ok pass null ViewRoot on AlertDialogs.
+            final View view = View.inflate(mActivity, R.layout.dialog_open_scoped_directory, null);
+            final CharSequence message;
+            if (mIsRoot) {
+                message = TextUtils.expandTemplate(getText(
+                        R.string.open_external_dialog_root_request), mAppLabel, mVolumeLabel);
+            } else {
+                message = TextUtils.expandTemplate(
+                        getText(mIsPrimary ? R.string.open_external_dialog_request_primary_volume
+                                : R.string.open_external_dialog_request),
+                                mAppLabel, directory, mVolumeLabel);
+            }
+            final TextView messageField = (TextView) view.findViewById(R.id.message);
+            messageField.setText(message);
+            mDialog = new AlertDialog.Builder(mActivity, R.style.Theme_AppCompat_Light_Dialog_Alert)
+                    .setView(view)
+                    .setPositiveButton(R.string.allow, listener)
+                    .setNegativeButton(R.string.deny, listener)
+                    .create();
+
+            mDontAskAgain = (CheckBox) view.findViewById(R.id.do_not_ask_checkbox);
+            if (getScopedAccessPermissionStatus(context, mActivity.getCallingPackage(),
+                    mVolumeUuid, directoryName) == PERMISSION_ASK_AGAIN) {
+                mDontAskAgain.setVisibility(View.VISIBLE);
+                mDontAskAgain.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+
+                    @Override
+                    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                        mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(!isChecked);
+                    }
+                });
+            }
+
+            return mDialog;
+        }
+
+        @Override
+        public void onCancel(DialogInterface dialog) {
+            super.onCancel(dialog);
+            final Activity activity = getActivity();
+            logValidScopedAccessRequest(activity, mFile.getName(), SCOPED_DIRECTORY_ACCESS_DENIED);
+            activity.setResult(RESULT_CANCELED);
+            activity.finish();
+        }
+    }
+
+    private synchronized ContentProviderClient getExternalStorageClient() {
+        if (mExternalStorageClient == null) {
+            mExternalStorageClient =
+                    getContentResolver().acquireContentProviderClient(Providers.AUTHORITY_STORAGE);
+        }
+        return mExternalStorageClient;
+    }
+}
diff --git a/src/com/android/documentsui/ScopedAccessMetrics.java b/src/com/android/documentsui/ScopedAccessMetrics.java
new file mode 100644
index 0000000..ec23e59
--- /dev/null
+++ b/src/com/android/documentsui/ScopedAccessMetrics.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2016 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.documentsui;
+
+import static android.os.Environment.STANDARD_DIRECTORIES;
+
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DIRECTORY_ROOT;
+
+import android.annotation.IntDef;
+import android.annotation.StringDef;
+import android.app.Activity;
+import android.content.Context;
+import android.util.Log;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Methods for logging scoped directory access metrics.
+ */
+public final class ScopedAccessMetrics {
+    private static final String TAG = "ScopedAccessMetrics";
+
+    // Types for logInvalidScopedAccessRequest
+    public static final String SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS =
+            "docsui_scoped_directory_access_invalid_args";
+    public static final String SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY =
+            "docsui_scoped_directory_access_invalid_dir";
+    public static final String SCOPED_DIRECTORY_ACCESS_ERROR =
+            "docsui_scoped_directory_access_error";
+
+    @StringDef(value = {
+            SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS,
+            SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY,
+            SCOPED_DIRECTORY_ACCESS_ERROR
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface InvalidScopedAccess{}
+
+    public static void logInvalidScopedAccessRequest(Context context,
+            @InvalidScopedAccess String type) {
+        switch (type) {
+            case SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS:
+            case SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY:
+            case SCOPED_DIRECTORY_ACCESS_ERROR:
+                logCount(context, type);
+                break;
+            default:
+                Log.wtf(TAG, "invalid InvalidScopedAccess: " + type);
+        }
+    }
+
+    // Types for logValidScopedAccessRequest
+    public static final int SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED = 0;
+    public static final int SCOPED_DIRECTORY_ACCESS_GRANTED = 1;
+    public static final int SCOPED_DIRECTORY_ACCESS_DENIED = 2;
+    public static final int SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST = 3;
+    public static final int SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED = 4;
+
+    @IntDef(flag = true, value = {
+            SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED,
+            SCOPED_DIRECTORY_ACCESS_GRANTED,
+            SCOPED_DIRECTORY_ACCESS_DENIED,
+            SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST,
+            SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ScopedAccessGrant {}
+
+    public static void logValidScopedAccessRequest(Activity activity, String directory,
+            @ScopedAccessGrant int type) {
+        int index = -1;
+        if (DIRECTORY_ROOT.equals(directory)) {
+            index = -2;
+        } else {
+            for (int i = 0; i < STANDARD_DIRECTORIES.length; i++) {
+                if (STANDARD_DIRECTORIES[i].equals(directory)) {
+                    index = i;
+                    break;
+                }
+            }
+        }
+        final String packageName = activity.getCallingPackage();
+        switch (type) {
+            case SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED:
+                MetricsLogger.action(activity, MetricsEvent
+                        .ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED_BY_PACKAGE, packageName);
+                MetricsLogger.action(activity, MetricsEvent
+                        .ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED_BY_FOLDER, index);
+                break;
+            case SCOPED_DIRECTORY_ACCESS_GRANTED:
+                MetricsLogger.action(activity, MetricsEvent
+                        .ACTION_SCOPED_DIRECTORY_ACCESS_GRANTED_BY_PACKAGE, packageName);
+                MetricsLogger.action(activity, MetricsEvent
+                        .ACTION_SCOPED_DIRECTORY_ACCESS_GRANTED_BY_FOLDER, index);
+                break;
+            case SCOPED_DIRECTORY_ACCESS_DENIED:
+                MetricsLogger.action(activity, MetricsEvent
+                        .ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_BY_PACKAGE, packageName);
+                MetricsLogger.action(activity, MetricsEvent
+                        .ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_BY_FOLDER, index);
+                break;
+            case SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST:
+                MetricsLogger.action(activity, MetricsEvent
+                        .ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST_BY_PACKAGE, packageName);
+                MetricsLogger.action(activity, MetricsEvent
+                        .ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST_BY_FOLDER, index);
+                break;
+            case SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED:
+                MetricsLogger.action(activity, MetricsEvent
+                        .ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED_BY_PACKAGE, packageName);
+                MetricsLogger.action(activity, MetricsEvent
+                        .ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED_BY_FOLDER, index);
+                break;
+            default:
+                Log.wtf(TAG, "invalid ScopedAccessGrant: " + type);
+        }
+    }
+
+    /**
+     * Internal method for making a MetricsLogger.count call. Increments the given counter by 1.
+     *
+     * @param context
+     * @param name The counter to increment.
+     */
+    private static void logCount(Context context, String name) {
+        if (DEBUG) Log.d(TAG, name + ": " + 1);
+        MetricsLogger.count(context, name, 1);
+    }
+}
diff --git a/src/com/android/documentsui/ScopedAccessPackageReceiver.java b/src/com/android/documentsui/ScopedAccessPackageReceiver.java
new file mode 100644
index 0000000..995eedc
--- /dev/null
+++ b/src/com/android/documentsui/ScopedAccessPackageReceiver.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 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.documentsui;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+
+import com.android.documentsui.prefs.ScopedAccessLocalPreferences;
+
+/**
+ * Clean up {@link ScopedAccessLocalPreferences} when packages are removed.
+ */
+public class ScopedAccessPackageReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        final String action = intent.getAction();
+        final Uri data = intent.getData();
+        final String packageName = data == null ? null : data.getSchemeSpecificPart();
+
+        if (Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action)) {
+            if (packageName != null) {
+                ScopedAccessLocalPreferences.clearPackagePreferences(context, packageName);
+            }
+        } else if (Intent.ACTION_PACKAGE_DATA_CLEARED.equals(action)) {
+            if (packageName != null) {
+                ScopedAccessLocalPreferences.clearPackagePreferences(context, packageName);
+            }
+        }
+    }
+}
diff --git a/src/com/android/documentsui/ScopedAccessProvider.java b/src/com/android/documentsui/ScopedAccessProvider.java
new file mode 100644
index 0000000..787d21e
--- /dev/null
+++ b/src/com/android/documentsui/ScopedAccessProvider.java
@@ -0,0 +1,557 @@
+/*
+ * Copyright (C) 2018 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.documentsui;
+
+import static android.os.storage.StorageVolume.ScopedAccessProviderContract.COL_GRANTED;
+import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PACKAGES;
+import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PACKAGES_COLUMNS;
+import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PACKAGES_COL_PACKAGE;
+import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS;
+import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COLUMNS;
+import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COL_DIRECTORY;
+import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COL_GRANTED;
+import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COL_PACKAGE;
+import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COL_VOLUME_UUID;
+import static android.os.Environment.isStandardDirectory;
+
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.getExternalDirectoryName;
+import static com.android.documentsui.base.SharedMinimal.getInternalDirectoryName;
+import static com.android.documentsui.base.SharedMinimal.getUriPermission;
+import static com.android.documentsui.prefs.ScopedAccessLocalPreferences.PERMISSION_ASK_AGAIN;
+import static com.android.documentsui.prefs.ScopedAccessLocalPreferences.PERMISSION_GRANTED;
+import static com.android.documentsui.prefs.ScopedAccessLocalPreferences.PERMISSION_NEVER_ASK;
+import static com.android.documentsui.prefs.ScopedAccessLocalPreferences.clearScopedAccessPreferences;
+import static com.android.documentsui.prefs.ScopedAccessLocalPreferences.getAllPackages;
+import static com.android.documentsui.prefs.ScopedAccessLocalPreferences.getAllPermissions;
+import static com.android.documentsui.prefs.ScopedAccessLocalPreferences.setScopedAccessPermissionStatus;
+import static com.android.internal.util.Preconditions.checkArgument;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.GrantedUriPermission;
+import android.content.ContentProvider;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.UriMatcher;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.net.Uri;
+import android.os.Environment;
+import android.os.UserHandle;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageVolume;
+import android.provider.DocumentsContract;
+import android.util.ArraySet;
+import android.util.Log;
+
+import com.android.documentsui.base.Providers;
+import com.android.documentsui.prefs.ScopedAccessLocalPreferences.Permission;
+import com.android.internal.util.ArrayUtils;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+//TODO(b/72055774): update javadoc once implementation is finished
+/**
+ * Provider used to manage scoped access directory permissions.
+ *
+ * <p>It fetches data from 2 sources:
+ *
+ * <ul>
+ * <li>{@link com.android.documentsui.prefs.ScopedAccessLocalPreferences} for denied permissions.
+ * <li>{@link ActivityManager} for allowed permissions.
+ * </ul>
+ *
+ * <p>And returns the results in 2 tables:
+ *
+ * <ul>
+ * <li>{@link #TABLE_PACKAGES}: read-only table with the name of all packages
+ * (column ({@link android.os.storage.StorageVolume.ScopedAccessProviderContract#COL_PACKAGE}) that
+ * had a scoped access directory permission granted or denied.
+ * <li>{@link #TABLE_PERMISSIONS}: writable table with the name of all packages
+ * (column ({@link android.os.storage.StorageVolume.ScopedAccessProviderContract#COL_PACKAGE}) that
+ * had a scoped access directory
+ * (column ({@link android.os.storage.StorageVolume.ScopedAccessProviderContract#COL_DIRECTORY})
+ * permission for a volume (column
+ * {@link android.os.storage.StorageVolume.ScopedAccessProviderContract#COL_VOLUME_UUID}, which
+ * contains the volume UUID or {@code null} if it's the primary partition) granted or denied
+ * (column ({@link android.os.storage.StorageVolume.ScopedAccessProviderContract#COL_GRANTED}).
+ * </ul>
+ *
+ * <p><b>Note:</b> the {@code query()} methods return all entries; it does not support selection or
+ * projections.
+ */
+// TODO(b/72055774): add unit tests
+public class ScopedAccessProvider extends ContentProvider {
+
+    private static final String TAG = "ScopedAccessProvider";
+    private static final UriMatcher sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+
+    private static final int URI_PACKAGES = 1;
+    private static final int URI_PERMISSIONS = 2;
+
+    public static final String AUTHORITY = "com.android.documentsui.scopedAccess";
+
+    static {
+        sMatcher.addURI(AUTHORITY, TABLE_PACKAGES + "/*", URI_PACKAGES);
+        sMatcher.addURI(AUTHORITY, TABLE_PERMISSIONS + "/*", URI_PERMISSIONS);
+    }
+
+    @Override
+    public boolean onCreate() {
+        return true;
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
+        if (DEBUG) {
+            Log.v(TAG, "query(" + uri + "): proj=" + Arrays.toString(projection)
+                + ", sel=" + selection);
+        }
+        switch (sMatcher.match(uri)) {
+            case URI_PACKAGES:
+                return getPackagesCursor();
+            case URI_PERMISSIONS:
+                if (ArrayUtils.isEmpty(selectionArgs)) {
+                    throw new UnsupportedOperationException("selections cannot be empty");
+                }
+                // For simplicity, we only support one package (which is what Settings is passing).
+                if (selectionArgs.length > 1) {
+                    Log.w(TAG, "Using just first entry of " + Arrays.toString(selectionArgs));
+                }
+                return getPermissionsCursor(selectionArgs[0]);
+            default:
+                throw new UnsupportedOperationException("Unsupported Uri " + uri);
+        }
+    }
+
+    private Cursor getPackagesCursor() {
+        final Context context = getContext();
+
+        // First, get the packages that were denied
+        final Set<String> pkgs = getAllPackages(context);
+
+        // Second, query AM to get all packages that have a permission.
+        final ActivityManager am =
+                (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+
+        final List<GrantedUriPermission> amPkgs = am.getGrantedUriPermissions(null).getList();
+        if (!amPkgs.isEmpty()) {
+            amPkgs.forEach((perm) -> pkgs.add(perm.packageName));
+        }
+
+        if (ArrayUtils.isEmpty(pkgs)) {
+            if (DEBUG) Log.v(TAG, "getPackagesCursor(): nothing to do" );
+            return null;
+        }
+
+        if (DEBUG) {
+            Log.v(TAG, "getPackagesCursor(): denied=" + pkgs + ", granted=" + amPkgs);
+        }
+
+        // Finally, create the cursor
+        final MatrixCursor cursor = new MatrixCursor(TABLE_PACKAGES_COLUMNS, pkgs.size());
+        pkgs.forEach((pkg) -> cursor.addRow( new Object[] { pkg }));
+        return cursor;
+    }
+
+    // TODO(b/72055774): need to unit tests to handle scenarios where the root permission of
+    // a secondary volume mismatches a child permission (for example, child is allowed by root
+    // is denied).
+    private Cursor getPermissionsCursor(String packageName) {
+        final Context context = getContext();
+
+        // List of volumes that were granted by AM at the root level - in that case,
+        // we can ignored individual grants from AM or denials from our preferences
+        final Set<String> grantedVolumes = new ArraySet<>();
+
+        // List of directories (mapped by volume uuid) that were granted by AM so they can be
+        // ignored if also found on our preferences
+        final Map<String, Set<String>> grantedDirsByUuid = new HashMap<>();
+
+        // Cursor rows
+        final List<Object[]> permissions = new ArrayList<>();
+
+        // First, query AM to get all packages that have a permission.
+        final ActivityManager am =
+                (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+        final List<GrantedUriPermission> uriPermissions =
+                am.getGrantedUriPermissions(packageName).getList();
+        if (DEBUG) {
+            Log.v(TAG, "am returned =" + uriPermissions);
+        }
+        setGrantedPermissions(packageName, uriPermissions, permissions, grantedVolumes,
+                grantedDirsByUuid);
+
+        // Now  gets the packages that were denied
+        final List<Permission> rawPermissions = getAllPermissions(context);
+
+        if (DEBUG) {
+            Log.v(TAG, "rawPermissions: " + rawPermissions);
+        }
+
+        // Merge the permissions granted by AM with the denied permissions saved on our preferences.
+        for (Permission rawPermission : rawPermissions) {
+            if (!packageName.equals(rawPermission.pkg)) {
+                if (DEBUG) {
+                    Log.v(TAG,
+                            "ignoring " + rawPermission + " because package is not " + packageName);
+                }
+                continue;
+            }
+            if (rawPermission.status != PERMISSION_NEVER_ASK
+                    && rawPermission.status != PERMISSION_ASK_AGAIN) {
+                // We only care for status where the user denied a request.
+                if (DEBUG) {
+                    Log.v(TAG, "ignoring " + rawPermission + " because of its status");
+                }
+                continue;
+            }
+            if (grantedVolumes.contains(rawPermission.uuid)) {
+                if (DEBUG) {
+                    Log.v(TAG, "ignoring " + rawPermission + " because whole volume is granted");
+                }
+                continue;
+            }
+            final Set<String> grantedDirs = grantedDirsByUuid.get(rawPermission.uuid);
+            if (grantedDirs != null
+                    && grantedDirs.contains(rawPermission.directory)) {
+                Log.w(TAG, "ignoring " + rawPermission + " because it was granted already");
+                continue;
+            }
+            permissions.add(new Object[] {
+                    packageName, rawPermission.uuid,
+                    getExternalDirectoryName(rawPermission.directory), 0
+            });
+        }
+
+        if (DEBUG) {
+            Log.v(TAG, "total permissions: " + permissions.size());
+        }
+
+        // Then create the cursor
+        final MatrixCursor cursor = new MatrixCursor(TABLE_PERMISSIONS_COLUMNS, permissions.size());
+        permissions.forEach((row) -> cursor.addRow(row));
+        return cursor;
+    }
+
+    /**
+     * Converts the permissions returned by AM and add it to 3 buckets ({@code permissions},
+     * {@code grantedVolumes}, and {@code grantedDirsByUuid}).
+     *
+     * @param packageName name of package that the permissions were granted to.
+     * @param uriPermissions permissions returend by AM
+     * @param permissions list of permissions that can be converted to a {@link #TABLE_PERMISSIONS}
+     * row.
+     * @param grantedVolumes volume uuids that were granted full access.
+     * @param grantedDirsByUuid directories that were granted individual acces (key is volume uuid,
+     * value is list of directories).
+     */
+    private void setGrantedPermissions(String packageName, List<GrantedUriPermission> uriPermissions,
+            List<Object[]> permissions, Set<String> grantedVolumes,
+            Map<String, Set<String>> grantedDirsByUuid) {
+        final List<Permission> grantedPermissions = parseGrantedPermissions(uriPermissions);
+
+        for (Permission p : grantedPermissions) {
+            // First check if it's for the full volume
+            if (p.directory == null) {
+                if (p.uuid == null) {
+                    // Should never happen - the Scoped Directory Access API does not allow it.
+                    Log.w(TAG, "ignoring entry whose uuid and directory is null");
+                    continue;
+                }
+                grantedVolumes.add(p.uuid);
+            } else {
+                if (!ArrayUtils.contains(Environment.STANDARD_DIRECTORIES, p.directory)) {
+                    if (DEBUG) Log.v(TAG, "Ignoring non-standard directory on " + p);
+                    continue;
+                }
+
+                Set<String> dirs = grantedDirsByUuid.get(p.uuid);
+                if (dirs == null) {
+                    // Life would be so much easier if Android had MultiMaps...
+                    dirs = new HashSet<>(1);
+                    grantedDirsByUuid.put(p.uuid, dirs);
+                }
+                dirs.add(p.directory);
+            }
+        }
+
+        if (DEBUG) {
+            Log.v(TAG, "grantedVolumes=" + grantedVolumes
+                    + ", grantedDirectories=" + grantedDirsByUuid);
+        }
+        // Add granted permissions to full volumes.
+        grantedVolumes.forEach((uuid) -> permissions.add(new Object[] {
+                packageName, uuid, /* dir= */ null, 1
+        }));
+
+        // Add granted permissions to individual directories
+        grantedDirsByUuid.forEach((uuid, dirs) -> {
+            if (grantedVolumes.contains(uuid)) {
+                Log.w(TAG, "Ignoring individual grants to " + uuid + ": " + dirs);
+            } else {
+                dirs.forEach((dir) -> permissions.add(new Object[] {packageName, uuid, dir, 1}));
+            }
+        });
+    }
+
+    /**
+     * Converts the permissions returned by AM to our own format.
+     */
+    private List<Permission> parseGrantedPermissions(List<GrantedUriPermission> uriPermissions) {
+        final List<Permission> permissions = new ArrayList<>(uriPermissions.size());
+        // TODO(b/72055774): we should query AUTHORITY_STORAGE or call DocumentsContract instead of
+        // hardcoding the logic here.
+        for (GrantedUriPermission uriPermission : uriPermissions) {
+            final Uri uri = uriPermission.uri;
+            final String authority = uri.getAuthority();
+            if (!Providers.AUTHORITY_STORAGE.equals(authority)) {
+                Log.w(TAG, "Wrong authority on " + uri);
+                continue;
+            }
+            final List<String> pathSegments = uri.getPathSegments();
+            if (pathSegments.size() < 2) {
+                Log.w(TAG, "wrong path segments on " + uri);
+                continue;
+            }
+            // TODO(b/72055774): make PATH_TREE private again if not used anymore
+            if (!DocumentsContract.PATH_TREE.equals(pathSegments.get(0))) {
+                Log.w(TAG, "wrong path tree on " + uri);
+                continue;
+            }
+
+            final String[] uuidAndDir = pathSegments.get(1).split(":");
+            // uuid and dir are either UUID:DIR (for scoped directory) or UUID: (for full volume)
+            if (uuidAndDir.length != 1 && uuidAndDir.length != 2) {
+                Log.w(TAG, "could not parse uuid and directory on " + uri);
+                continue;
+            }
+            // TODO(b/72055774): to make things uglier, the Documents directory in the primary
+            // storage is a special case as its URI is "$ROOT_ID_HOME", instead of
+            // "${ROOT_ID_DEVICE}/Documents. This is another reason to move this logic to the
+            // provider...
+            final String uuid, dir;
+            if (Providers.ROOT_ID_HOME.equals(uuidAndDir[0])) {
+                uuid = null;
+                dir = Environment.DIRECTORY_DOCUMENTS;
+            } else {
+                uuid = Providers.ROOT_ID_DEVICE.equals(uuidAndDir[0])
+                        ? null // primary
+                        : uuidAndDir[0]; // external volume
+                dir = uuidAndDir.length == 1 ? null : uuidAndDir[1];
+            }
+            permissions
+                    .add(new Permission(uriPermission.packageName, uuid, dir, PERMISSION_GRANTED));
+        }
+        return permissions;
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        return null;
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        throw new UnsupportedOperationException("insert(): unsupported " + uri);
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        if (sMatcher.match(uri) != URI_PERMISSIONS) {
+            throw new UnsupportedOperationException("delete(): unsupported " + uri);
+        }
+
+        if (DEBUG) {
+            Log.v(TAG, "delete(" + uri + "): " + Arrays.toString(selectionArgs));
+        }
+
+        // TODO(b/72055774): add unit tests for invalid input
+        checkArgument(selectionArgs != null && selectionArgs.length == 1,
+                "Must have exactly 1 args: package_name" + Arrays.toString(selectionArgs));
+        final String packageName = selectionArgs[0];
+
+        // Delete just our preferences - the URI permissions is handled externally
+        // TODO(b/72055774): move logic to revoke permissions here, so AppStorageSettings does
+        // not need to call am.clearGrantedUriPermissions(packageName) (then we could remove that
+        // method from ActivityManager)
+        return clearScopedAccessPreferences(getContext(), packageName);
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        if (sMatcher.match(uri) != URI_PERMISSIONS) {
+            throw new UnsupportedOperationException("update(): unsupported " + uri);
+        }
+
+        if (DEBUG) {
+            Log.v(TAG, "update(" + uri + "): " + Arrays.toString(selectionArgs) + " = " + values);
+        }
+
+        // TODO(b/72055774): add unit tests for invalid input
+        checkArgument(selectionArgs != null && selectionArgs.length == 3,
+                "Must have exactly 3 args: package_name, (nullable) uuid, (nullable) directory: "
+                        + Arrays.toString(selectionArgs));
+        final String packageName = selectionArgs[0];
+        final String uuid = selectionArgs[1];
+        final String dir = selectionArgs[2];
+        final boolean granted = values.getAsBoolean(COL_GRANTED);
+
+        // First update the effective URI permission ...
+        if (!persistUriPermission(packageName, uuid, dir, granted)) {
+            // Failed - nothing left to do...
+            return 0;
+        }
+
+        // ...then our preferences.
+        setScopedAccessPermissionStatus(getContext(), packageName, uuid,
+                getInternalDirectoryName(dir), granted ? PERMISSION_GRANTED : PERMISSION_NEVER_ASK);
+        return 1;
+    }
+
+    /**
+     * Calls AM to persist a URI.
+     *
+     * @return whether the call succeeded.
+     */
+    private boolean persistUriPermission(String packageName, @Nullable String uuid,
+            @Nullable String directory, boolean granted) {
+        final Context context = getContext();
+
+        final ContentProviderClient storageClient = context.getContentResolver()
+                .acquireContentProviderClient(Providers.AUTHORITY_STORAGE);
+
+        final StorageManager sm = context.getSystemService(StorageManager.class);
+
+        StorageVolume volume = null;
+        if (uuid == null) {
+            if (directory == null) {
+                Log.w(TAG, "cannot grant full access to the primary volume");
+                return false;
+            }
+            volume = sm.getPrimaryStorageVolume();
+        } else {
+            for (StorageVolume candidate : sm.getVolumeList()) {
+                if (uuid.equals(candidate.getUuid())) {
+                    volume = candidate;
+                    break;
+                }
+            }
+            if (volume == null) {
+                Log.w(TAG, "didn't find volume for UUID=" + uuid);
+                return false;
+            }
+            if (directory != null && !isStandardDirectory(directory)) {
+                Log.w(TAG, "not a scoped directory: " + directory);
+                return false;
+            }
+        }
+
+        return getUriPermission(context, storageClient, volume, getInternalDirectoryName(directory),
+                UserHandle.getCallingUserId(), /* logMetrics= */ false,
+                (file, volumeLabel, isRoot, isPrimary, grantedUri, rootUri) -> {
+                    updatePermission(context, grantedUri, packageName, granted);
+                    return true;
+                });
+    }
+
+    private void updatePermission(Context context, Uri grantedUri, String toPackage,
+            boolean granted) {
+        final int persistFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION
+                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
+        final int grantFlags = persistFlags
+                | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
+                | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
+
+        final ContentResolver cr = context.getContentResolver();
+        if (granted) {
+            context.grantUriPermission(toPackage, grantedUri, grantFlags);
+            cr.takePersistableUriPermission(toPackage, grantedUri, persistFlags);
+        } else {
+            context.revokeUriPermission(toPackage, grantedUri, grantFlags);
+            // There's no need to release after revoking
+        }
+    }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        final String prefix = "  ";
+
+        final List<String> packages = new ArrayList<>();
+        pw.print("Packages: ");
+        try (Cursor cursor = getPackagesCursor()) {
+            if (cursor == null || cursor.getCount() == 0) {
+                pw.println("N/A");
+            } else {
+                pw.println(cursor.getCount());
+                while (cursor.moveToNext()) {
+                    final String pkg = cursor.getString(TABLE_PACKAGES_COL_PACKAGE);
+                    packages.add(pkg);
+                    pw.print(prefix);
+                    pw.println(pkg);
+                }
+            }
+        }
+
+        pw.print("Permissions: ");
+        for (int i = 0; i < packages.size(); i++) {
+            final String pkg = packages.get(i);
+            try (Cursor cursor = getPermissionsCursor(pkg)) {
+                if (cursor == null) {
+                    pw.println("N/A");
+                } else {
+                    pw.println(cursor.getCount());
+                    while (cursor.moveToNext()) {
+                        pw.print(prefix); pw.print(cursor.getString(TABLE_PERMISSIONS_COL_PACKAGE));
+                        pw.print('/');
+                        final String uuid = cursor.getString(TABLE_PERMISSIONS_COL_VOLUME_UUID);
+                        if (uuid != null) {
+                            pw.print(uuid); pw.print('>');
+                        }
+                        pw.print(cursor.getString(TABLE_PERMISSIONS_COL_DIRECTORY));
+                        pw.print(": "); pw.println(cursor.getInt(TABLE_PERMISSIONS_COL_GRANTED) == 1);
+                    }
+                }
+            }
+        }
+
+        pw.print("Raw permissions: ");
+        final List<Permission> rawPermissions = getAllPermissions(getContext());
+        if (rawPermissions.isEmpty()) {
+            pw.println("N/A");
+        } else {
+            final int size = rawPermissions.size();
+            pw.println(size);
+            for (int i = 0; i < size; i++) {
+                final Permission permission = rawPermissions.get(i);
+                pw.print(prefix); pw.println(permission);
+            }
+        }
+    }
+}
diff --git a/src/com/android/documentsui/SharedInputHandler.java b/src/com/android/documentsui/SharedInputHandler.java
index f3f2641..0c91341 100644
--- a/src/com/android/documentsui/SharedInputHandler.java
+++ b/src/com/android/documentsui/SharedInputHandler.java
@@ -15,7 +15,7 @@
  */
 package com.android.documentsui;
 
-import static com.android.documentsui.base.Shared.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
 
 import android.util.Log;
 import android.view.KeyEvent;
@@ -24,7 +24,7 @@
 import com.android.documentsui.base.Features;
 import com.android.documentsui.base.Procedure;
 import com.android.documentsui.dirlist.FocusHandler;
-import com.android.documentsui.selection.SelectionManager;
+import com.android.documentsui.selection.SelectionHelper;
 
 public class SharedInputHandler {
 
@@ -34,11 +34,11 @@
     private final Procedure mSearchCanceler;
     private final Procedure mDirPopper;
     private final Features mFeatures;
-    private final SelectionManager mSelectionMgr;
+    private final SelectionHelper mSelectionMgr;
 
     public SharedInputHandler(
             FocusHandler focusHandler,
-            SelectionManager selectionMgr,
+            SelectionHelper selectionMgr,
             Procedure searchCanceler,
             Procedure dirPopper,
             Features features) {
diff --git a/src/com/android/documentsui/ThumbnailLoader.java b/src/com/android/documentsui/ThumbnailLoader.java
index bb1c6fc..f5a93aa 100644
--- a/src/com/android/documentsui/ThumbnailLoader.java
+++ b/src/com/android/documentsui/ThumbnailLoader.java
@@ -15,15 +15,13 @@
  */
 package com.android.documentsui;
 
-import static com.android.documentsui.base.Shared.VERBOSE;
+import static com.android.documentsui.base.SharedMinimal.VERBOSE;
 
-import android.annotation.Nullable;
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Point;
-import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.CancellationSignal;
diff --git a/src/com/android/documentsui/archives/Archive.java b/src/com/android/documentsui/archives/Archive.java
index e3c81e3..14d703c 100644
--- a/src/com/android/documentsui/archives/Archive.java
+++ b/src/com/android/documentsui/archives/Archive.java
@@ -26,6 +26,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.storage.StorageManager;
 import android.provider.DocumentsContract;
+import android.provider.MetadataReader;
 import android.provider.DocumentsContract.Document;
 import android.support.annotation.Nullable;
 import android.system.ErrnoException;
@@ -281,7 +282,10 @@
         final String mimeType = getMimeTypeForEntry(entry);
         row.add(Document.COLUMN_MIME_TYPE, mimeType);
 
-        final int flags = mimeType.startsWith("image/") ? Document.FLAG_SUPPORTS_THUMBNAIL : 0;
+        int flags = mimeType.startsWith("image/") ? Document.FLAG_SUPPORTS_THUMBNAIL : 0;
+        if (MetadataReader.isSupportedMimeType(mimeType)) {
+            flags |= Document.FLAG_SUPPORTS_METADATA;
+        }
         row.add(Document.COLUMN_FLAGS, flags);
     }
 
diff --git a/src/com/android/documentsui/archives/ArchivesProvider.java b/src/com/android/documentsui/archives/ArchivesProvider.java
index 8f0e399..508a1aa 100644
--- a/src/com/android/documentsui/archives/ArchivesProvider.java
+++ b/src/com/android/documentsui/archives/ArchivesProvider.java
@@ -17,38 +17,34 @@
 package com.android.documentsui.archives;
 
 import android.content.ContentProviderClient;
-import android.content.ContentResolver;
-import android.content.Context;
 import android.content.res.AssetFileDescriptor;
-import android.content.res.Configuration;
-import android.database.ContentObserver;
 import android.database.Cursor;
-import android.database.MatrixCursor.RowBuilder;
 import android.database.MatrixCursor;
+import android.database.MatrixCursor.RowBuilder;
 import android.graphics.Point;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.ParcelFileDescriptor;
+import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
 import android.provider.DocumentsContract.Root;
-import android.provider.DocumentsContract;
 import android.provider.DocumentsProvider;
+import android.provider.MetadataReader;
 import android.support.annotation.Nullable;
 import android.util.Log;
 
 import com.android.documentsui.R;
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
 
-import java.io.Closeable;
-import java.io.File;
+import libcore.io.IoUtils;
+
 import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
-import java.util.concurrent.locks.Lock;
 
 /**
  * Provides basic implementation for creating, extracting and accessing
@@ -71,7 +67,7 @@
     };
 
     @GuardedBy("mArchives")
-    private final Map<Key, Loader> mArchives = new HashMap<Key, Loader>();
+    private final Map<Key, Loader> mArchives = new HashMap<>();
 
     @Override
     public Bundle call(String method, String arg, Bundle extras) {
@@ -153,6 +149,32 @@
     }
 
     @Override
+    public @Nullable Bundle getDocumentMetadata(String documentId)
+            throws FileNotFoundException {
+
+        final Archive archive = getLoaderOrThrow(documentId).get();
+        final String mimeType = archive.getDocumentType(documentId);
+
+        if (!MetadataReader.isSupportedMimeType(mimeType)) {
+            return null;
+        }
+
+        InputStream stream = null;
+        try {
+            stream = new ParcelFileDescriptor.AutoCloseInputStream(
+                    openDocument(documentId, "r", null));
+            final Bundle metadata = new Bundle();
+            MetadataReader.getMetadata(metadata, stream, mimeType, null);
+            return metadata;
+        } catch (IOException e) {
+            Log.e(TAG, "An error occurred retrieving the metadata.", e);
+            return null;
+        } finally {
+            IoUtils.closeQuietly(stream);
+        }
+    }
+
+    @Override
     public Cursor queryDocument(String documentId, @Nullable String[] projection)
             throws FileNotFoundException {
         final ArchiveId archiveId = ArchiveId.fromDocumentId(documentId);
diff --git a/src/com/android/documentsui/base/DebugHelper.java b/src/com/android/documentsui/base/DebugHelper.java
index f649dfb..201f725 100644
--- a/src/com/android/documentsui/base/DebugHelper.java
+++ b/src/com/android/documentsui/base/DebugHelper.java
@@ -16,6 +16,8 @@
 
 package com.android.documentsui.base;
 
+import static com.android.documentsui.base.SharedMinimal.VERBOSE;
+
 import android.util.Log;
 import android.util.Pair;
 
@@ -115,7 +117,7 @@
             mInjector.actions.setDebugMode(mDebugEnabled);
         }
 
-        if (Shared.VERBOSE) {
+        if (VERBOSE) {
             Log.v(TAG, "Debug mode " + (mDebugEnabled ? "on" : "off"));
         }
     }
diff --git a/src/com/android/documentsui/base/DocumentInfo.java b/src/com/android/documentsui/base/DocumentInfo.java
index 5d9a93c..a13ad98 100644
--- a/src/com/android/documentsui/base/DocumentInfo.java
+++ b/src/com/android/documentsui/base/DocumentInfo.java
@@ -223,6 +223,7 @@
                 + ", isDeleteSupported=" + isDeleteSupported()
                 + ", isCreateSupported=" + isCreateSupported()
                 + ", isRenameSupported=" + isRenameSupported()
+                + ", isMetadataSupported=" + isMetadataSupported()
                 + "} @ "
                 + derivedUri;
     }
@@ -231,30 +232,30 @@
         return (flags & Document.FLAG_DIR_SUPPORTS_CREATE) != 0;
     }
 
-    public boolean isDirectory() {
-        return Document.MIME_TYPE_DIR.equals(mimeType);
-    }
-
-    public boolean isWriteSupported() {
-        return (flags & Document.FLAG_SUPPORTS_WRITE) != 0;
-    }
-
     public boolean isDeleteSupported() {
         return (flags & Document.FLAG_SUPPORTS_DELETE) != 0;
     }
 
-    public boolean isRemoveSupported() {
-        return (flags & Document.FLAG_SUPPORTS_REMOVE) != 0;
+    public boolean isMetadataSupported() {
+        return (flags & Document.FLAG_SUPPORTS_METADATA) != 0;
     }
 
     public boolean isMoveSupported() {
         return (flags & Document.FLAG_SUPPORTS_MOVE) != 0;
     }
 
+    public boolean isRemoveSupported() {
+        return (flags & Document.FLAG_SUPPORTS_REMOVE) != 0;
+    }
+
     public boolean isRenameSupported() {
         return (flags & Document.FLAG_SUPPORTS_RENAME) != 0;
     }
 
+    public boolean isSettingsSupported() {
+        return (flags & Document.FLAG_SUPPORTS_SETTINGS) != 0;
+    }
+
     public boolean isThumbnailSupported() {
         return (flags & Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
     }
@@ -263,6 +264,14 @@
         return (flags & Document.FLAG_WEB_LINKABLE) != 0;
     }
 
+    public boolean isWriteSupported() {
+        return (flags & Document.FLAG_SUPPORTS_WRITE) != 0;
+    }
+
+    public boolean isDirectory() {
+        return Document.MIME_TYPE_DIR.equals(mimeType);
+    }
+
     public boolean isArchive() {
         return ArchivesProvider.isSupportedArchiveType(mimeType);
     }
@@ -284,10 +293,6 @@
         return (flags & Document.FLAG_VIRTUAL_DOCUMENT) != 0;
     }
 
-    public boolean isSettingsSupported() {
-        return (flags & Document.FLAG_SUPPORTS_SETTINGS) != 0;
-    }
-
     public boolean prefersSortByLastModified() {
         return (flags & Document.FLAG_DIR_PREFERS_LAST_MODIFIED) != 0;
     }
diff --git a/src/com/android/documentsui/base/DocumentStack.java b/src/com/android/documentsui/base/DocumentStack.java
index 9b0605c..f30c43a 100644
--- a/src/com/android/documentsui/base/DocumentStack.java
+++ b/src/com/android/documentsui/base/DocumentStack.java
@@ -16,7 +16,8 @@
 
 package com.android.documentsui.base;
 
-import static com.android.documentsui.base.Shared.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
+import static com.android.internal.util.Preconditions.checkArgument;
 
 import android.content.ContentResolver;
 import android.database.Cursor;
@@ -123,13 +124,10 @@
     }
 
     public void push(DocumentInfo info) {
-        boolean alreadyInStack = mList.contains(info);
-        assert (!alreadyInStack);
-        if (!alreadyInStack) {
-            if (DEBUG) Log.d(TAG, "Adding doc to stack: " + info);
-            mList.addLast(info);
-            mStackTouched = true;
-        }
+        checkArgument(!mList.contains(info));
+        if (DEBUG) Log.d(TAG, "Adding doc to stack: " + info);
+        mList.addLast(info);
+        mStackTouched = true;
     }
 
     public DocumentInfo pop() {
diff --git a/src/com/android/documentsui/base/DummyLookup.java b/src/com/android/documentsui/base/DummyLookup.java
new file mode 100644
index 0000000..11a6375
--- /dev/null
+++ b/src/com/android/documentsui/base/DummyLookup.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 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.documentsui.base;
+
+/**
+ * Lookup that always returns null.
+ */
+public final class DummyLookup<K, V> implements Lookup<K, V> {
+    @Override
+    public V lookup(K key) {
+        return null;
+    }
+}
diff --git a/src/com/android/documentsui/base/DurableUtils.java b/src/com/android/documentsui/base/DurableUtils.java
index 00f63df..227bdb1 100644
--- a/src/com/android/documentsui/base/DurableUtils.java
+++ b/src/com/android/documentsui/base/DurableUtils.java
@@ -16,7 +16,7 @@
 
 package com.android.documentsui.base;
 
-import static com.android.documentsui.base.Shared.TAG;
+import static com.android.documentsui.base.SharedMinimal.TAG;
 
 import android.os.BadParcelableException;
 import android.os.Parcel;
diff --git a/src/com/android/documentsui/base/Events.java b/src/com/android/documentsui/base/Events.java
index 67814df..c38f1a4 100644
--- a/src/com/android/documentsui/base/Events.java
+++ b/src/com/android/documentsui/base/Events.java
@@ -16,72 +16,83 @@
 
 package com.android.documentsui.base;
 
-import static com.android.documentsui.base.Shared.DEBUG;
-
 import android.graphics.Point;
-import android.support.v7.widget.RecyclerView;
-import android.util.Log;
-import android.util.Pools;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
-import android.view.View;
-
-import com.android.documentsui.dirlist.DocumentDetails;
-import com.android.documentsui.dirlist.DocumentHolder;
-
-import javax.annotation.Nullable;
 
 /**
  * Utility code for dealing with MotionEvents.
  */
 public final class Events {
 
-    /**
-     * Returns true if event was triggered by a mouse.
-     */
     public static boolean isMouseEvent(MotionEvent e) {
-        int toolType = e.getToolType(0);
-        return toolType == MotionEvent.TOOL_TYPE_MOUSE;
+        return e.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE;
     }
 
-    /**
-     * Returns true if event was triggered by a finger or stylus touch.
-     */
+    public static boolean isActionMove(MotionEvent e) {
+        return e.getActionMasked() == MotionEvent.ACTION_MOVE;
+    }
+
     public static boolean isActionDown(MotionEvent e) {
         return e.getActionMasked() == MotionEvent.ACTION_DOWN;
     }
 
-    /**
-     * Returns true if event was triggered by a finger or stylus touch.
-     */
     public static boolean isActionUp(MotionEvent e) {
         return e.getActionMasked() == MotionEvent.ACTION_UP;
     }
 
-    /**
-     * Returns true if the shift is pressed.
-     */
-    public boolean isShiftPressed(MotionEvent e) {
-        return hasShiftBit(e.getMetaState());
+    public static boolean isMultiPointerActionDown(MotionEvent e) {
+        return e.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN;
+    }
+
+    public static boolean isMultiPointerActionUp(MotionEvent e) {
+        return e.getActionMasked() == MotionEvent.ACTION_POINTER_UP;
+    }
+
+    public static boolean isActionCancel(MotionEvent e) {
+        return e.getActionMasked() == MotionEvent.ACTION_CANCEL;
+    }
+
+    public static boolean isPrimaryButtonPressed(MotionEvent e) {
+        return e.isButtonPressed(MotionEvent.BUTTON_PRIMARY);
+    }
+
+    public static boolean isSecondaryButtonPressed(MotionEvent e) {
+        return e.isButtonPressed(MotionEvent.BUTTON_SECONDARY);
+    }
+
+    public static boolean isTertiaryButtonPressed(MotionEvent e) {
+        return e.isButtonPressed(MotionEvent.BUTTON_TERTIARY);
+    }
+
+    public static boolean isCtrlKeyPressed(MotionEvent e) {
+        return hasBit(e.getMetaState(), KeyEvent.META_CTRL_ON);
+    }
+
+    public static boolean isAltKeyPressed(MotionEvent e) {
+        return hasBit(e.getMetaState(), KeyEvent.META_ALT_ON);
+    }
+
+    public static boolean isShiftKeyPressed(MotionEvent e) {
+        return hasBit(e.getMetaState(), KeyEvent.META_SHIFT_ON);
+    }
+
+    public static boolean isTouchpadScroll(MotionEvent e) {
+        // Touchpad inputs are treated as mouse inputs, and when scrolling, there are no buttons
+        // returned.
+        return isMouseEvent(e) && isActionMove(e) && e.getButtonState() == 0;
+    }
+
+    private static boolean hasBit(int metaState, int bit) {
+        return (metaState & bit) != 0;
+    }
+
+    public static Point getOrigin(MotionEvent e) {
+        return new Point((int) e.getX(), (int) e.getY());
     }
 
     /**
-     * Returns true if the event is a mouse drag event.
-     * @param e
-     * @return
-     */
-    public static boolean isMouseDragEvent(InputEvent e) {
-        return e.isMouseEvent()
-                && e.isActionMove()
-                && e.isPrimaryButtonPressed()
-                && e.isOverDragHotspot();
-    }
-
-    /**
-     * Whether or not the given keyCode represents a navigation keystroke (e.g. up, down, home).
-     *
-     * @param keyCode
-     * @return
+     * @return true if keyCode is a known navigation code (e.g. up, down, home).
      */
     public static boolean isNavigationKeyCode(int keyCode) {
         switch (keyCode) {
@@ -99,320 +110,14 @@
         }
     }
 
-
     /**
-     * Returns true if the "SHIFT" bit is set.
+     * Returns true if the event is a mouse drag event.
+     * @param e
+     * @return
      */
-    public static boolean hasShiftBit(int metaState) {
-        return (metaState & KeyEvent.META_SHIFT_ON) != 0;
-    }
-
-    public static boolean hasCtrlBit(int metaState) {
-        return (metaState & KeyEvent.META_CTRL_ON) != 0;
-    }
-
-    public static boolean hasAltBit(int metaState) {
-        return (metaState & KeyEvent.META_ALT_ON) != 0;
-    }
-
-    /**
-     * A facade over MotionEvent primarily designed to permit for unit testing
-     * of related code.
-     */
-    public interface InputEvent extends AutoCloseable {
-        boolean isMouseEvent();
-        boolean isPrimaryButtonPressed();
-        boolean isSecondaryButtonPressed();
-        boolean isTertiaryButtonPressed();
-        boolean isAltKeyDown();
-        boolean isShiftKeyDown();
-        boolean isCtrlKeyDown();
-
-        /** Returns true if the action is the initial press of a mouse or touch. */
-        boolean isActionDown();
-
-        /** Returns true if the action is the final release of a mouse or touch. */
-        boolean isActionUp();
-
-        /**
-         * Returns true when the action is the initial press of a non-primary (ex. second finger)
-         * pointer.
-         * See {@link MotionEvent#ACTION_POINTER_DOWN}.
-         */
-        boolean isMultiPointerActionDown();
-
-        /**
-         * Returns true when the action is the final of a non-primary (ex. second finger)
-         * pointer.
-         * * See {@link MotionEvent#ACTION_POINTER_UP}.
-         */
-        boolean isMultiPointerActionUp();
-
-        /** Returns true if the action is neither the initial nor the final release of a mouse
-         * or touch. */
-        boolean isActionMove();
-
-        /** Returns true if the action is cancel. */
-        boolean isActionCancel();
-
-        // Eliminate the checked Exception from Autoclosable.
-        @Override
-        public void close();
-
-        Point getOrigin();
-        float getX();
-        float getY();
-        float getRawX();
-        float getRawY();
-        int getPointerCount();
-
-        /** Returns true if there is an item under the finger/cursor. */
-        boolean isOverItem();
-
-        /**
-         * Returns true if there is a model backed item under the finger/cursor.
-         * Resulting calls on the event instance should never return a null
-         * DocumentDetails and DocumentDetails#hasModelId should always return true
-         */
-        boolean isOverModelItem();
-
-        /**
-         * Returns true if the event is over an area that can be dragged via touch.
-         * List items have a white area that is not draggable.
-         */
-        boolean isOverDragHotspot();
-
-        /**
-         * Returns true if the event is a two/three-finger scroll on touchpad.
-         */
-        boolean isTouchpadScroll();
-
-        /** Returns the adapter position of the item under the finger/cursor. */
-        int getItemPosition();
-
-        boolean isOverDocIcon();
-
-        /** Returns the DocumentDetails for the item under the event, or null. */
-        @Nullable DocumentDetails getDocumentDetails();
-    }
-
-    public static final class MotionInputEvent implements InputEvent {
-        private static final String TAG = "MotionInputEvent";
-
-        private static final int UNSET_POSITION = RecyclerView.NO_POSITION - 1;
-
-        private static final Pools.SimplePool<MotionInputEvent> sPool = new Pools.SimplePool<>(1);
-
-        private MotionEvent mEvent;
-        private @Nullable RecyclerView mRecView;
-
-        private int mPosition = UNSET_POSITION;
-        private @Nullable DocumentDetails mDocDetails;
-
-        private MotionInputEvent() {
-            if (DEBUG) Log.i(TAG, "Created a new instance.");
-        }
-
-        public static MotionInputEvent obtain(MotionEvent event, RecyclerView view) {
-            Shared.checkMainLoop();
-
-            MotionInputEvent instance = sPool.acquire();
-            instance = (instance != null ? instance : new MotionInputEvent());
-
-            instance.mEvent = event;
-            instance.mRecView = view;
-
-            return instance;
-        }
-
-        public void recycle() {
-            Shared.checkMainLoop();
-
-            mEvent = null;
-            mRecView = null;
-            mPosition = UNSET_POSITION;
-            mDocDetails = null;
-
-            boolean released = sPool.release(this);
-            // This assert is used to guarantee we won't generate too many instances that can't be
-            // held in the pool, which indicates our pool size is too small.
-            //
-            // Right now one instance is enough because we expect all instances are only used in
-            // main thread.
-            assert(released);
-        }
-
-        @Override
-        public void close() {
-            recycle();
-        }
-
-        @Override
-        public boolean isMouseEvent() {
-            return Events.isMouseEvent(mEvent);
-        }
-
-        @Override
-        public boolean isPrimaryButtonPressed() {
-            return mEvent.isButtonPressed(MotionEvent.BUTTON_PRIMARY);
-        }
-
-        @Override
-        public boolean isSecondaryButtonPressed() {
-            return mEvent.isButtonPressed(MotionEvent.BUTTON_SECONDARY);
-        }
-
-        @Override
-        public boolean isTertiaryButtonPressed() {
-            return mEvent.isButtonPressed(MotionEvent.BUTTON_TERTIARY);
-        }
-
-        @Override
-        public boolean isAltKeyDown() {
-            return Events.hasAltBit(mEvent.getMetaState());
-        }
-
-        @Override
-        public boolean isShiftKeyDown() {
-            return Events.hasShiftBit(mEvent.getMetaState());
-        }
-
-        @Override
-        public boolean isCtrlKeyDown() {
-            return Events.hasCtrlBit(mEvent.getMetaState());
-        }
-
-        @Override
-        public boolean isActionDown() {
-            return mEvent.getActionMasked() == MotionEvent.ACTION_DOWN;
-        }
-
-        @Override
-        public boolean isActionUp() {
-            return mEvent.getActionMasked() == MotionEvent.ACTION_UP;
-        }
-
-        @Override
-        public boolean isMultiPointerActionDown() {
-            return mEvent.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN;
-        }
-
-        @Override
-        public boolean isMultiPointerActionUp() {
-            return mEvent.getActionMasked() == MotionEvent.ACTION_POINTER_UP;
-        }
-
-
-        @Override
-        public boolean isActionMove() {
-            return mEvent.getActionMasked() == MotionEvent.ACTION_MOVE;
-        }
-
-        @Override
-        public boolean isActionCancel() {
-            return mEvent.getActionMasked() == MotionEvent.ACTION_CANCEL;
-        }
-
-        @Override
-        public Point getOrigin() {
-            return new Point((int) mEvent.getX(), (int) mEvent.getY());
-        }
-
-        @Override
-        public float getX() {
-            return mEvent.getX();
-        }
-
-        @Override
-        public float getY() {
-            return mEvent.getY();
-        }
-
-        @Override
-        public float getRawX() {
-            return mEvent.getRawX();
-        }
-
-        @Override
-        public float getRawY() {
-            return mEvent.getRawY();
-        }
-
-        @Override
-        public int getPointerCount() {
-            return mEvent.getPointerCount();
-        }
-
-        @Override
-        public boolean isTouchpadScroll() {
-            // Touchpad inputs are treated as mouse inputs, and when scrolling, there are no buttons
-            // returned.
-            return isMouseEvent() && isActionMove() && mEvent.getButtonState() == 0;
-        }
-
-        @Override
-        public boolean isOverDragHotspot() {
-            return isOverItem() && getDocumentDetails().isInDragHotspot(this);
-        }
-
-        @Override
-        public boolean isOverItem() {
-            return getItemPosition() != RecyclerView.NO_POSITION;
-        }
-
-        @Override
-        public boolean isOverDocIcon() {
-            return isOverItem() && getDocumentDetails().isOverDocIcon(this);
-        }
-
-        @Override
-        public boolean isOverModelItem() {
-            return isOverItem() && getDocumentDetails().hasModelId();
-        }
-
-        @Override
-        public int getItemPosition() {
-            if (mPosition == UNSET_POSITION) {
-                View child = mRecView.findChildViewUnder(mEvent.getX(), mEvent.getY());
-                mPosition = (child != null)
-                        ? mRecView.getChildAdapterPosition(child)
-                        : RecyclerView.NO_POSITION;
-            }
-            return mPosition;
-        }
-
-        @Override
-        public @Nullable DocumentDetails getDocumentDetails() {
-            if (mDocDetails == null) {
-                View childView = mRecView.findChildViewUnder(mEvent.getX(), mEvent.getY());
-                mDocDetails = (childView != null)
-                    ? (DocumentHolder) mRecView.getChildViewHolder(childView)
-                    : null;
-            }
-            if (isOverItem()) {
-                assert(mDocDetails != null);
-            }
-            return mDocDetails;
-        }
-
-        @Override
-        public String toString() {
-            return new StringBuilder()
-                    .append("MotionInputEvent {")
-                    .append("isMouseEvent=").append(isMouseEvent())
-                    .append(" isPrimaryButtonPressed=").append(isPrimaryButtonPressed())
-                    .append(" isSecondaryButtonPressed=").append(isSecondaryButtonPressed())
-                    .append(" isShiftKeyDown=").append(isShiftKeyDown())
-                    .append(" isAltKeyDown=").append(isAltKeyDown())
-                    .append(" action(decoded)=").append(
-                            MotionEvent.actionToString(mEvent.getActionMasked()))
-                    .append(" getOrigin=").append(getOrigin())
-                    .append(" isOverItem=").append(isOverItem())
-                    .append(" getItemPosition=").append(getItemPosition())
-                    .append(" getDocumentDetails=").append(getDocumentDetails())
-                    .append(" getPointerCount=").append(getPointerCount())
-                    .append("}")
-                    .toString();
-        }
+    public static boolean isMouseDragEvent(MotionEvent e) {
+        return isMouseEvent(e)
+                && isActionMove(e)
+                && isPrimaryButtonPressed(e);
     }
 }
diff --git a/src/com/android/documentsui/base/Features.java b/src/com/android/documentsui/base/Features.java
index 7a9936f..7714353 100644
--- a/src/com/android/documentsui/base/Features.java
+++ b/src/com/android/documentsui/base/Features.java
@@ -106,6 +106,10 @@
             return isEnabled(R.bool.feature_content_refresh);
         }
 
+        private boolean isFunPolicyEnabled() {
+            return !mUserMgr.hasUserRestriction(UserManager.DISALLOW_FUN);
+        }
+
         private boolean isDebugPolicyEnabled() {
             return !mUserMgr.hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES);
         }
@@ -120,15 +124,12 @@
             return isEnabled(R.bool.feature_folders_in_search_results);
         }
 
-        private boolean isFunPolicyEnabled() {
-            return !mUserMgr.hasUserRestriction(UserManager.DISALLOW_FUN);
-        }
-
         @Override
         public boolean isGestureScaleEnabled() {
             return isEnabled(R.bool.feature_gesture_scale);
         }
 
+        @Override
         public boolean isInspectorEnabled() {
             return isEnabled(R.bool.feature_inspector);
         }
diff --git a/src/com/android/documentsui/base/FilteringCursorWrapper.java b/src/com/android/documentsui/base/FilteringCursorWrapper.java
index 0288f4f..5ef7c7a 100644
--- a/src/com/android/documentsui/base/FilteringCursorWrapper.java
+++ b/src/com/android/documentsui/base/FilteringCursorWrapper.java
@@ -18,8 +18,8 @@
 
 import static com.android.documentsui.base.DocumentInfo.getCursorLong;
 import static com.android.documentsui.base.DocumentInfo.getCursorString;
-import static com.android.documentsui.base.Shared.DEBUG;
-import static com.android.documentsui.base.Shared.TAG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.TAG;
 
 import android.database.AbstractCursor;
 import android.database.Cursor;
diff --git a/src/com/android/documentsui/base/Lookup.java b/src/com/android/documentsui/base/Lookup.java
index 7057bfc..34253bb 100644
--- a/src/com/android/documentsui/base/Lookup.java
+++ b/src/com/android/documentsui/base/Lookup.java
@@ -21,8 +21,11 @@
 
 /**
  * A {@link Function}-like interface for looking up information.
+ *
+ * @param K input type (the "key").
+ * @param V output type (the "value").
  */
 @FunctionalInterface
-public interface Lookup<T, R> {
-    @Nullable R lookup(T key);
+public interface Lookup<K, V> {
+    @Nullable V lookup(K key);
 }
diff --git a/src/com/android/documentsui/base/RootInfo.java b/src/com/android/documentsui/base/RootInfo.java
index 3fe9a21..340d614 100644
--- a/src/com/android/documentsui/base/RootInfo.java
+++ b/src/com/android/documentsui/base/RootInfo.java
@@ -19,7 +19,7 @@
 import static com.android.documentsui.base.DocumentInfo.getCursorInt;
 import static com.android.documentsui.base.DocumentInfo.getCursorLong;
 import static com.android.documentsui.base.DocumentInfo.getCursorString;
-import static com.android.documentsui.base.Shared.VERBOSE;
+import static com.android.documentsui.base.SharedMinimal.VERBOSE;
 import static com.android.documentsui.base.Shared.compareToIgnoreCaseNullable;
 
 import android.annotation.IntDef;
@@ -54,7 +54,7 @@
 public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> {
 
     private static final String TAG = "RootInfo";
-    private static final int VERSION_INIT = 1;
+    // private static final int VERSION_INIT = 1; // Not used anymore
     private static final int VERSION_DROP_TYPE = 2;
 
     // The values of these constants determine the sort order of various roots in the RootsFragment.
diff --git a/src/com/android/documentsui/base/Shared.java b/src/com/android/documentsui/base/Shared.java
index d0ee2de..638b5f4 100644
--- a/src/com/android/documentsui/base/Shared.java
+++ b/src/com/android/documentsui/base/Shared.java
@@ -16,6 +16,8 @@
 
 package com.android.documentsui.base;
 
+import static com.android.documentsui.base.SharedMinimal.TAG;
+
 import android.annotation.PluralsRes;
 import android.app.Activity;
 import android.app.AlertDialog;
@@ -34,13 +36,12 @@
 import android.text.format.DateUtils;
 import android.text.format.Time;
 import android.util.Log;
+import android.view.View;
 import android.view.WindowManager;
 
 import com.android.documentsui.R;
 import com.android.documentsui.ui.MessageBuilder;
 
-import java.io.PrintWriter;
-import java.io.StringWriter;
 import java.text.Collator;
 import java.util.ArrayList;
 import java.util.List;
@@ -50,15 +51,16 @@
 /** @hide */
 public final class Shared {
 
-    public static final String TAG = "Documents";
-
-    public static final boolean DEBUG = Build.IS_DEBUGGABLE;
-    public static final boolean VERBOSE = DEBUG && Log.isLoggable(TAG, Log.VERBOSE);
-
     /** Intent action name to pick a copy destination. */
     public static final String ACTION_PICK_COPY_DESTINATION =
             "com.android.documentsui.PICK_COPY_DESTINATION";
 
+    // These values track values declared in MediaDocumentsProvider.
+    public static final String METADATA_KEY_AUDIO = "android.media.metadata.audio";
+    public static final String METADATA_KEY_VIDEO = "android.media.metadata.video";
+    public static final String METADATA_VIDEO_LATITUDE = "android.media.metadata.video:latitude";
+    public static final String METADATA_VIDEO_LONGITUTE = "android.media.metadata.video:longitude";
+
     /**
      * Extra boolean flag for {@link #ACTION_PICK_COPY_DESTINATION}, which
      * specifies if the destination directory needs to create new directory or not.
@@ -261,14 +263,43 @@
         }
     }
 
+    /**
+     * This method exists solely to smooth over the fact that two different types of
+     * views cannot be bound to the same id in different layouts. "What's this crazy-pants
+     * stuff?", you say? Here's an example:
+     *
+     * The main DocumentsUI view (aka "Files app") when running on a phone has a drop-down
+     * "breadcrumb" (file path representation) in both landscape and portrait orientation.
+     * Larger format devices, like a tablet, use a horizontal "Dir1 > Dir2 > Dir3" format
+     * breadcrumb in landscape layouts, but the regular drop-down breadcrumb in portrait
+     * mode.
+     *
+     * Our initial inclination was to give each of those views the same ID (as they both
+     * implement the same "Breadcrumb" interface). But at runtime, when rotating a device
+     * from one orientation to the other, deeeeeeep within the UI toolkit a exception
+     * would happen, because one view instance (drop-down) was being inflated in place of
+     * another (horizontal). I'm writing this code comment significantly after the face,
+     * so I don't recall all of the details, but it had to do with View type-checking the
+     * Parcelable state in onRestore, or something like that. Either way, this isn't
+     * allowed (my patch to fix this was rejected).
+     *
+     * To work around this we have this cute little method that accepts multiple
+     * resource IDs, and along w/ type inference finds our view, no matter which
+     * id it is wearing, and returns it.
+     */
+    @SuppressWarnings("TypeParameterUnusedInFormals")
     public static @Nullable <T> T findView(Activity activity, int... resources) {
         for (int id : resources) {
             @SuppressWarnings("unchecked")
-            T r = (T) activity.findViewById(id);
-            if (r != null) {
-                return r;
+            View view = activity.findViewById(id);
+            if (view != null) {
+                return (T) view;
             }
         }
         return null;
     }
+
+    private Shared() {
+        throw new UnsupportedOperationException("provides static fields only");
+    }
 }
diff --git a/src/com/android/documentsui/base/SharedMinimal.java b/src/com/android/documentsui/base/SharedMinimal.java
new file mode 100644
index 0000000..880ee49
--- /dev/null
+++ b/src/com/android/documentsui/base/SharedMinimal.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2018 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.documentsui.base;
+
+import static android.os.Environment.isStandardDirectory;
+
+import static com.android.documentsui.ScopedAccessMetrics.SCOPED_DIRECTORY_ACCESS_ERROR;
+import static com.android.documentsui.ScopedAccessMetrics.SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY;
+import static com.android.documentsui.ScopedAccessMetrics.logInvalidScopedAccessRequest;
+
+import android.annotation.Nullable;
+import android.content.ContentProviderClient;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageVolume;
+import android.os.storage.VolumeInfo;
+import android.provider.DocumentsContract;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Contains the minimum number of utilities (contants, helpers, etc...) that can be used by both the
+ * main package and the minimal APK that's used by Android TV (and other devices).
+ *
+ * <p>In other words, it should not include any external dependency that would increase the APK
+ * size.
+ */
+public final class SharedMinimal {
+
+    public static final String TAG = "Documents";
+
+    public static final boolean DEBUG = Build.IS_DEBUGGABLE;
+    public static final boolean VERBOSE = DEBUG && Log.isLoggable(TAG, Log.VERBOSE);
+
+    /**
+     * Special directory name representing the full volume of a scoped directory request.
+     */
+    public static final String DIRECTORY_ROOT = "ROOT_DIRECTORY";
+
+    /**
+     * Callback for {@link SharedMinimal#getUriPermission(Context, ContentProviderClient,
+     * StorageVolume, String, int, boolean, GetUriPermissionCallback)}.
+     */
+    public static interface GetUriPermissionCallback {
+
+        /**
+         * Evaluates the result of the request.
+         *
+         * @param file the path of the requested URI.
+         * @param volumeLabel user-friendly label of the volume.
+         * @param isRoot whether the requested directory is the root directory.
+         * @param isPrimary whether the requested volume is the primary storage volume.
+         * @param requestedUri the requested URI.
+         * @param rootUri the URI for the volume's root directory.
+         * @return whethe the result was sucessfully.
+         */
+        boolean onResult(File file, String volumeLabel, boolean isRoot, boolean isPrimary,
+                Uri requestedUri, Uri rootUri);
+    }
+
+    /**
+     * Gets the name of a directory name in the format that's used internally by the app
+     * (i.e., mapping {@code null} to {@link #DIRECTORY_ROOT});
+     * if necessary.
+     */
+    public static String getInternalDirectoryName(@Nullable String name) {
+        return name == null ? DIRECTORY_ROOT : name;
+    }
+
+    /**
+     * Gets the name of a directory name in the format that is used externally
+     * (i.e., mapping {@link #DIRECTORY_ROOT} to {@code null} if necessary);
+     */
+    @Nullable
+    public static String getExternalDirectoryName(String name) {
+        return name.equals(DIRECTORY_ROOT) ? null : name;
+    }
+
+    /**
+     * Gets the URI permission for the given volume and directory.
+     *
+     * @param context caller's context.
+     * @param storageClient storage provider client.
+     * @param storageVolume volume.
+     * @param directoryName directory name, or {@link #DIRECTORY_ROOT} for full volume.
+     * @param userId caller's user handle.
+     * @param logMetrics whether intermediate errors should be logged.
+     * @param callback callback that receives the results.
+     *
+     * @return whether the call was succesfull or not.
+     */
+    public static boolean getUriPermission(Context context,
+            ContentProviderClient storageClient, StorageVolume storageVolume,
+            String directoryName, int userId, boolean logMetrics,
+            GetUriPermissionCallback callback) {
+        if (DEBUG) {
+            Log.d(TAG, "getUriPermission() for volume " + storageVolume.dump() + ", directory "
+                    + directoryName + ", and user " + userId);
+        }
+        final boolean isRoot = directoryName.equals(DIRECTORY_ROOT);
+        final boolean isPrimary = storageVolume.isPrimary();
+
+        if (isRoot && isPrimary) {
+            if (DEBUG) Log.d(TAG, "root access requested on primary volume");
+            return false;
+        }
+
+        final File volumeRoot = storageVolume.getPathFile();
+        File file;
+        try {
+            file = isRoot ? volumeRoot : new File(volumeRoot, directoryName).getCanonicalFile();
+        } catch (IOException e) {
+            Log.e(TAG, "Could not get canonical file for volume " + storageVolume.dump()
+                    + " and directory " + directoryName);
+            if (logMetrics) logInvalidScopedAccessRequest(context, SCOPED_DIRECTORY_ACCESS_ERROR);
+            return false;
+        }
+        final StorageManager sm = context.getSystemService(StorageManager.class);
+
+        final String root, directory;
+        if (isRoot) {
+            root = volumeRoot.getAbsolutePath();
+            directory = ".";
+        } else {
+            root = file.getParent();
+            directory = file.getName();
+            // Verify directory is valid.
+            if (TextUtils.isEmpty(directory) || !isStandardDirectory(directory)) {
+                if (DEBUG) {
+                    Log.d(TAG, "Directory '" + directory + "' is not standard (full path: '"
+                            + file.getAbsolutePath() + "')");
+                }
+                if (logMetrics) {
+                    logInvalidScopedAccessRequest(context,
+                            SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY);
+                }
+                return false;
+            }
+        }
+
+        // Gets volume label and converted path.
+        String volumeLabel = null;
+        final List<VolumeInfo> volumes = sm.getVolumes();
+        if (DEBUG) Log.d(TAG, "Number of volumes: " + volumes.size());
+        File internalRoot = null;
+        for (VolumeInfo volume : volumes) {
+            if (isRightVolume(volume, root, userId)) {
+                internalRoot = volume.getInternalPathForUser(userId);
+                // Must convert path before calling getDocIdForFileCreateNewDir()
+                if (DEBUG) Log.d(TAG, "Converting " + root + " to " + internalRoot);
+                file = isRoot ? internalRoot : new File(internalRoot, directory);
+                volumeLabel = sm.getBestVolumeDescription(volume);
+                if (TextUtils.isEmpty(volumeLabel)) {
+                    volumeLabel = storageVolume.getDescription(context);
+                }
+                if (TextUtils.isEmpty(volumeLabel)) {
+                    volumeLabel = context.getString(android.R.string.unknownName);
+                    Log.w(TAG, "No volume description  for " + volume + "; using " + volumeLabel);
+                }
+                break;
+            }
+        }
+        if (internalRoot == null) {
+            // Should not happen on normal circumstances, unless app crafted an invalid volume
+            // using reflection or the list of mounted volumes changed.
+            Log.e(TAG, "Didn't find right volume for '" + storageVolume.dump() + "' on " + volumes);
+            return false;
+        }
+
+        final Uri requestedUri = getUriPermission(context, storageClient, file);
+        final Uri rootUri = internalRoot.equals(file) ? requestedUri
+                : getUriPermission(context, storageClient, internalRoot);
+
+        return callback.onResult(file, volumeLabel, isRoot, isPrimary, requestedUri, rootUri);
+    }
+
+    /**
+     * Creates an URI permission for the given file.
+     */
+    public static Uri getUriPermission(Context context, ContentProviderClient storageProvider,
+            File file) {
+        // Calls ExternalStorageProvider to get the doc id for the file
+        final Bundle bundle;
+        try {
+            bundle = storageProvider.call("getDocIdForFileCreateNewDir", file.getPath(), null);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Did not get doc id from External Storage provider for " + file, e);
+            logInvalidScopedAccessRequest(context, SCOPED_DIRECTORY_ACCESS_ERROR);
+            return null;
+        }
+        final String docId = bundle == null ? null : bundle.getString("DOC_ID");
+        if (docId == null) {
+            Log.e(TAG, "Did not get doc id from External Storage provider for " + file);
+            logInvalidScopedAccessRequest(context, SCOPED_DIRECTORY_ACCESS_ERROR);
+            return null;
+        }
+        if (DEBUG) Log.d(TAG, "doc id for " + file + ": " + docId);
+
+        final Uri uri = DocumentsContract.buildTreeDocumentUri(Providers.AUTHORITY_STORAGE, docId);
+        if (uri == null) {
+            Log.e(TAG, "Could not get URI for doc id " + docId);
+            return null;
+        }
+        if (DEBUG) Log.d(TAG, "URI for " + file + ": " + uri);
+        return uri;
+    }
+
+    private static boolean isRightVolume(VolumeInfo volume, String root, int userId) {
+        final File userPath = volume.getPathForUser(userId);
+        final String path = userPath == null ? null : volume.getPathForUser(userId).getPath();
+        final boolean isMounted = volume.isMountedReadable();
+        if (DEBUG)
+            Log.d(TAG, "Volume: " + volume
+                    + "\n\tuserId: " + userId
+                    + "\n\tuserPath: " + userPath
+                    + "\n\troot: " + root
+                    + "\n\tpath: " + path
+                    + "\n\tisMounted: " + isMounted);
+
+        return isMounted && root.equals(path);
+    }
+
+    private SharedMinimal() {
+        throw new UnsupportedOperationException("provides static fields only");
+    }
+}
diff --git a/src/com/android/documentsui/base/State.java b/src/com/android/documentsui/base/State.java
index fbfd385..13a28ef 100644
--- a/src/com/android/documentsui/base/State.java
+++ b/src/com/android/documentsui/base/State.java
@@ -20,7 +20,6 @@
 import android.content.Intent;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.provider.DocumentsContract;
 import android.util.SparseArray;
 
 import com.android.documentsui.services.FileOperationService;
@@ -30,6 +29,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 
@@ -139,7 +139,7 @@
     public String toString() {
         return "State{"
                 + "action=" + action
-                + ", acceptMimes=" + acceptMimes
+                + ", acceptMimes=" + Arrays.toString(acceptMimes)
                 + ", allowMultiple=" + allowMultiple
                 + ", localOnly=" + localOnly
                 + ", showDeviceStorageOption=" + showDeviceStorageOption
diff --git a/src/com/android/documentsui/dirlist/DirectoryAddonsAdapter.java b/src/com/android/documentsui/dirlist/DirectoryAddonsAdapter.java
index 6bf0d8b..2af3850 100644
--- a/src/com/android/documentsui/dirlist/DirectoryAddonsAdapter.java
+++ b/src/com/android/documentsui/dirlist/DirectoryAddonsAdapter.java
@@ -21,10 +21,10 @@
 import android.view.ViewGroup;
 
 import com.android.documentsui.Model;
+import com.android.documentsui.Model.Update;
 import com.android.documentsui.base.EventListener;
 import com.android.documentsui.dirlist.Message.HeaderMessage;
 import com.android.documentsui.dirlist.Message.InflateMessage;
-import com.android.documentsui.Model.Update;
 
 import java.util.List;
 
@@ -238,8 +238,8 @@
     }
 
     @Override
-    public List<String> getModelIds() {
-        return mDelegate.getModelIds();
+    public List<String> getStableIds() {
+        return mDelegate.getStableIds();
     }
 
     @Override
@@ -248,7 +248,7 @@
     }
 
     @Override
-    public String getModelId(int p) {
+    public String getStableId(int p) {
         if (p == mBreakPosition) {
             return null;
         }
@@ -261,12 +261,12 @@
             return null;
         }
 
-        return mDelegate.getModelId(toDelegatePosition(p));
+        return mDelegate.getStableId(toDelegatePosition(p));
     }
 
     @Override
-    public void onItemSelectionChanged(String id) {
-        mDelegate.onItemSelectionChanged(id);
+    public int getPosition(String id) {
+        return toViewPosition(mDelegate.getPosition(id));
     }
 
     // Listener we add to our delegate. This allows us to relay events published
diff --git a/src/com/android/documentsui/dirlist/DirectoryFragment.java b/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 9096f63..e48cf9d 100644
--- a/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -16,10 +16,9 @@
 
 package com.android.documentsui.dirlist;
 
-import static com.android.documentsui.base.DocumentInfo.getCursorInt;
 import static com.android.documentsui.base.DocumentInfo.getCursorString;
-import static com.android.documentsui.base.Shared.DEBUG;
-import static com.android.documentsui.base.Shared.VERBOSE;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.VERBOSE;
 import static com.android.documentsui.base.State.MODE_GRID;
 import static com.android.documentsui.base.State.MODE_LIST;
 
@@ -41,6 +40,7 @@
 import android.os.Parcelable;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
+import android.support.annotation.Nullable;
 import android.support.v4.widget.SwipeRefreshLayout;
 import android.support.v7.widget.GridLayoutManager;
 import android.support.v7.widget.GridLayoutManager.SpanSizeLookup;
@@ -50,7 +50,7 @@
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.ContextMenu;
-import android.view.HapticFeedbackConstants;
+import android.view.GestureDetector;
 import android.view.LayoutInflater;
 import android.view.MenuInflater;
 import android.view.MenuItem;
@@ -63,7 +63,6 @@
 import com.android.documentsui.ActionModeController;
 import com.android.documentsui.BaseActivity;
 import com.android.documentsui.BaseActivity.RetainedState;
-import com.android.documentsui.DirectoryReloadLock;
 import com.android.documentsui.DocumentsApplication;
 import com.android.documentsui.FocusManager;
 import com.android.documentsui.Injector;
@@ -76,10 +75,7 @@
 import com.android.documentsui.base.DocumentFilters;
 import com.android.documentsui.base.DocumentInfo;
 import com.android.documentsui.base.DocumentStack;
-import com.android.documentsui.base.EventHandler;
 import com.android.documentsui.base.EventListener;
-import com.android.documentsui.base.Events.InputEvent;
-import com.android.documentsui.base.Events.MotionInputEvent;
 import com.android.documentsui.base.Features;
 import com.android.documentsui.base.RootInfo;
 import com.android.documentsui.base.Shared;
@@ -90,11 +86,20 @@
 import com.android.documentsui.clipping.UrisSupplier;
 import com.android.documentsui.dirlist.AnimationView.AnimationType;
 import com.android.documentsui.picker.PickActivity;
-import com.android.documentsui.selection.BandController;
-import com.android.documentsui.selection.GestureSelector;
+import com.android.documentsui.selection.BandSelectionHelper;
+import com.android.documentsui.selection.ContentLock;
+import com.android.documentsui.selection.DefaultBandHost;
+import com.android.documentsui.selection.DefaultBandPredicate;
+import com.android.documentsui.selection.GestureRouter;
+import com.android.documentsui.selection.GestureSelectionHelper;
+import com.android.documentsui.selection.ItemDetailsLookup;
+import com.android.documentsui.selection.MotionInputHandler;
+import com.android.documentsui.selection.MouseInputHandler;
 import com.android.documentsui.selection.Selection;
-import com.android.documentsui.selection.SelectionManager;
-import com.android.documentsui.selection.SelectionMetadata;
+import com.android.documentsui.selection.SelectionHelper;
+import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
+import com.android.documentsui.selection.TouchEventRouter;
+import com.android.documentsui.selection.TouchInputHandler;
 import com.android.documentsui.services.FileOperation;
 import com.android.documentsui.services.FileOperationService;
 import com.android.documentsui.services.FileOperationService.OpType;
@@ -107,8 +112,6 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.List;
 
-import javax.annotation.Nullable;
-
 /**
  * Display the documents inside a single directory.
  */
@@ -124,7 +127,7 @@
     public @interface RequestCode {}
     public static final int REQUEST_COPY_DESTINATION = 1;
 
-    private static final String TAG = "DirectoryFragment";
+    static final String TAG = "DirectoryFragment";
     private static final int LOADER_ID = 42;
 
     private static final int CACHE_EVICT_LIMIT = 100;
@@ -143,7 +146,7 @@
 
     @Injected
     @ContentScoped
-    private SelectionManager mSelectionMgr;
+    private SelectionHelper mSelectionMgr;
 
     @Injected
     @ContentScoped
@@ -157,14 +160,14 @@
     @ContentScoped
     private ActionModeController mActionModeController;
 
+    private ItemDetailsLookup mDetailsLookup;
     private SelectionMetadata mSelectionMetadata;
-    private UserInputHandler<InputEvent> mInputHandler;
-    private @Nullable BandController mBandController;
+    private KeyInputHandler mKeyListener;
+    private @Nullable BandSelectionHelper mBandSelector;
     private @Nullable DragHoverListener mDragHoverListener;
     private IconHelper mIconHelper;
     private SwipeRefreshLayout mRefreshLayout;
     private RecyclerView mRecView;
-
     private DocumentsAdapter mAdapter;
     private DocumentClipper mClipper;
     private GridLayoutManager mLayout;
@@ -176,9 +179,11 @@
     private View mProgressBar;
 
     private DirectoryState mLocalState;
-    private DirectoryReloadLock mReloadLock = new DirectoryReloadLock();
 
-    private Runnable mBandSelectStarted;
+    // Blocks loading/reloading of content while user is actively making selection.
+    private ContentLock mContentLock = new ContentLock();
+
+    private Runnable mBandSelectStartedCallback;
 
     // Note, we use !null to indicate that selection was restored (from rotation).
     // So don't fiddle with this field unless you've got the bigger picture in mind.
@@ -201,7 +206,7 @@
         final View view = inflater.inflate(R.layout.fragment_directory, container, false);
 
         mProgressBar = view.findViewById(R.id.progressbar);
-        assert(mProgressBar != null);
+        assert mProgressBar != null;
 
         mRecView = (RecyclerView) view.findViewById(R.id.dir_list);
         mRecView.setRecyclerListener(
@@ -261,8 +266,8 @@
         mModel.removeUpdateListener(mModelUpdateListener);
         mModel.removeUpdateListener(mAdapter.getModelUpdateListener());
 
-        if (mBandController != null) {
-            mBandController.removeBandSelectStartedListener(mBandSelectStarted);
+        if (mBandSelector != null) {
+            mBandSelector.removeOnBandStartedListener(mBandSelectStartedCallback);
         }
 
         super.onDestroyView();
@@ -316,77 +321,99 @@
         mModel.addUpdateListener(mAdapter.getModelUpdateListener());
         mModel.addUpdateListener(mModelUpdateListener);
 
-        mSelectionMgr = mInjector.getSelectionManager(mAdapter, this::canSetSelectionState);
+        SelectionPredicate selectionPredicate =
+                new DocsSelectionPredicate(mInjector.config, mState, mModel, mRecView);
+
+        mSelectionMgr = mInjector.getSelectionManager(mAdapter, selectionPredicate);
         mFocusManager = mInjector.getFocusManager(mRecView, mModel);
-        mActions = mInjector.getActionHandler(mReloadLock);
+        mActions = mInjector.getActionHandler(mContentLock);
 
         mRecView.setAccessibilityDelegateCompat(
                 new AccessibilityEventRouter(mRecView,
                         (View child) -> onAccessibilityClick(child)));
         mSelectionMetadata = new SelectionMetadata(mModel::getItem);
-        mSelectionMgr.addItemCallback(mSelectionMetadata);
+        mSelectionMgr.addObserver(mSelectionMetadata);
+        mDetailsLookup = new DocsItemDetailsLookup(mRecView);
 
-        GestureSelector gestureSel = GestureSelector.create(mSelectionMgr, mRecView, mReloadLock);
+        GestureSelectionHelper gestureHelper = GestureSelectionHelper.create(
+                mSelectionMgr, mRecView, mContentLock, mDetailsLookup);
 
         if (mState.allowMultiple) {
-            mBandController = new BandController(
-                    mRecView,
+            mBandSelector = new BandSelectionHelper(
+                    new DefaultBandHost(mRecView, R.drawable.band_select_overlay),
                     mAdapter,
+                    new DocsStableIdProvider(mAdapter),
                     mSelectionMgr,
-                    mReloadLock,
-                    (int pos) -> {
-                        // The band selection model only operates on documents and directories.
-                        // Exclude other types of adapter items like whitespace and dividers.
-                        RecyclerView.ViewHolder vh = mRecView.findViewHolderForAdapterPosition(pos);
-                        return ModelBackedDocumentsAdapter.isContentType(vh.getItemViewType());
-                    });
-            mBandSelectStarted = mFocusManager::clearFocus;
-            mBandController.addBandSelectStartedListener(mBandSelectStarted);
+                    selectionPredicate,
+                    new DefaultBandPredicate(mDetailsLookup),
+                    mContentLock);
+
+            mBandSelectStartedCallback = mFocusManager::clearFocus;
+            mBandSelector.addOnBandStartedListener(mBandSelectStartedCallback);
         }
 
-        DragStartListener mDragStartListener = mInjector.config.dragAndDropEnabled()
+        DragStartListener dragStartListener = mInjector.config.dragAndDropEnabled()
                 ? DragStartListener.create(
                         mIconHelper,
                         mModel,
                         mSelectionMgr,
                         mSelectionMetadata,
                         mState,
+                        mDetailsLookup,
                         this::getModelId,
                         mRecView::findChildViewUnder,
                         DocumentsApplication.getDragAndDropManager(mActivity))
                 : DragStartListener.DUMMY;
 
-        EventHandler<InputEvent> gestureHandler = mState.allowMultiple
-                ? gestureSel::start
-                : EventHandler.createStub(false);
-
-        mInputHandler = new UserInputHandler<>(
+        // Construction of the input handlers is non trivial, so to keep logic clear,
+        // and code flexible, and DirectoryFragment small, the construction has been
+        // moved off into a separate class.
+        InputHandlers handlers = new InputHandlers(
                 mActions,
-                mFocusManager,
                 mSelectionMgr,
-                (MotionEvent t) -> MotionInputEvent.obtain(t, mRecView),
-                this::canSelect,
-                this::onContextMenuClick,
-                mDragStartListener::onTouchDragEvent,
-                gestureHandler,
-                () -> mRecView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS));
-
-        new ListeningGestureDetector(
-                mInjector.features,
-                this.getContext(),
+                selectionPredicate,
+                mDetailsLookup,
+                mFocusManager,
                 mRecView,
-                mDragStartListener::onMouseDragEvent,
-                mRefreshLayout::setEnabled,
-                gestureSel,
-                mInputHandler,
-                mBandController,
-                this::scaleLayout);
+                mState);
+
+        MouseInputHandler mouseHandler =
+                handlers.createMouseHandler(this::onContextMenuClick);
+
+        TouchInputHandler touchHandler =
+                handlers.createTouchHandler(gestureHelper, dragStartListener);
+
+        GestureRouter<MotionInputHandler> gestureRouter = new GestureRouter<>(touchHandler);
+        gestureRouter.register(MotionEvent.TOOL_TYPE_MOUSE, mouseHandler);
+
+        // This little guy gets added to each Holder, so that we can be notified of key events
+        // on RecyclerView items.
+        mKeyListener = handlers.createKeyHandler();
+
+        if (Build.IS_DEBUGGABLE) {
+            new ScaleHelper(this.getContext(), mInjector.features, this::scaleLayout)
+                    .attach(mRecView);
+        }
+
+        new RefreshHelper(mRefreshLayout::setEnabled)
+                .attach(mRecView);
+
+        GestureDetector gestureDetector = new GestureDetector(getContext(), gestureRouter);
+
+        TouchEventRouter eventRouter = new TouchEventRouter(gestureDetector, gestureHelper);
+
+        eventRouter.register(
+                MotionEvent.TOOL_TYPE_MOUSE,
+                new MouseDragEventInterceptor(
+                        mDetailsLookup, dragStartListener::onMouseDragEvent, mBandSelector));
+
+        mRecView.addOnItemTouchListener(eventRouter);
 
         mActionModeController = mInjector.getActionModeController(
                 mSelectionMetadata,
                 this::handleMenuItemClick);
 
-        mSelectionMgr.addCallback(mActionModeController);
+        mSelectionMgr.addObserver(mActionModeController);
 
         final ActivityManager am = (ActivityManager) mActivity.getSystemService(
                 Context.ACTIVITY_SERVICE);
@@ -428,7 +455,8 @@
     }
 
     public void retainState(RetainedState state) {
-        state.selection = mSelectionMgr.getSelection(new Selection());
+        state.selection = new Selection();
+        mSelectionMgr.copySelection(state.selection);
     }
 
     @Override
@@ -452,7 +480,8 @@
             // at the same time.
             mInjector.menuManager.inflateContextMenuForContainer(menu, inflater);
         } else {
-            mInjector.menuManager.inflateContextMenuForDocs(menu, inflater, mSelectionMetadata);
+            mInjector.menuManager.inflateContextMenuForDocs(
+                    menu, inflater, mSelectionMetadata);
         }
     }
 
@@ -482,23 +511,21 @@
                 jobId);
     }
 
-    protected boolean onContextMenuClick(InputEvent e) {
-        final View v;
-        final float x, y;
-        if (e.isOverModelItem()) {
-            DocumentHolder doc = (DocumentHolder) e.getDocumentDetails();
+    // TODO: Move to UserInputHander.
+    protected boolean onContextMenuClick(MotionEvent e) {
 
-            v = doc.itemView;
-            x = e.getX() - v.getLeft();
-            y = e.getY() - v.getTop();
-        } else {
-            v = mRecView;
-            x = e.getX();
-            y = e.getY();
+        if (mDetailsLookup.overStableItem(e)) {
+            View childView = mRecView.findChildViewUnder(e.getX(), e.getY());
+            ViewHolder holder = mRecView.getChildViewHolder(childView);
+
+            View view = holder.itemView;
+            float x = e.getX() - view.getLeft();
+            float y = e.getY() - view.getTop();
+            mInjector.menuManager.showContextMenu(this, view, x, y);
+            return true;
         }
 
-        mInjector.menuManager.showContextMenu(this, v, x, y);
-
+        mInjector.menuManager.showContextMenu(this, mRecView, e.getX(), e.getY());
         return true;
     }
 
@@ -526,8 +553,8 @@
         int pad = getDirectoryPadding(mode);
         mRecView.setPadding(pad, pad, pad, pad);
         mRecView.requestLayout();
-        if (mBandController != null) {
-            mBandController.handleLayoutChanged();
+        if (mBandSelector != null) {
+            mBandSelector.reset();
         }
         mIconHelper.setViewMode(mode);
     }
@@ -537,7 +564,8 @@
      * @param mode The new view mode.
      */
     private void scaleLayout(float scale) {
-        assert(Build.IS_DEBUGGABLE);
+        assert Build.IS_DEBUGGABLE;
+
         if (VERBOSE) Log.v(
                 TAG, "Handling scale event: " + scale + ", existing scale: " + mLiveScale);
 
@@ -606,7 +634,8 @@
     }
 
     private boolean handleMenuItemClick(MenuItem item) {
-        Selection selection = mSelectionMgr.getSelection(new Selection());
+        Selection selection = new Selection();
+        mSelectionMgr.copySelection(selection);
 
         switch (item.getItemId()) {
             case R.id.action_menu_open:
@@ -669,11 +698,15 @@
                 transferDocuments(selection, null, FileOperationService.OPERATION_MOVE);
                 return true;
 
-            case R.id.action_menu_inspector:
+            case R.id.action_menu_inspect:
+            case R.id.dir_menu_inspect:
                 mActionModeController.finishActionMode();
-                assert(selection.size() == 1);
-                DocumentInfo doc = mModel.getDocuments(selection).get(0);
-                mActions.showInspector(doc);
+                assert selection.size() <= 1;
+                DocumentInfo doc = selection.isEmpty()
+                        ? mActivity.getCurrentDirectory()
+                        : mModel.getDocuments(selection).get(0);
+
+                        mActions.showInspector(doc);
                 return true;
 
             case R.id.dir_menu_cut_to_clipboard:
@@ -720,8 +753,8 @@
     }
 
     private boolean onAccessibilityClick(View child) {
-        DocumentDetails doc = getDocumentHolder(child);
-        mActions.openDocument(doc, ActionHandler.VIEW_TYPE_PREVIEW,
+        DocumentHolder holder = getDocumentHolder(child);
+        mActions.openItem(holder.getItemDetails(), ActionHandler.VIEW_TYPE_PREVIEW,
                 ActionHandler.VIEW_TYPE_REGULAR);
         return true;
     }
@@ -749,7 +782,7 @@
     private void showChooserForDoc(final Selection selected) {
         Metrics.logUserAction(getContext(), Metrics.USER_ACTION_OPEN);
 
-        assert(selected.size() == 1);
+        assert selected.size() == 1;
         DocumentInfo doc =
                 DocumentInfo.fromDirectoryCursor(mModel.getItem(selected.iterator().next()));
         mActions.showChooserForDoc(doc);
@@ -780,7 +813,7 @@
             throw new RuntimeException("Failed to create uri supplier.", e);
         }
 
-        final DocumentInfo parent = mState.stack.peek();
+        final DocumentInfo parent = mActivity.getCurrentDirectory();
         final FileOperation operation = new FileOperation.Builder()
                 .withOpType(mode)
                 .withSrcParent(parent == null ? null : parent.derivedUri)
@@ -871,7 +904,7 @@
 
         // Batch renaming not supported
         // Rename option is only available in menu when 1 document selected
-        assert(selected.size() == 1);
+        assert selected.size() == 1;
 
         // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
         List<DocumentInfo> docs = mModel.getDocuments(selected);
@@ -882,10 +915,6 @@
         return mModel;
     }
 
-    private boolean isDocumentEnabled(String mimeType, int flags) {
-        return mInjector.config.isDocumentEnabled(mimeType, flags, mState);
-    }
-
     /**
      * Paste selection files from the primary clip into the current window.
      */
@@ -937,7 +966,7 @@
         }
 
         if (v == mRecView) {
-            return mState.stack.peek();
+            return mActivity.getCurrentDirectory();
         }
 
         return null;
@@ -968,31 +997,6 @@
         return null;
     }
 
-    // TODO: Move to activities when Model becomes activity level object.
-    private boolean canSelect(DocumentDetails doc) {
-        return canSetSelectionState(doc.getModelId(), true);
-    }
-
-    // TODO: Move to activities when Model becomes activity level object.
-    private boolean canSetSelectionState(String modelId, boolean nextState) {
-        if (nextState) {
-            // Check if an item can be selected
-            final Cursor cursor = mModel.getItem(modelId);
-            if (cursor == null) {
-                Log.w(TAG, "Couldn't obtain cursor for modelId: " + modelId);
-                return false;
-            }
-
-            final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
-            final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
-            return mInjector.config.canSelectType(docMimeType, docFlags, mState);
-        } else {
-        final DocumentInfo parent = mState.stack.peek();
-            // Right now all selected items can be deselected.
-            return true;
-        }
-    }
-
     public static void showDirectory(
             FragmentManager fm, RootInfo root, DocumentInfo doc, int anim) {
         if (DEBUG) Log.d(TAG, "Showing directory: " + DocumentInfo.debugString(doc));
@@ -1056,7 +1060,7 @@
             cache.removeUri(mModel.getItemUri(ids[i]));
         }
 
-        final DocumentInfo doc = mState.stack.peek();
+        final DocumentInfo doc = mActivity.getCurrentDirectory();
         mActions.refreshDocument(doc, (boolean refreshSupported) -> {
             if (refreshSupported) {
                 mRefreshLayout.setRefreshing(false);
@@ -1113,6 +1117,10 @@
             if (!mModel.isLoading()) {
                 mActivity.notifyDirectoryLoaded(
                         mModel.doc != null ? mModel.doc.derivedUri : null);
+                if (mModel.doc == null) {
+                    // Invalid model, then update options menu to disable some items.
+                    mActivity.invalidateOptionsMenu();
+                }
             }
         }
     }
@@ -1151,7 +1159,7 @@
 
         @Override
         public boolean isSelected(String id) {
-            return mSelectionMgr.getSelection().contains(id);
+            return mSelectionMgr.isSelected(id);
         }
 
         @Override
@@ -1161,7 +1169,7 @@
 
         @Override
         public void initDocumentHolder(DocumentHolder holder) {
-            holder.addKeyEventListener(mInputHandler);
+            holder.addKeyEventListener(mKeyListener);
             holder.itemView.setOnFocusChangeListener(mFocusManager);
         }
 
diff --git a/src/com/android/documentsui/dirlist/DocsItemDetailsLookup.java b/src/com/android/documentsui/dirlist/DocsItemDetailsLookup.java
new file mode 100644
index 0000000..a1f91a0
--- /dev/null
+++ b/src/com/android/documentsui/dirlist/DocsItemDetailsLookup.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2017 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.documentsui.dirlist;
+
+import android.support.annotation.Nullable;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.android.documentsui.selection.ItemDetailsLookup;
+
+/**
+ * Access to details of an item associated with a {@link MotionEvent} instance.
+ */
+final class DocsItemDetailsLookup extends ItemDetailsLookup {
+
+    private final RecyclerView mRecView;
+
+    public DocsItemDetailsLookup(RecyclerView view) {
+        mRecView = view;
+    }
+
+    @Override
+    public boolean overItem(MotionEvent e) {
+        return getItemPosition(e) != RecyclerView.NO_POSITION;
+    }
+
+    @Override
+    public boolean overStableItem(MotionEvent e) {
+    if (!overItem(e)) {
+        return false;
+    }
+    ItemDetails details = getItemDetails(e);
+    return details != null && details.hasStableId();
+    }
+
+    @Override
+    public boolean inItemDragRegion(MotionEvent e) {
+    if (!overItem(e)) {
+        return false;
+    }
+    ItemDetails details = getItemDetails(e);
+    return details != null && details.inDragRegion(e);
+    }
+
+    @Override
+    public boolean inItemSelectRegion(MotionEvent e) {
+    if (!overItem(e)) {
+        return false;
+    }
+    ItemDetails details = getItemDetails(e);
+    return details != null && details.inSelectionHotspot(e);
+    }
+
+    @Override
+    public int getItemPosition(MotionEvent e) {
+        View child = mRecView.findChildViewUnder(e.getX(), e.getY());
+        return (child != null)
+                ? mRecView.getChildAdapterPosition(child)
+                : RecyclerView.NO_POSITION;
+    }
+
+    @Override
+    public ItemDetails getItemDetails(MotionEvent e) {
+        @Nullable DocumentHolder holder = getDocumentHolder(e);
+        return holder == null ? null : holder.getItemDetails();
+    }
+
+    private @Nullable DocumentHolder getDocumentHolder(MotionEvent e) {
+        View childView = mRecView.findChildViewUnder(e.getX(), e.getY());
+        if (childView != null) {
+            ViewHolder holder = mRecView.getChildViewHolder(childView);
+            if (holder instanceof DocumentHolder) {
+                return (DocumentHolder) holder;
+            }
+        }
+        return null;
+    }
+}
diff --git a/src/com/android/documentsui/dirlist/DocsSelectionPredicate.java b/src/com/android/documentsui/dirlist/DocsSelectionPredicate.java
new file mode 100644
index 0000000..679bd9f
--- /dev/null
+++ b/src/com/android/documentsui/dirlist/DocsSelectionPredicate.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2017 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.documentsui.dirlist;
+
+import static android.support.v4.util.Preconditions.checkArgument;
+import static com.android.documentsui.base.DocumentInfo.getCursorInt;
+import static com.android.documentsui.base.DocumentInfo.getCursorString;
+
+import android.database.Cursor;
+import android.provider.DocumentsContract.Document;
+import android.support.v7.widget.RecyclerView;
+import android.util.Log;
+
+import com.android.documentsui.ActivityConfig;
+import com.android.documentsui.Model;
+import com.android.documentsui.base.State;
+import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
+
+/**
+ * Class embodying the logic as to whether an item (specified by id or position)
+ * can be selected (or not).
+ */
+final class DocsSelectionPredicate extends SelectionPredicate {
+
+    private ActivityConfig mConfig;
+    private Model mModel;
+    private RecyclerView mRecView;
+    private State mState;
+
+    DocsSelectionPredicate(
+            ActivityConfig config, State state, Model model, RecyclerView recView) {
+
+        checkArgument(config != null);
+        checkArgument(state != null);
+        checkArgument(model != null);
+        checkArgument(recView != null);
+
+        mConfig = config;
+        mState = state;
+        mModel = model;
+        mRecView = recView;
+
+    }
+
+    @Override
+    public boolean canSetStateForId(String id, boolean nextState) {
+        if (nextState) {
+            // Check if an item can be selected
+            final Cursor cursor = mModel.getItem(id);
+            if (cursor == null) {
+                Log.w(DirectoryFragment.TAG, "Couldn't obtain cursor for id: " + id);
+                return false;
+            }
+
+            final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+            final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
+            return mConfig.canSelectType(docMimeType, docFlags, mState);
+        }
+
+        // Right now all selected items can be deselected.
+        return true;
+    }
+
+    @Override
+    public boolean canSetStateAtPosition(int position, boolean nextState) {
+        // This method features a nextState arg for symmetry.
+        // But, there are no current uses for checking un-selecting state by position.
+        // So rather than have some unsuspecting client think canSetState(int, false)
+        // will ever do anything. Let's just be grumpy about it.
+        assert nextState == true;
+
+        // NOTE: Given that we have logic in some places disallowing selection,
+        // it may be a bug that Band and Gesture based selections don't
+        // also verify something can be unselected.
+
+        // The band selection model only operates on documents and directories.
+        // Exclude other types of adapter items like whitespace and dividers.
+        RecyclerView.ViewHolder vh = mRecView.findViewHolderForAdapterPosition(position);
+        return ModelBackedDocumentsAdapter.isContentType(vh.getItemViewType());
+    }
+
+    @Override
+    public boolean canSelectMultiple() {
+        return mState.allowMultiple;
+    }
+}
diff --git a/src/com/android/documentsui/dirlist/DocsStableIdProvider.java b/src/com/android/documentsui/dirlist/DocsStableIdProvider.java
new file mode 100644
index 0000000..889b82a
--- /dev/null
+++ b/src/com/android/documentsui/dirlist/DocsStableIdProvider.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 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.documentsui.dirlist;
+
+import static android.support.v4.util.Preconditions.checkArgument;
+
+import com.android.documentsui.selection.SelectionHelper.StableIdProvider;
+
+import java.util.List;
+
+/**
+ * Provides RecyclerView selection code access to stable ids backed
+ * by DocumentsAdapter.
+ */
+public final class DocsStableIdProvider extends StableIdProvider {
+
+    private final DocumentsAdapter mAdapter;
+
+    public DocsStableIdProvider(DocumentsAdapter adapter) {
+        checkArgument(adapter != null);
+        mAdapter = adapter;
+    }
+
+    @Override
+    public String getStableId(int position) {
+        return mAdapter.getStableId(position);
+    }
+
+    @Override
+    public int getPosition(String id) {
+        return mAdapter.getPosition(id);
+    }
+
+    @Override
+    public List<String> getStableIds() {
+        return mAdapter.getStableIds();
+    }
+}
diff --git a/src/com/android/documentsui/dirlist/DocumentDetails.java b/src/com/android/documentsui/dirlist/DocumentDetails.java
deleted file mode 100644
index a321e64..0000000
--- a/src/com/android/documentsui/dirlist/DocumentDetails.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.dirlist;
-
-import com.android.documentsui.base.Events.InputEvent;
-
-/**
- * Interface providing a loose coupling between DocumentHolder.
- */
-public interface DocumentDetails {
-    boolean hasModelId();
-    String getModelId();
-    int getAdapterPosition();
-    boolean isInSelectionHotspot(InputEvent event);
-    boolean isInDragHotspot(InputEvent event);
-
-    /**
-     * Given a mouse input event, this method does a hit-test to see if the cursor
-     * is currently positioned over the document icon or checkbox in the case where
-     * the document is selected.
-     */
-    boolean isOverDocIcon(InputEvent event);
-}
diff --git a/src/com/android/documentsui/dirlist/DocumentHolder.java b/src/com/android/documentsui/dirlist/DocumentHolder.java
index d7f7ce5..a412e72 100644
--- a/src/com/android/documentsui/dirlist/DocumentHolder.java
+++ b/src/com/android/documentsui/dirlist/DocumentHolder.java
@@ -16,33 +16,24 @@
 
 package com.android.documentsui.dirlist;
 
-import android.annotation.ColorInt;
 import android.content.Context;
 import android.database.Cursor;
-import android.graphics.Rect;
-import android.os.Build;
 import android.support.v7.widget.RecyclerView;
-import android.text.TextUtils;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewPropertyAnimator;
-import android.widget.FrameLayout;
 import android.widget.ImageView;
 
-import com.android.documentsui.R;
-import com.android.documentsui.base.DebugFlags;
-import com.android.documentsui.base.DocumentInfo;
-import com.android.documentsui.base.Events.InputEvent;
 import com.android.documentsui.base.Shared;
-import com.android.documentsui.ui.DocumentDebugInfo;
+import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
 
 import javax.annotation.Nullable;
 
 public abstract class DocumentHolder
-        extends RecyclerView.ViewHolder
-        implements View.OnKeyListener, DocumentDetails {
+        extends RecyclerView.ViewHolder implements View.OnKeyListener {
 
     static final float DISABLED_ALPHA = 0.3f;
 
@@ -50,12 +41,11 @@
 
     protected @Nullable String mModelId;
 
-    private final View mSelectionHotspot;
-    private @Nullable DocumentDebugInfo mDebugInfo;
-
     // See #addKeyEventListener for details on the need for this field.
     private KeyboardEventListener mKeyEventListener;
 
+    private final DocumentItemDetails mDetails;
+
     public DocumentHolder(Context context, ViewGroup parent, int layout) {
         this(context, inflateLayout(context, parent, layout));
     }
@@ -66,8 +56,7 @@
         itemView.setOnKeyListener(this);
 
         mContext = context;
-
-        mSelectionHotspot = itemView.findViewById(R.id.icon_check);
+        mDetails = new DocumentItemDetails();
     }
 
     /**
@@ -78,12 +67,6 @@
      */
     public abstract void bind(Cursor cursor, String modelId);
 
-    @Override
-    public boolean hasModelId() {
-        return !TextUtils.isEmpty(mModelId);
-    }
-
-    @Override
     public String getModelId() {
         return mModelId;
     }
@@ -111,7 +94,10 @@
     @Override
     public boolean onKey(View v, int keyCode, KeyEvent event) {
         assert(mKeyEventListener != null);
-        return mKeyEventListener.onKey(this,  keyCode,  event);
+        ItemDetails details = getItemDetails();
+        return (details == null)
+            ? false
+            : mKeyEventListener.onKey(getItemDetails(),  keyCode,  event);
     }
 
     /**
@@ -127,28 +113,18 @@
         mKeyEventListener = listener;
     }
 
-    @Override
-    public boolean isInSelectionHotspot(InputEvent event) {
-        // Do everything in global coordinates - it makes things simpler.
-        int[] coords = new int[2];
-        mSelectionHotspot.getLocationOnScreen(coords);
-        Rect rect = new Rect(coords[0], coords[1], coords[0] + mSelectionHotspot.getWidth(),
-                coords[1] + mSelectionHotspot.getHeight());
-
-        // If the tap occurred within the icon rect, consider it a selection.
-        return rect.contains((int) event.getRawX(), (int) event.getRawY());
-    }
-
-    @Override
-    public boolean isInDragHotspot(InputEvent event) {
+    public boolean inDragRegion(MotionEvent event) {
         return false;
     }
 
-    @Override
-    public boolean isOverDocIcon(InputEvent event) {
+    public boolean inSelectRegion(MotionEvent event) {
         return false;
     }
 
+    public ItemDetails getItemDetails() {
+        return mDetails;
+    }
+
     static void setEnabledRecursive(View itemView, boolean enabled) {
         if (itemView == null || itemView.isEnabled() == enabled) {
             return;
@@ -163,6 +139,7 @@
         }
     }
 
+    @SuppressWarnings("TypeParameterUnusedInFormals")
     private static <V extends View> V inflateLayout(Context context, ViewGroup parent, int layout) {
         final LayoutInflater inflater = LayoutInflater.from(context);
         return (V) inflater.inflate(layout, parent, false);
@@ -172,20 +149,31 @@
         return view.animate().setDuration(Shared.CHECK_ANIMATION_DURATION).alpha(alpha);
     }
 
-    /**
-     * Implement this in order to be able to respond to events coming from DocumentHolders.
-     * TODO: Make this bubble up logic events rather than having imperative commands.
-     */
-    interface KeyboardEventListener {
+    private final class DocumentItemDetails extends ItemDetails {
 
-        /**
-         * Handles key events on the document holder.
-         *
-         * @param doc The target DocumentHolder.
-         * @param keyCode Key code for the event.
-         * @param event KeyEvent for the event.
-         * @return Whether the event was handled.
-         */
-        public boolean onKey(DocumentHolder doc, int keyCode, KeyEvent event);
+        @Override
+        public int getPosition() {
+            return DocumentHolder.this.getAdapterPosition();
+        }
+
+        @Override
+        public String getStableId() {
+            return DocumentHolder.this.getModelId();
+        }
+
+        @Override
+        public int getItemViewType() {
+            return DocumentHolder.this.getItemViewType();
+        }
+
+        @Override
+        public boolean inDragRegion(MotionEvent e) {
+            return DocumentHolder.this.inDragRegion(e);
+        }
+
+        @Override
+        public boolean inSelectionHotspot(MotionEvent e) {
+            return DocumentHolder.this.inSelectRegion(e);
+        }
     }
 }
diff --git a/src/com/android/documentsui/dirlist/DocumentsAdapter.java b/src/com/android/documentsui/dirlist/DocumentsAdapter.java
index 82f2524..f940814 100644
--- a/src/com/android/documentsui/dirlist/DocumentsAdapter.java
+++ b/src/com/android/documentsui/dirlist/DocumentsAdapter.java
@@ -33,7 +33,7 @@
 import java.util.List;
 
 /**
- * DocumentsAdapter provides glue between a directory Model, and RecylcerView. We've
+ * DocumentsAdapter provides glue between a directory Model, and RecyclerView. We've
  * abstracted this a bit in order to decompose some specialized support
  * for adding dummy layout objects (@see SectionBreakDocumentsAdapter). Handling of the
  * dummy layout objects was error prone when interspersed with the core mode / adapter code.
@@ -41,8 +41,7 @@
  * @see ModelBackedDocumentsAdapter
  * @see DirectoryAddonsAdapter
  */
-public abstract class DocumentsAdapter
-        extends RecyclerView.Adapter<DocumentHolder> {
+public abstract class DocumentsAdapter extends RecyclerView.Adapter<DocumentHolder> {
     // Item types used by ModelBackedDocumentsAdapter
     public static final int ITEM_TYPE_DOCUMENT = 1;
     public static final int ITEM_TYPE_DIRECTORY = 2;
@@ -51,28 +50,10 @@
     public static final int ITEM_TYPE_HEADER_MESSAGE = Integer.MAX_VALUE - 1;
     public static final int ITEM_TYPE_INFLATED_MESSAGE = Integer.MAX_VALUE - 2;
 
-    // Payloads for notifyItemChange to distinguish between selection and other events.
-    static final String SELECTION_CHANGED_MARKER = "Selection-Changed";
-
-    /**
-     * Returns a list of model IDs of items currently in the adapter.
-     *
-     * @return A list of Model IDs.
-     */
-    public abstract List<String> getModelIds();
-
     public abstract int getAdapterPosition(String modelId);
-
-    /**
-     * Triggers item-change notifications by stable ID (as opposed to position).
-     * Passing an unrecognized ID will result in a warning in logcat, but no other error.
-     */
-    public abstract void onItemSelectionChanged(String id);
-
-    /**
-     * @return The model ID of the item at the given adapter position.
-     */
-    public abstract String getModelId(int position);
+    public abstract String getStableId(int adapterPosition);
+    public abstract List<String> getStableIds();
+    public abstract int getPosition(String id);
 
     abstract EventListener<Model.Update> getModelUpdateListener();
 
@@ -85,17 +66,13 @@
         throw new UnsupportedOperationException();
     }
 
-    public boolean hasModelIds() {
-        return !getModelIds().isEmpty();
-    }
-
     static boolean isDirectory(Cursor cursor) {
         final String mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
         return Document.MIME_TYPE_DIR.equals(mimeType);
     }
 
     boolean isDirectory(Model model, int position) {
-        String modelId = getModelIds().get(position);
+        String modelId = getStableIds().get(position);
         Cursor cursor = model.getItem(modelId);
         return isDirectory(cursor);
     }
diff --git a/src/com/android/documentsui/dirlist/DragHost.java b/src/com/android/documentsui/dirlist/DragHost.java
index 987303a..770097d 100644
--- a/src/com/android/documentsui/dirlist/DragHost.java
+++ b/src/com/android/documentsui/dirlist/DragHost.java
@@ -16,7 +16,7 @@
 
 package com.android.documentsui.dirlist;
 
-import static com.android.documentsui.base.Shared.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
 
 import android.app.Activity;
 import android.content.ClipData;
@@ -32,7 +32,7 @@
 import com.android.documentsui.base.DocumentStack;
 import com.android.documentsui.base.Lookup;
 import com.android.documentsui.base.State;
-import com.android.documentsui.selection.SelectionManager;
+import com.android.documentsui.selection.SelectionHelper;
 import com.android.documentsui.ui.DialogController;
 
 import java.util.function.Predicate;
@@ -45,7 +45,7 @@
     private static final String TAG = "dirlist.DragHost";
 
     private final T mActivity;
-    private final SelectionManager mSelectionMgr;
+    private final SelectionHelper mSelectionMgr;
     private final ActionHandler mActions;
     private final State mState;
     private final DialogController mDialogs;
@@ -56,7 +56,7 @@
     DragHost(
             T activity,
             DragAndDropManager dragAndDropManager,
-            SelectionManager selectionMgr,
+            SelectionHelper selectionMgr,
             ActionHandler actions,
             State state,
             DialogController dialogs,
diff --git a/src/com/android/documentsui/dirlist/DragHoverListener.java b/src/com/android/documentsui/dirlist/DragHoverListener.java
index 63d93ec..7babe26 100644
--- a/src/com/android/documentsui/dirlist/DragHoverListener.java
+++ b/src/com/android/documentsui/dirlist/DragHoverListener.java
@@ -24,9 +24,9 @@
 
 import com.android.documentsui.ItemDragListener;
 import com.android.documentsui.ItemDragListener.DragHost;
-import com.android.documentsui.ui.ViewAutoScroller;
-import com.android.documentsui.ui.ViewAutoScroller.ScrollActionDelegate;
-import com.android.documentsui.ui.ViewAutoScroller.ScrollDistanceDelegate;
+import com.android.documentsui.selection.ViewAutoScroller;
+import com.android.documentsui.selection.ViewAutoScroller.ScrollHost;
+import com.android.documentsui.selection.ViewAutoScroller.ScrollerCallbacks;
 
 import java.util.function.BooleanSupplier;
 import java.util.function.IntSupplier;
@@ -66,14 +66,15 @@
             Predicate<View> isScrollView,
             BooleanSupplier scrollUpSupplier,
             BooleanSupplier scrollDownSupplier,
-            ViewAutoScroller.ScrollActionDelegate actionDelegate) {
+            ViewAutoScroller.ScrollerCallbacks scrollCallbacks) {
+
         mDragHandler = dragHandler;
         mHeight = heightSupplier;
         mIsScrollView = isScrollView;
         mCanScrollUp = scrollUpSupplier;
         mCanScrollDown = scrollDownSupplier;
 
-        ScrollDistanceDelegate distanceDelegate = new ScrollDistanceDelegate() {
+        ScrollHost scrollHost = new ScrollHost() {
             @Override
             public Point getCurrentPosition() {
                 return mCurrentPosition;
@@ -90,13 +91,14 @@
             }
         };
 
-        mDragScroller = new ViewAutoScroller(distanceDelegate, actionDelegate);
+        mDragScroller = new ViewAutoScroller(scrollHost, scrollCallbacks);
     }
 
     static DragHoverListener create(
             ItemDragListener<? extends DragHost> dragHandler,
             View scrollView) {
-        ScrollActionDelegate actionDelegate = new ScrollActionDelegate() {
+
+        ScrollerCallbacks scrollCallbacks = new ScrollerCallbacks() {
             @Override
             public void scrollBy(int dy) {
                 scrollView.scrollBy(0, dy);
@@ -113,13 +115,15 @@
                 scrollView.removeCallbacks(r);
             }
         };
+
         DragHoverListener listener = new DragHoverListener(
                 dragHandler,
                 scrollView::getHeight,
                 (view) -> (scrollView == view),
                 () -> scrollView.canScrollVertically(-1),
                 () -> scrollView.canScrollVertically(1),
-                actionDelegate);
+                scrollCallbacks);
+
         return listener;
     }
 
diff --git a/src/com/android/documentsui/dirlist/DragStartListener.java b/src/com/android/documentsui/dirlist/DragStartListener.java
index 1651603..e2859fc 100644
--- a/src/com/android/documentsui/dirlist/DragStartListener.java
+++ b/src/com/android/documentsui/dirlist/DragStartListener.java
@@ -16,11 +16,13 @@
 
 package com.android.documentsui.dirlist;
 
-import static com.android.documentsui.base.Shared.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
+import static com.android.internal.util.Preconditions.checkArgument;
 
 import android.net.Uri;
 import android.support.annotation.VisibleForTesting;
 import android.util.Log;
+import android.view.MotionEvent;
 import android.view.View;
 
 import com.android.documentsui.DragAndDropManager;
@@ -28,10 +30,11 @@
 import com.android.documentsui.Model;
 import com.android.documentsui.base.DocumentInfo;
 import com.android.documentsui.base.Events;
-import com.android.documentsui.base.Events.InputEvent;
 import com.android.documentsui.base.State;
+import com.android.documentsui.selection.ItemDetailsLookup;
+import com.android.documentsui.selection.MutableSelection;
 import com.android.documentsui.selection.Selection;
-import com.android.documentsui.selection.SelectionManager;
+import com.android.documentsui.selection.SelectionHelper;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -42,44 +45,47 @@
 /**
  * Listens for potential "drag-like" events and kick-start dragging as needed. Also allows external
  * direct call to {@code #startDrag(RecyclerView, View)} if explicit start is needed, such as long-
- * pressing on an item via touch. (e.g. {@link UserInputHandler#onLongPress(InputEvent)} via touch.)
+ * pressing on an item via touch. (e.g. InputEventDispatcher#onLongPress(MotionEvent)} via touch.
  */
 interface DragStartListener {
 
     static final DragStartListener DUMMY = new DragStartListener() {
         @Override
-        public boolean onMouseDragEvent(InputEvent event) {
+        public boolean onMouseDragEvent(MotionEvent event) {
             return false;
         }
         @Override
-        public boolean onTouchDragEvent(InputEvent event) {
+        public boolean onTouchDragEvent(MotionEvent event) {
             return false;
         }
     };
 
-    boolean onMouseDragEvent(InputEvent event);
-    boolean onTouchDragEvent(InputEvent event);
+    boolean onMouseDragEvent(MotionEvent event);
+    boolean onTouchDragEvent(MotionEvent event);
 
     @VisibleForTesting
-    class ActiveListener implements DragStartListener {
+    class RuntimeDragStartListener implements DragStartListener {
 
         private static String TAG = "DragStartListener";
 
         private final IconHelper mIconHelper;
         private final State mState;
-        private final SelectionManager mSelectionMgr;
+        private final ItemDetailsLookup mDetailsLookup;
+        private final SelectionHelper mSelectionMgr;
         private final SelectionDetails mSelectionDetails;
         private final ViewFinder mViewFinder;
         private final Function<View, String> mIdFinder;
         private final Function<Selection, List<DocumentInfo>> mDocsConverter;
         private final DragAndDropManager mDragAndDropManager;
 
+
         // use DragStartListener.create
         @VisibleForTesting
-        public ActiveListener(
+        public RuntimeDragStartListener(
                 IconHelper iconHelper,
                 State state,
-                SelectionManager selectionMgr,
+                ItemDetailsLookup detailsLookup,
+                SelectionHelper selectionMgr,
                 SelectionDetails selectionDetails,
                 ViewFinder viewFinder,
                 Function<View, String> idFinder,
@@ -88,6 +94,7 @@
 
             mIconHelper = iconHelper;
             mState = state;
+            mDetailsLookup = detailsLookup;
             mSelectionMgr = selectionMgr;
             mSelectionDetails = selectionDetails;
             mViewFinder = viewFinder;
@@ -97,20 +104,22 @@
         }
 
         @Override
-        public final boolean onMouseDragEvent(InputEvent event) {
-            assert(Events.isMouseDragEvent(event));
+        public final boolean onMouseDragEvent(MotionEvent event) {
+            checkArgument(Events.isMouseDragEvent(event));
+            checkArgument(mDetailsLookup.inItemDragRegion(event));
+
             return startDrag(mViewFinder.findView(event.getX(), event.getY()), event);
         }
 
         @Override
-        public final boolean onTouchDragEvent(InputEvent event) {
+        public final boolean onTouchDragEvent(MotionEvent event) {
             return startDrag(mViewFinder.findView(event.getX(), event.getY()), event);
         }
 
         /**
          * May be called externally when drag is initiated from other event handling code.
          */
-        private boolean startDrag(@Nullable View view, InputEvent event) {
+        private boolean startDrag(@Nullable View view, MotionEvent event) {
 
             if (view == null) {
                 if (DEBUG) Log.d(TAG, "Ignoring drag event, null view.");
@@ -145,21 +154,22 @@
         }
 
         /**
-         * Given the InputEvent (for CTRL case) and modelId of the view associated with the
+         * Given the MotionEvent (for CTRL case) and modelId of the view associated with the
          * coordinates of the event, return a valid selection for drag and drop operation
          */
         @VisibleForTesting
-        Selection getSelectionToBeCopied(String modelId, InputEvent event) {
-            Selection selection = new Selection();
+        MutableSelection getSelectionToBeCopied(String modelId, MotionEvent event) {
+            MutableSelection selection = new MutableSelection();
             // If CTRL-key is held down and there's other existing selection, add item to
             // selection (if not already selected)
-            if (event.isCtrlKeyDown() && !mSelectionMgr.getSelection().contains(modelId)
-                    && mSelectionMgr.hasSelection()) {
-                mSelectionMgr.toggleSelection(modelId);
+            if (Events.isCtrlKeyPressed(event)
+                    && mSelectionMgr.hasSelection()
+                    && !mSelectionMgr.isSelected(modelId)) {
+                mSelectionMgr.select(modelId);
             }
 
-            if (mSelectionMgr.getSelection().contains(modelId)) {
-                mSelectionMgr.getSelection(selection);
+            if (mSelectionMgr.isSelected(modelId)) {
+                mSelectionMgr.copySelection(selection);
             } else {
                 selection.add(modelId);
                 mSelectionMgr.clearSelection();
@@ -171,16 +181,18 @@
     static DragStartListener create(
             IconHelper iconHelper,
             Model model,
-            SelectionManager selectionMgr,
+            SelectionHelper selectionMgr,
             SelectionDetails selectionDetails,
             State state,
+            ItemDetailsLookup detailsLookup,
             Function<View, String> idFinder,
             ViewFinder viewFinder,
             DragAndDropManager dragAndDropManager) {
 
-        return new ActiveListener(
+        return new RuntimeDragStartListener(
                 iconHelper,
                 state,
+                detailsLookup,
                 selectionMgr,
                 selectionDetails,
                 viewFinder,
diff --git a/src/com/android/documentsui/dirlist/GridDirectoryHolder.java b/src/com/android/documentsui/dirlist/GridDirectoryHolder.java
index cf793db..5d02957 100644
--- a/src/com/android/documentsui/dirlist/GridDirectoryHolder.java
+++ b/src/com/android/documentsui/dirlist/GridDirectoryHolder.java
@@ -22,15 +22,12 @@
 import android.database.Cursor;
 import android.graphics.Rect;
 import android.provider.DocumentsContract.Document;
+import android.view.MotionEvent;
 import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.TextView;
 
 import com.android.documentsui.R;
-import com.android.documentsui.base.DebugFlags;
-import com.android.documentsui.base.DocumentInfo;
-import com.android.documentsui.base.Events.InputEvent;
-import com.android.documentsui.roots.RootCursorWrapper;
 
 final class GridDirectoryHolder extends DocumentHolder {
 
@@ -62,13 +59,13 @@
     }
 
     @Override
-    public boolean isInDragHotspot(InputEvent event) {
+    public boolean inDragRegion(MotionEvent event) {
         // Entire grid box should be draggable
         return true;
     }
 
     @Override
-    public boolean isOverDocIcon(InputEvent event) {
+    public boolean inSelectRegion(MotionEvent event) {
         Rect iconRect = new Rect();
         mIconMime.getGlobalVisibleRect(iconRect);
 
diff --git a/src/com/android/documentsui/dirlist/GridDocumentHolder.java b/src/com/android/documentsui/dirlist/GridDocumentHolder.java
index e96d09f..95be1b9 100644
--- a/src/com/android/documentsui/dirlist/GridDocumentHolder.java
+++ b/src/com/android/documentsui/dirlist/GridDocumentHolder.java
@@ -25,15 +25,14 @@
 import android.graphics.Rect;
 import android.provider.DocumentsContract.Document;
 import android.text.format.Formatter;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.TextView;
 
 import com.android.documentsui.R;
-import com.android.documentsui.base.DebugFlags;
 import com.android.documentsui.base.DocumentInfo;
-import com.android.documentsui.base.Events.InputEvent;
 import com.android.documentsui.base.Shared;
 import com.android.documentsui.roots.RootCursorWrapper;
 
@@ -112,13 +111,13 @@
     }
 
     @Override
-    public boolean isInDragHotspot(InputEvent event) {
+    public boolean inDragRegion(MotionEvent event) {
      // Entire grid box should be draggable
         return true;
     }
 
     @Override
-    public boolean isOverDocIcon(InputEvent event) {
+    public boolean inSelectRegion(MotionEvent event) {
         Rect iconRect = new Rect();
         mIconMimeSm.getGlobalVisibleRect(iconRect);
 
diff --git a/src/com/android/documentsui/dirlist/IconHelper.java b/src/com/android/documentsui/dirlist/IconHelper.java
index fe14558..c5e86c1 100644
--- a/src/com/android/documentsui/dirlist/IconHelper.java
+++ b/src/com/android/documentsui/dirlist/IconHelper.java
@@ -16,7 +16,7 @@
 
 package com.android.documentsui.dirlist;
 
-import static com.android.documentsui.base.Shared.VERBOSE;
+import static com.android.documentsui.base.SharedMinimal.VERBOSE;
 import static com.android.documentsui.base.State.MODE_GRID;
 import static com.android.documentsui.base.State.MODE_LIST;
 
diff --git a/src/com/android/documentsui/dirlist/InputHandlers.java b/src/com/android/documentsui/dirlist/InputHandlers.java
new file mode 100644
index 0000000..43143d4
--- /dev/null
+++ b/src/com/android/documentsui/dirlist/InputHandlers.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2017 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.documentsui.dirlist;
+
+import static android.support.v4.util.Preconditions.checkArgument;
+
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.view.HapticFeedbackConstants;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import com.android.documentsui.ActionHandler;
+import com.android.documentsui.base.EventHandler;
+import com.android.documentsui.base.State;
+import com.android.documentsui.selection.GestureSelectionHelper;
+import com.android.documentsui.selection.ItemDetailsLookup;
+import com.android.documentsui.selection.MouseInputHandler;
+import com.android.documentsui.selection.SelectionHelper;
+import com.android.documentsui.selection.TouchInputHandler;
+import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
+import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
+
+/**
+ * Helper class dedicated to building gesture input handlers. The construction
+ * of the various input handlers is non trivial. To keep logic clear,
+ * code flexible, and DirectoryFragment small(er), the construction has been
+ * isolated here in a separate class.
+ */
+final class InputHandlers {
+
+    private ActionHandler mActions;
+    private SelectionHelper mSelectionHelper;
+    private SelectionPredicate mSelectionPredicate;
+    private ItemDetailsLookup mDetailsLookup;
+    private FocusHandler mFocusHandler;
+    private RecyclerView mRecView;
+    private State mState;
+
+    InputHandlers(
+            ActionHandler actions,
+            SelectionHelper selectionHelper,
+            SelectionPredicate selectionPredicate,
+            ItemDetailsLookup detailsLookup,
+            FocusHandler focusHandler,
+            RecyclerView recView,
+            State state) {
+
+        checkArgument(actions != null);
+        checkArgument(selectionHelper != null);
+        checkArgument(selectionPredicate != null);
+        checkArgument(detailsLookup != null);
+        checkArgument(focusHandler != null);
+        checkArgument(recView != null);
+        checkArgument(state != null);
+
+        mActions = actions;
+        mSelectionHelper = selectionHelper;
+        mSelectionPredicate = selectionPredicate;
+        mDetailsLookup = detailsLookup;
+        mFocusHandler = focusHandler;
+        mRecView = recView;
+        mState = state;
+    }
+
+    KeyInputHandler createKeyHandler() {
+        KeyInputHandler.Callbacks callbacks = new KeyInputHandler.Callbacks() {
+            @Override
+            public boolean isInteractiveItem(ItemDetails item, KeyEvent e) {
+                switch (item.getItemViewType()) {
+                    case DocumentsAdapter.ITEM_TYPE_HEADER_MESSAGE:
+                    case DocumentsAdapter.ITEM_TYPE_INFLATED_MESSAGE:
+                    case DocumentsAdapter.ITEM_TYPE_SECTION_BREAK:
+                        return false;
+                    case DocumentsAdapter.ITEM_TYPE_DOCUMENT:
+                    case DocumentsAdapter.ITEM_TYPE_DIRECTORY:
+                        return true;
+                    default:
+                        throw new RuntimeException(
+                                "Unsupported item type: " + item.getItemViewType());
+                }
+            }
+
+            @Override
+            public boolean onItemActivated(ItemDetails item, KeyEvent e) {
+                // Handle enter key events
+                switch (e.getKeyCode()) {
+                    case KeyEvent.KEYCODE_ENTER:
+                    case KeyEvent.KEYCODE_DPAD_CENTER:
+                    case KeyEvent.KEYCODE_BUTTON_A:
+                        return mActions.openItem(
+                                item,
+                                ActionHandler.VIEW_TYPE_REGULAR,
+                                ActionHandler.VIEW_TYPE_PREVIEW);
+                    case KeyEvent.KEYCODE_SPACE:
+                        return mActions.openItem(
+                                item,
+                                ActionHandler.VIEW_TYPE_PREVIEW,
+                                ActionHandler.VIEW_TYPE_NONE);
+                }
+
+                return false;
+            }
+
+            @Override
+            public boolean onFocusItem(ItemDetails details, int keyCode, KeyEvent event) {
+                ViewHolder holder =
+                        mRecView.findViewHolderForAdapterPosition(details.getPosition());
+                if (holder instanceof DocumentHolder) {
+                    return mFocusHandler.handleKey((DocumentHolder) holder, keyCode, event);
+                }
+                return false;
+            }
+
+            @Override
+            public void onPerformHapticFeedback() {
+                mRecView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+            }
+        };
+
+        return new KeyInputHandler(mSelectionHelper, mSelectionPredicate, callbacks);
+    }
+
+    MouseInputHandler createMouseHandler(
+            EventHandler<MotionEvent> showContextMenuCallback) {
+
+        checkArgument(showContextMenuCallback != null);
+
+        MouseInputHandler.Callbacks callbacks = new MouseInputHandler.Callbacks() {
+            @Override
+            public boolean onItemActivated(ItemDetails item, MotionEvent e) {
+                return mActions.openItem(
+                        item,
+                        ActionHandler.VIEW_TYPE_REGULAR,
+                        ActionHandler.VIEW_TYPE_PREVIEW);
+            }
+
+            @Override
+            public boolean onContextClick(MotionEvent e) {
+                return showContextMenuCallback.accept(e);
+            }
+
+            @Override
+            public void onPerformHapticFeedback() {
+                mRecView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+            }
+
+            @Override
+            public void focusItem(ItemDetails item) {
+                mFocusHandler.focusDocument(item.getStableId());
+            }
+
+            @Override
+            public void clearFocus() {
+                mFocusHandler.clearFocus();
+            }
+
+            @Override
+            public boolean hasFocusedItem() {
+                return mFocusHandler.hasFocusedItem();
+            }
+
+            @Override
+            public int getFocusedPosition() {
+                return mFocusHandler.getFocusPosition();
+            }
+        };
+
+        return new MouseInputHandler(mSelectionHelper, mDetailsLookup, callbacks);
+    }
+
+    /**
+     * Factory method for input touch delegate. Exists to reduce complexity in the
+     * calling scope.
+     * @param gestureHelper
+     */
+    TouchInputHandler createTouchHandler(
+            GestureSelectionHelper gestureHelper, DragStartListener dragStartListener) {
+        checkArgument(dragStartListener != null);
+
+        TouchInputHandler.Callbacks callbacks = new TouchInputHandler.Callbacks() {
+            @Override
+            public boolean onItemActivated(ItemDetails item, MotionEvent e) {
+                return mActions.openItem(
+                        item,
+                        ActionHandler.VIEW_TYPE_PREVIEW,
+                        ActionHandler.VIEW_TYPE_REGULAR);
+            }
+
+            @Override
+            public boolean onDragInitiated(MotionEvent e) {
+                return dragStartListener.onTouchDragEvent(e);
+            }
+
+            @Override
+            public void onPerformHapticFeedback() {
+                mRecView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+            }
+
+            @Override
+            public void focusItem(ItemDetails item) {
+                mFocusHandler.focusDocument(item.getStableId());
+            }
+
+            @Override
+            public void clearFocus() {
+                mFocusHandler.clearFocus();
+            }
+        };
+
+        return new TouchInputHandler(
+                mSelectionHelper, mDetailsLookup, mSelectionPredicate, gestureHelper, callbacks);
+    }
+}
diff --git a/src/com/android/documentsui/dirlist/KeyInputHandler.java b/src/com/android/documentsui/dirlist/KeyInputHandler.java
new file mode 100644
index 0000000..b70438a
--- /dev/null
+++ b/src/com/android/documentsui/dirlist/KeyInputHandler.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2017 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.documentsui.dirlist;
+
+import android.view.KeyEvent;
+
+import com.android.documentsui.base.Events;
+import com.android.documentsui.selection.ItemDetailsLookup;
+import com.android.documentsui.selection.MotionInputHandler;
+import com.android.documentsui.selection.SelectionHelper;
+import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
+import com.android.documentsui.selection.MotionInputHandler.Callbacks;
+import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
+
+import javax.annotation.Nullable;
+
+/**
+ * Class that handles keyboard events on RecyclerView items. The input handler
+ * must be attached directly to a RecyclerView item since, unlike DOM, events
+ * don't appear bubble up.
+ */
+public final class KeyInputHandler extends KeyboardEventListener {
+
+    private final SelectionHelper mSelectionHelper;
+    private final SelectionPredicate mSelectionPredicate;
+    private final Callbacks mCallbacks;
+
+    public KeyInputHandler(
+            SelectionHelper selectionHelper,
+            SelectionPredicate selectionPredicate,
+            Callbacks callbacks) {
+
+        mSelectionHelper = selectionHelper;
+        mSelectionPredicate = selectionPredicate;
+        mCallbacks = callbacks;
+    }
+
+    @Override
+    public boolean onKey(@Nullable ItemDetails details, int keyCode, KeyEvent event) {
+        // Only handle key-down events. This is simpler, consistent with most other UIs, and
+        // enables the handling of repeated key events from holding down a key.
+        if (event.getAction() != KeyEvent.ACTION_DOWN) {
+            return false;
+        }
+
+        // Ignore tab key events.  Those should be handled by the top-level key handler.
+        if (keyCode == KeyEvent.KEYCODE_TAB) {
+            return false;
+        }
+
+        // Ignore events sent to Addon Holders.
+        if (details != null) {
+            int itemType = details.getItemViewType();
+            if (itemType == DocumentsAdapter.ITEM_TYPE_HEADER_MESSAGE
+                    || itemType == DocumentsAdapter.ITEM_TYPE_INFLATED_MESSAGE
+                    || itemType == DocumentsAdapter.ITEM_TYPE_SECTION_BREAK) {
+                return false;
+            }
+        }
+
+        if (mCallbacks.onFocusItem(details, keyCode, event)) {
+            // Handle range selection adjustments. Extending the selection will adjust the
+            // bounds of the in-progress range selection. Each time an unshifted navigation
+            // event is received, the range selection is restarted.
+            if (shouldExtendSelection(details, event)) {
+                if (!mSelectionHelper.isRangeActive()) {
+                    // Start a range selection if one isn't active
+                    mSelectionHelper.startRange(details.getPosition());
+                }
+                mSelectionHelper.extendRange(details.getPosition());
+            } else {
+                mSelectionHelper.endRange();
+                mSelectionHelper.clearSelection();
+            }
+            return true;
+        }
+
+        // we don't yet have a mechanism to handle opening/previewing multiple documents at once
+        if (mSelectionHelper.getSelection().size() > 1) {
+            return false;
+        }
+
+        return mCallbacks.onItemActivated(details, event);
+    }
+
+    private boolean shouldExtendSelection(ItemDetails item, KeyEvent event) {
+        if (!Events.isNavigationKeyCode(event.getKeyCode()) || !event.isShiftPressed()) {
+            return false;
+        }
+
+        return mSelectionPredicate.canSetStateForId(item.getStableId(), true);
+    }
+
+    public static abstract class Callbacks extends MotionInputHandler.Callbacks {
+        public abstract boolean isInteractiveItem(ItemDetails item, KeyEvent e);
+        public abstract boolean onItemActivated(ItemDetails item, KeyEvent e);
+        public boolean onFocusItem(ItemDetails details, int keyCode, KeyEvent event) {
+            return true;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/documentsui/dirlist/KeyboardEventListener.java b/src/com/android/documentsui/dirlist/KeyboardEventListener.java
new file mode 100644
index 0000000..fb1fc0a
--- /dev/null
+++ b/src/com/android/documentsui/dirlist/KeyboardEventListener.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 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.documentsui.dirlist;
+
+import android.view.KeyEvent;
+
+import com.android.documentsui.selection.ItemDetailsLookup;
+import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
+
+/**
+ * KeyboardListener is implemented by {@link KeyInputHandler}. The handler
+ * must be called from RecyclerView.Holders in response to keyboard events.
+ */
+public abstract class KeyboardEventListener {
+
+    /**
+     * Handles key events on the view holder.
+     *
+     * @param details The target ItemHolder.
+     * @param keyCode Key code for the event.
+     * @param event KeyEvent for the event.
+     *
+     * @return Whether the event was handled.
+     */
+    public abstract boolean onKey(ItemDetails details, int keyCode, KeyEvent event);
+}
diff --git a/src/com/android/documentsui/dirlist/ListDocumentHolder.java b/src/com/android/documentsui/dirlist/ListDocumentHolder.java
index 42be8f9..f97410a 100644
--- a/src/com/android/documentsui/dirlist/ListDocumentHolder.java
+++ b/src/com/android/documentsui/dirlist/ListDocumentHolder.java
@@ -23,6 +23,7 @@
 import android.database.Cursor;
 import android.graphics.Rect;
 import android.text.format.Formatter;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
@@ -31,7 +32,6 @@
 
 import com.android.documentsui.R;
 import com.android.documentsui.base.DocumentInfo;
-import com.android.documentsui.base.Events.InputEvent;
 import com.android.documentsui.base.Lookup;
 import com.android.documentsui.base.Shared;
 import com.android.documentsui.roots.RootCursorWrapper;
@@ -114,7 +114,7 @@
     }
 
     @Override
-    public boolean isInDragHotspot(InputEvent event) {
+    public boolean inDragRegion(MotionEvent event) {
         // If itemView is activated = selected, then whole region is interactive
         if (itemView.isActivated()) {
             return true;
@@ -139,7 +139,7 @@
     }
 
     @Override
-    public boolean isOverDocIcon(InputEvent event) {
+    public boolean inSelectRegion(MotionEvent event) {
         Rect iconRect = new Rect();
         mIconLayout.getGlobalVisibleRect(iconRect);
 
@@ -177,7 +177,13 @@
             // Note, we don't show any details for any directory...ever.
             hasDetails = false;
         } else {
-            if (mDoc.summary != null) {
+            // Show summary if the file is partial. Otherwise, there tends
+            // to be a bunch of confusing junk in the summary field
+            // as populated by Downlaods (and others). So to make things
+            // simpler and clearer for the user in list view, we only
+            // show the summary if the file is partial >
+            // which we believe to mean actively downloading.
+            if (mDoc.isPartial() && mDoc.summary != null) {
                 hasDetails = true;
                 mSummary.setText(mDoc.summary);
                 mSummary.setVisibility(View.VISIBLE);
diff --git a/src/com/android/documentsui/dirlist/ListeningGestureDetector.java b/src/com/android/documentsui/dirlist/ListeningGestureDetector.java
deleted file mode 100644
index cc81d3f..0000000
--- a/src/com/android/documentsui/dirlist/ListeningGestureDetector.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.dirlist;
-
-import static com.android.documentsui.base.Shared.VERBOSE;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.os.Build;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.RecyclerView.OnItemTouchListener;
-import android.util.Log;
-import android.view.GestureDetector;
-import android.view.MotionEvent;
-import android.view.ScaleGestureDetector;
-
-import com.android.documentsui.base.BooleanConsumer;
-import com.android.documentsui.base.EventHandler;
-import com.android.documentsui.base.Events;
-import com.android.documentsui.base.Events.InputEvent;
-import com.android.documentsui.base.Events.MotionInputEvent;
-import com.android.documentsui.base.Features;
-import com.android.documentsui.selection.BandController;
-import com.android.documentsui.selection.GestureSelector;
-
-import java.util.function.Consumer;
-
-//Receives event meant for both directory and empty view, and either pass them to
-//{@link UserInputHandler} for simple gestures (Single Tap, Long-Press), or intercept them for
-//other types of gestures (drag n' drop)
-final class ListeningGestureDetector extends GestureDetector implements OnItemTouchListener {
-
-    private static final String TAG = "ListeningGestureDetector";
-
-    private final Features mFeatures;
-    private final GestureSelector mGestureSelector;
-    private final EventHandler<InputEvent> mMouseDragListener;
-    private final BooleanConsumer mRefreshLayoutEnabler;
-    private final BandController mBandController;
-    private final MouseDelegate mMouseDelegate = new MouseDelegate();
-    private final TouchDelegate mTouchDelegate = new TouchDelegate();
-
-    // Currently only initialized on IS_DEBUGGABLE builds.
-    private final @Nullable ScaleGestureDetector mScaleDetector;
-
-    public ListeningGestureDetector(
-            Features features,
-            Context context,
-            RecyclerView recView,
-            EventHandler<InputEvent> mouseDragListener,
-            BooleanConsumer refreshLayoutEnabler,
-            GestureSelector gestureSelector,
-            UserInputHandler<? extends InputEvent> handler,
-            @Nullable BandController bandController,
-            Consumer<Float> scaleHandler) {
-
-        super(context, handler);
-
-        mFeatures = features;
-        mMouseDragListener = mouseDragListener;
-        mRefreshLayoutEnabler = refreshLayoutEnabler;
-        mGestureSelector = gestureSelector;
-        mBandController = bandController;
-        recView.addOnItemTouchListener(this);
-
-        mScaleDetector = !Build.IS_DEBUGGABLE
-                ? null
-                : new ScaleGestureDetector(
-                        context,
-                        new ScaleGestureDetector.SimpleOnScaleGestureListener() {
-                            @Override
-                            public boolean onScale(ScaleGestureDetector detector) {
-                                if (VERBOSE) Log.v(TAG,
-                                        "Received scale event: " + detector.getScaleFactor());
-                                scaleHandler.accept(detector.getScaleFactor());
-                                return true;
-                            }
-                        });
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
-        boolean handled = false;
-
-        // TODO: Re-wire event handling so that we're not dispatching
-        //     events to to scaledetector's #onTouchEvent from this
-        //     #onInterceptTouchEvent touch event.
-        if (mFeatures.isGestureScaleEnabled()
-                && mScaleDetector != null) {
-            mScaleDetector.onTouchEvent(e);
-        }
-
-        try (InputEvent event = MotionInputEvent.obtain(e, rv)) {
-            if (event.isMouseEvent()) {
-                if (event.isActionDown()) {
-                    mRefreshLayoutEnabler.accept(false);
-                }
-                handled |= mMouseDelegate.onInterceptTouchEvent(event);
-            } else {
-                // If user has started some gesture while RecyclerView is not at the top, disable
-                // refresh
-                if (event.isActionDown() && rv.computeVerticalScrollOffset() != 0) {
-                    mRefreshLayoutEnabler.accept(false);
-                }
-                handled |= mTouchDelegate.onInterceptTouchEvent(event);
-            }
-
-
-            if (event.isActionUp()) {
-                mRefreshLayoutEnabler.accept(true);
-            }
-        }
-
-        // Forward all events to UserInputHandler.
-        // This is necessary since UserInputHandler needs to always see the first DOWN event. Or
-        // else all future UP events will be tossed.
-        handled |= onTouchEvent(e);
-
-        return handled;
-    }
-
-    @Override
-    public void onTouchEvent(RecyclerView rv, MotionEvent e) {
-        try (InputEvent event = MotionInputEvent.obtain(e, rv)) {
-            if (Events.isMouseEvent(e)) {
-                mMouseDelegate.onTouchEvent(event);
-            } else {
-                mTouchDelegate.onTouchEvent(rv, event);
-            }
-
-            if (event.isActionUp()) {
-                mRefreshLayoutEnabler.accept(true);
-            }
-        }
-
-        // Note: even though this event is being handled as part of gestures such as drag and band,
-        // continue forwarding to the GestureDetector. The detector needs to see the entire cluster
-        // of events in order to properly interpret other gestures, such as long press.
-        onTouchEvent(e);
-    }
-
-    private class MouseDelegate {
-        boolean onInterceptTouchEvent(InputEvent e) {
-            if (Events.isMouseDragEvent(e)) {
-                return mMouseDragListener.accept(e);
-            } else if (mBandController != null &&
-                    (mBandController.shouldStart(e) || mBandController.shouldStop(e))) {
-                return mBandController.onInterceptTouchEvent(e);
-            }
-            return false;
-        }
-
-        void onTouchEvent(InputEvent e) {
-            if (mBandController != null) {
-                mBandController.onTouchEvent(e);
-            }
-        }
-    }
-
-    private class TouchDelegate {
-        boolean onInterceptTouchEvent(InputEvent e) {
-            // Gesture Selector needs to be constantly fed events, so that when a long press does
-            // happen, we would have the last DOWN event that occurred to keep track of our anchor
-            // point
-            return mGestureSelector.onInterceptTouchEvent(e);
-        }
-
-        // TODO: Make this take just an InputEvent, no RecyclerView
-        void onTouchEvent(RecyclerView rv, InputEvent e) {
-            mGestureSelector.onTouchEvent(rv, e);
-        }
-    }
-
-    @Override
-    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {}
-}
diff --git a/src/com/android/documentsui/dirlist/Message.java b/src/com/android/documentsui/dirlist/Message.java
index 7c8072a..b81a72c 100644
--- a/src/com/android/documentsui/dirlist/Message.java
+++ b/src/com/android/documentsui/dirlist/Message.java
@@ -159,7 +159,7 @@
 
         private void updateToCantDisplayContentMessage() {
             update(mEnv.getContext().getResources().getText(R.string.cant_display_content), null,
-                    mEnv.getContext().getDrawable(R.drawable.cabinet));
+                    mEnv.getContext().getDrawable(R.drawable.empty));
         }
 
         private void updateToInflatedEmptyMessage() {
@@ -172,7 +172,7 @@
             } else {
                 message = mEnv.getContext().getResources().getText(R.string.empty);
             }
-            update(message, null, mEnv.getContext().getDrawable(R.drawable.cabinet));
+            update(message, null, mEnv.getContext().getDrawable(R.drawable.empty));
         }
     }
 }
diff --git a/src/com/android/documentsui/dirlist/MessageHolder.java b/src/com/android/documentsui/dirlist/MessageHolder.java
index a9a722d..9268602 100644
--- a/src/com/android/documentsui/dirlist/MessageHolder.java
+++ b/src/com/android/documentsui/dirlist/MessageHolder.java
@@ -16,13 +16,13 @@
 
 package com.android.documentsui.dirlist;
 
+import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
+
 import android.content.Context;
+import android.view.MotionEvent;
 import android.view.ViewGroup;
 import android.widget.Space;
 
-import com.android.documentsui.base.DocumentInfo;
-import com.android.documentsui.base.Events.InputEvent;
-
 /**
  * Base class for all non-Document Holder classes.
  */
@@ -36,12 +36,7 @@
     }
 
     @Override
-    public boolean isInSelectionHotspot(InputEvent event) {
-        return false;
+    public ItemDetails getItemDetails() {
+        return null;
     }
-
-    @Override
-    public boolean isInDragHotspot(InputEvent event) {
-        return false;
-    }
-}
\ No newline at end of file
+}
diff --git a/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java b/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
index 921917c..99bb63c 100644
--- a/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
+++ b/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
@@ -23,14 +23,16 @@
 
 import android.database.Cursor;
 import android.provider.DocumentsContract.Document;
+import android.support.v7.widget.RecyclerView;
 import android.util.Log;
 import android.view.ViewGroup;
 
 import com.android.documentsui.Model;
+import com.android.documentsui.Model.Update;
 import com.android.documentsui.base.EventListener;
 import com.android.documentsui.base.Lookup;
 import com.android.documentsui.base.State;
-import com.android.documentsui.Model.Update;
+import com.android.documentsui.selection.SelectionHelper;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -109,7 +111,7 @@
 
     @Override
     public void onBindViewHolder(DocumentHolder holder, int position, List<Object> payload) {
-        if (payload.contains(SELECTION_CHANGED_MARKER)) {
+        if (payload.contains(SelectionHelper.SELECTION_CHANGED_MARKER)) {
             final boolean selected = mEnv.isSelected(mModelIds.get(position));
             holder.setSelected(selected, true);
         } else {
@@ -156,7 +158,7 @@
     }
 
     @Override
-    public String getModelId(int adapterPosition) {
+    public String getStableId(int adapterPosition) {
         return mModelIds.get(adapterPosition);
     }
 
@@ -166,11 +168,17 @@
     }
 
     @Override
-    public List<String> getModelIds() {
+    public List<String> getStableIds() {
         return mModelIds;
     }
 
     @Override
+    public int getPosition(String id) {
+        int position = mModelIds.indexOf(id);
+        return position >= 0 ? position : RecyclerView.NO_POSITION;
+    }
+
+    @Override
     public int getItemViewType(int position) {
         return isDirectory(mEnv.getModel(), position)
                 ? ITEM_TYPE_DIRECTORY
@@ -189,15 +197,4 @@
         }
         return false;
     }
-
-    @Override
-    public void onItemSelectionChanged(String id) {
-        int position = mModelIds.indexOf(id);
-
-        if (position >= 0) {
-            notifyItemChanged(position, SELECTION_CHANGED_MARKER);
-        } else {
-            Log.w(TAG, "Item change notification received for unknown item: " + id);
-        }
-    }
 }
diff --git a/src/com/android/documentsui/dirlist/MouseDragEventInterceptor.java b/src/com/android/documentsui/dirlist/MouseDragEventInterceptor.java
new file mode 100644
index 0000000..fa40c26
--- /dev/null
+++ b/src/com/android/documentsui/dirlist/MouseDragEventInterceptor.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2017 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.documentsui.dirlist;
+
+import static android.support.v4.util.Preconditions.checkArgument;
+
+import android.support.annotation.Nullable;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.OnItemTouchListener;
+import android.view.MotionEvent;
+
+import com.android.documentsui.base.EventHandler;
+import com.android.documentsui.base.Events;
+import com.android.documentsui.selection.BandSelectionHelper;
+import com.android.documentsui.selection.ItemDetailsLookup;
+import com.android.documentsui.selection.TouchEventRouter;
+
+/**
+ * OnItemTouchListener that helps enable support for drag/drop functionality
+ * in DirectoryFragment.
+ *
+ * <p>This class takes an OnItemTouchListener that is presumably the
+ * one provided by {@link BandSelectionHelper#getListener()}, and
+ * is used in conjunction with the {@link TouchEventRouter}.
+ *
+ * <p>See DirectoryFragment for more details on how this is glued
+ * into DocumetnsUI event handling to make the magic happen.
+ */
+class MouseDragEventInterceptor implements OnItemTouchListener {
+
+    private final ItemDetailsLookup mEventDetailsLookup;
+    private final EventHandler<MotionEvent> mMouseDragListener;
+    private final @Nullable OnItemTouchListener mDelegate;
+
+    public MouseDragEventInterceptor(
+            ItemDetailsLookup eventDetailsLookup,
+            EventHandler<MotionEvent> mouseDragListener,
+            @Nullable OnItemTouchListener delegate) {
+
+        checkArgument(eventDetailsLookup != null);
+        checkArgument(mouseDragListener != null);
+
+        mEventDetailsLookup = eventDetailsLookup;
+        mMouseDragListener = mouseDragListener;
+        mDelegate = delegate;
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
+        if (Events.isMouseDragEvent(e) && mEventDetailsLookup.inItemDragRegion(e)) {
+            return mMouseDragListener.accept(e);
+        } else if (mDelegate != null) {
+            return mDelegate.onInterceptTouchEvent(rv, e);
+        }
+        return false;
+    }
+
+    @Override
+    public void onTouchEvent(RecyclerView rv, MotionEvent e) {
+        if (mDelegate != null) {
+            mDelegate.onTouchEvent(rv, e);
+        }
+    }
+
+    @Override
+    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {}
+}
diff --git a/src/com/android/documentsui/dirlist/RefreshHelper.java b/src/com/android/documentsui/dirlist/RefreshHelper.java
new file mode 100644
index 0000000..a1a5662
--- /dev/null
+++ b/src/com/android/documentsui/dirlist/RefreshHelper.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2017 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.documentsui.dirlist;
+
+import static android.support.v4.util.Preconditions.checkState;
+
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.OnItemTouchListener;
+import android.view.MotionEvent;
+
+import com.android.documentsui.base.BooleanConsumer;
+import com.android.documentsui.base.Events;
+
+/**
+ * Class providing support for gluing gesture scaling of the ui into RecyclerView + DocsUI.
+ */
+final class RefreshHelper {
+
+    private final BooleanConsumer mRefreshLayoutEnabler;
+
+    private boolean mAttached;
+
+    public RefreshHelper(BooleanConsumer refreshLayoutEnabler) {
+        mRefreshLayoutEnabler = refreshLayoutEnabler;
+    }
+
+    private boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
+        if (Events.isMouseEvent(e)) {
+            if (Events.isActionDown(e)) {
+                mRefreshLayoutEnabler.accept(false);
+            }
+        } else {
+            // If user has started some gesture while RecyclerView is not at the top, disable
+            // refresh
+            if (Events.isActionDown(e) && rv.computeVerticalScrollOffset() != 0) {
+                mRefreshLayoutEnabler.accept(false);
+            }
+        }
+
+        if (Events.isActionUp(e)) {
+            mRefreshLayoutEnabler.accept(true);
+        }
+
+        return false;
+    }
+
+    private void onTouchEvent(RecyclerView rv, MotionEvent e) {
+        if (Events.isActionUp(e)) {
+            mRefreshLayoutEnabler.accept(true);
+        }
+    }
+
+    void attach(RecyclerView view) {
+        checkState(!mAttached);
+
+        view.addOnItemTouchListener(
+                new OnItemTouchListener() {
+                    @Override
+                    public void onTouchEvent(RecyclerView rv, MotionEvent e) {
+                        RefreshHelper.this.onTouchEvent(rv, e);
+                    }
+
+                    @Override
+                    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
+                        return RefreshHelper.this.onInterceptTouchEvent(rv, e);
+                    }
+
+                    @Override
+                    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {}
+        });
+
+        mAttached = true;
+    }
+}
diff --git a/src/com/android/documentsui/dirlist/RenameDocumentFragment.java b/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
index db9d399..2573448 100644
--- a/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
+++ b/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
@@ -16,7 +16,7 @@
 
 package com.android.documentsui.dirlist;
 
-import static com.android.documentsui.base.Shared.TAG;
+import static com.android.documentsui.base.SharedMinimal.TAG;
 
 import android.app.AlertDialog;
 import android.app.Dialog;
@@ -107,6 +107,7 @@
                         return false;
                     }
                 });
+        mEditText.requestFocus();
         return dialog;
     }
 
diff --git a/src/com/android/documentsui/dirlist/ScaleHelper.java b/src/com/android/documentsui/dirlist/ScaleHelper.java
new file mode 100644
index 0000000..84b939d
--- /dev/null
+++ b/src/com/android/documentsui/dirlist/ScaleHelper.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2017 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.documentsui.dirlist;
+
+import static android.support.v4.util.Preconditions.checkState;
+import static com.android.documentsui.base.SharedMinimal.VERBOSE;
+
+import android.content.Context;
+import android.os.Build;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.OnItemTouchListener;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
+
+import com.android.documentsui.base.Features;
+
+import java.util.function.Consumer;
+
+/**
+ * Class providing support for gluing gesture scaling of the ui into RecyclerView + DocsUI.
+ */
+final class ScaleHelper {
+
+    private static final String TAG = "ScaleHelper";
+
+    private final Context mContext;
+    private final Features mFeatures;
+    private final Consumer<Float> mScaleCallback;
+
+    private @Nullable ScaleGestureDetector mScaleDetector;
+
+    public ScaleHelper(Context context, Features features, Consumer<Float> scaleCallback) {
+        mContext = context;
+        mFeatures = features;
+        mScaleCallback = scaleCallback;
+    }
+
+    private boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
+        // Checking feature is deferred to runtime so the feature can be enabled
+        // after this class has been setup.
+        if (mFeatures.isGestureScaleEnabled() && mScaleDetector != null) {
+            mScaleDetector.onTouchEvent(e);
+        }
+
+        return false;
+    }
+
+    void attach(RecyclerView view) {
+        checkState(Build.IS_DEBUGGABLE);
+        checkState(mScaleDetector == null);
+
+        mScaleDetector = new ScaleGestureDetector(
+            mContext,
+            new ScaleGestureDetector.SimpleOnScaleGestureListener() {
+                @Override
+                public boolean onScale(ScaleGestureDetector detector) {
+                    if (VERBOSE) Log.v(TAG,
+                            "Received scale event: " + detector.getScaleFactor());
+                    mScaleCallback.accept(detector.getScaleFactor());
+                    return true;
+                }
+            });
+
+        view.addOnItemTouchListener(
+                new OnItemTouchListener() {
+                    @Override
+                    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
+                        return ScaleHelper.this.onInterceptTouchEvent(rv, e);
+                    }
+
+                    @Override
+                    public void onTouchEvent(RecyclerView rv, MotionEvent e) {}
+
+                    @Override
+                    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {}
+        });
+    }
+}
diff --git a/src/com/android/documentsui/selection/SelectionMetadata.java b/src/com/android/documentsui/dirlist/SelectionMetadata.java
similarity index 89%
rename from src/com/android/documentsui/selection/SelectionMetadata.java
rename to src/com/android/documentsui/dirlist/SelectionMetadata.java
index df0f1d6..3ac3a07 100644
--- a/src/com/android/documentsui/selection/SelectionMetadata.java
+++ b/src/com/android/documentsui/dirlist/SelectionMetadata.java
@@ -14,14 +14,11 @@
  * limitations under the License.
  */
 
-package com.android.documentsui.selection;
+package com.android.documentsui.dirlist;
 
 import static com.android.documentsui.base.DocumentInfo.getCursorInt;
 import static com.android.documentsui.base.DocumentInfo.getCursorString;
 
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.pm.ProviderInfo;
 import android.database.Cursor;
 import android.provider.DocumentsContract.Document;
 import android.util.Log;
@@ -30,14 +27,19 @@
 import com.android.documentsui.archives.ArchivesProvider;
 import com.android.documentsui.base.MimeTypes;
 import com.android.documentsui.roots.RootCursorWrapper;
+import com.android.documentsui.selection.SelectionHelper.SelectionObserver;
 
 import java.util.function.Function;
 
 /**
- * A class that holds metadata
+ * A class that aggregates document metadata describing the selection. It can answer questions
+ * like: Can the selection be deleted? and Does the selection contain a folder?
+ *
+ * <p>By collecting information in real-time as the selection changes the need to
+ * traverse the entire selection in order to answer questions is eliminated.
  */
-public class SelectionMetadata
-        implements MenuManager.SelectionDetails, SelectionManager.ItemCallback {
+public class SelectionMetadata extends SelectionObserver
+        implements MenuManager.SelectionDetails {
 
     private static final String TAG = "SelectionMetadata";
     private final static int FLAG_CAN_DELETE =
diff --git a/src/com/android/documentsui/dirlist/UserInputHandler.java b/src/com/android/documentsui/dirlist/UserInputHandler.java
deleted file mode 100644
index f33284b..0000000
--- a/src/com/android/documentsui/dirlist/UserInputHandler.java
+++ /dev/null
@@ -1,551 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.dirlist;
-
-import static com.android.documentsui.base.Shared.DEBUG;
-import static com.android.documentsui.base.Shared.VERBOSE;
-
-import android.support.annotation.VisibleForTesting;
-import android.util.Log;
-import android.view.GestureDetector;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-
-import com.android.documentsui.ActionHandler;
-import com.android.documentsui.base.EventHandler;
-import com.android.documentsui.base.Events;
-import com.android.documentsui.base.Events.InputEvent;
-import com.android.documentsui.selection.SelectionManager;
-
-import java.util.function.Function;
-import java.util.function.Predicate;
-
-import javax.annotation.Nullable;
-
-/**
- * Grand unified-ish gesture/event listener for items in the directory list.
- */
-public final class UserInputHandler<T extends InputEvent>
-        extends GestureDetector.SimpleOnGestureListener
-        implements DocumentHolder.KeyboardEventListener {
-
-    private static final String TAG = "UserInputHandler";
-
-    private ActionHandler mActions;
-    private final FocusHandler mFocusHandler;
-    private final SelectionManager mSelectionMgr;
-    private final Function<MotionEvent, T> mEventConverter;
-    private final Predicate<DocumentDetails> mSelectable;
-
-    private final EventHandler<InputEvent> mContextMenuClickHandler;
-
-    private final EventHandler<InputEvent> mTouchDragListener;
-    private final EventHandler<InputEvent> mGestureSelectHandler;
-    private final Runnable mPerformHapticFeedback;
-
-    private final TouchInputDelegate mTouchDelegate;
-    private final MouseInputDelegate mMouseDelegate;
-    private final KeyInputHandler mKeyListener;
-
-    public UserInputHandler(
-            ActionHandler actions,
-            FocusHandler focusHandler,
-            SelectionManager selectionMgr,
-            Function<MotionEvent, T> eventConverter,
-            Predicate<DocumentDetails> selectable,
-            EventHandler<InputEvent> contextMenuClickHandler,
-            EventHandler<InputEvent> touchDragListener,
-            EventHandler<InputEvent> gestureSelectHandler,
-            Runnable performHapticFeedback) {
-
-        mActions = actions;
-        mFocusHandler = focusHandler;
-        mSelectionMgr = selectionMgr;
-        mEventConverter = eventConverter;
-        mSelectable = selectable;
-        mContextMenuClickHandler = contextMenuClickHandler;
-        mTouchDragListener = touchDragListener;
-        mGestureSelectHandler = gestureSelectHandler;
-        mPerformHapticFeedback = performHapticFeedback;
-
-        mTouchDelegate = new TouchInputDelegate();
-        mMouseDelegate = new MouseInputDelegate();
-        mKeyListener = new KeyInputHandler();
-    }
-
-    @Override
-    public boolean onDown(MotionEvent e) {
-        try (T event = mEventConverter.apply(e)) {
-            return onDown(event);
-        }
-    }
-
-    @VisibleForTesting
-    boolean onDown(T event) {
-        return event.isMouseEvent()
-                ? mMouseDelegate.onDown(event)
-                : mTouchDelegate.onDown(event);
-    }
-
-    @Override
-    public boolean onScroll(MotionEvent e1, MotionEvent e2,
-            float distanceX, float distanceY) {
-        try (T event = mEventConverter.apply(e2)) {
-            return onScroll(event);
-        }
-    }
-
-    @VisibleForTesting
-    boolean onScroll(T event) {
-        return event.isMouseEvent()
-                ? mMouseDelegate.onScroll(event)
-                : mTouchDelegate.onScroll(event);
-    }
-
-    @Override
-    public boolean onSingleTapUp(MotionEvent e) {
-        try (T event = mEventConverter.apply(e)) {
-            return onSingleTapUp(event);
-        }
-    }
-
-    @VisibleForTesting
-    boolean onSingleTapUp(T event) {
-        return event.isMouseEvent()
-                ? mMouseDelegate.onSingleTapUp(event)
-                : mTouchDelegate.onSingleTapUp(event);
-    }
-
-    @Override
-    public boolean onSingleTapConfirmed(MotionEvent e) {
-        try (T event = mEventConverter.apply(e)) {
-            return onSingleTapConfirmed(event);
-        }
-    }
-
-    @VisibleForTesting
-    boolean onSingleTapConfirmed(T event) {
-        return event.isMouseEvent()
-                ? mMouseDelegate.onSingleTapConfirmed(event)
-                : mTouchDelegate.onSingleTapConfirmed(event);
-    }
-
-    @Override
-    public boolean onDoubleTap(MotionEvent e) {
-        try (T event = mEventConverter.apply(e)) {
-            return onDoubleTap(event);
-        }
-    }
-
-    @VisibleForTesting
-    boolean onDoubleTap(T event) {
-        return event.isMouseEvent()
-                ? mMouseDelegate.onDoubleTap(event)
-                : mTouchDelegate.onDoubleTap(event);
-    }
-
-    @Override
-    public void onLongPress(MotionEvent e) {
-        try (T event = mEventConverter.apply(e)) {
-            onLongPress(event);
-        }
-    }
-
-    @VisibleForTesting
-    void onLongPress(T event) {
-        if (event.isMouseEvent()) {
-            mMouseDelegate.onLongPress(event);
-        } else {
-            mTouchDelegate.onLongPress(event);
-        }
-    }
-
-    // Only events from RecyclerView are fed into UserInputHandler#onDown.
-    // ListeningGestureDetector#onTouch directly calls this method to support context menu in empty
-    // view
-    boolean onRightClick(MotionEvent e) {
-        try (T event = mEventConverter.apply(e)) {
-            return mMouseDelegate.onRightClick(event);
-        }
-    }
-
-    @Override
-    public boolean onKey(DocumentHolder doc, int keyCode, KeyEvent event) {
-        return mKeyListener.onKey(doc, keyCode, event);
-    }
-
-    private boolean selectDocument(DocumentDetails doc) {
-        assert(doc != null);
-        assert(doc.hasModelId());
-        mSelectionMgr.toggleSelection(doc.getModelId());
-        mSelectionMgr.setSelectionRangeBegin(doc.getAdapterPosition());
-
-        // we set the focus on this doc so it will be the origin for keyboard events or shift+clicks
-        // if there is only a single item selected, otherwise clear focus
-        if (mSelectionMgr.getSelection().size() == 1) {
-            mFocusHandler.focusDocument(doc.getModelId());
-        } else {
-            mFocusHandler.clearFocus();
-        }
-        return true;
-    }
-
-    private boolean focusDocument(DocumentDetails doc) {
-        assert(doc != null);
-        assert(doc.hasModelId());
-
-        mSelectionMgr.clearSelection();
-        mFocusHandler.focusDocument(doc.getModelId());
-        return true;
-    }
-
-    private void extendSelectionRange(DocumentDetails doc) {
-        mSelectionMgr.snapRangeSelection(doc.getAdapterPosition());
-        mFocusHandler.focusDocument(doc.getModelId());
-    }
-
-    boolean isRangeExtension(T event) {
-        return event.isShiftKeyDown() && mSelectionMgr.isRangeSelectionActive();
-    }
-
-    private boolean shouldClearSelection(T event, DocumentDetails doc) {
-        return !event.isCtrlKeyDown()
-                && !doc.isInSelectionHotspot(event)
-                && !doc.isOverDocIcon(event)
-                && !isSelected(doc);
-    }
-
-    private boolean isSelected(DocumentDetails doc) {
-        return mSelectionMgr.getSelection().contains(doc.getModelId());
-    }
-
-    private static final String TTAG = "TouchInputDelegate";
-    private final class TouchInputDelegate {
-
-        boolean onDown(T event) {
-            if (VERBOSE) Log.v(TTAG, "Delegated onDown event.");
-            return false;
-        }
-
-        // Don't consume so the RecyclerView will get the event and will get touch-based scrolling
-        boolean onScroll(T event) {
-            if (VERBOSE) Log.v(TTAG, "Delegated onScroll event.");
-            return false;
-        }
-
-        boolean onSingleTapUp(T event) {
-            if (VERBOSE) Log.v(TTAG, "Delegated onSingleTapUp event.");
-            if (!event.isOverModelItem()) {
-                if (DEBUG) Log.d(TTAG, "Tap not associated w/ model item. Clearing selection.");
-                mSelectionMgr.clearSelection();
-                return false;
-            }
-
-            DocumentDetails doc = event.getDocumentDetails();
-            if (mSelectionMgr.hasSelection()) {
-                if (isRangeExtension(event)) {
-                    extendSelectionRange(doc);
-                } else if (mSelectionMgr.getSelection().contains(doc.getModelId())) {
-                    mSelectionMgr.toggleSelection(doc.getModelId());
-                } else {
-                    selectDocument(doc);
-                }
-
-                return true;
-            }
-
-            // Touch events select if they occur in the selection hotspot,
-            // otherwise they activate.
-            return doc.isInSelectionHotspot(event)
-                    ? selectDocument(doc)
-                    : mActions.openDocument(doc, ActionHandler.VIEW_TYPE_PREVIEW,
-                            ActionHandler.VIEW_TYPE_REGULAR);
-        }
-
-        boolean onSingleTapConfirmed(T event) {
-            if (VERBOSE) Log.v(TTAG, "Delegated onSingleTapConfirmed event.");
-            return false;
-        }
-
-        boolean onDoubleTap(T event) {
-            if (VERBOSE) Log.v(TTAG, "Delegated onDoubleTap event.");
-            return false;
-        }
-
-        final void onLongPress(T event) {
-            if (VERBOSE) Log.v(TTAG, "Delegated onLongPress event.");
-            if (!event.isOverModelItem()) {
-                if (DEBUG) Log.d(TTAG, "Ignoring LongPress on non-model-backed item.");
-                return;
-            }
-
-            DocumentDetails doc = event.getDocumentDetails();
-            boolean handled = false;
-            if (isRangeExtension(event)) {
-                extendSelectionRange(doc);
-                handled = true;
-            } else {
-                if (!mSelectionMgr.getSelection().contains(doc.getModelId())) {
-                    selectDocument(doc);
-                    // If we cannot select it, we didn't apply anchoring - therefore should not
-                    // start gesture selection
-                    if (mSelectable.test(doc)) {
-                        mGestureSelectHandler.accept(event);
-                        handled = true;
-                    }
-                } else {
-                    // We only initiate drag and drop on long press for touch to allow regular
-                    // touch-based scrolling
-                    mTouchDragListener.accept(event);
-                    handled = true;
-                }
-            }
-            if (handled) {
-                mPerformHapticFeedback.run();
-            }
-        }
-    }
-
-    private static final String MTAG = "MouseInputDelegate";
-    private final class MouseInputDelegate {
-        // The event has been handled in onSingleTapUp
-        private boolean mHandledTapUp;
-        // true when the previous event has consumed a right click motion event
-        private boolean mHandledOnDown;
-
-        boolean onDown(T event) {
-            if (VERBOSE) Log.v(MTAG, "Delegated onDown event.");
-            if (event.isSecondaryButtonPressed()
-                    || (event.isAltKeyDown() && event.isPrimaryButtonPressed())) {
-                mHandledOnDown = true;
-                return onRightClick(event);
-            }
-
-            return false;
-        }
-
-        // Don't scroll content window in response to mouse drag
-        boolean onScroll(T event) {
-            if (VERBOSE) Log.v(MTAG, "Delegated onScroll event.");
-            // If it's two-finger trackpad scrolling, we want to scroll
-            return !event.isTouchpadScroll();
-        }
-
-        boolean onSingleTapUp(T event) {
-            if (VERBOSE) Log.v(MTAG, "Delegated onSingleTapUp event.");
-
-            // See b/27377794. Since we don't get a button state back from UP events, we have to
-            // explicitly save this state to know whether something was previously handled by
-            // DOWN events or not.
-            if (mHandledOnDown) {
-                if (VERBOSE) Log.v(MTAG, "Ignoring onSingleTapUp, previously handled in onDown.");
-                mHandledOnDown = false;
-                return false;
-            }
-
-            if (!event.isOverModelItem()) {
-                if (DEBUG) Log.d(MTAG, "Tap not associated w/ model item. Clearing selection.");
-                mSelectionMgr.clearSelection();
-                mFocusHandler.clearFocus();
-                return false;
-            }
-
-            if (event.isTertiaryButtonPressed()) {
-                if (DEBUG) Log.d(MTAG, "Ignoring middle click");
-                return false;
-            }
-
-            DocumentDetails doc = event.getDocumentDetails();
-            if (mSelectionMgr.hasSelection()) {
-                if (isRangeExtension(event)) {
-                    extendSelectionRange(doc);
-                } else {
-                    if (shouldClearSelection(event, doc)) {
-                        mSelectionMgr.clearSelection();
-                    }
-                    if (isSelected(doc)) {
-                        mSelectionMgr.toggleSelection(doc.getModelId());
-                        mFocusHandler.clearFocus();
-                    } else {
-                        selectOrFocusItem(event);
-                    }
-                }
-                mHandledTapUp = true;
-                return true;
-            }
-
-            return false;
-        }
-
-        boolean onSingleTapConfirmed(T event) {
-            if (VERBOSE) Log.v(MTAG, "Delegated onSingleTapConfirmed event.");
-            if (mHandledTapUp) {
-                if (VERBOSE) Log.v(MTAG, "Ignoring onSingleTapConfirmed, previously handled in onSingleTapUp.");
-                mHandledTapUp = false;
-                return false;
-            }
-
-            if (mSelectionMgr.hasSelection()) {
-                return false;  // should have been handled by onSingleTapUp.
-            }
-
-            if (!event.isOverItem()) {
-                if (DEBUG) Log.d(MTAG, "Ignoring Confirmed Tap on non-item.");
-                return false;
-            }
-
-            if (event.isTertiaryButtonPressed()) {
-                if (DEBUG) Log.d(MTAG, "Ignoring middle click");
-                return false;
-            }
-
-            @Nullable DocumentDetails doc = event.getDocumentDetails();
-            if (doc == null || !doc.hasModelId()) {
-                Log.w(MTAG, "Ignoring Confirmed Tap. No document details associated w/ event.");
-                return false;
-            }
-
-            if (mFocusHandler.hasFocusedItem() && event.isShiftKeyDown()) {
-                mSelectionMgr.formNewSelectionRange(mFocusHandler.getFocusPosition(),
-                        doc.getAdapterPosition());
-            } else {
-                selectOrFocusItem(event);
-            }
-            return true;
-        }
-
-        boolean onDoubleTap(T event) {
-            if (VERBOSE) Log.v(MTAG, "Delegated onDoubleTap event.");
-            mHandledTapUp = false;
-
-            if (!event.isOverModelItem()) {
-                if (DEBUG) Log.d(MTAG, "Ignoring DoubleTap on non-model-backed item.");
-                return false;
-            }
-
-            if (event.isTertiaryButtonPressed()) {
-                if (DEBUG) Log.d(MTAG, "Ignoring middle click");
-                return false;
-            }
-
-            DocumentDetails doc = event.getDocumentDetails();
-            return mActions.openDocument(doc, ActionHandler.VIEW_TYPE_REGULAR,
-                    ActionHandler.VIEW_TYPE_PREVIEW);
-        }
-
-        final void onLongPress(T event) {
-            if (VERBOSE) Log.v(MTAG, "Delegated onLongPress event.");
-            return;
-        }
-
-        private boolean onRightClick(T event) {
-            if (VERBOSE) Log.v(MTAG, "Delegated onRightClick event.");
-            if (event.isOverModelItem()) {
-                DocumentDetails doc = event.getDocumentDetails();
-                if (!mSelectionMgr.getSelection().contains(doc.getModelId())) {
-                    mSelectionMgr.clearSelection();
-                    selectDocument(doc);
-                }
-            }
-
-            // We always delegate final handling of the event,
-            // since the handler might want to show a context menu
-            // in an empty area or some other weirdo view.
-            return mContextMenuClickHandler.accept(event);
-        }
-
-        private void selectOrFocusItem(T event) {
-            if (event.isOverDocIcon() || event.isCtrlKeyDown()) {
-                selectDocument(event.getDocumentDetails());
-            } else {
-                focusDocument(event.getDocumentDetails());
-            }
-        }
-    }
-
-    private final class KeyInputHandler {
-        // TODO: Refactor FocusManager to depend only on DocumentDetails so we can eliminate
-        // difficult to test dependency on DocumentHolder.
-
-        boolean onKey(@Nullable DocumentHolder doc, int keyCode, KeyEvent event) {
-            // Only handle key-down events. This is simpler, consistent with most other UIs, and
-            // enables the handling of repeated key events from holding down a key.
-            if (event.getAction() != KeyEvent.ACTION_DOWN) {
-                return false;
-            }
-
-            // Ignore tab key events.  Those should be handled by the top-level key handler.
-            if (keyCode == KeyEvent.KEYCODE_TAB) {
-                return false;
-            }
-
-            // Ignore events sent to Addon Holders.
-            if (doc != null) {
-                int itemType = doc.getItemViewType();
-                if (itemType == DocumentsAdapter.ITEM_TYPE_HEADER_MESSAGE
-                        || itemType == DocumentsAdapter.ITEM_TYPE_INFLATED_MESSAGE
-                        || itemType == DocumentsAdapter.ITEM_TYPE_SECTION_BREAK) {
-                    return false;
-                }
-            }
-
-            if (mFocusHandler.handleKey(doc, keyCode, event)) {
-                // Handle range selection adjustments. Extending the selection will adjust the
-                // bounds of the in-progress range selection. Each time an unshifted navigation
-                // event is received, the range selection is restarted.
-                if (shouldExtendSelection(doc, event)) {
-                    if (!mSelectionMgr.isRangeSelectionActive()) {
-                        // Start a range selection if one isn't active
-                        mSelectionMgr.startRangeSelection(doc.getAdapterPosition());
-                    }
-                    mSelectionMgr.snapRangeSelection(mFocusHandler.getFocusPosition());
-                } else {
-                    mSelectionMgr.endRangeSelection();
-                    mSelectionMgr.clearSelection();
-                }
-                return true;
-            }
-
-            // we don't yet have a mechanism to handle opening/previewing multiple documents at once
-            if (mSelectionMgr.getSelection().size() > 1) {
-                return false;
-            }
-
-            // Handle enter key events
-            switch (keyCode) {
-                case KeyEvent.KEYCODE_ENTER:
-                case KeyEvent.KEYCODE_DPAD_CENTER:
-                case KeyEvent.KEYCODE_BUTTON_A:
-                    return mActions.openDocument(doc, ActionHandler.VIEW_TYPE_REGULAR,
-                            ActionHandler.VIEW_TYPE_PREVIEW);
-                case KeyEvent.KEYCODE_SPACE:
-                    return mActions.openDocument(doc, ActionHandler.VIEW_TYPE_PREVIEW,
-                            ActionHandler.VIEW_TYPE_NONE);
-            }
-
-            return false;
-        }
-
-        private boolean shouldExtendSelection(DocumentDetails doc, KeyEvent event) {
-            if (!Events.isNavigationKeyCode(event.getKeyCode()) || !event.isShiftPressed()) {
-                return false;
-            }
-
-            return mSelectable.test(doc);
-        }
-    }
-}
diff --git a/src/com/android/documentsui/files/ActionHandler.java b/src/com/android/documentsui/files/ActionHandler.java
index 922f0c0..6b5a0a2 100644
--- a/src/com/android/documentsui/files/ActionHandler.java
+++ b/src/com/android/documentsui/files/ActionHandler.java
@@ -16,7 +16,7 @@
 
 package com.android.documentsui.files;
 
-import static com.android.documentsui.base.Shared.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
 
 import android.app.Activity;
 import android.content.ActivityNotFoundException;
@@ -25,7 +25,9 @@
 import android.content.ContentResolver;
 import android.content.Intent;
 import android.net.Uri;
+import android.os.Build;
 import android.provider.DocumentsContract;
+import android.text.TextUtils;
 import android.util.Log;
 import android.view.DragEvent;
 
@@ -56,12 +58,13 @@
 import com.android.documentsui.clipping.DocumentClipper;
 import com.android.documentsui.clipping.UrisSupplier;
 import com.android.documentsui.dirlist.AnimationView;
-import com.android.documentsui.dirlist.DocumentDetails;
 import com.android.documentsui.files.ActionHandler.Addons;
 import com.android.documentsui.inspector.InspectorActivity;
 import com.android.documentsui.queries.SearchViewManager;
 import com.android.documentsui.roots.ProvidersAccess;
+import com.android.documentsui.selection.MutableSelection;
 import com.android.documentsui.selection.Selection;
+import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
 import com.android.documentsui.services.FileOperation;
 import com.android.documentsui.services.FileOperationService;
 import com.android.documentsui.services.FileOperations;
@@ -187,12 +190,12 @@
     }
 
     @Override
-    public boolean openDocument(DocumentDetails details, @ViewType int type,
+    public boolean openItem(ItemDetails details, @ViewType int type,
             @ViewType int fallback) {
-        DocumentInfo doc = mModel.getDocument(details.getModelId());
+        DocumentInfo doc = mModel.getDocument(details.getStableId());
         if (doc == null) {
             Log.w(TAG,
-                    "Can't view item. No Document available for modeId: " + details.getModelId());
+                    "Can't view item. No Document available for modeId: " + details.getStableId());
             return false;
         }
 
@@ -218,7 +221,7 @@
     }
 
     private Selection getSelectedOrFocused() {
-        final Selection selection = this.getStableSelection();
+        final MutableSelection selection = this.getStableSelection();
         if (selection.isEmpty()) {
             String focusModelId = mFocusHandler.getFocusModelId();
             if (focusModelId != null) {
@@ -508,6 +511,14 @@
             return;
         }
 
+        // For APKs, even if the type is preview, we send an ACTION_VIEW intent to allow
+        // PackageManager to install it.  This allows users to install APKs from any root.
+        // The Downloads special case is handled above in #manageDocument.
+        if (MimeTypes.isApkType(doc.mimeType)) {
+            viewDocument(doc);
+            return;
+        }
+
         switch (type) {
           case VIEW_TYPE_REGULAR:
             if (viewDocument(doc)) {
@@ -678,11 +689,26 @@
     public void showInspector(DocumentInfo doc) {
         Metrics.logUserAction(mActivity, Metrics.USER_ACTION_INSPECTOR);
         Intent intent = new Intent(mActivity, InspectorActivity.class);
+        intent.setData(doc.derivedUri);
+
+        // permit the display of debug info about the file.
         intent.putExtra(
                 Shared.EXTRA_SHOW_DEBUG,
-                mFeatures.isDebugSupportEnabled()
-                        || DebugFlags.getDocumentDetailsEnabled());
-        intent.setData(doc.derivedUri);
+                mFeatures.isDebugSupportEnabled() &&
+                        (Build.IS_DEBUGGABLE || DebugFlags.getDocumentDetailsEnabled()));
+
+        // The "root document" (top level folder in a root) don't usually have a
+        // human friendly display name. That's because we've never shown the root
+        // folder's name to anyone.
+        // For that reason when the doc being inspected is the root folder,
+        // we override the displayName of the doc w/ the Root's name instead.
+        // The Root's name is shown to the user in the sidebar.
+        if (doc.isDirectory() && mState.stack.size() == 1 && mState.stack.get(0).equals(doc)) {
+            RootInfo root = mActivity.getCurrentRoot();
+            // Recents root title isn't defined, but inspector is disabled for recents root folder.
+            assert !TextUtils.isEmpty(root.title);
+            intent.putExtra(Intent.EXTRA_TITLE, root.title);
+        }
         mActivity.startActivity(intent);
     }
 
diff --git a/src/com/android/documentsui/files/FilesActivity.java b/src/com/android/documentsui/files/FilesActivity.java
index 50ba2ff..f17e175 100644
--- a/src/com/android/documentsui/files/FilesActivity.java
+++ b/src/com/android/documentsui/files/FilesActivity.java
@@ -21,14 +21,13 @@
 import android.app.ActivityManager.TaskDescription;
 import android.app.FragmentManager;
 import android.content.Intent;
-import android.content.Context;
-import android.graphics.drawable.AdaptiveIconDrawable;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
 import android.support.annotation.CallSuper;
@@ -39,6 +38,7 @@
 
 import com.android.documentsui.ActionModeController;
 import com.android.documentsui.BaseActivity;
+import com.android.documentsui.DocsSelectionHelper;
 import com.android.documentsui.DocumentsApplication;
 import com.android.documentsui.FocusManager;
 import com.android.documentsui.Injector;
@@ -57,7 +57,6 @@
 import com.android.documentsui.dirlist.AnimationView.AnimationType;
 import com.android.documentsui.dirlist.DirectoryFragment;
 import com.android.documentsui.prefs.ScopedPreferences;
-import com.android.documentsui.selection.SelectionManager;
 import com.android.documentsui.services.FileOperationService;
 import com.android.documentsui.sidebar.RootsFragment;
 import com.android.documentsui.ui.DialogController;
@@ -105,7 +104,7 @@
         super.onCreate(icicle);
 
         DocumentClipper clipper = DocumentsApplication.getDocumentClipper(this);
-        mInjector.selectionMgr = new SelectionManager(SelectionManager.MODE_MULTIPLE);
+        mInjector.selectionMgr = DocsSelectionHelper.createMultiSelect();
 
         mInjector.focusManager = new FocusManager(
                 mInjector.features,
@@ -352,6 +351,9 @@
             case R.id.option_menu_select_all:
                 mInjector.actions.selectAllFiles();
                 break;
+            case R.id.option_menu_inspect:
+                mInjector.actions.showInspector(getCurrentDirectory());
+                break;
             default:
                 return super.onOptionsItemSelected(item);
         }
@@ -396,6 +398,11 @@
         mInjector.focusManager.focusDocument(doc.documentId);
     }
 
+    @Override
+    protected boolean canInspectDirectory() {
+        return getCurrentDirectory() != null && mInjector.getModel().doc != null;
+    }
+
     @CallSuper
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
diff --git a/src/com/android/documentsui/files/LauncherActivity.java b/src/com/android/documentsui/files/LauncherActivity.java
index 705d968..f14be5a 100644
--- a/src/com/android/documentsui/files/LauncherActivity.java
+++ b/src/com/android/documentsui/files/LauncherActivity.java
@@ -16,7 +16,7 @@
 
 package com.android.documentsui.files;
 
-import static com.android.documentsui.base.Shared.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
 
 import android.app.Activity;
 import android.app.ActivityManager;
diff --git a/src/com/android/documentsui/files/MenuManager.java b/src/com/android/documentsui/files/MenuManager.java
index 4754c6d..e2f39d5 100644
--- a/src/com/android/documentsui/files/MenuManager.java
+++ b/src/com/android/documentsui/files/MenuManager.java
@@ -29,23 +29,23 @@
 import android.view.View;
 
 import com.android.documentsui.R;
+import com.android.documentsui.MenuManager.SelectionDetails;
 import com.android.documentsui.base.DocumentInfo;
 import com.android.documentsui.base.Features;
 import com.android.documentsui.base.Lookup;
 import com.android.documentsui.base.RootInfo;
 import com.android.documentsui.base.State;
 import com.android.documentsui.queries.SearchViewManager;
-import com.android.documentsui.selection.SelectionManager;
+import com.android.documentsui.selection.SelectionHelper;
 
 import java.util.List;
-import java.util.function.Function;
 import java.util.function.IntFunction;
 
 public final class MenuManager extends com.android.documentsui.MenuManager {
 
     private final Features mFeatures;
     private final Context mContext;
-    private final SelectionManager mSelectionManager;
+    private final SelectionHelper mSelectionManager;
     private final Lookup<String, Uri> mUriLookup;
     private final Lookup<String, String> mAppNameLookup;
 
@@ -55,10 +55,12 @@
             State displayState,
             DirectoryDetails dirDetails,
             Context context,
-            SelectionManager selectionManager,
+            SelectionHelper selectionManager,
             Lookup<String, String> appNameLookup,
             Lookup<String, Uri> uriLookup) {
+
         super(searchManager, displayState, dirDetails);
+
         mFeatures = features;
         mContext = context;
         mSelectionManager = selectionManager;
@@ -265,10 +267,17 @@
     }
 
     @Override
-    protected void updateInspector(MenuItem properties, SelectionDetails selectionDetails) {
+    protected void updateInspect(MenuItem inspect) {
         boolean visible = mFeatures.isInspectorEnabled();
-        properties.setVisible(visible);
-        properties.setEnabled(visible && selectionDetails.size() == 1);
+        inspect.setVisible(visible);
+        inspect.setEnabled(visible && mDirDetails.canInspectDirectory());
+    }
+
+    @Override
+    protected void updateInspect(MenuItem inspect, SelectionDetails selectionDetails) {
+        boolean visible = mFeatures.isInspectorEnabled();
+        inspect.setVisible(visible);
+        inspect.setEnabled(visible && selectionDetails.size() <= 1);
     }
 
     @Override
diff --git a/src/com/android/documentsui/files/QuickViewIntentBuilder.java b/src/com/android/documentsui/files/QuickViewIntentBuilder.java
index 7eef89a..0226146 100644
--- a/src/com/android/documentsui/files/QuickViewIntentBuilder.java
+++ b/src/com/android/documentsui/files/QuickViewIntentBuilder.java
@@ -17,7 +17,7 @@
 package com.android.documentsui.files;
 
 import static com.android.documentsui.base.DocumentInfo.getCursorString;
-import static com.android.documentsui.base.Shared.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
 import static com.android.documentsui.base.Shared.MAX_DOCS_IN_INTENT;
 
 import android.content.ClipData;
@@ -62,6 +62,7 @@
     private static final String[] FULL_FEATURES = {
             QuickViewConstants.FEATURE_VIEW,
             QuickViewConstants.FEATURE_EDIT,
+            QuickViewConstants.FEATURE_DELETE,
             QuickViewConstants.FEATURE_SEND,
             QuickViewConstants.FEATURE_DOWNLOAD,
             QuickViewConstants.FEATURE_PRINT
diff --git a/src/com/android/documentsui/inspector/DateUtils.java b/src/com/android/documentsui/inspector/DateUtils.java
new file mode 100644
index 0000000..7e4901e
--- /dev/null
+++ b/src/com/android/documentsui/inspector/DateUtils.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 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.documentsui.inspector;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.text.format.DateFormat;
+
+import com.android.documentsui.R;
+
+import java.util.Locale;
+
+/**
+ * Helper methods for dealing with dates.
+ */
+final class DateUtils {
+    /**
+     * This small helper method combines two different DateFormat subclasses in order to format
+     * both the date and the time based on user locale.
+     * @param date Unix timestamp
+     * @return formatted String of date
+     */
+    static String formatDate(Context context, long date) {
+        Resources res = context.getResources();
+        int formatRes = DateFormat.is24HourFormat(context)
+                ? R.string.datetime_format_24
+                : R.string.datetime_format_12;
+        String format = DateFormat.getBestDateTimePattern(
+                Locale.getDefault(),
+                res.getString(formatRes));
+        return DateFormat.format(format, date).toString();
+    }
+}
diff --git a/src/com/android/documentsui/inspector/DebugView.java b/src/com/android/documentsui/inspector/DebugView.java
index 581e754..03427e5 100644
--- a/src/com/android/documentsui/inspector/DebugView.java
+++ b/src/com/android/documentsui/inspector/DebugView.java
@@ -15,18 +15,38 @@
  */
 package com.android.documentsui.inspector;
 
+import android.annotation.StringRes;
 import android.content.Context;
+import android.content.res.Resources;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.provider.DocumentsContract;
 import android.util.AttributeSet;
+import android.widget.TextView;
 
 import com.android.documentsui.R;
 import com.android.documentsui.base.DocumentInfo;
+import com.android.documentsui.base.DummyLookup;
+import com.android.documentsui.base.Lookup;
+import com.android.documentsui.inspector.InspectorController.DebugDisplay;
 
-import java.util.function.Consumer;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Executor;
 
 /**
- * Organizes and Displays the basic details about a file
+ * Organizes and Displays the debug information about a file. This view
+ * should only be made visible when build is debuggable and system policies
+ * allow debug "stuff".
  */
-public class DebugView extends TableView implements Consumer<DocumentInfo> {
+public class DebugView extends TableView implements DebugDisplay {
+
+    private final Context mContext;
+    private final Resources mRes;
+    private Lookup<String, Executor> mExecutors = new DummyLookup<>();
 
     public DebugView(Context context) {
         this(context, null);
@@ -38,29 +58,88 @@
 
     public DebugView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
+        mContext = context;
+        mRes = context.getResources();
+    }
+
+    void init(Lookup<String, Executor> executors) {
+        assert executors != null;
+        setBackgroundColor(0xFFFFFFFF);  // it's just debug. We do what we want!
+        mExecutors = executors;
     }
 
     @Override
     public void accept(DocumentInfo info) {
-        setTitle(this, R.string.inspector_debug_section);
+        setTitle(R.string.inspector_debug_section, false);
 
-        put("Content uri", info.derivedUri);
-        put("Document id", info.documentId);
-        put("Mimetype: ", info.mimeType);
-        put("Is archive", info.isArchive());
-        put("Is container", info.isContainer());
-        put("Is partial", info.isPartial());
-        put("Is virtual", info.isVirtual());
-        put("Supports create", info.isCreateSupported());
-        put("Supports delete", info.isDeleteSupported());
-        put("Supports rename", info.isRenameSupported());
-        put("Supports settings", info.isSettingsSupported());
-        put("Supports thumbnail", info.isThumbnailSupported());
-        put("Supports weblink", info.isWeblinkSupported());
-        put("Supports write", info.isWriteSupported());
+        put(R.string.debug_content_uri, info.derivedUri.toString());
+        put(R.string.debug_document_id, info.documentId);
+        put(R.string.debug_raw_mimetype, info.mimeType);
+        put(R.string.debug_stream_types, "-");
+        put(R.string.debug_raw_size, NumberFormat.getInstance().format(info.size));
+        put(R.string.debug_is_archive, info.isArchive());
+        put(R.string.debug_is_container, info.isContainer());
+        put(R.string.debug_is_partial, info.isPartial());
+        put(R.string.debug_is_virtual, info.isVirtual());
+        put(R.string.debug_supports_create, info.isCreateSupported());
+        put(R.string.debug_supports_delete, info.isDeleteSupported());
+        put(R.string.debug_supports_metadata, info.isMetadataSupported());
+        put(R.string.debug_supports_remove, info.isRemoveSupported());
+        put(R.string.debug_supports_rename, info.isRenameSupported());
+        put(R.string.debug_supports_settings, info.isSettingsSupported());
+        put(R.string.debug_supports_thumbnail, info.isThumbnailSupported());
+        put(R.string.debug_supports_weblink, info.isWeblinkSupported());
+        put(R.string.debug_supports_write, info.isWriteSupported());
+
+        // Load Document stream types of the file. For virtual files, this should be
+        // something other than the primary type of the file.
+        Executor executor = mExecutors.lookup(info.derivedUri.getAuthority());
+        if (executor != null) {
+            new AsyncTask<Void, Void, String[]>() {
+                @Override
+                protected String[] doInBackground(Void... params) {
+                    return mContext.getContentResolver().getStreamTypes(info.derivedUri, "*/*");
+                }
+
+                @Override
+                protected void onPostExecute(String[] streamTypes) {
+                    put(R.string.debug_stream_types,
+                            streamTypes != null ? Arrays.toString(streamTypes) : "[]");
+                }
+            }.executeOnExecutor(executor, (Void[]) null);
+        }
     }
 
-    private void put(String key, Object value) {
-        put(key, String.valueOf(value));
+    @Override
+    public void accept(Bundle metadata) {
+        if (metadata == null) {
+            return;
+        }
+
+        String[] types = metadata.getStringArray(DocumentsContract.METADATA_TYPES);
+        if (types == null) {
+            return;
+        }
+
+        for (String type : types) {
+            dumpMetadata(type, metadata.getBundle(type));
+        }
+    }
+
+    private void dumpMetadata(String type, Bundle bundle) {
+        String title = mContext.getResources().getString(
+                R.string.inspector_debug_metadata_section);
+        putTitle(String.format(title, type), true);
+        List<String> keys = new ArrayList<>(bundle.keySet());
+        Collections.sort(keys);
+        for (String key : keys) {
+            put(key, String.valueOf(bundle.get(key)));
+        }
+    }
+
+    private void put(@StringRes int key, boolean value) {
+        KeyValueRow row = put(mRes.getString(key), String.valueOf(value));
+        TextView valueView = ((TextView) row.findViewById(R.id.table_row_value));
+        valueView.setTextColor(value ? 0xFF006400 : 0xFF9A2020);
     }
 }
diff --git a/src/com/android/documentsui/inspector/DetailsView.java b/src/com/android/documentsui/inspector/DetailsView.java
index 5497068..5563471 100644
--- a/src/com/android/documentsui/inspector/DetailsView.java
+++ b/src/com/android/documentsui/inspector/DetailsView.java
@@ -16,7 +16,6 @@
 package com.android.documentsui.inspector;
 
 import android.content.Context;
-import android.text.format.DateFormat;
 import android.text.format.Formatter;
 import android.util.AttributeSet;
 
@@ -44,26 +43,34 @@
     }
 
     @Override
-    public void accept(DocumentInfo info) {
+    public void accept(DocumentInfo doc) {
 
         Lookup<String, String> fileTypeLookup =
                 DocumentsApplication.getFileTypeLookup(getContext());
 
-        put(R.string.sort_dimension_file_type, fileTypeLookup.lookup(info.mimeType));
+        String mimeType = fileTypeLookup.lookup(doc.mimeType);
+
+        put(R.string.sort_dimension_file_type, mimeType);
 
         // TODO: Each of these rows need to be removed if the condition is false and previously
         // set.
-        if (info.size > 0) {
-            put(R.string.sort_dimension_size, Formatter.formatFileSize(getContext(), info.size));
+        if (doc.size >= 0 && !doc.isDirectory()) {
+            put(R.string.sort_dimension_size, Formatter.formatFileSize(getContext(), doc.size));
         }
 
-        if (info.lastModified > 0) {
+        if (doc.lastModified > 0) {
             put(R.string.sort_dimension_date,
-                    DateFormat.getDateFormat(getContext()).format(info.lastModified));
+                    DateUtils.formatDate(this.getContext(), doc.lastModified));
         }
 
-        if (info.summary != null) {
-            put(R.string.sort_dimension_summary, info.summary);
+        // We only show summary field when doc is partial (meaning an active download).
+        // The rest of the time "summary" tends to be less than useful. For example
+        // after a download is completed DownloadsProvider include the orig filename
+        // in the summary field. This is confusing to folks in-and-if-itself, but
+        // after the file is renamed, it creates even more confusion (since it still
+        // shows the original). For that reason, and others. We only display on partial files.
+        if (doc.isPartial() && doc.summary != null) {
+            put(R.string.sort_dimension_summary, doc.summary);
         }
     }
 
@@ -71,4 +78,4 @@
     public void setChildrenCount(int count) {
         put(R.string.directory_items, String.valueOf(count));
     }
-}
\ No newline at end of file
+}
diff --git a/src/com/android/documentsui/inspector/GpsCoordinatesTextClassifier.java b/src/com/android/documentsui/inspector/GpsCoordinatesTextClassifier.java
new file mode 100644
index 0000000..a0a95a2
--- /dev/null
+++ b/src/com/android/documentsui/inspector/GpsCoordinatesTextClassifier.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2017 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.documentsui.inspector;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.os.LocaleList;
+import android.view.textclassifier.TextClassification;
+import android.view.textclassifier.TextClassificationManager;
+import android.view.textclassifier.TextClassifier;
+import android.view.textclassifier.TextSelection;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Checks if a TextView has a latitude and longitude. If so shows the default maps app to open
+ * those coordinates.
+ *
+ * Example - textView.setTextClassifier(new GpsCoordinatesTextClassifier(context, intent));
+ */
+final class GpsCoordinatesTextClassifier implements TextClassifier {
+
+    // Checks for latitude and longitude points, latitude ranges -90.0 to 90.0 and longitude
+    // ranges -180.0 to 180.0 Valid entries can be of the format "0,0", "0, 0" and "0.0, 0.0"
+    // in the mentioned range.
+    private static final String geoPattern
+        = "-?(90(\\.0*)?|[1-8]?[0-9](\\.[0-9]*)?), *-?(180("
+        + "\\.0*)?|([1][0-7][0-9]|[0-9]?[0-9])(\\.[0-9]*)?)";
+    private static final Pattern sGeoPattern = Pattern.compile(geoPattern);
+
+    private final TextClassifier mSystemClassifier;
+    private final PackageManager mPackageManager;
+
+    public GpsCoordinatesTextClassifier(PackageManager pm, TextClassifier classifier) {
+        assert pm != null;
+        assert classifier != null;
+        mPackageManager = pm;
+        mSystemClassifier = classifier;
+    }
+
+    public static GpsCoordinatesTextClassifier create(Context context) {
+        return new GpsCoordinatesTextClassifier(
+                context.getPackageManager(),
+                context.getSystemService(TextClassificationManager.class).getTextClassifier());
+    }
+
+    // TODO: add support for local specific formatting
+    @Override
+    public TextClassification classifyText(
+            CharSequence text, int start, int end, LocaleList localeList) {
+
+        CharSequence sequence = text.subSequence(start, end);
+        if (isGeoSequence(sequence)) {
+
+            Intent intent = new Intent(Intent.ACTION_VIEW)
+                .setData(Uri.parse(String.format("geo:0,0?q=%s", sequence)));
+
+            final ResolveInfo info = mPackageManager.resolveActivity(intent, 0);
+            if (info != null) {
+
+                return new TextClassification.Builder()
+                        .setText(sequence.toString())
+                        .setEntityType(TextClassifier.TYPE_ADDRESS, 1.0f)
+                        .setIcon(info.loadIcon(mPackageManager))
+                        .setLabel(info.loadLabel(mPackageManager).toString())
+                        .setIntent(intent)
+                        .build();
+            }
+        }
+
+        // return default if text was not latitude, longitude or we couldn't find an application
+        // to handle the geo intent.
+        return mSystemClassifier.classifyText(text, start, end, localeList);
+    }
+
+    @Override
+    public TextSelection suggestSelection(
+        CharSequence context, int start, int end, LocaleList localeList) {
+
+        // Show map action menu popup when entire TextView is selected.
+        final int[] boundaries = {0, context.length()};
+
+        if (boundaries != null) {
+            return new TextSelection.Builder(boundaries[0], boundaries[1])
+                .setEntityType(TextClassifier.TYPE_ADDRESS, 1.0f)
+                .build();
+        }
+        return mSystemClassifier.suggestSelection(context, start, end, localeList);
+    }
+
+    private static boolean isGeoSequence(CharSequence text) {
+        return sGeoPattern.matcher(text).matches();
+    }
+}
diff --git a/src/com/android/documentsui/inspector/HeaderTextSelector.java b/src/com/android/documentsui/inspector/HeaderTextSelector.java
new file mode 100644
index 0000000..5530fbe
--- /dev/null
+++ b/src/com/android/documentsui/inspector/HeaderTextSelector.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2017 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.documentsui.inspector;
+
+import static com.android.internal.util.Preconditions.checkArgument;
+
+import android.text.Spannable;
+import android.view.ActionMode;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.TextView;
+
+/**
+ * Selects all or part of a textview.
+ */
+ public final class HeaderTextSelector implements ActionMode.Callback {
+
+    private final TextView mText;
+    private final Selector mSelector;
+
+    public HeaderTextSelector(TextView text, Selector selector) {
+        checkArgument(text != null);
+        checkArgument(selector != null);
+        mText = text;
+        mSelector = selector;
+    }
+
+    // An action mode is created when the user selects text. This method is called where
+    // we force it to select only the filename in the header. Meaning the name of the file would
+    // be selected but the extension would not.
+    @Override
+    public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
+        CharSequence value = mText.getText();
+        if (value instanceof Spannable) {
+            mSelector.select((Spannable) value, 0, getLengthOfFilename(value));
+        }
+        return true;
+    }
+
+    @Override
+    public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
+        return true;
+    }
+
+    @Override
+    public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
+        return false;
+    }
+
+    @Override
+    public void onDestroyActionMode(ActionMode actionMode) {}
+
+    /**
+     * Gets the length of the inspector header for selection.
+     *
+     * Example:
+     * filename.txt returns the end index needed to select "filename".
+     *
+     * @return the index of the last character in the filename
+     */
+    private static int getLengthOfFilename(CharSequence text) {
+        String title = text.toString();
+        if (title != null) {
+            int index = title.indexOf('.');
+            if (index > 0) {
+                return index;
+            }
+        }
+
+        return text.length();
+    }
+
+    public interface Selector {
+        void select(Spannable text, int start, int stop);
+    }
+}
diff --git a/src/com/android/documentsui/inspector/HeaderView.java b/src/com/android/documentsui/inspector/HeaderView.java
index 835af77..c411082 100644
--- a/src/com/android/documentsui/inspector/HeaderView.java
+++ b/src/com/android/documentsui/inspector/HeaderView.java
@@ -20,6 +20,8 @@
 import android.graphics.Bitmap;
 import android.graphics.Point;
 import android.graphics.drawable.Drawable;
+import android.text.Selection;
+import android.text.Spannable;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -29,18 +31,20 @@
 import android.widget.TextView;
 
 import com.android.documentsui.ProviderExecutor;
+import com.android.documentsui.R;
 import com.android.documentsui.ThumbnailLoader;
 import com.android.documentsui.base.Display;
 import com.android.documentsui.base.DocumentInfo;
-import com.android.documentsui.R;
+import com.android.documentsui.inspector.InspectorController.HeaderDisplay;
+
 import java.util.function.Consumer;
 
+import javax.annotation.Nullable;
+
 /**
  * Organizes and displays the title and thumbnail for a given document
  */
-public final class HeaderView extends RelativeLayout implements Consumer<DocumentInfo> {
-
-    private static final String TAG = HeaderView.class.getCanonicalName();
+public final class HeaderView extends RelativeLayout implements HeaderDisplay {
 
     private final Context mContext;
     private final View mHeader;
@@ -68,63 +72,55 @@
         int width = (int) Display.screenWidth((Activity)context);
         int height = mContext.getResources().getDimensionPixelSize(R.dimen.inspector_header_height);
         mImageDimensions = new Point(width, height);
+        addView(mHeader);
     }
 
     @Override
-    public void accept(DocumentInfo info) {
-        if (!hasHeader()) {
-            addView(mHeader);
-        }
-
-        if (!hasHeaderImage()) {
-            if (info.isDirectory()) {
-                loadFileIcon(info);
-            } else {
-                loadHeaderImage(info);
-            }
-        }
-        mTitle.setText(info.displayName);
+    public void accept(DocumentInfo info, String displayName) {
+        loadHeaderImage(info);
+        mTitle.setText(displayName);
+        mTitle.setCustomSelectionActionModeCallback(
+                new HeaderTextSelector(mTitle, this::selectText));
     }
 
-    private boolean hasHeader() {
-        for (int i = 0; i < getChildCount(); i++) {
-            if (getChildAt(i).equals(mHeader)) {
-                return true;
-            }
-        }
-        return false;
+    private void selectText(Spannable text, int start, int stop) {
+        Selection.setSelection(text, start, stop);
     }
 
-    private void loadFileIcon(DocumentInfo info) {
-        Drawable mimeIcon = mContext.getContentResolver()
-            .getTypeDrawable(info.mimeType);
-        mThumbnail.setScaleType(ScaleType.FIT_CENTER);
-        mThumbnail.setImageDrawable(mimeIcon);
-    }
-
-    private void loadHeaderImage(DocumentInfo info) {
-
-        Consumer<Bitmap> callback = new Consumer<Bitmap>() {
-            @Override
-            public void accept(Bitmap bitmap) {
-                if (bitmap != null) {
-                    mThumbnail.setScaleType(ScaleType.CENTER_CROP);
-                    mThumbnail.setImageBitmap(bitmap);
-                } else {
-                    loadFileIcon(info);
+    private void loadHeaderImage(DocumentInfo doc) {
+        if (!doc.isThumbnailSupported()) {
+            showImage(doc, null);
+        } else {
+            Consumer<Bitmap> callback = new Consumer<Bitmap>() {
+                @Override
+                public void accept(Bitmap thumbnail) {
+                    showImage(doc, thumbnail);
                 }
-                mThumbnail.animate().alpha(1.0f).start();
-            }
-        };
-
-        // load the thumbnail async.
-        final ThumbnailLoader task = new ThumbnailLoader(info.derivedUri, mThumbnail,
-            mImageDimensions, info.lastModified, callback, false);
-        task.executeOnExecutor(ProviderExecutor.forAuthority(info.derivedUri.getAuthority()),
-            info.derivedUri);
+            };
+            // load the thumbnail async.
+            final ThumbnailLoader task = new ThumbnailLoader(doc.derivedUri, mThumbnail,
+                    mImageDimensions, doc.lastModified, callback, false);
+            task.executeOnExecutor(ProviderExecutor.forAuthority(doc.derivedUri.getAuthority()),
+                    doc.derivedUri);
+        }
     }
 
-    private boolean hasHeaderImage() {
-        return mThumbnail.getAlpha() == 1.0f;
+    /**
+     * Shows the supplied image, falling back to a mimetype icon if the image is null.
+     */
+    private void showImage(DocumentInfo info, @Nullable Bitmap thumbnail) {
+        if (thumbnail != null) {
+            mThumbnail.resetPaddingToInitialValues();
+            mThumbnail.setScaleType(ScaleType.CENTER_CROP);
+            mThumbnail.setImageBitmap(thumbnail);
+        } else {
+            mThumbnail.setPadding(0, 0, 0, mTitle.getHeight());
+
+            Drawable mimeIcon =
+                    mContext.getContentResolver().getTypeDrawable(info.mimeType);
+            mThumbnail.setScaleType(ScaleType.FIT_CENTER);
+            mThumbnail.setImageDrawable(mimeIcon);
+        }
+        mThumbnail.animate().alpha(1.0f).start();
     }
 }
\ No newline at end of file
diff --git a/src/com/android/documentsui/inspector/InspectorActivity.java b/src/com/android/documentsui/inspector/InspectorActivity.java
index 44af735..d02c43b 100644
--- a/src/com/android/documentsui/inspector/InspectorActivity.java
+++ b/src/com/android/documentsui/inspector/InspectorActivity.java
@@ -33,7 +33,7 @@
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         requestWindowFeature(Window.FEATURE_ACTION_BAR);
-        setContentView(R.layout.document_inspector_activity);
+        setContentView(R.layout.inspector_activity);
 
         Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
         setActionBar(toolbar);
@@ -45,10 +45,7 @@
 
         if (mFragment == null) {
             Intent intent = getIntent();
-
             mFragment = InspectorFragment.newInstance(intent);
-
-
             fragmentManager.beginTransaction()
                     .add(R.id.fragment_container, mFragment)
                     .commit();
diff --git a/src/com/android/documentsui/inspector/InspectorController.java b/src/com/android/documentsui/inspector/InspectorController.java
index 2b1c4b4..79612f9 100644
--- a/src/com/android/documentsui/inspector/InspectorController.java
+++ b/src/com/android/documentsui/inspector/InspectorController.java
@@ -15,59 +15,69 @@
  */
 package com.android.documentsui.inspector;
 
-import static android.provider.DocumentsContract.Document.FLAG_SUPPORTS_SETTINGS;
 import static com.android.internal.util.Preconditions.checkArgument;
 
+import android.annotation.StringRes;
 import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.Bundle;
 import android.provider.DocumentsContract;
 import android.support.annotation.Nullable;
 import android.support.annotation.VisibleForTesting;
 import android.view.View;
 import android.view.View.OnClickListener;
+
 import com.android.documentsui.DocumentsApplication;
 import com.android.documentsui.ProviderExecutor;
 import com.android.documentsui.R;
 import com.android.documentsui.base.DocumentInfo;
-import com.android.documentsui.base.Lookup;
+import com.android.documentsui.base.Shared;
 import com.android.documentsui.inspector.actions.Action;
 import com.android.documentsui.inspector.actions.ClearDefaultAppAction;
 import com.android.documentsui.inspector.actions.ShowInProviderAction;
 import com.android.documentsui.roots.ProvidersAccess;
 import com.android.documentsui.ui.Snackbars;
-import java.util.concurrent.Executor;
+
 import java.util.function.Consumer;
 /**
  * A controller that coordinates retrieving document information and sending it to the view.
  */
 public final class InspectorController {
 
-    private final Loader mLoader;
-    private final Consumer<DocumentInfo> mHeader;
+    private final DataSupplier mLoader;
+    private final HeaderDisplay mHeader;
     private final DetailsDisplay mDetails;
+    private final MediaDisplay mMedia;
     private final ActionDisplay mShowProvider;
     private final ActionDisplay mAppDefaults;
-    private final Consumer<DocumentInfo> mDebugView;
-    private final boolean mShowDebug;
+    private final DebugDisplay mDebugView;
     private final Context mContext;
     private final PackageManager mPackageManager;
     private final ProvidersAccess mProviders;
-    private final Runnable mShowSnackbar;
-    private final Lookup<String, Executor> mExecutors;
+    private final Runnable mErrorSnackbar;
+    private Bundle mArgs;
 
     /**
      * InspectorControllerTest relies on this controller.
      */
     @VisibleForTesting
-    public InspectorController(Context context, Loader loader, PackageManager pm,
-            ProvidersAccess providers, boolean showDebug, Consumer<DocumentInfo> header,
-            DetailsDisplay details, ActionDisplay showProvider, ActionDisplay appDefaults,
-            Consumer<DocumentInfo> debugView, Lookup<String, Executor> executors,
-            Runnable showSnackbar) {
+    public InspectorController(
+            Context context,
+            DataSupplier loader,
+            PackageManager pm,
+            ProvidersAccess providers,
+            HeaderDisplay header,
+            DetailsDisplay details,
+            MediaDisplay media,
+            ActionDisplay showProvider,
+            ActionDisplay appDefaults,
+            DebugDisplay debugView,
+            Bundle args,
+            Runnable errorRunnable) {
 
         checkArgument(context != null);
         checkArgument(loader != null);
@@ -75,46 +85,57 @@
         checkArgument(providers != null);
         checkArgument(header != null);
         checkArgument(details != null);
+        checkArgument(media != null);
         checkArgument(showProvider != null);
         checkArgument(appDefaults != null);
         checkArgument(debugView != null);
-        checkArgument(showSnackbar != null);
-        checkArgument(executors != null);
+        checkArgument(args != null);
+        checkArgument(errorRunnable != null);
 
         mContext = context;
         mLoader = loader;
         mPackageManager = pm;
-        mShowDebug = showDebug;
         mProviders = providers;
         mHeader = header;
         mDetails = details;
+        mMedia = media;
         mShowProvider = showProvider;
         mAppDefaults = appDefaults;
+        mArgs = args;
         mDebugView = debugView;
-        mExecutors = executors;
-        mShowSnackbar = showSnackbar;
+
+        mErrorSnackbar = errorRunnable;
     }
 
-    public InspectorController(Activity activity, Loader loader, View layout, boolean showDebug) {
-
+    /**
+     * @param activity
+     * @param loader
+     * @param layout
+     * @param args Bundle of arguments passed to our host {@link InspectorFragment}. These
+     *     can include extras that enable debug mode ({@link Shared#EXTRA_SHOW_DEBUG}
+     *     and override the file title (@link {@link Intent#EXTRA_TITLE}).
+     */
+    public InspectorController(Activity activity, DataSupplier loader, View layout, Bundle args) {
         this(activity,
-                loader,
-                activity.getPackageManager(),
-                DocumentsApplication.getProvidersCache (activity),
-                showDebug,
-                (HeaderView) layout.findViewById(R.id.inspector_header_view),
-                (DetailsView) layout.findViewById(R.id.inspector_details_view),
-                (ActionDisplay) layout.findViewById(R.id.inspector_show_in_provider_view),
-                (ActionDisplay) layout.findViewById(R.id.inspector_app_defaults_view),
-                (DebugView) layout.findViewById(R.id.inspector_debug_view),
-                ProviderExecutor::forAuthority,
-                () -> {
-                    // using a runnable to support unit testing this feature.
-                    Snackbars.showInspectorError(activity);
-                }
+            loader,
+            activity.getPackageManager(),
+            DocumentsApplication.getProvidersCache (activity),
+            (HeaderView) layout.findViewById(R.id.inspector_header_view),
+            (DetailsView) layout.findViewById(R.id.inspector_details_view),
+            (MediaView) layout.findViewById(R.id.inspector_media_view),
+            (ActionDisplay) layout.findViewById(R.id.inspector_show_in_provider_view),
+            (ActionDisplay) layout.findViewById(R.id.inspector_app_defaults_view),
+            (DebugView) layout.findViewById(R.id.inspector_debug_view),
+            args,
+            () -> {
+                // using a runnable to support unit testing this feature.
+                Snackbars.showInspectorError(activity);
+            }
         );
-        if (showDebug) {
-            layout.findViewById(R.id.inspector_debug_view).setVisibility(View.VISIBLE);
+
+        if (args.getBoolean(Shared.EXTRA_SHOW_DEBUG)) {
+            DebugView view = (DebugView) layout.findViewById(R.id.inspector_debug_view);
+            view.init(ProviderExecutor::forAuthority);
         }
     }
 
@@ -129,13 +150,11 @@
     /**
      * Updates the view with documentInfo.
      */
-    @Nullable
-    public void updateView(@Nullable DocumentInfo docInfo) {
-
+    private void updateView(@Nullable DocumentInfo docInfo) {
         if (docInfo == null) {
-            mShowSnackbar.run();
+            mErrorSnackbar.run();
         } else {
-            mHeader.accept(docInfo);
+            mHeader.accept(docInfo, mArgs.getString(Intent.EXTRA_TITLE, docInfo.displayName));
             mDetails.accept(docInfo);
 
             if (docInfo.isDirectory()) {
@@ -147,28 +166,62 @@
                     Action showProviderAction =
                         new ShowInProviderAction(mContext, mPackageManager, docInfo, mProviders);
                     mShowProvider.init(
-                            showProviderAction,
-                            (view) -> {
-                                showInProvider(docInfo.derivedUri);
-                            });
+                        showProviderAction,
+                        (view) -> {
+                            showInProvider(docInfo.derivedUri);
+                        });
                 }
 
                 Action defaultAction =
-                        new ClearDefaultAppAction(mContext, mPackageManager, docInfo);
+                    new ClearDefaultAppAction(mContext, mPackageManager, docInfo);
 
                 mAppDefaults.setVisible(defaultAction.canPerformAction());
                 if (defaultAction.canPerformAction()) {
                     mAppDefaults.init(
-                            defaultAction,
-                            (View) -> {
-                                clearDefaultApp(defaultAction.getPackageName());
-                            });
+                        defaultAction,
+                        (View) -> {
+                            clearDefaultApp(defaultAction.getPackageName());
+                        });
                 }
             }
 
-            if (mShowDebug) {
+            if (docInfo.isMetadataSupported()) {
+                mLoader.getDocumentMetadata(
+                        docInfo.derivedUri,
+                        (Bundle bundle) -> {
+                            onDocumentMetadataLoaded(docInfo, bundle);
+                        });
+            }
+            mMedia.setVisible(!mMedia.isEmpty());
+
+            if (mArgs.getBoolean(Shared.EXTRA_SHOW_DEBUG)) {
                 mDebugView.accept(docInfo);
             }
+            mDebugView.setVisible(mArgs.getBoolean(Shared.EXTRA_SHOW_DEBUG)
+                    && !mDebugView.isEmpty());
+        }
+    }
+
+    private void onDocumentMetadataLoaded(DocumentInfo doc, @Nullable Bundle metadata) {
+        if (metadata == null) {
+            return;
+        }
+
+        Runnable geoClickListener = null;
+        if (MetadataUtils.hasGeoCoordinates(metadata)) {
+            float[] coords = MetadataUtils.getGeoCoordinates(metadata);
+            final Intent intent = createGeoIntent(coords[0], coords[1], doc.displayName);
+            if (hasHandler(intent)) {
+                geoClickListener = () -> {
+                    startActivity(intent);
+                };
+            }
+        }
+
+        mMedia.accept(doc, metadata, geoClickListener);
+
+        if (mArgs.getBoolean(Shared.EXTRA_SHOW_DEBUG)) {
+            mDebugView.accept(metadata);
         }
     }
 
@@ -181,6 +234,31 @@
         mDetails.setChildrenCount(count);
     }
 
+    private void startActivity(Intent intent) {
+        assert hasHandler(intent);
+        mContext.startActivity(intent);
+    }
+
+    /**
+     * checks that we can handle a geo-intent.
+     */
+    private boolean hasHandler(Intent intent) {
+        return mPackageManager.resolveActivity(intent, 0) != null;
+    }
+
+    /**
+     * Creates a geo-intent for opening a location in maps.
+     *
+     * @see https://developer.android.com/guide/components/intents-common.html#Maps
+     */
+    private static Intent createGeoIntent(
+            float latitude, float longitude, @Nullable String label) {
+        label = Uri.encode(label == null ? "" : label);
+        String data = "geo:0,0?q=" + latitude + " " + longitude + "(" + label + ")";
+        Uri uri = Uri.parse(data);
+        return new Intent(Intent.ACTION_VIEW, uri);
+    }
+
     /**
      * Shows the selected document in it's content provider.
      *
@@ -210,9 +288,10 @@
     }
 
     /**
-     * Interface for loading document metadata.
+     * Interface for loading all the various forms of document data. This primarily
+     * allows us to easily supply test data in tests.
      */
-    public interface Loader {
+    public interface DataSupplier {
 
         /**
          * Starts the Asynchronous process of loading file data.
@@ -235,12 +314,28 @@
          * Deletes all loader id's when android lifecycle ends.
          */
         void reset();
+
+        /**
+         * @param uri
+         * @param callback
+         */
+        void getDocumentMetadata(Uri uri, Consumer<Bundle> callback);
     }
 
     /**
      * This interface is for unit testing.
      */
-    public interface ActionDisplay {
+    public interface Display {
+        /**
+         * Makes the action visible.
+         */
+        void setVisible(boolean visible);
+    }
+
+    /**
+     * This interface is for unit testing.
+     */
+    public interface ActionDisplay extends Display {
 
         /**
          * Initializes the view based on the action.
@@ -249,11 +344,6 @@
          */
         void init(Action action, OnClickListener listener);
 
-        /**
-         * Makes the action visible.
-         */
-        void setVisible(boolean visible);
-
         void setActionHeader(String header);
 
         void setAppIcon(Drawable icon);
@@ -266,10 +356,63 @@
     /**
      * Provides details about a file.
      */
+    public interface HeaderDisplay {
+        void accept(DocumentInfo info, String displayName);
+    }
+
+    /**
+     * Provides basic details about a file.
+     */
     public interface DetailsDisplay {
 
         void accept(DocumentInfo info);
 
         void setChildrenCount(int count);
     }
+
+    /**
+     * Provides details about a media file.
+     */
+    public interface MediaDisplay extends Display {
+        void accept(DocumentInfo info, Bundle metadata, @Nullable Runnable geoClickListener);
+
+        /**
+         * Returns true if there are now rows in the display. Does not consider the title.
+         */
+        boolean isEmpty();
+    }
+
+    /**
+     * Provides details about a media file.
+     */
+    public interface DebugDisplay extends Display {
+        void accept(DocumentInfo info);
+        void accept(Bundle metadata);
+
+        /**
+         * Returns true if there are now rows in the display. Does not consider the title.
+         */
+        boolean isEmpty();
+    }
+
+    /**
+     * Displays a table of image metadata.
+     */
+    public interface TableDisplay extends Display {
+
+        /**
+         * Adds a row in the table.
+         */
+        void put(@StringRes int keyId, CharSequence value);
+
+        /**
+         * Adds a row in the table and makes it clickable.
+         */
+        void put(@StringRes int keyId, CharSequence value, OnClickListener callback);
+
+        /**
+         * Returns true if there are now rows in the display. Does not consider the title.
+         */
+        boolean isEmpty();
+    }
 }
\ No newline at end of file
diff --git a/src/com/android/documentsui/inspector/InspectorFragment.java b/src/com/android/documentsui/inspector/InspectorFragment.java
index ef7c3b1..b2fd155 100644
--- a/src/com/android/documentsui/inspector/InspectorFragment.java
+++ b/src/com/android/documentsui/inspector/InspectorFragment.java
@@ -27,8 +27,7 @@
 import android.widget.ScrollView;
 
 import com.android.documentsui.R;
-import com.android.documentsui.base.Shared;
-import com.android.documentsui.inspector.InspectorController.Loader;
+import com.android.documentsui.inspector.InspectorController.DataSupplier;
 
 /**
  * Displays the Properties view in Files.
@@ -47,12 +46,11 @@
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
         Bundle savedInstanceState) {
-        final Loader loader = new DocumentLoader(getActivity(), getLoaderManager());
+        final DataSupplier loader = new RuntimeDataSupplier(getActivity(), getLoaderManager());
 
-        mView = (ScrollView) inflater.inflate(R.layout.document_inspector_fragment,
+        mView = (ScrollView) inflater.inflate(R.layout.inspector_fragment,
                 container, false);
-        boolean showDebug = (boolean) getArguments().get(Shared.EXTRA_SHOW_DEBUG);
-        mController = new InspectorController(getActivity(), loader, mView, showDebug);
+        mController = new InspectorController(getActivity(), loader, mView, getArguments());
         return mView;
     }
 
@@ -70,16 +68,17 @@
     }
 
     /**
-     * Creates a fragment and sets a Uri as an argument.
+     * Creates a fragment with the appropriate args.
      */
     public static InspectorFragment newInstance(Intent intent) {
-        Uri uri = intent.getData();
-        boolean showDebug = intent.getBooleanExtra(Shared.EXTRA_SHOW_DEBUG, false);
 
+        Bundle extras = intent.getExtras();
+        extras = extras != null ? extras : Bundle.EMPTY;
+        Bundle args = extras.deepCopy();
+
+        Uri uri = intent.getData();
         checkArgument(uri.getScheme().equals("content"));
-        Bundle args = new Bundle();
         args.putParcelable(DOC_URI_ARG, uri);
-        args.putBoolean(Shared.EXTRA_SHOW_DEBUG, showDebug);
 
         InspectorFragment fragment = new InspectorFragment();
         fragment.setArguments(args);
diff --git a/src/com/android/documentsui/inspector/KeyValueRow.java b/src/com/android/documentsui/inspector/KeyValueRow.java
index 45a6e05..48801d5 100644
--- a/src/com/android/documentsui/inspector/KeyValueRow.java
+++ b/src/com/android/documentsui/inspector/KeyValueRow.java
@@ -15,12 +15,17 @@
  */
 package com.android.documentsui.inspector;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
-
 import android.annotation.StringRes;
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.Resources;
+import android.graphics.Paint;
+import android.support.annotation.Nullable;
+import android.text.Selection;
+import android.text.Spannable;
 import android.util.AttributeSet;
+import android.view.View;
+import android.view.textclassifier.TextClassifier;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
@@ -32,6 +37,8 @@
 public class KeyValueRow extends LinearLayout {
 
     private final Resources mRes;
+    private @Nullable ColorStateList mDefaultTextColor;
+    private @Nullable TextClassifier mClassifier;
 
     public KeyValueRow(Context context) {
         this(context, null);
@@ -43,15 +50,18 @@
 
     public KeyValueRow(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
-
         mRes = context.getResources();
     }
 
+    public void setTextClassifier(TextClassifier classifier) {
+        mClassifier = classifier;
+    }
+
     /**
      * Sets the raw value of the key. Only localized values
      * should be passed.
      */
-    public void setKey(String key) {
+    public void setKey(CharSequence key) {
         ((TextView) findViewById(R.id.table_row_key)).setText(key);
     }
 
@@ -59,7 +69,38 @@
         setKey(mRes.getString(id));
     }
 
-    public void setValue(String value) {
-        ((TextView) findViewById(R.id.table_row_value)).setText(value);
+    public void setValue(CharSequence value) {
+        TextView text = ((TextView) findViewById(R.id.table_row_value));
+        text.setText(value);
+        text.setTextClassifier(mClassifier);
+        text.setOnLongClickListener((View view) -> {
+
+            CharSequence textValue = text.getText();
+            if (textValue instanceof Spannable) {
+                Spannable spn = (Spannable) textValue;
+                Selection.selectAll(spn);
+            }
+            // we still want the default selection arrows and menu after we specified to select
+            // all text in the TextView.
+            return false;
+        });
+    }
+
+    @Override
+    public void setOnClickListener(OnClickListener callback) {
+        TextView clickable = ((TextView) findViewById(R.id.table_row_value));
+        mDefaultTextColor = clickable.getTextColors();
+        clickable.setTextColor(R.color.inspector_link);
+        clickable.setPaintFlags(clickable.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
+        clickable.setOnClickListener(callback);
+    }
+
+    public void removeOnClickListener() {
+        TextView reset = ((TextView) findViewById(R.id.table_row_value));
+        if (mDefaultTextColor != null) {
+            reset.setTextColor(mDefaultTextColor);
+        }
+        reset.setPaintFlags(reset.getPaintFlags() & ~Paint.UNDERLINE_TEXT_FLAG);
+        reset.setOnClickListener(null);
     }
 }
diff --git a/src/com/android/documentsui/inspector/MediaView.java b/src/com/android/documentsui/inspector/MediaView.java
new file mode 100644
index 0000000..b2ae758
--- /dev/null
+++ b/src/com/android/documentsui/inspector/MediaView.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2017 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.documentsui.inspector;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.location.Address;
+import android.location.Geocoder;
+import android.media.ExifInterface;
+import android.media.MediaMetadata;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.provider.DocumentsContract;
+import android.support.annotation.VisibleForTesting;
+import android.text.format.DateUtils;
+import android.util.AttributeSet;
+
+import com.android.documentsui.R;
+import com.android.documentsui.base.DocumentInfo;
+import com.android.documentsui.base.Shared;
+import com.android.documentsui.inspector.InspectorController.MediaDisplay;
+import com.android.documentsui.inspector.InspectorController.TableDisplay;
+
+import java.io.IOException;
+import java.util.function.Consumer;
+
+import javax.annotation.Nullable;
+
+/**
+ * Organizes and Displays the debug information about a file. This view
+ * should only be made visible when build is debuggable and system policies
+ * allow debug "stuff".
+ */
+public class MediaView extends TableView implements MediaDisplay {
+
+    private final Resources mResources;
+    private final Context mContext;
+
+    public MediaView(Context context) {
+        this(context, null);
+    }
+
+    public MediaView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public MediaView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mContext = context;
+        mResources = context.getResources();
+    }
+
+    @Override
+    public void accept(DocumentInfo doc, Bundle metadata, @Nullable Runnable geoClickListener) {
+        setTitle(R.string.inspector_metadata_section, true);
+
+        Bundle exif = metadata.getBundle(DocumentsContract.METADATA_EXIF);
+        if (exif != null) {
+            showExifData(this, mResources, doc, exif, geoClickListener, this::getAddress);
+        }
+
+        Bundle video = metadata.getBundle(Shared.METADATA_KEY_VIDEO);
+        if (video != null) {
+            showVideoData(this, mResources, doc, video, geoClickListener);
+        }
+
+        Bundle audio = metadata.getBundle(Shared.METADATA_KEY_AUDIO);
+        if (audio != null) {
+            showAudioData(this, audio);
+        }
+
+        setVisible(!isEmpty());
+    }
+
+    @VisibleForTesting
+    public static void showAudioData(TableDisplay table, Bundle tags) {
+
+        if (tags.containsKey(MediaMetadata.METADATA_KEY_ARTIST)) {
+            table.put(R.string.metadata_artist, tags.getString(MediaMetadata.METADATA_KEY_ARTIST));
+        }
+
+        if (tags.containsKey(MediaMetadata.METADATA_KEY_COMPOSER)) {
+            table.put(R.string.metadata_composer,
+                    tags.getString(MediaMetadata.METADATA_KEY_COMPOSER));
+        }
+
+        if (tags.containsKey(MediaMetadata.METADATA_KEY_ALBUM)) {
+            table.put(R.string.metadata_album, tags.getString(MediaMetadata.METADATA_KEY_ALBUM));
+        }
+
+        if (tags.containsKey(MediaMetadata.METADATA_KEY_DURATION)) {
+            int millis = tags.getInt(MediaMetadata.METADATA_KEY_DURATION);
+            table.put(R.string.metadata_duration, DateUtils.formatElapsedTime(millis / 1000));
+        }
+    }
+
+    @VisibleForTesting
+    public static void showVideoData(
+            TableDisplay table,
+            Resources resources,
+            DocumentInfo doc,
+            Bundle tags,
+            @Nullable Runnable geoClickListener) {
+
+        addDimensionsRow(table, resources, tags);
+
+        if (MetadataUtils.hasVideoCoordinates(tags)) {
+            float[] coords = MetadataUtils.getVideoCoords(tags);
+            showCoordiantes(table, resources, coords, geoClickListener);
+        }
+
+        if (tags.containsKey(MediaMetadata.METADATA_KEY_DURATION)) {
+            int millis = tags.getInt(MediaMetadata.METADATA_KEY_DURATION);
+            table.put(R.string.metadata_duration, DateUtils.formatElapsedTime(millis / 1000));
+        }
+    }
+
+    @VisibleForTesting
+    public static void showExifData(
+            TableDisplay table,
+            Resources resources,
+            DocumentInfo doc,
+            Bundle tags,
+            @Nullable Runnable geoClickListener,
+            Consumer<float[]> geoAddressFetcher) {
+
+        addDimensionsRow(table, resources, tags);
+
+        if (tags.containsKey(ExifInterface.TAG_DATETIME)) {
+            String date = tags.getString(ExifInterface.TAG_DATETIME);
+            table.put(R.string.metadata_date_time, date);
+        }
+
+        if (tags.containsKey(ExifInterface.TAG_GPS_ALTITUDE)) {
+            double altitude = tags.getDouble(ExifInterface.TAG_GPS_ALTITUDE);
+            table.put(R.string.metadata_altitude, String.valueOf(altitude));
+        }
+
+        if (tags.containsKey(ExifInterface.TAG_MAKE) || tags.containsKey(ExifInterface.TAG_MODEL)) {
+                String make = tags.getString(ExifInterface.TAG_MAKE);
+                String model = tags.getString(ExifInterface.TAG_MODEL);
+                make = make != null ? make : "";
+                model = model != null ? model : "";
+                table.put(
+                        R.string.metadata_camera,
+                        resources.getString(R.string.metadata_camera_format, make, model));
+        }
+
+        if (tags.containsKey(ExifInterface.TAG_APERTURE)) {
+            table.put(R.string.metadata_aperture, resources.getString(
+                    R.string.metadata_aperture_format, tags.getDouble(ExifInterface.TAG_APERTURE)));
+        }
+
+        if (tags.containsKey(ExifInterface.TAG_SHUTTER_SPEED_VALUE)) {
+            String shutterSpeed = String.valueOf(
+                    formatShutterSpeed(tags.getDouble(ExifInterface.TAG_SHUTTER_SPEED_VALUE)));
+            table.put(R.string.metadata_shutter_speed, shutterSpeed);
+        }
+
+        if (tags.containsKey(ExifInterface.TAG_FOCAL_LENGTH)) {
+            double length = tags.getDouble(ExifInterface.TAG_FOCAL_LENGTH);
+            table.put(R.string.metadata_focal_length,
+                    String.format(resources.getString(R.string.metadata_focal_format), length));
+        }
+
+        if (tags.containsKey(ExifInterface.TAG_ISO_SPEED_RATINGS)) {
+            int iso = tags.getInt(ExifInterface.TAG_ISO_SPEED_RATINGS);
+            table.put(R.string.metadata_iso_speed_ratings,
+                    String.format(resources.getString(R.string.metadata_iso_format), iso));
+        }
+
+        if (MetadataUtils.hasExifGpsFields(tags)) {
+            float[] coords = MetadataUtils.getExifGpsCoords(tags);
+            showCoordiantes(table, resources, coords, geoClickListener);
+            geoAddressFetcher.accept(coords);
+        }
+    }
+
+    private static void showCoordiantes(
+            TableDisplay table,
+            Resources resources,
+            float[] coords,
+            @Nullable Runnable geoClickListener) {
+
+        String value = resources.getString(
+                R.string.metadata_coordinates_format, coords[0], coords[1]);
+        if (geoClickListener != null) {
+            table.put(
+                    R.string.metadata_coordinates,
+                    value,
+                    view -> {
+                        geoClickListener.run();
+                    }
+            );
+        } else {
+            table.put(R.string.metadata_coordinates, value);
+        }
+    }
+
+    /**
+     * Attempts to retrieve an approximate address and displays the address if it can find one.
+     * @param coords the coordinates that gets an address.
+     */
+    private void getAddress(float[] coords) {
+        new AsyncTask<Float, Void, Address>() {
+            @Override
+            protected Address doInBackground(Float... coords) {
+                assert (coords.length == 2);
+                Geocoder geocoder = new Geocoder(mContext);
+                try {
+                    Address address = geocoder.getFromLocation(coords[0], // latitude
+                            coords[1], // longitude
+                            1 // amount of results returned
+                    ).get(0);
+                    return address;
+                } catch (IOException e) {
+                    return null;
+                }
+            }
+            @Override
+            protected void onPostExecute(@Nullable Address address) {
+                if (address != null) {
+                    TableDisplay table = MediaView.this;
+                    if (address.getMaxAddressLineIndex() >= 0) {
+                        String formattedAddress;
+                        StringBuilder addressBuilder = new StringBuilder("");
+                        addressBuilder.append(address.getAddressLine(0));
+                        for (int i = 1; i < address.getMaxAddressLineIndex(); i++) {
+                            addressBuilder.append("\n");
+                            addressBuilder.append(address.getAddressLine(i));
+                        }
+                        formattedAddress = addressBuilder.toString();
+                        table.put(R.string.metadata_address, formattedAddress);
+                    } else if (address.getLocality() != null) {
+                        table.put(R.string.metadata_address, address.getLocality());
+                    } else if (address.getSubAdminArea() != null) {
+                        table.put(R.string.metadata_address, address.getSubAdminArea());
+                    } else if (address.getAdminArea() != null) {
+                        table.put(R.string.metadata_address, address.getAdminArea());
+                    } else if (address.getCountryName() != null) {
+                        table.put(R.string.metadata_address, address.getCountryName());
+                    }                }
+            }
+        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, coords[0], coords[1]);
+    }
+
+    /**
+     * @param speed a value n, where shutter speed equals 1/(2^n)
+     * @return a String containing either a fraction that displays 1 over a positive integer, or a
+     * double rounded to one decimal, depending on if 1/(2^n) is less than or greater than 1,
+     * respectively.
+     */
+    private static String formatShutterSpeed(double speed) {
+        if (speed <= 0) {
+            double shutterSpeed = Math.pow(2, -1 * speed);
+            String formattedSpeed = String.valueOf(Math.round(shutterSpeed * 10.0) / 10.0);
+            return formattedSpeed;
+        } else {
+            int approximateSpeedDenom = (int) Math.pow(2, speed) + 1;
+            String formattedSpeed = "1/" + String.valueOf(approximateSpeedDenom);
+            return formattedSpeed;
+        }
+    }
+
+    /**
+     * @param table
+     * @param resources
+     * @param tags
+     */
+    private static void addDimensionsRow(TableDisplay table, Resources resources, Bundle tags) {
+        if (tags.containsKey(ExifInterface.TAG_IMAGE_WIDTH)
+            && tags.containsKey(ExifInterface.TAG_IMAGE_LENGTH)) {
+            int width = tags.getInt(ExifInterface.TAG_IMAGE_WIDTH);
+            int height = tags.getInt(ExifInterface.TAG_IMAGE_LENGTH);
+            float megaPixels = height * width / 1000000f;
+            table.put(R.string.metadata_dimensions,
+                    resources.getString(
+                            R.string.metadata_dimensions_format, width, height, megaPixels));
+        }
+    }
+}
diff --git a/src/com/android/documentsui/inspector/MetadataLoader.java b/src/com/android/documentsui/inspector/MetadataLoader.java
new file mode 100644
index 0000000..3de15ba
--- /dev/null
+++ b/src/com/android/documentsui/inspector/MetadataLoader.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 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.documentsui.inspector;
+
+import android.content.AsyncTaskLoader;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.DocumentsContract;
+import android.support.annotation.Nullable;
+import android.util.Log;
+
+import java.io.FileNotFoundException;
+
+/**
+ * Loads metadata from {@link DocumentsContract#getDocumentMetadata(android.content.ContentProviderClient, Uri, String[])}
+ */
+final class MetadataLoader extends AsyncTaskLoader<Bundle> {
+
+    private static final String TAG = "MetadataLoader";
+
+    private final Context mContext;
+    private final Uri mUri;
+
+    private @Nullable Bundle mMetadata;
+
+    MetadataLoader(Context context, Uri uri) {
+        super(context);
+        mContext = context;
+        mUri = uri;
+    }
+
+    @Override
+    public Bundle loadInBackground() {
+        try {
+            return DocumentsContract.getDocumentMetadata(mContext.getContentResolver(), mUri);
+        } catch (FileNotFoundException e) {
+            Log.e(TAG, "Failed to load metadata for doc: " + mUri, e);
+        }
+
+        return null;
+    }
+
+    @Override
+    protected void onStartLoading() {
+        if (mMetadata != null) {
+            deliverResult(mMetadata);
+        }
+        if (takeContentChanged() || mMetadata == null) {
+            forceLoad();
+        }
+    }
+
+    @Override
+    public void deliverResult(Bundle metadata) {
+        if (isReset()) {
+            return;
+        }
+        mMetadata = metadata;
+        if (isStarted()) {
+            super.deliverResult(metadata);
+        }
+    }
+
+    /**
+     * Must be called from the UI thread
+     */
+    @Override
+    protected void onStopLoading() {
+        // Attempt to cancel the current load task if possible.
+        cancelLoad();
+    }
+
+    @Override
+    protected void onReset() {
+        super.onReset();
+
+        // Ensure the loader is stopped
+        onStopLoading();
+
+        mMetadata = null;
+    }
+}
diff --git a/src/com/android/documentsui/inspector/MetadataUtils.java b/src/com/android/documentsui/inspector/MetadataUtils.java
new file mode 100644
index 0000000..b5c1034
--- /dev/null
+++ b/src/com/android/documentsui/inspector/MetadataUtils.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2017 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.documentsui.inspector;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.media.ExifInterface;
+import android.os.Bundle;
+import android.provider.DocumentsContract;
+
+import com.android.documentsui.base.Shared;
+
+import javax.annotation.Nullable;
+
+final class MetadataUtils {
+
+    private MetadataUtils() {}
+
+    static boolean hasGeoCoordinates(@Nullable Bundle metadata) {
+        if (metadata == null) {
+            return false;
+        }
+        return hasVideoCoordinates(metadata.getBundle(Shared.METADATA_KEY_VIDEO))
+                || hasExifGpsFields(metadata.getBundle(DocumentsContract.METADATA_EXIF));
+    }
+
+    static boolean hasVideoCoordinates(@Nullable Bundle data) {
+        return data != null && (data.containsKey(Shared.METADATA_VIDEO_LATITUDE)
+                && data.containsKey(Shared.METADATA_VIDEO_LONGITUTE));
+    }
+
+    static boolean hasExifGpsFields(@Nullable Bundle exif) {
+        return exif != null && (exif.containsKey(ExifInterface.TAG_GPS_LATITUDE)
+                && exif.containsKey(ExifInterface.TAG_GPS_LONGITUDE)
+                && exif.containsKey(ExifInterface.TAG_GPS_LATITUDE_REF)
+                && exif.containsKey(ExifInterface.TAG_GPS_LONGITUDE_REF));
+    }
+
+    static float[] getGeoCoordinates(Bundle metadata) {
+        assert hasGeoCoordinates(metadata);
+        checkNotNull(metadata);
+
+        Bundle bundle = metadata.getBundle(DocumentsContract.METADATA_EXIF);
+        if (hasExifGpsFields(bundle)) {
+            return getExifGpsCoords(bundle);
+        }
+
+        bundle = metadata.getBundle(Shared.METADATA_KEY_VIDEO);
+        if (hasVideoCoordinates(bundle)) {
+            return getVideoCoords(bundle);
+        }
+
+        // This should never happen, because callers should always check w/ hasGeoCoordinates first.
+        throw new IllegalArgumentException("Invalid metadata bundle: " + metadata);
+    }
+
+    static float[] getExifGpsCoords(Bundle exif) {
+        assert hasExifGpsFields(exif);
+
+        String lat = exif.getString(ExifInterface.TAG_GPS_LATITUDE);
+        String lon = exif.getString(ExifInterface.TAG_GPS_LONGITUDE);
+        String latRef = exif.getString(ExifInterface.TAG_GPS_LATITUDE_REF);
+        String lonRef = exif.getString(ExifInterface.TAG_GPS_LONGITUDE_REF);
+
+        return new float[] {
+            ExifInterface.convertRationalLatLonToFloat(lat, latRef),
+            ExifInterface.convertRationalLatLonToFloat(lon, lonRef)
+        };
+    }
+
+    static float[] getVideoCoords(Bundle data) {
+        assert hasVideoCoordinates(data);
+        return new float[] {
+                data.getFloat(Shared.METADATA_VIDEO_LATITUDE),
+                data.getFloat(Shared.METADATA_VIDEO_LONGITUTE)
+        };
+    }
+}
diff --git a/src/com/android/documentsui/inspector/DocumentLoader.java b/src/com/android/documentsui/inspector/RuntimeDataSupplier.java
similarity index 77%
rename from src/com/android/documentsui/inspector/DocumentLoader.java
rename to src/com/android/documentsui/inspector/RuntimeDataSupplier.java
index 9c92b1c..e6cbda9 100644
--- a/src/com/android/documentsui/inspector/DocumentLoader.java
+++ b/src/com/android/documentsui/inspector/RuntimeDataSupplier.java
@@ -27,32 +27,35 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
-
 import android.provider.DocumentsContract;
 import android.support.annotation.Nullable;
+
 import com.android.documentsui.base.DocumentInfo;
-import com.android.documentsui.inspector.InspectorController.Loader;
+import com.android.documentsui.inspector.InspectorController.DataSupplier;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.function.Consumer;
 
 /**
- * Asynchronously loads a document's metadata for the inspector.
+ * Asynchronously loads a document data for the inspector.
+ *
+ * <p>This loader is not a Loader! Its our own funky loader.
  */
-public class DocumentLoader implements Loader {
+public class RuntimeDataSupplier implements DataSupplier {
 
     private final Context mContext;
-    private final LoaderManager mLoader;
-    private List<Integer> loaderIds;
+    private final LoaderManager mLoaderMgr;
+    private final List<Integer> loaderIds = new ArrayList<>();
     private @Nullable Callbacks mDocCallbacks;
     private @Nullable Callbacks mDirCallbacks;
+    private @Nullable LoaderCallbacks<Bundle> mMetadataCallbacks;
 
-    public DocumentLoader(Context context, LoaderManager loader) {
+    public RuntimeDataSupplier(Context context, LoaderManager loaderMgr) {
         checkArgument(context != null);
-        checkArgument(loader != null);
+        checkArgument(loaderMgr != null);
         mContext = context;
-        mLoader = loader;
-        loaderIds = new ArrayList<>();
+        mLoaderMgr = loaderMgr;
     }
 
     /**
@@ -63,14 +66,10 @@
         //Check that we have correct Uri type and that the loader is not already created.
         checkArgument(uri.getScheme().equals("content"));
 
-        //get a new loader id.
-        int loadId = getNextLoaderId();
-        checkArgument(mLoader.getLoader(loadId) == null);
-        loaderIds.add(loadId);
-
         Consumer<Cursor> callback = new Consumer<Cursor>() {
             @Override
             public void accept(Cursor cursor) {
+
                 if (cursor == null || !cursor.moveToFirst()) {
                     updateView.accept(null);
                 } else {
@@ -81,7 +80,7 @@
         };
 
         mDocCallbacks = new Callbacks(mContext, uri, callback);
-        mLoader.restartLoader(loadId, null, mDocCallbacks);
+        mLoaderMgr.restartLoader(getNextLoaderId(), null, mDocCallbacks);
     }
 
     /**
@@ -93,11 +92,6 @@
         Uri children = DocumentsContract.buildChildDocumentsUri(
                 directory.authority, directory.documentId);
 
-        //get a new loader id.
-        int loadId = getNextLoaderId();
-        checkArgument(mLoader.getLoader(loadId) == null);
-        loaderIds.add(loadId);
-
         Consumer<Cursor> callback = new Consumer<Cursor>() {
             @Override
             public void accept(Cursor cursor) {
@@ -108,30 +102,54 @@
         };
 
         mDirCallbacks = new Callbacks(mContext, children, callback);
-        mLoader.restartLoader(loadId, null, mDirCallbacks);
+        mLoaderMgr.restartLoader(getNextLoaderId(), null, mDirCallbacks);
+    }
+
+    @Override
+    public void getDocumentMetadata(Uri uri, Consumer<Bundle> callback) {
+        mMetadataCallbacks = new LoaderCallbacks<Bundle>() {
+            @Override
+            public android.content.Loader<Bundle> onCreateLoader(int id, Bundle unused) {
+                return new MetadataLoader(mContext, uri);
+            }
+
+            @Override
+            public void onLoadFinished(android.content.Loader<Bundle> loader, Bundle data) {
+                callback.accept(data);
+            }
+
+            @Override
+            public void onLoaderReset(android.content.Loader<Bundle> loader) {
+            }
+        };
+
+        // TODO: Listen for changes on content URI.
+        mLoaderMgr.restartLoader(getNextLoaderId(), null, mMetadataCallbacks);
     }
 
     @Override
     public void reset() {
         for (Integer id : loaderIds) {
-            mLoader.destroyLoader(id);
+            mLoaderMgr.destroyLoader(id);
         }
         loaderIds.clear();
 
         if (mDocCallbacks != null && mDocCallbacks.getObserver() != null) {
             mContext.getContentResolver().unregisterContentObserver(mDocCallbacks.getObserver());
         }
+
         if (mDirCallbacks != null && mDirCallbacks.getObserver() != null) {
-            mContext.getContentResolver().unregisterContentObserver(mDocCallbacks.getObserver());
+            mContext.getContentResolver().unregisterContentObserver(mDirCallbacks.getObserver());
         }
     }
 
     private int getNextLoaderId() {
         int id = 0;
-        while(mLoader.getLoader(id) != null) {
+        while(mLoaderMgr.getLoader(id) != null) {
             id++;
             checkArgument(id <= Integer.MAX_VALUE);
         }
+        loaderIds.add(id);
         return id;
     }
 
@@ -195,4 +213,4 @@
             mContentChangedCallback.run();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/com/android/documentsui/inspector/TableView.java b/src/com/android/documentsui/inspector/TableView.java
index 91c30d8..191e89a 100644
--- a/src/com/android/documentsui/inspector/TableView.java
+++ b/src/com/android/documentsui/inspector/TableView.java
@@ -20,28 +20,29 @@
 import android.content.res.Resources;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
+import android.view.View;
 import android.view.ViewGroup;
+import android.view.textclassifier.TextClassifier;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import com.android.documentsui.R;
+import com.android.documentsui.inspector.InspectorController.TableDisplay;
 
 import java.util.HashMap;
 import java.util.Map;
 
-import javax.annotation.Nullable;
-
-
 /**
  * Organizes and Displays the basic details about a file
  */
-public class TableView extends LinearLayout {
+public class TableView extends LinearLayout implements TableDisplay {
 
     private final LayoutInflater mInflater;
 
-    private final Map<String, KeyValueRow> mRows = new HashMap<>();
+    private final Map<CharSequence, KeyValueRow> mRows = new HashMap<>();
     private final Resources mRes;
-    private @Nullable TextView mTitle;
+    private final Map<CharSequence, TextView> mTitles = new HashMap<>();
+    private final TextClassifier mClassifier;
 
     public TableView(Context context) {
         this(context, null);
@@ -55,40 +56,77 @@
         super(context, attrs, defStyleAttr);
         mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         mRes = context.getResources();
+        mClassifier = GpsCoordinatesTextClassifier.create(context);
     }
 
-    protected void setTitle(ViewGroup parent, @StringRes int title) {
-        if (mTitle == null) {
-            mTitle = (TextView) mInflater.inflate(R.layout.inspector_section_title, null);
-            parent.addView(mTitle);
+    void setTitle(@StringRes int title, boolean showDivider) {
+        putTitle(mContext.getResources().getString(title), showDivider);
+    }
+
+    // A naughty title method (that takes strings, not message ids), mostly for DebugView.
+    protected void putTitle(CharSequence title, boolean showDivider) {
+        TextView view = mTitles.get(title);
+        if (view == null) {
+            LinearLayout layout =
+                (LinearLayout) mInflater.inflate(R.layout.inspector_section_title, null);
+            if (!showDivider) {
+                layout.setDividerDrawable(null);
+            }
+            view = (TextView) layout.findViewById(R.id.inspector_header_title);
+            addView(layout);
+            mTitles.put(title, view);
         }
-        mTitle.setText(mContext.getResources().getString(title));
+        view.setText(title);
     }
 
     protected KeyValueRow createKeyValueRow(ViewGroup parent) {
         KeyValueRow row = (KeyValueRow) mInflater.inflate(R.layout.table_key_value_row, null);
         parent.addView(row);
+        row.setTextClassifier(mClassifier);
         return row;
     }
 
     /**
-     * Puts or updates an value in the table view.
+     * Puts or updates a value in the table view.
      */
-    protected void put(@StringRes int keyId, String value) {
+    @Override
+    public void put(@StringRes int keyId, CharSequence value) {
         put(mRes.getString(keyId), value);
     }
 
+
     /**
-     * Puts or updates an value in the table view.
+     * Puts or updates a value in the table view.
      */
-    protected void put(String key, String value) {
-        if(mRows.containsKey(key)) {
-            mRows.get(key).setValue(value);
-        } else {
-            KeyValueRow row = createKeyValueRow(this);
+    protected KeyValueRow put(CharSequence key, CharSequence value) {
+        KeyValueRow row = mRows.get(key);
+
+        if (row == null) {
+            row = createKeyValueRow(this);
             row.setKey(key);
-            row.setValue(value);
             mRows.put(key, row);
+        } else {
+            row.removeOnClickListener();
         }
+
+        row.setValue(value);
+        row.setTextClassifier(mClassifier);
+        return row;
+    }
+
+    @Override
+    public void put(@StringRes int keyId, CharSequence value, OnClickListener callback) {
+        put(keyId, value);
+        mRows.get(mRes.getString(keyId)).setOnClickListener(callback);
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return mRows.isEmpty();
+    }
+
+    @Override
+    public void setVisible(boolean visible) {
+        setVisibility(visible ? View.VISIBLE : View.GONE);
     }
 }
diff --git a/src/com/android/documentsui/inspector/actions/Action.java b/src/com/android/documentsui/inspector/actions/Action.java
index 1b0b693..d90d6dc 100644
--- a/src/com/android/documentsui/inspector/actions/Action.java
+++ b/src/com/android/documentsui/inspector/actions/Action.java
@@ -17,6 +17,7 @@
 package com.android.documentsui.inspector.actions;
 
 import android.annotation.Nullable;
+import android.annotation.StringRes;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
@@ -54,6 +55,8 @@
 
     public abstract @Nullable String getPackageName();
 
+    public abstract @StringRes int getButtonLabel();
+
     public @Nullable Drawable getAppIcon() {
 
         String packageName = getPackageName();
diff --git a/src/com/android/documentsui/inspector/actions/ActionView.java b/src/com/android/documentsui/inspector/actions/ActionView.java
index 485e2b1..b519bcc 100644
--- a/src/com/android/documentsui/inspector/actions/ActionView.java
+++ b/src/com/android/documentsui/inspector/actions/ActionView.java
@@ -15,6 +15,7 @@
  */
 package com.android.documentsui.inspector.actions;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
@@ -34,6 +35,7 @@
  */
 public final class ActionView extends LinearLayout implements InspectorController.ActionDisplay {
 
+    private Context mContext;
     private final TextView mHeader;
     private final ImageView mAppIcon;
     private final TextView mAppName;
@@ -55,12 +57,18 @@
         View view = inflater.inflate(R.layout.inspector_action_view, null);
         addView(view);
 
-        mHeader = (TextView) findViewById(R.id.action_header);
+        mContext = context;
+        mHeader = getSectionTitle();
         mAppIcon = (ImageView) findViewById(R.id.app_icon);
         mAppName = (TextView) findViewById(R.id.app_name);
         mActionButton = (ImageButton) findViewById(R.id.inspector_action_button);
     }
 
+    public TextView getSectionTitle() {
+        LinearLayout header = (LinearLayout) findViewById(R.id.action_header);
+        return (TextView) header.findViewById(R.id.inspector_header_title);
+    }
+
     @Override
     public void init(Action action, OnClickListener listener) {
         mAction = action;
@@ -68,6 +76,7 @@
 
         setAppIcon(mAction.getAppIcon());
         setAppName(mAction.getAppName());
+        mActionButton.setContentDescription(mContext.getString(action.getButtonLabel()));
 
         mActionButton.setOnClickListener(listener);
         showAction(true);
@@ -84,8 +93,14 @@
     }
 
     @Override
-    public void setAppIcon(Drawable icon) {
-        mAppIcon.setImageDrawable(icon);
+    public void setAppIcon(@Nullable Drawable icon) {
+
+        if (icon != null) {
+            mAppIcon.setVisibility(View.VISIBLE);
+            mAppIcon.setImageDrawable(icon);
+        } else {
+            mAppIcon.setVisibility(View.GONE);
+        }
     }
 
     @Override
diff --git a/src/com/android/documentsui/inspector/actions/ClearDefaultAppAction.java b/src/com/android/documentsui/inspector/actions/ClearDefaultAppAction.java
index 4f954ba..f8f6aeb 100644
--- a/src/com/android/documentsui/inspector/actions/ClearDefaultAppAction.java
+++ b/src/com/android/documentsui/inspector/actions/ClearDefaultAppAction.java
@@ -15,6 +15,7 @@
  */
 package com.android.documentsui.inspector.actions;
 
+import android.annotation.StringRes;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -84,4 +85,8 @@
             return null;
         }
     }
+
+    public @StringRes int getButtonLabel() {
+        return R.string.button_clear;
+    }
 }
\ No newline at end of file
diff --git a/src/com/android/documentsui/inspector/actions/ShowInProviderAction.java b/src/com/android/documentsui/inspector/actions/ShowInProviderAction.java
index aee649d..0dc221a 100644
--- a/src/com/android/documentsui/inspector/actions/ShowInProviderAction.java
+++ b/src/com/android/documentsui/inspector/actions/ShowInProviderAction.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 
+import android.support.annotation.StringRes;
 import com.android.documentsui.R;
 import com.android.documentsui.base.DocumentInfo;
 import com.android.documentsui.roots.ProvidersAccess;
@@ -67,4 +68,8 @@
     public String getPackageName() {
         return mProviders.getPackageName(mDoc.derivedUri.getAuthority());
     }
+
+    public @StringRes int getButtonLabel() {
+        return R.string.button_show_provider;
+    }
 }
\ No newline at end of file
diff --git a/src/com/android/documentsui/picker/ActionHandler.java b/src/com/android/documentsui/picker/ActionHandler.java
index 0a3972a..4511fef 100644
--- a/src/com/android/documentsui/picker/ActionHandler.java
+++ b/src/com/android/documentsui/picker/ActionHandler.java
@@ -16,7 +16,7 @@
 
 package com.android.documentsui.picker;
 
-import static com.android.documentsui.base.Shared.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
 import static com.android.documentsui.base.State.ACTION_CREATE;
 import static com.android.documentsui.base.State.ACTION_GET_CONTENT;
 import static com.android.documentsui.base.State.ACTION_OPEN;
@@ -41,6 +41,7 @@
 import com.android.documentsui.DocumentsAccess;
 import com.android.documentsui.Injector;
 import com.android.documentsui.Metrics;
+import com.android.documentsui.Model;
 import com.android.documentsui.base.BooleanConsumer;
 import com.android.documentsui.base.DocumentInfo;
 import com.android.documentsui.base.DocumentStack;
@@ -50,11 +51,10 @@
 import com.android.documentsui.base.Shared;
 import com.android.documentsui.base.State;
 import com.android.documentsui.dirlist.AnimationView;
-import com.android.documentsui.dirlist.DocumentDetails;
-import com.android.documentsui.Model;
 import com.android.documentsui.picker.ActionHandler.Addons;
 import com.android.documentsui.queries.SearchViewManager;
 import com.android.documentsui.roots.ProvidersAccess;
+import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
 import com.android.documentsui.services.FileOperationService;
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -246,12 +246,12 @@
     }
 
     @Override
-    public boolean openDocument(DocumentDetails details, @ViewType int type,
+    public boolean openItem(ItemDetails details, @ViewType int type,
             @ViewType int fallback) {
-        DocumentInfo doc = mModel.getDocument(details.getModelId());
+        DocumentInfo doc = mModel.getDocument(details.getStableId());
         if (doc == null) {
             Log.w(TAG,
-                    "Can't view item. No Document available for modeId: " + details.getModelId());
+                    "Can't view item. No Document available for modeId: " + details.getStableId());
             return false;
         }
 
@@ -374,6 +374,7 @@
     }
 
     public interface Addons extends CommonAddons {
+        @Override
         void onDocumentPicked(DocumentInfo doc);
 
         /**
diff --git a/src/com/android/documentsui/picker/PickActivity.java b/src/com/android/documentsui/picker/PickActivity.java
index fb43ce6..94327b1 100644
--- a/src/com/android/documentsui/picker/PickActivity.java
+++ b/src/com/android/documentsui/picker/PickActivity.java
@@ -34,6 +34,7 @@
 
 import com.android.documentsui.ActionModeController;
 import com.android.documentsui.BaseActivity;
+import com.android.documentsui.DocsSelectionHelper;
 import com.android.documentsui.DocumentsApplication;
 import com.android.documentsui.FocusManager;
 import com.android.documentsui.Injector;
@@ -49,7 +50,6 @@
 import com.android.documentsui.base.State;
 import com.android.documentsui.dirlist.DirectoryFragment;
 import com.android.documentsui.prefs.ScopedPreferences;
-import com.android.documentsui.selection.SelectionManager;
 import com.android.documentsui.services.FileOperationService;
 import com.android.documentsui.sidebar.RootsFragment;
 import com.android.documentsui.ui.DialogController;
@@ -94,10 +94,9 @@
 
         super.onCreate(icicle);
 
-        mInjector.selectionMgr = new SelectionManager(
-                mState.allowMultiple
-                        ? SelectionManager.MODE_MULTIPLE
-                        : SelectionManager.MODE_SINGLE);
+        mInjector.selectionMgr = mState.allowMultiple
+                ? DocsSelectionHelper.createMultiSelect()
+                : DocsSelectionHelper.createSingleSelect();
 
         mInjector.focusManager = new FocusManager(
                 mInjector.features,
diff --git a/src/com/android/documentsui/prefs/LocalPreferences.java b/src/com/android/documentsui/prefs/LocalPreferences.java
index 48a9220..955b19d 100644
--- a/src/com/android/documentsui/prefs/LocalPreferences.java
+++ b/src/com/android/documentsui/prefs/LocalPreferences.java
@@ -19,20 +19,19 @@
 import static com.android.documentsui.base.State.MODE_UNKNOWN;
 
 import android.annotation.IntDef;
-import android.annotation.Nullable;
 import android.content.Context;
 import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
-import android.os.UserHandle;
 import android.preference.PreferenceManager;
 
 import com.android.documentsui.base.RootInfo;
-import com.android.documentsui.base.State;
 import com.android.documentsui.base.State.ViewMode;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
+/**
+ * Methods for accessing the local preferences.
+ */
 public class LocalPreferences {
     private static final String ROOT_VIEW_MODE_PREFIX = "rootViewMode-";
 
@@ -66,64 +65,6 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface PermissionStatus {}
 
-    /**
-     * Clears all preferences associated with a given package.
-     *
-     * <p>Typically called when a package is removed or when user asked to clear its data.
-     */
-    public static void clearPackagePreferences(Context context, String packageName) {
-        clearScopedAccessPreferences(context, packageName);
-    }
-
-    /**
-     * Methods below are used to keep track of denied user requests on scoped directory access so
-     * the dialog is not offered when user checked the 'Do not ask again' box
-     *
-     * <p>It uses a shared preferences, whose key is:
-     * <ol>
-     * <li>{@code USER_ID|PACKAGE_NAME|VOLUME_UUID|DIRECTORY} for storage volumes that have a UUID
-     * (typically physical volumes like SD cards).
-     * <li>{@code USER_ID|PACKAGE_NAME||DIRECTORY} for storage volumes that do not have a UUID
-     * (typically the emulated volume used for primary storage
-     * </ol>
-     */
-    public static @PermissionStatus int getScopedAccessPermissionStatus(Context context,
-            String packageName, @Nullable String uuid, String directory) {
-        final String key = getScopedAccessDenialsKey(packageName, uuid, directory);
-        return getPrefs(context).getInt(key, PERMISSION_ASK);
-    }
-
-    public static void setScopedAccessPermissionStatus(Context context, String packageName,
-            @Nullable String uuid, String directory, @PermissionStatus int status) {
-      final String key = getScopedAccessDenialsKey(packageName, uuid, directory);
-      getPrefs(context).edit().putInt(key, status).apply();
-    }
-
-    private static void clearScopedAccessPreferences(Context context, String packageName) {
-        final String keySubstring = "|" + packageName + "|";
-        final SharedPreferences prefs = getPrefs(context);
-        Editor editor = null;
-        for (final String key : prefs.getAll().keySet()) {
-            if (key.contains(keySubstring)) {
-                if (editor == null) {
-                    editor = prefs.edit();
-                }
-                editor.remove(key);
-            }
-        }
-        if (editor != null) {
-            editor.apply();
-        }
-    }
-
-    private static String getScopedAccessDenialsKey(String packageName, String uuid,
-            String directory) {
-        final int userId = UserHandle.myUserId();
-        return uuid == null
-                ? userId + "|" + packageName + "||" + directory
-                : userId + "|" + packageName + "|" + uuid + "|" + directory;
-    }
-
     public static boolean shouldBackup(String s) {
         return (s != null) ? s.startsWith(ROOT_VIEW_MODE_PREFIX) : false;
     }
diff --git a/src/com/android/documentsui/prefs/ScopedAccessLocalPreferences.java b/src/com/android/documentsui/prefs/ScopedAccessLocalPreferences.java
new file mode 100644
index 0000000..5da0e49
--- /dev/null
+++ b/src/com/android/documentsui/prefs/ScopedAccessLocalPreferences.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2017 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.documentsui.prefs;
+
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DIRECTORY_ROOT;
+import static com.android.internal.util.Preconditions.checkArgument;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.os.UserHandle;
+import android.preference.PreferenceManager;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Methods for accessing the local preferences with regards to scoped directory access.
+ */
+//TODO(b/72055774): add unit tests
+public class ScopedAccessLocalPreferences {
+
+    private static final String TAG = "ScopedAccessLocalPreferences";
+
+    private static SharedPreferences getPrefs(Context context) {
+        return PreferenceManager.getDefaultSharedPreferences(context);
+    }
+
+    public static final int PERMISSION_ASK = 0;
+    public static final int PERMISSION_ASK_AGAIN = 1;
+    public static final int PERMISSION_NEVER_ASK = -1;
+    // NOTE: this status is not used on preferences, but on permissions granted by AM
+    public static final int PERMISSION_GRANTED = 2;
+
+    @IntDef(flag = true, value = {
+            PERMISSION_ASK,
+            PERMISSION_ASK_AGAIN,
+            PERMISSION_NEVER_ASK,
+            PERMISSION_GRANTED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PermissionStatus {}
+
+    private static final String KEY_REGEX = "^.+\\|(.+)\\|(.*)\\|(.+)$";
+    private static final Pattern KEY_PATTERN = Pattern.compile(KEY_REGEX);
+
+    /**
+     * Methods below are used to keep track of denied user requests on scoped directory access so
+     * the dialog is not offered when user checked the 'Do not ask again' box
+     *
+     * <p>It uses a shared preferences, whose key is:
+     * <ol>
+     * <li>{@code USER_ID|PACKAGE_NAME|VOLUME_UUID|DIRECTORY} for storage volumes that have a UUID
+     * (typically physical volumes like SD cards).
+     * <li>{@code USER_ID|PACKAGE_NAME||DIRECTORY} for storage volumes that do not have a UUID
+     * (typically the emulated volume used for primary storage
+     * </ol>
+     */
+    public static @PermissionStatus int getScopedAccessPermissionStatus(Context context,
+            String packageName, @Nullable String uuid, String directory) {
+        final String key = getScopedAccessDenialsKey(packageName, uuid, directory);
+        return getPrefs(context).getInt(key, PERMISSION_ASK);
+    }
+
+    public static void setScopedAccessPermissionStatus(Context context, String packageName,
+            @Nullable String uuid, String directory, @PermissionStatus int status) {
+        checkArgument(!TextUtils.isEmpty(directory),
+                "Cannot pass empty directory - did you mean %s?", DIRECTORY_ROOT);
+        final String key = getScopedAccessDenialsKey(packageName, uuid, directory);
+        if (DEBUG) {
+            Log.d(TAG, "Setting permission of " + packageName + ":" + uuid + ":" + directory
+                    + " to " + statusAsString(status));
+        }
+
+        getPrefs(context).edit().putInt(key, status).apply();
+    }
+
+    public static int clearScopedAccessPreferences(Context context, String packageName) {
+        final String keySubstring = "|" + packageName + "|";
+        final SharedPreferences prefs = getPrefs(context);
+        Editor editor = null;
+        int removed = 0;
+        for (final String key : prefs.getAll().keySet()) {
+            if (key.contains(keySubstring)) {
+                if (editor == null) {
+                    editor = prefs.edit();
+                }
+                editor.remove(key);
+                removed ++;
+            }
+        }
+        if (editor != null) {
+            editor.apply();
+        }
+        return removed;
+    }
+
+    private static String getScopedAccessDenialsKey(String packageName, @Nullable String uuid,
+            String directory) {
+        final int userId = UserHandle.myUserId();
+        return uuid == null
+                ? userId + "|" + packageName + "||" + directory
+                : userId + "|" + packageName + "|" + uuid + "|" + directory;
+    }
+
+    /**
+     * Clears all preferences associated with a given package.
+     *
+     * <p>Typically called when a package is removed or when user asked to clear its data.
+     */
+    public static void clearPackagePreferences(Context context, String packageName) {
+        ScopedAccessLocalPreferences.clearScopedAccessPreferences(context, packageName);
+    }
+
+    /**
+     * Gets all packages that have entries in the preferences
+     */
+    public static Set<String> getAllPackages(Context context) {
+        final SharedPreferences prefs = getPrefs(context);
+
+        final ArraySet<String> pkgs = new ArraySet<>();
+        for (Entry<String, ?> pref : prefs.getAll().entrySet()) {
+            final String key = pref.getKey();
+            final String pkg = getPackage(key);
+            if (pkg == null) {
+                Log.w(TAG, "getAllPackages(): error parsing pref '" + key + "'");
+                continue;
+            }
+            pkgs.add(pkg);
+        }
+        return pkgs;
+    }
+
+    /**
+     * Gets all permissions.
+     */
+    public static List<Permission> getAllPermissions(Context context) {
+        final SharedPreferences prefs = getPrefs(context);
+        final ArrayList<Permission> permissions = new ArrayList<>();
+
+        for (Entry<String, ?> pref : prefs.getAll().entrySet()) {
+            final String key = pref.getKey();
+            final Object value = pref.getValue();
+            final Integer status;
+            try {
+                status = (Integer) value;
+            } catch (Exception e) {
+                Log.w(TAG, "error gettting value for key '" + key + "': " + value);
+                continue;
+            }
+            final Permission permission = getPermission(key, status);
+            if (permission != null) {
+                permissions.add(permission);
+            }
+        }
+
+        return permissions;
+    }
+
+    public static String statusAsString(@PermissionStatus int status) {
+        switch (status) {
+            case PERMISSION_ASK:
+                return "PERMISSION_ASK";
+            case PERMISSION_ASK_AGAIN:
+                return "PERMISSION_ASK_AGAIN";
+            case PERMISSION_NEVER_ASK:
+                return "PERMISSION_NEVER_ASK";
+            case PERMISSION_GRANTED:
+                return "PERMISSION_GRANTED";
+            default:
+                return "UNKNOWN";
+        }
+    }
+
+    @Nullable
+    private static String getPackage(String key) {
+        final Matcher matcher = KEY_PATTERN.matcher(key);
+        return matcher.matches() ? matcher.group(1) : null;
+    }
+
+    private static Permission getPermission(String key, Integer status) {
+        final Matcher matcher = KEY_PATTERN.matcher(key);
+        if (!matcher.matches()) return null;
+
+        final String pkg = matcher.group(1);
+        final String uuid = matcher.group(2);
+        final String directory = matcher.group(3);
+
+        return new Permission(pkg, uuid, directory, status);
+    }
+
+    public static final class Permission {
+        public final String pkg;
+
+        @Nullable
+        public final String uuid;
+        public final String directory;
+        public final int status;
+
+        public Permission(String pkg, String uuid, String directory, Integer status) {
+            this.pkg = pkg;
+            this.uuid = TextUtils.isEmpty(uuid) ? null : uuid;
+            this.directory = directory;
+            this.status = status.intValue();
+        }
+
+        @Override
+        public String toString() {
+            return "Permission: [pkg=" + pkg + ", uuid=" + uuid + ", dir=" + directory + ", status="
+                    + statusAsString(status) + " (" + status + ")]";
+        }
+    }
+}
diff --git a/src/com/android/documentsui/queries/CommandInterceptor.java b/src/com/android/documentsui/queries/CommandInterceptor.java
index 84e563e..143b933 100644
--- a/src/com/android/documentsui/queries/CommandInterceptor.java
+++ b/src/com/android/documentsui/queries/CommandInterceptor.java
@@ -15,7 +15,7 @@
  */
 package com.android.documentsui.queries;
 
-import static com.android.documentsui.base.Shared.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
 
 import android.content.Context;
 import android.support.annotation.VisibleForTesting;
diff --git a/src/com/android/documentsui/queries/SearchViewManager.java b/src/com/android/documentsui/queries/SearchViewManager.java
index 6a2790d..fab5a93 100644
--- a/src/com/android/documentsui/queries/SearchViewManager.java
+++ b/src/com/android/documentsui/queries/SearchViewManager.java
@@ -16,10 +16,12 @@
 
 package com.android.documentsui.queries;
 
-import static com.android.documentsui.base.Shared.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
 
 import android.annotation.Nullable;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
 import android.provider.DocumentsContract.Root;
 import android.text.TextUtils;
 import android.util.Log;
@@ -38,6 +40,11 @@
 import com.android.documentsui.base.EventHandler;
 import com.android.documentsui.base.RootInfo;
 import com.android.documentsui.base.Shared;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Timer;
+import java.util.TimerTask;
 
 /**
  * Manages searching UI behavior.
@@ -48,9 +55,19 @@
 
     private static final String TAG = "SearchManager";
 
+    // How long we wait after the user finishes typing before kicking off a search.
+    public static final int SEARCH_DELAY_MS = 750;
+
     private final SearchManagerListener mListener;
     private final EventHandler<String> mCommandProcessor;
+    private final Timer mTimer;
+    private final Handler mUiHandler;
 
+    private final Object mSearchLock;
+    @GuardedBy("mSearchLock")
+    private @Nullable Runnable mQueuedSearchRunnable;
+    @GuardedBy("mSearchLock")
+    private @Nullable TimerTask mQueuedSearchTask;
     private @Nullable String mCurrentSearch;
     private boolean mSearchExpanded;
     private boolean mIgnoreNextClose;
@@ -64,12 +81,25 @@
             SearchManagerListener listener,
             EventHandler<String> commandProcessor,
             @Nullable Bundle savedState) {
+        this(listener, commandProcessor, savedState, new Timer(),
+                new Handler(Looper.getMainLooper()));
+    }
 
+    @VisibleForTesting
+    protected SearchViewManager(
+            SearchManagerListener listener,
+            EventHandler<String> commandProcessor,
+            @Nullable Bundle savedState,
+            Timer timer,
+            Handler handler) {
         assert (listener != null);
         assert (commandProcessor != null);
 
+        mSearchLock = new Object();
         mListener = listener;
         mCommandProcessor = commandProcessor;
+        mTimer = timer;
+        mUiHandler = handler;
         mCurrentSearch = savedState != null ? savedState.getString(Shared.EXTRA_QUERY) : null;
     }
 
@@ -169,6 +199,7 @@
      */
     public boolean cancelSearch() {
         if (isExpanded() || isSearching()) {
+            cancelQueuedSearch();
             // If the query string is not empty search view won't get iconified
             mSearchView.setQuery("", false);
 
@@ -183,13 +214,24 @@
         return false;
     }
 
+    private void cancelQueuedSearch() {
+        synchronized (mSearchLock) {
+            if (mQueuedSearchTask != null) {
+                mQueuedSearchTask.cancel();
+            }
+            mQueuedSearchTask = null;
+            mUiHandler.removeCallbacks(mQueuedSearchRunnable);
+            mQueuedSearchRunnable = null;
+        }
+    }
+
     /**
      * Sets search view into the searching state. Used to restore state after device orientation
      * change.
      */
     private void restoreSearch() {
         if (isSearching()) {
-            if(mFullBar) {
+            if (mFullBar) {
                 mMenuItem.expandActionView();
             } else {
                 mSearchView.setIconified(false);
@@ -202,7 +244,7 @@
 
     private void onSearchExpanded() {
         mSearchExpanded = true;
-        if(mFullBar) {
+        if (mFullBar) {
             mMenu.setGroupVisible(R.id.group_hide_when_searching, false);
         }
 
@@ -228,7 +270,7 @@
             mListener.onSearchChanged(mCurrentSearch);
         }
 
-        if(mFullBar) {
+        if (mFullBar) {
             mMenuItem.collapseActionView();
         }
         mListener.onSearchFinished();
@@ -261,9 +303,13 @@
         if (mCommandProcessor.accept(query)) {
             mSearchView.setQuery("", false);
         } else {
-            mCurrentSearch = query;
+            cancelQueuedSearch();
+            // Don't kick off a search if we've already finished it.
+            if (mCurrentSearch != query) {
+                mCurrentSearch = query;
+                mListener.onSearchChanged(mCurrentSearch);
+            }
             mSearchView.clearFocus();
-            mListener.onSearchChanged(mCurrentSearch);
         }
 
         return true;
@@ -283,9 +329,35 @@
         }
     }
 
+    @VisibleForTesting
+    protected TimerTask createSearchTask(String newText) {
+        return new TimerTask() {
+            @Override
+            public void run() {
+                // Do the actual work on the main looper.
+                synchronized (mSearchLock) {
+                    mQueuedSearchRunnable = () -> {
+                        mCurrentSearch = newText;
+                        if (mCurrentSearch != null && mCurrentSearch.isEmpty()) {
+                            mCurrentSearch = null;
+                        }
+                        mListener.onSearchChanged(mCurrentSearch);
+                    };
+                    mUiHandler.post(mQueuedSearchRunnable);
+                }
+            }
+        };
+    }
+
     @Override
     public boolean onQueryTextChange(String newText) {
-        return false;
+        cancelQueuedSearch();
+        synchronized (mSearchLock) {
+            mQueuedSearchTask = createSearchTask(newText);
+
+            mTimer.schedule(mQueuedSearchTask, SEARCH_DELAY_MS);
+        }
+        return true;
     }
 
     @Override
diff --git a/src/com/android/documentsui/roots/LoadRootTask.java b/src/com/android/documentsui/roots/LoadRootTask.java
index fbcbf91..308bb45 100644
--- a/src/com/android/documentsui/roots/LoadRootTask.java
+++ b/src/com/android/documentsui/roots/LoadRootTask.java
@@ -16,7 +16,7 @@
 
 package com.android.documentsui.roots;
 
-import static com.android.documentsui.base.Shared.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
 
 import android.app.Activity;
 import android.net.Uri;
diff --git a/src/com/android/documentsui/roots/ProvidersAccess.java b/src/com/android/documentsui/roots/ProvidersAccess.java
index a1aa33c..93db10a 100644
--- a/src/com/android/documentsui/roots/ProvidersAccess.java
+++ b/src/com/android/documentsui/roots/ProvidersAccess.java
@@ -16,8 +16,8 @@
 
 package com.android.documentsui.roots;
 
-import static com.android.documentsui.base.Shared.DEBUG;
-import static com.android.documentsui.base.Shared.VERBOSE;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.VERBOSE;
 
 import android.util.Log;
 
diff --git a/src/com/android/documentsui/roots/ProvidersCache.java b/src/com/android/documentsui/roots/ProvidersCache.java
index 9b1044d..1527918 100644
--- a/src/com/android/documentsui/roots/ProvidersCache.java
+++ b/src/com/android/documentsui/roots/ProvidersCache.java
@@ -16,8 +16,8 @@
 
 package com.android.documentsui.roots;
 
-import static com.android.documentsui.base.Shared.DEBUG;
-import static com.android.documentsui.base.Shared.VERBOSE;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.VERBOSE;
 
 import android.content.BroadcastReceiver.PendingResult;
 import android.content.ContentProviderClient;
@@ -241,8 +241,13 @@
         if (VERBOSE) Log.v(TAG, "Loading roots for " + authority);
 
         final ArrayList<RootInfo> roots = new ArrayList<>();
-        ProviderInfo provider = mContext.getPackageManager().resolveContentProvider(
+        final PackageManager pm = mContext.getPackageManager();
+        ProviderInfo provider = pm.resolveContentProvider(
                 authority, PackageManager.GET_META_DATA);
+        if (provider == null) {
+            Log.w(TAG, "Failed to get provider info for " + authority);
+            return roots;
+        }
         if (!provider.exported) {
             Log.w(TAG, "Provider is not exported. Failed to load roots for " + authority);
             return roots;
@@ -261,7 +266,6 @@
 
         synchronized (mObservedAuthoritiesDetails) {
             if (!mObservedAuthoritiesDetails.containsKey(authority)) {
-                PackageManager pm = mContext.getPackageManager();
                 CharSequence appName = pm.getApplicationLabel(provider.applicationInfo);
                 String packageName = provider.applicationInfo.packageName;
 
@@ -396,6 +400,7 @@
         }
     }
 
+    @Override
     public RootInfo getDefaultRootBlocking(State state) {
         for (RootInfo root : ProvidersAccess.getMatchingRoots(getRootsBlocking(), state)) {
             if (root.isDownloads()) {
@@ -459,7 +464,10 @@
             final Intent intent = new Intent(DocumentsContract.PROVIDER_INTERFACE);
             final List<ResolveInfo> providers = pm.queryIntentContentProviders(intent, 0);
             for (ResolveInfo info : providers) {
-                handleDocumentsProvider(info.providerInfo);
+                ProviderInfo providerInfo = info.providerInfo;
+                if (providerInfo.authority != null) {
+                    handleDocumentsProvider(providerInfo);
+                }
             }
 
             final long delta = SystemClock.elapsedRealtime() - start;
diff --git a/src/com/android/documentsui/roots/RootCursorWrapper.java b/src/com/android/documentsui/roots/RootCursorWrapper.java
index b7f9c20..d220f68 100644
--- a/src/com/android/documentsui/roots/RootCursorWrapper.java
+++ b/src/com/android/documentsui/roots/RootCursorWrapper.java
@@ -21,7 +21,7 @@
 import android.os.Bundle;
 import android.util.Log;
 
-import static com.android.documentsui.base.Shared.VERBOSE;
+import static com.android.documentsui.base.SharedMinimal.VERBOSE;
 
 /**
  * Cursor wrapper that adds columns to identify which root a document came from.
diff --git a/src/com/android/documentsui/selection/BandController.java b/src/com/android/documentsui/selection/BandController.java
deleted file mode 100644
index 399bb15..0000000
--- a/src/com/android/documentsui/selection/BandController.java
+++ /dev/null
@@ -1,1160 +0,0 @@
-/*
- * 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.documentsui.selection;
-
-import static com.android.documentsui.base.Shared.DEBUG;
-import static com.android.documentsui.ui.ViewAutoScroller.NOT_SET;
-
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.Nullable;
-import android.support.annotation.VisibleForTesting;
-import android.support.v7.widget.GridLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.RecyclerView.OnScrollListener;
-import android.util.Log;
-import android.util.SparseArray;
-import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
-import android.view.View;
-
-import com.android.documentsui.DirectoryReloadLock;
-import com.android.documentsui.R;
-import com.android.documentsui.base.Events.InputEvent;
-import com.android.documentsui.dirlist.DocumentsAdapter;
-import com.android.documentsui.dirlist.FocusHandler;
-import com.android.documentsui.ui.ViewAutoScroller;
-import com.android.documentsui.ui.ViewAutoScroller.ScrollActionDelegate;
-import com.android.documentsui.ui.ViewAutoScroller.ScrollDistanceDelegate;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.IntPredicate;
-
-/**
- * Provides mouse driven band-select support when used in conjunction with {@link RecyclerView}
- * and {@link SelectionManager}. This class is responsible for rendering the band select
- * overlay and selecting overlaid items via SelectionManager.
- */
-public class BandController extends OnScrollListener {
-
-    private static final String TAG = "BandController";
-
-    private final Runnable mModelBuilder;
-    private final SelectionEnvironment mEnvironment;
-    private final DocumentsAdapter mAdapter;
-    private final SelectionManager mSelectionManager;
-    private final DirectoryReloadLock mLock;
-    private final Runnable mViewScroller;
-    private final GridModel.OnSelectionChangedListener mGridListener;
-    private final List<Runnable> mStartBandSelectListeners = new ArrayList<>();
-
-    @Nullable private Rect mBounds;
-    @Nullable private Point mCurrentPosition;
-    @Nullable private Point mOrigin;
-    @Nullable private BandController.GridModel mModel;
-
-    private Selection mSelection;
-
-    public BandController(
-            final RecyclerView view,
-            DocumentsAdapter adapter,
-            SelectionManager selectionManager,
-            DirectoryReloadLock lock,
-            IntPredicate gridItemTester) {
-        this(new RuntimeSelectionEnvironment(view), adapter, selectionManager,
-                lock, gridItemTester);
-    }
-
-    @VisibleForTesting
-    BandController(
-            SelectionEnvironment env,
-            DocumentsAdapter adapter,
-            SelectionManager selectionManager,
-            DirectoryReloadLock lock,
-            IntPredicate gridItemTester) {
-
-        mLock = lock;
-        selectionManager.bindContoller(this);
-
-        mEnvironment = env;
-        mAdapter = adapter;
-        mSelectionManager = selectionManager;
-
-        mEnvironment.addOnScrollListener(this);
-        mViewScroller = new ViewAutoScroller(
-                new ScrollDistanceDelegate() {
-                    @Override
-                    public Point getCurrentPosition() {
-                        return mCurrentPosition;
-                    }
-
-                    @Override
-                    public int getViewHeight() {
-                        return mEnvironment.getHeight();
-                    }
-
-                    @Override
-                    public boolean isActive() {
-                        return BandController.this.isActive();
-                    }
-                },
-                env);
-
-        mAdapter.registerAdapterDataObserver(
-                new RecyclerView.AdapterDataObserver() {
-                    @Override
-                    public void onChanged() {
-                        if (isActive()) {
-                            endBandSelect();
-                        }
-                    }
-
-                    @Override
-                    public void onItemRangeChanged(
-                            int startPosition, int itemCount, Object payload) {
-                        // No change in position. Ignoring.
-                    }
-
-                    @Override
-                    public void onItemRangeInserted(int startPosition, int itemCount) {
-                        if (isActive()) {
-                            endBandSelect();
-                        }
-                    }
-
-                    @Override
-                    public void onItemRangeRemoved(int startPosition, int itemCount) {
-                        assert(startPosition >= 0);
-                        assert(itemCount > 0);
-
-                        // TODO: Should update grid model.
-                    }
-
-                    @Override
-                    public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
-                        throw new UnsupportedOperationException();
-                    }
-                });
-
-        mGridListener = new GridModel.OnSelectionChangedListener() {
-
-            @Override
-            public void onSelectionChanged(Set<String> updatedSelection) {
-                BandController.this.onSelectionChanged(updatedSelection);
-            }
-
-            @Override
-            public boolean onBeforeItemStateChange(String id, boolean nextState) {
-                return BandController.this.onBeforeItemStateChange(id, nextState);
-            }
-        };
-
-        mModelBuilder = new Runnable() {
-            @Override
-            public void run() {
-                mModel = new GridModel(mEnvironment, gridItemTester, mAdapter);
-                mModel.addOnSelectionChangedListener(mGridListener);
-            }
-        };
-    }
-
-    @VisibleForTesting
-    boolean isActive() {
-        return mModel != null;
-    }
-
-    void bindSelection(Selection selection) {
-        mSelection = selection;
-    }
-
-    public boolean onInterceptTouchEvent(InputEvent e) {
-        if (shouldStart(e)) {
-            if (!e.isCtrlKeyDown()) {
-                mSelectionManager.clearSelection();
-            }
-            startBandSelect(e.getOrigin());
-        } else if (shouldStop(e)) {
-            endBandSelect();
-        }
-
-        return isActive();
-    }
-
-    public void addBandSelectStartedListener(Runnable listener) {
-        mStartBandSelectListeners.add(listener);
-    }
-
-    public void removeBandSelectStartedListener(Runnable listener) {
-        mStartBandSelectListeners.remove(listener);
-    }
-
-    /**
-     * Handle a change in layout by cleaning up and getting rid of the old model and creating
-     * a new model which will track the new layout.
-     */
-    public void handleLayoutChanged() {
-        if (mModel != null) {
-            mModel.removeOnSelectionChangedListener(mGridListener);
-            mModel.stopListening();
-
-            // build a new model, all fresh and happy.
-            mModelBuilder.run();
-        }
-    }
-
-    public boolean shouldStart(InputEvent e) {
-        // Don't start, or extend bands on non-left clicks.
-        if (!e.isPrimaryButtonPressed()) {
-            return false;
-        }
-
-        if (!e.isMouseEvent() && isActive()) {
-            // Weird things happen if we keep up band select
-            // when touch events happen.
-            endBandSelect();
-            return false;
-        }
-
-        // b/30146357 && b/23793622. onInterceptTouchEvent does not dispatch events to onTouchEvent
-        // unless the event is != ACTION_DOWN. Thus, we need to actually start band selection when
-        // mouse moves, or else starting band selection on mouse down can cause problems as events
-        // don't get routed correctly to onTouchEvent.
-        return !isActive()
-                && e.isActionMove() // the initial button move via mouse-touch (ie. down press)
-                && mAdapter.hasModelIds() // we want to check against actual modelIds count to
-                                          // avoid dummy view count from the AdapterWrapper
-                && !e.isOverDragHotspot();
-
-    }
-
-    public boolean shouldStop(InputEvent input) {
-        return isActive()
-                && input.isMouseEvent()
-                && (input.isActionUp() || input.isMultiPointerActionUp() || input.isActionCancel());
-    }
-
-    /**
-     * Processes a MotionEvent by starting, ending, or resizing the band select overlay.
-     * @param input
-     */
-    public void onTouchEvent(InputEvent input) {
-        assert(input.isMouseEvent());
-
-        if (shouldStop(input)) {
-            endBandSelect();
-            return;
-        }
-
-        // We shouldn't get any events in this method when band select is not active,
-        // but it turns some guests show up late to the party.
-        // Probably happening when a re-layout is happening to the ReyclerView (ie. Pull-To-Refresh)
-        if (!isActive()) {
-            return;
-        }
-
-        assert(input.isActionMove());
-        mCurrentPosition = input.getOrigin();
-        mModel.resizeSelection(input.getOrigin());
-        scrollViewIfNecessary();
-        resizeBandSelectRectangle();
-    }
-
-    /**
-     * Starts band select by adding the drawable to the RecyclerView's overlay.
-     */
-    private void startBandSelect(Point origin) {
-        if (DEBUG) Log.d(TAG, "Starting band select @ " + origin);
-
-        mLock.block();
-        notifyBandSelectStartedListeners();
-        mOrigin = origin;
-        mModelBuilder.run();  // Creates a new selection model.
-        mModel.startSelection(mOrigin);
-    }
-
-    private void notifyBandSelectStartedListeners() {
-        for (Runnable listener : mStartBandSelectListeners) {
-            listener.run();
-        }
-    }
-
-    /**
-     * Scrolls the view if necessary.
-     */
-    private void scrollViewIfNecessary() {
-        mEnvironment.removeCallback(mViewScroller);
-        mViewScroller.run();
-        mEnvironment.invalidateView();
-    }
-
-    /**
-     * Resizes the band select rectangle by using the origin and the current pointer position as
-     * two opposite corners of the selection.
-     */
-    private void resizeBandSelectRectangle() {
-        mBounds = new Rect(Math.min(mOrigin.x, mCurrentPosition.x),
-                Math.min(mOrigin.y, mCurrentPosition.y),
-                Math.max(mOrigin.x, mCurrentPosition.x),
-                Math.max(mOrigin.y, mCurrentPosition.y));
-        mEnvironment.showBand(mBounds);
-    }
-
-    /**
-     * Ends band select by removing the overlay.
-     */
-    private void endBandSelect() {
-        if (DEBUG) Log.d(TAG, "Ending band select.");
-
-        mEnvironment.hideBand();
-        mSelection.applyProvisionalSelection();
-        mModel.endSelection();
-        int firstSelected = mModel.getPositionNearestOrigin();
-        if (firstSelected != NOT_SET) {
-            if (mSelection.contains(mAdapter.getModelId(firstSelected))) {
-                // TODO: firstSelected should really be lastSelected, we want to anchor the item
-                // where the mouse-up occurred.
-                mSelectionManager.setSelectionRangeBegin(firstSelected);
-            } else {
-                // TODO: Check if this is really happening.
-                Log.w(TAG, "First selected by band is NOT in selection!");
-            }
-        }
-
-        mModel = null;
-        mOrigin = null;
-        mLock.unblock();
-    }
-
-    private void onSelectionChanged(Set<String> updatedSelection) {
-        Map<String, Boolean> delta = mSelection.setProvisionalSelection(updatedSelection);
-        for (Map.Entry<String, Boolean> entry: delta.entrySet()) {
-            mSelectionManager.notifyItemStateChanged(entry.getKey(), entry.getValue());
-        }
-        mSelectionManager.notifySelectionChanged();
-    }
-
-    private boolean onBeforeItemStateChange(String id, boolean nextState) {
-        return mSelectionManager.canSetState(id, nextState);
-    }
-
-    @Override
-    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
-        if (!isActive()) {
-            return;
-        }
-
-        // Adjust the y-coordinate of the origin the opposite number of pixels so that the
-        // origin remains in the same place relative to the view's items.
-        mOrigin.y -= dy;
-        resizeBandSelectRectangle();
-    }
-
-    /**
-     * Provides a band selection item model for views within a RecyclerView. This class queries the
-     * RecyclerView to determine where its items are placed; then, once band selection is underway,
-     * it alerts listeners of which items are covered by the selections.
-     */
-    @VisibleForTesting
-    static final class GridModel extends RecyclerView.OnScrollListener {
-
-        public static final int NOT_SET = -1;
-
-        // Enum values used to determine the corner at which the origin is located within the
-        private static final int UPPER = 0x00;
-        private static final int LOWER = 0x01;
-        private static final int LEFT = 0x00;
-        private static final int RIGHT = 0x02;
-        private static final int UPPER_LEFT = UPPER | LEFT;
-        private static final int UPPER_RIGHT = UPPER | RIGHT;
-        private static final int LOWER_LEFT = LOWER | LEFT;
-        private static final int LOWER_RIGHT = LOWER | RIGHT;
-
-        private final SelectionEnvironment mHelper;
-        private final IntPredicate mGridItemTester;
-        private final DocumentsAdapter mAdapter;
-
-        private final List<GridModel.OnSelectionChangedListener> mOnSelectionChangedListeners =
-                new ArrayList<>();
-
-        // Map from the x-value of the left side of a SparseBooleanArray of adapter positions, keyed
-        // by their y-offset. For example, if the first column of the view starts at an x-value of 5,
-        // mColumns.get(5) would return an array of positions in that column. Within that array, the
-        // value for key y is the adapter position for the item whose y-offset is y.
-        private final SparseArray<SparseIntArray> mColumns = new SparseArray<>();
-
-        // List of limits along the x-axis (columns).
-        // This list is sorted from furthest left to furthest right.
-        private final List<GridModel.Limits> mColumnBounds = new ArrayList<>();
-
-        // List of limits along the y-axis (rows). Note that this list only contains items which
-        // have been in the viewport.
-        private final List<GridModel.Limits> mRowBounds = new ArrayList<>();
-
-        // The adapter positions which have been recorded so far.
-        private final SparseBooleanArray mKnownPositions = new SparseBooleanArray();
-
-        // Array passed to registered OnSelectionChangedListeners. One array is created and reused
-        // throughout the lifetime of the object.
-        private final Set<String> mSelection = new HashSet<>();
-
-        // The current pointer (in absolute positioning from the top of the view).
-        private Point mPointer = null;
-
-        // The bounds of the band selection.
-        private RelativePoint mRelativeOrigin;
-        private RelativePoint mRelativePointer;
-
-        private boolean mIsActive;
-
-        // Tracks where the band select originated from. This is used to determine where selections
-        // should expand from when Shift+click is used.
-        private int mPositionNearestOrigin = NOT_SET;
-
-        GridModel(SelectionEnvironment helper, IntPredicate gridItemTester, DocumentsAdapter adapter) {
-            mHelper = helper;
-            mAdapter = adapter;
-            mGridItemTester = gridItemTester;
-            mHelper.addOnScrollListener(this);
-        }
-
-        /**
-         * Stops listening to the view's scrolls. Call this function before discarding a
-         * BandSelecModel object to prevent memory leaks.
-         */
-        void stopListening() {
-            mHelper.removeOnScrollListener(this);
-        }
-
-        /**
-         * Start a band select operation at the given point.
-         * @param relativeOrigin The origin of the band select operation, relative to the viewport.
-         *     For example, if the view is scrolled to the bottom, the top-left of the viewport
-         *     would have a relative origin of (0, 0), even though its absolute point has a higher
-         *     y-value.
-         */
-        void startSelection(Point relativeOrigin) {
-            recordVisibleChildren();
-            if (isEmpty()) {
-                // The selection band logic works only if there is at least one visible child.
-                return;
-            }
-
-            mIsActive = true;
-            mPointer = mHelper.createAbsolutePoint(relativeOrigin);
-            mRelativeOrigin = new RelativePoint(mPointer);
-            mRelativePointer = new RelativePoint(mPointer);
-            computeCurrentSelection();
-            notifyListeners();
-        }
-
-        /**
-         * Resizes the selection by adjusting the pointer (i.e., the corner of the selection
-         * opposite the origin.
-         * @param relativePointer The pointer (opposite of the origin) of the band select operation,
-         *     relative to the viewport. For example, if the view is scrolled to the bottom, the
-         *     top-left of the viewport would have a relative origin of (0, 0), even though its
-         *     absolute point has a higher y-value.
-         */
-        @VisibleForTesting
-        void resizeSelection(Point relativePointer) {
-            mPointer = mHelper.createAbsolutePoint(relativePointer);
-            updateModel();
-        }
-
-        /**
-         * Ends the band selection.
-         */
-        void endSelection() {
-            mIsActive = false;
-        }
-
-        /**
-         * @return The adapter position for the item nearest the origin corresponding to the latest
-         *         band select operation, or NOT_SET if the selection did not cover any items.
-         */
-        int getPositionNearestOrigin() {
-            return mPositionNearestOrigin;
-        }
-
-        @Override
-        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
-            if (!mIsActive) {
-                return;
-            }
-
-            mPointer.x += dx;
-            mPointer.y += dy;
-            recordVisibleChildren();
-            updateModel();
-        }
-
-        /**
-         * Queries the view for all children and records their location metadata.
-         */
-        private void recordVisibleChildren() {
-            for (int i = 0; i < mHelper.getVisibleChildCount(); i++) {
-                int adapterPosition = mHelper.getAdapterPositionAt(i);
-                // Sometimes the view is not attached, as we notify the multi selection manager
-                // synchronously, while views are attached asynchronously. As a result items which
-                // are in the adapter may not actually have a corresponding view (yet).
-                if (mHelper.hasView(adapterPosition) &&
-                        mGridItemTester.test(adapterPosition) &&
-                        !mKnownPositions.get(adapterPosition)) {
-                    mKnownPositions.put(adapterPosition, true);
-                    recordItemData(mHelper.getAbsoluteRectForChildViewAt(i), adapterPosition);
-                }
-            }
-        }
-
-        /**
-         * Checks if there are any recorded children.
-         */
-        private boolean isEmpty() {
-            return mColumnBounds.size() == 0 || mRowBounds.size() == 0;
-        }
-
-        /**
-         * Updates the limits lists and column map with the given item metadata.
-         * @param absoluteChildRect The absolute rectangle for the child view being processed.
-         * @param adapterPosition The position of the child view being processed.
-         */
-        private void recordItemData(Rect absoluteChildRect, int adapterPosition) {
-            if (mColumnBounds.size() != mHelper.getColumnCount()) {
-                // If not all x-limits have been recorded, record this one.
-                recordLimits(
-                        mColumnBounds, new Limits(absoluteChildRect.left, absoluteChildRect.right));
-            }
-
-            recordLimits(mRowBounds, new Limits(absoluteChildRect.top, absoluteChildRect.bottom));
-
-            SparseIntArray columnList = mColumns.get(absoluteChildRect.left);
-            if (columnList == null) {
-                columnList = new SparseIntArray();
-                mColumns.put(absoluteChildRect.left, columnList);
-            }
-            columnList.put(absoluteChildRect.top, adapterPosition);
-        }
-
-        /**
-         * Ensures limits exists within the sorted list limitsList, and adds it to the list if it
-         * does not exist.
-         */
-        private void recordLimits(List<GridModel.Limits> limitsList, GridModel.Limits limits) {
-            int index = Collections.binarySearch(limitsList, limits);
-            if (index < 0) {
-                limitsList.add(~index, limits);
-            }
-        }
-
-        /**
-         * Handles a moved pointer; this function determines whether the pointer movement resulted
-         * in a selection change and, if it has, notifies listeners of this change.
-         */
-        private void updateModel() {
-            RelativePoint old = mRelativePointer;
-            mRelativePointer = new RelativePoint(mPointer);
-            if (old != null && mRelativePointer.equals(old)) {
-                return;
-            }
-
-            computeCurrentSelection();
-            notifyListeners();
-        }
-
-        /**
-         * Computes the currently-selected items.
-         */
-        private void computeCurrentSelection() {
-            if (areItemsCoveredByBand(mRelativePointer, mRelativeOrigin)) {
-                updateSelection(computeBounds());
-            } else {
-                mSelection.clear();
-                mPositionNearestOrigin = NOT_SET;
-            }
-        }
-
-        /**
-         * Notifies all listeners of a selection change. Note that this function simply passes
-         * mSelection, so computeCurrentSelection() should be called before this
-         * function.
-         */
-        private void notifyListeners() {
-            for (GridModel.OnSelectionChangedListener listener : mOnSelectionChangedListeners) {
-                listener.onSelectionChanged(mSelection);
-            }
-        }
-
-        /**
-         * @param rect Rectangle including all covered items.
-         */
-        private void updateSelection(Rect rect) {
-            int columnStart =
-                    Collections.binarySearch(mColumnBounds, new Limits(rect.left, rect.left));
-            assert(columnStart >= 0);
-            int columnEnd = columnStart;
-
-            for (int i = columnStart; i < mColumnBounds.size()
-                    && mColumnBounds.get(i).lowerLimit <= rect.right; i++) {
-                columnEnd = i;
-            }
-
-            int rowStart = Collections.binarySearch(mRowBounds, new Limits(rect.top, rect.top));
-            if (rowStart < 0) {
-                mPositionNearestOrigin = NOT_SET;
-                return;
-            }
-
-            int rowEnd = rowStart;
-            for (int i = rowStart; i < mRowBounds.size()
-                    && mRowBounds.get(i).lowerLimit <= rect.bottom; i++) {
-                rowEnd = i;
-            }
-
-            updateSelection(columnStart, columnEnd, rowStart, rowEnd);
-        }
-
-        /**
-         * Computes the selection given the previously-computed start- and end-indices for each
-         * row and column.
-         */
-        private void updateSelection(
-                int columnStartIndex, int columnEndIndex, int rowStartIndex, int rowEndIndex) {
-            if (DEBUG) Log.d(TAG, String.format("updateSelection: %d, %d, %d, %d",
-                    columnStartIndex, columnEndIndex, rowStartIndex, rowEndIndex));
-
-            mSelection.clear();
-            for (int column = columnStartIndex; column <= columnEndIndex; column++) {
-                SparseIntArray items = mColumns.get(mColumnBounds.get(column).lowerLimit);
-                for (int row = rowStartIndex; row <= rowEndIndex; row++) {
-                    // The default return value for SparseIntArray.get is 0, which is a valid
-                    // position. Use a sentry value to prevent erroneously selecting item 0.
-                    final int rowKey = mRowBounds.get(row).lowerLimit;
-                    int position = items.get(rowKey, NOT_SET);
-                    if (position != NOT_SET) {
-                        String id = mAdapter.getModelId(position);
-                        if (id != null) {
-                            // The adapter inserts items for UI layout purposes that aren't associated
-                            // with files.  Those will have a null model ID.  Don't select them.
-                            if (canSelect(id)) {
-                                mSelection.add(id);
-                            }
-                        }
-                        if (isPossiblePositionNearestOrigin(column, columnStartIndex, columnEndIndex,
-                                row, rowStartIndex, rowEndIndex)) {
-                            // If this is the position nearest the origin, record it now so that it
-                            // can be returned by endSelection() later.
-                            mPositionNearestOrigin = position;
-                        }
-                    }
-                }
-            }
-        }
-
-        /**
-         * @return True if the item is selectable.
-         */
-        private boolean canSelect(String id) {
-            // TODO: Simplify the logic, so the check whether we can select is done in one place.
-            // Consider injecting ActivityConfig, or move the checks from MultiSelectManager to
-            // Selection.
-            for (GridModel.OnSelectionChangedListener listener : mOnSelectionChangedListeners) {
-                if (!listener.onBeforeItemStateChange(id, true)) {
-                    return false;
-                }
-            }
-            return true;
-        }
-
-        /**
-         * @return Returns true if the position is the nearest to the origin, or, in the case of the
-         *     lower-right corner, whether it is possible that the position is the nearest to the
-         *     origin. See comment below for reasoning for this special case.
-         */
-        private boolean isPossiblePositionNearestOrigin(int columnIndex, int columnStartIndex,
-                int columnEndIndex, int rowIndex, int rowStartIndex, int rowEndIndex) {
-            int corner = computeCornerNearestOrigin();
-            switch (corner) {
-                case UPPER_LEFT:
-                    return columnIndex == columnStartIndex && rowIndex == rowStartIndex;
-                case UPPER_RIGHT:
-                    return columnIndex == columnEndIndex && rowIndex == rowStartIndex;
-                case LOWER_LEFT:
-                    return columnIndex == columnStartIndex && rowIndex == rowEndIndex;
-                case LOWER_RIGHT:
-                    // Note that in some cases, the last row will not have as many items as there
-                    // are columns (e.g., if there are 4 items and 3 columns, the second row will
-                    // only have one item in the first column). This function is invoked for each
-                    // position from left to right, so return true for any position in the bottom
-                    // row and only the right-most position in the bottom row will be recorded.
-                    return rowIndex == rowEndIndex;
-                default:
-                    throw new RuntimeException("Invalid corner type.");
-            }
-        }
-
-        /**
-         * Listener for changes in which items have been band selected.
-         */
-        static interface OnSelectionChangedListener {
-            public void onSelectionChanged(Set<String> updatedSelection);
-            public boolean onBeforeItemStateChange(String id, boolean nextState);
-        }
-
-        void addOnSelectionChangedListener(GridModel.OnSelectionChangedListener listener) {
-            mOnSelectionChangedListeners.add(listener);
-        }
-
-        void removeOnSelectionChangedListener(GridModel.OnSelectionChangedListener listener) {
-            mOnSelectionChangedListeners.remove(listener);
-        }
-
-        /**
-         * Limits of a view item. For example, if an item's left side is at x-value 5 and its right side
-         * is at x-value 10, the limits would be from 5 to 10. Used to record the left- and right sides
-         * of item columns and the top- and bottom sides of item rows so that it can be determined
-         * whether the pointer is located within the bounds of an item.
-         */
-        private static class Limits implements Comparable<GridModel.Limits> {
-            int lowerLimit;
-            int upperLimit;
-
-            Limits(int lowerLimit, int upperLimit) {
-                this.lowerLimit = lowerLimit;
-                this.upperLimit = upperLimit;
-            }
-
-            @Override
-            public int compareTo(GridModel.Limits other) {
-                return lowerLimit - other.lowerLimit;
-            }
-
-            @Override
-            public boolean equals(Object other) {
-                if (!(other instanceof GridModel.Limits)) {
-                    return false;
-                }
-
-                return ((GridModel.Limits) other).lowerLimit == lowerLimit &&
-                        ((GridModel.Limits) other).upperLimit == upperLimit;
-            }
-
-            @Override
-            public String toString() {
-                return "(" + lowerLimit + ", " + upperLimit + ")";
-            }
-        }
-
-        /**
-         * The location of a coordinate relative to items. This class represents a general area of the
-         * view as it relates to band selection rather than an explicit point. For example, two
-         * different points within an item are considered to have the same "location" because band
-         * selection originating within the item would select the same items no matter which point
-         * was used. Same goes for points between items as well as those at the very beginning or end
-         * of the view.
-         *
-         * Tracking a coordinate (e.g., an x-value) as a CoordinateLocation instead of as an int has the
-         * advantage of tying the value to the Limits of items along that axis. This allows easy
-         * selection of items within those Limits as opposed to a search through every item to see if a
-         * given coordinate value falls within those Limits.
-         */
-        private static class RelativeCoordinate
-                implements Comparable<GridModel.RelativeCoordinate> {
-            /**
-             * Location describing points after the last known item.
-             */
-            static final int AFTER_LAST_ITEM = 0;
-
-            /**
-             * Location describing points before the first known item.
-             */
-            static final int BEFORE_FIRST_ITEM = 1;
-
-            /**
-             * Location describing points between two items.
-             */
-            static final int BETWEEN_TWO_ITEMS = 2;
-
-            /**
-             * Location describing points within the limits of one item.
-             */
-            static final int WITHIN_LIMITS = 3;
-
-            /**
-             * The type of this coordinate, which is one of AFTER_LAST_ITEM, BEFORE_FIRST_ITEM,
-             * BETWEEN_TWO_ITEMS, or WITHIN_LIMITS.
-             */
-            final int type;
-
-            /**
-             * The limits before the coordinate; only populated when type == WITHIN_LIMITS or type ==
-             * BETWEEN_TWO_ITEMS.
-             */
-            GridModel.Limits limitsBeforeCoordinate;
-
-            /**
-             * The limits after the coordinate; only populated when type == BETWEEN_TWO_ITEMS.
-             */
-            GridModel.Limits limitsAfterCoordinate;
-
-            // Limits of the first known item; only populated when type == BEFORE_FIRST_ITEM.
-            GridModel.Limits mFirstKnownItem;
-            // Limits of the last known item; only populated when type == AFTER_LAST_ITEM.
-            GridModel.Limits mLastKnownItem;
-
-            /**
-             * @param limitsList The sorted limits list for the coordinate type. If this
-             *     CoordinateLocation is an x-value, mXLimitsList should be passed; otherwise,
-             *     mYLimitsList should be pased.
-             * @param value The coordinate value.
-             */
-            RelativeCoordinate(List<GridModel.Limits> limitsList, int value) {
-                int index = Collections.binarySearch(limitsList, new Limits(value, value));
-
-                if (index >= 0) {
-                    this.type = WITHIN_LIMITS;
-                    this.limitsBeforeCoordinate = limitsList.get(index);
-                } else if (~index == 0) {
-                    this.type = BEFORE_FIRST_ITEM;
-                    this.mFirstKnownItem = limitsList.get(0);
-                } else if (~index == limitsList.size()) {
-                    GridModel.Limits lastLimits = limitsList.get(limitsList.size() - 1);
-                    if (lastLimits.lowerLimit <= value && value <= lastLimits.upperLimit) {
-                        this.type = WITHIN_LIMITS;
-                        this.limitsBeforeCoordinate = lastLimits;
-                    } else {
-                        this.type = AFTER_LAST_ITEM;
-                        this.mLastKnownItem = lastLimits;
-                    }
-                } else {
-                    GridModel.Limits limitsBeforeIndex = limitsList.get(~index - 1);
-                    if (limitsBeforeIndex.lowerLimit <= value && value <= limitsBeforeIndex.upperLimit) {
-                        this.type = WITHIN_LIMITS;
-                        this.limitsBeforeCoordinate = limitsList.get(~index - 1);
-                    } else {
-                        this.type = BETWEEN_TWO_ITEMS;
-                        this.limitsBeforeCoordinate = limitsList.get(~index - 1);
-                        this.limitsAfterCoordinate = limitsList.get(~index);
-                    }
-                }
-            }
-
-            int toComparisonValue() {
-                if (type == BEFORE_FIRST_ITEM) {
-                    return mFirstKnownItem.lowerLimit - 1;
-                } else if (type == AFTER_LAST_ITEM) {
-                    return mLastKnownItem.upperLimit + 1;
-                } else if (type == BETWEEN_TWO_ITEMS) {
-                    return limitsBeforeCoordinate.upperLimit + 1;
-                } else {
-                    return limitsBeforeCoordinate.lowerLimit;
-                }
-            }
-
-            @Override
-            public boolean equals(Object other) {
-                if (!(other instanceof GridModel.RelativeCoordinate)) {
-                    return false;
-                }
-
-                GridModel.RelativeCoordinate otherCoordinate = (GridModel.RelativeCoordinate) other;
-                return toComparisonValue() == otherCoordinate.toComparisonValue();
-            }
-
-            @Override
-            public int compareTo(GridModel.RelativeCoordinate other) {
-                return toComparisonValue() - other.toComparisonValue();
-            }
-        }
-
-        /**
-         * The location of a point relative to the Limits of nearby items; consists of both an x- and
-         * y-RelativeCoordinateLocation.
-         */
-        private class RelativePoint {
-            final GridModel.RelativeCoordinate xLocation;
-            final GridModel.RelativeCoordinate yLocation;
-
-            RelativePoint(Point point) {
-                this.xLocation = new RelativeCoordinate(mColumnBounds, point.x);
-                this.yLocation = new RelativeCoordinate(mRowBounds, point.y);
-            }
-
-            @Override
-            public boolean equals(Object other) {
-                if (!(other instanceof RelativePoint)) {
-                    return false;
-                }
-
-                RelativePoint otherPoint = (RelativePoint) other;
-                return xLocation.equals(otherPoint.xLocation) && yLocation.equals(otherPoint.yLocation);
-            }
-        }
-
-        /**
-         * Generates a rectangle which contains the items selected by the pointer and origin.
-         * @return The rectangle, or null if no items were selected.
-         */
-        private Rect computeBounds() {
-            Rect rect = new Rect();
-            rect.left = getCoordinateValue(
-                    min(mRelativeOrigin.xLocation, mRelativePointer.xLocation),
-                    mColumnBounds,
-                    true);
-            rect.right = getCoordinateValue(
-                    max(mRelativeOrigin.xLocation, mRelativePointer.xLocation),
-                    mColumnBounds,
-                    false);
-            rect.top = getCoordinateValue(
-                    min(mRelativeOrigin.yLocation, mRelativePointer.yLocation),
-                    mRowBounds,
-                    true);
-            rect.bottom = getCoordinateValue(
-                    max(mRelativeOrigin.yLocation, mRelativePointer.yLocation),
-                    mRowBounds,
-                    false);
-            return rect;
-        }
-
-        /**
-         * Computes the corner of the selection nearest the origin.
-         * @return
-         */
-        private int computeCornerNearestOrigin() {
-            int cornerValue = 0;
-
-            if (mRelativeOrigin.yLocation ==
-                    min(mRelativeOrigin.yLocation, mRelativePointer.yLocation)) {
-                cornerValue |= UPPER;
-            } else {
-                cornerValue |= LOWER;
-            }
-
-            if (mRelativeOrigin.xLocation ==
-                    min(mRelativeOrigin.xLocation, mRelativePointer.xLocation)) {
-                cornerValue |= LEFT;
-            } else {
-                cornerValue |= RIGHT;
-            }
-
-            return cornerValue;
-        }
-
-        private GridModel.RelativeCoordinate min(GridModel.RelativeCoordinate first, GridModel.RelativeCoordinate second) {
-            return first.compareTo(second) < 0 ? first : second;
-        }
-
-        private GridModel.RelativeCoordinate max(GridModel.RelativeCoordinate first, GridModel.RelativeCoordinate second) {
-            return first.compareTo(second) > 0 ? first : second;
-        }
-
-        /**
-         * @return The absolute coordinate (i.e., the x- or y-value) of the given relative
-         *     coordinate.
-         */
-        private int getCoordinateValue(GridModel.RelativeCoordinate coordinate,
-                List<GridModel.Limits> limitsList, boolean isStartOfRange) {
-            switch (coordinate.type) {
-                case RelativeCoordinate.BEFORE_FIRST_ITEM:
-                    return limitsList.get(0).lowerLimit;
-                case RelativeCoordinate.AFTER_LAST_ITEM:
-                    return limitsList.get(limitsList.size() - 1).upperLimit;
-                case RelativeCoordinate.BETWEEN_TWO_ITEMS:
-                    if (isStartOfRange) {
-                        return coordinate.limitsAfterCoordinate.lowerLimit;
-                    } else {
-                        return coordinate.limitsBeforeCoordinate.upperLimit;
-                    }
-                case RelativeCoordinate.WITHIN_LIMITS:
-                    return coordinate.limitsBeforeCoordinate.lowerLimit;
-            }
-
-            throw new RuntimeException("Invalid coordinate value.");
-        }
-
-        private boolean areItemsCoveredByBand(
-                RelativePoint first, RelativePoint second) {
-            return doesCoordinateLocationCoverItems(first.xLocation, second.xLocation) &&
-                    doesCoordinateLocationCoverItems(first.yLocation, second.yLocation);
-        }
-
-        private boolean doesCoordinateLocationCoverItems(
-                GridModel.RelativeCoordinate pointerCoordinate,
-                GridModel.RelativeCoordinate originCoordinate) {
-            if (pointerCoordinate.type == RelativeCoordinate.BEFORE_FIRST_ITEM &&
-                    originCoordinate.type == RelativeCoordinate.BEFORE_FIRST_ITEM) {
-                return false;
-            }
-
-            if (pointerCoordinate.type == RelativeCoordinate.AFTER_LAST_ITEM &&
-                    originCoordinate.type == RelativeCoordinate.AFTER_LAST_ITEM) {
-                return false;
-            }
-
-            if (pointerCoordinate.type == RelativeCoordinate.BETWEEN_TWO_ITEMS &&
-                    originCoordinate.type == RelativeCoordinate.BETWEEN_TWO_ITEMS &&
-                    pointerCoordinate.limitsBeforeCoordinate.equals(
-                            originCoordinate.limitsBeforeCoordinate) &&
-                    pointerCoordinate.limitsAfterCoordinate.equals(
-                            originCoordinate.limitsAfterCoordinate)) {
-                return false;
-            }
-
-            return true;
-        }
-    }
-
-    /**
-     * Provides functionality for BandController. Exists primarily to tests that are
-     * fully isolated from RecyclerView.
-     */
-    interface SelectionEnvironment extends ScrollActionDelegate {
-        void showBand(Rect rect);
-        void hideBand();
-        void addOnScrollListener(RecyclerView.OnScrollListener listener);
-        void removeOnScrollListener(RecyclerView.OnScrollListener listener);
-        int getHeight();
-        void invalidateView();
-        Point createAbsolutePoint(Point relativePoint);
-        Rect getAbsoluteRectForChildViewAt(int index);
-        int getAdapterPositionAt(int index);
-        int getColumnCount();
-        int getChildCount();
-        int getVisibleChildCount();
-        /**
-         * Items may be in the adapter, but without an attached view.
-         */
-        boolean hasView(int adapterPosition);
-    }
-
-    /** Recycler view facade implementation backed by good ol' RecyclerView. */
-    private static final class RuntimeSelectionEnvironment implements SelectionEnvironment {
-
-        private final RecyclerView mView;
-        private final Drawable mBand;
-
-        private boolean mIsOverlayShown = false;
-
-        RuntimeSelectionEnvironment(RecyclerView view) {
-            mView = view;
-            mBand = mView.getContext().getTheme().getDrawable(R.drawable.band_select_overlay);
-        }
-
-        @Override
-        public int getAdapterPositionAt(int index) {
-            return mView.getChildAdapterPosition(mView.getChildAt(index));
-        }
-
-        @Override
-        public void addOnScrollListener(RecyclerView.OnScrollListener listener) {
-            mView.addOnScrollListener(listener);
-        }
-
-        @Override
-        public void removeOnScrollListener(RecyclerView.OnScrollListener listener) {
-            mView.removeOnScrollListener(listener);
-        }
-
-        @Override
-        public Point createAbsolutePoint(Point relativePoint) {
-            return new Point(relativePoint.x + mView.computeHorizontalScrollOffset(),
-                    relativePoint.y + mView.computeVerticalScrollOffset());
-        }
-
-        @Override
-        public Rect getAbsoluteRectForChildViewAt(int index) {
-            final View child = mView.getChildAt(index);
-            final Rect childRect = new Rect();
-            child.getHitRect(childRect);
-            childRect.left += mView.computeHorizontalScrollOffset();
-            childRect.right += mView.computeHorizontalScrollOffset();
-            childRect.top += mView.computeVerticalScrollOffset();
-            childRect.bottom += mView.computeVerticalScrollOffset();
-            return childRect;
-        }
-
-        @Override
-        public int getChildCount() {
-            return mView.getAdapter().getItemCount();
-        }
-
-        @Override
-        public int getVisibleChildCount() {
-            return mView.getChildCount();
-        }
-
-        @Override
-        public int getColumnCount() {
-            RecyclerView.LayoutManager layoutManager = mView.getLayoutManager();
-            if (layoutManager instanceof GridLayoutManager) {
-                return ((GridLayoutManager) layoutManager).getSpanCount();
-            }
-
-            // Otherwise, it is a list with 1 column.
-            return 1;
-        }
-
-        @Override
-        public int getHeight() {
-            return mView.getHeight();
-        }
-
-        @Override
-        public void invalidateView() {
-            mView.invalidate();
-        }
-
-        @Override
-        public void runAtNextFrame(Runnable r) {
-            mView.postOnAnimation(r);
-        }
-
-        @Override
-        public void removeCallback(Runnable r) {
-            mView.removeCallbacks(r);
-        }
-
-        @Override
-        public void scrollBy(int dy) {
-            mView.scrollBy(0, dy);
-        }
-
-        @Override
-        public void showBand(Rect rect) {
-            mBand.setBounds(rect);
-
-            if (!mIsOverlayShown) {
-                mView.getOverlay().add(mBand);
-            }
-        }
-
-        @Override
-        public void hideBand() {
-            mView.getOverlay().remove(mBand);
-        }
-
-        @Override
-        public boolean hasView(int pos) {
-            return mView.findViewHolderForAdapterPosition(pos) != null;
-        }
-    }
-}
diff --git a/src/com/android/documentsui/selection/BandPredicate.java b/src/com/android/documentsui/selection/BandPredicate.java
new file mode 100644
index 0000000..48b154b
--- /dev/null
+++ b/src/com/android/documentsui/selection/BandPredicate.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection;
+
+import static android.support.v4.util.Preconditions.checkArgument;
+
+import android.support.v7.widget.RecyclerView;
+import android.view.MotionEvent;
+import android.view.View;
+
+/**
+ * Provides a means of controlling when and where band selection is initiated.
+ * This can be used to permit band initiation in non-empty areas, like in the whitespace of
+ * a bound view. This is especially useful when there is no empty space between items.
+ */
+public abstract class BandPredicate {
+
+    /** @return true if band selection can be initiated in response to the {@link MotionEvent}. */
+    public abstract boolean canInitiate(MotionEvent e);
+
+    /**
+     * A BandPredicate that allows initiation of band selection only in areas of RecyclerView
+     * that have {@link RecyclerView#NO_POSITION}. In most cases, this will be the empty areas
+     * between views.
+     */
+    public static final class NoPositionBandPredicate extends BandPredicate {
+
+        private final RecyclerView mRecView;
+
+        public NoPositionBandPredicate(RecyclerView recView) {
+            checkArgument(recView != null);
+
+            mRecView = recView;
+        }
+
+        @Override
+        public boolean canInitiate(MotionEvent e) {
+            View itemView = mRecView.findChildViewUnder(e.getX(), e.getY());
+            int position = itemView != null
+                    ? mRecView.getChildAdapterPosition(itemView)
+                    : RecyclerView.NO_POSITION;
+
+            return position == RecyclerView.NO_POSITION;
+        }
+    };
+}
diff --git a/src/com/android/documentsui/selection/BandSelectionHelper.java b/src/com/android/documentsui/selection/BandSelectionHelper.java
new file mode 100644
index 0000000..554dcf4
--- /dev/null
+++ b/src/com/android/documentsui/selection/BandSelectionHelper.java
@@ -0,0 +1,401 @@
+/*
+ * 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.documentsui.selection;
+
+import static android.support.v4.util.Preconditions.checkArgument;
+import static android.support.v4.util.Preconditions.checkState;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.Build;
+import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.OnItemTouchListener;
+import android.support.v7.widget.RecyclerView.OnScrollListener;
+import android.util.Log;
+import android.view.MotionEvent;
+
+import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
+import com.android.documentsui.selection.SelectionHelper.StableIdProvider;
+import com.android.documentsui.selection.ViewAutoScroller.ScrollHost;
+import com.android.documentsui.selection.ViewAutoScroller.ScrollerCallbacks;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Provides mouse driven band-selection support when used in conjunction with a {@link RecyclerView}
+ * instance. This class is responsible for rendering a band overlay and manipulating selection
+ * status of the items it intersects with.
+ *
+ * <p> Given the recycling nature of RecyclerView items that have scrolled off-screen would not
+ * be selectable with a band that itself was partially rendered off-screen. To address this,
+ * BandSelectionController builds a model of the list/grid information presented by RecyclerView as
+ * the user interacts with items using their pointer (and the band). Selectable items that intersect
+ * with the band, both on and off screen, are selected on pointer up.
+ */
+public class BandSelectionHelper implements OnItemTouchListener {
+
+    static final boolean DEBUG = false;
+    static final String TAG = "BandController";
+
+    private final BandHost mHost;
+    private final StableIdProvider mStableIds;
+    private final RecyclerView.Adapter<?> mAdapter;
+    private final SelectionHelper mSelectionHelper;
+    private final SelectionPredicate mSelectionPredicate;
+    private final BandPredicate mBandPredicate;
+    private final ContentLock mLock;
+    private final Runnable mViewScroller;
+    private final GridModel.SelectionObserver mGridObserver;
+    private final List<Runnable> mBandStartedListeners = new ArrayList<>();
+
+    @Nullable private Rect mBounds;
+    @Nullable private Point mCurrentPosition;
+    @Nullable private Point mOrigin;
+    @Nullable private GridModel mModel;
+
+    public BandSelectionHelper(
+            BandHost host,
+            RecyclerView.Adapter<?> adapter,
+            StableIdProvider stableIds,
+            SelectionHelper selectionHelper,
+            SelectionPredicate selectionPredicate,
+            BandPredicate bandPredicate,
+            ContentLock lock) {
+
+        checkArgument(host != null);
+        checkArgument(adapter != null);
+        checkArgument(stableIds != null);
+        checkArgument(selectionHelper != null);
+        checkArgument(selectionPredicate != null);
+        checkArgument(bandPredicate != null);
+        checkArgument(lock != null);
+
+        mHost = host;
+        mStableIds = stableIds;
+        mAdapter = adapter;
+        mSelectionHelper = selectionHelper;
+        mSelectionPredicate = selectionPredicate;
+        mBandPredicate = bandPredicate;
+        mLock = lock;
+
+        mHost.addOnScrollListener(
+                new OnScrollListener() {
+                    @Override
+                    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+                        BandSelectionHelper.this.onScrolled(recyclerView, dx, dy);
+                    }
+                });
+
+        mViewScroller = new ViewAutoScroller(
+                new ScrollHost() {
+                    @Override
+                    public Point getCurrentPosition() {
+                        return mCurrentPosition;
+                    }
+
+                    @Override
+                    public int getViewHeight() {
+                        return mHost.getHeight();
+                    }
+
+                    @Override
+                    public boolean isActive() {
+                        return BandSelectionHelper.this.isActive();
+                    }
+                },
+                host);
+
+        mAdapter.registerAdapterDataObserver(
+                new RecyclerView.AdapterDataObserver() {
+                    @Override
+                    public void onChanged() {
+                        if (isActive()) {
+                            endBandSelect();
+                        }
+                    }
+
+                    @Override
+                    public void onItemRangeChanged(
+                            int startPosition, int itemCount, Object payload) {
+                        // No change in position. Ignoring.
+                    }
+
+                    @Override
+                    public void onItemRangeInserted(int startPosition, int itemCount) {
+                        if (isActive()) {
+                            endBandSelect();
+                        }
+                    }
+
+                    @Override
+                    public void onItemRangeRemoved(int startPosition, int itemCount) {
+                        assert(startPosition >= 0);
+                        assert(itemCount > 0);
+
+                        // TODO: Should update grid model.
+                    }
+
+                    @Override
+                    public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
+                        throw new UnsupportedOperationException();
+                    }
+                });
+
+        mGridObserver = new GridModel.SelectionObserver() {
+                @Override
+                public void onSelectionChanged(Set<String> updatedSelection) {
+                    mSelectionHelper.setProvisionalSelection(updatedSelection);
+                }
+            };
+    }
+
+    @VisibleForTesting
+    boolean isActive() {
+        boolean active = mModel != null;
+        if (Build.IS_DEBUGGABLE && active) {
+            mLock.checkLocked();
+        }
+        return active;
+    }
+
+    /**
+     * Adds a new listener to be notified when band is created.
+     */
+    public void addOnBandStartedListener(Runnable listener) {
+        checkArgument(listener != null);
+
+        mBandStartedListeners.add(listener);
+    }
+
+    /**
+     * Removes listener. No-op if listener was not previously installed.
+     */
+    public void removeOnBandStartedListener(Runnable listener) {
+        mBandStartedListeners.remove(listener);
+    }
+
+    /**
+     * Clients must call reset when there are any material changes to the layout of items
+     * in RecyclerView.
+     */
+    public void reset() {
+        if (!isActive()) {
+            return;
+        }
+
+        mHost.hideBand();
+        mModel.stopCapturing();
+        mModel.onDestroy();
+        mModel = null;
+        mOrigin = null;
+        mLock.unblock();
+    }
+
+    boolean shouldStart(MotionEvent e) {
+        // Don't start, or extend bands on non-left clicks.
+        if (!MotionEvents.isPrimaryButtonPressed(e)) {
+            return false;
+        }
+
+        // TODO: Refactor to NOT have side-effects on this "should" method.
+        // Weird things happen if we keep up band select
+        // when touch events happen.
+        if (isActive() && !MotionEvents.isMouseEvent(e)) {
+            endBandSelect();
+            return false;
+        }
+
+        // b/30146357 && b/23793622. onInterceptTouchEvent does not dispatch events to onTouchEvent
+        // unless the event is != ACTION_DOWN. Thus, we need to actually start band selection when
+        // mouse moves, or else starting band selection on mouse down can cause problems as events
+        // don't get routed correctly to onTouchEvent.
+        return !isActive()
+                && MotionEvents.isActionMove(e)
+                // the initial button move via mouse-touch (ie. down press)
+                // The adapter inserts items for UI layout purposes that aren't
+                // associated with files. Checking against actual modelIds count
+                // effectively ignores those UI layout items.
+                && !mStableIds.getStableIds().isEmpty()
+                && mBandPredicate.canInitiate(e);
+    }
+
+    public boolean shouldStop(MotionEvent e) {
+        return isActive()
+                && MotionEvents.isMouseEvent(e)
+                && (MotionEvents.isActionUp(e)
+                        || MotionEvents.isActionPointerUp(e)
+                        || MotionEvents.isActionCancel(e));
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(RecyclerView unused, MotionEvent e) {
+        if (shouldStart(e)) {
+            if (!MotionEvents.isCtrlKeyPressed(e)) {
+                mSelectionHelper.clearSelection();
+            }
+
+            startBandSelect(MotionEvents.getOrigin(e));
+            return isActive();
+        }
+
+        if (shouldStop(e)) {
+            endBandSelect();
+            checkState(mModel == null);
+            // fall through to return false, because the band eeess done!
+        }
+
+        return false;
+    }
+
+    /**
+     * Processes a MotionEvent by starting, ending, or resizing the band select overlay.
+     * @param input
+     */
+    @Override
+    public void onTouchEvent(RecyclerView unused, MotionEvent e) {
+        if (shouldStop(e)) {
+            endBandSelect();
+            return;
+        }
+
+        // We shouldn't get any events in this method when band select is not active,
+        // but it turns some guests show up late to the party.
+        // Probably happening when a re-layout is happening to the ReyclerView (ie. Pull-To-Refresh)
+        if (!isActive()) {
+            return;
+        }
+
+        assert MotionEvents.isActionMove(e);
+
+        mCurrentPosition = MotionEvents.getOrigin(e);
+        mModel.resizeSelection(mCurrentPosition);
+
+        scrollViewIfNecessary();
+        resizeBand();
+    }
+
+    @Override
+    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {}
+
+    /**
+     * Starts band select by adding the drawable to the RecyclerView's overlay.
+     */
+    private void startBandSelect(Point origin) {
+        if (DEBUG) Log.d(TAG, "Starting band select @ " + origin);
+
+        reset();
+        mModel = new GridModel(mHost, mStableIds, mSelectionPredicate);
+        mModel.addOnSelectionChangedListener(mGridObserver);
+
+        mLock.block();
+        notifyBandStarted();
+        mOrigin = origin;
+        mModel.startCapturing(mOrigin);
+    }
+
+    private void notifyBandStarted() {
+        for (Runnable listener : mBandStartedListeners) {
+            listener.run();
+        }
+    }
+
+    private void scrollViewIfNecessary() {
+        mHost.removeCallback(mViewScroller);
+        mViewScroller.run();
+        mHost.invalidateView();
+    }
+
+    /**
+     * Resizes the band select rectangle by using the origin and the current pointer position as
+     * two opposite corners of the selection.
+     */
+    private void resizeBand() {
+        mBounds = new Rect(Math.min(mOrigin.x, mCurrentPosition.x),
+                Math.min(mOrigin.y, mCurrentPosition.y),
+                Math.max(mOrigin.x, mCurrentPosition.x),
+                Math.max(mOrigin.y, mCurrentPosition.y));
+
+        mHost.showBand(mBounds);
+    }
+
+    /**
+     * Ends band select by removing the overlay.
+     */
+    private void endBandSelect() {
+        if (DEBUG) Log.d(TAG, "Ending band select.");
+
+        // TODO: Currently when a band select operation ends outside
+        // of an item (e.g. in the empty area between items),
+        // getPositionNearestOrigin may return an unselected item.
+        // Since the point of this code is to establish the
+        // anchor point for subsequent range operations (SHIFT+CLICK)
+        // we really want to do a better job figuring out the last
+        // item selected (and nearest to the cursor).
+        int firstSelected = mModel.getPositionNearestOrigin();
+        if (firstSelected != GridModel.NOT_SET
+                && mSelectionHelper.isSelected(mStableIds.getStableId(firstSelected))) {
+            // Establish the band selection point as range anchor. This
+            // allows touch and keyboard based selection activities
+            // to be based on the band selection anchor point.
+            mSelectionHelper.anchorRange(firstSelected);
+        }
+
+        mSelectionHelper.mergeProvisionalSelection();
+        reset();
+    }
+
+    /**
+     * @see RecyclerView.OnScrollListener
+     */
+    private void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+        if (!isActive()) {
+            return;
+        }
+
+        // Adjust the y-coordinate of the origin the opposite number of pixels so that the
+        // origin remains in the same place relative to the view's items.
+        mOrigin.y -= dy;
+        resizeBand();
+    }
+
+    /**
+     * Provides functionality for BandController. Exists primarily to tests that are
+     * fully isolated from RecyclerView.
+     */
+    public static abstract class BandHost extends ScrollerCallbacks {
+        public abstract void showBand(Rect rect);
+        public abstract void hideBand();
+        public abstract void addOnScrollListener(RecyclerView.OnScrollListener listener);
+        public abstract void removeOnScrollListener(RecyclerView.OnScrollListener listener);
+        public abstract int getHeight();
+        public abstract void invalidateView();
+        public abstract Point createAbsolutePoint(Point relativePoint);
+        public abstract Rect getAbsoluteRectForChildViewAt(int index);
+        public abstract int getAdapterPositionAt(int index);
+        public abstract int getColumnCount();
+        public abstract int getChildCount();
+        public abstract int getVisibleChildCount();
+        /**
+         * @return true if the item at adapter position is attached to a view.
+         */
+        public abstract boolean hasView(int adapterPosition);
+    }
+}
diff --git a/src/com/android/documentsui/selection/ContentLock.java b/src/com/android/documentsui/selection/ContentLock.java
new file mode 100644
index 0000000..5cc3132
--- /dev/null
+++ b/src/com/android/documentsui/selection/ContentLock.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection;
+
+import static android.support.v4.util.Preconditions.checkState;
+import static com.android.documentsui.selection.Shared.DEBUG;
+import static com.android.documentsui.selection.Shared.TAG;
+
+import android.annotation.MainThread;
+import android.annotation.Nullable;
+import android.content.Loader;
+import android.util.Log;
+
+/**
+ * ContentLock provides a mechanism to block content from reloading while selection
+ * activities like gesture and band selection are active. Clients using live data
+ * (data loaded, for example by a {@link Loader}), should route calls to load
+ * content through this lock using {@link ContentLock#runWhenUnlocked(Runnable)}.
+ */
+public final class ContentLock {
+
+    private int mLocks = 0;
+    private @Nullable Runnable mCallback;
+
+    /**
+     * Increment the block count by 1
+     */
+    @MainThread
+    public synchronized void block() {
+        mLocks++;
+        if (DEBUG) Log.v(TAG, "Incremented content lock count to " + mLocks + ".");
+    }
+
+    /**
+     * Decrement the block count by 1; If no other object is trying to block and there exists some
+     * callback, that callback will be run
+     */
+    @MainThread
+    public synchronized void unblock() {
+        checkState(mLocks > 0);
+
+        mLocks--;
+        if (DEBUG) Log.v(TAG, "Decremented content lock count to " + mLocks + ".");
+
+        if (mLocks == 0 && mCallback != null) {
+            mCallback.run();
+            mCallback = null;
+        }
+    }
+
+    /**
+     * Attempts to run the given Runnable if not-locked, or else the Runnable is set to be ran next
+     * (replacing any previous set Runnables).
+     */
+    public synchronized void runWhenUnlocked(Runnable runnable) {
+        if (mLocks == 0) {
+            runnable.run();
+        } else {
+            mCallback = runnable;
+        }
+    }
+
+    /**
+     * Returns true if locked.
+     */
+    synchronized boolean isLocked() {
+        return mLocks > 0;
+    }
+
+    /**
+     * Allows other selection code to perform a precondition check asserting the state is locked.
+     */
+    final void checkLocked() {
+        checkState(isLocked());
+    }
+
+    /**
+     * Allows other selection code to perform a precondition check asserting the state is unlocked.
+     */
+    final void checkUnlocked() {
+        checkState(!isLocked());
+    }
+}
diff --git a/src/com/android/documentsui/selection/DefaultBandHost.java b/src/com/android/documentsui/selection/DefaultBandHost.java
new file mode 100644
index 0000000..6760706
--- /dev/null
+++ b/src/com/android/documentsui/selection/DefaultBandHost.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection;
+
+import static com.android.internal.util.Preconditions.checkArgument;
+
+import android.annotation.DrawableRes;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+
+import com.android.documentsui.selection.BandSelectionHelper.BandHost;
+
+/**
+ * RecyclerView backed {@link BandHost}.
+ */
+public final class DefaultBandHost extends BandHost {
+
+    private final RecyclerView mRecView;
+    private final Drawable mBand;
+
+    private boolean mIsOverlayShown;
+
+    public DefaultBandHost(RecyclerView recView, @DrawableRes int bandOverlayId) {
+
+        checkArgument(recView != null);
+
+        mRecView = recView;
+        mBand = mRecView.getContext().getTheme().getDrawable(bandOverlayId);
+
+        checkArgument(mBand != null);
+    }
+
+    @Override
+    public int getAdapterPositionAt(int index) {
+        return mRecView.getChildAdapterPosition(mRecView.getChildAt(index));
+    }
+
+    @Override
+    public void addOnScrollListener(RecyclerView.OnScrollListener listener) {
+        mRecView.addOnScrollListener(listener);
+    }
+
+    @Override
+    public void removeOnScrollListener(RecyclerView.OnScrollListener listener) {
+        mRecView.removeOnScrollListener(listener);
+    }
+
+    @Override
+    public Point createAbsolutePoint(Point relativePoint) {
+        return new Point(relativePoint.x + mRecView.computeHorizontalScrollOffset(),
+                relativePoint.y + mRecView.computeVerticalScrollOffset());
+    }
+
+    @Override
+    public Rect getAbsoluteRectForChildViewAt(int index) {
+        final View child = mRecView.getChildAt(index);
+        final Rect childRect = new Rect();
+        child.getHitRect(childRect);
+        childRect.left += mRecView.computeHorizontalScrollOffset();
+        childRect.right += mRecView.computeHorizontalScrollOffset();
+        childRect.top += mRecView.computeVerticalScrollOffset();
+        childRect.bottom += mRecView.computeVerticalScrollOffset();
+        return childRect;
+    }
+
+    @Override
+    public int getChildCount() {
+        return mRecView.getAdapter().getItemCount();
+    }
+
+    @Override
+    public int getVisibleChildCount() {
+        return mRecView.getChildCount();
+    }
+
+    @Override
+    public int getColumnCount() {
+        RecyclerView.LayoutManager layoutManager = mRecView.getLayoutManager();
+        if (layoutManager instanceof GridLayoutManager) {
+            return ((GridLayoutManager) layoutManager).getSpanCount();
+        }
+
+        // Otherwise, it is a list with 1 column.
+        return 1;
+    }
+
+    @Override
+    public int getHeight() {
+        return mRecView.getHeight();
+    }
+
+    @Override
+    public void invalidateView() {
+        mRecView.invalidate();
+    }
+
+    @Override
+    public void runAtNextFrame(Runnable r) {
+        mRecView.postOnAnimation(r);
+    }
+
+    @Override
+    public void removeCallback(Runnable r) {
+        mRecView.removeCallbacks(r);
+    }
+
+    @Override
+    public void scrollBy(int dy) {
+        mRecView.scrollBy(0, dy);
+    }
+
+    @Override
+    public void showBand(Rect rect) {
+        mBand.setBounds(rect);
+
+        if (!mIsOverlayShown) {
+            mRecView.getOverlay().add(mBand);
+        }
+    }
+
+    @Override
+    public void hideBand() {
+        mRecView.getOverlay().remove(mBand);
+    }
+
+    @Override
+    public boolean hasView(int pos) {
+        return mRecView.findViewHolderForAdapterPosition(pos) != null;
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/documentsui/selection/DefaultBandPredicate.java b/src/com/android/documentsui/selection/DefaultBandPredicate.java
new file mode 100644
index 0000000..5de59d8
--- /dev/null
+++ b/src/com/android/documentsui/selection/DefaultBandPredicate.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection;
+
+import static android.support.v4.util.Preconditions.checkArgument;
+
+import android.support.annotation.Nullable;
+import android.view.MotionEvent;
+
+import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
+
+/**
+ * BandPredicate that consults ItemDetails, premitting band selection to start
+ * when the event is not in the drag region of the item.
+ */
+public final class DefaultBandPredicate extends BandPredicate {
+
+    private final ItemDetailsLookup mDetailsLookup;
+
+    public DefaultBandPredicate(ItemDetailsLookup detailsLookup) {
+        checkArgument(detailsLookup != null);
+
+        mDetailsLookup = detailsLookup;
+    }
+
+    @Override
+    public boolean canInitiate(MotionEvent e) {
+        @Nullable ItemDetails details = mDetailsLookup.getItemDetails(e);
+        return (details != null)
+            ? !details.inDragRegion(e)
+            : true;
+    }
+}
diff --git a/src/com/android/documentsui/selection/DefaultSelectionHelper.java b/src/com/android/documentsui/selection/DefaultSelectionHelper.java
new file mode 100644
index 0000000..75fcacb
--- /dev/null
+++ b/src/com/android/documentsui/selection/DefaultSelectionHelper.java
@@ -0,0 +1,554 @@
+/*
+ * 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.documentsui.selection;
+
+import static android.support.v4.util.Preconditions.checkArgument;
+import static android.support.v4.util.Preconditions.checkState;
+import static com.android.documentsui.selection.Shared.DEBUG;
+import static com.android.documentsui.selection.Shared.TAG;
+
+import android.support.annotation.IntDef;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.Adapter;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * {@link SelectionHelper} providing support traditional multi-item selection on top
+ * of {@link RecyclerView}.
+ *
+ * <p>The class supports running in a single-select mode, which can be enabled
+ * by passing {@colde #MODE_SINGLE} to the constructor.
+ */
+public final class DefaultSelectionHelper extends SelectionHelper {
+
+    public static final int MODE_MULTIPLE = 0;
+    public static final int MODE_SINGLE = 1;
+
+    @IntDef(flag = true, value = {
+            MODE_MULTIPLE,
+            MODE_SINGLE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SelectionMode {}
+
+    private static final int RANGE_REGULAR = 0;
+
+    /**
+     * "Provisional" selection represents a overlay on the primary selection. A provisional
+     * selection maybe be eventually added to the primary selection, or it may be abandoned.
+     *
+     * <p>E.g. BandController creates a provisional selection while a user is actively selecting
+     * items with the band. Provisionally selected items are considered to be selected in
+     * {@link Selection#contains(String)} and related methods. A provisional may be abandoned or
+     * applied by selection components (like
+     * {@link com.android.documentsui.selection.BandSelectionHelper}).
+     *
+     * <p>A provisional selection may intersect the primary selection, however clearing the
+     * provisional selection will not affect the primary selection where the two may intersect.
+     */
+    private static final int RANGE_PROVISIONAL = 1;
+    @IntDef({
+        RANGE_REGULAR,
+        RANGE_PROVISIONAL
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface RangeType {}
+
+    private final Selection mSelection = new Selection();
+    private final List<SelectionObserver> mObservers = new ArrayList<>(1);
+    private final RecyclerView.Adapter<?> mAdapter;
+    private final StableIdProvider mStableIds;
+    private final SelectionPredicate mSelectionPredicate;
+    private final RecyclerView.AdapterDataObserver mAdapterObserver;
+    private final RangeCallbacks mRangeCallbacks;
+    private final boolean mSingleSelect;
+
+    private @Nullable Range mRange;
+
+    /**
+     * Creates a new instance.
+     *
+     * @param mode single or multiple selection mode. In single selection mode
+     *     users can only select a single item.
+     * @param adapter {@link Adapter} for the RecyclerView this instance is coupled with.
+     * @param stableIds client supplied class providing access to stable ids.
+     * @param selectionPredicate A predicate allowing the client to disallow selection
+     *     of individual elements.
+     */
+    public DefaultSelectionHelper(
+            @SelectionMode int mode,
+            RecyclerView.Adapter<?> adapter,
+            StableIdProvider stableIds,
+            SelectionPredicate selectionPredicate) {
+
+        checkArgument(mode == MODE_SINGLE || mode == MODE_MULTIPLE);
+        checkArgument(adapter != null);
+        checkArgument(stableIds != null);
+        checkArgument(selectionPredicate != null);
+
+        mAdapter = adapter;
+        mStableIds = stableIds;
+        mSelectionPredicate = selectionPredicate;
+        mAdapterObserver = new AdapterObserver();
+        mRangeCallbacks = new RangeCallbacks();
+
+        mSingleSelect = mode == MODE_SINGLE;
+
+        mAdapter.registerAdapterDataObserver(mAdapterObserver);
+    }
+
+    @Override
+    public void addObserver(SelectionObserver callback) {
+        checkArgument(callback != null);
+        mObservers.add(callback);
+    }
+
+    @Override
+    public boolean hasSelection() {
+        return !mSelection.isEmpty();
+    }
+
+    @Override
+    public Selection getSelection() {
+        return mSelection;
+    }
+
+    @Override
+    public void copySelection(Selection dest) {
+        dest.copyFrom(mSelection);
+    }
+
+    @Override
+    public boolean isSelected(String id) {
+        return mSelection.contains(id);
+    }
+
+    @Override
+    public void restoreSelection(Selection other) {
+        setItemsSelectedQuietly(other.mSelection, true);
+        // NOTE: We intentionally don't restore provisional selection. It's provisional.
+        notifySelectionRestored();
+    }
+
+    @Override
+    public boolean setItemsSelected(Iterable<String> ids, boolean selected) {
+        boolean changed = setItemsSelectedQuietly(ids, selected);
+        notifySelectionChanged();
+        return changed;
+    }
+
+    private boolean setItemsSelectedQuietly(Iterable<String> ids, boolean selected) {
+        boolean changed = false;
+        for (String id: ids) {
+            boolean itemChanged = selected
+                    ? canSetState(id, true) && mSelection.add(id)
+                    : canSetState(id, false) && mSelection.remove(id);
+            if (itemChanged) {
+                notifyItemStateChanged(id, selected);
+            }
+            changed |= itemChanged;
+        }
+        return changed;
+    }
+
+    @Override
+    public void clearSelection() {
+        if (!hasSelection()) {
+            return;
+        }
+
+        Selection prev = clearSelectionQuietly();
+        notifySelectionCleared(prev);
+        notifySelectionChanged();
+    }
+
+    /**
+     * Clears the selection, without notifying selection listeners.
+     * Returns items in previous selection. Callers are responsible for notifying
+     * listeners about changes.
+     */
+    private Selection clearSelectionQuietly() {
+        mRange = null;
+
+        Selection prevSelection = new Selection();
+        if (hasSelection()) {
+            copySelection(prevSelection);
+            mSelection.clear();
+        }
+
+        return prevSelection;
+    }
+
+    @Override
+    public boolean select(String id) {
+        checkArgument(id != null);
+
+        if (!mSelection.contains(id)) {
+            if (!canSetState(id, true)) {
+                if (DEBUG) Log.d(TAG, "Select cancelled by selection predicate test.");
+                return false;
+            }
+
+            // Enforce single selection policy.
+            if (mSingleSelect && hasSelection()) {
+                Selection prev = clearSelectionQuietly();
+                notifySelectionCleared(prev);
+            }
+
+            mSelection.add(id);
+            notifyItemStateChanged(id, true);
+            notifySelectionChanged();
+
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
+    public boolean deselect(String id) {
+        checkArgument(id != null);
+
+        if (mSelection.contains(id)) {
+            if (!canSetState(id, false)) {
+                if (DEBUG) Log.d(TAG, "Deselect cancelled by selection predicate test.");
+                return false;
+            }
+            mSelection.remove(id);
+            notifyItemStateChanged(id, false);
+            notifySelectionChanged();
+            if (mSelection.isEmpty() && isRangeActive()) {
+                // if there's nothing in the selection and there is an active ranger it results
+                // in unexpected behavior when the user tries to start range selection: the item
+                // which the ranger 'thinks' is the already selected anchor becomes unselectable
+                endRange();
+            }
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
+    public void startRange(int pos) {
+        select(mStableIds.getStableId(pos));
+        anchorRange(pos);
+    }
+
+    @Override
+    public void extendRange(int pos) {
+        extendRange(pos, RANGE_REGULAR);
+    }
+
+    @Override
+    public void endRange() {
+        mRange = null;
+        // Clean up in case there was any leftover provisional selection
+        clearProvisionalSelection();
+    }
+
+    @Override
+    public void anchorRange(int position) {
+        checkArgument(position != RecyclerView.NO_POSITION);
+
+        // TODO: I'm not a fan of silently ignoring calls.
+        // Determine if there are any cases where method can be called
+        // w/o item already being selected. Else, tighten up the ship
+        // and make this conditional guard into a proper precondition check.
+        if (mSelection.contains(mStableIds.getStableId(position))) {
+            mRange = new Range(mRangeCallbacks, position);
+        }
+    }
+
+    @Override
+    public void extendProvisionalRange(int pos) {
+        extendRange(pos, RANGE_PROVISIONAL);
+    }
+
+    /**
+     * Sets the end point for the current range selection, started by a call to
+     * {@link #startRange(int)}. This function should only be called when a range selection
+     * is active (see {@link #isRangeActive()}. Items in the range [anchor, end] will be
+     * selected or in provisional select, depending on the type supplied. Note that if the type is
+     * provisional selection, one should do {@link #mergeProvisionalSelection()} at some
+     * point before calling on {@link #endRange()}.
+     *
+     * @param pos The new end position for the selection range.
+     * @param type The type of selection the range should utilize.
+     */
+    private void extendRange(int pos, @RangeType int type) {
+        checkState(isRangeActive(), "Range start point not set.");
+
+        mRange.extendSelection(pos, type);
+
+        // We're being lazy here notifying even when something might not have changed.
+        // To make this more correct, we'd need to update the Ranger class to return
+        // information about what has changed.
+        notifySelectionChanged();
+    }
+
+    @Override
+    public void setProvisionalSelection(Set<String> newSelection) {
+        Map<String, Boolean> delta = mSelection.setProvisionalSelection(newSelection);
+        for (Map.Entry<String, Boolean> entry: delta.entrySet()) {
+            notifyItemStateChanged(entry.getKey(), entry.getValue());
+        }
+
+        notifySelectionChanged();
+    }
+
+    @Override
+    public void mergeProvisionalSelection() {
+        mSelection.mergeProvisionalSelection();
+    }
+
+    @Override
+    public void clearProvisionalSelection() {
+        for (String id : mSelection.mProvisionalSelection) {
+            notifyItemStateChanged(id, false);
+        }
+        mSelection.clearProvisionalSelection();
+    }
+
+    @Override
+    public boolean isRangeActive() {
+        return mRange != null;
+    }
+
+    private boolean canSetState(String id, boolean nextState) {
+        return mSelectionPredicate.canSetStateForId(id, nextState);
+    }
+
+    private void onDataSetChanged() {
+        // Update the selection to remove any disappeared IDs.
+        mSelection.clearProvisionalSelection();
+        mSelection.intersect(mStableIds.getStableIds());
+        notifySelectionReset();
+
+        for (String id : mSelection) {
+            // If the underlying data set has changed, before restoring
+            // selection we must re-verify that it can be selected.
+            // Why? Because if the dataset has changed, then maybe the
+            // selectability of an item has changed.
+            if (!canSetState(id, true)) {
+                deselect(id);
+            } else {
+                int lastListener = mObservers.size() - 1;
+                for (int i = lastListener; i >= 0; i--) {
+                    mObservers.get(i).onItemStateChanged(id, true);
+                }
+            }
+        }
+        notifySelectionChanged();
+    }
+
+    private void onDataSetItemRangeInserted(int startPosition, int itemCount) {
+        mSelection.clearProvisionalSelection();
+    }
+
+    private void onDataSetItemRangeRemoved(int startPosition, int itemCount) {
+        checkArgument(startPosition >= 0);
+        checkArgument(itemCount > 0);
+
+        mSelection.clearProvisionalSelection();
+
+        // Remove any disappeared IDs from the selection.
+        //
+        // Ideally there could be a cheaper approach, checking
+        // each position individually, but since the source of
+        // truth for stable ids (StableIdProvider) probably
+        // it-self no-longer knows about the positions in question
+        // we fall back to the sledge hammer approach.
+        mSelection.intersect(mStableIds.getStableIds());
+    }
+
+    /**
+     * Notifies registered listeners when the selection status of a single item
+     * (identified by {@code position}) changes.
+     */
+    private void notifyItemStateChanged(String id, boolean selected) {
+        checkArgument(id != null);
+
+        int lastListenerIndex = mObservers.size() - 1;
+        for (int i = lastListenerIndex; i >= 0; i--) {
+            mObservers.get(i).onItemStateChanged(id, selected);
+        }
+
+        int position = mStableIds.getPosition(id);
+        if (DEBUG) Log.d(TAG, "ITEM " + id + " CHANGED at pos: " + position);
+
+        if (position >= 0) {
+            mAdapter.notifyItemChanged(position, SelectionHelper.SELECTION_CHANGED_MARKER);
+        } else {
+            Log.w(TAG, "Item change notification received for unknown item: " + id);
+        }
+    }
+
+    private void notifySelectionCleared(Selection selection) {
+        for (String id: selection.mSelection) {
+            notifyItemStateChanged(id, false);
+        }
+        for (String id: selection.mProvisionalSelection) {
+            notifyItemStateChanged(id, false);
+        }
+    }
+
+    /**
+     * Notifies registered listeners when the selection has changed. This
+     * notification should be sent only once a full series of changes
+     * is complete, e.g. clearingSelection, or updating the single
+     * selection from one item to another.
+     */
+    private void notifySelectionChanged() {
+        int lastListenerIndex = mObservers.size() - 1;
+        for (int i = lastListenerIndex; i >= 0; i--) {
+            mObservers.get(i).onSelectionChanged();
+        }
+    }
+
+    private void notifySelectionRestored() {
+        int lastListenerIndex = mObservers.size() - 1;
+        for (int i = lastListenerIndex; i >= 0; i--) {
+            mObservers.get(i).onSelectionRestored();
+        }
+    }
+
+    private void notifySelectionReset() {
+        int lastListenerIndex = mObservers.size() - 1;
+        for (int i = lastListenerIndex; i >= 0; i--) {
+            mObservers.get(i).onSelectionReset();
+        }
+    }
+
+    private void updateForRange(int begin, int end, boolean selected, @RangeType int type) {
+        switch (type) {
+            case RANGE_REGULAR:
+                updateForRegularRange(begin, end, selected);
+                break;
+            case RANGE_PROVISIONAL:
+                updateForProvisionalRange(begin, end, selected);
+                break;
+            default:
+                throw new IllegalArgumentException("Invalid range type: " + type);
+        }
+    }
+
+    private void updateForRegularRange(int begin, int end, boolean selected) {
+        checkArgument(end >= begin);
+
+        for (int i = begin; i <= end; i++) {
+            String id = mStableIds.getStableId(i);
+            if (id == null) {
+                continue;
+            }
+
+            if (selected) {
+                select(id);
+            } else {
+                deselect(id);
+            }
+        }
+    }
+
+    private void updateForProvisionalRange(int begin, int end, boolean selected) {
+        checkArgument(end >= begin);
+
+        for (int i = begin; i <= end; i++) {
+            String id = mStableIds.getStableId(i);
+            if (id == null) {
+                continue;
+            }
+
+            boolean changedState = false;
+            if (selected) {
+                boolean canSelect = canSetState(id, true);
+                if (canSelect && !mSelection.mSelection.contains(id)) {
+                    mSelection.mProvisionalSelection.add(id);
+                    changedState = true;
+                }
+            } else {
+                mSelection.mProvisionalSelection.remove(id);
+                changedState = true;
+            }
+
+            // Only notify item callbacks when something's state is actually changed in provisional
+            // selection.
+            if (changedState) {
+                notifyItemStateChanged(id, selected);
+            }
+        }
+
+        notifySelectionChanged();
+    }
+
+    private final class AdapterObserver extends RecyclerView.AdapterDataObserver {
+        @Override
+        public void onChanged() {
+            onDataSetChanged();
+        }
+
+        @Override
+        public void onItemRangeChanged(
+                int startPosition, int itemCount, Object payload) {
+            // No change in position. Ignore, since we assume
+            // selection is a user driven activity. So changes
+            // in properties of items shouldn't result in a
+            // change of selection.
+        }
+
+        @Override
+        public void onItemRangeInserted(int startPosition, int itemCount) {
+            onDataSetItemRangeInserted(startPosition, itemCount);
+        }
+
+        @Override
+        public void onItemRangeRemoved(int startPosition, int itemCount) {
+            onDataSetItemRangeRemoved(startPosition, itemCount);
+        }
+
+        @Override
+        public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    private final class RangeCallbacks extends Range.Callbacks {
+        @Override
+        void updateForRange(int begin, int end, boolean selected, int type) {
+            switch (type) {
+                case RANGE_REGULAR:
+                    updateForRegularRange(begin, end, selected);
+                    break;
+                case RANGE_PROVISIONAL:
+                    updateForProvisionalRange(begin, end, selected);
+                    break;
+                default:
+                    throw new IllegalArgumentException(
+                            "Invalid range type: " + type);
+            }
+        }
+    }
+}
diff --git a/src/com/android/documentsui/selection/GestureRouter.java b/src/com/android/documentsui/selection/GestureRouter.java
new file mode 100644
index 0000000..b336450
--- /dev/null
+++ b/src/com/android/documentsui/selection/GestureRouter.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2016 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.documentsui.selection;
+
+import static android.support.v4.util.Preconditions.checkNotNull;
+
+import android.support.annotation.Nullable;
+import android.view.GestureDetector.OnDoubleTapListener;
+import android.view.GestureDetector.OnGestureListener;
+import android.view.GestureDetector.SimpleOnGestureListener;
+import android.view.MotionEvent;
+
+/**
+ * GestureRouter is responsible for routing gestures detected by a GestureDetector
+ * to registered handlers. The primary function is to divide events by tool-type
+ * allowing handlers to cleanly implement tool-type specific policies.
+ */
+public final class GestureRouter<T extends OnGestureListener & OnDoubleTapListener>
+        implements OnGestureListener, OnDoubleTapListener {
+
+    private final ToolHandlerRegistry<T> mDelegates;
+
+    public GestureRouter(T defaultDelegate) {
+        checkNotNull(defaultDelegate);
+        mDelegates = new ToolHandlerRegistry<>(defaultDelegate);
+    }
+
+    public GestureRouter() {
+        this((T) new SimpleOnGestureListener());
+    }
+
+    /**
+     * @param toolType
+     * @param delegate the delegate, or null to unregister.
+     */
+    public void register(int toolType, @Nullable T delegate) {
+        mDelegates.set(toolType, delegate);
+    }
+
+    @Override
+    public boolean onSingleTapConfirmed(MotionEvent e) {
+        return mDelegates.get(e).onSingleTapConfirmed(e);
+    }
+
+    @Override
+    public boolean onDoubleTap(MotionEvent e) {
+        return mDelegates.get(e).onDoubleTap(e);
+    }
+
+    @Override
+    public boolean onDoubleTapEvent(MotionEvent e) {
+        return mDelegates.get(e).onDoubleTapEvent(e);
+    }
+
+    @Override
+    public boolean onDown(MotionEvent e) {
+        return mDelegates.get(e).onDown(e);
+    }
+
+    @Override
+    public void onShowPress(MotionEvent e) {
+        mDelegates.get(e).onShowPress(e);
+    }
+
+    @Override
+    public boolean onSingleTapUp(MotionEvent e) {
+        return mDelegates.get(e).onSingleTapUp(e);
+    }
+
+    @Override
+    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
+        return mDelegates.get(e2).onScroll(e1, e2, distanceX, distanceY);
+    }
+
+    @Override
+    public void onLongPress(MotionEvent e) {
+        mDelegates.get(e).onLongPress(e);
+    }
+
+    @Override
+    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+        return mDelegates.get(e2).onFling(e1, e2, velocityX, velocityY);
+    }
+}
diff --git a/src/com/android/documentsui/selection/GestureSelectionHelper.java b/src/com/android/documentsui/selection/GestureSelectionHelper.java
new file mode 100644
index 0000000..8a55cc3
--- /dev/null
+++ b/src/com/android/documentsui/selection/GestureSelectionHelper.java
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2016 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.documentsui.selection;
+
+import static android.support.v4.util.Preconditions.checkArgument;
+import static android.support.v4.util.Preconditions.checkState;
+
+import android.graphics.Point;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.VisibleForTesting;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.OnItemTouchListener;
+
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.android.documentsui.selection.ViewAutoScroller.ScrollHost;
+import com.android.documentsui.selection.ViewAutoScroller.ScrollerCallbacks;
+
+/**
+ * GestureSelectionHelper provides logic that interprets a combination
+ * of motions and gestures in order to provide gesture driven selection support
+ * when used in conjunction with RecyclerView and other classes in the ReyclerView
+ * selection support package.
+ */
+public final class GestureSelectionHelper extends ScrollHost implements OnItemTouchListener {
+
+    private static final String TAG = "GestureSelectionHelper";
+
+    private final SelectionHelper mSelectionMgr;
+    private final Runnable mScroller;
+    private final ViewDelegate mView;
+    private final ContentLock mLock;
+    private final ItemDetailsLookup mItemLookup;
+
+    private int mLastTouchedItemPosition = RecyclerView.NO_POSITION;
+    private boolean mStarted = false;
+    private Point mLastInterceptedPoint;
+
+    /**
+     * See {@link #create(SelectionHelper, RecyclerView, ContentLock)} for convenience
+     * method.
+     */
+    @VisibleForTesting
+    GestureSelectionHelper(
+            SelectionHelper selectionHelper,
+            ViewDelegate view,
+            ContentLock lock,
+            ItemDetailsLookup itemLookup) {
+
+        checkArgument(selectionHelper != null);
+        checkArgument(view != null);
+        checkArgument(lock != null);
+        checkArgument(itemLookup != null);
+
+        mSelectionMgr = selectionHelper;
+        mView = view;
+        mLock = lock;
+        mItemLookup = itemLookup;
+
+        mScroller = new ViewAutoScroller(this, mView);
+    }
+
+    /**
+     * Explicitly kicks off a gesture multi-select.
+     *
+     * @return true if started.
+     */
+    public void start() {
+        checkState(!mStarted);
+        // See: b/70518185. It appears start() is being called via onLongPress
+        // even though we never received an intial handleInterceptedDownEvent
+        // where we would usually initialize mLastStartedItemPos.
+        if (mLastTouchedItemPosition == RecyclerView.NO_POSITION) {
+            Log.w(TAG, "Illegal state. Can't start without valid mLastStartedItemPos.");
+            return;
+        }
+
+        // Partner code in MotionInputHandler ensures items
+        // are selected and range established prior to
+        // start being called.
+        // Verify the truth of that statement here
+        // to make the implicit coupling less of a time bomb.
+        checkState(mSelectionMgr.isRangeActive());
+
+        mLock.checkUnlocked();
+
+        mStarted = true;
+        mLock.block();
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(RecyclerView unused, MotionEvent e) {
+        if (MotionEvents.isMouseEvent(e)) {
+            if (Shared.DEBUG) Log.w(TAG, "Unexpected Mouse event. Check configuration.");
+        }
+
+        // TODO(b/109808552): It seems that mLastStartedItemPos should likely be set as a method
+        // parameter in start().
+        if (e.getActionMasked() == MotionEvent.ACTION_DOWN) {
+            if (mItemLookup.getItemDetails(e) != null) {
+                mLastTouchedItemPosition = mView.getItemUnder(e);
+            }
+        }
+
+        // See handleTouch(MotionEvent) javadoc for explanation as to why this is correct.
+        return handleTouch(e);
+    }
+
+    @Override
+    /** @hide */
+    public void onTouchEvent(@NonNull RecyclerView unused, @NonNull MotionEvent e) {
+        // See handleTouch(MotionEvent) javadoc for explanation as to why this is correct.
+        handleTouch(e);
+    }
+
+    /**
+     * If selection has started, will handle all appropriate types of MotionEvents and will return
+     * true if this OnItemTouchListener should start intercepting the rest of the MotionEvents.
+     *
+     * <p>This code, and the fact that this method is used by both OnInterceptTouchEvent and
+     * OnTouchEvent, is correct and valid because:
+     * <ol>
+     * <li>MotionEvents that aren't ACTION_DOWN are only ever passed to either onInterceptTouchEvent
+     * or onTouchEvent; never to both.  The MotionEvents we are handling in this method are not
+     * ACTION_DOWN, and therefore, its appropriate that both the onInterceptTouchEvent and
+     * onTouchEvent code paths cross this method.
+     * <li>This method returns true when we want to intercept MotionEvents.  OnInterceptTouchEvent
+     * uses that information to determine its own return, and OnMotionEvent doesn't have a return
+     * so this methods return value is irrelevant to it.
+     * </ol>
+     */
+    private boolean handleTouch(MotionEvent e) {
+        if (!mStarted) {
+            return false;
+        }
+
+        switch (e.getActionMasked()) {
+            case MotionEvent.ACTION_MOVE:
+                handleMoveEvent(e);
+                return true;
+            case MotionEvent.ACTION_UP:
+                handleUpEvent();
+                return true;
+            case MotionEvent.ACTION_CANCEL:
+                handleCancelEvent();
+                return true;
+        }
+
+        return false;
+    }
+
+    @Override
+    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+    }
+
+    // Called when ACTION_UP event is to be handled.
+    // Essentially, since this means all gesture movement is over, reset everything and apply
+    // provisional selection.
+    private void handleUpEvent() {
+        mSelectionMgr.mergeProvisionalSelection();
+        endSelection();
+        if (mLastTouchedItemPosition != RecyclerView.NO_POSITION) {
+            mSelectionMgr.startRange(mLastTouchedItemPosition);
+        }
+    }
+
+    // Called when ACTION_CANCEL event is to be handled.
+    // This means this gesture selection is aborted, so reset everything and abandon provisional
+    // selection.
+    private void handleCancelEvent() {
+        mSelectionMgr.clearProvisionalSelection();
+        endSelection();
+    }
+
+    private void endSelection() {
+        checkState(mStarted);
+
+        mLastTouchedItemPosition = RecyclerView.NO_POSITION;
+        mStarted = false;
+        mLock.unblock();
+    }
+
+    // Call when an intercepted ACTION_MOVE event is passed down.
+    // At this point, we are sure user wants to gesture multi-select.
+    private void handleMoveEvent(MotionEvent e) {
+        mLastInterceptedPoint = MotionEvents.getOrigin(e);
+
+        int lastGlidedItemPos = mView.getLastGlidedItemPosition(e);
+        if (lastGlidedItemPos != RecyclerView.NO_POSITION) {
+            doGestureMultiSelect(lastGlidedItemPos);
+        }
+        scrollIfNecessary();
+    }
+
+    // It's possible for events to go over the top/bottom of the RecyclerView.
+    // We want to get a Y-coordinate within the RecyclerView so we can find the childView underneath
+    // correctly.
+    private static float getInboundY(float max, float y) {
+        if (y < 0f) {
+            return 0f;
+        } else if (y > max) {
+            return max;
+        }
+        return y;
+    }
+
+    /* Given the end position, select everything in-between.
+     * @param endPos  The adapter position of the end item.
+     */
+    private void doGestureMultiSelect(int endPos) {
+        mSelectionMgr.extendProvisionalRange(endPos);
+    }
+
+    private void scrollIfNecessary() {
+        mScroller.run();
+    }
+
+    @Override
+    public Point getCurrentPosition() {
+        return mLastInterceptedPoint;
+    }
+
+    @Override
+    public int getViewHeight() {
+        return mView.getHeight();
+    }
+
+    @Override
+    public boolean isActive() {
+        return mStarted && mSelectionMgr.hasSelection();
+    }
+
+    /**
+     * Returns a new instance of GestureSelectionHelper, wrapping the
+     * RecyclerView in a test friendly wrapper.
+     */
+    public static GestureSelectionHelper create(
+            SelectionHelper selectionMgr,
+            RecyclerView recycler,
+            ContentLock lock,
+            ItemDetailsLookup itemLookup) {
+
+        return new GestureSelectionHelper(
+                selectionMgr, new RecyclerViewDelegate(recycler), lock, itemLookup);
+    }
+
+    @VisibleForTesting
+    static abstract class ViewDelegate extends ScrollerCallbacks {
+        abstract int getHeight();
+
+        abstract int getItemUnder(MotionEvent e);
+
+        abstract int getLastGlidedItemPosition(MotionEvent e);
+    }
+
+    @VisibleForTesting
+    static final class RecyclerViewDelegate extends ViewDelegate {
+
+        private final RecyclerView mView;
+
+        RecyclerViewDelegate(RecyclerView view) {
+            checkArgument(view != null);
+            mView = view;
+        }
+
+        @Override
+        int getHeight() {
+            return mView.getHeight();
+        }
+
+        @Override
+        int getItemUnder(MotionEvent e) {
+            View child = mView.findChildViewUnder(e.getX(), e.getY());
+            return child != null
+                    ? mView.getChildAdapterPosition(child)
+                    : RecyclerView.NO_POSITION;
+        }
+
+        @Override
+        int getLastGlidedItemPosition(MotionEvent e) {
+            // If user has moved his pointer to the bottom-right empty pane (ie. to the right of the
+            // last item of the recycler view), we would want to set that as the currentItemPos
+            View lastItem = mView.getLayoutManager()
+                    .getChildAt(mView.getLayoutManager().getChildCount() - 1);
+            int direction =
+                    mView.getContext().getResources().getConfiguration().getLayoutDirection();
+            final boolean pastLastItem = isPastLastItem(lastItem.getTop(),
+                    lastItem.getLeft(),
+                    lastItem.getRight(),
+                    e,
+                    direction);
+
+            // Since views get attached & detached from RecyclerView,
+            // {@link LayoutManager#getChildCount} can return a different number from the actual
+            // number
+            // of items in the adapter. Using the adapter is the for sure way to get the actual last
+            // item position.
+            final float inboundY = getInboundY(mView.getHeight(), e.getY());
+            return (pastLastItem) ? mView.getAdapter().getItemCount() - 1
+                    : mView.getChildAdapterPosition(mView.findChildViewUnder(e.getX(), inboundY));
+        }
+
+        /*
+         * Check to see if MotionEvent if past a particular item, i.e. to the right or to the bottom
+         * of the item.
+         * For RTL, it would to be to the left or to the bottom of the item.
+         */
+        @VisibleForTesting
+        static boolean isPastLastItem(int top, int left, int right, MotionEvent e, int direction) {
+            if (direction == View.LAYOUT_DIRECTION_LTR) {
+                return e.getX() > right && e.getY() > top;
+            } else {
+                return e.getX() < left && e.getY() > top;
+            }
+        }
+
+        @Override
+        public void scrollBy(int dy) {
+            mView.scrollBy(0, dy);
+        }
+
+        @Override
+        public void runAtNextFrame(Runnable r) {
+            mView.postOnAnimation(r);
+        }
+
+        @Override
+        public void removeCallback(Runnable r) {
+            mView.removeCallbacks(r);
+        }
+    }
+}
diff --git a/src/com/android/documentsui/selection/GestureSelector.java b/src/com/android/documentsui/selection/GestureSelector.java
deleted file mode 100644
index 7c5f217..0000000
--- a/src/com/android/documentsui/selection/GestureSelector.java
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.selection;
-
-import static com.android.documentsui.base.Shared.DEBUG;
-
-import android.graphics.Point;
-import android.support.annotation.VisibleForTesting;
-import android.support.v7.widget.RecyclerView;
-import android.util.Log;
-import android.view.View;
-
-import com.android.documentsui.DirectoryReloadLock;
-import com.android.documentsui.base.Events.InputEvent;
-import com.android.documentsui.ui.ViewAutoScroller;
-import com.android.documentsui.ui.ViewAutoScroller.ScrollActionDelegate;
-import com.android.documentsui.ui.ViewAutoScroller.ScrollDistanceDelegate;
-
-import java.util.function.IntSupplier;
-
-import javax.annotation.Nullable;
-
-/*
- * Helper class used to intercept events that could cause a gesture multi-select, and keeps
- * the interception going if necessary.
- */
-public final class GestureSelector {
-    private final String TAG = "GestureSelector";
-
-    private final SelectionManager mSelectionMgr;
-    private final Runnable mDragScroller;
-    private final IntSupplier mHeight;
-    private final ViewFinder mViewFinder;
-    private final DirectoryReloadLock mLock;
-    private int mLastStartedItemPos = -1;
-    private boolean mStarted = false;
-    private Point mLastInterceptedPoint;
-
-    GestureSelector(
-            SelectionManager selectionMgr,
-            IntSupplier heightSupplier,
-            ViewFinder viewFinder,
-            ScrollActionDelegate actionDelegate,
-            DirectoryReloadLock lock) {
-        mSelectionMgr = selectionMgr;
-        mHeight = heightSupplier;
-        mViewFinder = viewFinder;
-        mLock = lock;
-
-        ScrollDistanceDelegate distanceDelegate = new ScrollDistanceDelegate() {
-            @Override
-            public Point getCurrentPosition() {
-                return mLastInterceptedPoint;
-            }
-
-            @Override
-            public int getViewHeight() {
-                return mHeight.getAsInt();
-            }
-
-            @Override
-            public boolean isActive() {
-                return mStarted && mSelectionMgr.hasSelection();
-            }
-        };
-
-        mDragScroller = new ViewAutoScroller(distanceDelegate, actionDelegate);
-    }
-
-    public static GestureSelector create(
-            SelectionManager selectionMgr,
-            RecyclerView scrollView,
-            DirectoryReloadLock lock) {
-        ScrollActionDelegate actionDelegate = new ScrollActionDelegate() {
-            @Override
-            public void scrollBy(int dy) {
-                scrollView.scrollBy(0, dy);
-            }
-
-            @Override
-            public void runAtNextFrame(Runnable r) {
-                scrollView.postOnAnimation(r);
-            }
-
-            @Override
-            public void removeCallback(Runnable r) {
-                scrollView.removeCallbacks(r);
-            }
-        };
-        GestureSelector helper =
-                new GestureSelector(
-                        selectionMgr,
-                        scrollView::getHeight,
-                        scrollView::findChildViewUnder,
-                        actionDelegate,
-                        lock);
-
-        return helper;
-    }
-
-    // Explicitly kick off a gesture multi-select.
-    public boolean start(InputEvent event) {
-        //the anchor must already be set before a multi-select event can be started
-        if (mLastStartedItemPos < 0) {
-            if (DEBUG) Log.d(TAG, "Tried to start multi-select without setting an anchor.");
-            return false;
-        }
-        if (mStarted) {
-            return false;
-        }
-        mStarted = true;
-        return true;
-    }
-
-    public boolean onInterceptTouchEvent(InputEvent e) {
-        if (e.isMouseEvent()) {
-            return false;
-        }
-
-        boolean handled = false;
-
-        if (e.isActionDown()) {
-            handled = handleInterceptedDownEvent(e);
-        }
-
-        if (e.isActionMove()) {
-            handled = handleInterceptedMoveEvent(e);
-        }
-
-        return handled;
-    }
-
-    public void onTouchEvent(RecyclerView rv, InputEvent e) {
-        if (!mStarted) {
-            return;
-        }
-
-        if (e.isActionUp()) {
-            handleUpEvent(e);
-        }
-
-        if (e.isActionCancel()) {
-            handleCancelEvent(e);
-        }
-
-        if (e.isActionMove()) {
-            handleOnTouchMoveEvent(rv, e);
-        }
-    }
-
-    // Called when an ACTION_DOWN event is intercepted.
-    // If down event happens on a file/doc, we mark that item's position as last started.
-    private boolean handleInterceptedDownEvent(InputEvent e) {
-        View itemView = mViewFinder.findView(e.getX(), e.getY());
-        if (itemView != null) {
-            mLastStartedItemPos = e.getItemPosition();
-        }
-        return false;
-    }
-
-    // Called when an ACTION_MOVE event is intercepted.
-    private boolean handleInterceptedMoveEvent(InputEvent e) {
-        mLastInterceptedPoint = e.getOrigin();
-        if (mStarted) {
-            mSelectionMgr.startRangeSelection(mLastStartedItemPos);
-            // Gesture Selection about to start
-            mLock.block();
-            return true;
-        }
-        return false;
-    }
-
-    // Called when ACTION_UP event is to be handled.
-    // Essentially, since this means all gesture movement is over, reset everything and apply
-    // provisional selection.
-    private void handleUpEvent(InputEvent e) {
-        mSelectionMgr.getSelection().applyProvisionalSelection();
-        endSelection();
-    }
-
-    // Called when ACTION_CANCEL event is to be handled.
-    // This means this gesture selection is aborted, so reset everything and abandon provisional
-    // selection.
-    private void handleCancelEvent(InputEvent e) {
-        mSelectionMgr.cancelProvisionalSelection();
-        endSelection();
-    }
-
-    private void endSelection() {
-        assert(mStarted);
-        mLastStartedItemPos = -1;
-        mStarted = false;
-        mLock.unblock();
-    }
-
-    // Call when an intercepted ACTION_MOVE event is passed down.
-    // At this point, we are sure user wants to gesture multi-select.
-    private void handleOnTouchMoveEvent(RecyclerView rv, InputEvent e) {
-        mLastInterceptedPoint = e.getOrigin();
-
-        // If user has moved his pointer to the bottom-right empty pane (ie. to the right of the
-        // last item of the recycler view), we would want to set that as the currentItemPos
-        View lastItem = rv.getLayoutManager()
-                .getChildAt(rv.getLayoutManager().getChildCount() - 1);
-        int direction = rv.getContext().getResources().getConfiguration().getLayoutDirection();
-        final boolean pastLastItem = isPastLastItem(lastItem.getTop(),
-                lastItem.getLeft(),
-                lastItem.getRight(),
-                e,
-                direction);
-
-        // Since views get attached & detached from RecyclerView,
-        // {@link LayoutManager#getChildCount} can return a different number from the actual
-        // number
-        // of items in the adapter. Using the adapter is the for sure way to get the actual last
-        // item position.
-        final float inboundY = getInboundY(rv.getHeight(), e.getY());
-        final int lastGlidedItemPos = (pastLastItem) ? rv.getAdapter().getItemCount() - 1
-                : rv.getChildAdapterPosition(rv.findChildViewUnder(e.getX(), inboundY));
-        if (lastGlidedItemPos != RecyclerView.NO_POSITION) {
-            doGestureMultiSelect(lastGlidedItemPos);
-        }
-        scrollIfNecessary();
-    }
-
-    // It's possible for events to go over the top/bottom of the RecyclerView.
-    // We want to get a Y-coordinate within the RecyclerView so we can find the childView underneath
-    // correctly.
-    private static float getInboundY(float max, float y) {
-        if (y < 0f) {
-            return 0f;
-        } else if (y > max) {
-            return max;
-        }
-        return y;
-    }
-
-    /*
-     * Check to see an InputEvent if past a particular item, i.e. to the right or to the bottom
-     * of the item.
-     * For RTL, it would to be to the left or to the bottom of the item.
-     */
-    @VisibleForTesting
-    static boolean isPastLastItem(int top, int left, int right, InputEvent e, int direction) {
-        if (direction == View.LAYOUT_DIRECTION_LTR) {
-            return e.getX() > right && e.getY() > top;
-        } else {
-            return e.getX() < left && e.getY() > top;
-        }
-    }
-
-    /* Given the end position, select everything in-between.
-     * @param endPos  The adapter position of the end item.
-     */
-    private void doGestureMultiSelect(int endPos) {
-        mSelectionMgr.snapProvisionalRangeSelection(endPos);
-    }
-
-    private void scrollIfNecessary() {
-        mDragScroller.run();
-    }
-
-    @FunctionalInterface
-    interface ViewFinder {
-        @Nullable View findView(float x, float y);
-    }
-}
\ No newline at end of file
diff --git a/src/com/android/documentsui/selection/GridModel.java b/src/com/android/documentsui/selection/GridModel.java
new file mode 100644
index 0000000..dae445d
--- /dev/null
+++ b/src/com/android/documentsui/selection/GridModel.java
@@ -0,0 +1,727 @@
+/*
+ * 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.documentsui.selection;
+
+import static android.support.v4.util.Preconditions.checkArgument;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.support.annotation.VisibleForTesting;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.OnScrollListener;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
+
+import com.android.documentsui.selection.BandSelectionHelper.BandHost;
+import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
+import com.android.documentsui.selection.SelectionHelper.StableIdProvider;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Provides a band selection item model for views within a RecyclerView. This class queries the
+ * RecyclerView to determine where its items are placed; then, once band selection is underway,
+ * it alerts listeners of which items are covered by the selections.
+ */
+final class GridModel {
+
+    // Magical value indicating that a value has not been previously set. primitive null :)
+    static final int NOT_SET = -1;
+
+    // Enum values used to determine the corner at which the origin is located within the
+    private static final int UPPER = 0x00;
+    private static final int LOWER = 0x01;
+    private static final int LEFT = 0x00;
+    private static final int RIGHT = 0x02;
+    private static final int UPPER_LEFT = UPPER | LEFT;
+    private static final int UPPER_RIGHT = UPPER | RIGHT;
+    private static final int LOWER_LEFT = LOWER | LEFT;
+    private static final int LOWER_RIGHT = LOWER | RIGHT;
+
+    private final BandHost mHost;
+    private final StableIdProvider mStableIds;
+    private final SelectionPredicate mSelectionPredicate;
+
+    private final List<SelectionObserver> mOnSelectionChangedListeners =
+            new ArrayList<>();
+
+    // Map from the x-value of the left side of a SparseBooleanArray of adapter positions, keyed
+    // by their y-offset. For example, if the first column of the view starts at an x-value of 5,
+    // mColumns.get(5) would return an array of positions in that column. Within that array, the
+    // value for key y is the adapter position for the item whose y-offset is y.
+    private final SparseArray<SparseIntArray> mColumns = new SparseArray<>();
+
+    // List of limits along the x-axis (columns).
+    // This list is sorted from furthest left to furthest right.
+    private final List<Limits> mColumnBounds = new ArrayList<>();
+
+    // List of limits along the y-axis (rows). Note that this list only contains items which
+    // have been in the viewport.
+    private final List<Limits> mRowBounds = new ArrayList<>();
+
+    // The adapter positions which have been recorded so far.
+    private final SparseBooleanArray mKnownPositions = new SparseBooleanArray();
+
+    // Array passed to registered OnSelectionChangedListeners. One array is created and reused
+    // throughout the lifetime of the object.
+    private final Set<String> mSelection = new HashSet<>();
+
+    // The current pointer (in absolute positioning from the top of the view).
+    private Point mPointer = null;
+
+    // The bounds of the band selection.
+    private RelativePoint mRelativeOrigin;
+    private RelativePoint mRelativePointer;
+
+    private boolean mIsActive;
+
+    // Tracks where the band select originated from. This is used to determine where selections
+    // should expand from when Shift+click is used.
+    private int mPositionNearestOrigin = NOT_SET;
+
+    private final OnScrollListener mScrollListener;
+
+    GridModel(
+            BandHost host,
+            StableIdProvider stableIds,
+            SelectionPredicate selectionPredicate) {
+
+        mHost = host;
+        mStableIds = stableIds;
+        mSelectionPredicate = selectionPredicate;
+
+        mScrollListener = new OnScrollListener() {
+            @Override
+            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+                GridModel.this.onScrolled(recyclerView, dx, dy);
+            }
+        };
+
+        mHost.addOnScrollListener(mScrollListener);
+    }
+
+    /**
+     * Stops listening to the view's scrolls. Call this function before discarding a
+     * GridModel object to prevent memory leaks.
+     */
+    void stopListening() {
+        mHost.removeOnScrollListener(mScrollListener);
+    }
+
+    /**
+     * Start a band select operation at the given point.
+     * @param relativeOrigin The origin of the band select operation, relative to the viewport.
+     *     For example, if the view is scrolled to the bottom, the top-left of the viewport
+     *     would have a relative origin of (0, 0), even though its absolute point has a higher
+     *     y-value.
+     */
+    void startCapturing(Point relativeOrigin) {
+        recordVisibleChildren();
+        if (isEmpty()) {
+            // The selection band logic works only if there is at least one visible child.
+            return;
+        }
+
+        mIsActive = true;
+        mPointer = mHost.createAbsolutePoint(relativeOrigin);
+        mRelativeOrigin = new RelativePoint(mPointer);
+        mRelativePointer = new RelativePoint(mPointer);
+        computeCurrentSelection();
+        notifySelectionChanged();
+    }
+
+    /**
+     * Ends the band selection.
+     */
+    void stopCapturing() {
+        mIsActive = false;
+    }
+
+    /**
+     * Resizes the selection by adjusting the pointer (i.e., the corner of the selection
+     * opposite the origin.
+     * @param relativePointer The pointer (opposite of the origin) of the band select operation,
+     *     relative to the viewport. For example, if the view is scrolled to the bottom, the
+     *     top-left of the viewport would have a relative origin of (0, 0), even though its
+     *     absolute point has a higher y-value.
+     */
+    @VisibleForTesting
+    void resizeSelection(Point relativePointer) {
+        mPointer = mHost.createAbsolutePoint(relativePointer);
+        updateModel();
+    }
+
+    /**
+     * @return The adapter position for the item nearest the origin corresponding to the latest
+     *         band select operation, or NOT_SET if the selection did not cover any items.
+     */
+    int getPositionNearestOrigin() {
+        return mPositionNearestOrigin;
+    }
+
+    private void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+        if (!mIsActive) {
+            return;
+        }
+
+        mPointer.x += dx;
+        mPointer.y += dy;
+        recordVisibleChildren();
+        updateModel();
+    }
+
+    /**
+     * Queries the view for all children and records their location metadata.
+     */
+    private void recordVisibleChildren() {
+        for (int i = 0; i < mHost.getVisibleChildCount(); i++) {
+            int adapterPosition = mHost.getAdapterPositionAt(i);
+            // Sometimes the view is not attached, as we notify the multi selection manager
+            // synchronously, while views are attached asynchronously. As a result items which
+            // are in the adapter may not actually have a corresponding view (yet).
+            if (mHost.hasView(adapterPosition) &&
+                    mSelectionPredicate.canSetStateAtPosition(adapterPosition, true) &&
+                    !mKnownPositions.get(adapterPosition)) {
+                mKnownPositions.put(adapterPosition, true);
+                recordItemData(mHost.getAbsoluteRectForChildViewAt(i), adapterPosition);
+            }
+        }
+    }
+
+    /**
+     * Checks if there are any recorded children.
+     */
+    private boolean isEmpty() {
+        return mColumnBounds.size() == 0 || mRowBounds.size() == 0;
+    }
+
+    /**
+     * Updates the limits lists and column map with the given item metadata.
+     * @param absoluteChildRect The absolute rectangle for the child view being processed.
+     * @param adapterPosition The position of the child view being processed.
+     */
+    private void recordItemData(Rect absoluteChildRect, int adapterPosition) {
+        if (mColumnBounds.size() != mHost.getColumnCount()) {
+            // If not all x-limits have been recorded, record this one.
+            recordLimits(
+                    mColumnBounds, new Limits(absoluteChildRect.left, absoluteChildRect.right));
+        }
+
+        recordLimits(mRowBounds, new Limits(absoluteChildRect.top, absoluteChildRect.bottom));
+
+        SparseIntArray columnList = mColumns.get(absoluteChildRect.left);
+        if (columnList == null) {
+            columnList = new SparseIntArray();
+            mColumns.put(absoluteChildRect.left, columnList);
+        }
+        columnList.put(absoluteChildRect.top, adapterPosition);
+    }
+
+    /**
+     * Ensures limits exists within the sorted list limitsList, and adds it to the list if it
+     * does not exist.
+     */
+    private void recordLimits(List<Limits> limitsList, Limits limits) {
+        int index = Collections.binarySearch(limitsList, limits);
+        if (index < 0) {
+            limitsList.add(~index, limits);
+        }
+    }
+
+    /**
+     * Handles a moved pointer; this function determines whether the pointer movement resulted
+     * in a selection change and, if it has, notifies listeners of this change.
+     */
+    private void updateModel() {
+        RelativePoint old = mRelativePointer;
+        mRelativePointer = new RelativePoint(mPointer);
+        if (old != null && mRelativePointer.equals(old)) {
+            return;
+        }
+
+        computeCurrentSelection();
+        notifySelectionChanged();
+    }
+
+    /**
+     * Computes the currently-selected items.
+     */
+    private void computeCurrentSelection() {
+        if (areItemsCoveredByBand(mRelativePointer, mRelativeOrigin)) {
+            updateSelection(computeBounds());
+        } else {
+            mSelection.clear();
+            mPositionNearestOrigin = NOT_SET;
+        }
+    }
+
+    /**
+     * Notifies all listeners of a selection change. Note that this function simply passes
+     * mSelection, so computeCurrentSelection() should be called before this
+     * function.
+     */
+    private void notifySelectionChanged() {
+        for (SelectionObserver listener : mOnSelectionChangedListeners) {
+            listener.onSelectionChanged(mSelection);
+        }
+    }
+
+    /**
+     * @param rect Rectangle including all covered items.
+     */
+    private void updateSelection(Rect rect) {
+        int columnStart =
+                Collections.binarySearch(mColumnBounds, new Limits(rect.left, rect.left));
+
+        checkArgument(columnStart >= 0, "Rect doesn't intesect any known column.");
+
+        int columnEnd = columnStart;
+
+        for (int i = columnStart; i < mColumnBounds.size()
+                && mColumnBounds.get(i).lowerLimit <= rect.right; i++) {
+            columnEnd = i;
+        }
+
+        int rowStart = Collections.binarySearch(mRowBounds, new Limits(rect.top, rect.top));
+        if (rowStart < 0) {
+            mPositionNearestOrigin = NOT_SET;
+            return;
+        }
+
+        int rowEnd = rowStart;
+        for (int i = rowStart; i < mRowBounds.size()
+                && mRowBounds.get(i).lowerLimit <= rect.bottom; i++) {
+            rowEnd = i;
+        }
+
+        updateSelection(columnStart, columnEnd, rowStart, rowEnd);
+    }
+
+    /**
+     * Computes the selection given the previously-computed start- and end-indices for each
+     * row and column.
+     */
+    private void updateSelection(
+            int columnStartIndex, int columnEndIndex, int rowStartIndex, int rowEndIndex) {
+
+        if (BandSelectionHelper.DEBUG) {
+            Log.d(BandSelectionHelper.TAG, String.format(
+                    "updateSelection: %d, %d, %d, %d",
+                    columnStartIndex, columnEndIndex, rowStartIndex, rowEndIndex));
+        }
+
+        mSelection.clear();
+        for (int column = columnStartIndex; column <= columnEndIndex; column++) {
+            SparseIntArray items = mColumns.get(mColumnBounds.get(column).lowerLimit);
+            for (int row = rowStartIndex; row <= rowEndIndex; row++) {
+                // The default return value for SparseIntArray.get is 0, which is a valid
+                // position. Use a sentry value to prevent erroneously selecting item 0.
+                final int rowKey = mRowBounds.get(row).lowerLimit;
+                int position = items.get(rowKey, NOT_SET);
+                if (position != NOT_SET) {
+                    String id = mStableIds.getStableId(position);
+                    if (id != null) {
+                        // The adapter inserts items for UI layout purposes that aren't
+                        // associated with files. Those will have a null model ID.
+                        // Don't select them.
+                        if (canSelect(id)) {
+                            mSelection.add(id);
+                        }
+                    }
+                    if (isPossiblePositionNearestOrigin(column, columnStartIndex, columnEndIndex,
+                            row, rowStartIndex, rowEndIndex)) {
+                        // If this is the position nearest the origin, record it now so that it
+                        // can be returned by endSelection() later.
+                        mPositionNearestOrigin = position;
+                    }
+                }
+            }
+        }
+    }
+
+    private boolean canSelect(String id) {
+        return mSelectionPredicate.canSetStateForId(id, true);
+    }
+
+    /**
+     * @return Returns true if the position is the nearest to the origin, or, in the case of the
+     *     lower-right corner, whether it is possible that the position is the nearest to the
+     *     origin. See comment below for reasoning for this special case.
+     */
+    private boolean isPossiblePositionNearestOrigin(int columnIndex, int columnStartIndex,
+            int columnEndIndex, int rowIndex, int rowStartIndex, int rowEndIndex) {
+        int corner = computeCornerNearestOrigin();
+        switch (corner) {
+            case UPPER_LEFT:
+                return columnIndex == columnStartIndex && rowIndex == rowStartIndex;
+            case UPPER_RIGHT:
+                return columnIndex == columnEndIndex && rowIndex == rowStartIndex;
+            case LOWER_LEFT:
+                return columnIndex == columnStartIndex && rowIndex == rowEndIndex;
+            case LOWER_RIGHT:
+                // Note that in some cases, the last row will not have as many items as there
+                // are columns (e.g., if there are 4 items and 3 columns, the second row will
+                // only have one item in the first column). This function is invoked for each
+                // position from left to right, so return true for any position in the bottom
+                // row and only the right-most position in the bottom row will be recorded.
+                return rowIndex == rowEndIndex;
+            default:
+                throw new RuntimeException("Invalid corner type.");
+        }
+    }
+
+    /**
+     * Listener for changes in which items have been band selected.
+     */
+    public static abstract class SelectionObserver {
+        abstract void onSelectionChanged(Set<String> updatedSelection);
+    }
+
+    void addOnSelectionChangedListener(SelectionObserver listener) {
+        mOnSelectionChangedListeners.add(listener);
+    }
+
+    /**
+     * Called when {@link BandSelectionHelper} is finished with a GridModel.
+     */
+    void onDestroy() {
+        mOnSelectionChangedListeners.clear();
+        stopListening();
+    }
+
+    /**
+     * Limits of a view item. For example, if an item's left side is at x-value 5 and its right side
+     * is at x-value 10, the limits would be from 5 to 10. Used to record the left- and right sides
+     * of item columns and the top- and bottom sides of item rows so that it can be determined
+     * whether the pointer is located within the bounds of an item.
+     */
+    private static class Limits implements Comparable<Limits> {
+        int lowerLimit;
+        int upperLimit;
+
+        Limits(int lowerLimit, int upperLimit) {
+            this.lowerLimit = lowerLimit;
+            this.upperLimit = upperLimit;
+        }
+
+        @Override
+        public int compareTo(Limits other) {
+            return lowerLimit - other.lowerLimit;
+        }
+
+        @Override
+        public int hashCode() {
+            return lowerLimit ^ upperLimit;
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (!(other instanceof Limits)) {
+                return false;
+            }
+
+            return ((Limits) other).lowerLimit == lowerLimit &&
+                    ((Limits) other).upperLimit == upperLimit;
+        }
+
+        @Override
+        public String toString() {
+            return "(" + lowerLimit + ", " + upperLimit + ")";
+        }
+    }
+
+    /**
+     * The location of a coordinate relative to items. This class represents a general area of the
+     * view as it relates to band selection rather than an explicit point. For example, two
+     * different points within an item are considered to have the same "location" because band
+     * selection originating within the item would select the same items no matter which point
+     * was used. Same goes for points between items as well as those at the very beginning or end
+     * of the view.
+     *
+     * Tracking a coordinate (e.g., an x-value) as a CoordinateLocation instead of as an int has the
+     * advantage of tying the value to the Limits of items along that axis. This allows easy
+     * selection of items within those Limits as opposed to a search through every item to see if a
+     * given coordinate value falls within those Limits.
+     */
+    private static class RelativeCoordinate
+            implements Comparable<RelativeCoordinate> {
+        /**
+         * Location describing points after the last known item.
+         */
+        static final int AFTER_LAST_ITEM = 0;
+
+        /**
+         * Location describing points before the first known item.
+         */
+        static final int BEFORE_FIRST_ITEM = 1;
+
+        /**
+         * Location describing points between two items.
+         */
+        static final int BETWEEN_TWO_ITEMS = 2;
+
+        /**
+         * Location describing points within the limits of one item.
+         */
+        static final int WITHIN_LIMITS = 3;
+
+        /**
+         * The type of this coordinate, which is one of AFTER_LAST_ITEM, BEFORE_FIRST_ITEM,
+         * BETWEEN_TWO_ITEMS, or WITHIN_LIMITS.
+         */
+        final int type;
+
+        /**
+         * The limits before the coordinate; only populated when type == WITHIN_LIMITS or type ==
+         * BETWEEN_TWO_ITEMS.
+         */
+        Limits limitsBeforeCoordinate;
+
+        /**
+         * The limits after the coordinate; only populated when type == BETWEEN_TWO_ITEMS.
+         */
+        Limits limitsAfterCoordinate;
+
+        // Limits of the first known item; only populated when type == BEFORE_FIRST_ITEM.
+        Limits mFirstKnownItem;
+        // Limits of the last known item; only populated when type == AFTER_LAST_ITEM.
+        Limits mLastKnownItem;
+
+        /**
+         * @param limitsList The sorted limits list for the coordinate type. If this
+         *     CoordinateLocation is an x-value, mXLimitsList should be passed; otherwise,
+         *     mYLimitsList should be pased.
+         * @param value The coordinate value.
+         */
+        RelativeCoordinate(List<Limits> limitsList, int value) {
+            int index = Collections.binarySearch(limitsList, new Limits(value, value));
+
+            if (index >= 0) {
+                this.type = WITHIN_LIMITS;
+                this.limitsBeforeCoordinate = limitsList.get(index);
+            } else if (~index == 0) {
+                this.type = BEFORE_FIRST_ITEM;
+                this.mFirstKnownItem = limitsList.get(0);
+            } else if (~index == limitsList.size()) {
+                Limits lastLimits = limitsList.get(limitsList.size() - 1);
+                if (lastLimits.lowerLimit <= value && value <= lastLimits.upperLimit) {
+                    this.type = WITHIN_LIMITS;
+                    this.limitsBeforeCoordinate = lastLimits;
+                } else {
+                    this.type = AFTER_LAST_ITEM;
+                    this.mLastKnownItem = lastLimits;
+                }
+            } else {
+                Limits limitsBeforeIndex = limitsList.get(~index - 1);
+                if (limitsBeforeIndex.lowerLimit <= value
+                        && value <= limitsBeforeIndex.upperLimit) {
+                    this.type = WITHIN_LIMITS;
+                    this.limitsBeforeCoordinate = limitsList.get(~index - 1);
+                } else {
+                    this.type = BETWEEN_TWO_ITEMS;
+                    this.limitsBeforeCoordinate = limitsList.get(~index - 1);
+                    this.limitsAfterCoordinate = limitsList.get(~index);
+                }
+            }
+        }
+
+        int toComparisonValue() {
+            if (type == BEFORE_FIRST_ITEM) {
+                return mFirstKnownItem.lowerLimit - 1;
+            } else if (type == AFTER_LAST_ITEM) {
+                return mLastKnownItem.upperLimit + 1;
+            } else if (type == BETWEEN_TWO_ITEMS) {
+                return limitsBeforeCoordinate.upperLimit + 1;
+            } else {
+                return limitsBeforeCoordinate.lowerLimit;
+            }
+        }
+
+        @Override
+        public int hashCode() {
+            return mFirstKnownItem.lowerLimit
+                    ^ mLastKnownItem.upperLimit
+                    ^ limitsBeforeCoordinate.upperLimit
+                    ^ limitsBeforeCoordinate.lowerLimit;
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (!(other instanceof RelativeCoordinate)) {
+                return false;
+            }
+
+            RelativeCoordinate otherCoordinate = (RelativeCoordinate) other;
+            return toComparisonValue() == otherCoordinate.toComparisonValue();
+        }
+
+        @Override
+        public int compareTo(RelativeCoordinate other) {
+            return toComparisonValue() - other.toComparisonValue();
+        }
+    }
+
+    /**
+     * The location of a point relative to the Limits of nearby items; consists of both an x- and
+     * y-RelativeCoordinateLocation.
+     */
+    private class RelativePoint {
+        final RelativeCoordinate xLocation;
+        final RelativeCoordinate yLocation;
+
+        RelativePoint(Point point) {
+            this.xLocation = new RelativeCoordinate(mColumnBounds, point.x);
+            this.yLocation = new RelativeCoordinate(mRowBounds, point.y);
+        }
+
+        @Override
+        public int hashCode() {
+            return xLocation.toComparisonValue()
+                    ^ yLocation.toComparisonValue();
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (!(other instanceof RelativePoint)) {
+                return false;
+            }
+
+            RelativePoint otherPoint = (RelativePoint) other;
+            return xLocation.equals(otherPoint.xLocation) && yLocation.equals(otherPoint.yLocation);
+        }
+    }
+
+    /**
+     * Generates a rectangle which contains the items selected by the pointer and origin.
+     * @return The rectangle, or null if no items were selected.
+     */
+    private Rect computeBounds() {
+        Rect rect = new Rect();
+        rect.left = getCoordinateValue(
+                min(mRelativeOrigin.xLocation, mRelativePointer.xLocation),
+                mColumnBounds,
+                true);
+        rect.right = getCoordinateValue(
+                max(mRelativeOrigin.xLocation, mRelativePointer.xLocation),
+                mColumnBounds,
+                false);
+        rect.top = getCoordinateValue(
+                min(mRelativeOrigin.yLocation, mRelativePointer.yLocation),
+                mRowBounds,
+                true);
+        rect.bottom = getCoordinateValue(
+                max(mRelativeOrigin.yLocation, mRelativePointer.yLocation),
+                mRowBounds,
+                false);
+        return rect;
+    }
+
+    /**
+     * Computes the corner of the selection nearest the origin.
+     * @return
+     */
+    private int computeCornerNearestOrigin() {
+        int cornerValue = 0;
+
+        if (mRelativeOrigin.yLocation ==
+                min(mRelativeOrigin.yLocation, mRelativePointer.yLocation)) {
+            cornerValue |= UPPER;
+        } else {
+            cornerValue |= LOWER;
+        }
+
+        if (mRelativeOrigin.xLocation ==
+                min(mRelativeOrigin.xLocation, mRelativePointer.xLocation)) {
+            cornerValue |= LEFT;
+        } else {
+            cornerValue |= RIGHT;
+        }
+
+        return cornerValue;
+    }
+
+    private RelativeCoordinate min(RelativeCoordinate first, RelativeCoordinate second) {
+        return first.compareTo(second) < 0 ? first : second;
+    }
+
+    private RelativeCoordinate max(RelativeCoordinate first, RelativeCoordinate second) {
+        return first.compareTo(second) > 0 ? first : second;
+    }
+
+    /**
+     * @return The absolute coordinate (i.e., the x- or y-value) of the given relative
+     *     coordinate.
+     */
+    private int getCoordinateValue(
+            RelativeCoordinate coordinate, List<Limits> limitsList, boolean isStartOfRange) {
+
+        switch (coordinate.type) {
+            case RelativeCoordinate.BEFORE_FIRST_ITEM:
+                return limitsList.get(0).lowerLimit;
+            case RelativeCoordinate.AFTER_LAST_ITEM:
+                return limitsList.get(limitsList.size() - 1).upperLimit;
+            case RelativeCoordinate.BETWEEN_TWO_ITEMS:
+                if (isStartOfRange) {
+                    return coordinate.limitsAfterCoordinate.lowerLimit;
+                } else {
+                    return coordinate.limitsBeforeCoordinate.upperLimit;
+                }
+            case RelativeCoordinate.WITHIN_LIMITS:
+                return coordinate.limitsBeforeCoordinate.lowerLimit;
+        }
+
+        throw new RuntimeException("Invalid coordinate value.");
+    }
+
+    private boolean areItemsCoveredByBand(
+            RelativePoint first, RelativePoint second) {
+
+        return doesCoordinateLocationCoverItems(first.xLocation, second.xLocation) &&
+                doesCoordinateLocationCoverItems(first.yLocation, second.yLocation);
+    }
+
+    private boolean doesCoordinateLocationCoverItems(
+            RelativeCoordinate pointerCoordinate, RelativeCoordinate originCoordinate) {
+
+        if (pointerCoordinate.type == RelativeCoordinate.BEFORE_FIRST_ITEM &&
+                originCoordinate.type == RelativeCoordinate.BEFORE_FIRST_ITEM) {
+            return false;
+        }
+
+        if (pointerCoordinate.type == RelativeCoordinate.AFTER_LAST_ITEM &&
+                originCoordinate.type == RelativeCoordinate.AFTER_LAST_ITEM) {
+            return false;
+        }
+
+        if (pointerCoordinate.type == RelativeCoordinate.BETWEEN_TWO_ITEMS &&
+                originCoordinate.type == RelativeCoordinate.BETWEEN_TWO_ITEMS &&
+                pointerCoordinate.limitsBeforeCoordinate.equals(
+                        originCoordinate.limitsBeforeCoordinate) &&
+                pointerCoordinate.limitsAfterCoordinate.equals(
+                        originCoordinate.limitsAfterCoordinate)) {
+            return false;
+        }
+
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/documentsui/selection/ItemDetailsLookup.java b/src/com/android/documentsui/selection/ItemDetailsLookup.java
new file mode 100644
index 0000000..b56a2bc
--- /dev/null
+++ b/src/com/android/documentsui/selection/ItemDetailsLookup.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection;
+
+import android.support.v7.widget.RecyclerView;
+import android.view.MotionEvent;
+
+import javax.annotation.Nullable;
+
+/**
+ * Provides event handlers w/ access to details about documents details
+ * view items Documents in the UI (RecyclerView).
+ */
+public abstract class ItemDetailsLookup {
+
+    /** @return true if there is an item under the finger/cursor. */
+    public abstract boolean overItem(MotionEvent e);
+
+    /** @return true if there is an item w/ a stable ID under the finger/cursor. */
+    public abstract boolean overStableItem(MotionEvent e);
+
+    /**
+     * @return true if the event is over an area that can be dragged via touch
+     * or via mouse. List items have a white area that is not draggable.
+     */
+    public abstract boolean inItemDragRegion(MotionEvent e);
+
+    /**
+     * @return true if the event is in the "selection hot spot" region.
+     * The hot spot region instantly selects in touch mode, vs launches.
+     */
+    public abstract boolean inItemSelectRegion(MotionEvent e);
+
+    /**
+     * @return the adapter position of the item under the finger/cursor.
+     */
+    public abstract int getItemPosition(MotionEvent e);
+
+    /**
+     * @return the DocumentDetails for the item under the event, or null.
+     */
+    public abstract @Nullable ItemDetails getItemDetails(MotionEvent e);
+
+    /**
+     * Abstract class providing helper classes with access to information about
+     * RecyclerView item associated with a MotionEvent.
+     */
+    public static abstract class ItemDetails {
+
+        public boolean hasPosition() {
+            return getPosition() > RecyclerView.NO_POSITION;
+        }
+
+        public abstract int getPosition();
+
+        public boolean hasStableId() {
+            return getStableId() != null;
+        }
+
+        public abstract @Nullable String getStableId();
+
+        /**
+         * @return The view type of this ViewHolder.
+         */
+        public abstract int getItemViewType();
+
+        /**
+         * @return true if the event is in an area of the item that should be
+         * directly interpreted as a user wishing to select the item. This
+         * is useful for checkboxes and other UI affordances focused on enabling
+         * selection.
+         */
+        public boolean inSelectionHotspot(MotionEvent e) {
+            return false;
+        }
+
+        /**
+         * Events in the drag region will not be processed as selection events. This
+         * allows the client to implement custom handling for events related to drag
+         * and drop.
+         */
+        public boolean inDragRegion(MotionEvent e) {
+            return false;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof ItemDetails) {
+                return equals((ItemDetails) obj);
+            }
+            return false;
+        }
+
+        private boolean equals(ItemDetails other) {
+            return this.getPosition() == other.getPosition()
+                    && this.getStableId() == other.getStableId();
+        }
+
+        @Override
+        public int hashCode() {
+            return getPosition() >>> 8;
+        }
+    }
+}
diff --git a/src/com/android/documentsui/selection/MotionEvents.java b/src/com/android/documentsui/selection/MotionEvents.java
new file mode 100644
index 0000000..1915c5a
--- /dev/null
+++ b/src/com/android/documentsui/selection/MotionEvents.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection;
+
+import android.graphics.Point;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+/**
+ * Utility methods for working with {@link MotionEvent} instances.
+ */
+final class MotionEvents {
+
+    private MotionEvents() {}
+
+    static boolean isMouseEvent(MotionEvent e) {
+        return e.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE;
+    }
+
+    static boolean isTouchEvent(MotionEvent e) {
+        return e.getToolType(0) == MotionEvent.TOOL_TYPE_FINGER;
+    }
+
+    static boolean isActionMove(MotionEvent e) {
+        return e.getActionMasked() == MotionEvent.ACTION_MOVE;
+    }
+
+    static boolean isActionDown(MotionEvent e) {
+        return e.getActionMasked() == MotionEvent.ACTION_DOWN;
+    }
+
+    static boolean isActionUp(MotionEvent e) {
+        return e.getActionMasked() == MotionEvent.ACTION_UP;
+    }
+
+    static boolean isActionPointerUp(MotionEvent e) {
+        return e.getActionMasked() == MotionEvent.ACTION_POINTER_UP;
+    }
+
+    static boolean isActionPointerDown(MotionEvent e) {
+        return e.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN;
+    }
+
+    static boolean isActionCancel(MotionEvent e) {
+        return e.getActionMasked() == MotionEvent.ACTION_CANCEL;
+    }
+
+    static Point getOrigin(MotionEvent e) {
+        return new Point((int) e.getX(), (int) e.getY());
+    }
+
+    static boolean isPrimaryButtonPressed(MotionEvent e) {
+        return e.isButtonPressed(MotionEvent.BUTTON_PRIMARY);
+    }
+
+    public static boolean isSecondaryButtonPressed(MotionEvent e) {
+        return e.isButtonPressed(MotionEvent.BUTTON_SECONDARY);
+    }
+
+    public static boolean isTertiaryButtonPressed(MotionEvent e) {
+        return e.isButtonPressed(MotionEvent.BUTTON_TERTIARY);
+    }
+
+    static boolean isShiftKeyPressed(MotionEvent e) {
+        return hasBit(e.getMetaState(), KeyEvent.META_SHIFT_ON);
+    }
+
+    static boolean isCtrlKeyPressed(MotionEvent e) {
+        return hasBit(e.getMetaState(), KeyEvent.META_CTRL_ON);
+    }
+
+    static boolean isAltKeyPressed(MotionEvent e) {
+        return hasBit(e.getMetaState(), KeyEvent.META_ALT_ON);
+    }
+
+    public static boolean isTouchpadScroll(MotionEvent e) {
+        // Touchpad inputs are treated as mouse inputs, and when scrolling, there are no buttons
+        // returned.
+        return isMouseEvent(e) && isActionMove(e) && e.getButtonState() == 0;
+    }
+
+    private static boolean hasBit(int metaState, int bit) {
+        return (metaState & bit) != 0;
+    }
+}
diff --git a/src/com/android/documentsui/selection/MotionInputHandler.java b/src/com/android/documentsui/selection/MotionInputHandler.java
new file mode 100644
index 0000000..474e17d
--- /dev/null
+++ b/src/com/android/documentsui/selection/MotionInputHandler.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection;
+
+import static android.support.v4.util.Preconditions.checkArgument;
+
+import android.view.GestureDetector.SimpleOnGestureListener;
+import android.view.MotionEvent;
+
+import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
+
+/**
+ * Base class for handlers that can be registered w/ {@link GestureRouter}.
+ */
+public abstract class MotionInputHandler extends SimpleOnGestureListener {
+
+    protected final SelectionHelper mSelectionHelper;
+    protected final ItemDetailsLookup mDetailsLookup;
+
+    private final Callbacks mCallbacks;
+
+    public MotionInputHandler(
+            SelectionHelper selectionHelper,
+            ItemDetailsLookup detailsLookup,
+            Callbacks callbacks) {
+
+        checkArgument(selectionHelper != null);
+        checkArgument(detailsLookup != null);
+        checkArgument(callbacks != null);
+
+        mSelectionHelper = selectionHelper;
+        mDetailsLookup = detailsLookup;
+        mCallbacks = callbacks;
+    }
+
+    protected final boolean selectItem(ItemDetails details) {
+        checkArgument(details != null);
+        checkArgument(details.hasPosition());
+        checkArgument(details.hasStableId());
+
+        if (mSelectionHelper.select(details.getStableId())) {
+            mSelectionHelper.anchorRange(details.getPosition());
+        }
+
+        // we set the focus on this doc so it will be the origin for keyboard events or shift+clicks
+        // if there is only a single item selected, otherwise clear focus
+        if (mSelectionHelper.getSelection().size() == 1) {
+            mCallbacks.focusItem(details);
+        } else {
+            mCallbacks.clearFocus();
+        }
+        return true;
+    }
+
+    protected final boolean focusItem(ItemDetails details) {
+        checkArgument(details != null);
+        checkArgument(details.hasStableId());
+
+        mSelectionHelper.clearSelection();
+        mCallbacks.focusItem(details);
+        return true;
+    }
+
+    protected final void extendSelectionRange(ItemDetails details) {
+        checkArgument(details.hasPosition());
+        checkArgument(details.hasStableId());
+
+        mSelectionHelper.extendRange(details.getPosition());
+        mCallbacks.focusItem(details);
+    }
+
+    protected final boolean isRangeExtension(MotionEvent e) {
+        return MotionEvents.isShiftKeyPressed(e) && mSelectionHelper.isRangeActive();
+    }
+
+    protected boolean shouldClearSelection(MotionEvent e, ItemDetails item) {
+        return !MotionEvents.isCtrlKeyPressed(e)
+                && !item.inSelectionHotspot(e)
+                && !mSelectionHelper.isSelected(item.getStableId());
+    }
+
+    public static abstract class Callbacks {
+        public abstract void onPerformHapticFeedback();
+        public void focusItem(ItemDetails item) {}
+        public void clearFocus() {}
+    }
+}
diff --git a/src/com/android/documentsui/selection/MouseInputHandler.java b/src/com/android/documentsui/selection/MouseInputHandler.java
new file mode 100644
index 0000000..7ceb0f5
--- /dev/null
+++ b/src/com/android/documentsui/selection/MouseInputHandler.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection;
+
+import static com.android.documentsui.selection.Shared.DEBUG;
+import static com.android.documentsui.selection.Shared.VERBOSE;
+
+import android.util.Log;
+import android.view.MotionEvent;
+
+import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
+import com.android.internal.widget.RecyclerView;
+
+import javax.annotation.Nullable;
+
+/**
+ * A MotionInputHandler that provides the high-level glue for mouse/stylus driven selection. This
+ * class works with {@link RecyclerView}, {@link GestureRouter}, and {@link GestureSelectionHelper}
+ * to provide robust user drive selection support.
+ */
+public final class MouseInputHandler extends MotionInputHandler {
+
+        private static final String TAG = "MouseInputDelegate";
+
+        private final Callbacks mCallbacks;
+
+        // The event has been handled in onSingleTapUp
+        private boolean mHandledTapUp;
+        // true when the previous event has consumed a right click motion event
+        private boolean mHandledOnDown;
+
+        public MouseInputHandler(
+                SelectionHelper selectionHelper,
+                ItemDetailsLookup detailsLookup,
+                Callbacks callbacks) {
+
+            super(selectionHelper, detailsLookup, callbacks);
+
+            mCallbacks = callbacks;
+        }
+
+        @Override
+        public boolean onDown(MotionEvent e) {
+            if (VERBOSE) Log.v(TAG, "Delegated onDown event.");
+            if ((MotionEvents.isAltKeyPressed(e) && MotionEvents.isPrimaryButtonPressed(e))
+                    || MotionEvents.isSecondaryButtonPressed(e)) {
+                mHandledOnDown = true;
+                return onRightClick(e);
+            }
+
+            return false;
+        }
+
+        @Override
+        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
+            // Don't scroll content window in response to mouse drag
+            // If it's two-finger trackpad scrolling, we want to scroll
+            return !MotionEvents.isTouchpadScroll(e2);
+        }
+
+        @Override
+        public boolean onSingleTapUp(MotionEvent e) {
+            // See b/27377794. Since we don't get a button state back from UP events, we have to
+            // explicitly save this state to know whether something was previously handled by
+            // DOWN events or not.
+            if (mHandledOnDown) {
+                if (VERBOSE) Log.v(TAG, "Ignoring onSingleTapUp, previously handled in onDown.");
+                mHandledOnDown = false;
+                return false;
+            }
+
+            if (!mDetailsLookup.overStableItem(e)) {
+                if (DEBUG) Log.d(TAG, "Tap not associated w/ model item. Clearing selection.");
+                mSelectionHelper.clearSelection();
+                mCallbacks.clearFocus();
+                return false;
+            }
+
+            if (MotionEvents.isTertiaryButtonPressed(e)) {
+                if (DEBUG) Log.d(TAG, "Ignoring middle click");
+                return false;
+            }
+
+            ItemDetails item = mDetailsLookup.getItemDetails(e);
+            if (mSelectionHelper.hasSelection()) {
+                if (isRangeExtension(e)) {
+                    extendSelectionRange(item);
+                } else {
+                    if (shouldClearSelection(e, item)) {
+                        mSelectionHelper.clearSelection();
+                    }
+                    if (mSelectionHelper.isSelected(item.getStableId())) {
+                        if (mSelectionHelper.deselect(item.getStableId())) {
+                            mCallbacks.clearFocus();
+                        }
+                    } else {
+                        selectOrFocusItem(item, e);
+                    }
+                }
+                mHandledTapUp = true;
+                return true;
+            }
+
+            return false;
+        }
+
+        @Override
+        public boolean onSingleTapConfirmed(MotionEvent e) {
+            if (mHandledTapUp) {
+                if (VERBOSE) Log.v(TAG,
+                        "Ignoring onSingleTapConfirmed, previously handled in onSingleTapUp.");
+                mHandledTapUp = false;
+                return false;
+            }
+
+            if (mSelectionHelper.hasSelection()) {
+                return false;  // should have been handled by onSingleTapUp.
+            }
+
+            if (!mDetailsLookup.overItem(e)) {
+                if (DEBUG) Log.d(TAG, "Ignoring Confirmed Tap on non-item.");
+                return false;
+            }
+
+            if (MotionEvents.isTertiaryButtonPressed(e)) {
+                if (DEBUG) Log.d(TAG, "Ignoring middle click");
+                return false;
+            }
+
+            @Nullable ItemDetails item = mDetailsLookup.getItemDetails(e);
+            if (item == null || !item.hasStableId()) {
+                Log.w(TAG, "Ignoring Confirmed Tap. No document details associated w/ event.");
+                return false;
+            }
+
+            if (mCallbacks.hasFocusedItem() && MotionEvents.isShiftKeyPressed(e)) {
+                mSelectionHelper.startRange(mCallbacks.getFocusedPosition());
+                mSelectionHelper.extendRange(item.getPosition());
+            } else {
+                selectOrFocusItem(item, e);
+            }
+            return true;
+        }
+
+        @Override
+        public boolean onDoubleTap(MotionEvent e) {
+            mHandledTapUp = false;
+
+            if (!mDetailsLookup.overStableItem(e)) {
+                if (DEBUG) Log.d(TAG, "Ignoring DoubleTap on non-model-backed item.");
+                return false;
+            }
+
+            if (MotionEvents.isTertiaryButtonPressed(e)) {
+                if (DEBUG) Log.d(TAG, "Ignoring middle click");
+                return false;
+            }
+
+            @Nullable ItemDetails item = mDetailsLookup.getItemDetails(e);
+            if (item != null) {
+                return mCallbacks.onItemActivated(item, e);
+            }
+
+            return false;
+        }
+
+        private boolean onRightClick(MotionEvent e) {
+            if (mDetailsLookup.overStableItem(e)) {
+                @Nullable ItemDetails item = mDetailsLookup.getItemDetails(e);
+                if (item != null && !mSelectionHelper.isSelected(item.getStableId())) {
+                    mSelectionHelper.clearSelection();
+                    selectItem(item);
+                }
+            }
+
+            // We always delegate final handling of the event,
+            // since the handler might want to show a context menu
+            // in an empty area or some other weirdo view.
+            return mCallbacks.onContextClick(e);
+        }
+
+        private void selectOrFocusItem(ItemDetails item, MotionEvent e) {
+            if (item.inSelectionHotspot(e) || MotionEvents.isCtrlKeyPressed(e)) {
+                selectItem(item);
+            } else {
+                focusItem(item);
+            }
+        }
+
+        public static abstract class Callbacks extends MotionInputHandler.Callbacks {
+            public abstract boolean onItemActivated(ItemDetails item, MotionEvent e);
+            public boolean onContextClick(MotionEvent e) {
+                return false;
+            }
+            public boolean hasFocusedItem() {
+                return false;
+            }
+            public int getFocusedPosition() {
+                return RecyclerView.NO_POSITION;
+            }
+        }
+    }
\ No newline at end of file
diff --git a/src/com/android/documentsui/selection/MutableSelection.java b/src/com/android/documentsui/selection/MutableSelection.java
new file mode 100644
index 0000000..7939e14
--- /dev/null
+++ b/src/com/android/documentsui/selection/MutableSelection.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection;
+
+/**
+ * Subclass of Selection exposing public support for mutating the underlying selection data.
+ * This is useful for clients of {@link SelectionHelper} that wish to manipulate
+ * a copy of selection data obtained via {@link SelectionHelper#copySelection(Selection)}.
+ */
+public final class MutableSelection extends Selection {
+
+    @Override
+    public boolean add(String id) {
+        return super.add(id);
+    }
+
+    @Override
+    public boolean remove(String id) {
+        return super.remove(id);
+    }
+
+    @Override
+    public void clear() {
+        super.clear();
+    }
+}
diff --git a/src/com/android/documentsui/selection/Range.java b/src/com/android/documentsui/selection/Range.java
index c7db84c..efe49e9 100644
--- a/src/com/android/documentsui/selection/Range.java
+++ b/src/com/android/documentsui/selection/Range.java
@@ -15,36 +15,36 @@
  */
 package com.android.documentsui.selection;
 
-import static com.android.documentsui.base.Shared.DEBUG;
-import static com.android.documentsui.base.Shared.VERBOSE;
+import static android.support.v4.util.Preconditions.checkArgument;
+import static android.support.v7.widget.RecyclerView.NO_POSITION;
+import static com.android.documentsui.selection.Shared.DEBUG;
+import static com.android.documentsui.selection.Shared.TAG;
 
-import android.support.v7.widget.RecyclerView;
 import android.util.Log;
 
-import com.android.documentsui.selection.SelectionManager.RangeType;
+import com.android.documentsui.selection.DefaultSelectionHelper.RangeType;
 
 /**
  * Class providing support for managing range selections.
  */
 final class Range {
-    private static final int UNDEFINED = -1;
 
-    private final Range.RangeUpdater mUpdater;
+    private final Callbacks mCallbacks;
     private final int mBegin;
-    private int mEnd = UNDEFINED;
+    private int mEnd = NO_POSITION;
 
-    public Range(Range.RangeUpdater updater, int begin) {
-        if (DEBUG) Log.d(SelectionManager.TAG, "New Ranger created beginning @ " + begin);
-        mUpdater = updater;
+    public Range(Callbacks callbacks, int begin) {
+        if (DEBUG) Log.d(TAG, "New Ranger created beginning @ " + begin);
+        mCallbacks = callbacks;
         mBegin = begin;
     }
 
-    void snapSelection(int position, @RangeType int type) {
-        assert(position != RecyclerView.NO_POSITION);
+    void extendSelection(int position, @RangeType int type) {
+        checkArgument(position != NO_POSITION, "Position cannot be NO_POSITION.");
 
-        if (mEnd == UNDEFINED || mEnd == mBegin) {
+        if (mEnd == NO_POSITION || mEnd == mBegin) {
             // Reset mEnd so it can be established in establishRange.
-            mEnd = UNDEFINED;
+            mEnd = NO_POSITION;
             establishRange(position, type);
         } else {
             reviseRange(position, type);
@@ -52,7 +52,7 @@
     }
 
     private void establishRange(int position, @RangeType int type) {
-        assert(mEnd == UNDEFINED);
+        checkArgument(mEnd == NO_POSITION, "End has already been set.");
 
         if (position == mBegin) {
             mEnd = position;
@@ -68,11 +68,11 @@
     }
 
     private void reviseRange(int position, @RangeType int type) {
-        assert(mEnd != UNDEFINED);
-        assert(mBegin != mEnd);
+        checkArgument(mEnd != NO_POSITION, "End must already be set.");
+        checkArgument(mBegin != mEnd, "Beging and end point to same position.");
 
         if (position == mEnd) {
-            if (VERBOSE) Log.v(SelectionManager.TAG, "Ignoring no-op revision for range: " + this);
+            if (DEBUG) Log.v(TAG, "Ignoring no-op revision for range: " + this);
         }
 
         if (mEnd > mBegin) {
@@ -86,7 +86,7 @@
     }
 
     /**
-     * Updates an existing ascending seleciton.
+     * Updates an existing ascending selection.
      * @param position
      */
     private void reviseAscendingRange(int position, @RangeType int type) {
@@ -133,7 +133,7 @@
      * @param selected New selection state.
      */
     private void updateRange(int begin, int end, boolean selected, @RangeType int type) {
-        mUpdater.updateForRange(begin, end, selected, type);
+        mCallbacks.updateForRange(begin, end, selected, type);
     }
 
     @Override
@@ -142,11 +142,10 @@
     }
 
     /*
-     * @see {@link MultiSelectManager#updateForRegularRange(int, int , boolean)} and {@link
-     * MultiSelectManager#updateForProvisionalRange(int, int, boolean)}
+     * @see {@link DefaultSelectionHelper#updateForRange(int, int , boolean, int)}.
      */
-    @FunctionalInterface
-    interface RangeUpdater {
-        void updateForRange(int begin, int end, boolean selected, @RangeType int type);
+    static abstract class Callbacks {
+        abstract void updateForRange(
+                int begin, int end, boolean selected, @RangeType int type);
     }
 }
diff --git a/src/com/android/documentsui/selection/Selection.java b/src/com/android/documentsui/selection/Selection.java
index 8775c58..88b4cbb 100644
--- a/src/com/android/documentsui/selection/Selection.java
+++ b/src/com/android/documentsui/selection/Selection.java
@@ -15,6 +15,8 @@
  */
 package com.android.documentsui.selection;
 
+import static android.support.v4.util.Preconditions.checkArgument;
+
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.support.annotation.VisibleForTesting;
@@ -30,22 +32,29 @@
 import javax.annotation.Nullable;
 
 /**
- * Object representing the current selection. Provides read only access
- * public access, and private write access.
+ * Object representing the current selection and provisional selection. Provides read only public
+ * access, and private write access.
+ * <p>
+ * This class tracks selected items by managing two sets:
+ *
+ * <li>primary selection
+ *
+ * Primary selection consists of items tapped by a user or by lassoed by band select operation.
+ *
+ * <li>provisional selection
+ *
+ * Provisional selections are selections which have been temporarily created
+ * by an in-progress band select or gesture selection. Once the user releases the mouse button
+ * or lifts their finger the corresponding provisional selection should be converted into
+ * primary selection.
+ *
+ * <p>The total selection is the combination of
+ * both the core selection and the provisional selection. Tracking both separately is necessary to
+ * ensure that items in the core selection are not "erased" from the core selection when they
+ * are temporarily included in a secondary selection (like band selection).
  */
-public final class Selection implements Iterable<String>, Parcelable {
+public class Selection implements Iterable<String>, Parcelable {
 
-    // This class tracks selected items by managing two sets: the saved selection, and the total
-    // selection. Saved selections are those which have been completed by tapping an item or by
-    // completing a band select operation. Provisional selections are selections which have been
-    // temporarily created by an in-progress band select operation (once the user releases the
-    // mouse button during a band select operation, the selected items become saved). The total
-    // selection is the combination of both the saved selection and the provisional
-    // selection. Tracking both separately is necessary to ensure that saved selections do not
-    // become deselected when they are removed from the provisional selection; for example, if
-    // item A is tapped (and selected), then an in-progress band select covers A then uncovers
-    // A, A should still be selected as it has been saved. To ensure this behavior, the saved
-    // selection must be tracked separately.
     final Set<String> mSelection;
     final Set<String> mProvisionalSelection;
 
@@ -101,13 +110,12 @@
      * one (if it exists) is abandoned.
      * @return Map of ids added or removed. Added ids have a value of true, removed are false.
      */
-    @VisibleForTesting
-    protected Map<String, Boolean> setProvisionalSelection(Set<String> newSelection) {
+    Map<String, Boolean> setProvisionalSelection(Set<String> newSelection) {
         Map<String, Boolean> delta = new HashMap<>();
 
         for (String id: mProvisionalSelection) {
-            // Mark each item that used to be in the selection but is unsaved and not in the new
-            // provisional selection.
+            // Mark each item that used to be in the provisional selection
+            // but is not in the new provisional selection.
             if (!newSelection.contains(id) && !mSelection.contains(id)) {
                 delta.put(id, false);
             }
@@ -150,7 +158,7 @@
      * cause items in this existing provisional selection to become deselected.
      */
     @VisibleForTesting
-    protected void applyProvisionalSelection() {
+    protected void mergeProvisionalSelection() {
         mSelection.addAll(mProvisionalSelection);
         mProvisionalSelection.clear();
     }
@@ -160,42 +168,59 @@
      * now deselected.
      */
     @VisibleForTesting
-    void cancelProvisionalSelection() {
+    void clearProvisionalSelection() {
         mProvisionalSelection.clear();
     }
 
-    /** @hide */
-    @VisibleForTesting
-    public boolean add(String id) {
-        if (!mSelection.contains(id)) {
-            mSelection.add(id);
-            return true;
-        }
-        return false;
-    }
-
-    /** @hide */
-    @VisibleForTesting
-    boolean remove(String id) {
+    /**
+     * Adds a new item to the primary selection.
+     *
+     * @return true if the operation resulted in a modification to the selection.
+     */
+    boolean add(String id) {
         if (mSelection.contains(id)) {
-            mSelection.remove(id);
-            return true;
+            return false;
         }
-        return false;
+
+        mSelection.add(id);
+        return true;
     }
 
-    public void clear() {
+    /**
+     * Removes an item from the primary selection.
+     *
+     * @return true if the operation resulted in a modification to the selection.
+     */
+    boolean remove(String id) {
+        if (!mSelection.contains(id)) {
+            return false;
+        }
+
+        mSelection.remove(id);
+        return true;
+    }
+
+    /**
+     * Clears the primary selection. The provisional selection, if any, is unaffected.
+     */
+    void clear() {
         mSelection.clear();
     }
 
     /**
-     * Trims this selection to be the intersection of itself with the set of given IDs.
+     * Trims this selection to be the intersection of itself and {@code ids}.
      */
-    public void intersect(Collection<String> ids) {
+    void intersect(Collection<String> ids) {
+        checkArgument(ids != null);
+
         mSelection.retainAll(ids);
         mProvisionalSelection.retainAll(ids);
     }
 
+    /**
+     * Clones primary and provisional selection from supplied {@link Selection}.
+     * Does not copy active range data.
+     */
     @VisibleForTesting
     void copyFrom(Selection source) {
         mSelection.clear();
@@ -213,7 +238,7 @@
 
         StringBuilder buffer = new StringBuilder(size() * 28);
         buffer.append("Selection{")
-            .append("applied{size=" + mSelection.size())
+            .append("primary{size=" + mSelection.size())
             .append(", entries=" + mSelection)
             .append("}, provisional{size=" + mProvisionalSelection.size())
             .append(", entries=" + mProvisionalSelection)
@@ -227,17 +252,19 @@
     }
 
     @Override
-    public boolean equals(Object that) {
-      if (this == that) {
-          return true;
-      }
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
 
-      if (!(that instanceof Selection)) {
-          return false;
-      }
+        return other instanceof Selection
+            ? equals((Selection) other)
+            : false;
+    }
 
-      return mSelection.equals(((Selection) that).mSelection) &&
-              mProvisionalSelection.equals(((Selection) that).mProvisionalSelection);
+    private boolean equals(Selection other) {
+        return mSelection.equals(((Selection) other).mSelection) &&
+                mProvisionalSelection.equals(((Selection) other).mProvisionalSelection);
     }
 
     @Override
diff --git a/src/com/android/documentsui/selection/SelectionHelper.java b/src/com/android/documentsui/selection/SelectionHelper.java
new file mode 100644
index 0000000..bd8b34e
--- /dev/null
+++ b/src/com/android/documentsui/selection/SelectionHelper.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * SelectionManager provides support for managing selection within a RecyclerView instance.
+ *
+ * @see DefaultSelectionHelper for details on instantiation.
+ */
+public abstract class SelectionHelper {
+
+    /**
+     * This value is included in the payload when SelectionHelper implementations
+     * notify RecyclerView of changes. Clients can look for this in
+     * {@code onBindViewHolder} to know if the bind event is occurring in response
+     * to a selection state change.
+     */
+    public static final String SELECTION_CHANGED_MARKER = "Selection-Changed";
+
+    /**
+     * Adds {@code observe} to be notified when changes to selection occur.
+     *
+     * @param observer
+     */
+    public abstract void addObserver(SelectionObserver observer);
+
+    public abstract boolean hasSelection();
+
+    /**
+     * Returns a Selection object that provides a live view on the current selection.
+     *
+     * @see #copySelection(Selection) on how to get a snapshot
+     *     of the selection that will not reflect future changes
+     *     to selection.
+     *
+     * @return The current selection.
+     */
+    public abstract Selection getSelection();
+
+    /**
+     * Updates {@code dest} to reflect the current selection.
+     * @param dest
+     */
+    public abstract void copySelection(Selection dest);
+
+    /**
+     * @return true if the item specified by its id is selected. Shorthand for
+     * {@code getSelection().contains(String)}.
+     */
+    public abstract boolean isSelected(String id);
+
+    /**
+     * Restores the selected state of specified items. Used in cases such as restore the selection
+     * after rotation etc. Provisional selection, being provisional 'n all, isn't restored.
+     */
+    public abstract void restoreSelection(Selection other);
+
+    /**
+     * Sets the selected state of the specified items. Note that the callback will NOT
+     * be consulted to see if an item can be selected.
+     *
+     * @param ids
+     * @param selected
+     * @return
+     */
+    public abstract boolean setItemsSelected(Iterable<String> ids, boolean selected);
+
+    /**
+     * Clears the selection and notifies (if something changes).
+     */
+    public abstract void clearSelection();
+
+    /**
+     * Attempts to select an item.
+     *
+     * @return true if the item was selected. False if the item was not selected, or was
+     *         was already selected prior to the method being called.
+     */
+    public abstract boolean select(String itemId);
+
+    /**
+     * Attempts to deselect an item.
+     *
+     * @return true if the item was deselected. False if the item was not deselected, or was
+     *         was already deselected prior to the method being called.
+     */
+    public abstract boolean deselect(String itemId);
+
+    /**
+     * Starts a range selection. If a range selection is already active, this will start a new range
+     * selection (which will reset the range anchor).
+     *
+     * @param pos The anchor position for the selection range.
+     */
+    public abstract void startRange(int pos);
+
+    /**
+     * Sets the end point for the active range selection.
+     *
+     * <p>This function should only be called when a range selection is active
+     * (see {@link #isRangeActive()}. Items in the range [anchor, end] will be
+     * selected.
+     *
+     * @param pos The new end position for the selection range.
+     * @param type The type of selection the range should utilize.
+     *
+     * @throws IllegalStateException if a range selection is not active. Range selection
+     *         must have been started by a call to {@link #startRange(int)}.
+     */
+    public abstract void extendRange(int pos);
+
+    /**
+     * Stops an in-progress range selection. All selection done with
+     * {@link #extendProvisionalRange(int)} will be lost if
+     * {@link Selection#mergeProvisionalSelection()} is not called beforehand.
+     */
+    public abstract void endRange();
+
+    /**
+     * @return Whether or not there is a current range selection active.
+     */
+    public abstract boolean isRangeActive();
+
+    /**
+     * Sets the magic location at which a selection range begins (the selection anchor). This value
+     * is consulted when determining how to extend, and modify selection ranges. Calling this when a
+     * range selection is active will reset the range selection.
+     */
+    public abstract void anchorRange(int position);
+
+    /**
+     * @param pos
+     */
+    // TODO: This is smelly. Maybe this type of logic needs to move into range selection,
+    // then selection manager can have a startProvisionalRange and startRange. Or
+    // maybe ranges always start life as provisional.
+    public abstract void extendProvisionalRange(int pos);
+
+    /**
+     * @param newSelection
+     */
+    public abstract void setProvisionalSelection(Set<String> newSelection);
+
+    /**
+     *
+     */
+    public abstract void clearProvisionalSelection();
+
+    public abstract void mergeProvisionalSelection();
+
+    /**
+     * Observer interface providing access to information about Selection state changes.
+     */
+    public static abstract class SelectionObserver {
+
+        /**
+         * Called when state of an item has been changed.
+         */
+        public void onItemStateChanged(String id, boolean selected) {}
+
+        /**
+         * Called when the underlying data set has change. After this method is called
+         * the selection manager will attempt traverse the existing selection,
+         * calling {@link #onItemStateChanged(String, boolean)} for each selected item,
+         * and deselecting any items that cannot be selected given the updated dataset.
+         */
+        public void onSelectionReset() {}
+
+        /**
+         * Called immediately after completion of any set of changes, excluding
+         * those resulting in calls to {@link #onSelectionReset()} and
+         * {@link #onSelectionRestored()}.
+         */
+        public void onSelectionChanged() {}
+
+        /**
+         * Called immediately after selection is restored.
+         * {@link #onItemStateChanged(String, boolean)} will not be called
+         * for individual items in the selection.
+         */
+        public void onSelectionRestored() {}
+    }
+
+    /**
+     * Facilitates the use of stable ids.
+     */
+    public static abstract class StableIdProvider {
+        /**
+         * @return The model ID of the item at the given adapter position.
+         */
+        public abstract String getStableId(int position);
+
+        /**
+         * @return the position of a stable ID, or RecyclerView.NO_POSITION.
+         */
+        public abstract int getPosition(String id);
+
+        /**
+         * @return A list of all known stable IDs.
+         */
+        public abstract List<String> getStableIds();
+    }
+
+    /**
+     * Implement SelectionPredicate to control when items can be selected or unselected.
+     */
+    public static abstract class SelectionPredicate {
+
+        /** @return true if the item at {@code id} can be set to {@code nextState}. */
+        public abstract boolean canSetStateForId(String id, boolean nextState);
+
+        /** @return true if the item at {@code id} can be set to {@code nextState}. */
+        public abstract boolean canSetStateAtPosition(int position, boolean nextState);
+
+        /** @return true if more than a single item can be selected. */
+        public boolean canSelectMultiple() {
+            return true;
+        }
+    }
+}
diff --git a/src/com/android/documentsui/selection/SelectionManager.java b/src/com/android/documentsui/selection/SelectionManager.java
deleted file mode 100644
index af77cfa..0000000
--- a/src/com/android/documentsui/selection/SelectionManager.java
+++ /dev/null
@@ -1,574 +0,0 @@
-/*
- * 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.documentsui.selection;
-
-import static com.android.documentsui.base.Shared.DEBUG;
-
-import android.annotation.IntDef;
-import android.support.annotation.VisibleForTesting;
-import android.support.v7.widget.RecyclerView;
-import android.util.Log;
-
-import com.android.documentsui.dirlist.DocumentsAdapter;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.Nullable;
-
-/**
- * MultiSelectManager provides support traditional multi-item selection support to RecyclerView.
- * Additionally it can be configured to restrict selection to a single element, @see
- * #setSelectMode.
- */
-public final class SelectionManager {
-
-    @IntDef(flag = true, value = {
-            MODE_MULTIPLE,
-            MODE_SINGLE
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface SelectionMode {}
-    public static final int MODE_MULTIPLE = 0;
-    public static final int MODE_SINGLE = 1;
-
-    @IntDef({
-            RANGE_REGULAR,
-            RANGE_PROVISIONAL
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface RangeType {}
-    public static final int RANGE_REGULAR = 0;
-    public static final int RANGE_PROVISIONAL = 1;
-
-    static final String TAG = "SelectionManager";
-
-    private final Selection mSelection = new Selection();
-
-    private final List<Callback> mCallbacks = new ArrayList<>(1);
-    private final List<ItemCallback> mItemCallbacks = new ArrayList<>(1);
-
-    private @Nullable DocumentsAdapter mAdapter;
-    private @Nullable Range mRanger;
-    private boolean mSingleSelect;
-
-    private RecyclerView.AdapterDataObserver mAdapterObserver;
-    private SelectionPredicate mCanSetState;
-
-    public SelectionManager(@SelectionMode int mode) {
-        mSingleSelect = mode == MODE_SINGLE;
-    }
-
-    public SelectionManager reset(DocumentsAdapter adapter, SelectionPredicate canSetState) {
-
-        mCallbacks.clear();
-        mItemCallbacks.clear();
-        if (mAdapter != null && mAdapterObserver != null) {
-            mAdapter.unregisterAdapterDataObserver(mAdapterObserver);
-        }
-
-        clearSelectionQuietly();
-
-        assert(adapter != null);
-        assert(canSetState != null);
-
-        mAdapter = adapter;
-        mCanSetState = canSetState;
-
-        mAdapterObserver = new RecyclerView.AdapterDataObserver() {
-
-            private List<String> mModelIds;
-
-            @Override
-            public void onChanged() {
-                mModelIds = mAdapter.getModelIds();
-
-                // Update the selection to remove any disappeared IDs.
-                mSelection.cancelProvisionalSelection();
-                mSelection.intersect(mModelIds);
-
-                notifyDataChanged();
-            }
-
-            @Override
-            public void onItemRangeChanged(
-                    int startPosition, int itemCount, Object payload) {
-                // No change in position. Ignoring.
-            }
-
-            @Override
-            public void onItemRangeInserted(int startPosition, int itemCount) {
-                mSelection.cancelProvisionalSelection();
-            }
-
-            @Override
-            public void onItemRangeRemoved(int startPosition, int itemCount) {
-                assert(startPosition >= 0);
-                assert(itemCount > 0);
-
-                mSelection.cancelProvisionalSelection();
-                // Remove any disappeared IDs from the selection.
-                mSelection.intersect(mModelIds);
-            }
-
-            @Override
-            public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
-                throw new UnsupportedOperationException();
-            }
-        };
-
-        mAdapter.registerAdapterDataObserver(mAdapterObserver);
-        return this;
-    }
-
-    void bindContoller(BandController controller) {
-        // Provides BandController with access to private mSelection state.
-        controller.bindSelection(mSelection);
-    }
-
-    /**
-     * Adds {@code callback} such that it will be notified when {@code MultiSelectManager}
-     * events occur.
-     *
-     * @param callback
-     */
-    public void addCallback(Callback callback) {
-        assert(callback != null);
-        mCallbacks.add(callback);
-    }
-
-    public void addItemCallback(ItemCallback itemCallback) {
-        assert(itemCallback != null);
-        mItemCallbacks.add(itemCallback);
-    }
-
-    public boolean hasSelection() {
-        return !mSelection.isEmpty();
-    }
-
-    /**
-     * Returns a Selection object that provides a live view
-     * on the current selection.
-     *
-     * @see #getSelection(Selection) on how to get a snapshot
-     *     of the selection that will not reflect future changes
-     *     to selection.
-     *
-     * @return The current selection.
-     */
-    public Selection getSelection() {
-        return mSelection;
-    }
-
-    /**
-     * Updates {@code dest} to reflect the current selection.
-     * @param dest
-     *
-     * @return The Selection instance passed in, for convenience.
-     */
-    public Selection getSelection(Selection dest) {
-        dest.copyFrom(mSelection);
-        return dest;
-    }
-
-    @VisibleForTesting
-    public void replaceSelection(Iterable<String> ids) {
-        clearSelection();
-        setItemsSelected(ids, true);
-    }
-
-    /**
-     * Restores the selected state of specified items. Used in cases such as restore the selection
-     * after rotation etc.
-     */
-    public void restoreSelection(Selection other) {
-        setItemsSelectedQuietly(other.mSelection, true);
-        // NOTE: We intentionally don't restore provisional selection. It's provisional.
-        notifySelectionRestored();
-    }
-
-    /**
-     * Sets the selected state of the specified items. Note that the callback will NOT
-     * be consulted to see if an item can be selected.
-     *
-     * @param ids
-     * @param selected
-     * @return
-     */
-    public boolean setItemsSelected(Iterable<String> ids, boolean selected) {
-        final boolean changed = setItemsSelectedQuietly(ids, selected);
-        notifySelectionChanged();
-        return changed;
-    }
-
-    private boolean setItemsSelectedQuietly(Iterable<String> ids, boolean selected) {
-        boolean changed = false;
-        for (String id: ids) {
-            final boolean itemChanged =
-                    selected
-                    ? canSetState(id, true) && mSelection.add(id)
-                    : canSetState(id, false) && mSelection.remove(id);
-            if (itemChanged) {
-                notifyItemStateChanged(id, selected);
-            }
-            changed |= itemChanged;
-        }
-        return changed;
-    }
-
-    /**
-     * Clears the selection and notifies (if something changes).
-     */
-    public void clearSelection() {
-        if (!hasSelection()) {
-            return;
-        }
-
-        clearSelectionQuietly();
-        notifySelectionChanged();
-    }
-
-    /**
-     * Clears the selection, without notifying selection listeners. UI elements still need to be
-     * notified about state changes so that they can update their appearance.
-     */
-    private void clearSelectionQuietly() {
-        mRanger = null;
-
-        if (!hasSelection()) {
-            return;
-        }
-
-        Selection oldSelection = getSelection(new Selection());
-        mSelection.clear();
-
-        for (String id: oldSelection.mSelection) {
-            notifyItemStateChanged(id, false);
-        }
-        for (String id: oldSelection.mProvisionalSelection) {
-            notifyItemStateChanged(id, false);
-        }
-    }
-
-    /**
-     * Toggles selection on the item with the given model ID.
-     *
-     * @param modelId
-     */
-    public void toggleSelection(String modelId) {
-        assert(modelId != null);
-
-        final boolean changed = mSelection.contains(modelId)
-                ? attemptDeselect(modelId)
-                : attemptSelect(modelId);
-
-        if (changed) {
-            notifySelectionChanged();
-        }
-    }
-
-    /**
-     * Starts a range selection. If a range selection is already active, this will start a new range
-     * selection (which will reset the range anchor).
-     *
-     * @param pos The anchor position for the selection range.
-     */
-    public void startRangeSelection(int pos) {
-        attemptSelect(mAdapter.getModelId(pos));
-        setSelectionRangeBegin(pos);
-    }
-
-    public void snapRangeSelection(int pos) {
-        snapRangeSelection(pos, RANGE_REGULAR);
-    }
-
-    void snapProvisionalRangeSelection(int pos) {
-        snapRangeSelection(pos, RANGE_PROVISIONAL);
-    }
-
-    /*
-     * Starts and extends range selection in one go. This assumes item at startPos is not selected
-     * beforehand.
-     */
-    public void formNewSelectionRange(int startPos, int endPos) {
-        assert(!mSelection.contains(mAdapter.getModelId(startPos)));
-        startRangeSelection(startPos);
-        snapRangeSelection(endPos);
-    }
-
-    /**
-     * Sets the end point for the current range selection, started by a call to
-     * {@link #startRangeSelection(int)}. This function should only be called when a range selection
-     * is active (see {@link #isRangeSelectionActive()}. Items in the range [anchor, end] will be
-     * selected or in provisional select, depending on the type supplied. Note that if the type is
-     * provisional select, one should do {@link Selection#applyProvisionalSelection()} at some point
-     * before calling on {@link #endRangeSelection()}.
-     *
-     * @param pos The new end position for the selection range.
-     * @param type The type of selection the range should utilize.
-     */
-    private void snapRangeSelection(int pos, @RangeType int type) {
-        if (!isRangeSelectionActive()) {
-            throw new IllegalStateException("Range start point not set.");
-        }
-
-        mRanger.snapSelection(pos, type);
-
-        // We're being lazy here notifying even when something might not have changed.
-        // To make this more correct, we'd need to update the Ranger class to return
-        // information about what has changed.
-        notifySelectionChanged();
-    }
-
-    void cancelProvisionalSelection() {
-        for (String id : mSelection.mProvisionalSelection) {
-            notifyItemStateChanged(id, false);
-        }
-        mSelection.cancelProvisionalSelection();
-    }
-
-    /**
-     * Stops an in-progress range selection. All selection done with
-     * {@link #snapRangeSelection(int, int)} with type RANGE_PROVISIONAL will be lost if
-     * {@link Selection#applyProvisionalSelection()} is not called beforehand.
-     */
-    public void endRangeSelection() {
-        mRanger = null;
-        // Clean up in case there was any leftover provisional selection
-        cancelProvisionalSelection();
-    }
-
-    /**
-     * @return Whether or not there is a current range selection active.
-     */
-    public boolean isRangeSelectionActive() {
-        return mRanger != null;
-    }
-
-    /**
-     * Sets the magic location at which a selection range begins (the selection anchor). This value
-     * is consulted when determining how to extend, and modify selection ranges. Calling this when a
-     * range selection is active will reset the range selection.
-     */
-    public void setSelectionRangeBegin(int position) {
-        if (position == RecyclerView.NO_POSITION) {
-            return;
-        }
-
-        if (mSelection.contains(mAdapter.getModelId(position))) {
-            mRanger = new Range(this::updateForRange, position);
-        }
-    }
-
-    /**
-     * @param modelId
-     * @return True if the update was applied.
-     */
-    private boolean selectAndNotify(String modelId) {
-        boolean changed = mSelection.add(modelId);
-        if (changed) {
-            notifyItemStateChanged(modelId, true);
-        }
-        return changed;
-    }
-
-    /**
-     * @param id
-     * @return True if the update was applied.
-     */
-    private boolean attemptDeselect(String id) {
-        assert(id != null);
-        if (canSetState(id, false)) {
-            mSelection.remove(id);
-            notifyItemStateChanged(id, false);
-
-            // if there's nothing in the selection and there is an active ranger it results
-            // in unexpected behavior when the user tries to start range selection: the item
-            // which the ranger 'thinks' is the already selected anchor becomes unselectable
-            if (mSelection.isEmpty() && isRangeSelectionActive()) {
-                endRangeSelection();
-            }
-            if (DEBUG) Log.d(TAG, "Selection after deselect: " + mSelection);
-            return true;
-        } else {
-            if (DEBUG) Log.d(TAG, "Select cancelled by listener.");
-            return false;
-        }
-    }
-
-    /**
-     * @param id
-     * @return True if the update was applied.
-     */
-    private boolean attemptSelect(String id) {
-        assert(id != null);
-        boolean canSelect = canSetState(id, true);
-        if (!canSelect) {
-            return false;
-        }
-        if (mSingleSelect && hasSelection()) {
-            clearSelectionQuietly();
-        }
-
-        selectAndNotify(id);
-        return true;
-    }
-
-    boolean canSetState(String id, boolean nextState) {
-        return mCanSetState.test(id, nextState);
-    }
-
-    private void notifyDataChanged() {
-        final int lastListener = mItemCallbacks.size() - 1;
-
-        for (int i = lastListener; i >= 0; i--) {
-            mItemCallbacks.get(i).onSelectionReset();
-        }
-
-        for (String id : mSelection) {
-            if (!canSetState(id, true)) {
-                attemptDeselect(id);
-            } else {
-                for (int i = lastListener; i >= 0; i--) {
-                    mItemCallbacks.get(i).onItemStateChanged(id, true);
-                }
-            }
-        }
-    }
-
-    /**
-     * Notifies registered listeners when the selection status of a single item
-     * (identified by {@code position}) changes.
-     */
-    void notifyItemStateChanged(String id, boolean selected) {
-        assert(id != null);
-        int lastListener = mItemCallbacks.size() - 1;
-        for (int i = lastListener; i >= 0; i--) {
-            mItemCallbacks.get(i).onItemStateChanged(id, selected);
-        }
-        mAdapter.onItemSelectionChanged(id);
-    }
-
-    /**
-     * Notifies registered listeners when the selection has changed. This
-     * notification should be sent only once a full series of changes
-     * is complete, e.g. clearingSelection, or updating the single
-     * selection from one item to another.
-     */
-    void notifySelectionChanged() {
-        int lastListener = mCallbacks.size() - 1;
-        for (int i = lastListener; i > -1; i--) {
-            mCallbacks.get(i).onSelectionChanged();
-        }
-    }
-
-    private void notifySelectionRestored() {
-        int lastListener = mCallbacks.size() - 1;
-        for (int i = lastListener; i > -1; i--) {
-            mCallbacks.get(i).onSelectionRestored();
-        }
-    }
-
-    void updateForRange(int begin, int end, boolean selected, @RangeType int type) {
-        switch (type) {
-            case RANGE_REGULAR:
-                updateForRegularRange(begin, end, selected);
-                break;
-            case RANGE_PROVISIONAL:
-                updateForProvisionalRange(begin, end, selected);
-                break;
-            default:
-                throw new IllegalArgumentException("Invalid range type: " + type);
-        }
-    }
-
-    private void updateForRegularRange(int begin, int end, boolean selected) {
-        assert(end >= begin);
-        for (int i = begin; i <= end; i++) {
-            String id = mAdapter.getModelId(i);
-            if (id == null) {
-                continue;
-            }
-
-            if (selected) {
-                boolean canSelect = canSetState(id, true);
-                if (canSelect) {
-                    if (mSingleSelect && hasSelection()) {
-                        clearSelectionQuietly();
-                    }
-                    selectAndNotify(id);
-                }
-            } else {
-                attemptDeselect(id);
-            }
-        }
-    }
-
-    private void updateForProvisionalRange(int begin, int end, boolean selected) {
-        assert (end >= begin);
-        for (int i = begin; i <= end; i++) {
-            String id = mAdapter.getModelId(i);
-            if (id == null) {
-                continue;
-            }
-
-            boolean changedState = false;
-            if (selected) {
-                boolean canSelect = canSetState(id, true);
-                if (canSelect && !mSelection.mSelection.contains(id)) {
-                    mSelection.mProvisionalSelection.add(id);
-                    changedState = true;
-                }
-            } else {
-                mSelection.mProvisionalSelection.remove(id);
-                changedState = true;
-            }
-
-            // Only notify item callbacks when something's state is actually changed in provisional
-            // selection.
-            if (changedState) {
-                notifyItemStateChanged(id, selected);
-            }
-        }
-        notifySelectionChanged();
-    }
-
-    public interface ItemCallback {
-        void onItemStateChanged(String id, boolean selected);
-
-        void onSelectionReset();
-    }
-
-    public interface Callback {
-        /**
-         * Called immediately after completion of any set of changes.
-         */
-        void onSelectionChanged();
-
-        /**
-         * Called immediately after selection is restored.
-         */
-        void onSelectionRestored();
-    }
-
-    @FunctionalInterface
-    public interface SelectionPredicate {
-        boolean test(String id, boolean nextState);
-    }
-}
diff --git a/src/com/android/documentsui/selection/Shared.java b/src/com/android/documentsui/selection/Shared.java
new file mode 100644
index 0000000..bf30919
--- /dev/null
+++ b/src/com/android/documentsui/selection/Shared.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection;
+
+/**
+ * Shared constants used in this and descendant packages.
+ */
+public final class Shared {
+
+    public static final String TAG = "SelectionHelper";
+    public static final boolean DEBUG = false;
+    public static final boolean VERBOSE = false;
+
+    private Shared() {}
+}
diff --git a/src/com/android/documentsui/selection/ToolHandlerRegistry.java b/src/com/android/documentsui/selection/ToolHandlerRegistry.java
new file mode 100644
index 0000000..65f9f2e
--- /dev/null
+++ b/src/com/android/documentsui/selection/ToolHandlerRegistry.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 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.documentsui.selection;
+
+import static android.support.v4.util.Preconditions.checkArgument;
+import static android.support.v4.util.Preconditions.checkState;
+
+import android.support.annotation.Nullable;
+import android.view.MotionEvent;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Registry for tool specific event handler.
+ */
+final class ToolHandlerRegistry<T> {
+
+    // Currently there are four known input types. ERASER is the last one, so has the
+    // highest value. UNKNOWN is zero, so we add one. This allows delegates to be
+    // registered by type, and avoid the auto-boxing that would be necessary were we
+    // to store delegates in a Map<Integer, Delegate>.
+    private static final int sNumInputTypes = MotionEvent.TOOL_TYPE_ERASER + 1;
+
+    private final List<T> mHandlers = Arrays.asList(null, null, null, null, null);
+    private final T mDefault;
+
+    ToolHandlerRegistry(T defaultDelegate) {
+        checkArgument(defaultDelegate != null);
+        mDefault = defaultDelegate;
+
+        // Initialize all values to null.
+        for (int i = 0; i < sNumInputTypes; i++) {
+            mHandlers.set(i, null);
+        }
+    }
+
+    /**
+     * @param toolType
+     * @param delegate the delegate, or null to unregister.
+     * @throws IllegalStateException if an tooltype handler is already registered.
+     */
+    void set(int toolType, @Nullable T delegate) {
+        checkArgument(toolType >= 0 && toolType <= MotionEvent.TOOL_TYPE_ERASER);
+        checkState(mHandlers.get(toolType) == null);
+
+        mHandlers.set(toolType, delegate);
+    }
+
+    T get(MotionEvent e) {
+        T d = mHandlers.get(e.getToolType(0));
+        return d != null ? d : mDefault;
+    }
+}
diff --git a/src/com/android/documentsui/selection/TouchEventRouter.java b/src/com/android/documentsui/selection/TouchEventRouter.java
new file mode 100644
index 0000000..50585fe
--- /dev/null
+++ b/src/com/android/documentsui/selection/TouchEventRouter.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2016 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.documentsui.selection;
+
+import static android.support.v4.util.Preconditions.checkArgument;
+
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.OnItemTouchListener;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+
+/**
+ * A class responsible for routing MotionEvents to tool-type specific handlers,
+ * and if not handled by a handler, on to a {@link GestureDetector} for further
+ * processing.
+ *
+ * <p>TouchEventRouter takes its name from
+ * {@link RecyclerView#addOnItemTouchListener(OnItemTouchListener)}. Despite "Touch"
+ * being in the name, it receives MotionEvents for all types of tools.
+ */
+public final class TouchEventRouter implements OnItemTouchListener {
+
+    private final GestureDetector mDetector;
+    private final ToolHandlerRegistry<OnItemTouchListener> mDelegates;
+
+    public TouchEventRouter(GestureDetector detector, OnItemTouchListener defaultDelegate) {
+        checkArgument(detector != null);
+        checkArgument(defaultDelegate != null);
+
+        mDetector = detector;
+        mDelegates = new ToolHandlerRegistry<>(defaultDelegate);
+    }
+
+    public TouchEventRouter(GestureDetector detector) {
+        this(
+                detector,
+                // Default listener does nothing.
+                new OnItemTouchListener() {
+                    @Override
+                    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
+                        return false;
+                    }
+
+                    @Override
+                    public void onTouchEvent(RecyclerView rv, MotionEvent e) {
+                    }
+
+                    @Override
+                    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+                    }
+                });
+    }
+
+    /**
+     * @param toolType See MotionEvent for details on available types.
+     * @param delegate An {@link OnItemTouchListener} to receive events
+     *     of {@code toolType}.
+     */
+    public void register(int toolType, OnItemTouchListener delegate) {
+        checkArgument(delegate != null);
+        mDelegates.set(toolType, delegate);
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
+        boolean handled = mDelegates.get(e).onInterceptTouchEvent(rv, e);
+
+        // Forward all events to UserInputHandler.
+        // This is necessary since UserInputHandler needs to always see the first DOWN event. Or
+        // else all future UP events will be tossed.
+        handled |= mDetector.onTouchEvent(e);
+
+        return handled;
+    }
+
+    @Override
+    public void onTouchEvent(RecyclerView rv, MotionEvent e) {
+        mDelegates.get(e).onTouchEvent(rv, e);
+
+        // Note: even though this event is being handled as part of gestures such as drag and band,
+        // continue forwarding to the GestureDetector. The detector needs to see the entire cluster
+        // of events in order to properly interpret other gestures, such as long press.
+        mDetector.onTouchEvent(e);
+    }
+
+    @Override
+    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {}
+}
diff --git a/src/com/android/documentsui/selection/TouchInputHandler.java b/src/com/android/documentsui/selection/TouchInputHandler.java
new file mode 100644
index 0000000..298d54b
--- /dev/null
+++ b/src/com/android/documentsui/selection/TouchInputHandler.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection;
+
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
+
+import android.support.v7.widget.RecyclerView;
+import android.util.Log;
+import android.view.MotionEvent;
+
+import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
+import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
+
+/**
+ * A MotionInputHandler that provides the high-level glue for touch driven selection. This class
+ * works with {@link RecyclerView}, {@link GestureRouter}, and {@link GestureSelectionHelper} to
+ * provide robust user drive selection support.
+ */
+public final class TouchInputHandler extends MotionInputHandler {
+    private static final String TAG = "TouchInputDelegate";
+
+    private final SelectionPredicate mSelectionPredicate;
+    private final Callbacks mCallbacks;
+    private final Runnable mGestureKicker;
+
+    public TouchInputHandler(
+            SelectionHelper selectionHelper,
+            ItemDetailsLookup detailsLookup,
+            SelectionPredicate selectionPredicate,
+            Runnable gestureKicker,
+            Callbacks callbacks) {
+
+        super(selectionHelper, detailsLookup, callbacks);
+
+        mSelectionPredicate = selectionPredicate;
+        mGestureKicker = gestureKicker;
+        mCallbacks = callbacks;
+    }
+
+    public TouchInputHandler(
+            SelectionHelper selectionHelper,
+            ItemDetailsLookup detailsLookup,
+            SelectionPredicate selectionPredicate,
+            GestureSelectionHelper gestureHelper,
+            Callbacks callbacks) {
+
+        this(
+                selectionHelper,
+                detailsLookup,
+                selectionPredicate,
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        gestureHelper.start();
+                    }
+                },
+                callbacks);
+    }
+
+    @Override
+    public boolean onSingleTapUp(MotionEvent e) {
+        if (!mDetailsLookup.overStableItem(e)) {
+            if (DEBUG) Log.d(TAG, "Tap not associated w/ model item. Clearing selection.");
+            mSelectionHelper.clearSelection();
+            return false;
+        }
+
+        ItemDetails item = mDetailsLookup.getItemDetails(e);
+        if (mSelectionHelper.hasSelection()) {
+            if (isRangeExtension(e)) {
+                extendSelectionRange(item);
+            } else if (mSelectionHelper.isSelected(item.getStableId())) {
+                mSelectionHelper.deselect(item.getStableId());
+            } else {
+                selectItem(item);
+            }
+
+            return true;
+        }
+
+        // Touch events select if they occur in the selection hotspot,
+        // otherwise they activate.
+        return item.inSelectionHotspot(e)
+                ? selectItem(item)
+                : mCallbacks.onItemActivated(item, e);
+    }
+
+    @Override
+    public final void onLongPress(MotionEvent e) {
+        if (!mDetailsLookup.overStableItem(e)) {
+            if (DEBUG) Log.d(TAG, "Ignoring LongPress on non-model-backed item.");
+            return;
+        }
+
+        ItemDetails item = mDetailsLookup.getItemDetails(e);
+        boolean handled = false;
+
+        if (isRangeExtension(e)) {
+            extendSelectionRange(item);
+            handled = true;
+        } else {
+            if (!mSelectionHelper.isSelected(item.getStableId())
+                    && mSelectionPredicate.canSetStateForId(item.getStableId(), true)) {
+                // If we cannot select it, we didn't apply anchoring - therefore should not
+                // start gesture selection
+                if (selectItem(item)) {
+                    // And finally if the item was selected && we can select multiple
+                    // we kick off gesture selection.
+                    if (mSelectionPredicate.canSelectMultiple()) {
+                        mGestureKicker.run();
+                    }
+                    handled = true;
+                }
+            } else {
+                // We only initiate drag and drop on long press for touch to allow regular
+                // touch-based scrolling
+                // mTouchDragListener.accept(e);
+                mCallbacks.onDragInitiated(e);
+                handled = true;
+            }
+        }
+
+        if (handled) {
+            mCallbacks.onPerformHapticFeedback();
+        }
+    }
+
+    public static abstract class Callbacks extends MotionInputHandler.Callbacks {
+        public abstract boolean onItemActivated(ItemDetails item, MotionEvent e);
+        public boolean onDragInitiated(MotionEvent e) {
+            return false;
+        }
+    }
+}
diff --git a/src/com/android/documentsui/ui/ViewAutoScroller.java b/src/com/android/documentsui/selection/ViewAutoScroller.java
similarity index 74%
rename from src/com/android/documentsui/ui/ViewAutoScroller.java
rename to src/com/android/documentsui/selection/ViewAutoScroller.java
index 2add5ae..b77176c 100644
--- a/src/com/android/documentsui/ui/ViewAutoScroller.java
+++ b/src/com/android/documentsui/selection/ViewAutoScroller.java
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-
-package com.android.documentsui.ui;
+package com.android.documentsui.selection;
 
 import android.graphics.Point;
 
@@ -27,19 +26,20 @@
  * past top/bottom of the screen.
  */
 public final class ViewAutoScroller implements Runnable {
-    public static final int NOT_SET = -1;
+
     // ratio used to calculate the top/bottom hotspot region; used with view height
     public static final float TOP_BOTTOM_THRESHOLD_RATIO = 0.125f;
     public static final int MAX_SCROLL_STEP = 70;
 
-    // Top and bottom inner buffer such that user's cursor does not have to be exactly off screen
-    // for auto scrolling to begin
-    private final ScrollDistanceDelegate mCalcDelegate;
-    private final ScrollActionDelegate mUiDelegate;
+    private ScrollHost mHost;
+    private ScrollerCallbacks mCallbacks;
 
-    public ViewAutoScroller(ScrollDistanceDelegate calcDelegate, ScrollActionDelegate uiDelegate) {
-        mCalcDelegate = calcDelegate;
-        mUiDelegate = uiDelegate;
+    public ViewAutoScroller(ScrollHost scrollHost, ScrollerCallbacks callbacks) {
+        assert scrollHost != null;
+        assert callbacks != null;
+
+        mHost = scrollHost;
+        mCallbacks = callbacks;
     }
 
     /**
@@ -56,18 +56,18 @@
         // pointer are in these buffer pixels.
         int pixelsPastView = 0;
 
-        final int topBottomThreshold = (int) (mCalcDelegate.getViewHeight()
+        final int topBottomThreshold = (int) (mHost.getViewHeight()
                 * TOP_BOTTOM_THRESHOLD_RATIO);
 
-        if (mCalcDelegate.getCurrentPosition().y <= topBottomThreshold) {
-            pixelsPastView = mCalcDelegate.getCurrentPosition().y - topBottomThreshold;
-        } else if (mCalcDelegate.getCurrentPosition().y >= mCalcDelegate.getViewHeight()
+        if (mHost.getCurrentPosition().y <= topBottomThreshold) {
+            pixelsPastView = mHost.getCurrentPosition().y - topBottomThreshold;
+        } else if (mHost.getCurrentPosition().y >= mHost.getViewHeight()
                 - topBottomThreshold) {
-            pixelsPastView = mCalcDelegate.getCurrentPosition().y - mCalcDelegate.getViewHeight()
+            pixelsPastView = mHost.getCurrentPosition().y - mHost.getViewHeight()
                     + topBottomThreshold;
         }
 
-        if (!mCalcDelegate.isActive() || pixelsPastView == 0) {
+        if (!mHost.isActive() || pixelsPastView == 0) {
             // If the operation that started the scrolling is no longer inactive, or if it is active
             // but not at the edge of the view, no scrolling is necessary.
             return;
@@ -79,11 +79,11 @@
 
         // Compute the number of pixels to scroll, and scroll that many pixels.
         final int numPixels = computeScrollDistance(pixelsPastView);
-        mUiDelegate.scrollBy(numPixels);
+        mCallbacks.scrollBy(numPixels);
 
         // Remove callback to this, and then properly run at next frame again
-        mUiDelegate.removeCallback(this);
-        mUiDelegate.runAtNextFrame(this);
+        mCallbacks.removeCallback(this);
+        mCallbacks.runAtNextFrame(this);
     }
 
     /**
@@ -93,8 +93,8 @@
      * @return
      */
     public int computeScrollDistance(int pixelsPastView) {
-        final int topBottomThreshold = (int) (mCalcDelegate.getViewHeight()
-                * TOP_BOTTOM_THRESHOLD_RATIO);
+        final int topBottomThreshold =
+                (int) (mHost.getViewHeight() * TOP_BOTTOM_THRESHOLD_RATIO);
 
         final int direction = (int) Math.signum(pixelsPastView);
         final int absPastView = Math.abs(pixelsPastView);
@@ -131,18 +131,19 @@
      * Used by {@link run} to properly calculate the proper amount of pixels to scroll given time
      * passed since scroll started, and to properly scroll / proper listener clean up if necessary.
      */
-    public interface ScrollDistanceDelegate {
-        public Point getCurrentPosition();
-        public int getViewHeight();
-        public boolean isActive();
+    public static abstract class ScrollHost {
+        public abstract Point getCurrentPosition();
+        public abstract int getViewHeight();
+        public abstract boolean isActive();
     }
 
     /**
-     * Used by {@link run} to do UI tasks, such as scrolling and rerunning at next UI cycle.
+     * Callback used by scroller to perform UI tasks, such as scrolling and rerunning at next UI
+     * cycle.
      */
-    public interface ScrollActionDelegate {
-        public void scrollBy(int dy);
-        public void runAtNextFrame(Runnable r);
-        public void removeCallback(Runnable r);
+    public static abstract class ScrollerCallbacks {
+        public void scrollBy(int dy) {}
+        public void runAtNextFrame(Runnable r) {}
+        public void removeCallback(Runnable r) {}
     }
-}
\ No newline at end of file
+}
diff --git a/src/com/android/documentsui/selection/demo/DemoDetailsLookup.java b/src/com/android/documentsui/selection/demo/DemoDetailsLookup.java
new file mode 100644
index 0000000..6811125
--- /dev/null
+++ b/src/com/android/documentsui/selection/demo/DemoDetailsLookup.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection.demo;
+
+import android.support.annotation.Nullable;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.android.documentsui.selection.ItemDetailsLookup;
+
+/**
+ * Access to details of an item associated with a {@link MotionEvent} instance.
+ */
+final class DemoDetailsLookup extends ItemDetailsLookup {
+
+    private final RecyclerView mRecView;
+
+    public DemoDetailsLookup(RecyclerView view) {
+        mRecView = view;
+    }
+
+    @Override
+    public boolean overItem(MotionEvent e) {
+        return getItemPosition(e) != RecyclerView.NO_POSITION;
+    }
+
+    @Override
+    public boolean overStableItem(MotionEvent e) {
+        return overItem(e) && getItemDetails(e).hasStableId();
+    }
+
+    @Override
+    public boolean inItemDragRegion(MotionEvent e) {
+        return overItem(e) && getItemDetails(e).inDragRegion(e);
+    }
+
+    @Override
+    public boolean inItemSelectRegion(MotionEvent e) {
+        return overItem(e) && getItemDetails(e).inSelectionHotspot(e);
+    }
+
+    @Override
+    public int getItemPosition(MotionEvent e) {
+        View child = mRecView.findChildViewUnder(e.getX(), e.getY());
+        return (child != null)
+                ? mRecView.getChildAdapterPosition(child)
+                : RecyclerView.NO_POSITION;
+    }
+
+    @Override
+    public ItemDetails getItemDetails(MotionEvent e) {
+        @Nullable DemoHolder holder = getDemoHolder(e);
+        return holder == null ? null : holder.getItemDetails();
+    }
+
+    private @Nullable DemoHolder getDemoHolder(MotionEvent e) {
+        View childView = mRecView.findChildViewUnder(e.getX(), e.getY());
+        if (childView != null) {
+            ViewHolder holder = mRecView.getChildViewHolder(childView);
+            if (holder instanceof DemoHolder) {
+                return (DemoHolder) holder;
+            }
+        }
+        return null;
+    }
+}
diff --git a/src/com/android/documentsui/selection/demo/DemoHolder.java b/src/com/android/documentsui/selection/demo/DemoHolder.java
new file mode 100644
index 0000000..3a783b5
--- /dev/null
+++ b/src/com/android/documentsui/selection/demo/DemoHolder.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection.demo;
+
+import android.graphics.Rect;
+import android.support.v7.widget.RecyclerView;
+import android.view.MotionEvent;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.documentsui.R;
+import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
+
+public final class DemoHolder extends RecyclerView.ViewHolder {
+
+        private final LinearLayout mContainer;
+        public final TextView mSelector;
+        public final TextView mLabel;
+        private final Details mDetails;
+        private DemoItem mItem;
+
+        DemoHolder(LinearLayout layout) {
+            super(layout);
+            mContainer = layout.findViewById(R.id.container);
+            mSelector = layout.findViewById(R.id.selector);
+            mLabel = layout.findViewById(R.id.label);
+            mDetails = new Details(this);
+        }
+
+        public void update(DemoItem demoItem) {
+            mItem = demoItem;
+            mLabel.setText(mItem.getName());
+        }
+
+        void setSelected(boolean selected) {
+            mContainer.setActivated(selected);
+            mSelector.setActivated(selected);
+        }
+
+        public String getStableId() {
+            return mItem != null ? mItem.getId() : null;
+        }
+
+        public boolean inDragRegion(MotionEvent e) {
+            // If itemView is activated = selected, then whole region is interactive
+            if (mContainer.isActivated()) {
+                return true;
+            }
+
+            if (inSelectRegion(e)) {
+                return true;
+            }
+
+            Rect rect = new Rect();
+            mLabel.getPaint().getTextBounds(
+                    mLabel.getText().toString(), 0, mLabel.getText().length(), rect);
+
+            // If the tap occurred inside the text, these are interactive spots.
+            return rect.contains((int) e.getRawX(), (int) e.getRawY());
+        }
+
+        public boolean inSelectRegion(MotionEvent e) {
+            Rect iconRect = new Rect();
+            mSelector.getGlobalVisibleRect(iconRect);
+            return iconRect.contains((int) e.getRawX(), (int) e.getRawY());
+        }
+
+        Details getItemDetails() {
+            return mDetails;
+        }
+
+        private static final class Details extends ItemDetails {
+
+            private final DemoHolder mHolder;
+
+            Details(DemoHolder holder) {
+                mHolder = holder;
+            }
+
+            @Override
+            public int getPosition() {
+                return mHolder.getAdapterPosition();
+            }
+
+            @Override
+            public String getStableId() {
+                return mHolder.getStableId();
+            }
+
+            @Override
+            public int getItemViewType() {
+                return mHolder.getItemViewType();
+            }
+
+            @Override
+            public boolean inDragRegion(MotionEvent e) {
+                return mHolder.inDragRegion(e);
+            }
+
+            @Override
+            public boolean inSelectionHotspot(MotionEvent e) {
+                return mHolder.inSelectRegion(e);
+            }
+        }
+    }
\ No newline at end of file
diff --git a/src/com/android/documentsui/selection/demo/DemoItem.java b/src/com/android/documentsui/selection/demo/DemoItem.java
new file mode 100644
index 0000000..15755a0
--- /dev/null
+++ b/src/com/android/documentsui/selection/demo/DemoItem.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection.demo;
+
+public class DemoItem {
+
+    private final String mId;
+    private final String mName;
+
+    DemoItem(String id, String name) {
+        mId = id;
+        mName = name;
+    }
+
+    public String getId() {
+        return mId;
+    }
+
+    public String getName() {
+        return mName;
+    }
+}
diff --git a/src/com/android/documentsui/selection/demo/DemoStableIdProvider.java b/src/com/android/documentsui/selection/demo/DemoStableIdProvider.java
new file mode 100644
index 0000000..45cdd6c
--- /dev/null
+++ b/src/com/android/documentsui/selection/demo/DemoStableIdProvider.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection.demo;
+
+import static android.support.v4.util.Preconditions.checkArgument;
+
+import com.android.documentsui.selection.SelectionHelper.StableIdProvider;
+
+import java.util.List;
+
+/**
+ * Provides RecyclerView selection code access to stable ids backed
+ * by DocumentsAdapter.
+ */
+final class DemoStableIdProvider extends StableIdProvider {
+
+    private final SelectionDemoAdapter mAdapter;
+
+    public DemoStableIdProvider(SelectionDemoAdapter adapter) {
+        checkArgument(adapter != null);
+        mAdapter = adapter;
+    }
+
+    @Override
+    public String getStableId(int position) {
+        return mAdapter.getStableId(position);
+    }
+
+    @Override
+    public int getPosition(String id) {
+        return mAdapter.getPosition(id);
+    }
+
+    @Override
+    public List<String> getStableIds() {
+        return mAdapter.getStableIds();
+    }
+}
diff --git a/src/com/android/documentsui/selection/demo/SelectionDemoActivity.java b/src/com/android/documentsui/selection/demo/SelectionDemoActivity.java
new file mode 100644
index 0000000..6c20695
--- /dev/null
+++ b/src/com/android/documentsui/selection/demo/SelectionDemoActivity.java
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection.demo;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.support.annotation.CallSuper;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.Toolbar;
+import android.view.GestureDetector;
+import android.view.HapticFeedbackConstants;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.widget.Toast;
+
+import com.android.documentsui.R;
+import com.android.documentsui.selection.BandSelectionHelper;
+import com.android.documentsui.selection.ContentLock;
+import com.android.documentsui.selection.DefaultBandHost;
+import com.android.documentsui.selection.DefaultBandPredicate;
+import com.android.documentsui.selection.DefaultSelectionHelper;
+import com.android.documentsui.selection.GestureRouter;
+import com.android.documentsui.selection.GestureSelectionHelper;
+import com.android.documentsui.selection.ItemDetailsLookup;
+import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
+import com.android.documentsui.selection.MotionInputHandler;
+import com.android.documentsui.selection.MouseInputHandler;
+import com.android.documentsui.selection.MutableSelection;
+import com.android.documentsui.selection.Selection;
+import com.android.documentsui.selection.SelectionHelper;
+import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
+import com.android.documentsui.selection.SelectionHelper.StableIdProvider;
+import com.android.documentsui.selection.TouchEventRouter;
+import com.android.documentsui.selection.TouchInputHandler;
+import com.android.documentsui.selection.demo.SelectionDemoAdapter.OnBindCallback;
+
+/**
+ * ContentPager demo activity.
+ */
+public class SelectionDemoActivity extends AppCompatActivity {
+
+    private static final String EXTRA_SAVED_SELECTION = "demo-saved-selection";
+    private static final String EXTRA_COLUMN_COUNT = "demo-column-count";
+
+    private Toolbar mToolbar;
+    private SelectionDemoAdapter mAdapter;
+    private SelectionHelper mSelectionHelper;
+
+    private RecyclerView mRecView;
+    private GridLayoutManager mLayout;
+    private int mColumnCount = 1;  // This will get updated when layout changes.
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.selection_demo_layout);
+        mToolbar = findViewById(R.id.toolbar);
+        setSupportActionBar(mToolbar);
+        mRecView = (RecyclerView) findViewById(R.id.list);
+
+        mLayout = new GridLayoutManager(this, mColumnCount);
+        mRecView.setLayoutManager(mLayout);
+
+        mAdapter = new SelectionDemoAdapter(this);
+        mRecView.setAdapter(mAdapter);
+
+        StableIdProvider stableIds = new DemoStableIdProvider(mAdapter);
+
+        // SelectionPredicate permits client control of which items can be selected.
+        SelectionPredicate canSelectAnything = new SelectionPredicate() {
+            @Override
+            public boolean canSetStateForId(String id, boolean nextState) {
+                return true;
+            }
+
+            @Override
+            public boolean canSetStateAtPosition(int position, boolean nextState) {
+                return true;
+            }
+        };
+
+        // TODO: Reload content when it changes. Could use CursorLoader.
+        // TODO: Retain selection. Restore when content changes.
+
+        mSelectionHelper = new DefaultSelectionHelper(
+                DefaultSelectionHelper.MODE_MULTIPLE,
+                mAdapter,
+                stableIds,
+                canSelectAnything);
+
+        // onBind event callback that allows items to be updated to reflect
+        // selection status when bound by recycler view.
+        // This allows us to defer initialization of the SelectionHelper dependency
+        // which itself depends on the Adapter.
+        mAdapter.addOnBindCallback(
+                new OnBindCallback() {
+                    @Override
+                    void onBound(DemoHolder holder, int position) {
+                        String id = mAdapter.getStableId(position);
+                        holder.setSelected(mSelectionHelper.isSelected(id));
+                    }
+                });
+
+        ItemDetailsLookup detailsLookup = new DemoDetailsLookup(mRecView);
+
+        // Setup basic input handling, with the touch handler as the default consumer
+        // of events. If mouse handling is configured as well, the mouse input
+        // related handlers will intercept mouse input events.
+
+        // GestureRouter is responsible for routing GestureDetector events
+        // to tool-type specific handlers.
+        GestureRouter<MotionInputHandler> gestureRouter = new GestureRouter<>();
+        GestureDetector gestureDetector = new GestureDetector(this, gestureRouter);
+
+        // TouchEventRouter takes its name from RecyclerView#OnItemTouchListener.
+        // Despite "Touch" being in the name, it receives events for all types of tools.
+        // This class is responsible for routing events to tool-type specific handlers,
+        // and if not handled by a handler, on to a GestureDetector for analysis.
+        TouchEventRouter eventRouter = new TouchEventRouter(gestureDetector);
+
+        // Content lock provides a mechanism to block content reload while selection
+        // activities are active. If using a loader to load content, route
+        // the call through the content lock using ContentLock#runWhenUnlocked.
+        // This is especially useful when listening on content change notification.
+        ContentLock contentLock = new ContentLock();
+
+        // GestureSelectionHelper provides logic that interprets a combination
+        // of motions and gestures in order to provide gesture driven selection support
+        // when used in conjunction with RecyclerView.
+        GestureSelectionHelper gestureHelper = GestureSelectionHelper.create(
+                mSelectionHelper, mRecView, contentLock, detailsLookup);
+
+        // Finally hook the framework up to listening to recycle view events.
+        mRecView.addOnItemTouchListener(eventRouter);
+
+        // But before you move on, there's more work to do. Event plumbing has been
+        // installed, but we haven't registered any of our helpers or callbacks.
+        // Helpers contain predefined logic converting events into selection related events.
+        // Callbacks provide authors the ability to reponspond to other types of
+        // events (like "active" a tapped item). This is broken up into two main
+        // suites, one for "touch" and one for "mouse", though both can and should (usually)
+        // be configued to handle other types of input (to satisfy user expectation).
+
+        // TOUCH (+ UNKNOWN) handeling provides gesture based selection allowing
+        // the user to long press on an item, then drag her finger over other
+        // items in order to extend the selection.
+        TouchCallbacks touchCallbacks = new TouchCallbacks(this, mRecView);
+
+        // Provides high level glue for binding touch events and gestures to selection framework.
+        TouchInputHandler touchHandler = new TouchInputHandler(
+                mSelectionHelper, detailsLookup, canSelectAnything, gestureHelper, touchCallbacks);
+
+        eventRouter.register(MotionEvent.TOOL_TYPE_FINGER, gestureHelper);
+        eventRouter.register(MotionEvent.TOOL_TYPE_UNKNOWN, gestureHelper);
+
+        gestureRouter.register(MotionEvent.TOOL_TYPE_FINGER, touchHandler);
+        gestureRouter.register(MotionEvent.TOOL_TYPE_UNKNOWN, touchHandler);
+
+        // MOUSE (+ STYLUS) handeling provides band based selection allowing
+        // the user to click down in an empty area, then drag her mouse
+        // to create a band that covers the items she wants selected.
+        //
+        // PRO TIP: Don't skip installing mouse/stylus support. It provides
+        // improved productivity and demonstrates feature maturity that users
+        // will appreciate. See InputManager for details on more sophisticated
+        // strategies on detecting the presence of input tools.
+
+        // Provides high level glue for binding mouse/stylus events and gestures
+        // to selection framework.
+        MouseInputHandler mouseHandler = new MouseInputHandler(
+                mSelectionHelper, detailsLookup, new MouseCallbacks(this, mRecView));
+
+        DefaultBandHost host = new DefaultBandHost(
+                mRecView, R.drawable.selection_demo_band_overlay);
+
+        // BandSelectionHelper provides support for band selection on-top of a RecyclerView
+        // instance. Given the recycling nature of RecyclerView BandSelectionController
+        // necessarily models and caches list/grid information as the user's pointer
+        // interacts with the item in the RecyclerView. Selectable items that intersect
+        // with the band, both on and off screen, are selected.
+        BandSelectionHelper bandHelper = new BandSelectionHelper(
+                host,
+                mAdapter,
+                stableIds,
+                mSelectionHelper,
+                canSelectAnything,
+                new DefaultBandPredicate(detailsLookup),
+                contentLock);
+
+
+        eventRouter.register(MotionEvent.TOOL_TYPE_MOUSE, bandHelper);
+        eventRouter.register(MotionEvent.TOOL_TYPE_STYLUS, bandHelper);
+
+        gestureRouter.register(MotionEvent.TOOL_TYPE_MOUSE, mouseHandler);
+        gestureRouter.register(MotionEvent.TOOL_TYPE_STYLUS, mouseHandler);
+
+        // Aaaaan, all done with mouse/stylus selection setup!
+
+        updateFromSavedState(savedInstanceState);
+    }
+
+    @Override
+    protected void onSaveInstanceState(Bundle state) {
+        super.onSaveInstanceState(state);
+        MutableSelection selection = new MutableSelection();
+        mSelectionHelper.copySelection(selection);
+        state.putParcelable(EXTRA_SAVED_SELECTION, selection);
+        state.putInt(EXTRA_COLUMN_COUNT, mColumnCount);
+    }
+
+    private void updateFromSavedState(Bundle state) {
+        // In order to preserve selection across various lifecycle events be sure to save
+        // the selection in onSaveInstanceState, and to restore it when present in the Bundle
+        // pass in via onCreate(Bundle).
+        if (state != null) {
+            if (state.containsKey(EXTRA_SAVED_SELECTION)) {
+                Selection savedSelection = state.getParcelable(EXTRA_SAVED_SELECTION);
+                if (!savedSelection.isEmpty()) {
+                    mSelectionHelper.restoreSelection(savedSelection);
+                    CharSequence text = "Selection restored.";
+                    Toast.makeText(this, "Selection restored.", Toast.LENGTH_SHORT).show();
+                }
+            }
+            if (state.containsKey(EXTRA_COLUMN_COUNT)) {
+                mColumnCount = state.getInt(EXTRA_COLUMN_COUNT);
+                mLayout.setSpanCount(mColumnCount);
+            }
+        }
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        boolean showMenu = super.onCreateOptionsMenu(menu);
+        getMenuInflater().inflate(R.menu.selection_demo_actions, menu);
+        return showMenu;
+    }
+
+    @Override
+    @CallSuper
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        super.onPrepareOptionsMenu(menu);
+        menu.findItem(R.id.option_menu_add_column).setEnabled(mColumnCount <= 3);
+        menu.findItem(R.id.option_menu_remove_column).setEnabled(mColumnCount > 1);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.option_menu_add_column:
+                // TODO: Add columns
+                mLayout.setSpanCount(++mColumnCount);
+                return true;
+
+            case R.id.option_menu_remove_column:
+                mLayout.setSpanCount(--mColumnCount);
+                return true;
+            default:
+                return super.onOptionsItemSelected(item);
+        }
+    }
+
+
+    @Override
+    public void onBackPressed () {
+        if (mSelectionHelper.hasSelection()) {
+            mSelectionHelper.clearSelection();
+            mSelectionHelper.clearProvisionalSelection();
+        } else {
+            super.onBackPressed();
+        }
+    }
+
+    private static void toast(Context context, String msg) {
+        Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
+    }
+
+    @Override
+    protected void onDestroy() {
+        mSelectionHelper.clearSelection();
+        super.onDestroy();
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        mAdapter.loadData();
+    }
+
+    // Implementation of MouseInputHandler.Callbacks allows handling
+    // of higher level events, like onActivated.
+    private static final class MouseCallbacks extends MouseInputHandler.Callbacks {
+
+        private final Context mContext;
+        private final RecyclerView mRecView;
+
+        MouseCallbacks(Context context, RecyclerView recView) {
+            mContext = context;
+            mRecView = recView;
+        }
+
+        @Override
+        public boolean onItemActivated(ItemDetails item, MotionEvent e) {
+            toast(mContext, "Activate item: " + item.getStableId());
+            return true;
+        }
+
+        @Override
+        public boolean onContextClick(MotionEvent e) {
+            toast(mContext, "Context click received.");
+            return true;
+        }
+
+        @Override
+        public void onPerformHapticFeedback() {
+            mRecView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+        }
+    };
+
+    private static final class TouchCallbacks extends TouchInputHandler.Callbacks {
+
+        private final Context mContext;
+        private final RecyclerView mRecView;
+
+        private TouchCallbacks(Context context, RecyclerView recView) {
+
+            mContext = context;
+            mRecView = recView;
+        }
+
+        @Override
+        public boolean onItemActivated(ItemDetails item, MotionEvent e) {
+            toast(mContext, "Activate item: " + item.getStableId());
+            return true;
+        }
+
+        @Override
+        public void onPerformHapticFeedback() {
+            mRecView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/documentsui/selection/demo/SelectionDemoAdapter.java b/src/com/android/documentsui/selection/demo/SelectionDemoAdapter.java
new file mode 100644
index 0000000..b896e91
--- /dev/null
+++ b/src/com/android/documentsui/selection/demo/SelectionDemoAdapter.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection.demo;
+
+import android.content.Context;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+import com.android.documentsui.R;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+final class SelectionDemoAdapter extends RecyclerView.Adapter<DemoHolder> {
+
+    private static final Map<String, DemoItem> sDemoData = new HashMap<>();
+    static {
+        for (int i = 0; i < 1000; i++) {
+            String id = createId(i);
+            sDemoData.put(id, new DemoItem(id, "item" + i));
+        }
+    }
+
+    private final Context mContext;
+    private @Nullable OnBindCallback mBindCallback;
+
+    SelectionDemoAdapter(Context context) {
+        mContext = context;
+    }
+
+    void addOnBindCallback(OnBindCallback bindCallback) {
+        mBindCallback = bindCallback;
+    }
+
+    void loadData() {
+        onDataReady();
+    }
+
+    private void onDataReady() {
+        notifyDataSetChanged();
+    }
+
+    @Override
+    public int getItemCount() {
+        return sDemoData.size();
+    }
+
+    @Override
+    public void onBindViewHolder(DemoHolder holder, int position) {
+        String id = createId(position);
+        holder.update(sDemoData.get(id));
+        if (mBindCallback != null) {
+            mBindCallback.onBound(holder, position);
+        }
+    }
+
+    private static String createId(int position) {
+        return "id" + position;
+    }
+
+    @Override
+    public DemoHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        LinearLayout layout = inflateLayout(mContext, parent, R.layout.selection_demo_list_item);
+        return new DemoHolder(layout);
+    }
+
+    String getStableId(int position) {
+        return createId(position);
+    }
+
+    int getPosition(String id) {
+        return Integer.parseInt(id.substring(2));
+    }
+
+    List<String> getStableIds() {
+        return new ArrayList<>(sDemoData.keySet());
+    }
+
+    @SuppressWarnings("TypeParameterUnusedInFormals")  // Convenience to avoid clumsy cast.
+    private static <V extends View> V inflateLayout(
+            Context context, ViewGroup parent, int layout) {
+
+        return (V) LayoutInflater.from(context).inflate(layout, parent, false);
+    }
+
+    static abstract class OnBindCallback {
+        abstract void onBound(DemoHolder holder, int position);
+    }
+}
diff --git a/src/com/android/documentsui/services/CompressJob.java b/src/com/android/documentsui/services/CompressJob.java
index bf674c4..555149b 100644
--- a/src/com/android/documentsui/services/CompressJob.java
+++ b/src/com/android/documentsui/services/CompressJob.java
@@ -16,7 +16,7 @@
 
 package com.android.documentsui.services;
 
-import static com.android.documentsui.base.Shared.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
 import static com.android.documentsui.services.FileOperationService.OPERATION_MOVE;
 
 import android.app.Notification;
diff --git a/src/com/android/documentsui/services/CopyJob.java b/src/com/android/documentsui/services/CopyJob.java
index 678e6d2..b9934dc 100644
--- a/src/com/android/documentsui/services/CopyJob.java
+++ b/src/com/android/documentsui/services/CopyJob.java
@@ -25,7 +25,7 @@
 import static com.android.documentsui.OperationDialogFragment.DIALOG_TYPE_CONVERTED;
 import static com.android.documentsui.base.DocumentInfo.getCursorLong;
 import static com.android.documentsui.base.DocumentInfo.getCursorString;
-import static com.android.documentsui.base.Shared.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
 import static com.android.documentsui.services.FileOperationService.EXTRA_DIALOG_TYPE;
 import static com.android.documentsui.services.FileOperationService.EXTRA_FAILED_DOCS;
 import static com.android.documentsui.services.FileOperationService.EXTRA_OPERATION_TYPE;
@@ -44,17 +44,19 @@
 import android.database.ContentObserver;
 import android.database.Cursor;
 import android.net.Uri;
-import android.os.CancellationSignal;
+import android.os.FileUtils;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Messenger;
+import android.os.OperationCanceledException;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.storage.StorageManager;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
 import android.system.ErrnoException;
+import android.system.Int64Ref;
 import android.system.Os;
 import android.system.OsConstants;
 import android.text.format.DateUtils;
@@ -541,7 +543,6 @@
      */
     private void copyFileHelper(DocumentInfo src, DocumentInfo dest, DocumentInfo destParent,
             String mimeType) throws ResourceException {
-        CancellationSignal canceller = new CancellationSignal();
         AssetFileDescriptor srcFileAsAsset = null;
         ParcelFileDescriptor srcFile = null;
         ParcelFileDescriptor dstFile = null;
@@ -555,7 +556,7 @@
             if (src.isVirtual()) {
                 try {
                     srcFileAsAsset = getClient(src).openTypedAssetFileDescriptor(
-                                src.derivedUri, mimeType, null, canceller);
+                                src.derivedUri, mimeType, null, mSignal);
                 } catch (FileNotFoundException | RemoteException | RuntimeException e) {
                     Metrics.logFileOperationFailure(
                             appContext, Metrics.SUBFILEOP_OPEN_FILE, src.derivedUri);
@@ -576,7 +577,7 @@
                         appContext, operationType, Metrics.OPMODE_CONVERTED);
             } else {
                 try {
-                    srcFile = getClient(src).openFile(src.derivedUri, "r", canceller);
+                    srcFile = getClient(src).openFile(src.derivedUri, "r", mSignal);
                 } catch (FileNotFoundException | RemoteException | RuntimeException e) {
                     Metrics.logFileOperationFailure(
                             appContext, Metrics.SUBFILEOP_OPEN_FILE, src.derivedUri);
@@ -590,7 +591,7 @@
             }
 
             try {
-                dstFile = getClient(dest).openFile(dest.derivedUri, "w", canceller);
+                dstFile = getClient(dest).openFile(dest.derivedUri, "w", mSignal);
             } catch (FileNotFoundException | RemoteException | RuntimeException e) {
                 Metrics.logFileOperationFailure(
                         appContext, Metrics.SUBFILEOP_OPEN_FILE, dest.derivedUri);
@@ -599,9 +600,6 @@
             }
             out = new ParcelFileDescriptor.AutoCloseOutputStream(dstFile);
 
-            byte[] buffer = new byte[32 * 1024];
-            int len;
-            boolean reading = true;
             try {
                 // If we know the source size, and the destination supports disk
                 // space allocation, then allocate the space we'll need. This
@@ -614,18 +612,18 @@
                     sm.allocateBytes(dstFd, srcSize);
                 }
 
-                while ((len = in.read(buffer)) != -1) {
-                    if (isCanceled()) {
-                        if (DEBUG) Log.d(TAG, "Canceled copy mid-copy of: " + src.derivedUri);
-                        return;
-                    }
-                    reading = false;
-                    out.write(buffer, 0, len);
-                    makeCopyProgress(len);
-                    reading = true;
+                try {
+                    final Int64Ref last = new Int64Ref(0);
+                    FileUtils.copy(in, out, (long progress) -> {
+                        final long delta = progress - last.value;
+                        last.value = progress;
+                        makeCopyProgress(delta);
+                    }, mSignal);
+                } catch (OperationCanceledException e) {
+                    if (DEBUG) Log.d(TAG, "Canceled copy mid-copy of: " + src.derivedUri);
+                    return;
                 }
 
-                reading = false;
                 // Need to invoke Os#fsync to ensure the file is written to the storage device.
                 try {
                     Os.fsync(dstFile.getFileDescriptor());
@@ -643,8 +641,8 @@
             } catch (IOException e) {
                 Metrics.logFileOperationFailure(
                         appContext,
-                        reading ? Metrics.SUBFILEOP_READ_FILE : Metrics.SUBFILEOP_WRITE_FILE,
-                        reading ? src.derivedUri: dest.derivedUri);
+                        Metrics.SUBFILEOP_WRITE_FILE,
+                        dest.derivedUri);
                 throw new ResourceException(
                         "Failed to copy bytes from %s to %s due to an IO exception.",
                         src.derivedUri, dest.derivedUri, e);
@@ -666,7 +664,7 @@
                 }
 
                 if (DEBUG) Log.d(TAG, "Cleaning up failed operation leftovers.");
-                canceller.cancel();
+                mSignal.cancel();
                 try {
                     deleteDocument(dest, destParent);
                 } catch (ResourceException e) {
@@ -765,9 +763,7 @@
      */
     private Cursor queryChildren(DocumentInfo srcDir, String[] queryColumns)
             throws RemoteException {
-        try (final ContentProviderClient client = getClient(srcDir)) {
-            return queryChildren(client, srcDir.derivedUri, queryColumns);
-        }
+        return queryChildren(getClient(srcDir), srcDir.derivedUri, queryColumns);
     }
 
     /**
diff --git a/src/com/android/documentsui/services/DeleteJob.java b/src/com/android/documentsui/services/DeleteJob.java
index 8abacda..041eba7 100644
--- a/src/com/android/documentsui/services/DeleteJob.java
+++ b/src/com/android/documentsui/services/DeleteJob.java
@@ -16,7 +16,7 @@
 
 package com.android.documentsui.services;
 
-import static com.android.documentsui.base.Shared.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
 import static com.android.documentsui.services.FileOperationService.OPERATION_DELETE;
 
 import android.app.Notification;
diff --git a/src/com/android/documentsui/services/FileOperation.java b/src/com/android/documentsui/services/FileOperation.java
index 2ee12d5..1f0e9b9 100644
--- a/src/com/android/documentsui/services/FileOperation.java
+++ b/src/com/android/documentsui/services/FileOperation.java
@@ -16,12 +16,13 @@
 
 package com.android.documentsui.services;
 
-import static com.android.documentsui.services.FileOperationService.OPERATION_COPY;
 import static com.android.documentsui.services.FileOperationService.OPERATION_COMPRESS;
-import static com.android.documentsui.services.FileOperationService.OPERATION_EXTRACT;
+import static com.android.documentsui.services.FileOperationService.OPERATION_COPY;
 import static com.android.documentsui.services.FileOperationService.OPERATION_DELETE;
+import static com.android.documentsui.services.FileOperationService.OPERATION_EXTRACT;
 import static com.android.documentsui.services.FileOperationService.OPERATION_MOVE;
 import static com.android.documentsui.services.FileOperationService.OPERATION_UNKNOWN;
+import static com.android.internal.util.Preconditions.checkArgument;
 
 import android.content.Context;
 import android.net.Uri;
@@ -57,8 +58,8 @@
 
     @VisibleForTesting
     FileOperation(@OpType int opType, UrisSupplier srcs, DocumentStack destination) {
-        assert(opType != OPERATION_UNKNOWN);
-        assert(srcs.getItemCount() > 0);
+        checkArgument(opType != OPERATION_UNKNOWN);
+        checkArgument(srcs.getItemCount() > 0);
 
         mOpType = opType;
         mSrcs = srcs;
@@ -133,6 +134,7 @@
             return builder.toString();
         }
 
+        @Override
         CopyJob createJob(Context service, Job.Listener listener, String id, Features features) {
             return new CopyJob(
                     service, listener, id, getDestination(), getSrc(), getMessenger(), features);
@@ -173,6 +175,7 @@
             return builder.toString();
         }
 
+        @Override
         CopyJob createJob(Context service, Job.Listener listener, String id, Features features) {
             return new CompressJob(service, listener, id, getDestination(), getSrc(),
                     getMessenger(), features);
@@ -214,6 +217,7 @@
         }
 
         // TODO: Replace CopyJob with ExtractJob.
+        @Override
         CopyJob createJob(Context service, Job.Listener listener, String id, Features features) {
             return new CopyJob(
                     service, listener, id, getDestination(), getSrc(), getMessenger(), features);
diff --git a/src/com/android/documentsui/services/FileOperationService.java b/src/com/android/documentsui/services/FileOperationService.java
index 6379237..40f18d3 100644
--- a/src/com/android/documentsui/services/FileOperationService.java
+++ b/src/com/android/documentsui/services/FileOperationService.java
@@ -16,7 +16,7 @@
 
 package com.android.documentsui.services;
 
-import static com.android.documentsui.base.Shared.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
 
 import android.annotation.IntDef;
 import android.app.Notification;
@@ -354,7 +354,7 @@
                 job.id, NOTIFICATION_ID_PROGRESS, notification);
 
         // Set up related monitor
-        JobMonitor monitor = new JobMonitor(job, notificationManager, handler);
+        JobMonitor monitor = new JobMonitor(job, notificationManager, handler, mJobs);
         monitor.start();
     }
 
@@ -458,11 +458,14 @@
         private final Job mJob;
         private final NotificationManager mNotificationManager;
         private final Handler mHandler;
+        private final Object mJobsLock;
 
-        private JobMonitor(Job job, NotificationManager notificationManager, Handler handler) {
+        private JobMonitor(Job job, NotificationManager notificationManager, Handler handler,
+                Object jobsLock) {
             mJob = job;
             mNotificationManager = notificationManager;
             mHandler = handler;
+            mJobsLock = jobsLock;
         }
 
         private void start() {
@@ -471,19 +474,21 @@
 
         @Override
         public void run() {
-            if (mJob.isFinished()) {
-                // Finish notification is already shown. Progress notification is removed.
-                // Just finish itself.
-                return;
-            }
+            synchronized (mJobsLock) {
+                if (mJob.isFinished()) {
+                    // Finish notification is already shown. Progress notification is removed.
+                    // Just finish itself.
+                    return;
+                }
 
-            // Only job in set up state has progress bar
-            if (mJob.getState() == Job.STATE_SET_UP) {
-                mNotificationManager.notify(
-                        mJob.id, NOTIFICATION_ID_PROGRESS, mJob.getProgressNotification());
-            }
+                // Only job in set up state has progress bar
+                if (mJob.getState() == Job.STATE_SET_UP) {
+                    mNotificationManager.notify(
+                            mJob.id, NOTIFICATION_ID_PROGRESS, mJob.getProgressNotification());
+                }
 
-            mHandler.postDelayed(this, PROGRESS_INTERVAL_MILLIS);
+                mHandler.postDelayed(this, PROGRESS_INTERVAL_MILLIS);
+            }
         }
     }
 
diff --git a/src/com/android/documentsui/services/FileOperations.java b/src/com/android/documentsui/services/FileOperations.java
index d699ed0..d35b237 100644
--- a/src/com/android/documentsui/services/FileOperations.java
+++ b/src/com/android/documentsui/services/FileOperations.java
@@ -17,7 +17,7 @@
 package com.android.documentsui.services;
 
 import static android.os.SystemClock.elapsedRealtime;
-import static com.android.documentsui.base.Shared.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
 import static com.android.documentsui.services.FileOperationService.EXTRA_CANCEL;
 import static com.android.documentsui.services.FileOperationService.EXTRA_JOB_ID;
 import static com.android.documentsui.services.FileOperationService.EXTRA_OPERATION;
diff --git a/src/com/android/documentsui/services/Job.java b/src/com/android/documentsui/services/Job.java
index 25ed4de..67b8df3 100644
--- a/src/com/android/documentsui/services/Job.java
+++ b/src/com/android/documentsui/services/Job.java
@@ -36,6 +36,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
+import android.os.CancellationSignal;
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.provider.DocumentsContract;
@@ -101,6 +102,8 @@
 
     final Notification.Builder mProgressBuilder;
 
+    final CancellationSignal mSignal = new CancellationSignal();
+
     private final Map<String, ContentProviderClient> mClients = new HashMap<>();
     private final Features mFeatures;
 
@@ -172,8 +175,7 @@
         return true;
     }
 
-    void finish() {
-    }
+    abstract void finish();
 
     abstract void start();
     abstract Notification getSetupNotification();
@@ -217,6 +219,7 @@
 
     final void cancel() {
         mState = STATE_CANCELED;
+        mSignal.cancel();
         Metrics.logFileOperationCancelled(service, operationType);
     }
 
diff --git a/src/com/android/documentsui/services/MoveJob.java b/src/com/android/documentsui/services/MoveJob.java
index cf8bb3c..c46f39b 100644
--- a/src/com/android/documentsui/services/MoveJob.java
+++ b/src/com/android/documentsui/services/MoveJob.java
@@ -16,7 +16,7 @@
 
 package com.android.documentsui.services;
 
-import static com.android.documentsui.base.Shared.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
 import static com.android.documentsui.services.FileOperationService.OPERATION_MOVE;
 
 import android.app.Notification;
diff --git a/src/com/android/documentsui/sidebar/RootsFragment.java b/src/com/android/documentsui/sidebar/RootsFragment.java
index 0fa3d85..db8d0e8 100644
--- a/src/com/android/documentsui/sidebar/RootsFragment.java
+++ b/src/com/android/documentsui/sidebar/RootsFragment.java
@@ -16,8 +16,8 @@
 
 package com.android.documentsui.sidebar;
 
-import static com.android.documentsui.base.Shared.DEBUG;
-import static com.android.documentsui.base.Shared.VERBOSE;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.VERBOSE;
 
 import android.annotation.Nullable;
 import android.app.Activity;
diff --git a/src/com/android/documentsui/sidebar/SpacerItem.java b/src/com/android/documentsui/sidebar/SpacerItem.java
index 56eecb1..89cea1a 100644
--- a/src/com/android/documentsui/sidebar/SpacerItem.java
+++ b/src/com/android/documentsui/sidebar/SpacerItem.java
@@ -16,7 +16,7 @@
 
 package com.android.documentsui.sidebar;
 
-import static com.android.documentsui.base.Shared.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
 
 import android.util.Log;
 import android.view.View;
diff --git a/src/com/android/documentsui/sorting/SortModel.java b/src/com/android/documentsui/sorting/SortModel.java
index 9dc0784..311e89f 100644
--- a/src/com/android/documentsui/sorting/SortModel.java
+++ b/src/com/android/documentsui/sorting/SortModel.java
@@ -16,7 +16,7 @@
 
 package com.android.documentsui.sorting;
 
-import static com.android.documentsui.base.Shared.DEBUG;
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
 
 import android.annotation.IntDef;
 import android.annotation.Nullable;
diff --git a/src/com/android/documentsui/ui/Snackbars.java b/src/com/android/documentsui/ui/Snackbars.java
index 8fa84dc..933af97 100644
--- a/src/com/android/documentsui/ui/Snackbars.java
+++ b/src/com/android/documentsui/ui/Snackbars.java
@@ -76,7 +76,7 @@
 
         //Document Inspector uses a different view from other files app activities.
         final View view = activity.findViewById(R.id.fragment_container);
-        Snackbar.make(view, R.string.file_inspector_load_error, Snackbar.LENGTH_INDEFINITE).show();
+        Snackbar.make(view, R.string.inspector_load_error, Snackbar.LENGTH_INDEFINITE).show();
     }
 
     public static final void showCustomTextWithImage(Activity activity, String text, int imageRes) {
diff --git a/tests/Android.mk b/tests/Android.mk
index 4d72ba6..143e685 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -12,13 +12,12 @@
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 LOCAL_AAPT_FLAGS += -0 .zip
 
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base android.test.mock
 LOCAL_STATIC_JAVA_LIBRARIES := \
     mockito-target \
     ub-uiautomator \
     espresso-core \
-    guava \
-    legacy-android-test
+    guava
 LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
 LOCAL_PACKAGE_NAME := DocumentsUITests
 LOCAL_PRIVATE_PLATFORM_APIS := true
diff --git a/tests/AndroidTest.xml b/tests/AndroidTest.xml
index a051df2..07968ae 100644
--- a/tests/AndroidTest.xml
+++ b/tests/AndroidTest.xml
@@ -23,5 +23,6 @@
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.documentsui.tests" />
         <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+        <option name="hidden-api-checks" value="false"/>
     </test>
 </configuration>
diff --git a/tests/common/com/android/documentsui/DemoProvider.java b/tests/common/com/android/documentsui/DemoProvider.java
index ff12f1d..6d1a364 100644
--- a/tests/common/com/android/documentsui/DemoProvider.java
+++ b/tests/common/com/android/documentsui/DemoProvider.java
@@ -34,6 +34,16 @@
  */
 public class DemoProvider extends TestRootProvider {
 
+    public static final String DIR_INFO = "show info";
+    public static final String DIR_ERROR = "show error";
+    public static final String DIR_ERROR_AND_INFO = "show both error and info";
+    public static final String DIR_THROW = "throw a nice exception";
+    public static final String DIR_AUTH = "throw a authentication exception";
+
+    public static final String MSG_INFO = "All files in this root support settings.";
+    public static final String MSG_ERROR = "I'm an error. Don't judge me.";
+    public static final String MSG_ERROR_AND_INFO = "ERROR: Both ERROR and INFO returned.";
+
     private static final String ROOT_ID = "demo-root";
     private static final String ROOT_DOC_ID = "root0";
 
@@ -61,10 +71,8 @@
         Bundle extras = c.getExtras();
 
         switch (parentDocumentId) {
-            case "show info":
-                extras.putString(
-                        DocumentsContract.EXTRA_INFO,
-                        "All files in this root support settings from owner.");
+            case DIR_INFO:
+                extras.putString(DocumentsContract.EXTRA_INFO, MSG_INFO);
                 addFolder(c, "folder");
                 addFile(c, "zzz");
                 for (int i = 0; i < 100; i++) {
@@ -72,25 +80,19 @@
                 }
                 break;
 
-            case "show error":
-                extras.putString(
-                        DocumentsContract.EXTRA_ERROR,
-                        "I'm a synthetic ERROR. Don't judge me.");
+            case DIR_ERROR:
+                extras.putString(DocumentsContract.EXTRA_ERROR, MSG_ERROR);
                 break;
 
-            case "show both error and info":
-                extras.putString(
-                        DocumentsContract.EXTRA_INFO,
-                        "INFO: I'm confused. I've show both ERROR and INFO.");
-                extras.putString(
-                        DocumentsContract.EXTRA_ERROR,
-                        "ERROR: I'm confused. I've show both ERROR and INFO.");
+            case DIR_ERROR_AND_INFO:
+                extras.putString(DocumentsContract.EXTRA_INFO, MSG_INFO);
+                extras.putString(DocumentsContract.EXTRA_ERROR, MSG_ERROR_AND_INFO);
                 break;
 
-            case "throw a nice exception":
+            case DIR_THROW:
                 throw new RuntimeException();
 
-            case "throw a authentication exception":
+            case DIR_AUTH:
                 Intent intent = new Intent("com.android.documentsui.test.action.AUTHENTICATE");
                 PendingIntent pIntent = PendingIntent.getActivity(getContext(),
                         AbstractActionHandler.CODE_AUTHENTICATION, intent, 0);
@@ -98,11 +100,11 @@
                         pIntent);
 
             default:
-                addFolder(c, "show info");
-                addFolder(c, "show error");
-                addFolder(c, "show both error and info");
-                addFolder(c, "throw a nice exception");
-                addFolder(c, "throw a authentication exception");
+                addFolder(c, DIR_INFO);
+                addFolder(c, DIR_ERROR);
+                addFolder(c, DIR_ERROR_AND_INFO);
+                addFolder(c, DIR_THROW);
+                addFolder(c, DIR_AUTH);
                 break;
         }
 
diff --git a/tests/common/com/android/documentsui/PagingProvider.java b/tests/common/com/android/documentsui/PagingProvider.java
index ad5f32c..a113bd1 100644
--- a/tests/common/com/android/documentsui/PagingProvider.java
+++ b/tests/common/com/android/documentsui/PagingProvider.java
@@ -63,7 +63,7 @@
             String parentDocumentId, String[] projection, Bundle queryArgs)
             throws FileNotFoundException {
 
-        // TODO: Content notification.
+        queryArgs = queryArgs != null ? queryArgs : Bundle.EMPTY;
 
         MatrixCursor c = createDocCursor(projection);
         Bundle extras = c.getExtras();
diff --git a/tests/common/com/android/documentsui/bots/DirectoryListBot.java b/tests/common/com/android/documentsui/bots/DirectoryListBot.java
index 17a9515..beeffdc 100644
--- a/tests/common/com/android/documentsui/bots/DirectoryListBot.java
+++ b/tests/common/com/android/documentsui/bots/DirectoryListBot.java
@@ -17,6 +17,7 @@
 package com.android.documentsui.bots;
 
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertTrue;
 import static junit.framework.Assert.fail;
@@ -103,14 +104,32 @@
         }
     }
 
-    public void assertHeaderMessageText(String message) throws UiObjectNotFoundException {
+    public void assertHasMessage(String expected) throws UiObjectNotFoundException {
         UiObject messageTextView = findHeaderMessageTextView();
-        assertTrue(messageTextView.exists());
-
-        String msg = String.valueOf(message);
+        String msg = String.valueOf(expected);
         assertEquals(msg, messageTextView.getText());
     }
 
+    public void assertHasMessage(boolean expected) throws UiObjectNotFoundException {
+        UiObject messageTextView = findHeaderMessageTextView();
+        if (expected) {
+            assertTrue(messageTextView.exists());
+        } else {
+            assertFalse(messageTextView.exists());
+        }
+    }
+
+    public void assertHasMessageButtonText(String expected) throws UiObjectNotFoundException {
+        UiObject button = findHeaderMessageButton();
+        String msg = String.valueOf(expected);
+        assertEquals(msg, button.getText());
+    }
+
+    public void clickMessageButton() throws UiObjectNotFoundException {
+        UiObject button = findHeaderMessageButton();
+        button.click();
+    }
+
     /**
      * Checks against placeholder text. Placeholder can be Empty page, No results page, or the
      * "Hourglass" page (ie. something-went-wrong page).
@@ -130,6 +149,12 @@
                 "com.android.documentsui:id/message_textview");
     }
 
+    private UiObject findHeaderMessageButton() {
+        return findObject(
+                DIR_CONTAINER_ID,
+                "com.android.documentsui:id/button_dismiss");
+    }
+
     private UiObject findPlaceholderMessageTextView() {
         return findObject(
                 DIR_CONTAINER_ID,
diff --git a/tests/common/com/android/documentsui/bots/InspectorBot.java b/tests/common/com/android/documentsui/bots/InspectorBot.java
index 55f9044..448a7b7 100644
--- a/tests/common/com/android/documentsui/bots/InspectorBot.java
+++ b/tests/common/com/android/documentsui/bots/InspectorBot.java
@@ -15,19 +15,24 @@
  */
 package com.android.documentsui.bots;
 
-import android.annotation.StringRes;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
 import android.app.Activity;
 import android.content.Context;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiSelector;
+import android.view.View;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertTrue;
-
-import com.android.documentsui.inspector.DetailsView;
 import com.android.documentsui.R;
+import com.android.documentsui.inspector.DetailsView;
+import com.android.documentsui.inspector.KeyValueRow;
+import com.android.documentsui.inspector.TableView;
+
+import java.util.HashMap;
+import java.util.Map;
 
 public class InspectorBot extends Bots.BaseBot {
 
@@ -42,23 +47,45 @@
         assertEquals(expected, text);
     }
 
-    public void assertRowPresent(@StringRes String key, String value, Activity activity)
+    public void assertRowPresent(String key, Activity activity)
             throws Exception {
-        assertTrue(isRowPresent(key, value, activity));
+        assertTrue(isRowPresent(key, activity));
     }
 
-    private boolean isRowPresent(@StringRes String key, String value, Activity activity)
+    public void assertRowEquals(String key, String value, Activity activity)
             throws Exception {
-        DetailsView detailsView = (DetailsView) activity.findViewById(R.id.inspector_details_view);
-        int children = detailsView.getChildCount();
+        assertTrue(isRowEquals(key, value, activity));
+    }
+
+    private static Map<String, String> getTableRows(TableView table)
+            throws Exception {
+        Map<String, String> rows = new HashMap<>();
+        int children = table.getChildCount();
         for (int i = 0; i < children; i++) {
-            LinearLayout child = (LinearLayout) detailsView.getChildAt(i);
-            TextView title = (TextView) child.getChildAt(0);
-            if (title.getText().equals(key)) {
-                TextView info = (TextView) child.getChildAt(1);
-                return info.getText().equals(value);
+            View view = table.getChildAt(i);
+            if (view instanceof KeyValueRow) {
+                LinearLayout row = (LinearLayout) table.getChildAt(i);
+                TextView key = (TextView) row.getChildAt(0);
+                TextView value = (TextView) row.getChildAt(1);
+                rows.put(
+                        String.valueOf(key.getText()),
+                        String.valueOf(value.getText()));
             }
         }
-        return false;
+        return rows;
+    }
+
+    private boolean isRowPresent(String key, Activity activity)
+            throws Exception {
+        DetailsView details = (DetailsView) activity.findViewById(R.id.inspector_details_view);
+        Map<String, String> rows = getTableRows(details);
+        return rows.containsKey(key);
+    }
+
+    private boolean isRowEquals(String key, String value, Activity activity)
+            throws Exception {
+        DetailsView details = (DetailsView) activity.findViewById(R.id.inspector_details_view);
+        Map<String, String> rows = getTableRows(details);
+        return rows.containsKey(key) && value.equals(rows.get(key));
     }
 }
diff --git a/tests/common/com/android/documentsui/bots/UiBot.java b/tests/common/com/android/documentsui/bots/UiBot.java
index 72c35a7..3552418 100644
--- a/tests/common/com/android/documentsui/bots/UiBot.java
+++ b/tests/common/com/android/documentsui/bots/UiBot.java
@@ -250,7 +250,7 @@
         while (it.hasNext()) {
             menuItem = it.next();
             UiObject2 text = menuItem.findObject(By.text(label));
-            if (text != null) {
+            if (text != null && menuItem.isClickable()) {
                 break;
             }
         }
diff --git a/tests/common/com/android/documentsui/dirlist/TestDocumentsAdapter.java b/tests/common/com/android/documentsui/dirlist/TestDocumentsAdapter.java
index c463bb2..e2160cf 100644
--- a/tests/common/com/android/documentsui/dirlist/TestDocumentsAdapter.java
+++ b/tests/common/com/android/documentsui/dirlist/TestDocumentsAdapter.java
@@ -16,10 +16,15 @@
 
 package com.android.documentsui.dirlist;
 
+import static org.junit.Assert.assertTrue;
+
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.AdapterDataObserver;
 import android.view.ViewGroup;
 
-import com.android.documentsui.base.EventListener;
 import com.android.documentsui.Model.Update;
+import com.android.documentsui.base.EventListener;
+import com.android.documentsui.selection.SelectionHelper;
 import com.android.documentsui.testing.TestEventListener;
 
 import java.util.ArrayList;
@@ -30,11 +35,53 @@
  */
 public class TestDocumentsAdapter extends DocumentsAdapter {
 
-    List<String> mModelIds = new ArrayList<>();
     final TestEventListener<Update> mModelListener = new TestEventListener<>();
+    List<String> mModelIds = new ArrayList<>();
+    private final AdapterDataObserver mAdapterObserver;
+    private final List<Integer> mSelectionChanged = new ArrayList<>();
 
     public TestDocumentsAdapter(List<String> modelIds) {
         mModelIds = modelIds;
+
+        mAdapterObserver = new RecyclerView.AdapterDataObserver() {
+
+            @Override
+            public void onChanged() {
+            }
+
+            @Override
+            public void onItemRangeChanged(int startPosition, int itemCount, Object payload) {
+                if (SelectionHelper.SELECTION_CHANGED_MARKER.equals(payload)) {
+                    int last = startPosition + itemCount;
+                    for (int i = startPosition; i < last; i++) {
+                        mSelectionChanged.add(i);
+                    }
+                }
+            }
+
+            @Override
+            public void onItemRangeInserted(int startPosition, int itemCount) {
+            }
+
+            @Override
+            public void onItemRangeRemoved(int startPosition, int itemCount) {
+            }
+
+            @Override
+            public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
+                throw new UnsupportedOperationException();
+            }
+        };
+
+        registerAdapterDataObserver(mAdapterObserver);
+    }
+
+    public void resetSelectionChanged() {
+        mSelectionChanged.clear();
+    }
+
+    public void assertSelectionChanged(int position) {
+        assertTrue(mSelectionChanged.contains(position));
     }
 
     @Override
@@ -43,16 +90,17 @@
     }
 
     @Override
-    public List<String> getModelIds() {
+    public List<String> getStableIds() {
         return mModelIds;
     }
 
     @Override
-    public void onItemSelectionChanged(String id) {
+    public int getPosition(String id) {
+        return mModelIds.indexOf(id);
     }
 
     @Override
-    public String getModelId(int position) {
+    public String getStableId(int position) {
         return mModelIds.get(position);
     }
 
diff --git a/tests/common/com/android/documentsui/dirlist/TestFocusHandler.java b/tests/common/com/android/documentsui/dirlist/TestFocusHandler.java
index 910a3c4..8dfbdea 100644
--- a/tests/common/com/android/documentsui/dirlist/TestFocusHandler.java
+++ b/tests/common/com/android/documentsui/dirlist/TestFocusHandler.java
@@ -16,6 +16,8 @@
 
 package com.android.documentsui.dirlist;
 
+import static org.junit.Assert.assertEquals;
+
 import android.view.KeyEvent;
 import android.view.View;
 
@@ -80,4 +82,12 @@
         focusModelId = null;
         focusPos = 0;
     }
-}
\ No newline at end of file
+
+    public void assertHasFocus(boolean focused) {
+        assertEquals(focused, hasFocusedItem());
+    }
+
+    public void assertFocused(String modelId) {
+        assertEquals(modelId, getFocusModelId());
+    }
+}
diff --git a/tests/common/com/android/documentsui/selection/TestItemSelectionListener.java b/tests/common/com/android/documentsui/selection/TestItemSelectionListener.java
deleted file mode 100644
index dfd8e2a..0000000
--- a/tests/common/com/android/documentsui/selection/TestItemSelectionListener.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-
-import java.util.HashSet;
-import java.util.Set;
-
-public class TestItemSelectionListener implements SelectionManager.ItemCallback {
-
-    private final Set<String> mSelected = new HashSet<>();
-
-    @Override
-    public void onItemStateChanged(String id, boolean selected) {
-        if (selected) {
-            assertNotSelected(id);
-            mSelected.add(id);
-        } else {
-            assertSelected(id);
-            mSelected.remove(id);
-        }
-    }
-
-    @Override
-    public void onSelectionReset() {
-        mSelected.clear();
-    }
-
-    void assertNoSelection() {
-        assertTrue(mSelected.isEmpty());
-    }
-
-    void assertSelectionSize(int expected) {
-        assertEquals(expected, mSelected.size());
-    }
-
-    void assertSelected(String id) {
-        assertTrue(id + " is not selected.", mSelected.contains(id));
-    }
-
-    void assertNotSelected(String id) {
-        assertFalse(id + " is already selected", mSelected.contains(id));
-    }
-}
diff --git a/tests/common/com/android/documentsui/selection/TestSelectionListener.java b/tests/common/com/android/documentsui/selection/TestSelectionListener.java
deleted file mode 100644
index 62a86b0..0000000
--- a/tests/common/com/android/documentsui/selection/TestSelectionListener.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.selection;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import com.android.documentsui.selection.SelectionManager;
-
-public final class TestSelectionListener implements SelectionManager.Callback {
-
-    private boolean mSelectionChanged = false;
-
-    @Override
-    public void onSelectionChanged() {
-        mSelectionChanged = true;
-    }
-
-    @Override
-    public void onSelectionRestored() {}
-
-    public void reset() {
-        mSelectionChanged = false;
-    }
-
-    public void assertSelectionChanged() {
-        assertTrue(mSelectionChanged);
-    }
-
-    public void assertSelectionUnchanged() {
-        assertFalse(mSelectionChanged);
-    }
-}
\ No newline at end of file
diff --git a/tests/common/com/android/documentsui/services/TestJob.java b/tests/common/com/android/documentsui/services/TestJob.java
index 3c4da22..10addeb 100644
--- a/tests/common/com/android/documentsui/services/TestJob.java
+++ b/tests/common/com/android/documentsui/services/TestJob.java
@@ -107,4 +107,8 @@
                 service.getString(android.R.string.cancel),
                 R.drawable.ic_cab_cancel);
     }
+
+    @Override
+    void finish() {
+    }
 }
diff --git a/tests/common/com/android/documentsui/testing/IntentAsserts.java b/tests/common/com/android/documentsui/testing/IntentAsserts.java
index 6fc1ae0..cbd6f38 100644
--- a/tests/common/com/android/documentsui/testing/IntentAsserts.java
+++ b/tests/common/com/android/documentsui/testing/IntentAsserts.java
@@ -40,6 +40,14 @@
         assertEquals(expected, intent.getAction());
     }
 
+    public static void assertTargetsComponent(Intent intent, Class<?> expected) {
+        assertEquals(expected.getName(), intent.getComponent().getClassName());
+    }
+
+    public static void assertHasExtra(Intent intent, String key) {
+        assertTrue(intent.getExtras().containsKey(key));
+    }
+
     public static Intent assertHasExtraIntent(Intent intent) {
         Intent extra = (Intent) intent.getExtra(EXTRA_INTENT);
         assertNotNull(extra);
@@ -64,4 +72,8 @@
         Assert.assertEquals(size, list.size());
         return list;
     }
+
+    public static void assertHasData(Intent intent, Uri expected) {
+        assertEquals(expected, intent.getData());
+    }
 }
diff --git a/tests/common/com/android/documentsui/testing/SelectionHelpers.java b/tests/common/com/android/documentsui/testing/SelectionHelpers.java
new file mode 100644
index 0000000..70bc44d
--- /dev/null
+++ b/tests/common/com/android/documentsui/testing/SelectionHelpers.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 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.documentsui.testing;
+
+import com.android.documentsui.DocsSelectionHelper;
+import com.android.documentsui.dirlist.DocsStableIdProvider;
+import com.android.documentsui.dirlist.DocumentsAdapter;
+import com.android.documentsui.dirlist.TestDocumentsAdapter;
+import com.android.documentsui.selection.DefaultSelectionHelper;
+import com.android.documentsui.selection.DefaultSelectionHelper.SelectionMode;
+import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
+
+import java.util.Collections;
+import java.util.List;
+
+public class SelectionHelpers {
+
+    public static final SelectionPredicate CAN_SET_ANYTHING = new SelectionPredicate() {
+        @Override
+        public boolean canSetStateForId(String id, boolean nextState) {
+            return true;
+        }
+
+        @Override
+        public boolean canSetStateAtPosition(int position, boolean nextState) {
+            return true;
+        }
+    };
+
+    private SelectionHelpers() {}
+
+    public static DocsSelectionHelper createTestInstance() {
+        return createTestInstance(Collections.emptyList());
+    }
+
+    public static DocsSelectionHelper createTestInstance(List<String> docs) {
+        return createTestInstance(docs, DefaultSelectionHelper.MODE_MULTIPLE);
+    }
+
+    public static DocsSelectionHelper createTestInstance(
+            List<String> docs, @SelectionMode int mode) {
+        return createTestInstance(new TestDocumentsAdapter(docs), mode, CAN_SET_ANYTHING);
+    }
+
+    public static DocsSelectionHelper createTestInstance(
+            DocumentsAdapter adapter, @SelectionMode int mode, SelectionPredicate canSetState) {
+        DocsSelectionHelper manager = mode == DefaultSelectionHelper.MODE_SINGLE
+                ? DocsSelectionHelper.createSingleSelect()
+                : DocsSelectionHelper.createMultiSelect();
+
+        manager.reset(adapter, new DocsStableIdProvider(adapter), canSetState);
+
+        return manager;
+    }
+}
diff --git a/tests/common/com/android/documentsui/testing/SelectionManagers.java b/tests/common/com/android/documentsui/testing/SelectionManagers.java
deleted file mode 100644
index c4f29a0..0000000
--- a/tests/common/com/android/documentsui/testing/SelectionManagers.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.testing;
-
-import com.android.documentsui.dirlist.DocumentsAdapter;
-import com.android.documentsui.dirlist.TestDocumentsAdapter;
-import com.android.documentsui.selection.SelectionManager;
-import com.android.documentsui.selection.SelectionManager.SelectionMode;
-import com.android.documentsui.selection.SelectionManager.SelectionPredicate;
-
-import java.util.Collections;
-import java.util.List;
-
-public class SelectionManagers {
-    private SelectionManagers() {}
-
-    public static SelectionManager createTestInstance() {
-        return createTestInstance(Collections.emptyList());
-    }
-
-    public static SelectionManager createTestInstance(List<String> docs) {
-        return createTestInstance(docs, SelectionManager.MODE_MULTIPLE);
-    }
-
-    public static SelectionManager createTestInstance(
-            List<String> docs, @SelectionMode int mode) {
-        return createTestInstance(
-                new TestDocumentsAdapter(docs),
-                mode,
-                (String id, boolean nextState) -> true);
-    }
-
-    public static SelectionManager createTestInstance(
-            DocumentsAdapter adapter, @SelectionMode int mode, SelectionPredicate canSetState) {
-        SelectionManager manager = new SelectionManager(mode);
-        manager.reset(adapter, canSetState);
-
-        return manager;
-    }
-}
diff --git a/tests/common/com/android/documentsui/testing/TestActionHandler.java b/tests/common/com/android/documentsui/testing/TestActionHandler.java
index 8353569..cd3fb1a 100644
--- a/tests/common/com/android/documentsui/testing/TestActionHandler.java
+++ b/tests/common/com/android/documentsui/testing/TestActionHandler.java
@@ -22,7 +22,7 @@
 import com.android.documentsui.TestActivity;
 import com.android.documentsui.base.DocumentInfo;
 import com.android.documentsui.base.RootInfo;
-import com.android.documentsui.dirlist.DocumentDetails;
+import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
 
 import java.util.function.Consumer;
 
@@ -30,7 +30,7 @@
 
     private final TestEnv mEnv;
 
-    public final TestEventHandler<DocumentDetails> open = new TestEventHandler<>();
+    public final TestEventHandler<ItemDetails> open = new TestEventHandler<>();
     public boolean mDeleteHappened;
 
     public DocumentInfo nextRootDocument;
@@ -53,7 +53,7 @@
     }
 
     @Override
-    public boolean openDocument(DocumentDetails doc, @ViewType int type, @ViewType int fallback) {
+    public boolean openItem(ItemDetails doc, @ViewType int type, @ViewType int fallback) {
         return open.accept(doc);
     }
 
diff --git a/tests/common/com/android/documentsui/testing/TestDirectoryDetails.java b/tests/common/com/android/documentsui/testing/TestDirectoryDetails.java
index a1b29cd..2841677 100644
--- a/tests/common/com/android/documentsui/testing/TestDirectoryDetails.java
+++ b/tests/common/com/android/documentsui/testing/TestDirectoryDetails.java
@@ -28,6 +28,7 @@
     public boolean hasItemsToPaste;
     public boolean canCreateDoc;
     public boolean canCreateDirectory;
+    public boolean canInspectDirectory;
 
     public TestDirectoryDetails() {
         super(null);
@@ -57,4 +58,9 @@
     public boolean canCreateDirectory() {
         return canCreateDirectory;
     }
+
+    @Override
+    public boolean canInspectDirectory() {
+        return canInspectDirectory;
+    }
 }
\ No newline at end of file
diff --git a/tests/common/com/android/documentsui/testing/TestEnv.java b/tests/common/com/android/documentsui/testing/TestEnv.java
index 96ee0b7..40b5e0a 100644
--- a/tests/common/com/android/documentsui/testing/TestEnv.java
+++ b/tests/common/com/android/documentsui/testing/TestEnv.java
@@ -15,10 +15,12 @@
  */
 package com.android.documentsui.testing;
 
+import android.content.Context;
 import android.provider.DocumentsContract.Document;
 import android.support.test.InstrumentationRegistry;
 import android.test.mock.MockContentResolver;
 
+import com.android.documentsui.DocsSelectionHelper;
 import com.android.documentsui.FocusManager;
 import com.android.documentsui.Injector;
 import com.android.documentsui.archives.ArchivesProvider;
@@ -27,12 +29,9 @@
 import com.android.documentsui.base.RootInfo;
 import com.android.documentsui.base.State;
 import com.android.documentsui.dirlist.TestFocusHandler;
-import com.android.documentsui.selection.SelectionManager;
 import com.android.documentsui.sorting.SortModel;
 import com.android.documentsui.ui.TestDialogController;
 
-import junit.framework.Assert;
-
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -49,6 +48,7 @@
     public static DocumentInfo FILE_JPG;
     public static DocumentInfo FILE_GIF;
     public static DocumentInfo FILE_PDF;
+    public static DocumentInfo FILE_MP4;
     public static DocumentInfo FILE_APK;
     public static DocumentInfo FILE_PARTIAL;
     public static DocumentInfo FILE_ARCHIVE;
@@ -64,29 +64,27 @@
     public final TestDialogController dialogs = new TestDialogController();
     public final TestModel model;
     public final TestModel archiveModel;
-    public final SelectionManager selectionMgr;
+    public final DocsSelectionHelper selectionMgr;
     public final TestSearchViewManager searchViewManager;
-    public final Injector injector;
+    public final Injector<?> injector;
     public final Features features;
 
     public final MockContentResolver contentResolver;
     public final Map<String, TestDocumentsProvider> mockProviders;
 
-    private TestEnv(String authority) {
+    private TestEnv(Context context, Features features, String authority) {
+        this.features = features;
         state.sortModel = SortModel.createModel();
         mExecutor = new TestScheduledExecutorService();
-        features = new Features.RuntimeFeatures(
-                InstrumentationRegistry.getInstrumentation().getTargetContext().getResources(),
-                null);
         model = new TestModel(authority, features);
         archiveModel = new TestModel(ArchivesProvider.AUTHORITY, features);
-        selectionMgr = SelectionManagers.createTestInstance();
+        selectionMgr = SelectionHelpers.createTestInstance();
         searchViewManager = new TestSearchViewManager();
         injector = new Injector(
                 features,
                 new TestActivityConfig(),
-                null,       //ScopedPreferences are not required for tests
-                null,   //a MessageBuilder is not required for tests
+                null,       // ScopedPreferences are not currently required for tests
+                null,       // MessageBuilder is not currently required for tests
                 dialogs,
                 new TestFileTypeLookup(),
                 (roots) -> {},  // not sure why, but java gets angry when I declare roots type.
@@ -111,12 +109,28 @@
         }
     }
 
+    // Many terrible creational permutations == easy to user for test authors!
+    public static TestEnv create(Features features) {
+        return create(features, TestProvidersAccess.HOME.authority);
+    }
+
     public static TestEnv create() {
         return create(TestProvidersAccess.HOME.authority);
     }
 
+    public static TestEnv create(Features features, String authority) {
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        return create(context, features, authority);
+    }
+
     public static TestEnv create(String authority) {
-        TestEnv env = new TestEnv(authority);
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        Features features = new Features.RuntimeFeatures(context.getResources(), null);
+        return create(context, features, authority);
+    }
+
+    private static TestEnv create(Context context, Features features, String authority) {
+        TestEnv env = new TestEnv(context, features, authority);
         env.reset();
         return env;
     }
@@ -136,6 +150,7 @@
         FILE_JPG = model.createFile("jiffy.jpg");
         FILE_GIF = model.createFile("glibby.gif");
         FILE_PDF = model.createFile("busy.pdf");
+        FILE_MP4 = model.createFile("cameravideo.mp4");
         FILE_APK = model.createFile("becareful.apk");
         FILE_PARTIAL = model.createFile(
                 "UbuntuFlappyBird.iso",
@@ -157,8 +172,11 @@
 
     public void populateStack() {
         DocumentInfo rootDoc = model.getDocument("1");
-        Assert.assertNotNull(rootDoc);
-        Assert.assertEquals(rootDoc.displayName, FOLDER_0.displayName);
+
+        // These are test setup sanity checks, not test assertions.
+        assert rootDoc != null;
+        assert rootDoc.isDirectory();
+        assert FOLDER_0.equals(rootDoc);
 
         state.stack.changeRoot(TestProvidersAccess.HOME);
         state.stack.push(rootDoc);
@@ -177,4 +195,21 @@
         ids.add(info.documentId);
         selectionMgr.setItemsSelected(ids, true);
     }
+
+    // Easily copy docs, so we don't pollute static data across tests.
+    public static DocumentInfo clone(DocumentInfo a) {
+        DocumentInfo b = new DocumentInfo();
+        b.authority = a.authority;
+        b.documentId = a.documentId;
+        b.mimeType = a.mimeType;
+        b.displayName = a.displayName;
+        b.lastModified = a.lastModified;
+        b.flags = a.flags;
+        b.summary = a.summary;
+        b.size = a.size;
+        b.icon = a.icon;
+        b.derivedUri = a.derivedUri;
+
+        return b;
+    }
 }
diff --git a/tests/common/com/android/documentsui/testing/TestEvent.java b/tests/common/com/android/documentsui/testing/TestEvent.java
deleted file mode 100644
index bc77211..0000000
--- a/tests/common/com/android/documentsui/testing/TestEvent.java
+++ /dev/null
@@ -1,532 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.testing;
-
-import android.annotation.IntDef;
-import android.graphics.Point;
-import android.support.v7.widget.RecyclerView;
-import android.text.TextUtils;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-
-import com.android.documentsui.base.Events.InputEvent;
-import com.android.documentsui.dirlist.DocumentDetails;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Events and DocDetails are closely related. For the pursposes of this test
- * we coalesce the two in a single, handy-dandy test class.
- */
-public class TestEvent implements InputEvent {
-    private static final int ACTION_UNSET = -1;
-
-    // Add other actions from MotionEvent.ACTION_ as needed.
-    @IntDef(flag = true, value = {
-            MotionEvent.ACTION_DOWN,
-            MotionEvent.ACTION_MOVE,
-            MotionEvent.ACTION_UP
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface Action {}
-
-    // Add other types from MotionEvent.TOOL_TYPE_ as needed.
-    @IntDef(flag = true, value = {
-            MotionEvent.TOOL_TYPE_FINGER,
-            MotionEvent.TOOL_TYPE_MOUSE,
-            MotionEvent.TOOL_TYPE_STYLUS,
-            MotionEvent.TOOL_TYPE_UNKNOWN
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface ToolType {}
-
-    @IntDef(flag = true, value = {
-            MotionEvent.BUTTON_PRIMARY,
-            MotionEvent.BUTTON_SECONDARY
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface Button {}
-
-    @IntDef(flag = true, value = {
-            KeyEvent.META_SHIFT_ON,
-            KeyEvent.META_CTRL_ON
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface Key {}
-
-    private @Action int mAction;
-    private @ToolType int mToolType;
-    private int mPointerCount;
-    private Set<Integer> mButtons;
-    private Set<Integer> mKeys;
-    private Point mLocation;
-    private Point mRawLocation;
-    private Details mDetails;
-
-    private TestEvent() {
-        mAction = ACTION_UNSET;  // somebody has to set this, else we'll barf later.
-        mToolType = MotionEvent.TOOL_TYPE_UNKNOWN;
-        mButtons = new HashSet<>();
-        mKeys = new HashSet<>();
-        mLocation = new Point(0, 0);
-        mRawLocation = new Point(0, 0);
-        mDetails = new Details();
-        mPointerCount = 0;
-    }
-
-    private TestEvent(TestEvent source) {
-        assert(source.mAction != ACTION_UNSET);
-        mAction = source.mAction;
-        mToolType = source.mToolType;
-        mButtons = source.mButtons;
-        mKeys = source.mKeys;
-        mLocation = source.mLocation;
-        mRawLocation = source.mRawLocation;
-        mDetails = new Details(source.mDetails);
-        mPointerCount = source.mPointerCount;
-    }
-
-    @Override
-    public Point getOrigin() {
-        return mLocation;
-    }
-
-    @Override
-    public float getX() {
-        return mLocation.x;
-    }
-
-    @Override
-    public float getY() {
-        return mLocation.y;
-    }
-
-    @Override
-    public float getRawX() {
-        return mRawLocation.x;
-    }
-
-    @Override
-    public float getRawY() {
-        return mRawLocation.y;
-    }
-
-    @Override
-    public int getPointerCount() {
-        return mPointerCount;
-    }
-
-    @Override
-    public boolean isMouseEvent() {
-        return mToolType == MotionEvent.TOOL_TYPE_MOUSE;
-    }
-
-    @Override
-    public boolean isPrimaryButtonPressed() {
-        return mButtons.contains(MotionEvent.BUTTON_PRIMARY);
-    }
-
-    @Override
-    public boolean isSecondaryButtonPressed() {
-        return mButtons.contains(MotionEvent.BUTTON_SECONDARY);
-    }
-
-    @Override
-    public boolean isTertiaryButtonPressed() {
-        return mButtons.contains(MotionEvent.BUTTON_TERTIARY);
-    }
-
-    @Override
-    public boolean isShiftKeyDown() {
-        return mKeys.contains(KeyEvent.META_SHIFT_ON);
-    }
-
-    @Override
-    public boolean isCtrlKeyDown() {
-        return mKeys.contains(KeyEvent.META_CTRL_ON);
-    }
-
-    @Override
-    public boolean isAltKeyDown() {
-        return mKeys.contains(KeyEvent.META_ALT_ON);
-    }
-
-    @Override
-    public boolean isActionDown() {
-        return mAction == MotionEvent.ACTION_DOWN;
-    }
-
-    @Override
-    public boolean isActionUp() {
-        return mAction == MotionEvent.ACTION_UP;
-    }
-
-    @Override
-    public boolean isMultiPointerActionDown() {
-        return mAction == MotionEvent.ACTION_POINTER_DOWN;
-    }
-
-    @Override
-    public boolean isMultiPointerActionUp() {
-        return mAction == MotionEvent.ACTION_POINTER_UP;
-    }
-
-    @Override
-    public boolean isActionMove() {
-        return mAction == MotionEvent.ACTION_MOVE;
-    }
-
-    @Override
-    public boolean isActionCancel() {
-        return mAction == MotionEvent.ACTION_CANCEL;
-    }
-
-    @Override
-    public boolean isOverItem() {
-        return mDetails.isOverItem();
-    }
-
-    @Override
-    public boolean isOverDocIcon() {
-        return mDetails.isOverDocIcon(this);
-    }
-
-    @Override
-    public boolean isOverDragHotspot() {
-        return isOverItem() && mDetails.isInDragHotspot(this);
-    }
-
-    @Override
-    public boolean isOverModelItem() {
-        if (isOverItem()) {
-            DocumentDetails doc = getDocumentDetails();
-            return doc != null && doc.hasModelId();
-        }
-        return false;
-    }
-
-    @Override
-    public boolean isTouchpadScroll() {
-        return isMouseEvent() && mButtons.isEmpty() && isActionMove();
-    }
-
-    @Override
-    public int getItemPosition() {
-        return mDetails.mPosition;
-    }
-
-    @Override
-    public DocumentDetails getDocumentDetails() {
-        return mDetails;
-    }
-
-    @Override
-    public void close() {}
-
-    @Override
-    public int hashCode() {
-        return mDetails.hashCode();
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      if (this == o) {
-          return true;
-      }
-
-      if (!(o instanceof TestEvent)) {
-          return false;
-      }
-
-      TestEvent other = (TestEvent) o;
-      return mAction == other.mAction
-              && mToolType == other.mToolType
-              && mButtons.equals(other.mButtons)
-              && mKeys.equals(other.mKeys)
-              && mLocation.equals(other.mLocation)
-              && mRawLocation.equals(other.mRawLocation)
-              && mDetails.equals(other.mDetails);
-    }
-
-    private static final class Details implements DocumentDetails {
-
-        private int mPosition;
-        private String mModelId;
-        private boolean mInSelectionHotspot;
-        private boolean mInDragHotspot;
-        private boolean mOverDocIcon;
-
-        public Details() {
-           mPosition = Integer.MIN_VALUE;
-        }
-
-        public Details(Details source) {
-            mPosition = source.mPosition;
-            mModelId = source.mModelId;
-            mInSelectionHotspot = source.mInSelectionHotspot;
-            mInDragHotspot = source.mInDragHotspot;
-            mOverDocIcon = source.mOverDocIcon;
-        }
-
-
-        private boolean isOverItem() {
-            return mPosition != Integer.MIN_VALUE && mPosition != RecyclerView.NO_POSITION;
-        }
-
-        @Override
-        public boolean hasModelId() {
-            return !TextUtils.isEmpty(mModelId);
-        }
-
-        @Override
-        public String getModelId() {
-            return mModelId;
-        }
-
-        @Override
-        public int getAdapterPosition() {
-            return mPosition;
-        }
-
-        @Override
-        public boolean isInSelectionHotspot(InputEvent event) {
-            return mInSelectionHotspot;
-        }
-
-        @Override
-        public boolean isInDragHotspot(InputEvent event) {
-            return mInDragHotspot;
-        }
-
-        @Override
-        public boolean isOverDocIcon(InputEvent event) {
-            return mOverDocIcon;
-        }
-
-        @Override
-        public int hashCode() {
-            return mModelId != null ? mModelId.hashCode() : ACTION_UNSET;
-        }
-
-        @Override
-        public boolean equals(Object o) {
-          if (this == o) {
-              return true;
-          }
-
-          if (!(o instanceof Details)) {
-              return false;
-          }
-
-          Details other = (Details) o;
-          return mPosition == other.mPosition
-                  && mModelId == other.mModelId;
-        }
-    }
-
-    public static final Builder builder() {
-        return new Builder();
-    }
-
-    /**
-     * Test event builder with convenience methods for common event attrs.
-     */
-    public static final class Builder {
-
-        private TestEvent mState = new TestEvent();
-
-        public Builder() {
-        }
-
-        public Builder(TestEvent state) {
-            mState = new TestEvent(state);
-        }
-
-        /**
-         * @param action Any action specified in {@link MotionEvent}.
-         * @return
-         */
-        public Builder action(int action) {
-            mState.mAction = action;
-            return this;
-        }
-
-        public Builder type(@ToolType int type) {
-            mState.mToolType = type;
-            return this;
-        }
-
-        public Builder location(int x, int y) {
-            mState.mLocation = new Point(x, y);
-            return this;
-        }
-
-        public Builder rawLocation(int x, int y) {
-            mState.mRawLocation = new Point(x, y);
-            return this;
-        }
-
-        public Builder pointerCount(int count) {
-            mState.mPointerCount = count;
-            return this;
-        }
-
-        /**
-         * Adds one or more button press attributes.
-         */
-        public Builder pressButton(@Button int... buttons) {
-            for (int button : buttons) {
-                mState.mButtons.add(button);
-            }
-            return this;
-        }
-
-        /**
-         * Removes one or more button press attributes.
-         */
-        public Builder releaseButton(@Button int... buttons) {
-            for (int button : buttons) {
-                mState.mButtons.remove(button);
-            }
-            return this;
-        }
-
-        /**
-         * Adds one or more key press attributes.
-         */
-        public Builder pressKey(@Key int... keys) {
-            for (int key : keys) {
-                mState.mKeys.add(key);
-            }
-            return this;
-        }
-
-        /**
-         * Removes one or more key press attributes.
-         */
-        public Builder releaseKey(@Button int... keys) {
-            for (int key : keys) {
-                mState.mKeys.remove(key);
-            }
-            return this;
-        }
-
-        public Builder at(int position) {
-            mState.mDetails.mPosition = position;  // this is both "adapter position" and "item position".
-            mState.mDetails.mModelId = String.valueOf(position);
-            return this;
-        }
-
-        public Builder inSelectionHotspot() {
-            mState.mDetails.mInSelectionHotspot = true;
-            return this;
-        }
-
-        public Builder inDragHotspot() {
-            mState.mDetails.mInDragHotspot = true;
-            return this;
-        }
-
-        public Builder notInDragHotspot() {
-            mState.mDetails.mInDragHotspot = false;
-            return this;
-        }
-
-        public Builder overDocIcon() {
-            mState.mDetails.mOverDocIcon = true;
-            return this;
-        }
-
-        public Builder notOverDocIcon() {
-            mState.mDetails.mOverDocIcon = false;
-            return this;
-        }
-
-        public Builder touch() {
-            type(MotionEvent.TOOL_TYPE_FINGER);
-            return this;
-        }
-
-        public Builder mouse() {
-            type(MotionEvent.TOOL_TYPE_MOUSE);
-            return this;
-        }
-
-        public Builder shift() {
-            pressKey(KeyEvent.META_SHIFT_ON);
-            return this;
-        }
-
-        /**
-         * Use {@link #remove(@Attribute int...)}
-         */
-        @Deprecated
-        public Builder unshift() {
-            releaseKey(KeyEvent.META_SHIFT_ON);
-            return this;
-        }
-
-        public Builder ctrl() {
-            pressKey(KeyEvent.META_CTRL_ON);
-            return this;
-        }
-
-        public Builder alt() {
-            pressKey(KeyEvent.META_ALT_ON);
-            return this;
-        }
-
-        public Builder primary() {
-            pressButton(MotionEvent.BUTTON_PRIMARY);
-            releaseButton(MotionEvent.BUTTON_SECONDARY);
-            releaseButton(MotionEvent.BUTTON_TERTIARY);
-            return this;
-        }
-
-        public Builder secondary() {
-            pressButton(MotionEvent.BUTTON_SECONDARY);
-            releaseButton(MotionEvent.BUTTON_PRIMARY);
-            releaseButton(MotionEvent.BUTTON_TERTIARY);
-            return this;
-        }
-
-        public Builder tertiary() {
-            pressButton(MotionEvent.BUTTON_TERTIARY);
-            releaseButton(MotionEvent.BUTTON_PRIMARY);
-            releaseButton(MotionEvent.BUTTON_SECONDARY);
-            return this;
-        }
-
-        public Builder reset() {
-            mState = new TestEvent();
-            return this;
-        }
-
-        @Override
-        public Builder clone() {
-            return new Builder(build());
-        }
-
-        public TestEvent build() {
-            // Return a copy, so nobody can mess w/ our internal state.
-            return new TestEvent(mState);
-        }
-    }
-}
diff --git a/tests/common/com/android/documentsui/testing/TestEvents.java b/tests/common/com/android/documentsui/testing/TestEvents.java
new file mode 100644
index 0000000..9aab9e8
--- /dev/null
+++ b/tests/common/com/android/documentsui/testing/TestEvents.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2016 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.documentsui.testing;
+
+import android.annotation.IntDef;
+import android.graphics.Point;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.MotionEvent.PointerCoords;
+import android.view.MotionEvent.PointerProperties;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Handy-dandy wrapper class to facilitate the creation of MotionEvents.
+ */
+public final class TestEvents {
+
+    /**
+     * Common mouse event types...for your convenience.
+     */
+    public static final class Mouse {
+        public static final MotionEvent CLICK =
+                TestEvents.builder().mouse().primary().build();
+        public static final MotionEvent CTRL_CLICK =
+                TestEvents.builder().mouse().primary().ctrl().build();
+        public static final MotionEvent ALT_CLICK =
+                TestEvents.builder().mouse().primary().alt().build();
+        public static final MotionEvent SHIFT_CLICK =
+                TestEvents.builder().mouse().primary().shift().build();
+        public static final MotionEvent SECONDARY_CLICK =
+                TestEvents.builder().mouse().secondary().build();
+        public static final MotionEvent TERTIARY_CLICK =
+                TestEvents.builder().mouse().tertiary().build();
+    }
+
+    /**
+     * Common touch event types...for your convenience.
+     */
+    public static final class Touch {
+        public static final MotionEvent TAP =
+                TestEvents.builder().touch().build();
+    }
+
+    static final int ACTION_UNSET = -1;
+
+    // Add other actions from MotionEvent.ACTION_ as needed.
+    @IntDef(flag = true, value = {
+            MotionEvent.ACTION_DOWN,
+            MotionEvent.ACTION_MOVE,
+            MotionEvent.ACTION_UP
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Action {}
+
+    // Add other types from MotionEvent.TOOL_TYPE_ as needed.
+    @IntDef(flag = true, value = {
+            MotionEvent.TOOL_TYPE_FINGER,
+            MotionEvent.TOOL_TYPE_MOUSE,
+            MotionEvent.TOOL_TYPE_STYLUS,
+            MotionEvent.TOOL_TYPE_UNKNOWN
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ToolType {}
+
+    @IntDef(flag = true, value = {
+            MotionEvent.BUTTON_PRIMARY,
+            MotionEvent.BUTTON_SECONDARY
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Button {}
+
+    @IntDef(flag = true, value = {
+            KeyEvent.META_SHIFT_ON,
+            KeyEvent.META_CTRL_ON
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Key {}
+
+    private static final class State {
+        private @Action int mAction = ACTION_UNSET;
+        private @ToolType int mToolType = MotionEvent.TOOL_TYPE_UNKNOWN;
+        private int mPointerCount = 1;
+        private Set<Integer> mButtons = new HashSet<>();
+        private Set<Integer> mKeys = new HashSet<>();
+        private Point mLocation = new Point(0, 0);
+        private Point mRawLocation = new Point(0, 0);
+    }
+
+    public static final Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Test event builder with convenience methods for common event attrs.
+     */
+    public static final class Builder {
+
+        private State mState = new State();
+
+        /**
+         * @param action Any action specified in {@link MotionEvent}.
+         * @return
+         */
+        public Builder action(int action) {
+            mState.mAction = action;
+            return this;
+        }
+
+        public Builder type(@ToolType int type) {
+            mState.mToolType = type;
+            return this;
+        }
+
+        public Builder location(int x, int y) {
+            mState.mLocation = new Point(x, y);
+            return this;
+        }
+
+        public Builder rawLocation(int x, int y) {
+            mState.mRawLocation = new Point(x, y);
+            return this;
+        }
+
+        public Builder pointerCount(int count) {
+            mState.mPointerCount = count;
+            return this;
+        }
+
+        /**
+         * Adds one or more button press attributes.
+         */
+        public Builder pressButton(@Button int... buttons) {
+            for (int button : buttons) {
+                mState.mButtons.add(button);
+            }
+            return this;
+        }
+
+        /**
+         * Removes one or more button press attributes.
+         */
+        public Builder releaseButton(@Button int... buttons) {
+            for (int button : buttons) {
+                mState.mButtons.remove(button);
+            }
+            return this;
+        }
+
+        /**
+         * Adds one or more key press attributes.
+         */
+        public Builder pressKey(@Key int... keys) {
+            for (int key : keys) {
+                mState.mKeys.add(key);
+            }
+            return this;
+        }
+
+        /**
+         * Removes one or more key press attributes.
+         */
+        public Builder releaseKey(@Button int... keys) {
+            for (int key : keys) {
+                mState.mKeys.remove(key);
+            }
+            return this;
+        }
+
+        public Builder touch() {
+            type(MotionEvent.TOOL_TYPE_FINGER);
+            return this;
+        }
+
+        public Builder mouse() {
+            type(MotionEvent.TOOL_TYPE_MOUSE);
+            return this;
+        }
+
+        public Builder shift() {
+            pressKey(KeyEvent.META_SHIFT_ON);
+            return this;
+        }
+
+        /**
+         * Use {@link #remove(@Attribute int...)}
+         */
+        public Builder unshift() {
+            releaseKey(KeyEvent.META_SHIFT_ON);
+            return this;
+        }
+
+        public Builder ctrl() {
+            pressKey(KeyEvent.META_CTRL_ON);
+            return this;
+        }
+
+        public Builder alt() {
+            pressKey(KeyEvent.META_ALT_ON);
+            return this;
+        }
+
+        public Builder primary() {
+            pressButton(MotionEvent.BUTTON_PRIMARY);
+            releaseButton(MotionEvent.BUTTON_SECONDARY);
+            releaseButton(MotionEvent.BUTTON_TERTIARY);
+            return this;
+        }
+
+        public Builder secondary() {
+            pressButton(MotionEvent.BUTTON_SECONDARY);
+            releaseButton(MotionEvent.BUTTON_PRIMARY);
+            releaseButton(MotionEvent.BUTTON_TERTIARY);
+            return this;
+        }
+
+        public Builder tertiary() {
+            pressButton(MotionEvent.BUTTON_TERTIARY);
+            releaseButton(MotionEvent.BUTTON_PRIMARY);
+            releaseButton(MotionEvent.BUTTON_SECONDARY);
+            return this;
+        }
+
+        public MotionEvent build() {
+
+            PointerProperties[] pointers = new PointerProperties[1];
+            pointers[0] = new PointerProperties();
+            pointers[0].id = 0;
+            pointers[0].toolType = mState.mToolType;
+
+            PointerCoords[] coords = new PointerCoords[1];
+            coords[0] = new PointerCoords();
+            coords[0].x = mState.mLocation.x;
+            coords[0].y = mState.mLocation.y;
+
+            int buttons = 0;
+            for (Integer button : mState.mButtons) {
+                buttons |= button;
+            }
+
+            int keys = 0;
+            for (Integer key : mState.mKeys) {
+                keys |= key;
+            }
+
+            return MotionEvent.obtain(
+                    0,     // down time
+                    1,     // event time
+                    mState.mAction,
+                    1,  // pointerCount,
+                    pointers,
+                    coords,
+                    keys,
+                    buttons,
+                    1.0f,  // x precision
+                    1.0f,  // y precision
+                    0,     // device id
+                    0,     // edge flags
+                    0,     // int source,
+                    0      // int flags
+                    );
+        }
+    }
+}
diff --git a/tests/common/com/android/documentsui/testing/TestGridLayoutManager.java b/tests/common/com/android/documentsui/testing/TestGridLayoutManager.java
new file mode 100644
index 0000000..f883e5e
--- /dev/null
+++ b/tests/common/com/android/documentsui/testing/TestGridLayoutManager.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2016 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.documentsui.testing;
+
+import android.content.Context;
+import android.support.v7.widget.GridLayoutManager;
+
+import org.mockito.Mockito;
+
+public class TestGridLayoutManager extends GridLayoutManager {
+
+    private int mFirstVisibleItemPosition;
+
+    public static TestGridLayoutManager create() {
+        final TestGridLayoutManager manager = Mockito.mock(TestGridLayoutManager.class,
+                Mockito.withSettings().defaultAnswer(Mockito.CALLS_REAL_METHODS));
+        return manager;
+    }
+
+    @Override
+    public int findFirstVisibleItemPosition() { return mFirstVisibleItemPosition; }
+
+    public void setFirstVisibleItemPosition(int position) { mFirstVisibleItemPosition = position; }
+
+    private TestGridLayoutManager(Context context, int spanCount) {
+        super(context, spanCount);
+    }
+}
diff --git a/tests/common/com/android/documentsui/testing/TestMenu.java b/tests/common/com/android/documentsui/testing/TestMenu.java
index 9df06d9..6a46668 100644
--- a/tests/common/com/android/documentsui/testing/TestMenu.java
+++ b/tests/common/com/android/documentsui/testing/TestMenu.java
@@ -18,6 +18,7 @@
 
 import android.util.SparseArray;
 import android.view.Menu;
+import android.widget.SearchView;
 
 import com.android.documentsui.R;
 
@@ -48,8 +49,9 @@
                 R.id.dir_menu_rename,
                 R.id.dir_menu_delete,
                 R.id.dir_menu_view_in_owner,
-                R.id.dir_menu_open_in_new_window,
                 R.id.dir_menu_paste_into_folder,
+                R.id.dir_menu_inspect,
+                R.id.dir_menu_open_in_new_window,
                 R.id.root_menu_eject_root,
                 R.id.root_menu_open_in_new_window,
                 R.id.root_menu_paste_into_folder,
@@ -64,7 +66,7 @@
                 R.id.action_menu_move_to,
                 R.id.action_menu_compress,
                 R.id.action_menu_rename,
-                R.id.action_menu_inspector,
+                R.id.action_menu_inspect,
                 R.id.action_menu_view_in_owner,
                 R.id.option_menu_search,
                 R.id.option_menu_debug,
@@ -74,7 +76,8 @@
                 R.id.option_menu_create_dir,
                 R.id.option_menu_select_all,
                 R.id.option_menu_advanced,
-                R.id.option_menu_settings);
+                R.id.option_menu_settings,
+                R.id.option_menu_inspect);
     }
 
 
@@ -86,6 +89,11 @@
         for (int id : ids) {
             TestMenuItem item = TestMenuItem.create(id);
             menu.addMenuItem(id, item);
+
+            // Used by SearchViewManager
+            if (id == R.id.option_menu_search) {
+                item.setActionView(Mockito.mock(SearchView.class));
+            }
         }
         return menu;
     }
diff --git a/tests/common/com/android/documentsui/testing/TestMenuItem.java b/tests/common/com/android/documentsui/testing/TestMenuItem.java
index a955adc..9f4df28 100644
--- a/tests/common/com/android/documentsui/testing/TestMenuItem.java
+++ b/tests/common/com/android/documentsui/testing/TestMenuItem.java
@@ -21,6 +21,7 @@
 
 import android.annotation.StringRes;
 import android.view.MenuItem;
+import android.view.View;
 
 import org.mockito.Mockito;
 
@@ -37,6 +38,7 @@
 
     boolean enabled;
     boolean visible;
+    View actionView;
     @StringRes int title;
 
     public static TestMenuItem create(int id) {
@@ -83,6 +85,17 @@
         return this.enabled;
     }
 
+    @Override
+    final public MenuItem setActionView(View actionView) {
+        this.actionView = actionView;
+        return this;
+    }
+
+    @Override
+    final public View getActionView() {
+        return this.actionView;
+    }
+
     public void assertEnabled() {
         assertTrue(this.enabled);
     }
diff --git a/tests/common/com/android/documentsui/testing/TestModel.java b/tests/common/com/android/documentsui/testing/TestModel.java
index 517b1f4..0df9b3a 100644
--- a/tests/common/com/android/documentsui/testing/TestModel.java
+++ b/tests/common/com/android/documentsui/testing/TestModel.java
@@ -53,6 +53,7 @@
         reset();
     }
 
+    @Override
     public void reset() {
         mLastId = 0;
         mCursor = new MatrixCursor(COLUMNS);
diff --git a/tests/common/com/android/documentsui/testing/TestProvidersAccess.java b/tests/common/com/android/documentsui/testing/TestProvidersAccess.java
index abe95d1..248bb53 100644
--- a/tests/common/com/android/documentsui/testing/TestProvidersAccess.java
+++ b/tests/common/com/android/documentsui/testing/TestProvidersAccess.java
@@ -16,6 +16,7 @@
 package com.android.documentsui.testing;
 
 import android.provider.DocumentsContract.Root;
+
 import com.android.documentsui.InspectorProvider;
 import com.android.documentsui.base.Providers;
 import com.android.documentsui.base.RootInfo;
@@ -45,6 +46,7 @@
         }};
         DOWNLOADS.authority = Providers.AUTHORITY_DOWNLOADS;
         DOWNLOADS.rootId = Providers.ROOT_ID_DOWNLOADS;
+        DOWNLOADS.title = "Downloads";
         DOWNLOADS.flags = Root.FLAG_LOCAL_ONLY
                 | Root.FLAG_SUPPORTS_CREATE
                 | Root.FLAG_SUPPORTS_IS_CHILD
@@ -53,6 +55,7 @@
         HOME = new RootInfo();
         HOME.authority = Providers.AUTHORITY_STORAGE;
         HOME.rootId = Providers.ROOT_ID_HOME;
+        HOME.title = "Home";
         HOME.flags = Root.FLAG_LOCAL_ONLY
                 | Root.FLAG_SUPPORTS_CREATE
                 | Root.FLAG_SUPPORTS_IS_CHILD
@@ -61,10 +64,12 @@
         HAMMY = new RootInfo();
         HAMMY.authority = "yummies";
         HAMMY.rootId = "hamsandwich";
+        HAMMY.title = "Ham Sandwich";
 
         PICKLES = new RootInfo();
         PICKLES.authority = "yummies";
         PICKLES.rootId = "pickles";
+        PICKLES.title = "Pickles";
 
         RECENTS = new RootInfo() {{
             // Special root for recents
@@ -72,10 +77,12 @@
             flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_IS_CHILD;
             availableBytes = -1;
         }};
+        RECENTS.title = "Recents";
 
         INSPECTOR = new RootInfo();
         INSPECTOR.authority = InspectorProvider.AUTHORITY;
         INSPECTOR.rootId = InspectorProvider.ROOT_ID;
+        INSPECTOR.title = "Inspector";
         INSPECTOR.flags = Root.FLAG_LOCAL_ONLY
             | Root.FLAG_SUPPORTS_CREATE;
     }
diff --git a/tests/common/com/android/documentsui/testing/TestRecyclerView.java b/tests/common/com/android/documentsui/testing/TestRecyclerView.java
index 8759a9a..a1f8e7f 100644
--- a/tests/common/com/android/documentsui/testing/TestRecyclerView.java
+++ b/tests/common/com/android/documentsui/testing/TestRecyclerView.java
@@ -17,6 +17,7 @@
 package com.android.documentsui.testing;
 
 import android.content.Context;
+import android.support.test.InstrumentationRegistry;
 import android.support.v7.widget.RecyclerView;
 import android.view.View;
 
@@ -32,6 +33,7 @@
 
     private List<RecyclerView.ViewHolder> holders = new ArrayList<>();
     private TestDocumentsAdapter adapter;
+    private RecyclerView.LayoutManager mLayoutManager;
 
     public TestRecyclerView(Context context) {
         super(context);
@@ -55,6 +57,16 @@
         return adapter;
     }
 
+    @Override
+    public void setLayoutManager(LayoutManager manager) {
+        mLayoutManager = manager;
+    }
+
+    @Override
+    public RecyclerView.LayoutManager getLayoutManager() {
+        return mLayoutManager;
+    }
+
     public void setItems(List<String> modelIds) {
         holders = new ArrayList<>();
         for (String modelId: modelIds) {
@@ -64,8 +76,8 @@
     }
 
     public static TestRecyclerView create(List<String> modelIds) {
-        final TestRecyclerView view = Mockito.mock(TestRecyclerView.class,
-                Mockito.withSettings().defaultAnswer(Mockito.CALLS_REAL_METHODS));
+        final TestRecyclerView view =
+                new TestRecyclerView(InstrumentationRegistry.getTargetContext());
         view.holders = new ArrayList<>();
         for (String modelId: modelIds) {
             view.holders.add(new TestViewHolder(Views.createTestView()));
diff --git a/tests/common/com/android/documentsui/testing/TestResources.java b/tests/common/com/android/documentsui/testing/TestResources.java
index 907d923..0bd21de 100644
--- a/tests/common/com/android/documentsui/testing/TestResources.java
+++ b/tests/common/com/android/documentsui/testing/TestResources.java
@@ -85,10 +85,12 @@
         return strings.get(id);
     }
 
+    @Override
     @NonNull
     public final String getString(
             @StringRes int id, Object... formatArgs) throws NotFoundException {
-        return getString(id);
+        final String raw = getString(id);
+        return String.format(raw, formatArgs);
     }
 
     @Override
@@ -106,6 +108,7 @@
         return null;
     }
 
+    @Override
     public final CharSequence getText(@StringRes int resId) {
         return getString(resId);
     }
diff --git a/tests/common/com/android/documentsui/testing/TestTimer.java b/tests/common/com/android/documentsui/testing/TestTimer.java
index e1a6610..89efb96 100644
--- a/tests/common/com/android/documentsui/testing/TestTimer.java
+++ b/tests/common/com/android/documentsui/testing/TestTimer.java
@@ -16,6 +16,7 @@
 
 package com.android.documentsui.testing;
 
+import java.lang.IllegalStateException;
 import java.util.Date;
 import java.util.Iterator;
 import java.util.LinkedList;
@@ -28,6 +29,7 @@
  */
 public class TestTimer extends Timer {
 
+    private boolean mIsCancelled;
     private long mNow = 0;
 
     private final LinkedList<Task> mTaskList = new LinkedList<>();
@@ -64,6 +66,7 @@
 
     @Override
     public void cancel() {
+        mIsCancelled = true;
         mTaskList.clear();
     }
 
@@ -114,6 +117,9 @@
     }
 
     public void scheduleAtTime(TimerTask task, long executeTime) {
+        if (mIsCancelled) {
+            throw new IllegalStateException("Timer already cancelled.");
+        }
         Task testTimerTask = (Task) task;
         testTimerTask.mExecuteTime = executeTime;
 
diff --git a/tests/functional/com/android/documentsui/DirectoryMessagesUiTest.java b/tests/functional/com/android/documentsui/DirectoryMessagesUiTest.java
new file mode 100644
index 0000000..fda1308
--- /dev/null
+++ b/tests/functional/com/android/documentsui/DirectoryMessagesUiTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.documentsui;
+
+import android.support.test.filters.LargeTest;
+
+import com.android.documentsui.files.FilesActivity;
+
+@LargeTest
+public class DirectoryMessagesUiTest extends ActivityTest<FilesActivity> {
+
+    public DirectoryMessagesUiTest() {
+        super(FilesActivity.class);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        bots.roots.openRoot("Demo Root");
+        bots.main.switchToListMode();
+    }
+
+    public void testAuthenticationMessage_visible() throws Exception {
+        // If feature is disabled, this test is a no-op.
+        if (!features.isRemoteActionsEnabled()) {
+            return;
+        }
+        bots.directory.openDocument(DemoProvider.DIR_AUTH);
+        bots.directory.assertHasMessage(
+                "To view this directory, sign in to DocumentsUI Tests");
+        bots.directory.assertHasMessageButtonText("SIGN IN");
+    }
+
+    public void testInfoMessage_visible() throws Exception {
+        bots.directory.openDocument(DemoProvider.DIR_INFO);
+        bots.directory.assertHasMessage(DemoProvider.MSG_INFO);
+        bots.directory.assertHasMessageButtonText("DISMISS");
+    }
+
+    public void testInfoMessage_dismissable() throws Exception {
+        bots.directory.openDocument(DemoProvider.DIR_INFO);
+        bots.directory.assertHasMessage(true);
+        bots.directory.clickMessageButton();
+        bots.directory.assertHasMessage(false);
+    }
+
+    public void testErrorMessage_visible() throws Exception {
+        bots.directory.openDocument(DemoProvider.DIR_ERROR);
+        bots.directory.assertHasMessage(DemoProvider.MSG_ERROR);
+        bots.directory.assertHasMessageButtonText("DISMISS");
+    }
+
+    public void testErrorMessage_dismissable() throws Exception {
+        bots.directory.openDocument(DemoProvider.DIR_ERROR);
+        bots.directory.assertHasMessage(true);
+        bots.directory.clickMessageButton();
+        bots.directory.assertHasMessage(false);
+    }
+
+    public void testErrorMessage_supercedesInfoMessage() throws Exception {
+        // When both error and info are returned in Directory, only show the error.
+        bots.directory.openDocument(DemoProvider.DIR_ERROR_AND_INFO);
+        bots.directory.assertHasMessage(DemoProvider.MSG_ERROR_AND_INFO);
+    }
+}
diff --git a/tests/functional/com/android/documentsui/FileManagementUiTest.java b/tests/functional/com/android/documentsui/FileManagementUiTest.java
index 5157ec3..58be747 100644
--- a/tests/functional/com/android/documentsui/FileManagementUiTest.java
+++ b/tests/functional/com/android/documentsui/FileManagementUiTest.java
@@ -77,7 +77,7 @@
     }
 
     public void testDeleteDocument() throws Exception {
-        bots.directory.selectDocument("file1.png");
+        bots.directory.selectDocument("file1.png", 1);
         device.waitForIdle();
         bots.main.clickToolbarItem(R.id.action_menu_delete);
 
@@ -88,7 +88,7 @@
     }
 
     public void testKeyboard_CutDocument() throws Exception {
-        bots.directory.selectDocument("file1.png");
+        bots.directory.selectDocument("file1.png", 1);
         device.waitForIdle();
         bots.keyboard.pressKey(KeyEvent.KEYCODE_X, KeyEvent.META_CTRL_ON);
 
@@ -105,7 +105,7 @@
     }
 
     public void testKeyboard_CopyDocument() throws Exception {
-        bots.directory.selectDocument("file1.png");
+        bots.directory.selectDocument("file1.png", 1);
         device.waitForIdle();
         bots.keyboard.pressKey(KeyEvent.KEYCODE_C, KeyEvent.META_CTRL_ON);
 
@@ -121,7 +121,7 @@
     }
 
     public void testDeleteDocument_Cancel() throws Exception {
-        bots.directory.selectDocument("file1.png");
+        bots.directory.selectDocument("file1.png", 1);
         device.waitForIdle();
         bots.main.clickToolbarItem(R.id.action_menu_delete);
 
diff --git a/tests/functional/com/android/documentsui/FilesActivityUiTest.java b/tests/functional/com/android/documentsui/FilesActivityUiTest.java
index 87f3bac..ac2e3aa 100644
--- a/tests/functional/com/android/documentsui/FilesActivityUiTest.java
+++ b/tests/functional/com/android/documentsui/FilesActivityUiTest.java
@@ -63,18 +63,6 @@
         bots.main.assertWindowTitle("Images");
     }
 
-    public void testProtectedFolder_showsAuthenticationUi() throws Exception {
-        // If feature is disabled, this test is a no-op.
-        if (features.isRemoteActionsEnabled()) {
-            bots.roots.openRoot("Demo Root");
-            bots.main.switchToListMode();
-            bots.directory.openDocument("throw a authentication exception");
-            bots.directory.assertHeaderMessageText(
-                    "To view this directory, sign in to DocumentsUI Tests");
-        }
-
-    }
-
     public void testFilesListed() throws Exception {
         bots.directory.assertDocumentsPresent("file0.log", "file1.png", "file2.csv");
     }
@@ -118,7 +106,7 @@
         Instrumentation.ActivityMonitor monitor = new Instrumentation.ActivityMonitor(
                 InspectorActivity.class.getName(), null, false);
         bots.directory.selectDocument("file0.log");
-        bots.main.clickActionItem("Properties");
+        bots.main.clickActionItem("Get info");
         monitor.waitForActivityWithTimeout(TIMEOUT);
     }
 
diff --git a/tests/functional/com/android/documentsui/InspectorUiTest.java b/tests/functional/com/android/documentsui/InspectorUiTest.java
index 724ba1d..a228de2 100644
--- a/tests/functional/com/android/documentsui/InspectorUiTest.java
+++ b/tests/functional/com/android/documentsui/InspectorUiTest.java
@@ -18,10 +18,12 @@
 import android.content.Intent;
 import android.net.Uri;
 import android.provider.DocumentsContract;
+import android.support.test.filters.LargeTest;
 
 import com.android.documentsui.bots.UiBot;
 import com.android.documentsui.inspector.InspectorActivity;
 
+@LargeTest
 public class InspectorUiTest extends ActivityTest<InspectorActivity> {
 
     private static final String TEST_DOC_NAME = "test.txt";
@@ -56,11 +58,17 @@
         bots.inspector.assertTitle("test.txt");
     }
 
-    public void testDisplayFileType() throws Exception {
+    public void testFolderDetails() throws Exception {
         if (!features.isInspectorEnabled()) {
             return;
         }
-        bots.inspector.assertRowPresent(getActivity().getString(R.string.sort_dimension_file_type),
-                "vnd.android.document/directory", getActivity());
+        bots.inspector.assertRowEquals(
+                getActivity().getString(R.string.sort_dimension_file_type),
+                "Folder",
+                getActivity());
+        bots.inspector.assertRowEquals(
+                getActivity().getString(R.string.directory_items),
+                "4",
+                getActivity());
     }
 }
diff --git a/tests/functional/com/android/documentsui/KeyboardNavigationUiTest.java b/tests/functional/com/android/documentsui/KeyboardNavigationUiTest.java
index 6dcad17..cef7913 100644
--- a/tests/functional/com/android/documentsui/KeyboardNavigationUiTest.java
+++ b/tests/functional/com/android/documentsui/KeyboardNavigationUiTest.java
@@ -84,6 +84,7 @@
         bots.roots.openDrawer();
 
         bots.keyboard.pressKey(KeyEvent.KEYCODE_TAB);
+        bots.keyboard.pressKey(KeyEvent.KEYCODE_TAB);
         for (int i = 0; i < 10; i++) {
             bots.keyboard.pressKey(KeyEvent.KEYCODE_DPAD_RIGHT);
             bots.roots.assertHasFocus();
diff --git a/tests/functional/com/android/documentsui/SearchViewUiTest.java b/tests/functional/com/android/documentsui/SearchViewUiTest.java
index e357936..d7ffe7c 100644
--- a/tests/functional/com/android/documentsui/SearchViewUiTest.java
+++ b/tests/functional/com/android/documentsui/SearchViewUiTest.java
@@ -70,6 +70,7 @@
     public void testSearchView_CollapsesOnBack() throws Exception {
         bots.search.clickIcon();
         device.pressBack();
+        device.pressBack();
 
         bots.search.assertIconVisible(true);
         bots.search.assertInputExists(false);
@@ -80,6 +81,7 @@
         bots.search.setInputText("file2");
 
         device.pressBack();
+        device.pressBack();
 
         // Wait for a file in the default directory to be listed.
         bots.directory.waitForDocument(dirName1);
diff --git a/tests/res/raw/images.zip b/tests/res/raw/images.zip
new file mode 100644
index 0000000..b3013e9
--- /dev/null
+++ b/tests/res/raw/images.zip
Binary files differ
diff --git a/tests/unit/com/android/documentsui/AbstractActionHandlerTest.java b/tests/unit/com/android/documentsui/AbstractActionHandlerTest.java
index e094078..d9c5517 100644
--- a/tests/unit/com/android/documentsui/AbstractActionHandlerTest.java
+++ b/tests/unit/com/android/documentsui/AbstractActionHandlerTest.java
@@ -17,7 +17,7 @@
 package com.android.documentsui;
 
 import static junit.framework.Assert.assertTrue;
-
+import static junit.framework.Assert.fail;
 import static org.junit.Assert.assertEquals;
 
 import android.content.Intent;
@@ -31,8 +31,8 @@
 import com.android.documentsui.base.DocumentStack;
 import com.android.documentsui.base.RootInfo;
 import com.android.documentsui.base.Shared;
-import com.android.documentsui.dirlist.DocumentDetails;
 import com.android.documentsui.files.LauncherActivity;
+import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
 import com.android.documentsui.sorting.SortDimension;
 import com.android.documentsui.sorting.SortModel;
 import com.android.documentsui.testing.DocumentStackAsserts;
@@ -77,8 +77,7 @@
             }
 
             @Override
-            public boolean openDocument(DocumentDetails doc, @ViewType int type,
-                    @ViewType int fallback) {
+            public boolean openItem(ItemDetails doc, @ViewType int type, @ViewType int fallback) {
                 throw new UnsupportedOperationException();
             }
 
@@ -106,7 +105,8 @@
     }
 
     @Test
-    public void testOpensContainerDocuments_jumpToNewLocation() throws Exception {
+    public void testOpensContainerDocuments_OpenFolderInSearch_JumpsToNewLocation()
+            throws Exception {
         if (!mEnv.features.isLaunchToDocumentEnabled()) {
             return;
         }
@@ -114,6 +114,7 @@
         mEnv.populateStack();
 
         mEnv.searchViewManager.isSearching = true;
+        mEnv.docs.nextIsDocumentsUri = true;
         mEnv.docs.nextPath = new Path(
                 TestProvidersAccess.HOME.rootId,
                 Arrays.asList(TestEnv.FOLDER_1.documentId, TestEnv.FOLDER_2.documentId));
@@ -124,15 +125,18 @@
         mEnv.beforeAsserts();
 
         assertEquals(mEnv.docs.nextPath.getPath().size(), mEnv.state.stack.size());
-        assertEquals(TestEnv.FOLDER_2, mEnv.state.stack.peek());
+        assertEquals(TestEnv.FOLDER_2, mEnv.state.stack.pop());
+        assertEquals(TestEnv.FOLDER_1, mEnv.state.stack.pop());
     }
 
 
     @Test
-    public void testOpensContainerDocuments_pushToRootDoc_NoFindPathSupport() throws Exception {
+    public void testOpensContainerDocuments_ClickFolderInSearch_PushToRootDoc_NoFindPathSupport()
+            throws Exception {
         mEnv.populateStack();
 
         mEnv.searchViewManager.isSearching = true;
+        mEnv.docs.nextIsDocumentsUri = true;
         mEnv.docs.nextDocuments = Arrays.asList(TestEnv.FOLDER_1, TestEnv.FOLDER_2);
 
         mHandler.openContainerDocument(TestEnv.FOLDER_2);
@@ -145,15 +149,42 @@
     }
 
     @Test
-    public void testOpensDocument_AssertionErrorIfAlreadyInStack() throws Exception {
+    public void testOpensContainerDocuments_ClickArchiveInSearch_opensArchiveInArchiveProvider()
+            throws Exception {
+        if (!mEnv.features.isLaunchToDocumentEnabled()) {
+            return;
+        }
+
         mEnv.populateStack();
-        boolean threw = false;
+
+        mEnv.searchViewManager.isSearching = true;
+        mEnv.docs.nextIsDocumentsUri = true;
+        mEnv.docs.nextPath = new Path(
+                TestProvidersAccess.HOME.rootId,
+                Arrays.asList(TestEnv.FOLDER_1.documentId, TestEnv.FOLDER_2.documentId,
+                        TestEnv.FILE_ARCHIVE.documentId));
+        mEnv.docs.nextDocuments = Arrays.asList(
+                TestEnv.FOLDER_1, TestEnv.FOLDER_2, TestEnv.FILE_ARCHIVE);
+        mEnv.docs.nextDocument = TestEnv.FILE_IN_ARCHIVE;
+
+        mHandler.openContainerDocument(TestEnv.FILE_ARCHIVE);
+
+        mEnv.beforeAsserts();
+
+        assertEquals(mEnv.docs.nextPath.getPath().size(), mEnv.state.stack.size());
+        assertEquals(TestEnv.FILE_IN_ARCHIVE, mEnv.state.stack.pop());
+        assertEquals(TestEnv.FOLDER_2, mEnv.state.stack.pop());
+        assertEquals(TestEnv.FOLDER_1, mEnv.state.stack.pop());
+    }
+
+    @Test
+    public void testOpensDocument_ExceptionIfAlreadyInStack() throws Exception {
+        mEnv.populateStack();
         try {
             mEnv.state.stack.push(TestEnv.FOLDER_0);
-        } catch (AssertionError e) {
-            threw = true;
+            fail("Should have thrown IllegalArgumentException.");
+        } catch (IllegalArgumentException expected) {
         }
-        assertTrue(threw);
     }
 
     @Test
diff --git a/tests/unit/com/android/documentsui/DocsSelectionHelperTest.java b/tests/unit/com/android/documentsui/DocsSelectionHelperTest.java
new file mode 100644
index 0000000..42f6bb0
--- /dev/null
+++ b/tests/unit/com/android/documentsui/DocsSelectionHelperTest.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2016 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.documentsui;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v7.widget.RecyclerView.Adapter;
+
+import com.android.documentsui.DocsSelectionHelper.DelegateFactory;
+import com.android.documentsui.selection.DefaultSelectionHelper;
+import com.android.documentsui.selection.Selection;
+import com.android.documentsui.selection.SelectionHelper;
+import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
+import com.android.documentsui.selection.SelectionHelper.StableIdProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Tests for the specialized behaviors provided by DocsSelectionManager.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class DocsSelectionHelperTest {
+
+    private DocsSelectionHelper mSelectionMgr;
+    private List<TestSelectionManager> mCreated;
+    private DelegateFactory mFactory;
+
+    @Before
+    public void setup() {
+        mCreated = new ArrayList<>();
+        mFactory = new DelegateFactory() {
+            @Override
+            TestSelectionManager create(
+                    int mode,
+                    Adapter<?> adapter,
+                    StableIdProvider stableIds,
+                    SelectionPredicate canSetState) {
+
+                TestSelectionManager mgr = new TestSelectionManager();
+                mCreated.add(mgr);
+                return mgr;
+            }
+        };
+
+        mSelectionMgr = new DocsSelectionHelper(mFactory, DefaultSelectionHelper.MODE_MULTIPLE);
+    }
+
+    @Test
+    public void testCallableBeforeReset() {
+        mSelectionMgr.hasSelection();
+        assertNotNull(mSelectionMgr.getSelection());
+        assertFalse(mSelectionMgr.isSelected("poodle"));
+    }
+
+    @Test
+    public void testReset_CreatesNewInstances() {
+        mSelectionMgr.reset(null, null, null);  // nulls are passed to factory. We ignore.
+        mSelectionMgr.reset(null, null, null);  // nulls are passed to factory. We ignore.
+
+        assertCreated(2);
+    }
+
+    @Test
+    public void testReset_ClearsPreviousSelection() {
+        mSelectionMgr.reset(null, null, null);  // nulls are passed to factory. We ignore.
+        mSelectionMgr.reset(null, null, null);  // nulls are passed to factory. We ignore.
+
+        mCreated.get(0).assertCleared(true);
+        mCreated.get(1).assertCleared(false);
+    }
+
+    @Test
+    public void testReplaceSelection() {
+        mSelectionMgr.reset(null, null, null);  // nulls are passed to factory. We ignore.
+
+        List<String> ids = new ArrayList<>();
+        ids.add("poodles");
+        ids.add("hammy");
+        mSelectionMgr.replaceSelection(ids);
+        mCreated.get(0).assertCleared(true);
+        mCreated.get(0).assertSelected("poodles", "hammy");
+    }
+
+    void assertCreated(int count) {
+        assertEquals(count, mCreated.size());
+    }
+
+    private static final class TestSelectionManager extends SelectionHelper {
+
+        private boolean mCleared;
+        private Map<String, Boolean> mSelected = new HashMap<>();
+
+        void assertCleared(boolean expected) {
+            assertEquals(expected, mCleared);
+        }
+
+        void assertSelected(String... expected) {
+            for (String id : expected) {
+                assertTrue(mSelected.containsKey(id));
+                assertTrue(mSelected.get(id));
+            }
+            assertEquals(expected.length, mSelected.size());
+        }
+
+        @Override
+        public void addObserver(SelectionObserver listener) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean hasSelection() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Selection getSelection() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void copySelection(Selection dest) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean isSelected(String id) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void restoreSelection(Selection other) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean setItemsSelected(Iterable<String> ids, boolean selected) {
+            for (String id : ids) {
+                mSelected.put(id, selected);
+            }
+            return true;
+        }
+
+        @Override
+        public void clearSelection() {
+            mCleared = true;
+        }
+
+        @Override
+        public boolean select(String itemId) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean deselect(String itemId) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void startRange(int pos) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void extendRange(int pos) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void endRange() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean isRangeActive() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void anchorRange(int position) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void extendProvisionalRange(int pos) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void clearProvisionalSelection() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void mergeProvisionalSelection() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void setProvisionalSelection(Set<String> newSelection) {
+            throw new UnsupportedOperationException();
+        }
+    }
+}
diff --git a/tests/unit/com/android/documentsui/FocusManagerTest.java b/tests/unit/com/android/documentsui/FocusManagerTest.java
index d4d7648..b386f82 100644
--- a/tests/unit/com/android/documentsui/FocusManagerTest.java
+++ b/tests/unit/com/android/documentsui/FocusManagerTest.java
@@ -16,15 +16,17 @@
 
 package com.android.documentsui;
 
+import android.support.v7.widget.RecyclerView;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.documentsui.base.Features;
 import com.android.documentsui.dirlist.TestData;
+import com.android.documentsui.selection.SelectionHelper;
 import com.android.documentsui.testing.TestModel;
-import com.android.documentsui.selection.SelectionManager;
-import com.android.documentsui.testing.SelectionManagers;
+import com.android.documentsui.testing.SelectionHelpers;
 import com.android.documentsui.testing.TestFeatures;
+import com.android.documentsui.testing.TestGridLayoutManager;
 import com.android.documentsui.testing.TestRecyclerView;
 
 import java.util.ArrayList;
@@ -39,13 +41,17 @@
 
     private FocusManager mManager;
     private TestRecyclerView mView;
-    private SelectionManager mSelectionMgr;
+    private TestGridLayoutManager mTestGridLayoutManager;
+    private SelectionHelper mSelectionMgr;
     private TestFeatures mFeatures;
 
     @Override
     public void setUp() throws Exception {
         mView = TestRecyclerView.create(ITEMS);
-        mSelectionMgr = SelectionManagers.createTestInstance(ITEMS);
+        mTestGridLayoutManager = TestGridLayoutManager.create();
+        mView.setLayoutManager(mTestGridLayoutManager);
+
+        mSelectionMgr = SelectionHelpers.createTestInstance(ITEMS);
         mFeatures = new TestFeatures();
         mManager = new FocusManager(mFeatures, mSelectionMgr, null, null, 0)
                 .reset(mView, new TestModel(TEST_AUTHORITY, mFeatures));
@@ -68,13 +74,18 @@
     public void testFocusDirectoryList_noItemsToFocus() {
         mView = TestRecyclerView.create(new ArrayList<>());
         mManager = new FocusManager(
-                mFeatures, SelectionManagers.createTestInstance(), null, null, 0)
+                mFeatures, SelectionHelpers.createTestInstance(), null, null, 0)
                 .reset(mView, new TestModel(TEST_AUTHORITY, mFeatures));
         assertFalse(mManager.focusDirectoryList());
     }
 
+    public void testFocusDirectoryList_noVisibleItems() {
+        mTestGridLayoutManager.setFirstVisibleItemPosition(RecyclerView.NO_POSITION);
+        assertFalse(mManager.focusDirectoryList());
+    }
+
     public void testFocusDirectoryList_hasSelection() {
-        mSelectionMgr.toggleSelection("0");
+        mSelectionMgr.select("0");
         assertFalse(mManager.focusDirectoryList());
     }
 }
diff --git a/tests/unit/com/android/documentsui/SharedInputHandlerTest.java b/tests/unit/com/android/documentsui/SharedInputHandlerTest.java
index 0f5c280..9c28094 100644
--- a/tests/unit/com/android/documentsui/SharedInputHandlerTest.java
+++ b/tests/unit/com/android/documentsui/SharedInputHandlerTest.java
@@ -27,8 +27,8 @@
 
 import com.android.documentsui.base.Procedure;
 import com.android.documentsui.dirlist.TestFocusHandler;
-import com.android.documentsui.selection.SelectionManager;
-import com.android.documentsui.testing.SelectionManagers;
+import com.android.documentsui.selection.SelectionHelper;
+import com.android.documentsui.testing.SelectionHelpers;
 import com.android.documentsui.testing.TestFeatures;
 
 import org.junit.Before;
@@ -40,7 +40,7 @@
 public class SharedInputHandlerTest {
 
     private SharedInputHandler mSharedInputHandler;
-    private SelectionManager mSelectionMgr = SelectionManagers.createTestInstance();
+    private SelectionHelper mSelectionMgr = SelectionHelpers.createTestInstance();
     private TestFeatures mFeatures = new TestFeatures();
     private TestFocusHandler mFocusHandler = new TestFocusHandler();
     private boolean mDirPopHappened;
@@ -75,10 +75,10 @@
 
     @Test
     public void testBackButton_CancelsSearch() {
-        mSelectionMgr.toggleSelection("1");
+        mSelectionMgr.select("1");
         mSharedInputHandler = new SharedInputHandler(
                 new TestFocusHandler(),
-                SelectionManagers.createTestInstance(),
+                SelectionHelpers.createTestInstance(),
                 () -> {
                         mCanceledSearch = true;
                         return true;
@@ -96,7 +96,7 @@
 
     @Test
     public void testBackButton_ClearsSelection() {
-        mSelectionMgr.toggleSelection("1");
+        mSelectionMgr.select("1");
         assertEquals(mSelectionMgr.getSelection().size(), 1);
         KeyEvent backEvent =
                 new KeyEvent(0, 0, MotionEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK, 0, 0);
@@ -120,10 +120,10 @@
 
     @Test
     public void testEscButton_CancelsSearch() {
-        mSelectionMgr.toggleSelection("1");
+        mSelectionMgr.select("1");
         mSharedInputHandler = new SharedInputHandler(
                 new TestFocusHandler(),
-                SelectionManagers.createTestInstance(),
+                SelectionHelpers.createTestInstance(),
                 () -> {
                         mCanceledSearch = true;
                         return true;
@@ -141,7 +141,7 @@
 
     @Test
     public void testEscButton_ClearsSelection() {
-        mSelectionMgr.toggleSelection("1");
+        mSelectionMgr.select("1");
         assertEquals(mSelectionMgr.getSelection().size(), 1);
         KeyEvent escapeEvent =
                 new KeyEvent(0, 0, MotionEvent.ACTION_DOWN, KeyEvent.KEYCODE_ESCAPE, 0, 0);
diff --git a/tests/unit/com/android/documentsui/archives/ArchivesProviderTest.java b/tests/unit/com/android/documentsui/archives/ArchivesProviderTest.java
index 7b2504a..cc40e56 100644
--- a/tests/unit/com/android/documentsui/archives/ArchivesProviderTest.java
+++ b/tests/unit/com/android/documentsui/archives/ArchivesProviderTest.java
@@ -28,11 +28,11 @@
 import android.content.Context;
 import android.database.ContentObserver;
 import android.database.Cursor;
+import android.media.ExifInterface;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
-import android.os.SystemClock;
 import android.provider.DocumentsContract;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
@@ -264,4 +264,35 @@
 
         client.release();
     }
+
+    @Test
+    public void testGetDocumentMetadata() throws InterruptedException, RemoteException {
+        final Uri sourceUri = DocumentsContract.buildDocumentUri(
+                ResourcesProvider.AUTHORITY, "images.zip");
+        final Uri archiveUri = ArchivesProvider.buildUriForArchive(sourceUri,
+                ParcelFileDescriptor.MODE_READ_ONLY);
+
+        final ContentResolver resolver = mContext.getContentResolver();
+        final ContentProviderClient client =
+                resolver.acquireUnstableContentProviderClient(archiveUri);
+
+        ArchivesProvider.acquireArchive(client, archiveUri);
+
+        Uri archivedImageUri = Uri.parse(
+                "content://com.android.documentsui.archives/document/content%3A%2F%2F"
+                + "com.android.documentsui.archives.resourcesprovider%2F"
+                + "document%2Fimages.zip%23268435456%23%2Ffreddy.jpg");
+
+        Bundle metadata = DocumentsContract.getDocumentMetadata(client, archivedImageUri);
+        assertNotNull(metadata);
+        Bundle exif = metadata.getBundle(DocumentsContract.METADATA_EXIF);
+        assertNotNull(exif);
+
+        assertEquals(3036, exif.getInt(ExifInterface.TAG_IMAGE_WIDTH));
+        assertEquals(4048, exif.getInt(ExifInterface.TAG_IMAGE_LENGTH));
+        assertEquals("Pixel", exif.getString(ExifInterface.TAG_MODEL));
+
+        ArchivesProvider.releaseArchive(client, archiveUri);
+        client.release();
+    }
 }
diff --git a/tests/unit/com/android/documentsui/archives/ResourcesProvider.java b/tests/unit/com/android/documentsui/archives/ResourcesProvider.java
index 988b495..b9ddb92 100644
--- a/tests/unit/com/android/documentsui/archives/ResourcesProvider.java
+++ b/tests/unit/com/android/documentsui/archives/ResourcesProvider.java
@@ -56,9 +56,10 @@
     private static final Map<String, Integer> RESOURCES = new HashMap<>();
     static {
         RESOURCES.put("archive.zip", R.raw.archive);
-        RESOURCES.put("empty_dirs.zip", R.raw.empty_dirs);
-        RESOURCES.put("no_dirs.zip", R.raw.no_dirs);
         RESOURCES.put("broken.zip", R.raw.broken);
+        RESOURCES.put("empty_dirs.zip", R.raw.empty_dirs);
+        RESOURCES.put("images.zip", R.raw.images);
+        RESOURCES.put("no_dirs.zip", R.raw.no_dirs);
     }
 
     private ExecutorService mExecutor = null;
diff --git a/tests/unit/com/android/documentsui/dirlist/DirectoryAddonsAdapterTest.java b/tests/unit/com/android/documentsui/dirlist/DirectoryAddonsAdapterTest.java
index 68169bc..c25e43f 100644
--- a/tests/unit/com/android/documentsui/dirlist/DirectoryAddonsAdapterTest.java
+++ b/tests/unit/com/android/documentsui/dirlist/DirectoryAddonsAdapterTest.java
@@ -66,6 +66,17 @@
         assertEquals(mEnv.model.getItemCount() + 1, mAdapter.getItemCount());
     }
 
+    public void testGetPosition() {
+        mEnv.model.createFolder("a");  // id will be "1"...derived from insert position.
+        mEnv.model.createFile("b");  // id will be "2"
+        mEnv.model.update();
+
+        assertEquals(0, mAdapter.getPosition("1"));
+        // adapter inserts a view between item 0 and 1 to force layout
+        // break between folders and files. This is reflected by an offset position.
+        assertEquals(2, mAdapter.getPosition("2"));
+    }
+
     // Tests that the item count is correct for a directory containing only subdirs.
     public void testItemCount_allDirs() {
         String[] names = {"Trader Joe's", "Alphabeta", "Lucky", "Vons", "Gelson's"};
@@ -187,8 +198,11 @@
     }
 
     private static class DummyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
+        @Override
         public int getItemCount() { return 0; }
+        @Override
         public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {}
+        @Override
         public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
             return null;
         }
diff --git a/tests/unit/com/android/documentsui/dirlist/DocumentHolderTest.java b/tests/unit/com/android/documentsui/dirlist/DocumentHolderTest.java
index 9d9256d..f2187e4 100644
--- a/tests/unit/com/android/documentsui/dirlist/DocumentHolderTest.java
+++ b/tests/unit/com/android/documentsui/dirlist/DocumentHolderTest.java
@@ -20,9 +20,9 @@
 import android.database.Cursor;
 import android.graphics.Rect;
 import android.os.SystemClock;
+import android.support.test.filters.SmallTest;
 import android.support.test.filters.Suppress;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -30,6 +30,7 @@
 import android.view.MotionEvent.PointerProperties;
 
 import com.android.documentsui.R;
+import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
 
 @SmallTest
 public class DocumentHolderTest extends AndroidTestCase {
@@ -98,9 +99,9 @@
                 );
     }
 
-    private class TestListener implements DocumentHolder.KeyboardEventListener {
+    private class TestListener extends KeyboardEventListener {
         @Override
-        public boolean onKey(DocumentHolder doc, int keyCode, KeyEvent event) {
+        public boolean onKey(ItemDetails item, int keyCode, KeyEvent event) {
             return false;
         }
 
diff --git a/tests/unit/com/android/documentsui/dirlist/DragHostTest.java b/tests/unit/com/android/documentsui/dirlist/DragHostTest.java
index 4331ac4..7db69dc 100644
--- a/tests/unit/com/android/documentsui/dirlist/DragHostTest.java
+++ b/tests/unit/com/android/documentsui/dirlist/DragHostTest.java
@@ -28,10 +28,10 @@
 
 import com.android.documentsui.base.DocumentInfo;
 import com.android.documentsui.files.TestActivity;
-import com.android.documentsui.selection.SelectionManager;
+import com.android.documentsui.selection.SelectionHelper;
 import com.android.documentsui.testing.ClipDatas;
 import com.android.documentsui.testing.DragEvents;
-import com.android.documentsui.testing.SelectionManagers;
+import com.android.documentsui.testing.SelectionHelpers;
 import com.android.documentsui.testing.TestActionHandler;
 import com.android.documentsui.testing.TestDragAndDropManager;
 import com.android.documentsui.testing.TestEnv;
@@ -55,7 +55,7 @@
     private TestDialogController mDialogs;
     private DragHost<?> dragHost;
     private TestDragAndDropManager mDragAndDropManager;
-    private SelectionManager mSelectionMgr;
+    private SelectionHelper mSelectionMgr;
     private boolean mIsDocumentView;
     private DocumentHolder mNextDocumentHolder;
     private DocumentInfo mNextDocumentInfo;
@@ -66,7 +66,7 @@
         mActivity = TestActivity.create(mEnv);
         mDialogs = new TestDialogController();
         mDragAndDropManager = new TestDragAndDropManager();
-        mSelectionMgr = SelectionManagers.createTestInstance(ITEMS);
+        mSelectionMgr = SelectionHelpers.createTestInstance(ITEMS);
         mActionHandler = new TestActionHandler();
         dragHost = new DragHost<>(
                 mActivity,
diff --git a/tests/unit/com/android/documentsui/dirlist/DragScrollListenerTest.java b/tests/unit/com/android/documentsui/dirlist/DragScrollListenerTest.java
index f779334..f0e9f9a 100644
--- a/tests/unit/com/android/documentsui/dirlist/DragScrollListenerTest.java
+++ b/tests/unit/com/android/documentsui/dirlist/DragScrollListenerTest.java
@@ -24,17 +24,14 @@
 import android.view.View;
 
 import com.android.documentsui.ItemDragListener;
+import com.android.documentsui.selection.ViewAutoScroller.ScrollerCallbacks;
 import com.android.documentsui.testing.DragEvents;
-import com.android.documentsui.testing.TestTimer;
 import com.android.documentsui.testing.Views;
-import com.android.documentsui.ui.ViewAutoScroller.ScrollActionDelegate;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.Timer;
-
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class DragScrollListenerTest {
@@ -204,7 +201,7 @@
         public void onDragEnded() {}
     }
 
-    private class TestScrollActionDelegate implements ScrollActionDelegate {
+    private class TestScrollActionDelegate extends ScrollerCallbacks {
 
         private int mDy;
 
diff --git a/tests/unit/com/android/documentsui/dirlist/DragStartListenerTest.java b/tests/unit/com/android/documentsui/dirlist/DragStartListenerTest.java
index 635e249..faa86a3 100644
--- a/tests/unit/com/android/documentsui/dirlist/DragStartListenerTest.java
+++ b/tests/unit/com/android/documentsui/dirlist/DragStartListenerTest.java
@@ -18,7 +18,7 @@
 
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
-import static junit.framework.TestCase.fail;
+import static junit.framework.Assert.fail;
 
 import android.provider.DocumentsContract;
 import android.support.test.filters.SmallTest;
@@ -26,20 +26,22 @@
 import android.view.MotionEvent;
 import android.view.View;
 
-import com.android.documentsui.MenuManager;
+import com.android.documentsui.DocsSelectionHelper;
 import com.android.documentsui.MenuManager.SelectionDetails;
 import com.android.documentsui.base.DocumentInfo;
+import com.android.documentsui.base.Events;
 import com.android.documentsui.base.Providers;
 import com.android.documentsui.base.State;
-import com.android.documentsui.dirlist.DragStartListener.ActiveListener;
-import com.android.documentsui.base.Events.InputEvent;
-import com.android.documentsui.selection.SelectionManager;
+import com.android.documentsui.dirlist.DragStartListener.RuntimeDragStartListener;
+import com.android.documentsui.selection.MutableSelection;
 import com.android.documentsui.selection.Selection;
+import com.android.documentsui.selection.TestItemDetailsLookup;
+import com.android.documentsui.testing.SelectionHelpers;
 import com.android.documentsui.testing.TestDragAndDropManager;
-import com.android.documentsui.testing.TestEvent;
-import com.android.documentsui.testing.SelectionManagers;
+import com.android.documentsui.testing.TestEvents;
 import com.android.documentsui.testing.TestSelectionDetails;
 import com.android.documentsui.testing.Views;
+import com.android.internal.widget.RecyclerView;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -51,18 +53,20 @@
 @SmallTest
 public class DragStartListenerTest {
 
-    private ActiveListener mListener;
-    private TestEvent.Builder mEvent;
-    private SelectionManager mMultiSelectManager;
+    private RuntimeDragStartListener mListener;
+    private TestEvents.Builder mEvent;
+    private DocsSelectionHelper mSelectionMgr;
+    private TestItemDetailsLookup mDocLookup;
     private SelectionDetails mSelectionDetails;
     private String mViewModelId;
     private TestDragAndDropManager mManager;
 
     @Before
     public void setUp() throws Exception {
-        mMultiSelectManager = SelectionManagers.createTestInstance();
+        mSelectionMgr = SelectionHelpers.createTestInstance();
         mManager = new TestDragAndDropManager();
         mSelectionDetails = new TestSelectionDetails();
+        mDocLookup = new TestItemDetailsLookup();
 
         DocumentInfo doc = new DocumentInfo();
         doc.authority = Providers.AUTHORITY_STORAGE;
@@ -71,10 +75,12 @@
 
         State state = new State();
         state.stack.push(doc);
-        mListener = new DragStartListener.ActiveListener(
+
+        mListener = new DragStartListener.RuntimeDragStartListener(
                 null, // icon helper
                 state,
-                mMultiSelectManager,
+                mDocLookup,
+                mSelectionMgr,
                 mSelectionDetails,
                 // view finder
                 (float x, float y) -> {
@@ -86,21 +92,25 @@
                 },
                 // docInfo Converter
                 (Selection selection) -> {
-                    return new ArrayList<DocumentInfo>();
+                    return new ArrayList<>();
                 },
                 mManager);
 
         mViewModelId = "1234";
 
-        mEvent = TestEvent.builder()
+        mDocLookup.initAt(1).setInItemDragRegion(true);
+        mEvent = TestEvents.builder()
                 .action(MotionEvent.ACTION_MOVE)
                 .mouse()
-                .at(1)
-                .inDragHotspot()
                 .primary();
     }
 
     @Test
+    public void testMouseEvent() {
+        assertTrue(Events.isMouseDragEvent(mEvent.build()));
+    }
+
+    @Test
     public void testDragStarted_OnMouseMove() {
         assertTrue(mListener.onMouseDragEvent(mEvent.build()));
         mManager.startDragHandler.assertCalled();
@@ -115,15 +125,13 @@
 
     @Test
     public void testThrows_OnNonMouseMove() {
-        TestEvent e = TestEvent.builder()
-                .at(1)
-                .action(MotionEvent.ACTION_MOVE).build();
-        assertThrows(e);
+        assertThrows(mEvent.touch().build());
     }
 
     @Test
     public void testThrows_OnNonPrimaryMove() {
-        assertThrows(mEvent.pressButton(MotionEvent.BUTTON_PRIMARY).build());
+        mEvent.releaseButton(MotionEvent.BUTTON_PRIMARY);
+        assertThrows(mEvent.pressButton(MotionEvent.BUTTON_SECONDARY).build());
     }
 
     @Test
@@ -133,7 +141,8 @@
 
     @Test
     public void testThrows_WhenNotOnItem() {
-        assertThrows(mEvent.at(-1).build());
+        mDocLookup.initAt(RecyclerView.NO_POSITION);
+        assertThrows(mEvent.build());
     }
 
     @Test
@@ -146,10 +155,10 @@
 
     @Test
     public void testDragStart_selectedItem() {
-        Selection selection = new Selection();
+        MutableSelection selection = new MutableSelection();
         selection.add("1234");
         selection.add("5678");
-        mMultiSelectManager.replaceSelection(selection);
+        mSelectionMgr.replaceSelection(selection);
 
         selection = mListener.getSelectionToBeCopied("1234",
                 mEvent.action(MotionEvent.ACTION_MOVE).build());
@@ -160,23 +169,23 @@
 
     @Test
     public void testDragStart_newNonSelectedItem() {
-        Selection selection = new Selection();
+        MutableSelection selection = new MutableSelection();
         selection.add("5678");
-        mMultiSelectManager.replaceSelection(selection);
+        mSelectionMgr.replaceSelection(selection);
 
         selection = mListener.getSelectionToBeCopied("1234",
                 mEvent.action(MotionEvent.ACTION_MOVE).build());
         assertTrue(selection.size() == 1);
         assertTrue(selection.contains("1234"));
         // After this, selection should be cleared
-        assertFalse(mMultiSelectManager.hasSelection());
+        assertFalse(mSelectionMgr.hasSelection());
     }
 
     @Test
     public void testCtrlDragStart_newNonSelectedItem() {
-        Selection selection = new Selection();
+        MutableSelection selection = new MutableSelection();
         selection.add("5678");
-        mMultiSelectManager.replaceSelection(selection);
+        mSelectionMgr.replaceSelection(selection);
 
         selection = mListener.getSelectionToBeCopied("1234",
                 mEvent.action(MotionEvent.ACTION_MOVE).ctrl().build());
@@ -185,10 +194,10 @@
         assertTrue(selection.contains("5678"));
     }
 
-    private void assertThrows(InputEvent e) {
+    private void assertThrows(MotionEvent e) {
         try {
-            assertFalse(mListener.onMouseDragEvent(e));
+            mListener.onMouseDragEvent(e);
             fail();
-        } catch (AssertionError expected) {}
+        } catch (IllegalArgumentException expected) {}
     }
 }
diff --git a/tests/unit/com/android/documentsui/dirlist/KeyInputHandlerTest.java b/tests/unit/com/android/documentsui/dirlist/KeyInputHandlerTest.java
new file mode 100644
index 0000000..fdf9a59
--- /dev/null
+++ b/tests/unit/com/android/documentsui/dirlist/KeyInputHandlerTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2016 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.documentsui.dirlist;
+
+import static org.junit.Assert.assertEquals;
+
+import android.support.annotation.Nullable;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.KeyEvent;
+
+import com.android.documentsui.selection.SelectionHelper;
+import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
+import com.android.documentsui.selection.testing.SelectionPredicates;
+import com.android.documentsui.selection.testing.SelectionProbe;
+import com.android.documentsui.selection.testing.TestData;
+import com.android.documentsui.testing.SelectionHelpers;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public final class KeyInputHandlerTest {
+
+    private static final List<String> ITEMS = TestData.create(100);
+
+    private KeyInputHandler mInputHandler;
+    private SelectionHelper mSelectionHelper;
+    private TestFocusHandler mFocusHandler;
+    private SelectionProbe mSelection;
+    private TestCallbacks mCallbacks;
+
+    @Before
+    public void setUp() {
+        mSelectionHelper = SelectionHelpers.createTestInstance(ITEMS);
+        mSelection = new SelectionProbe(mSelectionHelper);
+        mFocusHandler = new TestFocusHandler();
+        mCallbacks = new TestCallbacks();
+
+        mInputHandler = new KeyInputHandler(
+                mSelectionHelper,
+                SelectionPredicates.CAN_SET_ANYTHING,
+                mCallbacks);
+    }
+
+    @Test
+    public void testArrowKey_nonShiftClearsSelection() {
+        mSelectionHelper.select("11");
+
+        mFocusHandler.handleKey = true;
+        KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP);
+        mInputHandler.onKey(null, event.getKeyCode(), event);
+
+        mSelection.assertNoSelection();
+    }
+
+    private static final class TestCallbacks extends KeyInputHandler.Callbacks {
+
+        private @Nullable ItemDetails mActivated;
+
+        @Override
+        public boolean isInteractiveItem(ItemDetails item, KeyEvent e) {
+            return true;
+        }
+
+        @Override
+        public boolean onItemActivated(ItemDetails item, KeyEvent e) {
+            mActivated = item;
+            return false;
+        }
+
+        private void assertActivated(ItemDetails expected) {
+            assertEquals(expected, mActivated);
+        }
+
+        @Override
+        public void onPerformHapticFeedback() {
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/unit/com/android/documentsui/dirlist/UserInputHandler_KeyboardTest.java b/tests/unit/com/android/documentsui/dirlist/UserInputHandler_KeyboardTest.java
deleted file mode 100644
index 97dd027..0000000
--- a/tests/unit/com/android/documentsui/dirlist/UserInputHandler_KeyboardTest.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.dirlist;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-
-import com.android.documentsui.base.Events.InputEvent;
-import com.android.documentsui.selection.SelectionManager;
-import com.android.documentsui.selection.SelectionProbe;
-import com.android.documentsui.testing.SelectionManagers;
-import com.android.documentsui.testing.TestActionHandler;
-import com.android.documentsui.testing.TestEvent;
-import com.android.documentsui.testing.TestEvent.Builder;
-import com.android.documentsui.testing.TestEventHandler;
-import com.android.documentsui.testing.TestPredicate;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public final class UserInputHandler_KeyboardTest {
-
-    private static final List<String> ITEMS = TestData.create(100);
-
-    private UserInputHandler<TestEvent> mInputHandler;
-    private TestActionHandler mActionHandler;
-    private TestFocusHandler mFocusHandler;
-    private SelectionProbe mSelection;
-
-    private TestPredicate<DocumentDetails> mCanSelect;
-    private TestEventHandler<InputEvent> mRightClickHandler;
-    private TestEventHandler<InputEvent> mDragAndDropHandler;
-    private TestEventHandler<InputEvent> mGestureSelectHandler;
-    private TestEventHandler<Void> mPerformHapticFeedback;
-
-    private Builder mEvent;
-
-    @Before
-    public void setUp() {
-        SelectionManager selectionMgr = SelectionManagers.createTestInstance(ITEMS);
-
-        mActionHandler = new TestActionHandler();
-        mSelection = new SelectionProbe(selectionMgr);
-        mFocusHandler = new TestFocusHandler();
-        mCanSelect = new TestPredicate<>();
-        mRightClickHandler = new TestEventHandler<>();
-        mDragAndDropHandler = new TestEventHandler<>();
-        mGestureSelectHandler = new TestEventHandler<>();
-
-        mInputHandler = new UserInputHandler<>(
-                mActionHandler,
-                mFocusHandler,
-                selectionMgr,
-                (MotionEvent event) -> {
-                    throw new UnsupportedOperationException("Not exercised in tests.");
-                },
-                mCanSelect,
-                mRightClickHandler::accept,
-                mDragAndDropHandler::accept,
-                mGestureSelectHandler::accept,
-                () -> mPerformHapticFeedback.accept(null));
-
-        mEvent = TestEvent.builder().mouse().overDocIcon();
-    }
-
-    @Test
-    public void testArrowKey_nonShiftClearsSelection() {
-        mInputHandler.onSingleTapConfirmed(mEvent.at(11).build());
-        mSelection.assertSelection(11);
-
-        mFocusHandler.handleKey = true;
-        KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP);
-        mInputHandler.onKey(null, event.getKeyCode(), event);
-
-        mSelection.assertNoSelection();
-    }
-}
\ No newline at end of file
diff --git a/tests/unit/com/android/documentsui/dirlist/UserInputHandler_MouseTest.java b/tests/unit/com/android/documentsui/dirlist/UserInputHandler_MouseTest.java
deleted file mode 100644
index 2c916c6..0000000
--- a/tests/unit/com/android/documentsui/dirlist/UserInputHandler_MouseTest.java
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.dirlist;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v7.widget.RecyclerView;
-import android.view.MotionEvent;
-
-import com.android.documentsui.base.Events.InputEvent;
-import com.android.documentsui.selection.SelectionManager;
-import com.android.documentsui.selection.SelectionProbe;
-import com.android.documentsui.testing.SelectionManagers;
-import com.android.documentsui.testing.TestActionHandler;
-import com.android.documentsui.testing.TestEvent;
-import com.android.documentsui.testing.TestEvent.Builder;
-import com.android.documentsui.testing.TestEventHandler;
-import com.android.documentsui.testing.TestPredicate;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public final class UserInputHandler_MouseTest {
-
-    private static final List<String> ITEMS = TestData.create(100);
-
-    private UserInputHandler<TestEvent> mInputHandler;
-    private TestActionHandler mActionHandler;
-    private TestFocusHandler mFocusHandler;
-    private SelectionProbe mSelection;
-    private SelectionManager mSelectionMgr;
-    private TestPredicate<DocumentDetails> mCanSelect;
-    private TestEventHandler<InputEvent> mContextMenuClickHandler;
-    private TestEventHandler<InputEvent> mDragAndDropHandler;
-    private TestEventHandler<InputEvent> mGestureSelectHandler;
-    private TestEventHandler<Void> mPerformHapticFeedback;
-
-    private Builder mEvent;
-
-    @Before
-    public void setUp() {
-
-        mSelectionMgr = SelectionManagers.createTestInstance(ITEMS);
-        mActionHandler = new TestActionHandler();
-
-        mSelection = new SelectionProbe(mSelectionMgr);
-        mCanSelect = new TestPredicate<>();
-        mContextMenuClickHandler = new TestEventHandler<>();
-        mDragAndDropHandler = new TestEventHandler<>();
-        mGestureSelectHandler = new TestEventHandler<>();
-        mFocusHandler = new TestFocusHandler();
-
-        mInputHandler = new UserInputHandler<>(
-                mActionHandler,
-                mFocusHandler,
-                mSelectionMgr,
-                (MotionEvent event) -> {
-                    throw new UnsupportedOperationException("Not exercised in tests.");
-                },
-                mCanSelect,
-                mContextMenuClickHandler::accept,
-                mDragAndDropHandler::accept,
-                mGestureSelectHandler::accept,
-                () -> mPerformHapticFeedback.accept(null));
-
-        mEvent = TestEvent.builder().mouse().overDocIcon();
-    }
-
-    @Test
-    public void testConfirmedClick_StartsSelection() {
-        mInputHandler.onSingleTapConfirmed(mEvent.at(11).build());
-        mSelection.assertSelection(11);
-    }
-
-    @Test
-    public void testClickOnIconWithExistingSelection_AddsToSelection() {
-        mInputHandler.onSingleTapConfirmed(mEvent.at(11).build());
-        mInputHandler.onSingleTapUp(mEvent.at(10).build());
-        mSelection.assertSelected(10, 11);
-    }
-
-    @Test
-    public void testClickOnIconOfSelectedItem_RemovesFromSelection() {
-        mInputHandler.onSingleTapConfirmed(mEvent.at(8).build());
-        mInputHandler.onSingleTapUp(mEvent.at(11).shift().build());
-        mSelection.assertSelected(8, 9, 10, 11);
-
-        mInputHandler.onSingleTapUp(mEvent.at(9).unshift().build());
-        mSelection.assertSelected(8, 10, 11);
-    }
-
-    @Test
-    public void testRightClickDown_StartsContextMenu() {
-        mInputHandler.onDown(mEvent.secondary().build());
-        mContextMenuClickHandler.assertLastArgument(mEvent.secondary().build());
-    }
-
-    @Test
-    public void testAltClickDown_StartsContextMenu() {
-        mInputHandler.onDown(mEvent.primary().alt().build());
-        mContextMenuClickHandler.assertLastArgument(mEvent.primary().alt().build());
-    }
-
-    @Test
-    public void testScroll_shouldTrap() {
-        assertTrue(mInputHandler.onScroll(mEvent.at(0).action(MotionEvent.ACTION_MOVE).primary().build()));
-    }
-
-    @Test
-    public void testScroll_NoTrapForTwoFinger() {
-        assertFalse(mInputHandler.onScroll(mEvent.at(0).action(MotionEvent.ACTION_MOVE).build()));
-    }
-
-    @Test
-    public void testUnconfirmedCtrlClick_AddsToExistingSelection() {
-        mInputHandler.onSingleTapConfirmed(mEvent.at(7).build());
-
-        mInputHandler.onSingleTapUp(mEvent.at(11).ctrl().build());
-        mSelection.assertSelection(7, 11);
-    }
-
-    @Test
-    public void testUnconfirmedShiftClick_ExtendsSelection() {
-        mInputHandler.onSingleTapConfirmed(mEvent.at(7).build());
-
-        mInputHandler.onSingleTapUp(mEvent.at(11).shift().build());
-        mSelection.assertSelection(7, 8, 9, 10, 11);
-    }
-
-    @Test
-    public void testConfirmedShiftClick_ExtendsSelectionFromOriginFocus() {
-        mFocusHandler.focusPos = 7;
-        mFocusHandler.focusModelId = "7";
-        // This is a hack-y test, since the real FocusManager would've set range begin itself.
-        mSelectionMgr.setSelectionRangeBegin(7);
-        mSelection.assertNoSelection();
-
-        mInputHandler.onSingleTapConfirmed(mEvent.at(11).shift().build());
-        mSelection.assertSelection(7, 8, 9, 10, 11);
-    }
-
-    @Test
-    public void testUnconfirmedShiftClick_RotatesAroundOrigin() {
-        mInputHandler.onSingleTapConfirmed(mEvent.at(7).build());
-
-        mInputHandler.onSingleTapUp(mEvent.at(11).shift().build());
-        mSelection.assertSelection(7, 8, 9, 10, 11);
-
-        mInputHandler.onSingleTapUp(mEvent.at(5).shift().build());
-        mSelection.assertSelection(5, 6, 7);
-        mSelection.assertNotSelected(8, 9, 10, 11);
-    }
-
-    @Test
-    public void testUnconfirmedShiftCtrlClick_Combination() {
-        mInputHandler.onSingleTapConfirmed(mEvent.at(7).build());
-
-        mInputHandler.onSingleTapUp(mEvent.at(11).shift().build());
-        mSelection.assertSelection(7, 8, 9, 10, 11);
-
-        mInputHandler.onSingleTapUp(mEvent.at(5).unshift().ctrl().build());
-
-        mSelection.assertSelection(5, 7, 8, 9, 10, 11);
-    }
-
-    @Test
-    public void testUnconfirmedShiftCtrlClick_ShiftTakesPriority() {
-        mInputHandler.onSingleTapConfirmed(mEvent.at(7).build());
-
-        mInputHandler.onSingleTapUp(mEvent.at(11).ctrl().shift().build());
-        mSelection.assertSelection(7, 8, 9, 10, 11);
-    }
-
-    // TODO: Add testSpaceBar_Previews, but we need to set a system property
-    // to have a deterministic state.
-
-    @Test
-    public void testDoubleClick_Opens() {
-        mInputHandler.onDoubleTap(mEvent.at(11).build());
-        mActionHandler.open.assertLastArgument(mEvent.build().getDocumentDetails());
-    }
-
-    @Test
-    public void testMiddleClick_DoesNothing() {
-        mInputHandler.onSingleTapConfirmed(mEvent.at(11).tertiary().build());
-        mSelection.assertNoSelection();
-    }
-
-    @Test
-    public void testClickOff_ClearsSelection() {
-        mInputHandler.onSingleTapConfirmed(mEvent.at(11).build());
-        mInputHandler.onSingleTapUp(mEvent.at(RecyclerView.NO_POSITION).build());
-        mSelection.assertNoSelection();
-    }
-
-    @Test
-    public void testClick_Focuses() {
-        int id = 11;
-        mInputHandler.onSingleTapConfirmed(mEvent.at(id).notOverDocIcon().build());
-        assertTrue(mFocusHandler.getFocusModelId().equals(Integer.toString(id)));
-    }
-
-    @Test
-    public void testClickOff_ClearsFocus() {
-        int id = 11;
-        mInputHandler.onSingleTapConfirmed(mEvent.at(id).notOverDocIcon().build());
-        assertTrue(mFocusHandler.hasFocusedItem());
-        mInputHandler.onSingleTapUp(mEvent.at(RecyclerView.NO_POSITION).build());
-        assertFalse(mFocusHandler.hasFocusedItem());
-    }
-
-    @Test
-    public void testClickOffSelection_RemovesSelectionAndFocuses() {
-        mInputHandler.onSingleTapConfirmed(mEvent.at(1).build());
-        mInputHandler.onSingleTapUp(mEvent.at(5).shift().build());
-        mSelection.assertSelection(1, 2, 3, 4, 5);
-
-        int id = 11;
-        mInputHandler.onSingleTapUp(mEvent.at(id).unshift().notOverDocIcon().build());
-        assertTrue(mFocusHandler.getFocusModelId().equals(Integer.toString(id)));
-        mSelection.assertNoSelection();
-    }
-}
diff --git a/tests/unit/com/android/documentsui/dirlist/UserInputHandler_RangeTest.java b/tests/unit/com/android/documentsui/dirlist/UserInputHandler_RangeTest.java
deleted file mode 100644
index 7ce85e1..0000000
--- a/tests/unit/com/android/documentsui/dirlist/UserInputHandler_RangeTest.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.dirlist;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.view.MotionEvent;
-
-import com.android.documentsui.base.Events.InputEvent;
-import com.android.documentsui.selection.SelectionManager;
-import com.android.documentsui.selection.SelectionProbe;
-import com.android.documentsui.testing.SelectionManagers;
-import com.android.documentsui.testing.TestActionHandler;
-import com.android.documentsui.testing.TestEvent;
-import com.android.documentsui.testing.TestEvent.Builder;
-import com.android.documentsui.testing.TestEventHandler;
-import com.android.documentsui.testing.TestPredicate;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-
-/**
- * UserInputHandler / MultiSelectManager integration test covering the shared
- * responsibility of range selection.
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public final class UserInputHandler_RangeTest {
-
-    private static final List<String> ITEMS = TestData.create(100);
-
-    private UserInputHandler<TestEvent> mInputHandler;
-    private TestActionHandler mActionHandler;
-
-    private SelectionProbe mSelection;
-    private TestFocusHandler mFocusHandler;
-    private TestPredicate<DocumentDetails> mCanSelect;
-    private TestEventHandler<InputEvent> mRightClickHandler;
-    private TestEventHandler<InputEvent> mDragAndDropHandler;
-    private TestEventHandler<InputEvent> mGestureSelectHandler;
-    private TestEventHandler<Void> mPerformHapticFeedback;
-    private Builder mEvent;
-
-    @Before
-    public void setUp() {
-
-        SelectionManager selectionMgr = SelectionManagers.createTestInstance(ITEMS);
-        mActionHandler = new TestActionHandler();
-        mFocusHandler = new TestFocusHandler();
-        mSelection = new SelectionProbe(selectionMgr);
-        mCanSelect = new TestPredicate<>();
-        mRightClickHandler = new TestEventHandler<>();
-        mDragAndDropHandler = new TestEventHandler<>();
-        mGestureSelectHandler = new TestEventHandler<>();
-
-        mInputHandler = new UserInputHandler<>(
-                mActionHandler,
-                mFocusHandler,
-                selectionMgr,
-                (MotionEvent event) -> {
-                    throw new UnsupportedOperationException("Not exercised in tests.");
-                },
-                mCanSelect,
-                mRightClickHandler::accept,
-                mDragAndDropHandler::accept,
-                mGestureSelectHandler::accept,
-                () -> mPerformHapticFeedback.accept(null));
-
-        mEvent = TestEvent.builder().mouse().overDocIcon();
-    }
-
-    @Test
-    public void testExtendRange() {
-        mInputHandler.onSingleTapConfirmed(mEvent.at(7).build());
-        mInputHandler.onSingleTapUp(mEvent.at(11).shift().build());
-        mSelection.assertRangeSelection(7, 11);
-    }
-
-    @Test
-    public void testExtendRangeContinues() {
-        mInputHandler.onSingleTapConfirmed(mEvent.at(7).build());
-        mInputHandler.onSingleTapUp(mEvent.at(11).shift().build());
-        mInputHandler.onSingleTapUp(mEvent.at(21).shift().build());
-        mSelection.assertRangeSelection(7, 21);
-    }
-
-    @Test
-    public void testMultipleContiguousRanges() {
-        mInputHandler.onSingleTapConfirmed(mEvent.at(7).build());
-        mInputHandler.onSingleTapUp(mEvent.at(11).shift().build());
-
-        // click without shift sets a new range start point.
-        mInputHandler.onSingleTapUp(mEvent.at(20).unshift().notOverDocIcon().build());
-        mInputHandler.onSingleTapConfirmed(mEvent.at(20).notOverDocIcon().build());
-        mFocusHandler.focusPos = 20;
-        mInputHandler.onSingleTapUp(mEvent.at(25).shift().notOverDocIcon().build());
-        mInputHandler.onSingleTapConfirmed(mEvent.at(25).shift().notOverDocIcon().build());
-
-        mSelection.assertRangeNotSelected(7, 11);
-        mSelection.assertRangeSelected(20, 25);
-        mSelection.assertSelectionSize(6);
-    }
-
-    @Test
-    public void testReducesSelectionRange() {
-        mInputHandler.onSingleTapConfirmed(mEvent.at(7).build());
-        mInputHandler.onSingleTapUp(mEvent.at(17).shift().build());
-        mInputHandler.onSingleTapUp(mEvent.at(10).shift().build());
-        mSelection.assertRangeSelection(7, 10);
-    }
-
-    @Test
-    public void testReducesSelectionRange_Reverse() {
-        mInputHandler.onSingleTapConfirmed(mEvent.at(17).build());
-        mInputHandler.onSingleTapUp(mEvent.at(7).shift().build());
-        mInputHandler.onSingleTapUp(mEvent.at(14).shift().build());
-        mSelection.assertRangeSelection(14, 17);
-    }
-
-    @Test
-    public void testExtendsRange_Reverse() {
-        mInputHandler.onSingleTapConfirmed(mEvent.at(12).build());
-        mInputHandler.onSingleTapUp(mEvent.at(5).shift().build());
-        mSelection.assertRangeSelection(5, 12);
-    }
-
-    @Test
-    public void testExtendsRange_ReversesAfterForwardClick() {
-        mInputHandler.onSingleTapConfirmed(mEvent.at(7).build());
-        mInputHandler.onSingleTapUp(mEvent.at(11).shift().build());
-        mInputHandler.onSingleTapUp(mEvent.at(0).shift().build());
-        mSelection.assertRangeSelection(0, 7);
-    }
-
-    @Test
-    public void testRightClickEstablishesRange() {
-
-        TestEvent fistClick = mEvent.at(7).secondary().build();
-        mInputHandler.onDown(fistClick);
-        // This next method call simulates the behavior of the system event dispatch code.
-        // UserInputHandler depends on a specific sequence of events for internal
-        // state to remain valid. It's not an awesome arrangement, but it is currently
-        // necessary.
-        //
-        // See: UserInputHandler.MouseDelegate#mHandledOnDown;
-        mInputHandler.onSingleTapUp(fistClick);
-
-        // Now we can send a subsequent event that should extend selection.
-        TestEvent secondClick = mEvent.at(11).primary().shift().build();
-        mInputHandler.onDown(secondClick);
-        mInputHandler.onSingleTapUp(secondClick);
-
-        mSelection.assertRangeSelection(7, 11);
-    }
-}
diff --git a/tests/unit/com/android/documentsui/dirlist/UserInputHandler_TouchTest.java b/tests/unit/com/android/documentsui/dirlist/UserInputHandler_TouchTest.java
deleted file mode 100644
index 86d49d0..0000000
--- a/tests/unit/com/android/documentsui/dirlist/UserInputHandler_TouchTest.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.dirlist;
-
-import static org.junit.Assert.assertFalse;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v7.widget.RecyclerView;
-import android.view.MotionEvent;
-
-import com.android.documentsui.base.Events.InputEvent;
-import com.android.documentsui.selection.SelectionManager;
-import com.android.documentsui.selection.SelectionProbe;
-import com.android.documentsui.testing.SelectionManagers;
-import com.android.documentsui.testing.TestActionHandler;
-import com.android.documentsui.testing.TestEvent;
-import com.android.documentsui.testing.TestEvent.Builder;
-import com.android.documentsui.testing.TestEventHandler;
-import com.android.documentsui.testing.TestPredicate;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public final class UserInputHandler_TouchTest {
-
-    private static final List<String> ITEMS = TestData.create(100);
-
-    private UserInputHandler<TestEvent> mInputHandler;
-    private TestActionHandler mActionHandler;
-
-    private SelectionProbe mSelection;
-    private TestPredicate<DocumentDetails> mCanSelect;
-    private TestEventHandler<InputEvent> mRightClickHandler;
-    private TestEventHandler<InputEvent> mDragAndDropHandler;
-    private TestEventHandler<InputEvent> mGestureSelectHandler;
-    private TestEventHandler<Void> mPerformHapticFeedback;
-
-    private Builder mEvent;
-
-    @Before
-    public void setUp() {
-        SelectionManager selectionMgr = SelectionManagers.createTestInstance(ITEMS);
-
-        mActionHandler = new TestActionHandler();
-
-        mSelection = new SelectionProbe(selectionMgr);
-        mCanSelect = new TestPredicate<>();
-        mRightClickHandler = new TestEventHandler<>();
-        mDragAndDropHandler = new TestEventHandler<>();
-        mGestureSelectHandler = new TestEventHandler<>();
-        mPerformHapticFeedback = new TestEventHandler<>();
-
-        mInputHandler = new UserInputHandler<>(
-                mActionHandler,
-                new TestFocusHandler(),
-                selectionMgr,
-                (MotionEvent event) -> {
-                    throw new UnsupportedOperationException("Not exercised in tests.");
-                },
-                mCanSelect,
-                mRightClickHandler::accept,
-                mDragAndDropHandler::accept,
-                mGestureSelectHandler::accept,
-                () -> mPerformHapticFeedback.accept(null));
-
-        mEvent = TestEvent.builder();
-    }
-
-    @Test
-    public void testTap_ActivatesWhenNoExistingSelection() {
-        mInputHandler.onSingleTapUp(mEvent.at(11).build());
-        mActionHandler.open.assertLastArgument(mEvent.build().getDocumentDetails());
-    }
-
-    @Test
-    public void testScroll_shouldNotBeTrapped() {
-        assertFalse(mInputHandler.onScroll(mEvent.build()));
-    }
-
-    @Test
-    public void testLongPress_StartsSelectionMode() {
-        mCanSelect.nextReturn(true);
-        TestEvent event = mEvent.at(7).build();
-        mInputHandler.onLongPress(event);
-        mSelection.assertSelection(7);
-        mPerformHapticFeedback.assertCalled();
-    }
-
-    @Test
-    public void testLongPress_SecondPressAddsSelection() {
-        mCanSelect.nextReturn(true);
-        TestEvent event1 = mEvent.at(7).build();
-        TestEvent event2 = mEvent.at(99).build();
-        TestEvent event3 = mEvent.at(13).build();
-        mInputHandler.onLongPress(event1);
-        mPerformHapticFeedback.assertCalled();
-        mPerformHapticFeedback.reset();
-        mInputHandler.onLongPress(event2);
-        mPerformHapticFeedback.assertCalled();
-        mPerformHapticFeedback.reset();
-        mInputHandler.onLongPress(event3);
-        mPerformHapticFeedback.assertCalled();
-        mPerformHapticFeedback.reset();
-        mSelection.assertSelection(7, 13, 99);
-    }
-
-    @Test
-    public void testTap_UnselectsSelectedItem() {
-        mInputHandler.onLongPress(mEvent.at(7).build());
-        mInputHandler.onSingleTapUp(mEvent.at(7).build());
-        mSelection.assertNoSelection();
-    }
-
-    @Test
-    public void testTapOff_ClearsSelection() {
-        mInputHandler.onLongPress(mEvent.at(7).build());
-        mInputHandler.onSingleTapUp(mEvent.at(11).build());
-        mInputHandler.onSingleTapUp(mEvent.at(RecyclerView.NO_POSITION).build());
-        mSelection.assertNoSelection();
-    }
-}
diff --git a/tests/unit/com/android/documentsui/files/ActionHandlerTest.java b/tests/unit/com/android/documentsui/files/ActionHandlerTest.java
index 9b35ee1..34c3142 100644
--- a/tests/unit/com/android/documentsui/files/ActionHandlerTest.java
+++ b/tests/unit/com/android/documentsui/files/ActionHandlerTest.java
@@ -17,9 +17,12 @@
 package com.android.documentsui.files;
 
 import static com.android.documentsui.testing.IntentAsserts.assertHasAction;
+import static com.android.documentsui.testing.IntentAsserts.assertHasData;
+import static com.android.documentsui.testing.IntentAsserts.assertHasExtra;
 import static com.android.documentsui.testing.IntentAsserts.assertHasExtraIntent;
 import static com.android.documentsui.testing.IntentAsserts.assertHasExtraList;
 import static com.android.documentsui.testing.IntentAsserts.assertHasExtraUri;
+import static com.android.documentsui.testing.IntentAsserts.assertTargetsComponent;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -35,8 +38,8 @@
 import android.os.Parcelable;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Path;
-import android.support.test.filters.MediumTest;
 import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.util.Pair;
 import android.view.DragEvent;
@@ -49,6 +52,7 @@
 import com.android.documentsui.base.DocumentStack;
 import com.android.documentsui.base.RootInfo;
 import com.android.documentsui.base.Shared;
+import com.android.documentsui.inspector.InspectorActivity;
 import com.android.documentsui.testing.ClipDatas;
 import com.android.documentsui.testing.DocumentStackAsserts;
 import com.android.documentsui.testing.Roots;
@@ -56,8 +60,10 @@
 import com.android.documentsui.testing.TestDocumentClipper;
 import com.android.documentsui.testing.TestDragAndDropManager;
 import com.android.documentsui.testing.TestEnv;
+import com.android.documentsui.testing.TestFeatures;
 import com.android.documentsui.testing.TestProvidersAccess;
 import com.android.documentsui.ui.TestDialogController;
+import com.android.internal.util.Preconditions;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -76,11 +82,13 @@
     private ActionHandler<TestActivity> mHandler;
     private TestDocumentClipper mClipper;
     private TestDragAndDropManager mDragAndDropManager;
+    private TestFeatures mFeatures;
     private boolean refreshAnswer = false;
 
     @Before
     public void setUp() {
-        mEnv = TestEnv.create();
+        mFeatures = new TestFeatures();
+        mEnv = TestEnv.create(mFeatures);
         mActivity = TestActivity.create(mEnv);
         mActionModeAddons = new TestActionModeAddons();
         mDialogs = new TestDialogController();
@@ -326,6 +334,15 @@
     }
 
     @Test
+    public void testDocumentPicked_Home_SendsActionViewForApks() throws Exception {
+        mActivity.currentRoot = TestProvidersAccess.HOME;
+
+        mHandler.openDocument(TestEnv.FILE_APK, ActionHandler.VIEW_TYPE_PREVIEW,
+                ActionHandler.VIEW_TYPE_REGULAR);
+        mActivity.assertActivityStarted(Intent.ACTION_VIEW);
+    }
+
+    @Test
     public void testDocumentPicked_Downloads_ManagesPartialFiles() throws Exception {
         mActivity.currentRoot = TestProvidersAccess.DOWNLOADS;
 
@@ -534,6 +551,78 @@
         mActivity.refreshCurrentRootAndDirectory.assertNotCalled();
     }
 
+    @Test
+    public void testShowInspector() throws Exception {
+        mHandler.showInspector(TestEnv.FILE_GIF);
+
+        mActivity.startActivity.assertCalled();
+        Intent intent = mActivity.startActivity.getLastValue();
+        assertTargetsComponent(intent, InspectorActivity.class);
+        assertHasData(intent, TestEnv.FILE_GIF.derivedUri);
+
+        // should only send this under especial circumstances. See test below.
+        assertFalse(intent.getExtras().containsKey(Intent.EXTRA_TITLE));
+    }
+
+    @Test
+    public void testShowInspector_DebugDisabled() throws Exception {
+        mFeatures.debugSupport = false;
+
+        mHandler.showInspector(TestEnv.FILE_GIF);
+        Intent intent = mActivity.startActivity.getLastValue();
+
+        assertHasExtra(intent, Shared.EXTRA_SHOW_DEBUG);
+        assertFalse(intent.getExtras().getBoolean(Shared.EXTRA_SHOW_DEBUG));
+    }
+
+    @Test
+    public void testShowInspector_DebugEnabled() throws Exception {
+        mFeatures.debugSupport = true;
+
+        mHandler.showInspector(TestEnv.FILE_GIF);
+        Intent intent = mActivity.startActivity.getLastValue();
+
+        assertHasExtra(intent, Shared.EXTRA_SHOW_DEBUG);
+        assertTrue(intent.getExtras().getBoolean(Shared.EXTRA_SHOW_DEBUG));
+    }
+
+    @Test
+    public void testShowInspector_OverridesRootDocumentName() throws Exception {
+        mActivity.currentRoot = TestProvidersAccess.PICKLES;
+        mEnv.populateStack();
+
+        // Verify test setup is correct, but not an assert related to the logic of our test.
+        Preconditions.checkState(mEnv.state.stack.size() == 1);
+        Preconditions.checkNotNull(mEnv.state.stack.peek());
+
+        DocumentInfo rootDoc = mEnv.state.stack.peek();
+        rootDoc.displayName = "poodles";
+
+        mHandler.showInspector(rootDoc);
+        Intent intent = mActivity.startActivity.getLastValue();
+        assertEquals(
+                TestProvidersAccess.PICKLES.title,
+                intent.getExtras().getString(Intent.EXTRA_TITLE));
+    }
+
+    @Test
+    public void testShowInspector_OverridesRootDocumentNameX() throws Exception {
+        mActivity.currentRoot = TestProvidersAccess.PICKLES;
+        mEnv.populateStack();
+        mEnv.state.stack.push(TestEnv.FOLDER_2);
+
+        // Verify test setup is correct, but not an assert related to the logic of our test.
+        Preconditions.checkState(mEnv.state.stack.size() == 2);
+        Preconditions.checkNotNull(mEnv.state.stack.peek());
+
+        DocumentInfo rootDoc = mEnv.state.stack.peek();
+        rootDoc.displayName = "poodles";
+
+        mHandler.showInspector(rootDoc);
+        Intent intent = mActivity.startActivity.getLastValue();
+        assertFalse(intent.getExtras().containsKey(Intent.EXTRA_TITLE));
+    }
+
     private void assertRootPicked(Uri expectedUri) throws Exception {
         mEnv.beforeAsserts();
 
diff --git a/tests/unit/com/android/documentsui/files/MenuManagerTest.java b/tests/unit/com/android/documentsui/files/MenuManagerTest.java
index 3420210..c30d572 100644
--- a/tests/unit/com/android/documentsui/files/MenuManagerTest.java
+++ b/tests/unit/com/android/documentsui/files/MenuManagerTest.java
@@ -32,8 +32,8 @@
 import com.android.documentsui.base.State;
 import com.android.documentsui.dirlist.TestContext;
 import com.android.documentsui.dirlist.TestData;
-import com.android.documentsui.selection.SelectionManager;
-import com.android.documentsui.testing.SelectionManagers;
+import com.android.documentsui.selection.SelectionHelper;
+import com.android.documentsui.testing.SelectionHelpers;
 import com.android.documentsui.testing.TestDirectoryDetails;
 import com.android.documentsui.testing.TestEnv;
 import com.android.documentsui.testing.TestFeatures;
@@ -66,8 +66,9 @@
     private TestMenuItem dirRename;
     private TestMenuItem dirDelete;
     private TestMenuItem dirViewInOwner;
-    private TestMenuItem dirOpenInNewWindow;
     private TestMenuItem dirPasteIntoFolder;
+    private TestMenuItem dirInspect;
+    private TestMenuItem dirOpenInNewWindow;
 
     /* Root List Context Menu items */
     private TestMenuItem rootEjectRoot;
@@ -99,6 +100,7 @@
     private TestMenuItem optionSelectAll;
     private TestMenuItem optionAdvanced;
     private TestMenuItem optionSettings;
+    private TestMenuItem optionInspector;
 
     private TestFeatures features;
     private TestSelectionDetails selectionDetails;
@@ -110,11 +112,13 @@
     private State state = new State();
     private MenuManager mgr;
     private TestActivity activity = TestActivity.create(TestEnv.create());
-    private SelectionManager selectionManager;
+    private SelectionHelper selectionManager;
 
     @Before
     public void setUp() {
         testMenu = TestMenu.create();
+
+        // The context menu on anything in DirectoryList (including no selection).
         dirShare = testMenu.findItem(R.id.dir_menu_share);
         dirOpen = testMenu.findItem(R.id.dir_menu_open);
         dirOpenWith = testMenu.findItem(R.id.dir_menu_open_with);
@@ -126,14 +130,16 @@
         dirRename = testMenu.findItem(R.id.dir_menu_rename);
         dirDelete = testMenu.findItem(R.id.dir_menu_delete);
         dirViewInOwner = testMenu.findItem(R.id.dir_menu_view_in_owner);
-        dirOpenInNewWindow = testMenu.findItem(R.id.dir_menu_open_in_new_window);
         dirPasteIntoFolder = testMenu.findItem(R.id.dir_menu_paste_into_folder);
+        dirInspect = testMenu.findItem(R.id.dir_menu_inspect);
+        dirOpenInNewWindow = testMenu.findItem(R.id.dir_menu_open_in_new_window);
 
         rootEjectRoot = testMenu.findItem(R.id.root_menu_eject_root);
         rootOpenInNewWindow = testMenu.findItem(R.id.root_menu_open_in_new_window);
         rootPasteIntoFolder = testMenu.findItem(R.id.root_menu_paste_into_folder);
         rootSettings = testMenu.findItem(R.id.root_menu_settings);
 
+        // Menu actions (including overflow) when action mode *is* active.
         actionModeOpen = testMenu.findItem(R.id.action_menu_open);
         actionModeOpenWith = testMenu.findItem(R.id.action_menu_open_with);
         actionModeShare = testMenu.findItem(R.id.action_menu_share);
@@ -144,9 +150,10 @@
         actionModeMoveTo = testMenu.findItem(R.id.action_menu_move_to);
         actionModeCompress = testMenu.findItem(R.id.action_menu_compress);
         actionModeRename = testMenu.findItem(R.id.action_menu_rename);
-        actionModeInspector = testMenu.findItem(R.id.action_menu_inspector);
+        actionModeInspector = testMenu.findItem(R.id.action_menu_inspect);
         actionModeViewInOwner = testMenu.findItem(R.id.action_menu_view_in_owner);
 
+        // Menu actions (including overflow) when action mode is not active.
         optionSearch = testMenu.findItem(R.id.option_menu_search);
         optionDebug = testMenu.findItem(R.id.option_menu_debug);
         optionGrid = testMenu.findItem(R.id.option_menu_grid);
@@ -156,6 +163,7 @@
         optionSelectAll = testMenu.findItem(R.id.option_menu_select_all);
         optionAdvanced = testMenu.findItem(R.id.option_menu_advanced);
         optionSettings = testMenu.findItem(R.id.option_menu_settings);
+        optionInspector = testMenu.findItem(R.id.option_menu_inspect);
 
         features = new TestFeatures();
 
@@ -168,8 +176,8 @@
         dirDetails = new TestDirectoryDetails();
         testSearchManager = new TestSearchViewManager();
         preferences = new TestScopedPreferences();
-        selectionManager = SelectionManagers.createTestInstance(TestData.create(1));
-        selectionManager.toggleSelection("0");
+        selectionManager = SelectionHelpers.createTestInstance(TestData.create(1));
+        selectionManager.select("0");
 
         mgr = new MenuManager(
                 features,
@@ -183,6 +191,7 @@
 
         testRootInfo = new RootInfo();
         testDocInfo = new DocumentInfo();
+        state.stack.push(testDocInfo);
     }
 
     private Uri getUriFromModelId(String id) {
@@ -271,6 +280,7 @@
 
     @Test
     public void testActionsMenu_canViewInOwner() {
+        activity.resources.strings.put(R.string.menu_view_in_owner, "Insert name here! %s");
         selectionDetails.canViewInOwner = true;
         mgr.updateActionMenu(testMenu, selectionDetails);
 
@@ -351,6 +361,26 @@
     }
 
     @Test
+    public void testActionMenu_Inspector_EnabledForSingleSelection() {
+        features.inspector = true;
+        selectionDetails.size = 1;
+        mgr.updateActionMenu(testMenu, selectionDetails);
+
+        actionModeInspector.assertVisible();
+        actionModeInspector.assertEnabled();
+    }
+
+    @Test
+    public void testActionMenu_Inspector_DisabledForMultiSelection() {
+        features.inspector = true;
+        selectionDetails.size = 2;
+        mgr.updateActionMenu(testMenu, selectionDetails);
+
+        actionModeInspector.assertVisible();
+        actionModeInspector.assertDisabled();
+    }
+
+    @Test
     public void testOptionMenu() {
         mgr.updateOptionMenu(testMenu);
 
@@ -388,6 +418,24 @@
     }
 
     @Test
+    public void testOptionMenu_Inspector_VisibleAndEnabled() {
+        features.inspector = true;
+        dirDetails.canInspectDirectory = true;
+        mgr.updateOptionMenu(testMenu);
+        optionInspector.assertVisible();
+        optionInspector.assertEnabled();
+    }
+
+    @Test
+    public void testOptionMenu_Inspector_VisibleButDisabled() {
+        features.inspector = true;
+        dirDetails.canInspectDirectory = false;
+        mgr.updateOptionMenu(testMenu);
+        optionInspector.assertVisible();
+        optionInspector.assertDisabled();
+    }
+
+    @Test
     public void testInflateContextMenu_Files() {
         TestMenuInflater inflater = new TestMenuInflater();
 
@@ -560,6 +608,15 @@
     }
 
     @Test
+    public void testContextMenu_CanInspectContainer() {
+        features.inspector = true;
+        dirDetails.canInspectDirectory = true;
+        mgr.updateContextMenuForContainer(testMenu);
+        dirInspect.assertVisible();
+        dirInspect.assertEnabled();
+    }
+
+    @Test
     public void testContextMenu_OnWritableDirectory_NothingToPaste() {
         selectionDetails.canPasteInto = true;
         selectionDetails.size = 1;
@@ -624,6 +681,14 @@
     }
 
     @Test
+    public void testContextMenu_CanInspectSingleSelection() {
+        selectionDetails.size = 1;
+        mgr.updateContextMenuForFiles(testMenu, selectionDetails);
+        dirInspect.assertVisible();
+        dirInspect.assertEnabled();
+    }
+
+    @Test
     public void testRootContextMenu() {
         testRootInfo.flags = Root.FLAG_SUPPORTS_CREATE;
 
diff --git a/tests/unit/com/android/documentsui/files/QuickViewIntentBuilderTest.java b/tests/unit/com/android/documentsui/files/QuickViewIntentBuilderTest.java
index 8fd130c..ad87726 100644
--- a/tests/unit/com/android/documentsui/files/QuickViewIntentBuilderTest.java
+++ b/tests/unit/com/android/documentsui/files/QuickViewIntentBuilderTest.java
@@ -59,9 +59,10 @@
         Set<String> features = new HashSet<>(
                 Arrays.asList(intent.getStringArrayExtra(Intent.EXTRA_QUICK_VIEW_FEATURES)));
 
-        assertEquals("Unexpected features set: " + features, 5, features.size());
+        assertEquals("Unexpected features set: " + features, 6, features.size());
         assertTrue(features.contains(QuickViewConstants.FEATURE_VIEW));
         assertTrue(features.contains(QuickViewConstants.FEATURE_EDIT));
+        assertTrue(features.contains(QuickViewConstants.FEATURE_DELETE));
         assertTrue(features.contains(QuickViewConstants.FEATURE_SEND));
         assertTrue(features.contains(QuickViewConstants.FEATURE_DOWNLOAD));
         assertTrue(features.contains(QuickViewConstants.FEATURE_PRINT));
diff --git a/tests/unit/com/android/documentsui/inspector/DocumentLoaderTest.java b/tests/unit/com/android/documentsui/inspector/DocumentLoaderTest.java
index 7c9bb02..cd487b6 100644
--- a/tests/unit/com/android/documentsui/inspector/DocumentLoaderTest.java
+++ b/tests/unit/com/android/documentsui/inspector/DocumentLoaderTest.java
@@ -25,7 +25,7 @@
 import com.android.documentsui.InspectorProvider;
 import android.test.suitebuilder.annotation.MediumTest;
 import com.android.documentsui.base.DocumentInfo;
-import com.android.documentsui.inspector.InspectorController.Loader;
+import com.android.documentsui.inspector.InspectorController.DataSupplier;
 import com.android.documentsui.testing.TestLoaderManager;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -46,7 +46,7 @@
 
     private Context mContext;
     private TestLoaderManager mLoaderManager;
-    private Loader mLoader;
+    private DataSupplier mLoader;
     private ContentResolver mResolver;
 
     @Before
@@ -55,7 +55,7 @@
         mContext = InstrumentationRegistry.getTargetContext();
         mResolver = mContext.getContentResolver();
         mLoaderManager = new TestLoaderManager();
-        mLoader = new DocumentLoader(mContext, mLoaderManager);
+        mLoader = new RuntimeDataSupplier(mContext, mLoaderManager);
 
         if (Looper.myLooper() == null) {
             Looper.prepare();
diff --git a/tests/unit/com/android/documentsui/inspector/GpsCoordinatesTextClassifierTest.java b/tests/unit/com/android/documentsui/inspector/GpsCoordinatesTextClassifierTest.java
new file mode 100644
index 0000000..8610ea7
--- /dev/null
+++ b/tests/unit/com/android/documentsui/inspector/GpsCoordinatesTextClassifierTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2017 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.documentsui.inspector;
+
+import static junit.framework.Assert.assertEquals;
+
+import android.content.pm.PackageManager;
+import android.os.LocaleList;
+import android.support.test.InstrumentationRegistry;
+
+import android.content.Context;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.textclassifier.TextClassification;
+import android.view.textclassifier.TextClassificationManager;
+import android.view.textclassifier.TextClassifier;
+import com.android.documentsui.testing.TestPackageManager;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test class for testing recognizing geo coordinates.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class GpsCoordinatesTextClassifierTest {
+
+    private GpsCoordinatesTextClassifier mClassifier;
+
+    @Before
+    public void setUp() throws Exception {
+        PackageManager pm = TestPackageManager.create();
+        Context context = InstrumentationRegistry.getTargetContext();
+
+        TextClassifier defaultClassifier =
+                context.getSystemService(TextClassificationManager.class).getTextClassifier();
+        mClassifier = new GpsCoordinatesTextClassifier(pm, defaultClassifier);
+    }
+
+    @Test
+    public void testBasicPatterns() throws Exception {
+        assertClassifiedGeo("0,0", true);
+        assertClassifiedGeo("0, 0", true);
+        assertClassifiedGeo("0.0,0.0", true);
+        assertClassifiedGeo("0.0, 0.0", true);
+        assertClassifiedGeo("90,180", true);
+        assertClassifiedGeo("90, 180", true);
+        assertClassifiedGeo("90.0000,180.0000", true);
+        assertClassifiedGeo("90.000, 180.000000000000000", true);
+        assertClassifiedGeo("-77.5646564,133.656554654", true);
+        assertClassifiedGeo("33, -179.324234242423", true);
+        assertClassifiedGeo("44.4545454,70.0", true);
+        assertClassifiedGeo("60.0, 60.0", true);
+        assertClassifiedGeo("-33.33,-180", true);
+        assertClassifiedGeo("-88.888888, -33.3333", true);
+        assertClassifiedGeo("90.0, 180.000000", true);
+        assertClassifiedGeo("-90.00000, -180.0", true);
+    }
+
+    @Test
+    public void testInvalidPatterns() throws Exception {
+        assertClassifiedGeo("0", false);
+        assertClassifiedGeo("Geo Intent", false);
+        assertClassifiedGeo("GeoIntent", false);
+        assertClassifiedGeo("A.B, C.D", false);
+        assertClassifiedGeo("90.165464, 180.1", false);
+        // TODO: Failing tests below
+        // assertClassifiedGeo("-90.1, -180.156754", false);
+        // assertClassifiedGeo("5000, 5000", false);
+        // assertClassifiedGeo("500, 500", false);
+    }
+
+    private void assertClassifiedGeo(CharSequence text, boolean expectClassified) {
+        boolean wasClassified;
+        TextClassification test = mClassifier.classifyText(
+                text,
+                0,
+                text.length(),
+                new LocaleList());
+        try {
+            wasClassified = "geo".equals(test.getIntent().getData().getScheme());
+        } catch (NullPointerException intentNotSet) {
+            wasClassified = false;
+        }
+        assertEquals(wasClassified, expectClassified);
+    }
+}
diff --git a/tests/unit/com/android/documentsui/inspector/HeaderTextSelectorTest.java b/tests/unit/com/android/documentsui/inspector/HeaderTextSelectorTest.java
new file mode 100644
index 0000000..58b533b
--- /dev/null
+++ b/tests/unit/com/android/documentsui/inspector/HeaderTextSelectorTest.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2017 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.documentsui.inspector;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.widget.TextView;
+import com.android.documentsui.inspector.HeaderTextSelector.Selector;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class HeaderTextSelectorTest {
+
+    private Context mContext;
+    private TestTextView mTestTextView;
+    private TestSelector mTestSelector;
+    private HeaderTextSelector mSelector;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mTestTextView = new TestTextView(mContext);
+        mTestSelector = new TestSelector();
+        mSelector = new HeaderTextSelector(mTestTextView, mTestSelector);
+    }
+
+    @Test
+    public void testSimpleFileName() throws Exception {
+        CharSequence fileName = "filename";
+        String extension = ".txt";
+        String testSequence = fileName + extension;
+
+        mTestTextView.setText(testSequence);
+        mSelector.onCreateActionMode(null, null);
+        mTestSelector.assertCalled();
+
+        CharSequence selectedSequence =
+                testSequence.subSequence(mTestSelector.mStart, mTestSelector.mStop);
+        assertEquals(selectedSequence, fileName);
+    }
+
+
+    @Test
+    public void testLotsOfPeriodsInFileName() throws Exception {
+        CharSequence fileName = "filename";
+        String extension = ".jpg.zip.pdf.txt";
+        String testSequence = fileName + extension;
+
+        mTestTextView.setText(testSequence);
+        mSelector.onCreateActionMode(null, null);
+        mTestSelector.assertCalled();
+
+        CharSequence selectedSequence =
+            testSequence.subSequence(mTestSelector.mStart, mTestSelector.mStop);
+        assertEquals(selectedSequence, fileName);
+    }
+
+    @Test
+    public void testNoPeriodsInFileName() throws Exception {
+        String testSequence = "filename";
+
+        mTestTextView.setText(testSequence);
+        mSelector.onCreateActionMode(null, null);
+        mTestSelector.assertCalled();
+
+        CharSequence selectedSequence =
+            testSequence.subSequence(mTestSelector.mStart, mTestSelector.mStop);
+        assertEquals(selectedSequence, testSequence);
+    }
+
+    private static class TestTextView extends TextView {
+
+        public TestTextView(Context context) {
+            super(context);
+        }
+
+        private String textViewString;
+
+        public void setText(String text) {
+            textViewString = text;
+        }
+
+        @Override
+        public CharSequence getText() {
+            return new SpannableString(textViewString);
+        }
+    }
+
+    private static class TestSelector implements Selector {
+
+        private boolean mCalled;
+        private int mStart;
+        private int mStop;
+
+        public TestSelector() {
+            mCalled = false;
+            mStart = -1;
+            mStop = -1;
+        }
+
+        @Override
+        public void select(Spannable text, int start, int stop) {
+            mCalled = true;
+            mStart = start;
+            mStop = stop;
+        }
+
+        public void assertCalled() {
+            assertTrue(mCalled);
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/unit/com/android/documentsui/inspector/InspectorControllerTest.java b/tests/unit/com/android/documentsui/inspector/InspectorControllerTest.java
index 68520ef..8f70477 100644
--- a/tests/unit/com/android/documentsui/inspector/InspectorControllerTest.java
+++ b/tests/unit/com/android/documentsui/inspector/InspectorControllerTest.java
@@ -15,102 +15,116 @@
  */
 package com.android.documentsui.inspector;
 
-import static android.provider.DocumentsContract.Document.FLAG_SUPPORTS_SETTINGS;
+import static junit.framework.Assert.fail;
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertTrue;
 
 import android.app.Activity;
-import android.content.Context;
 import android.content.Intent;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.Looper;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
 import android.support.annotation.Nullable;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.view.View.OnClickListener;
+
 import com.android.documentsui.InspectorProvider;
-import com.android.documentsui.ProviderExecutor;
+import com.android.documentsui.R;
+import com.android.documentsui.TestProviderActivity;
 import com.android.documentsui.base.DocumentInfo;
-import com.android.documentsui.inspector.InspectorController.DetailsDisplay;
-import com.android.documentsui.inspector.InspectorController.Loader;
-import com.android.documentsui.inspector.actions.Action;
+import com.android.documentsui.base.Shared;
 import com.android.documentsui.inspector.InspectorController.ActionDisplay;
+import com.android.documentsui.inspector.InspectorController.DataSupplier;
+import com.android.documentsui.inspector.InspectorController.DebugDisplay;
+import com.android.documentsui.inspector.InspectorController.DetailsDisplay;
+import com.android.documentsui.inspector.InspectorController.HeaderDisplay;
+import com.android.documentsui.inspector.InspectorController.MediaDisplay;
+import com.android.documentsui.inspector.actions.Action;
 import com.android.documentsui.testing.TestConsumer;
 import com.android.documentsui.testing.TestEnv;
 import com.android.documentsui.testing.TestLoaderManager;
 import com.android.documentsui.testing.TestPackageManager;
 import com.android.documentsui.testing.TestPackageManager.TestResolveInfo;
 import com.android.documentsui.testing.TestProvidersAccess;
-import java.util.ArrayList;
+
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
+import java.util.function.Consumer;
+
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class InspectorControllerTest  {
 
     private static final String OPEN_IN_PROVIDER_DOC = "OpenInProviderTest";
 
-    private TestActivity mContext;
+    private TestActivity mActivity;
     private TestLoaderManager mLoaderManager;
-    private Loader mLoader;
+    private TestDataSupplier mDataSupplier;
     private TestPackageManager mPm;
     private InspectorController mController;
     private TestEnv mEnv;
-    private TestConsumer<DocumentInfo> mHeaderTestDouble;
+    private TestHeader mHeaderTestDouble;
     private TestDetails mDetailsTestDouble;
+    private TestMedia mMedia;
     private TestAction mShowInProvider;
     private TestAction mDefaultsTestDouble;
-    private TestConsumer<DocumentInfo> mDebugTestDouble;
-    private Boolean mShowSnackbarsCalled;
+    private TestDebug mDebugTestDouble;
+    private TestRunnable mErrCallback;
+    private Bundle mTestArgs;
 
     @Before
     public void setUp() throws Exception {
 
-        //Needed to create a non null loader for the InspectorController.
-        Context loader = InstrumentationRegistry.getTargetContext();
         mEnv = TestEnv.create();
         mPm = TestPackageManager.create();
         mLoaderManager = new TestLoaderManager();
-        mLoader = new DocumentLoader(loader, mLoaderManager);
-        mHeaderTestDouble = new TestConsumer<>();
+        mDataSupplier = new TestDataSupplier();
+        mHeaderTestDouble = new TestHeader();
         mDetailsTestDouble = new TestDetails();
+        mMedia = new TestMedia();
         mShowInProvider = new TestAction();
         mDefaultsTestDouble = new TestAction();
-        mDebugTestDouble = new TestConsumer<>();
+        mDebugTestDouble = new TestDebug();
+        mErrCallback = new TestRunnable();
+        mTestArgs = new Bundle();
 
-        mShowSnackbarsCalled = false;
+        // Add some fake data.
+        mDataSupplier.mDoc = TestEnv.FILE_JPG;
+        mDataSupplier.mMetadata = new Bundle();
+        TestMetadata.populateExifData(mDataSupplier.mMetadata);
 
-        //Crashes if not called before "new TestActivity".
+        // Crashes if not called before "new TestActivity".
         if (Looper.myLooper() == null) {
             Looper.prepare();
         }
-        mContext = new TestActivity();
+        mActivity = new TestActivity();
+        recreateController();
+    }
 
+    private void recreateController() {
         mController = new InspectorController(
-                mContext,
-                mLoader,
+                mActivity,
+                mDataSupplier,
                 mPm,
                 new TestProvidersAccess(),
-                false,
                 mHeaderTestDouble,
                 mDetailsTestDouble,
+                mMedia,
                 mShowInProvider,
                 mDefaultsTestDouble,
                 mDebugTestDouble,
-                ProviderExecutor::forAuthority,
-                () -> {
-                    mShowSnackbarsCalled = true;
-                }
-        );
+                mTestArgs,
+                mErrCallback);
     }
 
     /**
@@ -118,8 +132,9 @@
      */
     @Test
     public void testHideDebugByDefault() throws Exception {
-        mController.updateView(new DocumentInfo());
-        mDebugTestDouble.assertNotCalled();
+        mController.loadInfo(TestEnv.FILE_JPG.derivedUri);  // actual URI doesn't matter :)
+        mDebugTestDouble.assertVisible(false);
+        mDebugTestDouble.assertEmpty();
     }
 
     /**
@@ -127,25 +142,22 @@
      */
     @Test
     public void testShowDebugUpdatesView() throws Exception {
-        mController = new InspectorController(
-            mContext,
-            mLoader,
-            mPm,
-            new TestProvidersAccess(),
-            true,
-            mHeaderTestDouble,
-            mDetailsTestDouble,
-            mShowInProvider,
-            mDefaultsTestDouble,
-            mDebugTestDouble,
-            ProviderExecutor::forAuthority,
-            () -> {
-                mShowSnackbarsCalled = true;
-            }
-        );
+        mTestArgs.putBoolean(Shared.EXTRA_SHOW_DEBUG, true);
+        recreateController();
+        mController.loadInfo(TestEnv.FILE_JPG.derivedUri);  // actual URI doesn't matter :)
+        mDebugTestDouble.assertVisible(true);
+        mDebugTestDouble.assertNotEmpty();
+    }
 
-        mController.updateView(new DocumentInfo());
-        mDebugTestDouble.assertCalled();
+    /**
+     * Tests Debug view should be updated when visible.
+     */
+    @Test
+    public void testExtraTitleOverridesDisplayName() throws Exception {
+        mTestArgs.putString(Intent.EXTRA_TITLE, "hammy!");
+        recreateController();
+        mController.loadInfo(TestEnv.FILE_JPG.derivedUri);  // actual URI doesn't matter :)
+        mHeaderTestDouble.assertTitle("hammy!");
     }
 
     /**
@@ -165,9 +177,9 @@
             OPEN_IN_PROVIDER_DOC);
         mController.showInProvider(uri);
 
-        assertNotNull(mContext.started);
-        assertEquals("com.android.documentsui", mContext.started.getPackage());
-        assertEquals(uri, mContext.started.getData());
+        assertNotNull(mActivity.started);
+        assertEquals("com.android.documentsui", mActivity.started.getPackage());
+        assertEquals(uri, mActivity.started.getData());
     }
     /**
      * Test that valid input will update the view properly. The test uses a test double for header
@@ -177,7 +189,7 @@
      */
     @Test
     public void testUpdateViewWithValidInput() throws Exception {
-        mController.updateView(new DocumentInfo());
+        mController.loadInfo(TestEnv.FILE_JPG.derivedUri);  // actual URI doesn't matter :)
         mHeaderTestDouble.assertCalled();
         mDetailsTestDouble.assertCalled();
     }
@@ -193,9 +205,9 @@
         DocumentInfo doc = new DocumentInfo();
         doc.derivedUri =
             DocumentsContract.buildDocumentUri(InspectorProvider.AUTHORITY, OPEN_IN_PROVIDER_DOC);
-
         doc.flags = doc.flags | Document.FLAG_SUPPORTS_SETTINGS;
-        mController.updateView(doc);
+        mDataSupplier.mDoc = doc;
+        mController.loadInfo(doc.derivedUri);  // actual URI doesn't matter :)
         assertTrue(mShowInProvider.becameVisible);
     }
 
@@ -206,11 +218,7 @@
      */
     @Test
     public void testShowInProvider_invisible() throws Exception {
-        DocumentInfo doc = new DocumentInfo();
-        doc.derivedUri =
-            DocumentsContract.buildDocumentUri(InspectorProvider.AUTHORITY, OPEN_IN_PROVIDER_DOC);
-
-        mController.updateView(doc);
+        mController.loadInfo(TestEnv.FILE_JPG.derivedUri);  // actual URI doesn't matter :)
         assertFalse(mShowInProvider.becameVisible);
     }
 
@@ -220,7 +228,6 @@
      */
     @Test
     public void testAppDefaults_visible() throws Exception {
-
         mPm.queryIntentProvidersResults = new ArrayList<>();
         mPm.queryIntentProvidersResults.add(new TestResolveInfo());
         mPm.queryIntentProvidersResults.add(new TestResolveInfo());
@@ -228,7 +235,8 @@
         doc.derivedUri =
             DocumentsContract.buildDocumentUri(InspectorProvider.AUTHORITY, OPEN_IN_PROVIDER_DOC);
 
-        mController.updateView(doc);
+        mDataSupplier.mDoc = doc;
+        mController.loadInfo(doc.derivedUri);  // actual URI doesn't matter :)
         assertTrue(mDefaultsTestDouble.becameVisible);
     }
 
@@ -244,7 +252,8 @@
         doc.derivedUri =
             DocumentsContract.buildDocumentUri(InspectorProvider.AUTHORITY, OPEN_IN_PROVIDER_DOC);
 
-        mController.updateView(doc);
+        mDataSupplier.mDoc = doc;
+        mController.loadInfo(doc.derivedUri);  // actual URI doesn't matter :)
         assertFalse(mDefaultsTestDouble.becameVisible);
     }
 
@@ -255,13 +264,60 @@
      * @throws Exception
      */
     @Test
-    public void testUpdateViewWithNullValue() throws Exception {
-        mController.updateView(null);
-        assertTrue(mShowSnackbarsCalled);
+    public void testUpdateView_withNullValue() throws Exception {
+        mDataSupplier.mDoc = null;
+        mController.loadInfo(TestEnv.FILE_JPG.derivedUri);  // actual URI doesn't matter :)
+
+        mErrCallback.assertCalled();
         mHeaderTestDouble.assertNotCalled();
         mDetailsTestDouble.assertNotCalled();
     }
 
+    @Test
+    public void testMetadata_GeoHandlerInstalled() {
+        DocumentInfo doc = TestEnv.clone(TestEnv.FILE_JPG);
+        doc.flags |= DocumentsContract.Document.FLAG_SUPPORTS_METADATA;
+        mDataSupplier.mDoc = doc;
+        mController.loadInfo(doc.derivedUri);  // actual URI doesn't matter :)
+        mMedia.assertGeoCallbackInstalled();
+    }
+
+    @Test
+    public void testMetadata_notDisplayedWhenNotReturned() {
+        DocumentInfo doc = TestEnv.clone(TestEnv.FILE_JPG);
+        doc.flags |= DocumentsContract.Document.FLAG_SUPPORTS_METADATA;
+        mDataSupplier.mDoc = doc;
+        mDataSupplier.mMetadata = null;  // sorry, no results sucka!
+        mController.loadInfo(doc.derivedUri);  // actual URI doesn't matter :)
+    }
+
+    @Test
+    public void testMetadata_notDisplayedDocWithoutSupportFlag() {
+        assert !TestEnv.FILE_JPG.isMetadataSupported();
+        mDataSupplier.mDoc = TestEnv.FILE_JPG;  // this is the default value. For "good measure".
+        mController.loadInfo(TestEnv.FILE_JPG.derivedUri);  // actual URI doesn't matter :)
+        mMedia.assertVisible(false);
+        mMedia.assertEmpty();
+    }
+
+    @Test
+    public void testMetadata_GeoHandlerStartsAction() {
+        DocumentInfo doc = TestEnv.clone(TestEnv.FILE_JPG);
+        doc.flags |= DocumentsContract.Document.FLAG_SUPPORTS_METADATA;
+        mDataSupplier.mDoc = doc;
+        mController.loadInfo(doc.derivedUri);  // actual URI doesn't matter :)
+        mMedia.mGeoClickCallback.run();
+        Intent geoIntent = mActivity.started;
+        assertEquals(Intent.ACTION_VIEW, geoIntent.getAction());
+        assertNotNull(geoIntent);
+        Uri uri = geoIntent.getData();
+        assertEquals("geo", uri.getScheme());
+        String strUri = uri.toSafeString();
+        assertTrue(strUri.contains("33."));
+        assertTrue(strUri.contains("-118."));
+        assertTrue(strUri.contains(TestEnv.FILE_JPG.displayName));
+    }
+
     private static class TestActivity extends Activity {
 
         private @Nullable Intent started;
@@ -311,6 +367,31 @@
         }
     }
 
+
+    private static class TestHeader implements HeaderDisplay {
+
+        private boolean mCalled = false;
+        private @Nullable String mTitle;
+
+        @Override
+        public void accept(DocumentInfo info, String displayName) {
+            mCalled = true;
+            mTitle = displayName;
+        }
+
+        public void assertTitle(String expected) {
+            Assert.assertEquals(expected, mTitle);
+        }
+
+        public void assertCalled() {
+            Assert.assertTrue(mCalled);
+        }
+
+        public void assertNotCalled() {
+            Assert.assertFalse(mCalled);
+        }
+    }
+
     private static class TestDetails implements DetailsDisplay {
 
         private boolean mCalled = false;
@@ -332,4 +413,71 @@
             Assert.assertFalse(mCalled);
         }
     }
+
+    private static class TestMedia extends TestTable implements MediaDisplay {
+
+        private @Nullable Runnable mGeoClickCallback;
+
+        @Override
+        public void accept(DocumentInfo info, Bundle metadata, Runnable geoClickCallback) {
+            mGeoClickCallback = geoClickCallback;
+        }
+
+        void assertGeoCallbackInstalled() {
+            assertNotNull(mGeoClickCallback);
+        }
+    }
+
+    private static class TestDebug extends TestTable implements DebugDisplay {
+
+        @Override
+        public void accept(DocumentInfo info) {
+            // We have to emulate some of the real DebugView behavior
+            // because the controller makes us visible if we're not-empty.
+            put(R.string.debug_content_uri, info.derivedUri.toString());
+        }
+
+        @Override
+        public void accept(Bundle metadata) {
+        }
+    }
+
+    private static final class TestDataSupplier implements DataSupplier {
+
+        private @Nullable DocumentInfo mDoc;
+        private @Nullable Bundle mMetadata;
+
+        @Override
+        public void loadDocInfo(Uri uri, Consumer<DocumentInfo> callback) {
+            callback.accept(mDoc);
+        }
+
+        @Override
+        public void getDocumentMetadata(Uri uri, Consumer<Bundle> callback) {
+            callback.accept(mMetadata);
+        }
+
+        @Override
+        public void loadDirCount(DocumentInfo directory, Consumer<Integer> callback) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void reset() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    private static final class TestRunnable implements Runnable {
+        private boolean mCalled;
+
+        @Override
+        public void run() {
+            mCalled = true;
+        }
+
+        void assertCalled() {
+            assertTrue(mCalled);
+        }
+    }
 }
\ No newline at end of file
diff --git a/tests/unit/com/android/documentsui/inspector/MediaViewTest.java b/tests/unit/com/android/documentsui/inspector/MediaViewTest.java
new file mode 100644
index 0000000..7cf7b21
--- /dev/null
+++ b/tests/unit/com/android/documentsui/inspector/MediaViewTest.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2017 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.documentsui.inspector;
+
+import android.media.ExifInterface;
+import android.media.MediaMetadata;
+import android.os.Bundle;
+import android.provider.DocumentsContract;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.documentsui.R;
+import com.android.documentsui.base.Shared;
+import com.android.documentsui.testing.TestEnv;
+import com.android.documentsui.testing.TestResources;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.function.Consumer;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class MediaViewTest {
+
+    private TestResources mResources;
+    private TestTable mTable;
+    private Bundle mMetadata;
+    private Consumer<float[]> mGeo = (float[] coords) -> {
+        mTable.put(R.string.metadata_address, "1234 Street Street\n"
+                + "City, State, 56789");
+    };
+
+    @Before
+    public void setUp() {
+        mResources = TestResources.create();
+        // TODO: We should just be using the real underlying resources.
+        mResources.strings.put(R.string.metadata_dimensions_format, "%d x %d, %.1fMP");
+        mResources.strings.put(R.string.metadata_aperture_format, "f/%.1f");
+        mResources.strings.put(R.string.metadata_coordinates_format, "%.3f, %.3f");
+        mResources.strings.put(R.string.metadata_camera_format, "%s %s");
+        mTable = new TestTable();
+        mMetadata = new Bundle();
+        TestMetadata.populateExifData(mMetadata);
+        TestMetadata.populateVideoData(mMetadata);
+        TestMetadata.populateAudioData(mMetadata);
+    }
+
+    /**
+     * Test that the updateMetadata method is printing metadata for selected items found in the
+     * bundle.
+     */
+    @Test
+    public void testShowExifData() throws Exception {
+        mResources.strings.put(R.string.metadata_focal_format, "%.2f mm");
+        mResources.strings.put(R.string.metadata_iso_format, "ISO %d");
+        Bundle exif = mMetadata.getBundle(DocumentsContract.METADATA_EXIF);
+        MediaView.showExifData(mTable, mResources, TestEnv.FILE_JPG, exif, null, mGeo);
+
+        mTable.assertHasRow(R.string.metadata_dimensions, "3840 x 2160, 8.3MP");
+        mTable.assertHasRow(R.string.metadata_date_time, "Jan 01, 1970, 12:16 AM");
+        mTable.assertHasRow(R.string.metadata_coordinates, "33.996, -118.475");
+        mTable.assertHasRow(R.string.metadata_altitude, "1244.0");
+        mTable.assertHasRow(R.string.metadata_camera, "Google Pixel");
+        mTable.assertHasRow(R.string.metadata_shutter_speed, "1/100");
+        mTable.assertHasRow(R.string.metadata_aperture, "f/2.0");
+        mTable.assertHasRow(R.string.metadata_iso_speed_ratings, "ISO 120");
+        mTable.assertHasRow(R.string.metadata_focal_length, "4.27 mm");
+        mTable.assertHasRow(R.string.metadata_address, "1234 Street Street\n"
+                + "City, State, 56789");
+    }
+
+    /**
+     * Bundle only supplies half of the values for the pairs that print in printMetaData. No put
+     * method should be called as the correct conditions have not been met.
+     * @throws Exception
+     */
+    @Test
+    public void testShowExifData_PartialGpsTags() throws Exception {
+        Bundle data = new Bundle();
+        data.putDouble(ExifInterface.TAG_GPS_LATITUDE, 37.7749);
+
+        mMetadata.putBundle(DocumentsContract.METADATA_EXIF, data);
+        MediaView.showExifData(mTable, mResources, TestEnv.FILE_JPG, mMetadata, null, mGeo);
+        mTable.assertEmpty();
+    }
+
+    /**
+     * Bundle only supplies half of the values for the pairs that print in printMetaData. No put
+     * method should be called as the correct conditions have not been met.
+     * @throws Exception
+     */
+    @Test
+    public void testShowExifData_PartialDimensionTags() throws Exception {
+        Bundle data = new Bundle();
+        data.putInt(ExifInterface.TAG_IMAGE_WIDTH, 3840);
+
+        mMetadata.putBundle(DocumentsContract.METADATA_EXIF, data);
+        MediaView.showExifData(mTable, mResources, TestEnv.FILE_JPG, mMetadata, null, mGeo);
+        mTable.assertEmpty();
+    }
+
+    /**
+     * Test that the updateMetadata method is printing metadata for selected items found in the
+     * bundle.
+     */
+    @Test
+    public void testShowVideoData() throws Exception {
+        Bundle data = mMetadata.getBundle(Shared.METADATA_KEY_VIDEO);
+        MediaView.showVideoData(mTable, mResources, TestEnv.FILE_MP4, data, null);
+
+        mTable.assertHasRow(R.string.metadata_duration, "01:12");
+        mTable.assertHasRow(R.string.metadata_dimensions, "1920 x 1080, 2.1MP");
+    }
+
+    @Test
+    public void testShowAudioData() throws Exception {
+        Bundle data = mMetadata.getBundle(Shared.METADATA_KEY_AUDIO);
+        MediaView.showAudioData(mTable, data);
+
+        mTable.assertHasRow(R.string.metadata_duration, "01:12");
+        mTable.assertHasRow(R.string.metadata_artist, "artist");
+        mTable.assertHasRow(R.string.metadata_composer, "composer");
+        mTable.assertHasRow(R.string.metadata_album, "album");
+    }
+
+    /**
+     * Test that the updateMetadata method is printing metadata for selected items found in the
+     * bundle.
+     */
+    @Test
+    public void testShowVideoData_HourPlusDuration() throws Exception {
+        Bundle data = mMetadata.getBundle(Shared.METADATA_KEY_VIDEO);
+        data.putInt(MediaMetadata.METADATA_KEY_DURATION, 21660000);
+        MediaView.showVideoData(mTable, mResources, TestEnv.FILE_MP4, data, null);
+
+        mTable.assertHasRow(R.string.metadata_duration, "6:01:00");
+    }
+
+    @Test
+    public void testGetAddress() throws Exception {
+        Consumer<float[]> badAddress = (float[] coords) -> {
+        };
+        Bundle data = new Bundle();
+        data.putInt(ExifInterface.TAG_IMAGE_WIDTH, 3840);
+        data.putInt(ExifInterface.TAG_IMAGE_LENGTH, 2160);
+
+        mMetadata.getBundle(DocumentsContract.METADATA_EXIF);
+        MediaView.showExifData(mTable, mResources, TestEnv.FILE_JPG, mMetadata, null, badAddress);
+        mTable.assertNotInTable(R.string.metadata_address);
+    }
+}
diff --git a/tests/unit/com/android/documentsui/inspector/TestMetadata.java b/tests/unit/com/android/documentsui/inspector/TestMetadata.java
new file mode 100644
index 0000000..a6801ad
--- /dev/null
+++ b/tests/unit/com/android/documentsui/inspector/TestMetadata.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 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.documentsui.inspector;
+
+import android.media.ExifInterface;
+import android.media.MediaMetadata;
+import android.os.Bundle;
+import android.provider.DocumentsContract;
+
+import com.android.documentsui.base.Shared;
+
+final class TestMetadata {
+    private TestMetadata() {}
+
+    static void populateExifData(Bundle container) {
+        Bundle data = new Bundle();
+        container.putBundle(DocumentsContract.METADATA_EXIF, data);
+
+        data.putInt(ExifInterface.TAG_IMAGE_WIDTH, 3840);
+        data.putInt(ExifInterface.TAG_IMAGE_LENGTH, 2160);
+        data.putString(ExifInterface.TAG_DATETIME, "Jan 01, 1970, 12:16 AM");
+        data.putString(ExifInterface.TAG_GPS_LATITUDE, "33/1,59/1,4530/100");
+        data.putString(ExifInterface.TAG_GPS_LONGITUDE, "118/1,28/1,3124/100");
+        data.putString(ExifInterface.TAG_GPS_LATITUDE_REF, "N");
+        data.putString(ExifInterface.TAG_GPS_LONGITUDE_REF, "W");
+        data.putDouble(ExifInterface.TAG_GPS_ALTITUDE, 1244);
+        data.putString(ExifInterface.TAG_MAKE, "Google");
+        data.putString(ExifInterface.TAG_MODEL, "Pixel");
+        data.putDouble(ExifInterface.TAG_SHUTTER_SPEED_VALUE, 6.643);
+        data.putDouble(ExifInterface.TAG_APERTURE, 2.0);
+        data.putInt(ExifInterface.TAG_ISO_SPEED_RATINGS, 120);
+        data.putDouble(ExifInterface.TAG_FOCAL_LENGTH, 4.27);
+    }
+
+    static void populateVideoData(Bundle container) {
+        Bundle data = new Bundle();
+        container.putBundle(Shared.METADATA_KEY_VIDEO, data);
+
+        // By convention we reuse exif tags for dimensions.
+        data.putInt(ExifInterface.TAG_IMAGE_WIDTH, 1920);
+        data.putInt(ExifInterface.TAG_IMAGE_LENGTH, 1080);
+        data.putInt(MediaMetadata.METADATA_KEY_DURATION, 72000);
+    }
+
+    static void populateAudioData(Bundle container) {
+        Bundle data = new Bundle();
+        container.putBundle(Shared.METADATA_KEY_AUDIO, data);
+
+        data.putInt(MediaMetadata.METADATA_KEY_DURATION, 72000);
+        data.putString(MediaMetadata.METADATA_KEY_ARTIST, "artist");
+        data.putString(MediaMetadata.METADATA_KEY_COMPOSER, "composer");
+        data.putString(MediaMetadata.METADATA_KEY_ALBUM, "album");
+    }
+}
diff --git a/tests/unit/com/android/documentsui/inspector/TestTable.java b/tests/unit/com/android/documentsui/inspector/TestTable.java
new file mode 100644
index 0000000..f1bd0b7
--- /dev/null
+++ b/tests/unit/com/android/documentsui/inspector/TestTable.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2017 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.documentsui.inspector;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+
+import android.view.View.OnClickListener;
+
+import com.android.documentsui.inspector.InspectorController.TableDisplay;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Friendly testable table implementation.
+ */
+class TestTable implements TableDisplay {
+
+    private Map<Integer, CharSequence> mRows;
+    private boolean mVisible;
+
+    public TestTable() {
+        mRows = new HashMap<>();
+    }
+
+    public void assertHasRow(int keyId, CharSequence expected) {
+        assertEquals(expected, mRows.get(keyId));
+    }
+
+    public void assertNotInTable (int keyId) {
+        assertNull(mRows.get(keyId));
+    }
+
+    @Override
+    public void put(int keyId, CharSequence value) {
+        mRows.put(keyId, value);
+    }
+
+    @Override
+    public void put(int keyId, CharSequence value, OnClickListener callback) {
+        mRows.put(keyId, value);
+    }
+
+    @Override
+    public void setVisible(boolean visible) {
+        mVisible = visible;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return mRows.isEmpty();
+    }
+
+    void assertEmpty() {
+        assertTrue(mRows.isEmpty());
+    }
+
+    void assertNotEmpty() {
+        assertFalse(mRows.isEmpty());
+    }
+
+    void assertVisible(boolean expected) {
+        assertEquals(expected, mVisible);
+    }
+}
diff --git a/tests/unit/com/android/documentsui/picker/ActionHandlerTest.java b/tests/unit/com/android/documentsui/picker/ActionHandlerTest.java
index 8a502bf..5d41565 100644
--- a/tests/unit/com/android/documentsui/picker/ActionHandlerTest.java
+++ b/tests/unit/com/android/documentsui/picker/ActionHandlerTest.java
@@ -80,7 +80,7 @@
 
         mEnv.dialogs.confirmNext();
 
-        mEnv.selectionMgr.toggleSelection("1");
+        mEnv.selectionMgr.select("1");
 
         AsyncTask.setDefaultExecutor(mEnv.mExecutor);
     }
diff --git a/tests/unit/com/android/documentsui/prefs/PrefsBackupHelperTest.java b/tests/unit/com/android/documentsui/prefs/PrefsBackupHelperTest.java
index 91ce1ce..3c421c3 100644
--- a/tests/unit/com/android/documentsui/prefs/PrefsBackupHelperTest.java
+++ b/tests/unit/com/android/documentsui/prefs/PrefsBackupHelperTest.java
@@ -27,6 +27,7 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -54,9 +55,20 @@
     public void setUp() {
         mDefaultPrefs = InstrumentationRegistry.getContext().getSharedPreferences("prefs1", 0);
         mBackupPrefs = InstrumentationRegistry.getContext().getSharedPreferences("prefs2", 0);
+        clearSharedPrefs();
         mPrefsBackupHelper = new PrefsBackupHelper(mDefaultPrefs);
     }
 
+    @After
+    public void tearDown() {
+        clearSharedPrefs();
+    }
+
+    private void clearSharedPrefs() {
+        mDefaultPrefs.edit().clear().commit();
+        mBackupPrefs.edit().clear().commit();
+    }
+
     @Test
     public void testPrepareBackupFile_BackupLocalPreferences() {
         mDefaultPrefs.edit().putInt(LOCAL_PREFERENCE_1, 1).commit();
diff --git a/tests/unit/com/android/documentsui/queries/SearchViewManagerTest.java b/tests/unit/com/android/documentsui/queries/SearchViewManagerTest.java
new file mode 100644
index 0000000..feffaec
--- /dev/null
+++ b/tests/unit/com/android/documentsui/queries/SearchViewManagerTest.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2016 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.documentsui.queries;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.os.Handler;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.documentsui.R;
+import com.android.documentsui.base.EventHandler;
+import com.android.documentsui.queries.SearchViewManager.SearchManagerListener;
+import com.android.documentsui.queries.SearchViewManager;
+import com.android.documentsui.testing.TestEventHandler;
+import com.android.documentsui.testing.TestHandler;
+import com.android.documentsui.testing.TestMenu;
+import com.android.documentsui.testing.TestTimer;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public final class SearchViewManagerTest {
+
+    private TestEventHandler<String> mTestEventHandler;
+    private TestTimer mTestTimer;
+    private TestHandler mTestHandler;
+    private SearchViewManager mSearchViewManager;
+
+    private boolean mListenerOnSearchChangedCalled;
+
+    @Before
+    public void setUp() {
+        mTestEventHandler = new TestEventHandler<>();
+        mTestTimer = new TestTimer();
+        mTestHandler = new TestHandler();
+
+        final SearchManagerListener searchListener = new SearchManagerListener() {
+            @Override
+            public void onSearchChanged(@Nullable String query) {
+                mListenerOnSearchChangedCalled = true;
+            }
+            @Override
+            public void onSearchFinished() {}
+            @Override
+            public void onSearchViewChanged(boolean opened) {}
+        };
+
+        mSearchViewManager = new TestableSearchViewManager(
+                searchListener, mTestEventHandler, null, mTestTimer, mTestHandler);
+
+        final TestMenu testMenu = TestMenu.create();
+        mSearchViewManager.install(testMenu, true);
+    }
+
+    private static class TestableSearchViewManager extends SearchViewManager {
+        public TestableSearchViewManager(
+                SearchManagerListener listener,
+                EventHandler<String> commandProcessor,
+                @Nullable Bundle savedState,
+                Timer timer,
+                Handler handler) {
+            super(listener, commandProcessor, savedState, timer, handler);
+        }
+
+        @Override
+        public TimerTask createSearchTask(String newText) {
+            TimerTask task = super.createSearchTask(newText);
+            TestTimer.Task testTask = new TestTimer.Task(task);
+            return testTask;
+        }
+    }
+
+    private void fastForwardTo(long timeMs) {
+        mTestTimer.fastForwardTo(timeMs);
+        mTestHandler.dispatchAllMessages();
+    }
+
+    @Test
+    public void testIsExpanded_ExpandsOnClick() {
+        mSearchViewManager.onClick(null);
+        assertTrue(mSearchViewManager.isExpanded());
+    }
+
+    @Test
+    public void testIsExpanded_CollapsesOnMenuItemActionCollapse() {
+        mSearchViewManager.onClick(null);
+        mSearchViewManager.onMenuItemActionCollapse(null);
+        assertFalse(mSearchViewManager.isExpanded());
+    }
+
+    @Test
+    public void testIsSearching_FalseOnClick() throws Exception {
+        mSearchViewManager.onClick(null);
+        assertFalse(mSearchViewManager.isSearching());
+    }
+
+    @Test
+    public void testIsSearching_TrueOnQueryTextSubmit() throws Exception {
+        mSearchViewManager.onClick(null);
+        mSearchViewManager.onQueryTextSubmit("query");
+        assertTrue(mSearchViewManager.isSearching());
+    }
+
+    @Test
+    public void testIsSearching_FalseImmediatelyAfterOnQueryTextChange() throws Exception {
+        mSearchViewManager.onClick(null);
+        mSearchViewManager.onQueryTextChange("q");
+        assertFalse(mSearchViewManager.isSearching());
+    }
+
+    @Test
+    public void testIsSearching_TrueAfterOnQueryTextChangeAndWait() throws Exception {
+        mSearchViewManager.onClick(null);
+        mSearchViewManager.onQueryTextChange("q");
+        fastForwardTo(SearchViewManager.SEARCH_DELAY_MS);
+        assertTrue(mSearchViewManager.isSearching());
+    }
+
+    @Test
+    public void testIsSearching_FalseWhenSecondOnQueryTextChangeResetsTimer() throws Exception {
+        mSearchViewManager.onClick(null);
+        mSearchViewManager.onQueryTextChange("q");
+        fastForwardTo(SearchViewManager.SEARCH_DELAY_MS - 1);
+        mSearchViewManager.onQueryTextChange("qu");
+        fastForwardTo(SearchViewManager.SEARCH_DELAY_MS);
+        assertFalse(mSearchViewManager.isSearching());
+    }
+
+    @Test
+    public void testIsSearching_TrueAfterSecondOnQueryTextChangeResetsTimer() throws Exception {
+        mSearchViewManager.onClick(null);
+        mSearchViewManager.onQueryTextChange("q");
+        fastForwardTo(SearchViewManager.SEARCH_DELAY_MS - 1);
+        mSearchViewManager.onQueryTextChange("qu");
+        fastForwardTo(SearchViewManager.SEARCH_DELAY_MS * 2);
+        assertTrue(mSearchViewManager.isSearching());
+    }
+
+    @Test
+    public void testIsSearching_FalseIfSearchCanceled() throws Exception {
+        mSearchViewManager.onClick(null);
+        mSearchViewManager.onQueryTextChange("q");
+        mSearchViewManager.cancelSearch();
+        fastForwardTo(SearchViewManager.SEARCH_DELAY_MS);
+        assertFalse(mSearchViewManager.isSearching());
+    }
+
+    @Test
+    public void testOnSearchChanged_CalledAfterOnQueryTextSubmit() throws Exception {
+        mSearchViewManager.onClick(null);
+        mSearchViewManager.onQueryTextSubmit("q");
+        assertTrue(mListenerOnSearchChangedCalled);
+    }
+
+    @Test
+    public void testOnSearchChanged_NotCalledImmediatelyAfterOnQueryTextChanged() throws Exception {
+        mSearchViewManager.onClick(null);
+        mSearchViewManager.onQueryTextChange("q");
+        assertFalse(mListenerOnSearchChangedCalled);
+    }
+
+    @Test
+    public void testOnSearchChanged_CalledAfterOnQueryTextChangedAndWait() throws Exception {
+        mSearchViewManager.onClick(null);
+        mSearchViewManager.onQueryTextChange("q");
+        fastForwardTo(SearchViewManager.SEARCH_DELAY_MS);
+        assertTrue(mListenerOnSearchChangedCalled);
+    }
+
+    @Test
+    public void testOnSearchChanged_CalledOnlyOnceAfterOnQueryTextSubmit() throws Exception {
+        mSearchViewManager.onClick(null);
+        mSearchViewManager.onQueryTextChange("q");
+        mSearchViewManager.onQueryTextSubmit("q");
+
+        // Clear the flag to check if it gets set again.
+        mListenerOnSearchChangedCalled = false;
+        fastForwardTo(SearchViewManager.SEARCH_DELAY_MS);
+        assertFalse(mListenerOnSearchChangedCalled);
+    }
+
+    @Test
+    public void testOnSearchChanged_NotCalledForOnQueryTextSubmitIfSearchAlreadyFinished()
+            throws Exception {
+        mSearchViewManager.onClick(null);
+        mSearchViewManager.onQueryTextChange("q");
+        fastForwardTo(SearchViewManager.SEARCH_DELAY_MS);
+        // Clear the flag to check if it gets set again.
+        mListenerOnSearchChangedCalled = false;
+        mSearchViewManager.onQueryTextSubmit("q");
+        assertFalse(mListenerOnSearchChangedCalled);
+    }
+}
diff --git a/tests/unit/com/android/documentsui/selection/BandControllerTest.java b/tests/unit/com/android/documentsui/selection/BandControllerTest.java
deleted file mode 100644
index 6a32147..0000000
--- a/tests/unit/com/android/documentsui/selection/BandControllerTest.java
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Copyright (C) 2017 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.documentsui.selection;
-
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.support.v7.widget.RecyclerView.OnScrollListener;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.view.MotionEvent;
-
-import com.android.documentsui.DirectoryReloadLock;
-import com.android.documentsui.dirlist.TestData;
-import com.android.documentsui.dirlist.TestDocumentsAdapter;
-import com.android.documentsui.dirlist.TestFocusHandler;
-import com.android.documentsui.testing.SelectionManagers;
-import com.android.documentsui.testing.TestEvent.Builder;
-
-import java.util.Collections;
-import java.util.List;
-
-@SmallTest
-public class BandControllerTest extends AndroidTestCase {
-
-    private static final List<String> ITEMS = TestData.create(10);
-    private BandController mBandController;
-    private boolean mIsActive;
-
-    @Override
-    public void setUp() throws Exception {
-        mIsActive = false;
-        mBandController = new BandController(new TestSelectionEnvironment(),
-                new TestDocumentsAdapter(ITEMS), SelectionManagers.createTestInstance(ITEMS),
-                new DirectoryReloadLock(), null) {
-          @Override
-          public boolean isActive() {
-              return mIsActive;
-          }
-        };
-    }
-
-    public void testGoodStart() {
-        assertTrue(mBandController.shouldStart(goodStartEventBuilder().build()));
-    }
-
-    public void testBadStart_NoButtons() {
-        assertFalse(mBandController.shouldStart(
-                goodStartEventBuilder().releaseButton(MotionEvent.BUTTON_PRIMARY).build()));
-    }
-
-    public void testBadStart_SecondaryButton() {
-        assertFalse(
-                mBandController.shouldStart(goodStartEventBuilder().secondary().build()));
-    }
-
-    public void testBadStart_TertiaryButton() {
-        assertFalse(
-                mBandController.shouldStart(goodStartEventBuilder().tertiary().build()));
-    }
-
-    public void testBadStart_Touch() {
-        assertFalse(mBandController.shouldStart(
-                goodStartEventBuilder().touch().releaseButton(MotionEvent.BUTTON_PRIMARY).build()));
-    }
-
-    public void testBadStart_inDragSpot() {
-        assertFalse(
-                mBandController.shouldStart(goodStartEventBuilder().at(1).inDragHotspot().build()));
-    }
-
-    public void testBadStart_ActionDown() {
-        assertFalse(mBandController
-                .shouldStart(goodStartEventBuilder().action(MotionEvent.ACTION_DOWN).build()));
-    }
-
-    public void testBadStart_ActionUp() {
-        assertFalse(mBandController
-                .shouldStart(goodStartEventBuilder().action(MotionEvent.ACTION_UP).build()));
-    }
-
-    public void testBadStart_ActionPointerDown() {
-        assertFalse(mBandController.shouldStart(
-                goodStartEventBuilder().action(MotionEvent.ACTION_POINTER_DOWN).build()));
-    }
-
-    public void testBadStart_ActionPointerUp() {
-        assertFalse(mBandController.shouldStart(
-                goodStartEventBuilder().action(MotionEvent.ACTION_POINTER_UP).build()));
-    }
-
-    public void testBadStart_NoItems() {
-        mBandController = new BandController(new TestSelectionEnvironment(),
-                new TestDocumentsAdapter(Collections.EMPTY_LIST),
-                SelectionManagers.createTestInstance(ITEMS),
-                new DirectoryReloadLock(), null);
-        assertFalse(mBandController.shouldStart(goodStartEventBuilder().build()));
-    }
-
-    public void testBadStart_alreadyActive() {
-        mIsActive = true;
-        assertFalse(mBandController.shouldStart(goodStartEventBuilder().build()));
-    }
-
-    public void testGoodStop() {
-        mIsActive = true;
-        assertTrue(mBandController.shouldStop(goodStopEventBuilder().build()));
-    }
-
-    public void testGoodStop_PointerUp() {
-        mIsActive = true;
-        assertTrue(mBandController
-                .shouldStop(goodStopEventBuilder().action(MotionEvent.ACTION_POINTER_UP).build()));
-    }
-
-    public void testGoodStop_Cancel() {
-        mIsActive = true;
-        assertTrue(mBandController
-                .shouldStop(goodStopEventBuilder().action(MotionEvent.ACTION_CANCEL).build()));
-    }
-
-    public void testBadStop_NotActive() {
-        assertFalse(mBandController.shouldStop(goodStopEventBuilder().build()));
-    }
-
-    public void testBadStop_NonMouse() {
-        mIsActive = true;
-        assertFalse(mBandController.shouldStop(goodStopEventBuilder().touch().build()));
-    }
-
-    public void testBadStop_Move() {
-        mIsActive = true;
-        assertFalse(mBandController.shouldStop(
-                goodStopEventBuilder().action(MotionEvent.ACTION_MOVE).touch().build()));
-    }
-
-    public void testBadStop_Down() {
-        mIsActive = true;
-        assertFalse(mBandController.shouldStop(
-                goodStopEventBuilder().action(MotionEvent.ACTION_DOWN).touch().build()));
-    }
-
-
-    private Builder goodStartEventBuilder() {
-        return new Builder().mouse().primary().action(MotionEvent.ACTION_MOVE).notInDragHotspot();
-    }
-
-    private Builder goodStopEventBuilder() {
-        return new Builder().mouse().action(MotionEvent.ACTION_UP).notInDragHotspot();
-    }
-
-    private final class TestSelectionEnvironment implements BandController.SelectionEnvironment {
-        @Override
-        public void scrollBy(int dy) {
-        }
-
-        @Override
-        public void runAtNextFrame(Runnable r) {
-        }
-
-        @Override
-        public void removeCallback(Runnable r) {
-        }
-
-        @Override
-        public void showBand(Rect rect) {
-        }
-
-        @Override
-        public void hideBand() {
-        }
-
-        @Override
-        public void addOnScrollListener(OnScrollListener listener) {
-        }
-
-        @Override
-        public void removeOnScrollListener(OnScrollListener listener) {
-        }
-
-        @Override
-        public int getHeight() {
-            return 0;
-        }
-
-        @Override
-        public void invalidateView() {
-        }
-
-        @Override
-        public Point createAbsolutePoint(Point relativePoint) {
-            return null;
-        }
-
-        @Override
-        public Rect getAbsoluteRectForChildViewAt(int index) {
-            return null;
-        }
-
-        @Override
-        public int getAdapterPositionAt(int index) {
-            return 0;
-        }
-
-        @Override
-        public int getColumnCount() {
-            return 0;
-        }
-
-        @Override
-        public int getChildCount() {
-            return 0;
-        }
-
-        @Override
-        public int getVisibleChildCount() {
-            return 0;
-        }
-
-        @Override
-        public boolean hasView(int adapterPosition) {
-            return false;
-        }
-    }
-}
diff --git a/tests/unit/com/android/documentsui/selection/BandSelectionHelperTest.java b/tests/unit/com/android/documentsui/selection/BandSelectionHelperTest.java
new file mode 100644
index 0000000..87b7a1d
--- /dev/null
+++ b/tests/unit/com/android/documentsui/selection/BandSelectionHelperTest.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v7.widget.RecyclerView.OnScrollListener;
+import android.view.MotionEvent;
+
+import com.android.documentsui.selection.BandSelectionHelper.BandHost;
+import com.android.documentsui.selection.testing.SelectionPredicates;
+import com.android.documentsui.selection.testing.TestAdapter;
+import com.android.documentsui.selection.testing.TestBandPredicate;
+import com.android.documentsui.selection.testing.TestEvents.Builder;
+import com.android.documentsui.selection.testing.TestStableIdProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Collections;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class BandSelectionHelperTest {
+
+    private List<String> mItems;
+    private BandSelectionHelper mBandController;
+    private boolean mIsActive;
+    private Builder mStartBuilder;
+    private Builder mStopBuilder;
+    private MotionEvent mStartEvent;
+    private MotionEvent mStopEvent;
+    private TestBandHost mBandHost;
+    private TestBandPredicate mBandPredicate;
+
+    @Before
+    public void setup() throws Exception {
+        mItems = TestAdapter.createItemList(10);
+        mIsActive = false;
+        TestAdapter adapter = new TestAdapter();
+        adapter.updateTestModelIds(mItems);
+        mBandHost = new TestBandHost();
+        mBandPredicate = new TestBandPredicate();
+
+        SelectionHelper helper = new DefaultSelectionHelper(
+                DefaultSelectionHelper.MODE_SINGLE,
+                adapter,
+                new TestStableIdProvider(adapter),
+                SelectionPredicates.CAN_SET_ANYTHING);
+
+        mBandController = new BandSelectionHelper(
+                mBandHost,
+                adapter,
+                new TestStableIdProvider(adapter),
+                helper,
+                SelectionPredicates.CAN_SET_ANYTHING,
+                mBandPredicate,
+                new ContentLock()) {
+                    @Override
+                    public boolean isActive() {
+                        return mIsActive;
+                    }
+                };
+
+        mStartBuilder = new Builder().mouse().primary().action(MotionEvent.ACTION_MOVE);
+        mStopBuilder = new Builder().mouse().action(MotionEvent.ACTION_UP);
+        mStartEvent = mStartBuilder.build();
+        mStopEvent = mStopBuilder.build();
+    }
+
+    @Test
+    public void testGoodStart() {
+        assertTrue(mBandController.shouldStart(mStartEvent));
+    }
+
+    @Test
+    public void testBadStart_NoButtons() {
+        assertFalse(mBandController.shouldStart(
+                mStartBuilder.releaseButton(MotionEvent.BUTTON_PRIMARY).build()));
+    }
+
+    @Test
+    public void testBadStart_SecondaryButton() {
+        assertFalse(
+                mBandController.shouldStart(mStartBuilder.secondary().build()));
+    }
+
+    @Test
+    public void testBadStart_TertiaryButton() {
+        assertFalse(
+                mBandController.shouldStart(mStartBuilder.tertiary().build()));
+    }
+
+    @Test
+    public void testBadStart_Touch() {
+        assertFalse(mBandController.shouldStart(
+                mStartBuilder.touch().releaseButton(MotionEvent.BUTTON_PRIMARY).build()));
+    }
+
+    @Test
+    public void testBadStart_RespectsCanInitiateBand() {
+        mBandPredicate.setCanInitiate(false);
+        assertFalse(mBandController.shouldStart(mStartEvent));
+    }
+
+    @Test
+    public void testBadStart_ActionDown() {
+        assertFalse(mBandController
+                .shouldStart(mStartBuilder.action(MotionEvent.ACTION_DOWN).build()));
+    }
+
+    @Test
+    public void testBadStart_ActionUp() {
+        assertFalse(mBandController
+                .shouldStart(mStartBuilder.action(MotionEvent.ACTION_UP).build()));
+    }
+
+    @Test
+    public void testBadStart_ActionPointerDown() {
+        assertFalse(mBandController.shouldStart(
+                mStartBuilder.action(MotionEvent.ACTION_POINTER_DOWN).build()));
+    }
+
+    @Test
+    public void testBadStart_ActionPointerUp() {
+        assertFalse(mBandController.shouldStart(
+                mStartBuilder.action(MotionEvent.ACTION_POINTER_UP).build()));
+    }
+
+    @Test
+    public void testBadStart_NoItems() {
+        TestAdapter emptyAdapter = new TestAdapter();
+        emptyAdapter.updateTestModelIds(Collections.EMPTY_LIST);
+
+        SelectionHelper helper = new DefaultSelectionHelper(
+                DefaultSelectionHelper.MODE_SINGLE,
+                emptyAdapter,
+                new TestStableIdProvider(emptyAdapter),
+                SelectionPredicates.CAN_SET_ANYTHING);
+
+        mBandController = new BandSelectionHelper(
+                new TestBandHost(),
+                emptyAdapter,
+                new TestStableIdProvider(emptyAdapter),
+                helper,
+                SelectionPredicates.CAN_SET_ANYTHING,
+                mBandPredicate,
+                new ContentLock());
+
+        assertFalse(mBandController.shouldStart(mStartEvent));
+    }
+
+    @Test
+    public void testBadStart_alreadyActive() {
+        mIsActive = true;
+        assertFalse(mBandController.shouldStart(mStartEvent));
+    }
+
+    @Test
+    public void testGoodStop() {
+        mIsActive = true;
+        assertTrue(mBandController.shouldStop(mStopEvent));
+    }
+
+    @Test
+    public void testGoodStop_PointerUp() {
+        mIsActive = true;
+        assertTrue(mBandController
+                .shouldStop(mStopBuilder.action(MotionEvent.ACTION_POINTER_UP).build()));
+    }
+
+    @Test
+    public void testGoodStop_Cancel() {
+        mIsActive = true;
+        assertTrue(mBandController
+                .shouldStop(mStopBuilder.action(MotionEvent.ACTION_CANCEL).build()));
+    }
+
+    @Test
+    public void testBadStop_NotActive() {
+        assertFalse(mBandController.shouldStop(mStopEvent));
+    }
+
+    @Test
+    public void testBadStop_NonMouse() {
+        mIsActive = true;
+        assertFalse(mBandController.shouldStop(mStopBuilder.touch().build()));
+    }
+
+    @Test
+    public void testBadStop_Move() {
+        mIsActive = true;
+        assertFalse(mBandController.shouldStop(
+                mStopBuilder.action(MotionEvent.ACTION_MOVE).touch().build()));
+    }
+
+    @Test
+    public void testBadStop_Down() {
+        mIsActive = true;
+        assertFalse(mBandController.shouldStop(
+                mStopBuilder.action(MotionEvent.ACTION_DOWN).touch().build()));
+    }
+
+    private final class TestBandHost extends BandHost {
+        @Override
+        public void scrollBy(int dy) {
+        }
+
+        @Override
+        public void runAtNextFrame(Runnable r) {
+        }
+
+        @Override
+        public void removeCallback(Runnable r) {
+        }
+
+        @Override
+        public void showBand(Rect rect) {
+        }
+
+        @Override
+        public void hideBand() {
+        }
+
+        @Override
+        public void addOnScrollListener(OnScrollListener listener) {
+        }
+
+        @Override
+        public void removeOnScrollListener(OnScrollListener listener) {
+        }
+
+        @Override
+        public int getHeight() {
+            return 0;
+        }
+
+        @Override
+        public void invalidateView() {
+        }
+
+        @Override
+        public Point createAbsolutePoint(Point relativePoint) {
+            return null;
+        }
+
+        @Override
+        public Rect getAbsoluteRectForChildViewAt(int index) {
+            return null;
+        }
+
+        @Override
+        public int getAdapterPositionAt(int index) {
+            return 0;
+        }
+
+        @Override
+        public int getColumnCount() {
+            return 0;
+        }
+
+        @Override
+        public int getChildCount() {
+            return 0;
+        }
+
+        @Override
+        public int getVisibleChildCount() {
+            return 0;
+        }
+
+        @Override
+        public boolean hasView(int adapterPosition) {
+            return false;
+        }
+    }
+}
diff --git a/tests/unit/com/android/documentsui/DirectoryReloadLockTest.java b/tests/unit/com/android/documentsui/selection/ContentLockTest.java
similarity index 63%
rename from tests/unit/com/android/documentsui/DirectoryReloadLockTest.java
rename to tests/unit/com/android/documentsui/selection/ContentLockTest.java
index dbbc9c6..71b6b0f 100644
--- a/tests/unit/com/android/documentsui/DirectoryReloadLockTest.java
+++ b/tests/unit/com/android/documentsui/selection/ContentLockTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.documentsui;
+package com.android.documentsui.selection;
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -28,45 +28,49 @@
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
-public class DirectoryReloadLockTest {
+public class ContentLockTest {
 
-    private DirectoryReloadLock lock = new DirectoryReloadLock();
-    private boolean called;
-    private Runnable callback = () -> {
-        called = true;
+    private ContentLock mLock = new ContentLock();
+    private boolean mCalled;
+
+    private Runnable mRunnable = new Runnable() {
+        @Override
+        public void run() {
+            mCalled = true;
+        }
     };
 
     @Before
     public void setUp() {
-        called = false;
+        mCalled = false;
     }
 
     @Test
     public void testNotBlocking_callbackNotBlocked() {
-        lock.tryUpdate(callback);
-        assertTrue(called);
+        mLock.runWhenUnlocked(mRunnable);
+        assertTrue(mCalled);
     }
 
     @Test
     public void testToggleBlocking_callbackNotBlocked() {
-        lock.block();
-        lock.unblock();
-        lock.tryUpdate(callback);
-        assertTrue(called);
+        mLock.block();
+        mLock.unblock();
+        mLock.runWhenUnlocked(mRunnable);
+        assertTrue(mCalled);
     }
 
     @Test
     public void testBlocking_callbackBlocked() {
-        lock.block();
-        lock.tryUpdate(callback);
-        assertFalse(called);
+        mLock.block();
+        mLock.runWhenUnlocked(mRunnable);
+        assertFalse(mCalled);
     }
 
     @Test
     public void testBlockthenUnblock_callbackNotBlocked() {
-        lock.block();
-        lock.tryUpdate(callback);
-        lock.unblock();
-        assertTrue(called);
+        mLock.block();
+        mLock.runWhenUnlocked(mRunnable);
+        mLock.unblock();
+        assertTrue(mCalled);
     }
 }
diff --git a/tests/unit/com/android/documentsui/selection/DefaultSelectionHelperTest.java b/tests/unit/com/android/documentsui/selection/DefaultSelectionHelperTest.java
new file mode 100644
index 0000000..48c0b2a
--- /dev/null
+++ b/tests/unit/com/android/documentsui/selection/DefaultSelectionHelperTest.java
@@ -0,0 +1,409 @@
+/*
+ * 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.documentsui.selection;
+import static org.junit.Assert.assertFalse;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.SparseBooleanArray;
+
+import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
+import com.android.documentsui.selection.testing.SelectionProbe;
+import com.android.documentsui.selection.testing.TestAdapter;
+import com.android.documentsui.selection.testing.TestSelectionObserver;
+import com.android.documentsui.selection.testing.TestStableIdProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class DefaultSelectionHelperTest {
+
+    private List<String> mItems;
+    private Set<String> mIgnored;
+    private TestAdapter mAdapter;
+    private DefaultSelectionHelper mHelper;
+    private TestSelectionObserver mListener;
+    private SelectionProbe mSelection;
+
+    @Before
+    public void setUp() throws Exception {
+        mIgnored = new HashSet<>();
+        mItems = TestAdapter.createItemList(100);
+        mListener = new TestSelectionObserver();
+        mAdapter = new TestAdapter();
+        mAdapter.updateTestModelIds(mItems);
+
+        SelectionPredicate canSelect = new SelectionPredicate() {
+
+            @Override
+            public boolean canSetStateForId(String id, boolean nextState) {
+                return !nextState || !mIgnored.contains(id);
+            }
+
+            @Override
+            public boolean canSetStateAtPosition(int position, boolean nextState) {
+                throw new UnsupportedOperationException("Not implemented.");
+            }
+        };
+        mHelper = new DefaultSelectionHelper(
+                DefaultSelectionHelper.MODE_MULTIPLE,
+                mAdapter,
+                new TestStableIdProvider(mAdapter),
+                canSelect);
+
+        mHelper.addObserver(mListener);
+
+        mSelection = new SelectionProbe(mHelper, mListener);
+
+        mIgnored.clear();
+    }
+
+    @Test
+    public void testSelect() {
+        mHelper.select(mItems.get(7));
+
+        mSelection.assertSelection(7);
+    }
+
+    @Test
+    public void testDeselect() {
+        mHelper.select(mItems.get(7));
+        mHelper.deselect(mItems.get(7));
+
+        mSelection.assertNoSelection();
+    }
+
+    @Test
+    public void testSelection_DoNothingOnUnselectableItem() {
+        mIgnored.add(mItems.get(7));
+        boolean selected = mHelper.select(mItems.get(7));
+
+        assertFalse(selected);
+        mSelection.assertNoSelection();
+    }
+
+    @Test
+    public void testSelect_NotifiesListenersOfChange() {
+        mHelper.select(mItems.get(7));
+
+        mListener.assertSelectionChanged();
+    }
+
+    @Test
+    public void testSelect_NotifiesAdapterOfSelect() {
+        mHelper.select(mItems.get(7));
+
+        mAdapter.assertNotifiedOfSelectionChange(7);
+    }
+
+    @Test
+    public void testSelect_NotifiesAdapterOfDeselect() {
+        mHelper.select(mItems.get(7));
+        mAdapter.resetSelectionNotifications();
+        mHelper.deselect(mItems.get(7));
+        mAdapter.assertNotifiedOfSelectionChange(7);
+    }
+
+    @Test
+    public void testDeselect_NotifiesSelectionChanged() {
+        mHelper.select(mItems.get(7));
+        mHelper.deselect(mItems.get(7));
+
+        mListener.assertSelectionChanged();
+    }
+
+    @Test
+    public void testSelection_PersistsOnUpdate() {
+        mHelper.select(mItems.get(7));
+        mAdapter.updateTestModelIds(mItems);
+
+        mSelection.assertSelection(7);
+    }
+
+    @Test
+    public void testSelection_IntersectsWithNewDataSet() {
+        mHelper.select(mItems.get(99));
+        mHelper.select(mItems.get(7));
+
+        mAdapter.updateTestModelIds(TestAdapter.createItemList(50));
+
+        mSelection.assertSelection(7);
+    }
+
+    @Test
+    public void testSetItemsSelected() {
+        mHelper.setItemsSelected(getStringIds(6, 7, 8), true);
+
+        mSelection.assertRangeSelected(6, 8);
+    }
+
+    @Test
+    public void testSetItemsSelected_SkipUnselectableItem() {
+        mIgnored.add(mItems.get(7));
+
+        mHelper.setItemsSelected(getStringIds(6, 7, 8), true);
+
+        mSelection.assertSelected(6);
+        mSelection.assertNotSelected(7);
+        mSelection.assertSelected(8);
+    }
+
+    @Test
+    public void testRangeSelection() {
+        mHelper.startRange(15);
+        mHelper.extendRange(19);
+        mSelection.assertRangeSelection(15, 19);
+    }
+
+    @Test
+    public void testRangeSelection_SkipUnselectableItem() {
+        mIgnored.add(mItems.get(17));
+
+        mHelper.startRange(15);
+        mHelper.extendRange(19);
+
+        mSelection.assertRangeSelected(15, 16);
+        mSelection.assertNotSelected(17);
+        mSelection.assertRangeSelected(18, 19);
+    }
+
+    @Test
+    public void testRangeSelection_snapExpand() {
+        mHelper.startRange(15);
+        mHelper.extendRange(19);
+        mHelper.extendRange(27);
+        mSelection.assertRangeSelection(15, 27);
+    }
+
+    @Test
+    public void testRangeSelection_snapContract() {
+        mHelper.startRange(15);
+        mHelper.extendRange(27);
+        mHelper.extendRange(19);
+        mSelection.assertRangeSelection(15, 19);
+    }
+
+    @Test
+    public void testRangeSelection_snapInvert() {
+        mHelper.startRange(15);
+        mHelper.extendRange(27);
+        mHelper.extendRange(3);
+        mSelection.assertRangeSelection(3, 15);
+    }
+
+    @Test
+    public void testRangeSelection_multiple() {
+        mHelper.startRange(15);
+        mHelper.extendRange(27);
+        mHelper.endRange();
+        mHelper.startRange(42);
+        mHelper.extendRange(57);
+        mSelection.assertSelectionSize(29);
+        mSelection.assertRangeSelected(15, 27);
+        mSelection.assertRangeSelected(42, 57);
+    }
+
+    @Test
+    public void testProvisionalRangeSelection() {
+        mHelper.startRange(13);
+        mHelper.extendProvisionalRange(15);
+        mSelection.assertRangeSelection(13, 15);
+        mHelper.getSelection().mergeProvisionalSelection();
+        mHelper.endRange();
+        mSelection.assertSelectionSize(3);
+    }
+
+    @Test
+    public void testProvisionalRangeSelection_endEarly() {
+        mHelper.startRange(13);
+        mHelper.extendProvisionalRange(15);
+        mSelection.assertRangeSelection(13, 15);
+
+        mHelper.endRange();
+        // If we end range selection prematurely for provision selection, nothing should be selected
+        // except the first item
+        mSelection.assertSelectionSize(1);
+    }
+
+    @Test
+    public void testProvisionalRangeSelection_snapExpand() {
+        mHelper.startRange(13);
+        mHelper.extendProvisionalRange(15);
+        mSelection.assertRangeSelection(13, 15);
+        mHelper.getSelection().mergeProvisionalSelection();
+        mHelper.extendRange(18);
+        mSelection.assertRangeSelection(13, 18);
+    }
+
+    @Test
+    public void testCombinationRangeSelection_IntersectsOldSelection() {
+        mHelper.startRange(13);
+        mHelper.extendRange(15);
+        mSelection.assertRangeSelection(13, 15);
+
+        mHelper.startRange(11);
+        mHelper.extendProvisionalRange(18);
+        mSelection.assertRangeSelected(11, 18);
+        mHelper.endRange();
+        mSelection.assertRangeSelected(13, 15);
+        mSelection.assertRangeSelected(11, 11);
+        mSelection.assertSelectionSize(4);
+    }
+
+    @Test
+    public void testProvisionalSelection() {
+        Selection s = mHelper.getSelection();
+        mSelection.assertNoSelection();
+
+        // Mimicking band selection case -- BandController notifies item callback by itself.
+        mListener.onItemStateChanged(mItems.get(1), true);
+        mListener.onItemStateChanged(mItems.get(2), true);
+
+        SparseBooleanArray provisional = new SparseBooleanArray();
+        provisional.append(1, true);
+        provisional.append(2, true);
+        s.setProvisionalSelection(getItemIds(provisional));
+        mSelection.assertSelection(1, 2);
+    }
+
+    @Test
+    public void testProvisionalSelection_Replace() {
+        Selection s = mHelper.getSelection();
+
+        // Mimicking band selection case -- BandController notifies item callback by itself.
+        mListener.onItemStateChanged(mItems.get(1), true);
+        mListener.onItemStateChanged(mItems.get(2), true);
+        SparseBooleanArray provisional = new SparseBooleanArray();
+        provisional.append(1, true);
+        provisional.append(2, true);
+        s.setProvisionalSelection(getItemIds(provisional));
+
+        mListener.onItemStateChanged(mItems.get(1), false);
+        mListener.onItemStateChanged(mItems.get(2), false);
+        provisional.clear();
+
+        mListener.onItemStateChanged(mItems.get(3), true);
+        mListener.onItemStateChanged(mItems.get(4), true);
+        provisional.append(3, true);
+        provisional.append(4, true);
+        s.setProvisionalSelection(getItemIds(provisional));
+        mSelection.assertSelection(3, 4);
+    }
+
+    @Test
+    public void testProvisionalSelection_IntersectsExistingProvisionalSelection() {
+        Selection s = mHelper.getSelection();
+
+        // Mimicking band selection case -- BandController notifies item callback by itself.
+        mListener.onItemStateChanged(mItems.get(1), true);
+        mListener.onItemStateChanged(mItems.get(2), true);
+        SparseBooleanArray provisional = new SparseBooleanArray();
+        provisional.append(1, true);
+        provisional.append(2, true);
+        s.setProvisionalSelection(getItemIds(provisional));
+
+        mListener.onItemStateChanged(mItems.get(1), false);
+        mListener.onItemStateChanged(mItems.get(2), false);
+        provisional.clear();
+
+        mListener.onItemStateChanged(mItems.get(1), true);
+        provisional.append(1, true);
+        s.setProvisionalSelection(getItemIds(provisional));
+        mSelection.assertSelection(1);
+    }
+
+    @Test
+    public void testProvisionalSelection_Apply() {
+        Selection s = mHelper.getSelection();
+
+        // Mimicking band selection case -- BandController notifies item callback by itself.
+        mListener.onItemStateChanged(mItems.get(1), true);
+        mListener.onItemStateChanged(mItems.get(2), true);
+        SparseBooleanArray provisional = new SparseBooleanArray();
+        provisional.append(1, true);
+        provisional.append(2, true);
+        s.setProvisionalSelection(getItemIds(provisional));
+        s.mergeProvisionalSelection();
+
+        mSelection.assertSelection(1, 2);
+    }
+
+    @Test
+    public void testProvisionalSelection_Cancel() {
+        mHelper.select(mItems.get(1));
+        mHelper.select(mItems.get(2));
+        Selection s = mHelper.getSelection();
+
+        SparseBooleanArray provisional = new SparseBooleanArray();
+        provisional.append(3, true);
+        provisional.append(4, true);
+        s.setProvisionalSelection(getItemIds(provisional));
+        s.clearProvisionalSelection();
+
+        // Original selection should remain.
+        mSelection.assertSelection(1, 2);
+    }
+
+    @Test
+    public void testProvisionalSelection_IntersectsAppliedSelection() {
+        mHelper.select(mItems.get(1));
+        mHelper.select(mItems.get(2));
+        Selection s = mHelper.getSelection();
+
+        // Mimicking band selection case -- BandController notifies item callback by itself.
+        mListener.onItemStateChanged(mItems.get(3), true);
+        SparseBooleanArray provisional = new SparseBooleanArray();
+        provisional.append(2, true);
+        provisional.append(3, true);
+        s.setProvisionalSelection(getItemIds(provisional));
+        mSelection.assertSelection(1, 2, 3);
+    }
+
+    @Test
+    public void testObserverOnChanged_NotifiesListenersOfChange() {
+        mAdapter.notifyDataSetChanged();
+
+        mListener.assertSelectionChanged();
+    }
+
+    private Set<String> getItemIds(SparseBooleanArray selection) {
+        Set<String> ids = new HashSet<>();
+
+        int count = selection.size();
+        for (int i = 0; i < count; ++i) {
+            ids.add(mItems.get(selection.keyAt(i)));
+        }
+
+        return ids;
+    }
+
+    private Iterable<String> getStringIds(int... ids) {
+        List<String> stringIds = new ArrayList<>(ids.length);
+        for (int id : ids) {
+            stringIds.add(mItems.get(id));
+        }
+        return stringIds;
+    }
+}
diff --git a/tests/unit/com/android/documentsui/selection/DefaultSelectionHelper_SingleSelectTest.java b/tests/unit/com/android/documentsui/selection/DefaultSelectionHelper_SingleSelectTest.java
new file mode 100644
index 0000000..563ce87
--- /dev/null
+++ b/tests/unit/com/android/documentsui/selection/DefaultSelectionHelper_SingleSelectTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.documentsui.selection;
+
+import static org.junit.Assert.fail;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.documentsui.selection.testing.SelectionPredicates;
+import com.android.documentsui.selection.testing.SelectionProbe;
+import com.android.documentsui.selection.testing.TestAdapter;
+import com.android.documentsui.selection.testing.TestSelectionObserver;
+import com.android.documentsui.selection.testing.TestStableIdProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class DefaultSelectionHelper_SingleSelectTest {
+
+    private List<String> mItems;
+    private SelectionHelper mHelper;
+    private TestSelectionObserver mListener;
+    private SelectionProbe mSelection;
+
+    @Before
+    public void setUp() throws Exception {
+        mItems = TestAdapter.createItemList(100);
+        mListener = new TestSelectionObserver();
+        TestAdapter adapter = new TestAdapter();
+        adapter.updateTestModelIds(mItems);
+
+        mHelper = new DefaultSelectionHelper(
+                DefaultSelectionHelper.MODE_SINGLE,
+                adapter,
+                new TestStableIdProvider(adapter),
+                SelectionPredicates.CAN_SET_ANYTHING);
+
+        mHelper.addObserver(mListener);
+
+        mSelection = new SelectionProbe(mHelper);
+    }
+
+    @Test
+    public void testSimpleSelect() {
+        mHelper.select(mItems.get(3));
+        mHelper.select(mItems.get(4));
+        mListener.assertSelectionChanged();
+        mSelection.assertSelection(4);
+    }
+
+    @Test
+    public void testRangeSelectionNotEstablished() {
+        mHelper.select(mItems.get(3));
+        mListener.reset();
+
+        try {
+            mHelper.extendRange(10);
+            fail("Should have thrown.");
+        } catch (Exception expected) {}
+
+        mListener.assertSelectionUnchanged();
+        mSelection.assertSelection(3);
+    }
+}
diff --git a/tests/unit/com/android/documentsui/selection/GestureRouterTest.java b/tests/unit/com/android/documentsui/selection/GestureRouterTest.java
new file mode 100644
index 0000000..e467f0f
--- /dev/null
+++ b/tests/unit/com/android/documentsui/selection/GestureRouterTest.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2016 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.documentsui.selection;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyFloat;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.GestureDetector.OnDoubleTapListener;
+import android.view.GestureDetector.OnGestureListener;
+import android.view.MotionEvent;
+
+import com.android.documentsui.selection.testing.TestEvents.Mouse;
+import com.android.documentsui.selection.testing.TestEvents.Touch;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public final class GestureRouterTest {
+
+    private TestHandler mHandler;
+    private TestHandler mAlt;
+    private GestureRouter<TestHandler> mRouter;
+
+    @Before
+    public void setUp() {
+        mAlt = new TestHandler();
+        mHandler = new TestHandler();
+    }
+
+    @Test
+    public void testDelegates() {
+        mRouter = new GestureRouter<>();
+        mRouter.register(MotionEvent.TOOL_TYPE_MOUSE, mHandler);
+        mRouter.register(MotionEvent.TOOL_TYPE_FINGER, mAlt);
+
+        mRouter.onDown(Mouse.CLICK);
+        mHandler.assertCalled_onDown(Mouse.CLICK);
+        mAlt.assertNotCalled_onDown();
+
+        mRouter.onShowPress(Mouse.CLICK);
+        mHandler.assertCalled_onShowPress(Mouse.CLICK);
+        mAlt.assertNotCalled_onShowPress();
+
+        mRouter.onSingleTapUp(Mouse.CLICK);
+        mHandler.assertCalled_onSingleTapUp(Mouse.CLICK);
+        mAlt.assertNotCalled_onSingleTapUp();
+
+        mRouter.onScroll(null, Mouse.CLICK, -1, -1);
+        mHandler.assertCalled_onScroll(null, Mouse.CLICK, -1, -1);
+        mAlt.assertNotCalled_onScroll();
+
+        mRouter.onLongPress(Mouse.CLICK);
+        mHandler.assertCalled_onLongPress(Mouse.CLICK);
+        mAlt.assertNotCalled_onLongPress();
+
+        mRouter.onFling(null, Mouse.CLICK, -1, -1);
+        mHandler.assertCalled_onFling(null, Mouse.CLICK, -1, -1);
+        mAlt.assertNotCalled_onFling();
+
+        mRouter.onSingleTapConfirmed(Mouse.CLICK);
+        mHandler.assertCalled_onSingleTapConfirmed(Mouse.CLICK);
+        mAlt.assertNotCalled_onSingleTapConfirmed();
+
+        mRouter.onDoubleTap(Mouse.CLICK);
+        mHandler.assertCalled_onDoubleTap(Mouse.CLICK);
+        mAlt.assertNotCalled_onDoubleTap();
+
+        mRouter.onDoubleTapEvent(Mouse.CLICK);
+        mHandler.assertCalled_onDoubleTapEvent(Mouse.CLICK);
+        mAlt.assertNotCalled_onDoubleTapEvent();
+    }
+
+    @Test
+    public void testFallsback() {
+        mRouter = new GestureRouter<>(mAlt);
+        mRouter.register(MotionEvent.TOOL_TYPE_MOUSE, mHandler);
+
+        mRouter.onDown(Touch.TAP);
+        mAlt.assertCalled_onDown(Touch.TAP);
+
+        mRouter.onShowPress(Touch.TAP);
+        mAlt.assertCalled_onShowPress(Touch.TAP);
+
+        mRouter.onSingleTapUp(Touch.TAP);
+        mAlt.assertCalled_onSingleTapUp(Touch.TAP);
+
+        mRouter.onScroll(null, Touch.TAP, -1, -1);
+        mAlt.assertCalled_onScroll(null, Touch.TAP, -1, -1);
+
+        mRouter.onLongPress(Touch.TAP);
+        mAlt.assertCalled_onLongPress(Touch.TAP);
+
+        mRouter.onFling(null, Touch.TAP, -1, -1);
+        mAlt.assertCalled_onFling(null, Touch.TAP, -1, -1);
+
+        mRouter.onSingleTapConfirmed(Touch.TAP);
+        mAlt.assertCalled_onSingleTapConfirmed(Touch.TAP);
+
+        mRouter.onDoubleTap(Touch.TAP);
+        mAlt.assertCalled_onDoubleTap(Touch.TAP);
+
+        mRouter.onDoubleTapEvent(Touch.TAP);
+        mAlt.assertCalled_onDoubleTapEvent(Touch.TAP);
+    }
+
+    @Test
+    public void testEatsEventsWhenNoFallback() {
+        mRouter = new GestureRouter<>();
+        // Register the the delegate on mouse so touch events don't get handled.
+        mRouter.register(MotionEvent.TOOL_TYPE_MOUSE, mHandler);
+
+        mRouter.onDown(Touch.TAP);
+        mAlt.assertNotCalled_onDown();
+
+        mRouter.onShowPress(Touch.TAP);
+        mAlt.assertNotCalled_onShowPress();
+
+        mRouter.onSingleTapUp(Touch.TAP);
+        mAlt.assertNotCalled_onSingleTapUp();
+
+        mRouter.onScroll(null, Touch.TAP, -1, -1);
+        mAlt.assertNotCalled_onScroll();
+
+        mRouter.onLongPress(Touch.TAP);
+        mAlt.assertNotCalled_onLongPress();
+
+        mRouter.onFling(null, Touch.TAP, -1, -1);
+        mAlt.assertNotCalled_onFling();
+
+        mRouter.onSingleTapConfirmed(Touch.TAP);
+        mAlt.assertNotCalled_onSingleTapConfirmed();
+
+        mRouter.onDoubleTap(Touch.TAP);
+        mAlt.assertNotCalled_onDoubleTap();
+
+        mRouter.onDoubleTapEvent(Touch.TAP);
+        mAlt.assertNotCalled_onDoubleTapEvent();
+    }
+
+    private static final class TestHandler implements OnGestureListener, OnDoubleTapListener {
+
+        private final Spy mSpy = Mockito.mock(Spy.class);
+
+        @Override
+        public boolean onDown(MotionEvent e) {
+            return mSpy.onDown(e);
+        }
+
+        @Override
+        public void onShowPress(MotionEvent e) {
+            mSpy.onShowPress(e);
+        }
+
+        @Override
+        public boolean onSingleTapUp(MotionEvent e) {
+            return mSpy.onSingleTapUp(e);
+        }
+
+        @Override
+        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
+            return mSpy.onScroll(e1, e2, distanceX, distanceY);
+        }
+
+        @Override
+        public void onLongPress(MotionEvent e) {
+            mSpy.onLongPress(e);
+        }
+
+        @Override
+        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+            return mSpy.onFling(e1, e2, velocityX, velocityY);
+        }
+
+        @Override
+        public boolean onSingleTapConfirmed(MotionEvent e) {
+            return mSpy.onSingleTapConfirmed(e);
+        }
+
+        @Override
+        public boolean onDoubleTap(MotionEvent e) {
+            return mSpy.onDoubleTap(e);
+        }
+
+        @Override
+        public boolean onDoubleTapEvent(MotionEvent e) {
+            return mSpy.onDoubleTapEvent(e);
+        }
+
+        void assertCalled_onDown(MotionEvent e) {
+            verify(mSpy).onDown(e);
+        }
+
+        void assertCalled_onShowPress(MotionEvent e) {
+            verify(mSpy).onShowPress(e);
+        }
+
+        void assertCalled_onSingleTapUp(MotionEvent e) {
+            verify(mSpy).onSingleTapUp(e);
+        }
+
+        void assertCalled_onScroll(MotionEvent e1, MotionEvent e2, float x, float y) {
+            verify(mSpy).onScroll(e1, e2, x, y);
+        }
+
+        void assertCalled_onLongPress(MotionEvent e) {
+            verify(mSpy).onLongPress(e);
+        }
+
+        void assertCalled_onFling(MotionEvent e1, MotionEvent e2, float x, float y) {
+            Mockito.verify(mSpy).onFling(e1, e2, x, y);
+        }
+
+        void assertCalled_onSingleTapConfirmed(MotionEvent e) {
+            Mockito.verify(mSpy).onSingleTapConfirmed(e);
+        }
+
+        void assertCalled_onDoubleTap(MotionEvent e) {
+            Mockito.verify(mSpy).onDoubleTap(e);
+        }
+
+        void assertCalled_onDoubleTapEvent(MotionEvent e) {
+            Mockito.verify(mSpy).onDoubleTapEvent(e);
+        }
+
+        void assertNotCalled_onDown() {
+            verify(mSpy, never()).onDown(any());
+        }
+
+        void assertNotCalled_onShowPress() {
+            verify(mSpy, never()).onShowPress(any());
+        }
+
+        void assertNotCalled_onSingleTapUp() {
+            verify(mSpy, never()).onSingleTapUp(any());
+        }
+
+        void assertNotCalled_onScroll() {
+            verify(mSpy, never()).onScroll(any(), any(), anyFloat(), anyFloat());
+        }
+
+        void assertNotCalled_onLongPress() {
+            verify(mSpy, never()).onLongPress(any());
+        }
+
+        void assertNotCalled_onFling() {
+            Mockito.verify(mSpy, never()).onFling(any(), any(), anyFloat(), anyFloat());
+        }
+
+        void assertNotCalled_onSingleTapConfirmed() {
+            Mockito.verify(mSpy, never()).onSingleTapConfirmed(any());
+        }
+
+        void assertNotCalled_onDoubleTap() {
+            Mockito.verify(mSpy, never()).onDoubleTap(any());
+        }
+
+        void assertNotCalled_onDoubleTapEvent() {
+            Mockito.verify(mSpy, never()).onDoubleTapEvent(any());
+        }
+    }
+
+    private static interface Spy extends OnGestureListener, OnDoubleTapListener {}
+}
diff --git a/tests/unit/com/android/documentsui/selection/GestureSelectionHelperTest.java b/tests/unit/com/android/documentsui/selection/GestureSelectionHelperTest.java
new file mode 100644
index 0000000..df69fdf
--- /dev/null
+++ b/tests/unit/com/android/documentsui/selection/GestureSelectionHelperTest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2016 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.documentsui.selection;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v7.widget.RecyclerView;
+
+import android.view.MotionEvent;
+
+import com.android.documentsui.selection.testing.SelectionProbe;
+import com.android.documentsui.selection.testing.TestData;
+import com.android.documentsui.testing.SelectionHelpers;
+import com.android.documentsui.testing.TestEvents;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class GestureSelectionHelperTest {
+
+    private static final List<String> ITEMS = TestData.create(100);
+    private static final MotionEvent DOWN = TestEvents.builder()
+            .action(MotionEvent.ACTION_DOWN)
+            .location(1, 1)
+            .build();
+
+    private static final MotionEvent MOVE = TestEvents.builder()
+            .action(MotionEvent.ACTION_MOVE)
+            .location(1, 1)
+            .build();
+
+    private static final MotionEvent UP = TestEvents.builder()
+            .action(MotionEvent.ACTION_UP)
+            .location(1, 1)
+            .build();
+
+    private GestureSelectionHelper mHelper;
+    private SelectionHelper mSelectionHelper;
+    private SelectionProbe mSelection;
+    private ContentLock mLock;
+    private TestItemDetailsLookup mItemLookup;
+    private TestViewDelegate mView;
+
+    @Before
+    public void setUp() {
+        mSelectionHelper = SelectionHelpers.createTestInstance(ITEMS);
+        mSelection = new SelectionProbe(mSelectionHelper);
+        mLock = new ContentLock();
+        mItemLookup = new TestItemDetailsLookup();
+        mItemLookup.initAt(3);
+        mView = new TestViewDelegate();
+        mHelper = new GestureSelectionHelper(mSelectionHelper, mView, mLock, mItemLookup);
+    }
+
+    @Test
+    public void testIgnoresDown_NoPosition() {
+        mView.mNextPosition = RecyclerView.NO_POSITION;
+        assertFalse(mHelper.onInterceptTouchEvent(null, DOWN));
+    }
+
+    @Test
+    public void testIgnoresDown_NoItemDetails() {
+        mItemLookup.reset();
+        assertFalse(mHelper.onInterceptTouchEvent(null, DOWN));
+    }
+
+    @Test
+    public void testNoStartOnIllegalPosition() {
+        mView.mNextPosition = -1;
+        mHelper.onInterceptTouchEvent(null, DOWN);
+        mHelper.start();
+        assertFalse(mLock.isLocked());
+    }
+
+    @Test
+    public void testDoesNotClaimDownOnItem() {
+        mView.mNextPosition = 0;
+        assertFalse(mHelper.onInterceptTouchEvent(null, DOWN));
+    }
+
+    @Test
+    public void testClaimsMoveIfStarted() {
+        mView.mNextPosition = 0;
+        // TODO(b/109808552): This should be removed with that bug is fixed because it will be a
+        // no-op at that time.
+        mHelper.onInterceptTouchEvent(null, DOWN);
+
+        // Normally, this is controller by the TouchSelectionHelper via a a long press gesture.
+        mSelectionHelper.select("1");
+        mSelectionHelper.anchorRange(1);
+        mHelper.start();
+        assertTrue(mHelper.onInterceptTouchEvent(null, MOVE));
+    }
+
+    @Test
+    public void testCreatesRangeSelection() {
+        mView.mNextPosition = 1;
+        mHelper.onInterceptTouchEvent(null, DOWN);
+        // Another way we are implicitly coupled to TouchInputHandler, is that we depend on
+        // long press to establish the initial anchor point. Without that we'll get an
+        // error when we try to extend the range.
+
+        mSelectionHelper.select("1");
+        mSelectionHelper.anchorRange(1);
+        mHelper.start();
+
+        mHelper.onTouchEvent(null, MOVE);
+
+        mView.mNextPosition = 9;
+        mHelper.onTouchEvent(null, MOVE);
+        mHelper.onTouchEvent(null, UP);
+
+        mSelection.assertRangeSelected(1, 9);
+    }
+
+    private static final class TestViewDelegate extends GestureSelectionHelper.ViewDelegate {
+
+        private int mNextPosition = RecyclerView.NO_POSITION;
+
+        @Override
+        int getHeight() {
+            return 1000;
+        }
+
+        @Override
+        int getItemUnder(MotionEvent e) {
+            return mNextPosition;
+        }
+
+        @Override
+        int getLastGlidedItemPosition(MotionEvent e) {
+            return mNextPosition;
+        }
+    }
+}
diff --git a/tests/unit/com/android/documentsui/selection/GestureSelectionHelper_RecyclerViewDelegateTest.java b/tests/unit/com/android/documentsui/selection/GestureSelectionHelper_RecyclerViewDelegateTest.java
new file mode 100644
index 0000000..9e05d0c
--- /dev/null
+++ b/tests/unit/com/android/documentsui/selection/GestureSelectionHelper_RecyclerViewDelegateTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 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.documentsui.selection;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.android.documentsui.selection.GestureSelectionHelper.RecyclerViewDelegate;
+import com.android.documentsui.testing.TestEvents;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class GestureSelectionHelper_RecyclerViewDelegateTest {
+
+    // Simulate a (20, 20) box locating at (20, 20)
+    static final int LEFT_BORDER = 20;
+    static final int RIGHT_BORDER = 40;
+    static final int TOP_BORDER = 20;
+    static final int BOTTOM_BORDER = 40;
+
+    @Test
+    public void testLtrPastLastItem() {
+        MotionEvent event = createEvent(100, 100);
+        assertTrue(RecyclerViewDelegate.isPastLastItem(
+                TOP_BORDER, LEFT_BORDER, RIGHT_BORDER, event, View.LAYOUT_DIRECTION_LTR));
+    }
+
+    @Test
+    public void testLtrPastLastItem_Inverse() {
+        MotionEvent event = createEvent(10, 10);
+        assertFalse(RecyclerViewDelegate.isPastLastItem(
+                TOP_BORDER, LEFT_BORDER, RIGHT_BORDER, event, View.LAYOUT_DIRECTION_LTR));
+    }
+
+    @Test
+    public void testRtlPastLastItem() {
+        MotionEvent event = createEvent(10, 30);
+        assertTrue(RecyclerViewDelegate.isPastLastItem(
+                TOP_BORDER, LEFT_BORDER, RIGHT_BORDER, event, View.LAYOUT_DIRECTION_RTL));
+    }
+
+    @Test
+    public void testRtlPastLastItem_Inverse() {
+        MotionEvent event = createEvent(100, 100);
+        assertFalse(RecyclerViewDelegate.isPastLastItem(
+                TOP_BORDER, LEFT_BORDER, RIGHT_BORDER, event, View.LAYOUT_DIRECTION_RTL));
+    }
+
+    private static MotionEvent createEvent(int x, int y) {
+        return TestEvents.builder().action(MotionEvent.ACTION_MOVE).location(x, y).build();
+    }
+}
diff --git a/tests/unit/com/android/documentsui/selection/GestureSelectorTest.java b/tests/unit/com/android/documentsui/selection/GestureSelectorTest.java
deleted file mode 100644
index 85a857a..0000000
--- a/tests/unit/com/android/documentsui/selection/GestureSelectorTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2016 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.documentsui.selection;
-
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.view.View;
-
-import com.android.documentsui.selection.GestureSelector;
-import com.android.documentsui.testing.TestEvent;
-
-@SmallTest
-public class GestureSelectorTest extends AndroidTestCase {
-
-    TestEvent.Builder e;
-
-    // Simulate a (20, 20) box locating at (20, 20)
-    static final int LEFT_BORDER = 20;
-    static final int RIGHT_BORDER = 40;
-    static final int TOP_BORDER = 20;
-    static final int BOTTOM_BORDER = 40;
-
-    @Override
-    public void setUp() throws Exception {
-        e = TestEvent.builder()
-                .location(100, 100);
-    }
-
-    public void testLTRPastLastItem() {
-        assertTrue(GestureSelector.isPastLastItem(
-                TOP_BORDER, LEFT_BORDER, RIGHT_BORDER, e.build(), View.LAYOUT_DIRECTION_LTR));
-    }
-
-    public void testLTRPastLastItem_Inverse() {
-        e.location(10, 10);
-        assertFalse(GestureSelector.isPastLastItem(
-                TOP_BORDER, LEFT_BORDER, RIGHT_BORDER, e.build(), View.LAYOUT_DIRECTION_LTR));
-    }
-
-    public void testRTLPastLastItem() {
-        e.location(10, 30);
-        assertTrue(GestureSelector.isPastLastItem(
-                TOP_BORDER, LEFT_BORDER, RIGHT_BORDER, e.build(), View.LAYOUT_DIRECTION_RTL));
-    }
-
-    public void testRTLPastLastItem_Inverse() {
-        assertFalse(GestureSelector.isPastLastItem(
-                TOP_BORDER, LEFT_BORDER, RIGHT_BORDER, e.build(), View.LAYOUT_DIRECTION_RTL));
-    }
-}
diff --git a/tests/unit/com/android/documentsui/selection/BandController_GridModelTest.java b/tests/unit/com/android/documentsui/selection/GridModelTest.java
similarity index 78%
rename from tests/unit/com/android/documentsui/selection/BandController_GridModelTest.java
rename to tests/unit/com/android/documentsui/selection/GridModelTest.java
index 4ce161d..1cb2900 100644
--- a/tests/unit/com/android/documentsui/selection/BandController_GridModelTest.java
+++ b/tests/unit/com/android/documentsui/selection/GridModelTest.java
@@ -16,33 +16,45 @@
 
 package com.android.documentsui.selection;
 
-import static com.android.documentsui.selection.BandController.GridModel.NOT_SET;
+import static com.android.documentsui.selection.GridModel.NOT_SET;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.support.v7.widget.RecyclerView.OnScrollListener;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
 
-import com.android.documentsui.dirlist.TestDocumentsAdapter;
-import com.android.documentsui.selection.BandController.GridModel;
+import com.android.documentsui.selection.BandSelectionHelper.BandHost;
+import com.android.documentsui.selection.testing.SelectionPredicates;
+import com.android.documentsui.selection.testing.TestAdapter;
+import com.android.documentsui.selection.testing.TestStableIdProvider;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 
+import javax.annotation.Nullable;
+
+@RunWith(AndroidJUnit4.class)
 @SmallTest
-public class BandController_GridModelTest extends AndroidTestCase {
+public class GridModelTest {
 
     private static final int VIEW_PADDING_PX = 5;
     private static final int CHILD_VIEW_EDGE_PX = 100;
     private static final int VIEWPORT_HEIGHT = 500;
 
-    private GridModel model;
-    private TestEnvironment env;
-    private TestDocumentsAdapter adapter;
-    private Set<String> lastSelection;
-    private int viewWidth;
+    private GridModel mModel;
+    private TestHost mHost;
+    private TestAdapter mAdapter;
+    private Set<String> mLastSelection;
+    private int mViewWidth;
 
     // TLDR: Don't call model.{start|resize}Selection; use the local #startSelection and
     // #resizeSelection methods instead.
@@ -55,91 +67,68 @@
     private Point mSelectionOrigin;
     private Point mSelectionPoint;
 
-    private void initData(final int numChildren, int numColumns) {
-        env = new TestEnvironment(numChildren, numColumns);
-        adapter = new TestDocumentsAdapter(new ArrayList<String>()) {
-            @Override
-            public String getModelId(int position) {
-                return Integer.toString(position);
-            }
-
-            @Override
-            public int getItemCount() {
-                return numChildren;
-            }
-        };
-
-        viewWidth = VIEW_PADDING_PX + numColumns * (VIEW_PADDING_PX + CHILD_VIEW_EDGE_PX);
-        model = new GridModel(env, (int pos) -> true, adapter);
-        model.addOnSelectionChangedListener(
-                new GridModel.OnSelectionChangedListener() {
-                    @Override
-                    public void onSelectionChanged(Set<String> updatedSelection) {
-                        lastSelection = updatedSelection;
-                    }
-
-                    @Override
-                    public boolean onBeforeItemStateChange(String id, boolean nextState) {
-                        return true;
-                    }
-                });
-    }
-
-    @Override
+    @After
     public void tearDown() {
-        model = null;
-        env = null;
-        lastSelection = null;
+        mModel = null;
+        mHost = null;
+        mLastSelection = null;
     }
 
+    @Test
     public void testSelectionLeftOfItems() {
         initData(20, 5);
         startSelection(new Point(0, 10));
         resizeSelection(new Point(1, 11));
         assertNoSelection();
-        assertEquals(NOT_SET, model.getPositionNearestOrigin());
+        assertEquals(NOT_SET, mModel.getPositionNearestOrigin());
     }
 
+    @Test
     public void testSelectionRightOfItems() {
         initData(20, 4);
-        startSelection(new Point(viewWidth - 1, 10));
-        resizeSelection(new Point(viewWidth - 2, 11));
+        startSelection(new Point(mViewWidth - 1, 10));
+        resizeSelection(new Point(mViewWidth - 2, 11));
         assertNoSelection();
-        assertEquals(NOT_SET, model.getPositionNearestOrigin());
+        assertEquals(NOT_SET, mModel.getPositionNearestOrigin());
     }
 
+    @Test
     public void testSelectionAboveItems() {
         initData(20, 4);
         startSelection(new Point(10, 0));
         resizeSelection(new Point(11, 1));
         assertNoSelection();
-        assertEquals(NOT_SET, model.getPositionNearestOrigin());
+        assertEquals(NOT_SET, mModel.getPositionNearestOrigin());
     }
 
+    @Test
     public void testSelectionBelowItems() {
         initData(5, 4);
         startSelection(new Point(10, VIEWPORT_HEIGHT - 1));
         resizeSelection(new Point(11, VIEWPORT_HEIGHT - 2));
         assertNoSelection();
-        assertEquals(NOT_SET, model.getPositionNearestOrigin());
+        assertEquals(NOT_SET, mModel.getPositionNearestOrigin());
     }
 
+    @Test
     public void testVerticalSelectionBetweenItems() {
         initData(20, 4);
         startSelection(new Point(106, 0));
         resizeSelection(new Point(107, 200));
         assertNoSelection();
-        assertEquals(NOT_SET, model.getPositionNearestOrigin());
+        assertEquals(NOT_SET, mModel.getPositionNearestOrigin());
     }
 
+    @Test
     public void testHorizontalSelectionBetweenItems() {
         initData(20, 4);
         startSelection(new Point(0, 105));
         resizeSelection(new Point(200, 106));
         assertNoSelection();
-        assertEquals(NOT_SET, model.getPositionNearestOrigin());
+        assertEquals(NOT_SET, mModel.getPositionNearestOrigin());
     }
 
+    @Test
     public void testGrowingAndShrinkingSelection() {
         initData(20, 4);
         startSelection(new Point(0, 0));
@@ -180,14 +169,15 @@
         resizeSelection(new Point(0, 0));
         verifySelection();
 
-        assertEquals(NOT_SET, model.getPositionNearestOrigin());
+        assertEquals(NOT_SET, mModel.getPositionNearestOrigin());
     }
 
+    @Test
     public void testSelectionMovingAroundOrigin() {
         initData(16, 4);
 
         startSelection(new Point(210, 210));
-        resizeSelection(new Point(viewWidth - 1, 0));
+        resizeSelection(new Point(mViewWidth - 1, 0));
         verifySelection();
 
         resizeSelection(new Point(0, 0));
@@ -196,14 +186,15 @@
         resizeSelection(new Point(0, 420));
         verifySelection();
 
-        resizeSelection(new Point(viewWidth - 1, 420));
+        resizeSelection(new Point(mViewWidth - 1, 420));
         verifySelection();
 
         // This is manually figured and will need to be adjusted if the separator position is
         // changed.
-        assertEquals(7, model.getPositionNearestOrigin());
+        assertEquals(7, mModel.getPositionNearestOrigin());
     }
 
+    @Test
     public void testScrollingBandSelect() {
         initData(40, 4);
 
@@ -226,7 +217,37 @@
         resizeSelection(new Point(100, VIEWPORT_HEIGHT - 1));
         verifySelection();
 
-        assertEquals(0, model.getPositionNearestOrigin());
+        assertEquals(0, mModel.getPositionNearestOrigin());
+    }
+
+    private void initData(final int numChildren, int numColumns) {
+        mHost = new TestHost(numChildren, numColumns);
+        mAdapter = new TestAdapter() {
+            @Override
+            public String getStableId(int position) {
+                return Integer.toString(position);
+            }
+
+            @Override
+            public int getItemCount() {
+                return numChildren;
+            }
+        };
+
+        mViewWidth = VIEW_PADDING_PX + numColumns * (VIEW_PADDING_PX + CHILD_VIEW_EDGE_PX);
+
+        mModel = new GridModel(
+                mHost,
+                new TestStableIdProvider(mAdapter),
+                SelectionPredicates.CAN_SET_ANYTHING);
+
+        mModel.addOnSelectionChangedListener(
+                new GridModel.SelectionObserver() {
+                    @Override
+                    public void onSelectionChanged(Set<String> updatedSelection) {
+                        mLastSelection = updatedSelection;
+                    }
+                });
     }
 
     /** Returns the current selection area as a Rect. */
@@ -244,43 +265,43 @@
 
     /** Asserts that the selection is currently empty. */
     private void assertNoSelection() {
-        assertEquals("Unexpected items " + lastSelection + " in selection " + getSelectionArea(),
-                0, lastSelection.size());
+        assertEquals("Unexpected items " + mLastSelection + " in selection " + getSelectionArea(),
+                0, mLastSelection.size());
     }
 
     /** Verifies the selection using actual bbox checks. */
     private void verifySelection() {
         Rect selectionArea = getSelectionArea();
-        for (TestEnvironment.Item item: env.items) {
+        for (TestHost.Item item: mHost.items) {
             if (Rect.intersects(selectionArea, item.rect)) {
                 assertTrue("Expected item " + item + " was not in selection " + selectionArea,
-                        lastSelection.contains(item.name));
+                        mLastSelection.contains(item.name));
             } else {
                 assertFalse("Unexpected item " + item + " in selection" + selectionArea,
-                        lastSelection.contains(item.name));
+                        mLastSelection.contains(item.name));
             }
         }
     }
 
     private void startSelection(Point p) {
-        model.startSelection(p);
-        mSelectionOrigin = env.createAbsolutePoint(p);
+        mModel.startCapturing(p);
+        mSelectionOrigin = mHost.createAbsolutePoint(p);
     }
 
     private void resizeSelection(Point p) {
-        model.resizeSelection(p);
-        mSelectionPoint = env.createAbsolutePoint(p);
+        mModel.resizeSelection(p);
+        mSelectionPoint = mHost.createAbsolutePoint(p);
     }
 
     private void scroll(int dy) {
-        assertTrue(env.verticalOffset + VIEWPORT_HEIGHT + dy <= env.getTotalHeight());
-        env.verticalOffset += dy;
+        assertTrue(mHost.verticalOffset + VIEWPORT_HEIGHT + dy <= mHost.getTotalHeight());
+        mHost.verticalOffset += dy;
         // Correct the cached selection point as well.
         mSelectionPoint.y += dy;
-        model.onScrolled(null, 0, dy);
+        mHost.mScrollListener.onScrolled(null, 0, dy);
     }
 
-    private static final class TestEnvironment implements BandController.SelectionEnvironment {
+    private static final class TestHost extends BandHost {
 
         private final int mNumColumns;
         private final int mNumRows;
@@ -291,7 +312,10 @@
         public int verticalOffset = 0;
         private List<Item> items = new ArrayList<>();
 
-        public TestEnvironment(int numChildren, int numColumns) {
+        // Installed by GridModel on construction.
+        private @Nullable OnScrollListener mScrollListener;
+
+        public TestHost(int numChildren, int numColumns) {
             mNumChildren = numChildren;
             mNumColumns = numColumns;
             mSeparatorPosition = mNumColumns + 1;
@@ -363,7 +387,9 @@
         }
 
         @Override
-        public void addOnScrollListener(OnScrollListener listener) {}
+        public void addOnScrollListener(OnScrollListener listener) {
+            mScrollListener = listener;
+        }
 
         @Override
         public void removeOnScrollListener(OnScrollListener listener) {}
@@ -458,6 +484,7 @@
                 rect = r;
             }
 
+            @Override
             public String toString() {
                 return name + ": " + rect;
             }
diff --git a/tests/unit/com/android/documentsui/selection/MouseInputHandlerTest.java b/tests/unit/com/android/documentsui/selection/MouseInputHandlerTest.java
new file mode 100644
index 0000000..f1bf556
--- /dev/null
+++ b/tests/unit/com/android/documentsui/selection/MouseInputHandlerTest.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2016 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.documentsui.selection;
+
+import static com.android.documentsui.testing.TestEvents.Mouse.ALT_CLICK;
+import static com.android.documentsui.testing.TestEvents.Mouse.CLICK;
+import static com.android.documentsui.testing.TestEvents.Mouse.CTRL_CLICK;
+import static com.android.documentsui.testing.TestEvents.Mouse.SECONDARY_CLICK;
+import static com.android.documentsui.testing.TestEvents.Mouse.SHIFT_CLICK;
+import static com.android.documentsui.testing.TestEvents.Mouse.TERTIARY_CLICK;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v7.widget.RecyclerView;
+import android.view.MotionEvent;
+
+import com.android.documentsui.selection.SelectionHelper;
+import com.android.documentsui.selection.testing.SelectionHelpers;
+import com.android.documentsui.selection.testing.SelectionProbe;
+import com.android.documentsui.selection.testing.TestData;
+import com.android.documentsui.selection.testing.TestEvents;
+import com.android.documentsui.selection.testing.TestMouseCallbacks;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public final class MouseInputHandlerTest {
+
+    private static final List<String> ITEMS = TestData.create(100);
+
+    private MouseInputHandler mInputDelegate;
+    private TestMouseCallbacks mCallbacks;
+    private TestItemDetailsLookup mDetailsLookup;
+    private SelectionProbe mSelection;
+    private SelectionHelper mSelectionMgr;
+
+    private TestEvents.Builder mEvent;
+
+    @Before
+    public void setUp() {
+
+        mSelectionMgr = SelectionHelpers.createTestInstance(ITEMS);
+        mDetailsLookup = new TestItemDetailsLookup();
+        mSelection = new SelectionProbe(mSelectionMgr);
+
+        mCallbacks = new TestMouseCallbacks();
+        mInputDelegate = new MouseInputHandler(mSelectionMgr, mDetailsLookup, mCallbacks);
+
+        mEvent = TestEvents.builder().mouse();
+        mDetailsLookup.initAt(RecyclerView.NO_POSITION);
+    }
+
+    @Test
+    public void testConfirmedClick_StartsSelection() {
+        mDetailsLookup.initAt(11).setInItemSelectRegion(true);
+        mInputDelegate.onSingleTapConfirmed(CLICK);
+
+        mSelection.assertSelection(11);
+    }
+
+    @Test
+    public void testClickOnSelectRegion_AddsToSelection() {
+        mDetailsLookup.initAt(11).setInItemSelectRegion(true);
+        mInputDelegate.onSingleTapConfirmed(CLICK);
+
+        mDetailsLookup.initAt(10).setInItemSelectRegion(true);
+        mInputDelegate.onSingleTapUp(CLICK);
+
+        mSelection.assertSelected(10, 11);
+    }
+
+    @Test
+    public void testClickOnIconOfSelectedItem_RemovesFromSelection() {
+        mDetailsLookup.initAt(8).setInItemSelectRegion(true);
+        mInputDelegate.onSingleTapConfirmed(CLICK);
+
+        mDetailsLookup.initAt(11);
+        mInputDelegate.onSingleTapUp(SHIFT_CLICK);
+        mSelection.assertSelected(8, 9, 10, 11);
+
+        mDetailsLookup.initAt(9);
+        mInputDelegate.onSingleTapUp(CLICK);
+        mSelection.assertSelected(8, 10, 11);
+    }
+
+    @Test
+    public void testRightClickDown_StartsContextMenu() {
+        mInputDelegate.onDown(SECONDARY_CLICK);
+
+        mCallbacks.assertLastEvent(SECONDARY_CLICK);
+    }
+
+    @Test
+    public void testAltClickDown_StartsContextMenu() {
+        mInputDelegate.onDown(ALT_CLICK);
+
+        mCallbacks.assertLastEvent(ALT_CLICK);
+    }
+
+    @Test
+    public void testScroll_shouldTrap() {
+        mDetailsLookup.initAt(0);
+        assertTrue(mInputDelegate.onScroll(
+                null,
+                mEvent.action(MotionEvent.ACTION_MOVE).primary().build(),
+                -1,
+                -1));
+    }
+
+    @Test
+    public void testScroll_NoTrapForTwoFinger() {
+        mDetailsLookup.initAt(0);
+        assertFalse(mInputDelegate.onScroll(
+                null,
+                mEvent.action(MotionEvent.ACTION_MOVE).build(),
+                -1,
+                -1));
+    }
+
+    @Test
+    public void testUnconfirmedCtrlClick_AddsToExistingSelection() {
+        mDetailsLookup.initAt(7).setInItemSelectRegion(true);
+        mInputDelegate.onSingleTapConfirmed(CLICK);
+
+        mDetailsLookup.initAt(11);
+        mInputDelegate.onSingleTapUp(CTRL_CLICK);
+
+        mSelection.assertSelection(7, 11);
+    }
+
+    @Test
+    public void testUnconfirmedShiftClick_ExtendsSelection() {
+        mDetailsLookup.initAt(7).setInItemSelectRegion(true);
+        mInputDelegate.onSingleTapConfirmed(CLICK);
+
+        mDetailsLookup.initAt(11);
+        mInputDelegate.onSingleTapUp(SHIFT_CLICK);
+
+        mSelection.assertSelection(7, 8, 9, 10, 11);
+    }
+
+    @Test
+    public void testConfirmedShiftClick_ExtendsSelectionFromOriginFocus() {
+        TestItemDetails item = mDetailsLookup.initAt(7);
+        mCallbacks.focusItem(item);
+
+        // This is a hack-y test, since the real FocusManager would've set range begin itself.
+        mSelectionMgr.anchorRange(7);
+        mSelection.assertNoSelection();
+
+        mDetailsLookup.initAt(11);
+        mInputDelegate.onSingleTapConfirmed(SHIFT_CLICK);
+        mSelection.assertSelection(7, 8, 9, 10, 11);
+    }
+
+    @Test
+    public void testUnconfirmedShiftClick_RotatesAroundOrigin() {
+        mDetailsLookup.initAt(7).setInItemSelectRegion(true);
+        mInputDelegate.onSingleTapConfirmed(CLICK);
+
+        mDetailsLookup.initAt(11);
+        mInputDelegate.onSingleTapUp(SHIFT_CLICK);
+        mSelection.assertSelection(7, 8, 9, 10, 11);
+
+        mDetailsLookup.initAt(5);
+        mInputDelegate.onSingleTapUp(SHIFT_CLICK);
+
+        mSelection.assertSelection(5, 6, 7);
+        mSelection.assertNotSelected(8, 9, 10, 11);
+    }
+
+    @Test
+    public void testUnconfirmedShiftCtrlClick_Combination() {
+        mDetailsLookup.initAt(7).setInItemSelectRegion(true);
+        mInputDelegate.onSingleTapConfirmed(CLICK);
+
+        mDetailsLookup.initAt(11);
+        mInputDelegate.onSingleTapUp(SHIFT_CLICK);
+        mSelection.assertSelection(7, 8, 9, 10, 11);
+
+        mDetailsLookup.initAt(5);
+        mInputDelegate.onSingleTapUp(CTRL_CLICK);
+
+        mSelection.assertSelection(5, 7, 8, 9, 10, 11);
+    }
+
+    @Test
+    public void testUnconfirmedShiftCtrlClick_ShiftTakesPriority() {
+        mDetailsLookup.initAt(7).setInItemSelectRegion(true);
+        mInputDelegate.onSingleTapConfirmed(CLICK);
+
+        mDetailsLookup.initAt(11);
+        mInputDelegate.onSingleTapUp(mEvent.ctrl().shift().build());
+
+        mSelection.assertSelection(7, 8, 9, 10, 11);
+    }
+
+    // TODO: Add testSpaceBar_Previews, but we need to set a system property
+    // to have a deterministic state.
+
+    @Test
+    public void testDoubleClick_Opens() {
+        TestItemDetails doc = mDetailsLookup.initAt(11);
+        mInputDelegate.onDoubleTap(CLICK);
+
+        mCallbacks.assertActivated(doc);
+    }
+
+    @Test
+    public void testMiddleClick_DoesNothing() {
+        mDetailsLookup.initAt(11).setInItemSelectRegion(true);
+        mInputDelegate.onSingleTapConfirmed(TERTIARY_CLICK);
+
+        mSelection.assertNoSelection();
+    }
+
+    @Test
+    public void testClickOff_ClearsSelection() {
+        mDetailsLookup.initAt(11).setInItemSelectRegion(true);
+        mInputDelegate.onSingleTapConfirmed(CLICK);
+
+        mDetailsLookup.initAt(RecyclerView.NO_POSITION);
+        mInputDelegate.onSingleTapUp(CLICK);
+
+        mSelection.assertNoSelection();
+    }
+
+    @Test
+    public void testClick_Focuses() {
+        mDetailsLookup.initAt(11).setInItemSelectRegion(false);
+        mInputDelegate.onSingleTapConfirmed(CLICK);
+
+        mCallbacks.assertHasFocus(true);
+        mCallbacks.assertFocused("11");
+    }
+
+    @Test
+    public void testClickOff_ClearsFocus() {
+        mDetailsLookup.initAt(11).setInItemSelectRegion(false);
+        mInputDelegate.onSingleTapConfirmed(CLICK);
+        mCallbacks.assertHasFocus(true);
+
+        mDetailsLookup.initAt(RecyclerView.NO_POSITION);
+        mInputDelegate.onSingleTapUp(CLICK);
+        mCallbacks.assertHasFocus(false);
+    }
+
+    @Test
+    public void testClickOffSelection_RemovesSelectionAndFocuses() {
+        mDetailsLookup.initAt(1).setInItemSelectRegion(true);
+        mInputDelegate.onSingleTapConfirmed(CLICK);
+
+        mDetailsLookup.initAt(5);
+        mInputDelegate.onSingleTapUp(SHIFT_CLICK);
+
+        mSelection.assertSelection(1, 2, 3, 4, 5);
+
+        mDetailsLookup.initAt(11);
+        mInputDelegate.onSingleTapUp(CLICK);
+
+        mCallbacks.assertFocused("11");
+        mSelection.assertNoSelection();
+    }
+}
diff --git a/tests/unit/com/android/documentsui/selection/MouseInputHandler_RangeTest.java b/tests/unit/com/android/documentsui/selection/MouseInputHandler_RangeTest.java
new file mode 100644
index 0000000..939e778
--- /dev/null
+++ b/tests/unit/com/android/documentsui/selection/MouseInputHandler_RangeTest.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2016 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.documentsui.selection;
+
+import static com.android.documentsui.testing.TestEvents.Mouse.CLICK;
+import static com.android.documentsui.testing.TestEvents.Mouse.SECONDARY_CLICK;
+import static com.android.documentsui.testing.TestEvents.Mouse.SHIFT_CLICK;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.documentsui.selection.SelectionHelper;
+import com.android.documentsui.selection.testing.SelectionHelpers;
+import com.android.documentsui.selection.testing.SelectionProbe;
+import com.android.documentsui.selection.testing.TestData;
+import com.android.documentsui.selection.testing.TestMouseCallbacks;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+/**
+ * MouseInputDelegate / SelectHelper integration test covering the shared
+ * responsibility of range selection.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public final class MouseInputHandler_RangeTest {
+
+    private static final List<String> ITEMS = TestData.create(100);
+
+    private MouseInputHandler mInputDelegate;
+    private SelectionHelper mSelectionMgr;
+    private SelectionProbe mSelection;
+    private TestMouseCallbacks mCallbacks;
+    private TestItemDetailsLookup mDetailsLookup;
+
+    @Before
+    public void setUp() {
+        mSelectionMgr = SelectionHelpers.createTestInstance(ITEMS);
+        mDetailsLookup = new TestItemDetailsLookup();
+        mSelection = new SelectionProbe(mSelectionMgr);
+
+        mCallbacks = new TestMouseCallbacks();
+        mInputDelegate = new MouseInputHandler(mSelectionMgr, mDetailsLookup, mCallbacks);
+    }
+
+    @Test
+    public void testExtendRange() {
+        // uni-click just focuses.
+        mDetailsLookup.initAt(7).setInItemSelectRegion(true);
+        mInputDelegate.onSingleTapConfirmed(CLICK);
+
+        mDetailsLookup.initAt(11);
+        mInputDelegate.onSingleTapUp(SHIFT_CLICK);
+
+        mSelection.assertRangeSelection(7, 11);
+    }
+
+    @Test
+    public void testExtendRangeContinues() {
+        mDetailsLookup.initAt(7).setInItemSelectRegion(true);
+        mInputDelegate.onSingleTapConfirmed(CLICK);
+
+        mDetailsLookup.initAt(11);
+        mInputDelegate.onSingleTapUp(SHIFT_CLICK);
+
+        mDetailsLookup.initAt(21);
+        mInputDelegate.onSingleTapUp(SHIFT_CLICK);
+
+        mSelection.assertRangeSelection(7, 21);
+    }
+
+    @Test
+    public void testMultipleContiguousRanges() {
+        mDetailsLookup.initAt(7).setInItemSelectRegion(true);
+        mInputDelegate.onSingleTapConfirmed(CLICK);
+
+        mDetailsLookup.initAt(11);
+        mInputDelegate.onSingleTapUp(SHIFT_CLICK);
+
+        // click without shift sets a new range start point.
+        TestItemDetails item = mDetailsLookup.initAt(20);
+        mInputDelegate.onSingleTapUp(CLICK);
+        mInputDelegate.onSingleTapConfirmed(CLICK);
+
+        mCallbacks.focusItem(item);
+
+        mDetailsLookup.initAt(25);
+        mInputDelegate.onSingleTapUp(SHIFT_CLICK);
+        mInputDelegate.onSingleTapConfirmed(SHIFT_CLICK);
+
+        mSelection.assertRangeNotSelected(7, 11);
+        mSelection.assertRangeSelected(20, 25);
+        mSelection.assertSelectionSize(6);
+    }
+
+    @Test
+    public void testReducesSelectionRange() {
+        mDetailsLookup.initAt(7).setInItemSelectRegion(true);
+        mInputDelegate.onSingleTapConfirmed(CLICK);
+
+        mDetailsLookup.initAt(17);
+        mInputDelegate.onSingleTapUp(SHIFT_CLICK);
+
+        mDetailsLookup.initAt(10);
+        mInputDelegate.onSingleTapUp(SHIFT_CLICK);
+
+        mSelection.assertRangeSelection(7, 10);
+    }
+
+    @Test
+    public void testReducesSelectionRange_Reverse() {
+        mDetailsLookup.initAt(17).setInItemSelectRegion(true);
+        mInputDelegate.onSingleTapConfirmed(CLICK);
+
+        mDetailsLookup.initAt(7);
+        mInputDelegate.onSingleTapUp(SHIFT_CLICK);
+
+        mDetailsLookup.initAt(14);
+        mInputDelegate.onSingleTapUp(SHIFT_CLICK);
+
+        mSelection.assertRangeSelection(14, 17);
+    }
+
+    @Test
+    public void testExtendsRange_Reverse() {
+        mDetailsLookup.initAt(12).setInItemSelectRegion(true);
+        mInputDelegate.onSingleTapConfirmed(CLICK);
+
+        mDetailsLookup.initAt(5);
+        mInputDelegate.onSingleTapUp(SHIFT_CLICK);
+
+        mSelection.assertRangeSelection(5, 12);
+    }
+
+    @Test
+    public void testExtendsRange_ReversesAfterForwardClick() {
+        mDetailsLookup.initAt(7).setInItemSelectRegion(true);
+        mInputDelegate.onSingleTapConfirmed(CLICK);
+
+        mDetailsLookup.initAt(11);
+        mInputDelegate.onSingleTapUp(SHIFT_CLICK);
+
+        mDetailsLookup.initAt(0);
+        mInputDelegate.onSingleTapUp(SHIFT_CLICK);
+
+        mSelection.assertRangeSelection(0, 7);
+    }
+
+    @Test
+    public void testRightClickEstablishesRange() {
+
+        mDetailsLookup.initAt(7).setInItemSelectRegion(true);
+        mInputDelegate.onDown(SECONDARY_CLICK);
+        // This next method call simulates the behavior of the system event dispatch code.
+        // UserInputHandler depends on a specific sequence of events for internal
+        // state to remain valid. It's not an awesome arrangement, but it is currently
+        // necessary.
+        //
+        // See: UserInputHandler.MouseDelegate#mHandledOnDown;
+        mInputDelegate.onSingleTapUp(SECONDARY_CLICK);
+
+        mDetailsLookup.initAt(11);
+        // Now we can send a subsequent event that should extend selection.
+        mInputDelegate.onDown(SHIFT_CLICK);
+        mInputDelegate.onSingleTapUp(SHIFT_CLICK);
+
+        mSelection.assertRangeSelection(7, 11);
+    }
+}
diff --git a/tests/unit/com/android/documentsui/selection/SelectionManagerTest.java b/tests/unit/com/android/documentsui/selection/SelectionManagerTest.java
deleted file mode 100644
index 987780e..0000000
--- a/tests/unit/com/android/documentsui/selection/SelectionManagerTest.java
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * 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.documentsui.selection;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.util.SparseBooleanArray;
-
-import com.android.documentsui.dirlist.TestDocumentsAdapter;
-import com.android.documentsui.selection.SelectionManager;
-import com.android.documentsui.dirlist.TestData;
-import com.android.documentsui.selection.Selection;
-import com.android.documentsui.testing.SelectionManagers;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class SelectionManagerTest {
-
-    private static final List<String> ITEMS = TestData.create(100);
-
-    private final Set<String> mIgnored = new HashSet<>();
-    private TestDocumentsAdapter mAdapter;
-    private SelectionManager mManager;
-    private TestSelectionListener mCallback;
-    private TestItemSelectionListener mItemCallback;
-    private SelectionProbe mSelection;
-
-    @Before
-    public void setUp() throws Exception {
-        mCallback = new TestSelectionListener();
-        mItemCallback = new TestItemSelectionListener();
-        mAdapter = new TestDocumentsAdapter(ITEMS);
-        mManager = SelectionManagers.createTestInstance(
-                mAdapter,
-                SelectionManager.MODE_MULTIPLE,
-                (String id, boolean nextState) -> (!nextState || !mIgnored.contains(id)));
-        mManager.addCallback(mCallback);
-        mManager.addItemCallback(mItemCallback);
-
-        mSelection = new SelectionProbe(mManager, mItemCallback);
-
-        mIgnored.clear();
-    }
-
-    @Test
-    public void testSelection() {
-        // Check selection.
-        mManager.toggleSelection(ITEMS.get(7));
-        mSelection.assertSelection(7);
-        // Check deselection.
-        mManager.toggleSelection(ITEMS.get(7));
-        mSelection.assertNoSelection();
-    }
-
-    @Test
-    public void testSelection_DoNothingOnUnselectableItem() {
-        mIgnored.add(ITEMS.get(7));
-
-        mManager.toggleSelection(ITEMS.get(7));
-        mSelection.assertNoSelection();
-    }
-
-    @Test
-    public void testSelection_NotifiesSelectionChanged() {
-        // Selection should notify.
-        mManager.toggleSelection(ITEMS.get(7));
-        mCallback.assertSelectionChanged();
-        // Deselection should notify.
-        mManager.toggleSelection(ITEMS.get(7));
-        mCallback.assertSelectionChanged();
-    }
-
-    @Test
-    public void testSelection_PersistsOnUpdate() {
-        mManager.toggleSelection(ITEMS.get(7));
-
-        mAdapter.updateTestModelIds(ITEMS);
-
-        mSelection.assertSelection(7);
-    }
-
-    @Test
-    public void testSelection_IntersectsWithNewDataSet() {
-        mManager.toggleSelection(ITEMS.get(99));
-        mManager.toggleSelection(ITEMS.get(7));
-
-        mAdapter.updateTestModelIds(TestData.create(50));
-
-        mSelection.assertSelection(7);
-    }
-
-    @Test
-    public void testSetItemsSelected() {
-        mManager.setItemsSelected(getStringIds(6, 7, 8), true);
-
-        mSelection.assertRangeSelected(6, 8);
-    }
-
-    @Test
-    public void testSetItemsSelected_SkipUnselectableItem() {
-        mIgnored.add(ITEMS.get(7));
-
-        mManager.setItemsSelected(getStringIds(6, 7, 8), true);
-
-        mSelection.assertSelected(6);
-        mSelection.assertNotSelected(7);
-        mSelection.assertSelected(8);
-    }
-
-    @Test
-    public void testRangeSelection() {
-        mManager.startRangeSelection(15);
-        mManager.snapRangeSelection(19);
-        mSelection.assertRangeSelection(15, 19);
-    }
-
-    @Test
-    public void testRangeSelection_SkipUnselectableItem() {
-        mIgnored.add(ITEMS.get(17));
-
-        mManager.startRangeSelection(15);
-        mManager.snapRangeSelection(19);
-
-        mSelection.assertRangeSelected(15, 16);
-        mSelection.assertNotSelected(17);
-        mSelection.assertRangeSelected(18, 19);
-    }
-
-    @Test
-    public void testRangeSelection_snapExpand() {
-        mManager.startRangeSelection(15);
-        mManager.snapRangeSelection(19);
-        mManager.snapRangeSelection(27);
-        mSelection.assertRangeSelection(15, 27);
-    }
-
-    @Test
-    public void testRangeSelection_snapContract() {
-        mManager.startRangeSelection(15);
-        mManager.snapRangeSelection(27);
-        mManager.snapRangeSelection(19);
-        mSelection.assertRangeSelection(15, 19);
-    }
-
-    @Test
-    public void testRangeSelection_snapInvert() {
-        mManager.startRangeSelection(15);
-        mManager.snapRangeSelection(27);
-        mManager.snapRangeSelection(3);
-        mSelection.assertRangeSelection(3, 15);
-    }
-
-    @Test
-    public void testRangeSelection_multiple() {
-        mManager.startRangeSelection(15);
-        mManager.snapRangeSelection(27);
-        mManager.endRangeSelection();
-        mManager.startRangeSelection(42);
-        mManager.snapRangeSelection(57);
-        mSelection.assertSelectionSize(29);
-        mSelection.assertRangeSelected(15, 27);
-        mSelection.assertRangeSelected(42, 57);
-    }
-
-    @Test
-    public void testProvisionalRangeSelection() {
-        mManager.startRangeSelection(13);
-        mManager.snapProvisionalRangeSelection(15);
-        mSelection.assertRangeSelection(13, 15);
-        mManager.getSelection().applyProvisionalSelection();
-        mManager.endRangeSelection();
-        mSelection.assertSelectionSize(3);
-    }
-
-    @Test
-    public void testProvisionalRangeSelection_endEarly() {
-        mManager.startRangeSelection(13);
-        mManager.snapProvisionalRangeSelection(15);
-        mSelection.assertRangeSelection(13, 15);
-
-        mManager.endRangeSelection();
-        // If we end range selection prematurely for provision selection, nothing should be selected
-        // except the first item
-        mSelection.assertSelectionSize(1);
-    }
-
-    @Test
-    public void testProvisionalRangeSelection_snapExpand() {
-        mManager.startRangeSelection(13);
-        mManager.snapProvisionalRangeSelection(15);
-        mSelection.assertRangeSelection(13, 15);
-        mManager.getSelection().applyProvisionalSelection();
-        mManager.snapRangeSelection(18);
-        mSelection.assertRangeSelection(13, 18);
-    }
-
-    @Test
-    public void testCombinationRangeSelection_IntersectsOldSelection() {
-        mManager.startRangeSelection(13);
-        mManager.snapRangeSelection(15);
-        mSelection.assertRangeSelection(13, 15);
-
-        mManager.startRangeSelection(11);
-        mManager.snapProvisionalRangeSelection(18);
-        mSelection.assertRangeSelected(11, 18);
-        mManager.endRangeSelection();
-        mSelection.assertRangeSelected(13, 15);
-        mSelection.assertRangeSelected(11, 11);
-        mSelection.assertSelectionSize(4);
-    }
-
-    @Test
-    public void testProvisionalSelection() {
-        Selection s = mManager.getSelection();
-        mSelection.assertNoSelection();
-
-        // Mimicking band selection case -- BandController notifies item callback by itself.
-        mItemCallback.onItemStateChanged(ITEMS.get(1), true);
-        mItemCallback.onItemStateChanged(ITEMS.get(2), true);
-
-        SparseBooleanArray provisional = new SparseBooleanArray();
-        provisional.append(1, true);
-        provisional.append(2, true);
-        s.setProvisionalSelection(getItemIds(provisional));
-        mSelection.assertSelection(1, 2);
-    }
-
-    @Test
-    public void testProvisionalSelection_Replace() {
-        Selection s = mManager.getSelection();
-
-        // Mimicking band selection case -- BandController notifies item callback by itself.
-        mItemCallback.onItemStateChanged(ITEMS.get(1), true);
-        mItemCallback.onItemStateChanged(ITEMS.get(2), true);
-        SparseBooleanArray provisional = new SparseBooleanArray();
-        provisional.append(1, true);
-        provisional.append(2, true);
-        s.setProvisionalSelection(getItemIds(provisional));
-
-        mItemCallback.onItemStateChanged(ITEMS.get(1), false);
-        mItemCallback.onItemStateChanged(ITEMS.get(2), false);
-        provisional.clear();
-
-        mItemCallback.onItemStateChanged(ITEMS.get(3), true);
-        mItemCallback.onItemStateChanged(ITEMS.get(4), true);
-        provisional.append(3, true);
-        provisional.append(4, true);
-        s.setProvisionalSelection(getItemIds(provisional));
-        mSelection.assertSelection(3, 4);
-    }
-
-    @Test
-    public void testProvisionalSelection_IntersectsExistingProvisionalSelection() {
-        Selection s = mManager.getSelection();
-
-        // Mimicking band selection case -- BandController notifies item callback by itself.
-        mItemCallback.onItemStateChanged(ITEMS.get(1), true);
-        mItemCallback.onItemStateChanged(ITEMS.get(2), true);
-        SparseBooleanArray provisional = new SparseBooleanArray();
-        provisional.append(1, true);
-        provisional.append(2, true);
-        s.setProvisionalSelection(getItemIds(provisional));
-
-        mItemCallback.onItemStateChanged(ITEMS.get(1), false);
-        mItemCallback.onItemStateChanged(ITEMS.get(2), false);
-        provisional.clear();
-
-        mItemCallback.onItemStateChanged(ITEMS.get(1), true);
-        provisional.append(1, true);
-        s.setProvisionalSelection(getItemIds(provisional));
-        mSelection.assertSelection(1);
-    }
-
-    @Test
-    public void testProvisionalSelection_Apply() {
-        Selection s = mManager.getSelection();
-
-        // Mimicking band selection case -- BandController notifies item callback by itself.
-        mItemCallback.onItemStateChanged(ITEMS.get(1), true);
-        mItemCallback.onItemStateChanged(ITEMS.get(2), true);
-        SparseBooleanArray provisional = new SparseBooleanArray();
-        provisional.append(1, true);
-        provisional.append(2, true);
-        s.setProvisionalSelection(getItemIds(provisional));
-        s.applyProvisionalSelection();
-
-        mSelection.assertSelection(1, 2);
-    }
-
-    @Test
-    public void testProvisionalSelection_Cancel() {
-        mManager.toggleSelection(ITEMS.get(1));
-        mManager.toggleSelection(ITEMS.get(2));
-        Selection s = mManager.getSelection();
-
-        SparseBooleanArray provisional = new SparseBooleanArray();
-        provisional.append(3, true);
-        provisional.append(4, true);
-        s.setProvisionalSelection(getItemIds(provisional));
-        s.cancelProvisionalSelection();
-
-        // Original selection should remain.
-        mSelection.assertSelection(1, 2);
-    }
-
-    @Test
-    public void testProvisionalSelection_IntersectsAppliedSelection() {
-        mManager.toggleSelection(ITEMS.get(1));
-        mManager.toggleSelection(ITEMS.get(2));
-        Selection s = mManager.getSelection();
-
-        // Mimicking band selection case -- BandController notifies item callback by itself.
-        mItemCallback.onItemStateChanged(ITEMS.get(3), true);
-        SparseBooleanArray provisional = new SparseBooleanArray();
-        provisional.append(2, true);
-        provisional.append(3, true);
-        s.setProvisionalSelection(getItemIds(provisional));
-        mSelection.assertSelection(1, 2, 3);
-    }
-
-    private static Set<String> getItemIds(SparseBooleanArray selection) {
-        Set<String> ids = new HashSet<>();
-
-        int count = selection.size();
-        for (int i = 0; i < count; ++i) {
-            ids.add(ITEMS.get(selection.keyAt(i)));
-        }
-
-        return ids;
-    }
-
-    private static Iterable<String> getStringIds(int... ids) {
-        List<String> stringIds = new ArrayList<>(ids.length);
-        for (int id : ids) {
-            stringIds.add(ITEMS.get(id));
-        }
-        return stringIds;
-    }
-}
diff --git a/tests/unit/com/android/documentsui/selection/SelectionManager_SingleSelectTest.java b/tests/unit/com/android/documentsui/selection/SelectionManager_SingleSelectTest.java
deleted file mode 100644
index b25c1c0..0000000
--- a/tests/unit/com/android/documentsui/selection/SelectionManager_SingleSelectTest.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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.documentsui.selection;
-
-import static junit.framework.Assert.fail;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import com.android.documentsui.dirlist.TestData;
-import com.android.documentsui.dirlist.TestDocumentsAdapter;
-import com.android.documentsui.selection.SelectionManager;
-import com.android.documentsui.testing.SelectionManagers;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class SelectionManager_SingleSelectTest {
-
-    private static final List<String> ITEMS = TestData.create(100);
-
-    private SelectionManager mManager;
-    private TestSelectionListener mCallback;
-    private TestDocumentsAdapter mAdapter;
-    private SelectionProbe mSelection;
-
-    @Before
-    public void setUp() throws Exception {
-        mCallback = new TestSelectionListener();
-        mManager = SelectionManagers.createTestInstance(ITEMS, SelectionManager.MODE_SINGLE);
-        mManager.addCallback(mCallback);
-
-        mSelection = new SelectionProbe(mManager);
-    }
-
-    @Test
-    public void testSimpleSelect() {
-        mManager.toggleSelection(ITEMS.get(3));
-        mManager.toggleSelection(ITEMS.get(4));
-        mCallback.assertSelectionChanged();
-        mSelection.assertSelection(4);
-    }
-
-    @Test
-    public void testRangeSelectionNotEstablished() {
-        mManager.toggleSelection(ITEMS.get(3));
-        mCallback.reset();
-
-        try {
-            mManager.snapRangeSelection(10);
-            fail("Should have thrown.");
-        } catch (Exception expected) {}
-
-        mCallback.assertSelectionUnchanged();
-        mSelection.assertSelection(3);
-    }
-}
diff --git a/tests/unit/com/android/documentsui/selection/SelectionTest.java b/tests/unit/com/android/documentsui/selection/SelectionTest.java
index ad1422a..fcf525b 100644
--- a/tests/unit/com/android/documentsui/selection/SelectionTest.java
+++ b/tests/unit/com/android/documentsui/selection/SelectionTest.java
@@ -23,8 +23,6 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
-import com.android.documentsui.selection.Selection;
-
 import com.google.common.collect.Sets;
 
 import org.junit.Before;
diff --git a/tests/unit/com/android/documentsui/selection/TestItemDetails.java b/tests/unit/com/android/documentsui/selection/TestItemDetails.java
new file mode 100644
index 0000000..b943247
--- /dev/null
+++ b/tests/unit/com/android/documentsui/selection/TestItemDetails.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection;
+
+import android.view.MotionEvent;
+
+import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
+import com.android.internal.widget.RecyclerView;
+
+public final class TestItemDetails extends ItemDetails {
+
+    // DocumentsAdapter.ITEM_TYPE_DOCUMENT
+    private int mViewType = -1;
+    private int mPosition;
+    private String mStableId;
+    private boolean mInDragRegion;
+    private boolean mInSelectionHotspot;
+
+    public TestItemDetails() {
+       mPosition = RecyclerView.NO_POSITION;
+    }
+
+    public TestItemDetails(TestItemDetails source) {
+        mPosition = source.mPosition;
+        mStableId = source.mStableId;
+        mViewType = source.mViewType;
+        mInDragRegion = source.mInDragRegion;
+        mInSelectionHotspot = source.mInSelectionHotspot;
+    }
+
+    public void setViewType(int viewType) {
+        mViewType = viewType;
+    }
+
+    public void at(int position) {
+        mPosition = position;  // this is both "adapter position" and "item position".
+        mStableId = (position == RecyclerView.NO_POSITION)
+                ? null
+                : String.valueOf(position);
+    }
+
+    public void setInItemDragRegion(boolean inHotspot) {
+        mInDragRegion = inHotspot;
+    }
+
+    public void setInItemSelectRegion(boolean over) {
+        mInSelectionHotspot = over;
+    }
+
+    @Override
+    public int getItemViewType() {
+        return mViewType;
+    }
+
+    @Override
+    public boolean inDragRegion(MotionEvent event) {
+        return mInDragRegion;
+    }
+
+    @Override
+    public int hashCode() {
+        return mPosition;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      if (this == o) {
+          return true;
+      }
+
+      if (!(o instanceof TestItemDetails)) {
+          return false;
+      }
+
+      TestItemDetails other = (TestItemDetails) o;
+      return mPosition == other.mPosition
+              && mStableId == other.mStableId
+              && mViewType == other.mViewType;
+    }
+
+    @Override
+    public int getPosition() {
+        return mPosition;
+    }
+
+    @Override
+    public String getStableId() {
+        return mStableId;
+    }
+
+    @Override
+    public boolean inSelectionHotspot(MotionEvent e) {
+        return mInSelectionHotspot;
+    }
+}
diff --git a/tests/unit/com/android/documentsui/selection/TestItemDetailsLookup.java b/tests/unit/com/android/documentsui/selection/TestItemDetailsLookup.java
new file mode 100644
index 0000000..a5397a3
--- /dev/null
+++ b/tests/unit/com/android/documentsui/selection/TestItemDetailsLookup.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection;
+
+import android.support.v7.widget.RecyclerView;
+import android.view.MotionEvent;
+
+import javax.annotation.Nullable;
+
+/**
+ * Test impl of ItemDetailsLookup.
+ */
+public class TestItemDetailsLookup extends ItemDetailsLookup {
+
+    private @Nullable TestItemDetails mDoc;
+
+    @Override
+    public boolean overItem(MotionEvent e) {
+        return getItemPosition(e) != RecyclerView.NO_POSITION;
+    }
+
+    @Override
+    public boolean overStableItem(MotionEvent e) {
+        return mDoc.getStableId() != null;
+    }
+
+    @Override
+    public boolean inItemDragRegion(MotionEvent e) {
+        return mDoc.inDragRegion(e);
+    }
+
+    @Override
+    public int getItemPosition(MotionEvent e) {
+        return mDoc.getPosition();
+    }
+
+    @Override
+    public boolean inItemSelectRegion(MotionEvent e) {
+        return mDoc.inSelectionHotspot(e);
+    }
+
+    @Override
+    public @Nullable ItemDetails getItemDetails(MotionEvent e) {
+        return mDoc;
+    }
+
+    /**
+     * Creates/installs/returns a new test document. Subsequent calls to
+     * any EventDocLookup methods will consult the newly created doc.
+     */
+    public TestItemDetails initAt(int position) {
+        TestItemDetails doc = new TestItemDetails();
+        doc.at(position);
+        mDoc = doc;
+        return doc;
+    }
+
+    public void reset() {
+        mDoc = null;
+    }
+}
diff --git a/tests/unit/com/android/documentsui/selection/TouchInputHandlerTest.java b/tests/unit/com/android/documentsui/selection/TouchInputHandlerTest.java
new file mode 100644
index 0000000..c39bfee
--- /dev/null
+++ b/tests/unit/com/android/documentsui/selection/TouchInputHandlerTest.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2016 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.documentsui.selection;
+
+import static com.android.documentsui.testing.TestEvents.Touch.TAP;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.support.annotation.Nullable;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v7.widget.RecyclerView;
+import android.view.MotionEvent;
+
+import com.android.documentsui.selection.SelectionHelper;
+import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
+import com.android.documentsui.selection.TouchInputHandler.Callbacks;
+import com.android.documentsui.selection.testing.SelectionHelpers;
+import com.android.documentsui.selection.testing.SelectionProbe;
+import com.android.documentsui.selection.testing.TestData;
+import com.android.documentsui.selection.testing.TestSelectionPredicate;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public final class TouchInputHandlerTest {
+
+    private static final List<String> ITEMS = TestData.create(100);
+
+    private TouchInputHandler mInputDelegate;
+    private SelectionHelper mSelectionMgr;
+    private TestSelectionPredicate mSelectionPredicate;
+    private TestRunnable mGestureStarted;
+    private TestCallbacks mCallbacks;
+    private TestItemDetailsLookup mDetailsLookup;
+    private SelectionProbe mSelection;
+
+    @Before
+    public void setUp() {
+        mSelectionMgr = SelectionHelpers.createTestInstance(ITEMS);
+        mDetailsLookup = new TestItemDetailsLookup();
+        mSelectionPredicate = new TestSelectionPredicate();
+        mSelection = new SelectionProbe(mSelectionMgr);
+        mGestureStarted = new TestRunnable();
+        mCallbacks = new TestCallbacks();
+
+        mInputDelegate = new TouchInputHandler(
+                mSelectionMgr,
+                mDetailsLookup,
+                mSelectionPredicate,
+                mGestureStarted,
+                mCallbacks);
+    }
+
+    @Test
+    public void testTap_ActivatesWhenNoExistingSelection() {
+        ItemDetails doc = mDetailsLookup.initAt(11);
+        mInputDelegate.onSingleTapUp(TAP);
+
+        mCallbacks.assertActivated(doc);
+    }
+
+    @Test
+    public void testScroll_shouldNotBeTrapped() {
+        assertFalse(mInputDelegate.onScroll(null, TAP, -1, -1));
+    }
+
+    @Test
+    public void testLongPress_SelectsItem() {
+        mSelectionPredicate.setReturnValue(true);
+
+        mDetailsLookup.initAt(7);
+        mInputDelegate.onLongPress(TAP);
+
+        mSelection.assertSelection(7);
+    }
+
+    @Test
+    public void testLongPress_StartsGestureSelection() {
+        mSelectionPredicate.setReturnValue(true);
+
+        mDetailsLookup.initAt(7);
+        mInputDelegate.onLongPress(TAP);
+        mGestureStarted.assertRan();
+    }
+
+    @Test
+    public void testSelectHotspot_StartsSelectionMode() {
+        mSelectionPredicate.setReturnValue(true);
+
+        mDetailsLookup.initAt(7).setInItemSelectRegion(true);
+        mInputDelegate.onSingleTapUp(TAP);
+
+        mSelection.assertSelection(7);
+    }
+
+    @Test
+    public void testSelectionHotspot_UnselectsSelectedItem() {
+        mSelectionMgr.select("11");
+
+        mDetailsLookup.initAt(11).setInItemSelectRegion(true);
+        mInputDelegate.onSingleTapUp(TAP);
+
+        mSelection.assertNoSelection();
+    }
+
+    @Test
+    public void testStartsSelection_PerformsHapticFeedback() {
+        mSelectionPredicate.setReturnValue(true);
+
+        mDetailsLookup.initAt(7);
+        mInputDelegate.onLongPress(TAP);
+
+        mCallbacks.assertVibrated();
+    }
+
+    @Test
+    public void testLongPress_AddsToSelection() {
+        mSelectionPredicate.setReturnValue(true);
+
+        mDetailsLookup.initAt(7);
+        mInputDelegate.onLongPress(TAP);
+
+        mDetailsLookup.initAt(99);
+        mInputDelegate.onLongPress(TAP);
+
+        mDetailsLookup.initAt(13);
+        mInputDelegate.onLongPress(TAP);
+
+        mSelection.assertSelection(7, 13, 99);
+    }
+
+    @Test
+    public void testTap_UnselectsSelectedItem() {
+        mSelectionMgr.select("11");
+
+        mDetailsLookup.initAt(11);
+        mInputDelegate.onSingleTapUp(TAP);
+
+        mSelection.assertNoSelection();
+    }
+
+    @Test
+    public void testTapOff_ClearsSelection() {
+        mSelectionMgr.select("7");
+        mDetailsLookup.initAt(7);
+
+        mInputDelegate.onLongPress(TAP);
+
+        mSelectionMgr.select("11");
+        mDetailsLookup.initAt(11);
+        mInputDelegate.onSingleTapUp(TAP);
+
+        mDetailsLookup.initAt(RecyclerView.NO_POSITION).setInItemSelectRegion(false);
+        mInputDelegate.onSingleTapUp(TAP);
+
+        mSelection.assertNoSelection();
+    }
+
+    private static final class TestCallbacks extends TouchInputHandler.Callbacks {
+
+        private @Nullable ItemDetails mActivated;
+        private boolean mVibrated;
+
+        @Override
+        public boolean onItemActivated(ItemDetails item, MotionEvent e) {
+            mActivated = item;
+            return false;
+        }
+
+        @Override
+        public boolean onDragInitiated(MotionEvent e) {
+            return false;
+        }
+
+        @Override
+        public void onPerformHapticFeedback() {
+            mVibrated = true;
+        }
+
+        private void assertActivated(ItemDetails expected) {
+            assertEquals(expected, mActivated);
+        }
+
+        private void assertVibrated() {
+            assertTrue(mVibrated);
+        }
+    }
+
+    private static final class TestRunnable implements Runnable {
+
+        private boolean mWasRun;
+
+        @Override
+        public void run() {
+            mWasRun = true;
+        }
+
+        void assertRan() {
+            assertTrue(mWasRun);
+        }
+    }
+}
diff --git a/tests/unit/com/android/documentsui/ui/ViewAutoScrollerTest.java b/tests/unit/com/android/documentsui/selection/ViewAutoScrollerTest.java
similarity index 88%
rename from tests/unit/com/android/documentsui/ui/ViewAutoScrollerTest.java
rename to tests/unit/com/android/documentsui/selection/ViewAutoScrollerTest.java
index 5ad5e3c..b75c3da 100644
--- a/tests/unit/com/android/documentsui/ui/ViewAutoScrollerTest.java
+++ b/tests/unit/com/android/documentsui/selection/ViewAutoScrollerTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.documentsui.ui;
+package com.android.documentsui.selection;
 
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -23,7 +23,8 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
-import com.android.documentsui.ui.ViewAutoScroller;
+import com.android.documentsui.selection.ViewAutoScroller.ScrollHost;
+import com.android.documentsui.selection.ViewAutoScroller.ScrollerCallbacks;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -46,15 +47,16 @@
     private ViewAutoScroller mAutoScroller;
     private Point mPoint;
     private boolean mActive;
-    private ViewAutoScroller.ScrollDistanceDelegate mDistanceDelegate;
-    private ViewAutoScroller.ScrollActionDelegate mActionDelegate;
+    private ScrollHost mHost;
+    private ScrollerCallbacks mCallbacks;
     private IntConsumer mScrollAssert;
 
     @Before
     public void setUp() {
         mActive = false;
         mPoint = new Point();
-        mDistanceDelegate = new ViewAutoScroller.ScrollDistanceDelegate() {
+
+        mHost = new ScrollHost() {
             @Override
             public boolean isActive() {
                 return mActive;
@@ -70,7 +72,8 @@
                 return mPoint;
             }
         };
-        mActionDelegate = new ViewAutoScroller.ScrollActionDelegate() {
+
+        mCallbacks = new ScrollerCallbacks() {
             @Override
             public void scrollBy(int dy) {
                 mScrollAssert.accept(dy);
@@ -84,7 +87,8 @@
             public void removeCallback(Runnable r) {
             }
         };
-        mAutoScroller = new ViewAutoScroller(mDistanceDelegate, mActionDelegate);
+
+        mAutoScroller = new ViewAutoScroller(mHost, mCallbacks);
     }
 
     @Test
diff --git a/tests/unit/com/android/documentsui/selection/testing/SelectionHelpers.java b/tests/unit/com/android/documentsui/selection/testing/SelectionHelpers.java
new file mode 100644
index 0000000..6bdd18a
--- /dev/null
+++ b/tests/unit/com/android/documentsui/selection/testing/SelectionHelpers.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 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.documentsui.selection.testing;
+
+import com.android.documentsui.selection.DefaultSelectionHelper;
+import com.android.documentsui.selection.DefaultSelectionHelper.SelectionMode;
+import com.android.documentsui.selection.SelectionHelper;
+import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
+
+import java.util.Collections;
+import java.util.List;
+
+public class SelectionHelpers {
+
+    public static final SelectionPredicate CAN_SET_ANYTHING = new SelectionPredicate() {
+        @Override
+        public boolean canSetStateForId(String id, boolean nextState) {
+            return true;
+        }
+
+        @Override
+        public boolean canSetStateAtPosition(int position, boolean nextState) {
+            return true;
+        }
+    };
+
+    private SelectionHelpers() {}
+
+    public static SelectionHelper createTestInstance() {
+        return createTestInstance(Collections.emptyList());
+    }
+
+    public static SelectionHelper createTestInstance(List<String> docs) {
+        return createTestInstance(docs, DefaultSelectionHelper.MODE_MULTIPLE);
+    }
+
+    public static SelectionHelper createTestInstance(
+            List<String> items, @SelectionMode int mode) {
+        return createTestInstance(new TestAdapter(items), mode, CAN_SET_ANYTHING);
+    }
+
+    public static SelectionHelper createTestInstance(
+            TestAdapter adapter, @SelectionMode int mode, SelectionPredicate selPredicate) {
+        return new DefaultSelectionHelper(
+                mode, adapter, new TestStableIdProvider(adapter), selPredicate);
+    }
+}
diff --git a/tests/unit/com/android/documentsui/selection/testing/SelectionPredicates.java b/tests/unit/com/android/documentsui/selection/testing/SelectionPredicates.java
new file mode 100644
index 0000000..0200919
--- /dev/null
+++ b/tests/unit/com/android/documentsui/selection/testing/SelectionPredicates.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection.testing;
+
+import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
+
+/**
+ * Test friendly {@link SelectionPredicate} instances.
+ */
+public final class SelectionPredicates {
+
+    private SelectionPredicates() {}
+
+    public static final SelectionPredicate CAN_SET_ANYTHING = new SelectionPredicate() {
+        @Override
+        public boolean canSetStateForId(String id, boolean nextState) {
+            return true;
+        }
+
+        @Override
+        public boolean canSetStateAtPosition(int position, boolean nextState) {
+            return true;
+        }
+    };
+}
diff --git a/tests/common/com/android/documentsui/selection/SelectionProbe.java b/tests/unit/com/android/documentsui/selection/testing/SelectionProbe.java
similarity index 69%
rename from tests/common/com/android/documentsui/selection/SelectionProbe.java
rename to tests/unit/com/android/documentsui/selection/testing/SelectionProbe.java
index d7a3632..4d5790b 100644
--- a/tests/common/com/android/documentsui/selection/SelectionProbe.java
+++ b/tests/unit/com/android/documentsui/selection/testing/SelectionProbe.java
@@ -14,35 +14,35 @@
  * limitations under the License.
  */
 
-package com.android.documentsui.selection;
+package com.android.documentsui.selection.testing;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import com.android.documentsui.selection.SelectionManager;
+import com.android.documentsui.selection.DefaultSelectionHelper;
 import com.android.documentsui.selection.Selection;
+import com.android.documentsui.selection.SelectionHelper;
 
 /**
- * Helper class for making assertions against the state of a {@link SelectionManager} instance and
- * the consistency of states between {@link SelectionManager} and
- * {@link SelectionManager.ItemCallback}.
+ * Helper class for making assertions against the state of a {@link DefaultSelectionHelper} instance
+ * and the consistency of states between {@link DefaultSelectionHelper} and
+ * {@link DefaultSelectionHelper.ItemEventCallback}.
  */
 public final class SelectionProbe {
 
-    private final SelectionManager mMgr;
-    private final TestItemSelectionListener mTestCallback;
+    private final SelectionHelper mMgr;
+    private final TestSelectionObserver mSelectionListener;
 
-    public SelectionProbe(SelectionManager mgr) {
+    public SelectionProbe(SelectionHelper mgr) {
         mMgr = mgr;
-        mTestCallback = new TestItemSelectionListener();
-
-        mMgr.addItemCallback(mTestCallback);
+        mSelectionListener = new TestSelectionObserver();
+        mMgr.addObserver(mSelectionListener);
     }
 
-    public SelectionProbe(SelectionManager mgr, TestItemSelectionListener testCallback) {
+    public SelectionProbe(SelectionHelper mgr, TestSelectionObserver selectionListener) {
         mMgr = mgr;
-        mTestCallback = testCallback;
+        mSelectionListener = selectionListener;
     }
 
     public void assertRangeSelected(int begin, int end) {
@@ -66,20 +66,20 @@
         Selection selection = mMgr.getSelection();
         assertEquals(selection.toString(), expected, selection.size());
 
-        mTestCallback.assertSelectionSize(expected);
+        mSelectionListener.assertSelectionSize(expected);
     }
 
     public void assertNoSelection() {
         assertSelectionSize(0);
 
-        mTestCallback.assertNoSelection();
+        mSelectionListener.assertNoSelection();
     }
 
     public void assertSelection(int... ids) {
         assertSelected(ids);
         assertEquals(ids.length, mMgr.getSelection().size());
 
-        mTestCallback.assertSelectionSize(ids.length);
+        mSelectionListener.assertSelectionSize(ids.length);
     }
 
     public void assertSelected(int... ids) {
@@ -88,7 +88,7 @@
             String sid = String.valueOf(id);
             assertTrue(sid + " is not in selection " + sel, sel.contains(sid));
 
-            mTestCallback.assertSelected(sid);
+            mSelectionListener.assertSelected(sid);
         }
     }
 
@@ -98,13 +98,13 @@
             String sid = String.valueOf(id);
             assertFalse(sid + " is in selection " + sel, sel.contains(sid));
 
-            mTestCallback.assertNotSelected(sid);
+            mSelectionListener.assertNotSelected(sid);
         }
     }
 
     public void select(int...positions) {
         for (int position : positions) {
-            mMgr.toggleSelection(String.valueOf(position));
+            mMgr.select(String.valueOf(position));
         }
     }
 }
diff --git a/tests/unit/com/android/documentsui/selection/testing/TestAdapter.java b/tests/unit/com/android/documentsui/selection/testing/TestAdapter.java
new file mode 100644
index 0000000..f4c6d17
--- /dev/null
+++ b/tests/unit/com/android/documentsui/selection/testing/TestAdapter.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection.testing;
+
+import static org.junit.Assert.assertTrue;
+
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.Adapter;
+import android.support.v7.widget.RecyclerView.AdapterDataObserver;
+import android.view.ViewGroup;
+
+import com.android.documentsui.selection.SelectionHelper;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class TestAdapter extends Adapter<TestHolder> {
+
+    private final List<String> mItems = new ArrayList<>();
+    private final List<Integer> mNotifiedOfSelection = new ArrayList<>();
+    private final AdapterDataObserver mAdapterObserver;
+
+    public TestAdapter() {
+        this(Collections.EMPTY_LIST);
+    }
+
+    public TestAdapter(List<String> items) {
+        mItems.addAll(items);
+        mAdapterObserver = new RecyclerView.AdapterDataObserver() {
+
+            @Override
+            public void onChanged() {
+            }
+
+            @Override
+            public void onItemRangeChanged(int startPosition, int itemCount, Object payload) {
+                if (SelectionHelper.SELECTION_CHANGED_MARKER.equals(payload)) {
+                    int last = startPosition + itemCount;
+                    for (int i = startPosition; i < last; i++) {
+                        mNotifiedOfSelection.add(i);
+                    }
+                }
+            }
+
+            @Override
+            public void onItemRangeInserted(int startPosition, int itemCount) {
+            }
+
+            @Override
+            public void onItemRangeRemoved(int startPosition, int itemCount) {
+            }
+
+            @Override
+            public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
+                throw new UnsupportedOperationException();
+            }
+        };
+
+        registerAdapterDataObserver(mAdapterObserver);
+    }
+
+    @Override
+    public TestHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        return new TestHolder(parent);
+    }
+
+    @Override
+    public void onBindViewHolder(TestHolder holder, int position) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getItemCount() {
+        return mItems.size();
+    }
+
+    public void updateTestModelIds(List<String> items) {
+        mItems.clear();
+        mItems.addAll(items);
+
+        notifyDataSetChanged();
+    }
+
+    public List<String> getStableIds() {
+        return mItems;
+    }
+
+    public int getPosition(String id) {
+        return mItems.indexOf(id);
+    }
+
+    public String getStableId(int position) {
+        return mItems.get(position);
+    }
+
+
+    public void resetSelectionNotifications() {
+        mNotifiedOfSelection.clear();
+    }
+
+    public void assertNotifiedOfSelectionChange(int position) {
+        assertTrue(mNotifiedOfSelection.contains(position));
+    }
+
+    public static List<String> createItemList(int num) {
+        List<String> items = new ArrayList<>(num);
+        for (int i = 0; i < num; ++i) {
+            items.add(Integer.toString(i));
+        }
+        return items;
+    }
+}
diff --git a/tests/unit/com/android/documentsui/selection/testing/TestBandPredicate.java b/tests/unit/com/android/documentsui/selection/testing/TestBandPredicate.java
new file mode 100644
index 0000000..2e901a0
--- /dev/null
+++ b/tests/unit/com/android/documentsui/selection/testing/TestBandPredicate.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection.testing;
+
+import android.view.MotionEvent;
+
+import com.android.documentsui.selection.BandPredicate;
+
+public class TestBandPredicate extends BandPredicate {
+
+    private boolean mCanInitiate = true;
+
+    public void setCanInitiate(boolean canInitiate) {
+        mCanInitiate = canInitiate;
+    }
+
+    @Override
+    public boolean canInitiate(MotionEvent e) {
+        return mCanInitiate;
+    }
+
+}
diff --git a/tests/unit/com/android/documentsui/selection/testing/TestData.java b/tests/unit/com/android/documentsui/selection/testing/TestData.java
new file mode 100644
index 0000000..1a05990
--- /dev/null
+++ b/tests/unit/com/android/documentsui/selection/testing/TestData.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 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.documentsui.selection.testing;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TestData {
+    public static List<String> create(int num) {
+        List<String> items = new ArrayList<String>(num);
+        for (int i = 0; i < num; ++i) {
+            items.add(Integer.toString(i));
+        }
+        return items;
+    }
+}
diff --git a/tests/unit/com/android/documentsui/selection/testing/TestEvents.java b/tests/unit/com/android/documentsui/selection/testing/TestEvents.java
new file mode 100644
index 0000000..c472adb
--- /dev/null
+++ b/tests/unit/com/android/documentsui/selection/testing/TestEvents.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2016 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.documentsui.selection.testing;
+
+import android.annotation.IntDef;
+import android.graphics.Point;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.MotionEvent.PointerCoords;
+import android.view.MotionEvent.PointerProperties;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Handy-dandy wrapper class to facilitate the creation of MotionEvents.
+ */
+public final class TestEvents {
+
+    /**
+     * Common mouse event types...for your convenience.
+     */
+    public static final class Mouse {
+        public static final MotionEvent CLICK =
+                TestEvents.builder().mouse().primary().build();
+        public static final MotionEvent CTRL_CLICK =
+                TestEvents.builder().mouse().primary().ctrl().build();
+        public static final MotionEvent ALT_CLICK =
+                TestEvents.builder().mouse().primary().alt().build();
+        public static final MotionEvent SHIFT_CLICK =
+                TestEvents.builder().mouse().primary().shift().build();
+        public static final MotionEvent SECONDARY_CLICK =
+                TestEvents.builder().mouse().secondary().build();
+        public static final MotionEvent TERTIARY_CLICK =
+                TestEvents.builder().mouse().tertiary().build();
+    }
+
+    /**
+     * Common touch event types...for your convenience.
+     */
+    public static final class Touch {
+        public static final MotionEvent TAP =
+                TestEvents.builder().touch().build();
+    }
+
+    static final int ACTION_UNSET = -1;
+
+    // Add other actions from MotionEvent.ACTION_ as needed.
+    @IntDef(flag = true, value = {
+            MotionEvent.ACTION_DOWN,
+            MotionEvent.ACTION_MOVE,
+            MotionEvent.ACTION_UP
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Action {}
+
+    // Add other types from MotionEvent.TOOL_TYPE_ as needed.
+    @IntDef(flag = true, value = {
+            MotionEvent.TOOL_TYPE_FINGER,
+            MotionEvent.TOOL_TYPE_MOUSE,
+            MotionEvent.TOOL_TYPE_STYLUS,
+            MotionEvent.TOOL_TYPE_UNKNOWN
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ToolType {}
+
+    @IntDef(flag = true, value = {
+            MotionEvent.BUTTON_PRIMARY,
+            MotionEvent.BUTTON_SECONDARY
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Button {}
+
+    @IntDef(flag = true, value = {
+            KeyEvent.META_SHIFT_ON,
+            KeyEvent.META_CTRL_ON
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Key {}
+
+    private static final class State {
+        private @Action int mAction = ACTION_UNSET;
+        private @ToolType int mToolType = MotionEvent.TOOL_TYPE_UNKNOWN;
+        private int mPointerCount = 1;
+        private Set<Integer> mButtons = new HashSet<>();
+        private Set<Integer> mKeys = new HashSet<>();
+        private Point mLocation = new Point(0, 0);
+        private Point mRawLocation = new Point(0, 0);
+    }
+
+    public static final Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Test event builder with convenience methods for common event attrs.
+     */
+    public static final class Builder {
+
+        private State mState = new State();
+
+        /**
+         * @param action Any action specified in {@link MotionEvent}.
+         * @return
+         */
+        public Builder action(int action) {
+            mState.mAction = action;
+            return this;
+        }
+
+        public Builder type(@ToolType int type) {
+            mState.mToolType = type;
+            return this;
+        }
+
+        public Builder location(int x, int y) {
+            mState.mLocation = new Point(x, y);
+            return this;
+        }
+
+        public Builder rawLocation(int x, int y) {
+            mState.mRawLocation = new Point(x, y);
+            return this;
+        }
+
+        public Builder pointerCount(int count) {
+            mState.mPointerCount = count;
+            return this;
+        }
+
+        /**
+         * Adds one or more button press attributes.
+         */
+        public Builder pressButton(@Button int... buttons) {
+            for (int button : buttons) {
+                mState.mButtons.add(button);
+            }
+            return this;
+        }
+
+        /**
+         * Removes one or more button press attributes.
+         */
+        public Builder releaseButton(@Button int... buttons) {
+            for (int button : buttons) {
+                mState.mButtons.remove(button);
+            }
+            return this;
+        }
+
+        /**
+         * Adds one or more key press attributes.
+         */
+        public Builder pressKey(@Key int... keys) {
+            for (int key : keys) {
+                mState.mKeys.add(key);
+            }
+            return this;
+        }
+
+        /**
+         * Removes one or more key press attributes.
+         */
+        public Builder releaseKey(@Button int... keys) {
+            for (int key : keys) {
+                mState.mKeys.remove(key);
+            }
+            return this;
+        }
+
+        public Builder touch() {
+            type(MotionEvent.TOOL_TYPE_FINGER);
+            return this;
+        }
+
+        public Builder mouse() {
+            type(MotionEvent.TOOL_TYPE_MOUSE);
+            return this;
+        }
+
+        public Builder shift() {
+            pressKey(KeyEvent.META_SHIFT_ON);
+            return this;
+        }
+
+        /**
+         * Use {@link #remove(@Attribute int...)}
+         */
+        public Builder unshift() {
+            releaseKey(KeyEvent.META_SHIFT_ON);
+            return this;
+        }
+
+        public Builder ctrl() {
+            pressKey(KeyEvent.META_CTRL_ON);
+            return this;
+        }
+
+        public Builder alt() {
+            pressKey(KeyEvent.META_ALT_ON);
+            return this;
+        }
+
+        public Builder primary() {
+            pressButton(MotionEvent.BUTTON_PRIMARY);
+            releaseButton(MotionEvent.BUTTON_SECONDARY);
+            releaseButton(MotionEvent.BUTTON_TERTIARY);
+            return this;
+        }
+
+        public Builder secondary() {
+            pressButton(MotionEvent.BUTTON_SECONDARY);
+            releaseButton(MotionEvent.BUTTON_PRIMARY);
+            releaseButton(MotionEvent.BUTTON_TERTIARY);
+            return this;
+        }
+
+        public Builder tertiary() {
+            pressButton(MotionEvent.BUTTON_TERTIARY);
+            releaseButton(MotionEvent.BUTTON_PRIMARY);
+            releaseButton(MotionEvent.BUTTON_SECONDARY);
+            return this;
+        }
+
+        public MotionEvent build() {
+
+            PointerProperties[] pointers = new PointerProperties[1];
+            pointers[0] = new PointerProperties();
+            pointers[0].id = 0;
+            pointers[0].toolType = mState.mToolType;
+
+            PointerCoords[] coords = new PointerCoords[1];
+            coords[0] = new PointerCoords();
+            coords[0].x = mState.mLocation.x;
+            coords[0].y = mState.mLocation.y;
+
+            int buttons = 0;
+            for (Integer button : mState.mButtons) {
+                buttons |= button;
+            }
+
+            int keys = 0;
+            for (Integer key : mState.mKeys) {
+                keys |= key;
+            }
+
+            return MotionEvent.obtain(
+                    0,     // down time
+                    1,     // event time
+                    mState.mAction,
+                    1,  // pointerCount,
+                    pointers,
+                    coords,
+                    keys,
+                    buttons,
+                    1.0f,  // x precision
+                    1.0f,  // y precision
+                    0,     // device id
+                    0,     // edge flags
+                    0,     // int source,
+                    0      // int flags
+                    );
+        }
+    }
+}
diff --git a/tests/unit/com/android/documentsui/selection/testing/TestHolder.java b/tests/unit/com/android/documentsui/selection/testing/TestHolder.java
new file mode 100644
index 0000000..a0728fe
--- /dev/null
+++ b/tests/unit/com/android/documentsui/selection/testing/TestHolder.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection.testing;
+
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.view.View;
+
+public class TestHolder extends ViewHolder {
+    public TestHolder(View itemView) {
+        super(itemView);
+    }
+}
diff --git a/tests/unit/com/android/documentsui/selection/testing/TestMouseCallbacks.java b/tests/unit/com/android/documentsui/selection/testing/TestMouseCallbacks.java
new file mode 100644
index 0000000..06edc1e
--- /dev/null
+++ b/tests/unit/com/android/documentsui/selection/testing/TestMouseCallbacks.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection.testing;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.support.v7.widget.RecyclerView;
+import android.view.MotionEvent;
+
+import com.android.documentsui.selection.MouseInputHandler;
+import com.android.documentsui.selection.ItemDetailsLookup.ItemDetails;
+
+public final class TestMouseCallbacks extends MouseInputHandler.Callbacks {
+
+    private String mFocusItemId;
+    private int mFocusPosition;
+    private MotionEvent mLastContextEvent;
+    private ItemDetails mActivated;
+
+    @Override
+    public boolean onItemActivated(ItemDetails item, MotionEvent e) {
+        mActivated = item;
+        return true;
+    }
+
+    @Override
+    public boolean onContextClick(MotionEvent e) {
+        mLastContextEvent = e;
+        return false;
+    }
+
+    @Override
+    public void onPerformHapticFeedback() {
+    }
+
+    @Override
+    public void clearFocus() {
+        mFocusPosition = RecyclerView.NO_POSITION;
+        mFocusItemId = null;
+    }
+
+    @Override
+    public void focusItem(ItemDetails item) {
+        mFocusItemId = item.getStableId();
+        mFocusPosition = item.getPosition();
+    }
+
+    @Override
+    public int getFocusedPosition() {
+        return mFocusPosition;
+    }
+
+    @Override
+    public boolean hasFocusedItem() {
+        return mFocusItemId != null;
+    }
+
+    public void assertLastEvent(MotionEvent expected) {
+        // sadly, MotionEvent doesn't implement equals, so we compare references.
+        assertTrue(expected == mLastContextEvent);
+    }
+
+    public void assertActivated(ItemDetails expected) {
+        assertEquals(expected, mActivated);
+    }
+
+    public void assertHasFocus(boolean focused) {
+        assertEquals(focused, hasFocusedItem());
+    }
+
+    public void assertFocused(String expectedId) {
+        assertEquals(expectedId, mFocusItemId);
+    }
+}
\ No newline at end of file
diff --git a/tests/unit/com/android/documentsui/selection/testing/TestSelectionObserver.java b/tests/unit/com/android/documentsui/selection/testing/TestSelectionObserver.java
new file mode 100644
index 0000000..e75bde3
--- /dev/null
+++ b/tests/unit/com/android/documentsui/selection/testing/TestSelectionObserver.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection.testing;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.android.documentsui.selection.SelectionHelper.SelectionObserver;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class TestSelectionObserver extends SelectionObserver {
+
+    private final Set<String> mSelected = new HashSet<>();
+    private boolean mSelectionChanged = false;
+    private boolean mSelectionReset = false;
+    private boolean mSelectionRestored = false;
+
+    public void reset() {
+        mSelected.clear();
+        mSelectionChanged = false;
+        mSelectionReset = false;
+    }
+
+    @Override
+    public void onItemStateChanged(String id, boolean selected) {
+        if (selected) {
+            assertNotSelected(id);
+            mSelected.add(id);
+        } else {
+            assertSelected(id);
+            mSelected.remove(id);
+        }
+    }
+
+    @Override
+    public void onSelectionReset() {
+        mSelectionReset = true;
+        mSelected.clear();
+    }
+
+    @Override
+    public void onSelectionChanged() {
+        mSelectionChanged = true;
+    }
+
+    @Override
+    public void onSelectionRestored() {
+        mSelectionRestored = true;
+    }
+
+    void assertNoSelection() {
+        assertTrue(mSelected.isEmpty());
+    }
+
+    void assertSelectionSize(int expected) {
+        assertEquals(expected, mSelected.size());
+    }
+
+    void assertSelected(String id) {
+        assertTrue(id + " is not selected.", mSelected.contains(id));
+    }
+
+    void assertNotSelected(String id) {
+        assertFalse(id + " is already selected", mSelected.contains(id));
+    }
+
+    public void assertSelectionChanged() {
+        assertTrue(mSelectionChanged);
+    }
+
+    public void assertSelectionUnchanged() {
+        assertFalse(mSelectionChanged);
+    }
+
+    public void assertSelectionReset() {
+        assertTrue(mSelectionReset);
+    }
+
+    public void assertSelectionRestored() {
+        assertTrue(mSelectionRestored);
+    }
+}
diff --git a/tests/unit/com/android/documentsui/selection/testing/TestSelectionPredicate.java b/tests/unit/com/android/documentsui/selection/testing/TestSelectionPredicate.java
new file mode 100644
index 0000000..578be3d
--- /dev/null
+++ b/tests/unit/com/android/documentsui/selection/testing/TestSelectionPredicate.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection.testing;
+
+import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
+
+public final class TestSelectionPredicate extends SelectionPredicate {
+    private boolean mValue;
+
+    public void setReturnValue(boolean value) {
+        mValue = value;
+    }
+
+    @Override
+    public boolean canSetStateForId(String id, boolean nextState) {
+        return mValue;
+    }
+
+    @Override
+    public boolean canSetStateAtPosition(int position, boolean nextState) {
+        return mValue;
+    }
+}
\ No newline at end of file
diff --git a/tests/unit/com/android/documentsui/selection/testing/TestStableIdProvider.java b/tests/unit/com/android/documentsui/selection/testing/TestStableIdProvider.java
new file mode 100644
index 0000000..1d50737
--- /dev/null
+++ b/tests/unit/com/android/documentsui/selection/testing/TestStableIdProvider.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 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.documentsui.selection.testing;
+
+import static android.support.v4.util.Preconditions.checkArgument;
+
+import com.android.documentsui.selection.SelectionHelper.StableIdProvider;
+
+import java.util.List;
+
+/**
+ * Provides RecyclerView selection code access to stable ids backed
+ * by TestAdapter.
+ */
+public final class TestStableIdProvider extends StableIdProvider {
+
+    private final TestAdapter mAdapter;
+
+    public TestStableIdProvider(TestAdapter adapter) {
+        checkArgument(adapter != null);
+        mAdapter = adapter;
+    }
+
+    @Override
+    public String getStableId(int position) {
+        return mAdapter.getStableId(position);
+    }
+
+    @Override
+    public int getPosition(String id) {
+        return mAdapter.getPosition(id);
+    }
+
+    @Override
+    public List<String> getStableIds() {
+        return mAdapter.getStableIds();
+    }
+}
diff --git a/tests/unit/com/android/documentsui/services/FileOperationServiceTest.java b/tests/unit/com/android/documentsui/services/FileOperationServiceTest.java
index 7f75aa5..a210c0e 100644
--- a/tests/unit/com/android/documentsui/services/FileOperationServiceTest.java
+++ b/tests/unit/com/android/documentsui/services/FileOperationServiceTest.java
@@ -21,8 +21,8 @@
 import static com.android.documentsui.services.FileOperations.createBaseIntent;
 import static com.android.documentsui.services.FileOperations.createJobId;
 import static com.google.android.collect.Lists.newArrayList;
+import static org.junit.Assert.fail;
 
-import android.app.Notification;
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
@@ -131,8 +131,9 @@
     public void testRunsCopyJobs_AfterExceptionInJobCreation() throws Exception {
         try {
             startService(createCopyIntent(new ArrayList<>(), BETA_DOC));
-        } catch(AssertionError e) {
-            // Expected AssertionError
+            fail("Should have throw exception.");
+        } catch(IllegalArgumentException expected) {
+            // We're sending a naughty empty list that should result in an IllegalArgumentException.
         }
         startService(createCopyIntent(newArrayList(GAMMA_DOC), DELTA_DOC));