Merge "Fix CTS tests related to ephemeral apps on Watch" into oc-dev am: 09d605d4db am: b6af67f1e6
am: 3cd50aa8a8

Change-Id: I9e68ba44beef15c77ab1c43903af8dd965fb681e
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index e67b07a..be7fe57 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -1685,7 +1685,7 @@
         2. If \'Cts Verifier\' is not allowed to install apps, a warning dialog will appear
         blocking the install. In this case go to step 3, else skip to step 4.\n
         3. Allow \'Cts Verifier\' to install apps. Return to package installer.\n
-        4. Accept the package and verify that it installs.
+        4. Accept the installation and verify that it succeeds (no error message is displayed).
     </string>
 
     <string name="provisioning_byod_nonmarket_deny">Disable non-market apps</string>
@@ -2850,7 +2850,7 @@
     <string name="disallow_outgoing_beam">Disallow outgoing beam</string>
     <string name="disallow_outgoing_beam_action">Switching on android beam</string>
     <string name="disallow_remove_user">Disallow remove user</string>
-    <string name="disallow_remove_user_action">Removing other users</string>
+    <string name="disallow_remove_user_action">Removing other users (please create a user and attempt to remove it to verify)</string>
     <string name="disallow_remove_managed_profile">Disallow remove managed profile</string>
     <string name="disallow_remove_managed_profile_action">Removing the work profile. It shouldn\'t be possible neither from the Accounts screen nor the Device Administrators screen (after selecting the Device Administrator that corresponds to the badged version of \"CTS Verifier\")</string>
     <string name="disallow_share_location">Disallow share location</string>
diff --git a/hostsidetests/jvmti/run-tests/test-912/AndroidTest.xml b/hostsidetests/jvmti/run-tests/test-912/AndroidTest.xml
index 697beb2..7137f5f 100644
--- a/hostsidetests/jvmti/run-tests/test-912/AndroidTest.xml
+++ b/hostsidetests/jvmti/run-tests/test-912/AndroidTest.xml
@@ -14,6 +14,7 @@
      limitations under the License.
 -->
 <configuration description="Config for CTS JVMTI test cases">
+    <option name="config-descriptor:metadata" key="component" value="art" />
     <target_preparer class="android.jvmti.cts.JvmtiPreparer">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsJvmtiRunTest912DeviceApp.apk" />
diff --git a/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java b/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
index 9b5f001..f0b303b 100644
--- a/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
+++ b/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
@@ -21,6 +21,7 @@
 import android.graphics.BitmapFactory;
 import android.media.ExifInterface;
 import android.os.Environment;
+import android.os.FileUtils;
 import android.test.AndroidTestCase;
 import android.util.Log;
 import android.system.ErrnoException;
@@ -70,7 +71,7 @@
             ExifInterface.TAG_MAKE,
             ExifInterface.TAG_MODEL,
             ExifInterface.TAG_F_NUMBER,
-            ExifInterface.TAG_DATETIME,
+            ExifInterface.TAG_DATETIME_ORIGINAL,
             ExifInterface.TAG_EXPOSURE_TIME,
             ExifInterface.TAG_FLASH,
             ExifInterface.TAG_FOCAL_LENGTH,
@@ -107,7 +108,7 @@
         public final String make;
         public final String model;
         public final float aperture;
-        public final String datetime;
+        public final String dateTimeOriginal;
         public final float exposureTime;
         public final float flash;
         public final String focalLength;
@@ -153,7 +154,7 @@
             make = getString(typedArray, index++);
             model = getString(typedArray, index++);
             aperture = typedArray.getFloat(index++, 0f);
-            datetime = getString(typedArray, index++);
+            dateTimeOriginal = getString(typedArray, index++);
             exposureTime = typedArray.getFloat(index++, 0f);
             flash = typedArray.getFloat(index++, 0f);
             focalLength = getString(typedArray, index++);
@@ -273,7 +274,8 @@
         assertStringTag(exifInterface, ExifInterface.TAG_MAKE, expectedValue.make);
         assertStringTag(exifInterface, ExifInterface.TAG_MODEL, expectedValue.model);
         assertFloatTag(exifInterface, ExifInterface.TAG_F_NUMBER, expectedValue.aperture);
-        assertStringTag(exifInterface, ExifInterface.TAG_DATETIME, expectedValue.datetime);
+        assertStringTag(exifInterface, ExifInterface.TAG_DATETIME_ORIGINAL,
+                expectedValue.dateTimeOriginal);
         assertFloatTag(exifInterface, ExifInterface.TAG_EXPOSURE_TIME, expectedValue.exposureTime);
         assertFloatTag(exifInterface, ExifInterface.TAG_FLASH, expectedValue.flash);
         assertStringTag(exifInterface, ExifInterface.TAG_FOCAL_LENGTH, expectedValue.focalLength);
@@ -478,4 +480,34 @@
     public void testReadExifDataFromSamsungNX3000Srw() throws Throwable {
         testExifInterfaceForRaw(SAMSUNG_NX3000_SRW, R.array.samsung_nx3000_srw);
     }
+
+    public void testSetDateTime() throws IOException {
+        final String dateTimeValue = "2017:02:02 22:22:22";
+        final String dateTimeOriginalValue = "2017:01:01 11:11:11";
+
+        File srcFile = new File(Environment.getExternalStorageDirectory(),
+                EXTERNAL_BASE_DIRECTORY + EXIF_BYTE_ORDER_II_JPEG);
+        File imageFile = new File(Environment.getExternalStorageDirectory(),
+                EXTERNAL_BASE_DIRECTORY + EXIF_BYTE_ORDER_II_JPEG + "_copied");
+
+        FileUtils.copyFileOrThrow(srcFile, imageFile);
+        ExifInterface exif = new ExifInterface(imageFile.getAbsolutePath());
+        exif.setAttribute(ExifInterface.TAG_DATETIME, dateTimeValue);
+        exif.setAttribute(ExifInterface.TAG_DATETIME_ORIGINAL, dateTimeOriginalValue);
+        exif.saveAttributes();
+
+        // Check that the DATETIME value is not overwritten by DATETIME_ORIGINAL's value.
+        exif = new ExifInterface(imageFile.getAbsolutePath());
+        assertEquals(dateTimeValue, exif.getAttribute(ExifInterface.TAG_DATETIME));
+        assertEquals(dateTimeOriginalValue, exif.getAttribute(ExifInterface.TAG_DATETIME_ORIGINAL));
+
+        // Now remove the DATETIME value.
+        exif.setAttribute(ExifInterface.TAG_DATETIME, null);
+        exif.saveAttributes();
+
+        // When the DATETIME has no value, then it should be set to DATETIME_ORIGINAL's value.
+        exif = new ExifInterface(imageFile.getAbsolutePath());
+        assertEquals(dateTimeOriginalValue, exif.getAttribute(ExifInterface.TAG_DATETIME));
+        imageFile.delete();
+    }
 }
diff --git a/tests/tests/text/src/android/text/cts/InputFilter_AllCapsTest.java b/tests/tests/text/src/android/text/cts/InputFilter_AllCapsTest.java
index 9e5d293..4d14454 100644
--- a/tests/tests/text/src/android/text/cts/InputFilter_AllCapsTest.java
+++ b/tests/tests/text/src/android/text/cts/InputFilter_AllCapsTest.java
@@ -17,16 +17,24 @@
 package android.text.cts;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.text.InputFilter;
 import android.text.InputFilter.AllCaps;
+import android.text.SpannableString;
 import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.SpannedString;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Locale;
+
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class InputFilter_AllCapsTest {
@@ -41,7 +49,7 @@
 
         String expectedString1 = "AllCAPSTest";
         dest.insert(3, source);
-        assertEquals(expectedString1 , dest.toString());
+        assertEquals(expectedString1, dest.toString());
 
         String expectedString2 = "AllCAPSCAPS";
         dest.replace(7, 11, source);
@@ -58,4 +66,71 @@
             allCaps.filter(beforeFilterSource, 2, 7, dest, 0, beforeFilterSource.length());
         assertEquals(expectedAfterFilter, actualAfterFilter);
     }
+
+    @Test
+    public void testFilter_nonBMP() {
+        // The source string, lowerBee, is two code units that contains a single lowercase letter.
+        // DESERET SMALL LETTER BEE
+        final String lowerBee = new String(Character.toChars(0x1043A));
+        // DESERET CAPITAL LETTER BEE
+        final String upperBee = new String(Character.toChars(0x10412));
+
+        final AllCaps allCaps = new AllCaps();
+        final SpannedString dest = new SpannedString("");
+
+        // If given the whole string, the filter should transform it to uppercase.
+        assertEquals(upperBee, allCaps.filter(lowerBee, 0, lowerBee.length(), dest, 0, 0));
+
+        // If given just part of the character, it should be treated as an isolated surrogate
+        // and not get transformed, so null should be returned.
+        assertNull(allCaps.filter(lowerBee, 0, 1, dest, 0, 0));
+    }
+
+    @Test
+    public void testFilter_turkish() {
+        final String source = "i";
+        final AllCaps usAllCaps = new AllCaps(Locale.US);
+        final AllCaps turkishAllCaps = new AllCaps(new Locale("tr", "TR"));
+        final SpannedString dest = new SpannedString("");
+
+        assertEquals("I", usAllCaps.filter(source, 0, source.length(), dest, 0, 0));
+        assertEquals("İ", turkishAllCaps.filter(source, 0, source.length(), dest, 0, 0));
+    }
+
+    @Test
+    public void testFilter_titlecase() {
+        final String source = "Lj"; // U+01C8 LATIN CAPITAL LETTER L WITH SMALL LETTER J
+        final AllCaps allCaps = new AllCaps();
+        final SpannedString dest = new SpannedString("");
+
+        assertEquals("LJ", // LATIN CAPITAL LETTER LJ
+                allCaps.filter(source, 0, source.length(), dest, 0, 0));
+    }
+
+    @Test
+    public void testFilter_greekWithSpans() {
+        final Locale greek = new Locale("el", "GR");
+        final String lowerString = "ι\u0301ριδα";  // ίριδα with first letter decomposed
+        final String upperString = "ΙΡΙΔΑ";  // uppercased
+
+        final SpannableString source = new SpannableString(lowerString);
+        final Object span = new Object();
+        source.setSpan(span, 0, 2, Spanned.SPAN_INCLUSIVE_INCLUSIVE); // around "ί"
+
+        final AllCaps greekAllCaps = new AllCaps(greek);
+        final SpannedString dest = new SpannedString("");
+        final CharSequence result = greekAllCaps.filter(source, 0, source.length(), dest, 0, 0);
+
+        assertEquals(upperString, result.toString());
+        assertTrue(result instanceof Spanned);
+        final Spanned spannedResult = (Spanned) result;
+        final Object[] resultSpans = spannedResult.getSpans(
+                0, spannedResult.length(), Object.class);
+        assertEquals(1, resultSpans.length);
+        assertSame(span, resultSpans[0]);
+        assertEquals(0, spannedResult.getSpanStart(span));
+        // The two characters in source have been transformed to one character in the result.
+        assertEquals(1, spannedResult.getSpanEnd(span));
+        assertEquals(Spanned.SPAN_INCLUSIVE_INCLUSIVE, spannedResult.getSpanFlags(span));
+    }
 }
diff --git a/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java b/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java
index 0a7f86d..27c388a 100644
--- a/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java
@@ -1431,29 +1431,41 @@
         final Uri CHANNEL_URI_FOR_PASSTHROUGH_INPUT =
                 TvContract.buildChannelUriForPassthroughInput("inputId");
         final Uri PROGRAM_URI = TvContract.buildProgramUri(0);
+        final Uri RECORDED_PROGRAM_URI = TvContract.buildRecordedProgramUri(0);
 
         // Test isChannelUri
         assertTrue(TvContract.isChannelUri(CHANNEL_URI_FOR_TUNER));
         assertTrue(TvContract.isChannelUri(CHANNEL_URI_FOR_PASSTHROUGH_INPUT));
         assertFalse(TvContract.isChannelUri(PROGRAM_URI));
+        assertFalse(TvContract.isChannelUri(RECORDED_PROGRAM_URI));
         assertFalse(TvContract.isChannelUri(null));
 
         // Test isChannelUriForPassthroughInput
         assertFalse(TvContract.isChannelUriForPassthroughInput(CHANNEL_URI_FOR_TUNER));
         assertTrue(TvContract.isChannelUriForPassthroughInput(CHANNEL_URI_FOR_PASSTHROUGH_INPUT));
         assertFalse(TvContract.isChannelUriForPassthroughInput(PROGRAM_URI));
+        assertFalse(TvContract.isChannelUriForPassthroughInput(RECORDED_PROGRAM_URI));
         assertFalse(TvContract.isChannelUriForPassthroughInput(null));
 
         // Test isChannelUriForTunerInput
         assertTrue(TvContract.isChannelUriForTunerInput(CHANNEL_URI_FOR_TUNER));
         assertFalse(TvContract.isChannelUriForTunerInput(CHANNEL_URI_FOR_PASSTHROUGH_INPUT));
         assertFalse(TvContract.isChannelUriForTunerInput(PROGRAM_URI));
+        assertFalse(TvContract.isChannelUriForTunerInput(RECORDED_PROGRAM_URI));
         assertFalse(TvContract.isChannelUriForTunerInput(null));
 
         // Test isProgramUri
         assertFalse(TvContract.isProgramUri(CHANNEL_URI_FOR_TUNER));
         assertFalse(TvContract.isProgramUri(CHANNEL_URI_FOR_PASSTHROUGH_INPUT));
         assertTrue(TvContract.isProgramUri(PROGRAM_URI));
+        assertFalse(TvContract.isProgramUri(RECORDED_PROGRAM_URI));
         assertFalse(TvContract.isProgramUri(null));
+
+        // Test isRecordedProgramUri
+        assertFalse(TvContract.isRecordedProgramUri(CHANNEL_URI_FOR_TUNER));
+        assertFalse(TvContract.isRecordedProgramUri(CHANNEL_URI_FOR_PASSTHROUGH_INPUT));
+        assertFalse(TvContract.isRecordedProgramUri(PROGRAM_URI));
+        assertTrue(TvContract.isRecordedProgramUri(RECORDED_PROGRAM_URI));
+        assertFalse(TvContract.isRecordedProgramUri(null));
     }
 }
diff --git a/tests/tests/view/src/android/view/cts/ChoreographerNativeTest.java b/tests/tests/view/src/android/view/cts/ChoreographerNativeTest.java
index 6c95e1f..145436b 100644
--- a/tests/tests/view/src/android/view/cts/ChoreographerNativeTest.java
+++ b/tests/tests/view/src/android/view/cts/ChoreographerNativeTest.java
@@ -19,6 +19,8 @@
 import static org.junit.Assert.fail;
 
 import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.FlakyTest;
+import android.support.test.filters.MediumTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
@@ -26,7 +28,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-@SmallTest
+@FlakyTest
 @RunWith(AndroidJUnit4.class)
 public class ChoreographerNativeTest {
     private long mChoreographerPtr;
@@ -49,11 +51,13 @@
         }
     }
 
+    @MediumTest
     @Test
     public void testPostCallbackWithoutDelayEventuallyRunsCallbacks() {
         nativeTestPostCallbackWithoutDelayEventuallyRunsCallbacks(mChoreographerPtr);
     }
 
+    @SmallTest
     @Test
     public void testPostCallbackWithDelayEventuallyRunsCallbacks() {
         nativeTestPostCallbackWithDelayEventuallyRunsCallbacks(mChoreographerPtr);
diff --git a/tests/tests/webkit/src/android/webkit/cts/ServiceWorkerClientTest.java b/tests/tests/webkit/src/android/webkit/cts/ServiceWorkerClientTest.java
index 1e9f5e8..ac736cf 100644
--- a/tests/tests/webkit/src/android/webkit/cts/ServiceWorkerClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/ServiceWorkerClientTest.java
@@ -57,13 +57,22 @@
             + "    <script>\n"
             + "      navigator.serviceWorker.register('sw.js').then(function(reg) {\n"
             + "         " + JS_INTERFACE_NAME + ".registrationSuccess();\n"
-            + "      }).catch(function(err) { \n"
+            + "      }).catch(function(err) {\n"
             + "         console.error(err);\n"
             + "      });\n"
             + "    </script>\n"
             + "  </body>\n"
             + "</html>\n";
     private static final String SW_RAW_HTML = "fetch('fetch.html');";
+    private static final String SW_UNREGISTER_RAW_JS =
+            "navigator.serviceWorker.getRegistration().then(function(r) {"
+            + "  r.unregister().then(function(success) {"
+            + "    if (success) " + JS_INTERFACE_NAME + ".unregisterSuccess();"
+            + "    else console.error('unregister() was not successful');"
+            + "  });"
+            + "}).catch(function(err) {"
+            + "   console.error(err);"
+            + "});";
 
     private JavascriptStatusReceiver mJavascriptStatusReceiver;
     private WebViewOnUiThread mOnUiThread;
@@ -171,17 +180,34 @@
         assertEquals(2, requests.size());
         assertEquals(SW_URL, requests.get(0).getUrl().toString());
         assertEquals(FETCH_URL, requests.get(1).getUrl().toString());
+
+        // Clean-up, make sure to unregister the Service Worker.
+        mOnUiThread.evaluateJavascript(SW_UNREGISTER_RAW_JS, null);
+        Callable<Boolean> unregisterSuccess = new Callable<Boolean>() {
+            @Override
+            public Boolean call() {
+                return mJavascriptStatusReceiver.mUnregisterSuccess;
+            }
+        };
+        PollingCheck.check("JS could not unregister Service Worker", POLLING_TIMEOUT,
+                unregisterSuccess);
     }
 
     // Object added to the page via AddJavascriptInterface() that is used by the test Javascript to
     // notify back to Java if the Service Worker registration was successful.
     public final static class JavascriptStatusReceiver {
         public volatile boolean mRegistrationSuccess = false;
+        public volatile boolean mUnregisterSuccess = false;
 
         @JavascriptInterface
         public void registrationSuccess() {
             mRegistrationSuccess = true;
         }
+
+        @JavascriptInterface
+        public void unregisterSuccess() {
+            mUnregisterSuccess = true;
+        }
     }
 }