Merge "Add test cases for Typeface.setFallback." into oc-dev
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/peripheralprofile/ProfileManager.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/peripheralprofile/ProfileManager.java
index 1d585ac..035dc3f 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/peripheralprofile/ProfileManager.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/peripheralprofile/ProfileManager.java
@@ -56,6 +56,10 @@
               "<OutputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\" />" +
               "<InputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\" />" +
             "</PeripheralProfile>" +
+            "<PeripheralProfile ProfileName=\"AudioBox USB\" ProfileDescription=\"Presonus AudioBox USB\" ProductName=\"USB-Audio - AudioBox USB\">" +
+              "<OutputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000\" />" +
+              "<InputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000\" />" +
+            "</PeripheralProfile>" +
           "</ProfileList>";
 
     // XML Tags and Attributes
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
index 15daed9..60d5cb9 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
@@ -700,9 +700,9 @@
         Log.i(TAG, "Setting Battery Saver Mode to " + enabled);
         if (enabled) {
             turnBatteryOff();
-            executeSilentShellCommand("settings put global low_power 1");
+            executeSilentShellCommand("cmd power set-mode 1");
         } else {
-            executeSilentShellCommand("settings put global low_power 0");
+            executeSilentShellCommand("cmd power set-mode 0");
             turnBatteryOn();
         }
     }
diff --git a/tests/app/src/android/app/cts/NotificationChannelTest.java b/tests/app/src/android/app/cts/NotificationChannelTest.java
index 74047be..70ec9cf 100644
--- a/tests/app/src/android/app/cts/NotificationChannelTest.java
+++ b/tests/app/src/android/app/cts/NotificationChannelTest.java
@@ -25,6 +25,7 @@
 import android.media.AudioAttributes;
 import android.net.Uri;
 import android.os.Parcel;
+import android.provider.Settings;
 import android.test.AndroidTestCase;
 
 public class NotificationChannelTest extends AndroidTestCase {
@@ -52,7 +53,7 @@
         assertEquals(false, channel.shouldVibrate());
         assertEquals(null, channel.getVibrationPattern());
         assertEquals(IMPORTANCE_DEFAULT, channel.getImportance());
-        assertEquals(null, channel.getSound());
+        assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, channel.getSound());
         assertTrue(channel.canShowBadge());
         assertEquals(Notification.AUDIO_ATTRIBUTES_DEFAULT, channel.getAudioAttributes());
         assertEquals(null, channel.getGroup());
diff --git a/tests/tests/content/src/android/content/cts/ContentResolverTest.java b/tests/tests/content/src/android/content/cts/ContentResolverTest.java
index 0ceda3a..e5e8fe4 100644
--- a/tests/tests/content/src/android/content/cts/ContentResolverTest.java
+++ b/tests/tests/content/src/android/content/cts/ContentResolverTest.java
@@ -24,7 +24,6 @@
 import android.content.res.AssetFileDescriptor;
 import android.database.ContentObserver;
 import android.database.Cursor;
-import android.database.PageViewCursor;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.CancellationSignal;
@@ -35,6 +34,7 @@
 import android.util.Log;
 
 import com.android.compatibility.common.util.PollingCheck;
+import com.android.internal.util.ArrayUtils;
 
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
@@ -419,41 +419,10 @@
     }
 
     /**
-     * Verifies that paging arguments are handled correctly
-     * when the provider supports paging.
+     * Verifies that paging information is correctly relayed, and that
+     * honored arguments from a supporting client are returned correctly.
      */
-    public void testQuery_InProcessProvider_NoAutoPaging() {
-
-        mContentResolver.delete(TABLE1_URI, null, null);
-        ContentValues values = new ContentValues();
-
-        for (int i = 0; i < 100; i++) {
-            values.put(COLUMN_KEY_NAME, i);
-            mContentResolver.insert(TABLE1_URI, values);
-        }
-
-        Bundle queryArgs = new Bundle();
-        queryArgs.putInt(ContentResolver.QUERY_ARG_OFFSET, 10);
-        queryArgs.putInt(ContentResolver.QUERY_ARG_LIMIT, 3);
-
-        mCursor = mContentResolver.query(TABLE1_URI, null, queryArgs, null);
-        int col = mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME);
-
-        Bundle extras = mCursor.getExtras();
-        extras = extras != null ? extras : Bundle.EMPTY;
-
-        assertEquals(100, mCursor.getCount());
-        assertFalse(extras.containsKey(PageViewCursor.EXTRA_AUTO_PAGED));
-        assertFalse(extras.containsKey(ContentResolver.EXTRA_TOTAL_SIZE));
-
-        mCursor.close();
-    }
-
-    /**
-     * Verifies that paging arguments are handled correctly
-     * when the provider supports paging.
-     */
-    public void testQuery_OutOfProcessProvider_AutoPaging() {
+    public void testQuery_PagedResults() {
 
         Bundle queryArgs = new Bundle();
         queryArgs.putInt(ContentResolver.QUERY_ARG_OFFSET, 10);
@@ -461,88 +430,30 @@
         queryArgs.putInt(TestPagingContentProvider.RECORDSET_SIZE, 100);
 
         mCursor = mContentResolver.query(
-                TestPagingContentProvider.UNPAGED_DATA_URI, null, queryArgs, null);
-
-        Bundle extras = mCursor.getExtras();
-        extras = extras != null ? extras : Bundle.EMPTY;
-
-        assertEquals(3, mCursor.getCount());
-        assertTrue(extras.getBoolean(PageViewCursor.EXTRA_AUTO_PAGED));
-        assertTrue(extras.containsKey(ContentResolver.EXTRA_TOTAL_SIZE));
-        assertEquals(100, extras.getInt(ContentResolver.EXTRA_TOTAL_SIZE));
-
-        int col = mCursor.getColumnIndexOrThrow(TestPagingContentProvider.COLUMN_POS);
-
-        mCursor.moveToNext();
-        assertEquals(10, mCursor.getInt(col));
-        mCursor.moveToNext();
-        assertEquals(11, mCursor.getInt(col));
-        mCursor.moveToNext();
-        assertEquals(12, mCursor.getInt(col));
-
-        assertFalse(mCursor.moveToNext());
-
-        mCursor.close();
-    }
-
-    /**
-     * Verifies that paging arguments are handled correctly
-     * when the provider supports paging.
-     */
-    public void testQuery_OutOfProcessProvider_AutoPaging_OffsetOutOfBounds() {
-
-        Bundle queryArgs = new Bundle();
-        queryArgs.putInt(ContentResolver.QUERY_ARG_OFFSET, 10);
-        queryArgs.putInt(ContentResolver.QUERY_ARG_LIMIT, 3);
-        queryArgs.putInt(TestPagingContentProvider.RECORDSET_SIZE, 100);
-
-        mCursor = mContentResolver.query(
-                TestPagingContentProvider.UNPAGED_DATA_URI, null, queryArgs, null);
-
-        Bundle extras = mCursor.getExtras();
-        extras = extras != null ? extras : Bundle.EMPTY;
-
-        assertEquals(3, mCursor.getCount());
-        assertTrue(extras.getBoolean(PageViewCursor.EXTRA_AUTO_PAGED));
-        assertTrue(extras.containsKey(ContentResolver.EXTRA_TOTAL_SIZE));
-        assertEquals(100, extras.getInt(ContentResolver.EXTRA_TOTAL_SIZE));
-
-        int col = mCursor.getColumnIndexOrThrow(TestPagingContentProvider.COLUMN_POS);
-
-        mCursor.moveToNext();
-        assertEquals(10, mCursor.getInt(col));
-        mCursor.moveToNext();
-        assertEquals(11, mCursor.getInt(col));
-        mCursor.moveToNext();
-        assertEquals(12, mCursor.getInt(col));
-
-        assertFalse(mCursor.moveToNext());
-
-        mCursor.close();
-    }
-
-    /**
-     * Verifies that auto-paging isn't applied when the underlying remote
-     * provider has already applied paging.
-     */
-    public void testQuery_OutOfProcessProvider_NoAutoPagingForAlreadyPagedResults() {
-
-        Bundle queryArgs = new Bundle();
-        queryArgs.putInt(ContentResolver.QUERY_ARG_OFFSET, 20);
-        queryArgs.putInt(ContentResolver.QUERY_ARG_LIMIT, 2);
-        queryArgs.putInt(TestPagingContentProvider.RECORDSET_SIZE, 500);
-
-        mCursor = mContentResolver.query(
                 TestPagingContentProvider.PAGED_DATA_URI, null, queryArgs, null);
 
         Bundle extras = mCursor.getExtras();
         extras = extras != null ? extras : Bundle.EMPTY;
 
-        assertFalse(extras.getBoolean(PageViewCursor.EXTRA_AUTO_PAGED));
+        assertEquals(3, mCursor.getCount());
+        assertTrue(extras.containsKey(ContentResolver.EXTRA_TOTAL_SIZE));
+        assertEquals(100, extras.getInt(ContentResolver.EXTRA_TOTAL_SIZE));
 
-        // we don't test the contents of the self-paged cursor
-        // because that's provided by TestPagingContentProvider
-        // a test-only test support class.
+        String[] honoredArgs = extras.getStringArray(ContentResolver.EXTRA_HONORED_ARGS);
+        assertNotNull(honoredArgs);
+        assertTrue(ArrayUtils.contains(honoredArgs, ContentResolver.QUERY_ARG_OFFSET));
+        assertTrue(ArrayUtils.contains(honoredArgs, ContentResolver.QUERY_ARG_LIMIT));
+
+        int col = mCursor.getColumnIndexOrThrow(TestPagingContentProvider.COLUMN_POS);
+
+        mCursor.moveToNext();
+        assertEquals(10, mCursor.getInt(col));
+        mCursor.moveToNext();
+        assertEquals(11, mCursor.getInt(col));
+        mCursor.moveToNext();
+        assertEquals(12, mCursor.getInt(col));
+
+        assertFalse(mCursor.moveToNext());
 
         mCursor.close();
     }
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java
index 80d604e..d563102 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java
@@ -36,6 +36,7 @@
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
 import android.graphics.PorterDuff.Mode;
+import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
 import android.graphics.Shader;
 import android.graphics.cts.R;
@@ -219,6 +220,18 @@
         assertNull(shapeDrawable.getShaderFactory());
     }
 
+    @Test
+    public void testSetXfermode() {
+        ShapeDrawable shapeDrawable = new ShapeDrawable();
+
+        PorterDuffXfermode xfermode = new PorterDuffXfermode(Mode.SRC_OVER);
+        shapeDrawable.setXfermode(xfermode);
+        assertSame(xfermode, shapeDrawable.getPaint().getXfermode());
+
+        shapeDrawable.setXfermode(null);
+        assertNull(shapeDrawable.getPaint().getXfermode());
+    }
+
     public static class MockShaderFactory extends ShaderFactory {
         public Shader resize(int width, int height) {
             return null;
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index f01b833..b7f7c8e 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -109,6 +109,7 @@
             .compile("([0-9]{4})-([0-9]{2})-[0-9]{2}");
 
     private static final int KM_ERROR_INVALID_INPUT_LENGTH = -21;
+    private static final int KM_ERROR_PERMISSION_DENIED = 6;
 
     public void testVersionParser() throws Exception {
         // Non-numerics/empty give version 0
@@ -211,6 +212,29 @@
         }
     }
 
+    public void testEcAttestation_KeyStoreExceptionWhenRequestingUniqueId() throws Exception {
+        String keystoreAlias = "test_key";
+        KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN)
+                .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
+                .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512)
+                .setAttestationChallenge(new byte[128])
+                .setUniqueIdIncluded(true)
+                .build();
+
+        try {
+            generateKeyPair(KEY_ALGORITHM_EC, spec);
+            fail("Attestation should have failed.");
+        } catch (ProviderException e) {
+            // Attestation is expected to fail because of lack of permissions.
+            KeyStoreException cause = (KeyStoreException) e.getCause();
+            assertEquals(KM_ERROR_PERMISSION_DENIED, cause.getErrorCode());
+        } finally {
+            KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+            keyStore.load(null);
+            keyStore.deleteEntry(keystoreAlias);
+        }
+    }
+
     public void testRsaAttestation() throws Exception {
         int[] keySizes = { // Smallish sizes to keep test runtimes down.
                 512, 768, 1024
diff --git a/tests/tests/nativemedia/aaudio/Android.mk b/tests/tests/nativemedia/aaudio/Android.mk
index af46aee..d8cfcf3 100644
--- a/tests/tests/nativemedia/aaudio/Android.mk
+++ b/tests/tests/nativemedia/aaudio/Android.mk
@@ -27,7 +27,8 @@
     frameworks/av/media/libaaudio/include
 
 LOCAL_SRC_FILES := \
-    src/test_aaudio.cpp
+    src/test_aaudio.cpp \
+    src/test_aaudio_callback.cpp
 
 LOCAL_SHARED_LIBRARIES := \
     libaaudio \
diff --git a/tests/tests/nativemedia/aaudio/src/test_aaudio.cpp b/tests/tests/nativemedia/aaudio/src/test_aaudio.cpp
index 77c91e4..4072fce 100644
--- a/tests/tests/nativemedia/aaudio/src/test_aaudio.cpp
+++ b/tests/tests/nativemedia/aaudio/src/test_aaudio.cpp
@@ -21,17 +21,9 @@
 #include <utils/Log.h>
 
 #include <aaudio/AAudio.h>
-#include <aaudio/AAudioDefinitions.h>
+#include "test_aaudio.h"
 
-
-#define NANOS_PER_MICROSECOND ((int64_t)1000)
-#define NANOS_PER_MILLISECOND (NANOS_PER_MICROSECOND * 1000)
-#define MILLIS_PER_SECOND     1000
-#define NANOS_PER_SECOND      (NANOS_PER_MILLISECOND * MILLIS_PER_SECOND)
-
-#define DEFAULT_STATE_TIMEOUT  (500 * NANOS_PER_MILLISECOND)
-
-static int64_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC) {
+int64_t getNanoseconds(clockid_t clockId) {
     struct timespec time;
     int result = clock_gettime(clockId, &time);
     if (result < 0) {
@@ -136,10 +128,12 @@
 
     // Check to see what kind of stream we actually got.
     actualSampleRate = AAudioStream_getSampleRate(aaudioStream);
-    ASSERT_TRUE(actualSampleRate >= 44100 && actualSampleRate <= 96000);  // TODO what is range?
+    ASSERT_GE(actualSampleRate, 44100);
+    ASSERT_LE(actualSampleRate, 96000); // TODO what is min/max?
 
     actualSamplesPerFrame = AAudioStream_getSamplesPerFrame(aaudioStream);
-    ASSERT_TRUE(actualSamplesPerFrame >= 1 && actualSamplesPerFrame <= 16); // TODO what is max?
+    ASSERT_GE(actualSamplesPerFrame, 1);
+    ASSERT_LE(actualSamplesPerFrame, 16); // TODO what is min/max?
 
     actualSharingMode = AAudioStream_getSharingMode(aaudioStream);
     ASSERT_TRUE(actualSharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE
@@ -151,7 +145,8 @@
     // ASSERT_NE(AAUDIO_DEVICE_UNSPECIFIED, AAudioStream_getDeviceId(aaudioStream));
 
     framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream);
-    ASSERT_TRUE(framesPerBurst >= 16 && framesPerBurst <= 1024); // TODO what is min/max?
+    ASSERT_GE(framesPerBurst, 16);
+    ASSERT_LE(framesPerBurst, 4096); // TODO what is min/max?
 
     // Allocate a buffer for the audio data.
     // TODO handle possibility of other data formats
@@ -270,10 +265,13 @@
     aaudioFramesRead = AAudioStream_getFramesRead(aaudioStream);
     EXPECT_EQ(aaudioFramesRead, aaudioFramesWritten);
 
+    sleep(1); // FIXME - The write returns 0 if we remove this sleep! Why?
+
     // The buffer should be empty after a flush so we should be able to write.
     framesWritten = AAudioStream_write(aaudioStream, data, framesPerBurst, timeoutNanos);
     // There should be some room for priming the buffer.
-    ASSERT_TRUE(framesWritten > 0 && framesWritten <= framesPerBurst);
+    ASSERT_GT(framesWritten, 0);
+    ASSERT_LE(framesWritten, framesPerBurst);
 
     EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream));
     free(data);
@@ -291,60 +289,6 @@
 }
 */
 
-#define AAUDIO_THREAD_ANSWER          1826375
-#define AAUDIO_THREAD_DURATION_MSEC       500
-
-static void *TestAAudioStreamThreadProc(void *arg) {
-    AAudioStream* aaudioStream = (AAudioStream*) reinterpret_cast<size_t>(arg);
-    aaudio_stream_state_t state;
-
-    // Use this to sleep by waiting for something that won't happen.
-    state = AAudioStream_getState(aaudioStream);
-    AAudioStream_waitForStateChange(aaudioStream, AAUDIO_STREAM_STATE_PAUSED, &state,
-            AAUDIO_THREAD_DURATION_MSEC * NANOS_PER_MILLISECOND);
-    return reinterpret_cast<void *>(AAUDIO_THREAD_ANSWER);
-}
-
-// Test creating a stream related thread.
-TEST(test_aaudio, aaudio_stream_thread_basic) {
-    AAudioStreamBuilder *aaudioBuilder = nullptr;
-    AAudioStream *aaudioStream = nullptr;
-    aaudio_result_t result = AAUDIO_OK;
-    void *threadResult;
-
-    // Use an AAudioStreamBuilder to define the stream.
-    result = AAudio_createStreamBuilder(&aaudioBuilder);
-    ASSERT_EQ(AAUDIO_OK, result);
-
-    // Create an AAudioStream using the Builder.
-    ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream));
-
-    // Start a thread.
-    ASSERT_EQ(AAUDIO_OK, AAudioStream_createThread(aaudioStream,
-            10 * NANOS_PER_MILLISECOND,
-            TestAAudioStreamThreadProc,
-            reinterpret_cast<void *>(aaudioStream)));
-    // Thread already started.
-    ASSERT_NE(AAUDIO_OK, AAudioStream_createThread(aaudioStream,   // should fail!
-            10 * NANOS_PER_MILLISECOND,
-            TestAAudioStreamThreadProc,
-            reinterpret_cast<void *>(aaudioStream)));
-
-    // Wait for the thread to finish.
-    ASSERT_EQ(AAUDIO_OK, AAudioStream_joinThread(aaudioStream,
-            &threadResult, 2 * AAUDIO_THREAD_DURATION_MSEC * NANOS_PER_MILLISECOND));
-    // The thread returns a special answer.
-    ASSERT_EQ(AAUDIO_THREAD_ANSWER, (int)reinterpret_cast<size_t>(threadResult));
-
-    // Thread should already be joined.
-    ASSERT_NE(AAUDIO_OK, AAudioStream_joinThread(aaudioStream,  // should fail!
-            &threadResult, 2 * AAUDIO_THREAD_DURATION_MSEC * NANOS_PER_MILLISECOND));
-
-    // Cleanup
-    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_delete(aaudioBuilder));
-    EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream));
-}
-
 int main(int argc, char **argv) {
     testing::InitGoogleTest(&argc, argv);
 
diff --git a/tests/tests/nativemedia/aaudio/src/test_aaudio.h b/tests/tests/nativemedia/aaudio/src/test_aaudio.h
new file mode 100644
index 0000000..dbb111d
--- /dev/null
+++ b/tests/tests/nativemedia/aaudio/src/test_aaudio.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef CTS_MEDIA_TEST_AAUDIO_H
+#define CTS_MEDIA_TEST_AAUDIO_H
+
+#define NANOS_PER_MICROSECOND ((int64_t)1000)
+#define NANOS_PER_MILLISECOND (NANOS_PER_MICROSECOND * 1000)
+#define MILLIS_PER_SECOND     1000
+#define NANOS_PER_SECOND      (NANOS_PER_MILLISECOND * MILLIS_PER_SECOND)
+
+#define DEFAULT_STATE_TIMEOUT  (500 * NANOS_PER_MILLISECOND)
+
+int64_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC);
+
+#endif //CTS_MEDIA_TEST_AAUDIO_H
diff --git a/tests/tests/nativemedia/aaudio/src/test_aaudio_callback.cpp b/tests/tests/nativemedia/aaudio/src/test_aaudio_callback.cpp
new file mode 100644
index 0000000..2ec1e1c
--- /dev/null
+++ b/tests/tests/nativemedia/aaudio/src/test_aaudio_callback.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright 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.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "AAudioTest"
+
+#include <gtest/gtest.h>
+#include <utils/Log.h>
+
+#include <aaudio/AAudio.h>
+#include "test_aaudio.h"
+
+typedef struct AAudioCallbackTestData {
+    int32_t callbackCount;
+    int32_t expectedFramesPerCallback;
+    int32_t actualFramesPerCallback;
+} AAudioCallbackTestData;
+
+// Callback function that fills the audio output buffer.
+static aaudio_data_callback_result_t MyDataCallbackProc(
+        AAudioStream *stream,
+        void *userData,
+        void *audioData,
+        int32_t numFrames
+) {
+    AAudioCallbackTestData *myData = (AAudioCallbackTestData *) userData;
+
+    if (numFrames != myData->expectedFramesPerCallback) {
+        // record unexpected framecounts
+        myData->actualFramesPerCallback = numFrames;
+    } else if (myData->actualFramesPerCallback == 0) {
+        // record at least one frame count
+        myData->actualFramesPerCallback = numFrames;
+    }
+    int32_t samplesPerFrame = AAudioStream_getSamplesPerFrame(stream);
+    int32_t numSamples = samplesPerFrame * numFrames;
+    if (AAudioStream_getFormat(stream) == AAUDIO_FORMAT_PCM_I16) {
+        int16_t *shortData = (int16_t *) audioData;
+        for (int i = 0; i < numSamples; i++) *shortData++ = 0;
+    } else if (AAudioStream_getFormat(stream) == AAUDIO_FORMAT_PCM_FLOAT) {
+        float *floatData = (float *) audioData;
+        for (int i = 0; i < numSamples; i++) *floatData++ = 0.0f;
+    }
+    myData->callbackCount++;
+    return AAUDIO_CALLBACK_RESULT_CONTINUE;
+}
+
+// Test Writing to an AAudioStream using a Callback
+void runtest_aaudio_callback(aaudio_sharing_mode_t requestedSharingMode,
+                             int32_t framesPerDataCallback) {
+    AAudioCallbackTestData myTestData = { 0, 0, 0 };
+    const int32_t requestedSampleRate = 48000;
+    const int32_t requestedSamplesPerFrame = 2;
+    const aaudio_audio_format_t requestedDataFormat = AAUDIO_FORMAT_PCM_I16;
+
+    int32_t actualSampleRate = -1;
+    int32_t actualSamplesPerFrame = -1;
+    aaudio_audio_format_t actualDataFormat = AAUDIO_FORMAT_INVALID;
+    aaudio_sharing_mode_t actualSharingMode;
+    int32_t framesPerBurst = -1;
+    int32_t actualBufferSize = 0;
+    int32_t actualFramesPerDataCallback = 0;
+
+    aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNINITIALIZED;
+    AAudioStreamBuilder *builder = nullptr;
+    AAudioStream *stream = nullptr;
+
+    aaudio_result_t result = AAUDIO_OK;
+
+    // Use an AAudioStreamBuilder to define the stream.
+    result = AAudio_createStreamBuilder(&builder);
+    ASSERT_EQ(AAUDIO_OK, result);
+
+    // Request stream properties.
+    AAudioStreamBuilder_setDeviceId(builder, AAUDIO_DEVICE_UNSPECIFIED);
+    AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_OUTPUT);
+    AAudioStreamBuilder_setSampleRate(builder, requestedSampleRate);
+    AAudioStreamBuilder_setSamplesPerFrame(builder, requestedSamplesPerFrame);
+    AAudioStreamBuilder_setFormat(builder, requestedDataFormat);
+    AAudioStreamBuilder_setSharingMode(builder, requestedSharingMode);
+    AAudioStreamBuilder_setBufferCapacityInFrames(builder, 2000);
+
+    AAudioStreamBuilder_setDataCallback(builder, MyDataCallbackProc, &myTestData);
+    if (framesPerDataCallback != AAUDIO_UNSPECIFIED) {
+        AAudioStreamBuilder_setFramesPerDataCallback(builder, framesPerDataCallback);
+    }
+
+    // Create an AAudioStream using the Builder.
+    ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(builder, &stream));
+    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_delete(builder));
+
+    EXPECT_EQ(AAUDIO_STREAM_STATE_OPEN, AAudioStream_getState(stream));
+    EXPECT_EQ(AAUDIO_DIRECTION_OUTPUT, AAudioStream_getDirection(stream));
+
+    // Check to see what kind of stream we actually got.
+    actualSampleRate = AAudioStream_getSampleRate(stream);
+    ASSERT_TRUE(actualSampleRate >= 44100 && actualSampleRate <= 96000);  // TODO what is range?
+
+    actualSamplesPerFrame = AAudioStream_getSamplesPerFrame(stream);
+    ASSERT_TRUE(actualSamplesPerFrame >= 1 && actualSamplesPerFrame <= 16); // TODO what is max?
+
+    actualSharingMode = AAudioStream_getSharingMode(stream);
+    ASSERT_TRUE(actualSharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE
+                || actualSharingMode == AAUDIO_SHARING_MODE_SHARED);
+
+    actualDataFormat = AAudioStream_getFormat(stream);
+
+    // TODO test this on full build
+    // ASSERT_NE(AAUDIO_DEVICE_UNSPECIFIED, AAudioStream_getDeviceId(stream));
+
+    framesPerBurst = AAudioStream_getFramesPerBurst(stream);
+    ASSERT_TRUE(framesPerBurst >= 16 && framesPerBurst <= 1024); // TODO what is min/max?
+
+    actualFramesPerDataCallback = AAudioStream_getFramesPerDataCallback(stream);
+    if (framesPerDataCallback != AAUDIO_UNSPECIFIED) {
+        ASSERT_EQ(framesPerDataCallback, actualFramesPerDataCallback);
+    }
+
+    actualBufferSize = AAudioStream_getBufferSizeInFrames(stream);
+    actualBufferSize = AAudioStream_setBufferSizeInFrames(stream, actualBufferSize);
+    ASSERT_TRUE(actualBufferSize > 0);
+
+    // Start/stop more than once to see if it fails after the first time.
+    // Write some data and measure the rate to see if the timing is OK.
+    for (int loopIndex = 0; loopIndex < 2; loopIndex++) {
+        myTestData.callbackCount = 0;
+        myTestData.expectedFramesPerCallback = actualFramesPerDataCallback;
+
+        // Start and wait for server to respond.
+        ASSERT_EQ(AAUDIO_OK, AAudioStream_requestStart(stream));
+        ASSERT_EQ(AAUDIO_OK, AAudioStream_waitForStateChange(stream,
+                                                             AAUDIO_STREAM_STATE_STARTING,
+                                                             &state,
+                                                             DEFAULT_STATE_TIMEOUT));
+        EXPECT_EQ(AAUDIO_STREAM_STATE_STARTED, state);
+
+        sleep(2);
+
+        // For more coverage, alternate pausing and stopping.
+        if ((loopIndex & 1) == 0) {
+            // Request async pause and wait for server to say that it has completed the request.
+            ASSERT_EQ(AAUDIO_OK, AAudioStream_requestPause(stream));
+            EXPECT_EQ(AAUDIO_OK, AAudioStream_waitForStateChange(stream,
+                                                                 AAUDIO_STREAM_STATE_PAUSING,
+                                                                 &state,
+                                                                 DEFAULT_STATE_TIMEOUT));
+            EXPECT_EQ(AAUDIO_STREAM_STATE_PAUSED, state);
+        } else {
+            // Request async stop and wait for server to say that it has completed the request.
+            ASSERT_EQ(AAUDIO_OK, AAudioStream_requestStop(stream));
+            EXPECT_EQ(AAUDIO_OK, AAudioStream_waitForStateChange(stream,
+                                                                 AAUDIO_STREAM_STATE_STOPPING,
+                                                                 &state,
+                                                                 DEFAULT_STATE_TIMEOUT));
+            EXPECT_EQ(AAUDIO_STREAM_STATE_STOPPED, state);
+        }
+
+        int32_t oldCallbackCount = myTestData.callbackCount;
+        EXPECT_GT(oldCallbackCount, 10);
+        sleep(1);
+        EXPECT_EQ(oldCallbackCount, myTestData.callbackCount); // expect not advancing
+
+        if (framesPerDataCallback != AAUDIO_UNSPECIFIED) {
+            ASSERT_EQ(framesPerDataCallback, myTestData.actualFramesPerCallback);
+        }
+    }
+
+    EXPECT_EQ(AAUDIO_OK, AAudioStream_close(stream));
+}
+
+// Test Using an AAudioStream callback in SHARED mode.
+
+TEST(test_aaudio, aaudio_callback_shared_unspecified) {
+runtest_aaudio_callback(AAUDIO_SHARING_MODE_SHARED, AAUDIO_UNSPECIFIED);
+}
+
+TEST(test_aaudio, aaudio_callback_shared_109) {
+runtest_aaudio_callback(AAUDIO_SHARING_MODE_SHARED, 109); // arbitrary prime number < 192
+}
+
+TEST(test_aaudio, aaudio_callback_shared_223) {
+runtest_aaudio_callback(AAUDIO_SHARING_MODE_SHARED, 223); // arbitrary prime number > 192
+}
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index 4ff3e5e..e66640a 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -4546,7 +4546,7 @@
                 | InputType.TYPE_NUMBER_FLAG_DECIMAL
                 | InputType.TYPE_NUMBER_FLAG_SIGNED, mTextView.getInputType());
         assertSame(mTextView.getKeyListener(),
-                DigitsKeyListener.getInstance(mTextView.getTextLocale(), true, true));
+                DigitsKeyListener.getInstance(null, true, true));
 
         mTextView.setInputType(InputType.TYPE_CLASS_PHONE);
         assertEquals(InputType.TYPE_CLASS_PHONE, mTextView.getInputType());
@@ -4762,6 +4762,59 @@
 
     @UiThreadTest
     @Test
+    public void testSetImeHintLocalesChangesInputType() {
+        final TextView textView = new TextView(mActivity);
+        textView.setText("", BufferType.EDITABLE);
+
+        textView.setInputType(InputType.TYPE_CLASS_NUMBER);
+        assertEquals(InputType.TYPE_CLASS_NUMBER, textView.getInputType());
+
+        final LocaleList localeList = LocaleList.forLanguageTags("fa-IR");
+        textView.setImeHintLocales(localeList);
+        final int textType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
+        // Setting IME hint locales to Persian must change the input type to a full text IME,
+        // since the typical number input IME may not have localized digits.
+        assertEquals(textType, textView.getInputType());
+
+        // Changing the input type to datetime should keep the full text IME, since the IME hint
+        // is still set to Persian, which needs advanced input.
+        final int dateType = InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_DATE;
+        textView.setInputType(dateType);
+        assertEquals(textType, textView.getInputType());
+
+        // Changing the input type to number password should keep the full text IME, since the IME
+        // hint is still set to Persian, which needs advanced input. But it also needs to set the
+        // text password flag.
+        final int numberPasswordType = InputType.TYPE_CLASS_NUMBER
+                | InputType.TYPE_NUMBER_VARIATION_PASSWORD;
+        final int textPasswordType = InputType.TYPE_CLASS_TEXT
+                | InputType.TYPE_TEXT_VARIATION_PASSWORD;
+        textView.setInputType(numberPasswordType);
+        assertEquals(textPasswordType, textView.getInputType());
+
+        // Setting the IME hint locales to null should reset the type to number password, since we
+        // no longer need internationalized input.
+        textView.setImeHintLocales(null);
+        assertEquals(numberPasswordType, textView.getInputType());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testSetImeHintLocalesDoesntLoseInputType() {
+        final TextView textView = new TextView(mActivity);
+        textView.setText("", BufferType.EDITABLE);
+        final int inputType = InputType.TYPE_CLASS_TEXT
+                | InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT
+                | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS
+                | InputType.TYPE_TEXT_FLAG_MULTI_LINE
+                | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
+        textView.setInputType(inputType);
+        textView.setImeHintLocales(new LocaleList(Locale.US));
+        assertEquals(inputType, textView.getInputType());
+    }
+
+    @UiThreadTest
+    @Test
     public void testSetExtractedText() {
         mTextView = findTextView(R.id.textview_text);
         assertEquals(mActivity.getResources().getString(R.string.text_view_hello),