Snap for 11219529 from a1aa87f7bc352bd72769cc18ddf92ceca014852a to mainline-tzdata4-release

Change-Id: Ibeadb712e77f06bec1260b6a4b4b417548fe5e4a
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index e62ab7e..44a5fd3 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -69,7 +69,7 @@
     <string name="picker_profile_work_paused_msg" msgid="6321552322125246726">"لفتح صور العمل، عليك تفعيل تطبيقات العمل ثم إعادة المحاولة."</string>
     <string name="picker_privacy_message" msgid="9132700451027116817">"يمكن لهذا التطبيق الوصول إلى الصور التي تختارها فقط."</string>
     <string name="picker_header_permissions" msgid="675872774407768495">"اختَر الصور والفيديوهات التي تريد السماح لهذا التطبيق بالوصول إليها"</string>
-    <string name="picker_album_item_count" msgid="4420723302534177596">"{count,plural, =1{عنصر واحد (<xliff:g id="COUNT_0">^1</xliff:g>)}zero{<xliff:g id="COUNT_1">^1</xliff:g> عنصر}two{عنصران (<xliff:g id="COUNT_1">^1</xliff:g>)}few{<xliff:g id="COUNT_1">^1</xliff:g> عناصر}many{<xliff:g id="COUNT_1">^1</xliff:g> عنصرًا}other{<xliff:g id="COUNT_1">^1</xliff:g> عنصر}}"</string>
+    <string name="picker_album_item_count" msgid="4420723302534177596">"{count,plural, =1{صورة واحدة (<xliff:g id="COUNT_0">^1</xliff:g>)}zero{<xliff:g id="COUNT_1">^1</xliff:g> صورة}two{صورتان (<xliff:g id="COUNT_1">^1</xliff:g>)}few{<xliff:g id="COUNT_1">^1</xliff:g> صور}many{<xliff:g id="COUNT_1">^1</xliff:g> صورة}other{<xliff:g id="COUNT_1">^1</xliff:g> صورة}}"</string>
     <string name="picker_add_button_multi_select" msgid="4005164092275518399">"إضافة (<xliff:g id="COUNT">^1</xliff:g>)"</string>
     <string name="picker_add_button_multi_select_permissions" msgid="5138751105800138838">"السماح (<xliff:g id="COUNT">^1</xliff:g>)"</string>
     <string name="picker_category_camera" msgid="4857367052026843664">"الكاميرا"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 9525714..421552d 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -59,7 +59,7 @@
     <string name="picker_view_selected" msgid="2266031384396143883">"Таңдалғанды көру"</string>
     <string name="picker_photos" msgid="7415035516411087392">"Фотосуреттер"</string>
     <string name="picker_albums" msgid="4822511902115299142">"Aльбомдар"</string>
-    <string name="picker_preview" msgid="6257414886055861039">"Алдын ала көру"</string>
+    <string name="picker_preview" msgid="6257414886055861039">"Алғы көрініс"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"Жұмыс профиліне ауысу"</string>
     <string name="picker_personal_profile" msgid="639484258397758406">"Жеке профильге ауысу"</string>
     <string name="picker_profile_admin_title" msgid="4172022376418293777">"Әкімшіңіз бөгеген"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index e121144..63ee61f 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -58,7 +58,7 @@
     <string name="picker_albums_empty_message" msgid="8341079772950966815">"କୌଣସି ଆଲବମ ନାହିଁ"</string>
     <string name="picker_view_selected" msgid="2266031384396143883">"ଚୟନିତଗୁଡ଼ିକୁ ଦେଖନ୍ତୁ"</string>
     <string name="picker_photos" msgid="7415035516411087392">"ଫଟୋ"</string>
-    <string name="picker_albums" msgid="4822511902115299142">"ଆଲବମ୍"</string>
+    <string name="picker_albums" msgid="4822511902115299142">"ଆଲବମ"</string>
     <string name="picker_preview" msgid="6257414886055861039">"ପ୍ରିଭ୍ୟୁ"</string>
     <string name="picker_work_profile" msgid="2083221066869141576">"ୱାର୍କକୁ ସ୍ୱିଚ୍ କରନ୍ତୁ"</string>
     <string name="picker_personal_profile" msgid="639484258397758406">"ବ୍ୟକ୍ତିଗତକୁ ସ୍ୱିଚ୍ କରନ୍ତୁ"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 38025e8..741a806 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -33,7 +33,7 @@
     <string name="permission_more_thumb" msgid="1938863829470531577">"{count,plural, =1{+<xliff:g id="COUNT_0">^1</xliff:g>}many{+<xliff:g id="COUNT_1">^1</xliff:g>}other{+<xliff:g id="COUNT_1">^1</xliff:g>}}"</string>
     <string name="permission_more_text" msgid="2471785045095597753">"{count,plural, =1{E <xliff:g id="COUNT_0">^1</xliff:g> item adicional}many{E <xliff:g id="COUNT_1">^1</xliff:g> itens adicionais}other{E <xliff:g id="COUNT_1">^1</xliff:g> itens adicionais}}"</string>
     <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Limpe ficheiros de apps temporários"</string>
-    <string name="cache_clearing_dialog_text" msgid="7057784635111940957">"A app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> pretende limpar alguns ficheiros temporários. Isto pode resultar num aumento da utilização da bateria ou dos dados móveis."</string>
+    <string name="cache_clearing_dialog_text" msgid="7057784635111940957">"A app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> quer limpar alguns ficheiros temporários. Isto pode resultar num aumento da utilização da bateria ou dos dados móveis."</string>
     <string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"A limpar ficheiros temporários da app…"</string>
     <string name="clear" msgid="5524638938415865915">"Limpar"</string>
     <string name="allow" msgid="8885707816848569619">"Permitir"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 78f2d7c..fd04b6d 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -68,7 +68,7 @@
     <string name="picker_profile_work_paused_title" msgid="382212880704235925">"వర్క్ యాప్‌లు పాజ్ చేయబడ్డాయి"</string>
     <string name="picker_profile_work_paused_msg" msgid="6321552322125246726">"వర్క్ ఫోటోలను తెరవడానికి, మీ వర్క్ యాప్‌లను ఆన్ చేసి, ఆపై మళ్లీ ట్రై చేయండి"</string>
     <string name="picker_privacy_message" msgid="9132700451027116817">"ఈ యాప్ మీరు ఎంచుకున్న ఫోటోలను మాత్రమే యాక్సెస్ చేయగలదు"</string>
-    <string name="picker_header_permissions" msgid="675872774407768495">"ఏ ఫోటోలు, వీడియోలను ఈ యాప్ యాక్సెస్ చేయవచ్చు అని మీరు అనుకుంటున్నారో వాటిని ఎంచుకోండి"</string>
+    <string name="picker_header_permissions" msgid="675872774407768495">"ఈ యాప్‌, యాక్సెస్ చేయడానికి మీరు అనుమతించే ఫోటోలను, వీడియోలను ఎంచుకోండి"</string>
     <string name="picker_album_item_count" msgid="4420723302534177596">"{count,plural, =1{<xliff:g id="COUNT_0">^1</xliff:g> ఐటెమ్}other{<xliff:g id="COUNT_1">^1</xliff:g> ఐటెమ్‌లు}}"</string>
     <string name="picker_add_button_multi_select" msgid="4005164092275518399">"జోడించండి (<xliff:g id="COUNT">^1</xliff:g>)"</string>
     <string name="picker_add_button_multi_select_permissions" msgid="5138751105800138838">"అనుమతించండి (<xliff:g id="COUNT">^1</xliff:g>)"</string>
diff --git a/src/com/android/providers/media/util/DatabaseUtils.java b/src/com/android/providers/media/util/DatabaseUtils.java
index e83d05c..ea48c2e 100644
--- a/src/com/android/providers/media/util/DatabaseUtils.java
+++ b/src/com/android/providers/media/util/DatabaseUtils.java
@@ -126,8 +126,9 @@
                             res.append(((Boolean) arg).booleanValue() ? 1 : 0);
                         } else {
                             res.append('\'');
-                            // Escape single quote character while appending the string.
-                            res.append(arg.toString().replace("'", "''"));
+                            // Escape single quote character while appending the string and reject
+                            // invalid unicode.
+                            res.append(escapeSingleQuoteAndRejectInvalidUnicode(arg.toString()));
                             res.append('\'');
                         }
                         break;
@@ -141,6 +142,37 @@
         return res.toString();
     }
 
+    private static String escapeSingleQuoteAndRejectInvalidUnicode(@NonNull String target) {
+        final int len = target.length();
+        final StringBuilder res = new StringBuilder(len);
+        boolean lastHigh = false;
+
+        for (int i = 0; i < len; ) {
+            final char c = target.charAt(i++);
+
+            if (lastHigh != Character.isLowSurrogate(c)) {
+                Log.e(TAG, "Invalid surrogate in string " + target);
+                throw new IllegalArgumentException("Invalid surrogate in string " + target);
+            }
+
+            lastHigh = Character.isHighSurrogate(c);
+
+            // Escape the single quotes by duplicating them
+            if (c == '\'') {
+                res.append(c);
+            }
+
+            res.append(c);
+        }
+
+        if (lastHigh) {
+            Log.e(TAG, "Invalid surrogate in string " + target);
+            throw new IllegalArgumentException("Invalid surrogate in string " + target);
+        }
+
+        return res.toString();
+    }
+
     /**
      * Returns data type of the given object's value.
      *<p>
diff --git a/src/com/android/providers/media/util/FileUtils.java b/src/com/android/providers/media/util/FileUtils.java
index d6296ae..376cdf3 100644
--- a/src/com/android/providers/media/util/FileUtils.java
+++ b/src/com/android/providers/media/util/FileUtils.java
@@ -1327,9 +1327,17 @@
         values.remove(MediaColumns.BUCKET_ID);
         values.remove(MediaColumns.BUCKET_DISPLAY_NAME);
 
-        final String data = values.getAsString(MediaColumns.DATA);
+        String data = values.getAsString(MediaColumns.DATA);
         if (TextUtils.isEmpty(data)) return;
 
+        try {
+            data = new File(data).getCanonicalPath();
+            values.put(MediaColumns.DATA, data);
+        } catch (IOException e) {
+            throw new IllegalArgumentException(
+                    String.format(Locale.ROOT, "Invalid file path:%s in request.", data));
+        }
+
         final File file = new File(data);
         final File fileLower = new File(data.toLowerCase(Locale.ROOT));
 
diff --git a/tests/AndroidTest.xml b/tests/AndroidTest.xml
index b388372..14412ba 100644
--- a/tests/AndroidTest.xml
+++ b/tests/AndroidTest.xml
@@ -26,10 +26,6 @@
         <option name="install-arg" value="-g" />
     </target_preparer>
 
-    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
-        <option name="force-root" value="true" />
-    </target_preparer>
-
     <option
         name="config-descriptor:metadata"
         key="mainline-param"
@@ -43,7 +39,6 @@
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
         <option name="hidden-api-checks" value="false"/>
         <option name="instrumentation-arg" key="thisisignored" value="thisisignored --no-window-animation" />
-        <option name="test-filter-dir" value="/data/data/com.android.providers.media.tests"/>
     </test>
 
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
diff --git a/tests/src/com/android/providers/media/PublicVolumeTest.java b/tests/src/com/android/providers/media/PublicVolumeTest.java
index e4a9ee8..e2a272f 100644
--- a/tests/src/com/android/providers/media/PublicVolumeTest.java
+++ b/tests/src/com/android/providers/media/PublicVolumeTest.java
@@ -35,6 +35,7 @@
 
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -63,6 +64,7 @@
     }
 
     @Test
+    @Ignore("Re-enable with fix b/281794265")
     public void testPublicVolumeDefaultFolders() throws Exception {
         Context context = InstrumentationRegistry.getTargetContext();
 
diff --git a/tests/src/com/android/providers/media/util/DatabaseUtilsTest.java b/tests/src/com/android/providers/media/util/DatabaseUtilsTest.java
index 685d897..a907875 100644
--- a/tests/src/com/android/providers/media/util/DatabaseUtilsTest.java
+++ b/tests/src/com/android/providers/media/util/DatabaseUtilsTest.java
@@ -39,6 +39,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -127,6 +128,15 @@
     }
 
     @Test
+    public void testBindSelection_RejectInvalidUnicode() {
+        assertThrows(IllegalArgumentException.class, () -> bindSelection("DATA=?", "Fo\uD83Do"));
+        assertThrows(IllegalArgumentException.class, () -> bindSelection("DATA=?", "Fo\uDE00o"));
+        assertEquals("DATA='Fo\uD83D\uDE00o'", bindSelection("DATA=?", "Fo\uD83D\uDE00o"));
+        assertThrows(
+                IllegalArgumentException.class, () -> bindSelection("DATA=?", "Fo\uDE00\uD83Do"));
+    }
+
+    @Test
     public void testResolveQueryArgs_GroupBy() throws Exception {
         args.putStringArray(QUERY_ARG_GROUP_COLUMNS, new String[] { "foo", "bar" });
         args.putString(QUERY_ARG_SQL_GROUP_BY, "raw");