Merge "Fix broken a11y function"
diff --git a/res/layout-sw720dp/item_doc_header_message.xml b/res/layout-sw720dp/item_doc_header_message.xml
index efec111..9b797ad 100644
--- a/res/layout-sw720dp/item_doc_header_message.xml
+++ b/res/layout-sw720dp/item_doc_header_message.xml
@@ -13,37 +13,52 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:animateLayoutChanges="true"
-    android:id="@+id/message_container"
-    android:layout_height="wrap_content"
+<com.google.android.material.card.MaterialCardView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
-    android:layout_marginTop="@dimen/list_item_padding"
-    android:layout_marginBottom="0dp"
-    android:minHeight="?android:attr/listPreferredItemHeightSmall">
+    android:layout_height="wrap_content"
+    android:layout_margin="4dp"
+    android:elevation="0dp"
+    android:duplicateParentState="true"
+    app:cardElevation="0dp"
+    app:strokeWidth="1dp"
+    app:strokeColor="?android:strokeColor">
 
-    <ImageView
-        android:contentDescription="@null"
-        android:id="@+id/message_icon"
-        android:layout_height="@dimen/icon_size"
-        android:layout_width="@dimen/icon_size"
-        android:layout_marginStart="@dimen/list_item_padding"
-        android:layout_marginEnd="12dp"
-        android:scaleType="centerInside"/>
-
-    <TextView
-        android:id="@+id/message_textview"
+    <RelativeLayout
+        android:animateLayoutChanges="true"
+        android:id="@+id/message_container"
         android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:layout_toEndOf="@+id/message_icon"
-        android:selectAllOnFocus="true"/>
+        android:layout_width="match_parent"
+        android:minHeight="?android:attr/listPreferredItemHeightSmall">
 
-    <Button
-        android:id="@+id/button_dismiss"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:layout_alignEnd="@+id/message_textview"
-        android:layout_below="@+id/message_textview"
-        android:text="@android:string/ok"
-        style="?attr/materialButtonStyle"/>
-</RelativeLayout>
+        <ImageView
+            android:contentDescription="@null"
+            android:id="@+id/message_icon"
+            android:layout_height="@dimen/icon_size"
+            android:layout_width="@dimen/icon_size"
+            android:layout_marginStart="0dp"
+            android:layout_marginEnd="10dp"
+            android:layout_marginTop="4dp"
+            android:scaleType="centerInside"/>
+
+        <TextView
+            android:id="@+id/message_textview"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:layout_toEndOf="@+id/message_icon"
+            android:layout_marginStart="0dp"
+            android:layout_marginEnd="8dp"
+            android:layout_marginTop="12dp"
+            android:selectAllOnFocus="true"/>
+
+        <Button
+            android:id="@+id/button_dismiss"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:layout_alignEnd="@+id/message_textview"
+            android:layout_below="@+id/message_textview"
+            android:text="@android:string/ok"
+            style="@style/DialogTextButton"/>
+    </RelativeLayout>
+</com.google.android.material.card.MaterialCardView>
diff --git a/res/layout/item_doc_header_message.xml b/res/layout/item_doc_header_message.xml
index 63766a2..9b797ad 100644
--- a/res/layout/item_doc_header_message.xml
+++ b/res/layout/item_doc_header_message.xml
@@ -13,35 +13,52 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:animateLayoutChanges="true"
-    android:id="@+id/message_container"
-    android:layout_height="wrap_content"
+<com.google.android.material.card.MaterialCardView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
-    android:minHeight="?android:attr/listPreferredItemHeightSmall">
+    android:layout_height="wrap_content"
+    android:layout_margin="4dp"
+    android:elevation="0dp"
+    android:duplicateParentState="true"
+    app:cardElevation="0dp"
+    app:strokeWidth="1dp"
+    app:strokeColor="?android:strokeColor">
 
-    <ImageView
-        android:contentDescription="@null"
-        android:id="@+id/message_icon"
-        android:layout_height="@dimen/icon_size"
-        android:layout_width="@dimen/icon_size"
-        android:layout_marginStart="0dp"
-        android:layout_marginEnd="@dimen/list_item_padding"
-        android:scaleType="centerInside"/>
-
-    <TextView
-        android:id="@+id/message_textview"
+    <RelativeLayout
+        android:animateLayoutChanges="true"
+        android:id="@+id/message_container"
         android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:layout_toEndOf="@+id/message_icon"
-        android:selectAllOnFocus="true"/>
+        android:layout_width="match_parent"
+        android:minHeight="?android:attr/listPreferredItemHeightSmall">
 
-    <Button
-        android:id="@+id/button_dismiss"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:layout_alignEnd="@+id/message_textview"
-        android:layout_below="@+id/message_textview"
-        android:text="@android:string/ok"
-        style="?attr/materialButtonStyle"/>
-</RelativeLayout>
+        <ImageView
+            android:contentDescription="@null"
+            android:id="@+id/message_icon"
+            android:layout_height="@dimen/icon_size"
+            android:layout_width="@dimen/icon_size"
+            android:layout_marginStart="0dp"
+            android:layout_marginEnd="10dp"
+            android:layout_marginTop="4dp"
+            android:scaleType="centerInside"/>
+
+        <TextView
+            android:id="@+id/message_textview"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:layout_toEndOf="@+id/message_icon"
+            android:layout_marginStart="0dp"
+            android:layout_marginEnd="8dp"
+            android:layout_marginTop="12dp"
+            android:selectAllOnFocus="true"/>
+
+        <Button
+            android:id="@+id/button_dismiss"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:layout_alignEnd="@+id/message_textview"
+            android:layout_below="@+id/message_textview"
+            android:text="@android:string/ok"
+            style="@style/DialogTextButton"/>
+    </RelativeLayout>
+</com.google.android.material.card.MaterialCardView>
diff --git a/src/com/android/documentsui/picker/ActionHandler.java b/src/com/android/documentsui/picker/ActionHandler.java
index ef16e6d..e9868df 100644
--- a/src/com/android/documentsui/picker/ActionHandler.java
+++ b/src/com/android/documentsui/picker/ActionHandler.java
@@ -23,6 +23,7 @@
 import static com.android.documentsui.base.State.ACTION_OPEN_TREE;
 import static com.android.documentsui.base.State.ACTION_PICK_COPY_DESTINATION;
 
+import android.content.ActivityNotFoundException;
 import android.content.ClipData;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -218,7 +219,7 @@
         mInjector.pickResult.setIsSearching(isSearching);
         mInjector.pickResult.setRoot(root);
         mInjector.pickResult.setFileUri(uri);
-        getUpdatePickResultTask().execute();
+        getUpdatePickResultTask().safeExecute();
     }
 
     private void loadDefaultLocation() {
@@ -298,7 +299,12 @@
         intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_FORWARD_RESULT);
         intent.setComponent(new ComponentName(
                 info.activityInfo.applicationInfo.packageName, info.activityInfo.name));
-        mActivity.startActivityForResult(intent, CODE_FORWARD);
+        try {
+            mActivity.startActivityForResult(intent, CODE_FORWARD);
+        } catch (SecurityException | ActivityNotFoundException e) {
+            Log.e(TAG, "Caught error: " + e.getLocalizedMessage());
+            mInjector.dialogs.showNoApplicationFound();
+        }
     }
 
     @Override
diff --git a/src/com/android/documentsui/picker/PickActivity.java b/src/com/android/documentsui/picker/PickActivity.java
index 57969e0..7736077 100644
--- a/src/com/android/documentsui/picker/PickActivity.java
+++ b/src/com/android/documentsui/picker/PickActivity.java
@@ -151,7 +151,7 @@
     public void onBackPressed() {
         super.onBackPressed();
         // log the case of user picking nothing.
-        mInjector.actions.getUpdatePickResultTask().execute();
+        mInjector.actions.getUpdatePickResultTask().safeExecute();
     }
 
     @Override
diff --git a/src/com/android/documentsui/picker/UpdatePickResultTask.java b/src/com/android/documentsui/picker/UpdatePickResultTask.java
index ff35137..43f42ab 100644
--- a/src/com/android/documentsui/picker/UpdatePickResultTask.java
+++ b/src/com/android/documentsui/picker/UpdatePickResultTask.java
@@ -20,6 +20,7 @@
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.SystemClock;
+
 import com.android.documentsui.Metrics;
 
 // load & update mime type & repeatedly pick count in background
@@ -62,4 +63,12 @@
         Metrics.logPickResult(mPickResult);
     }
 
+    /**
+     * Check the status and only execute if task is pending.
+     */
+    public void safeExecute() {
+        if (getStatus() == Status.PENDING) {
+            execute();
+        }
+    }
 }
diff --git a/src/com/android/documentsui/sidebar/RootsFragment.java b/src/com/android/documentsui/sidebar/RootsFragment.java
index 4d40bbc..4db65f3 100644
--- a/src/com/android/documentsui/sidebar/RootsFragment.java
+++ b/src/com/android/documentsui/sidebar/RootsFragment.java
@@ -355,6 +355,13 @@
 
         // Omit ourselves and maybe calling package from the list
         for (ResolveInfo info : infos) {
+            if (!info.activityInfo.exported) {
+                if (VERBOSE) {
+                    Log.v(TAG, "Non exported activity: " + info.activityInfo);
+                }
+                continue;
+            }
+
             final String packageName = info.activityInfo.packageName;
             if (!context.getPackageName().equals(packageName) &&
                     !TextUtils.equals(excludePackage, packageName)) {
diff --git a/tests/unit/com/android/documentsui/picker/UpdatePickResultTaskTest.java b/tests/unit/com/android/documentsui/picker/UpdatePickResultTaskTest.java
new file mode 100644
index 0000000..4c2fb89
--- /dev/null
+++ b/tests/unit/com/android/documentsui/picker/UpdatePickResultTaskTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 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.picker;
+
+import android.content.Context;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class UpdatePickResultTaskTest {
+
+    private UpdatePickResultTask mTask;
+
+    @Before
+    public void setUp() {
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        mTask = new UpdatePickResultTask(context, new PickResult());
+    }
+
+    @Test
+    public void testSafeExcute_noCrash() throws Exception {
+        mTask.safeExecute();
+        mTask.safeExecute();
+    }
+}