Merge "Add CTS tests for default dialer permissions" into mnc-dev
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index 8386124..4e1e008 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -67,6 +67,7 @@
 cts_support_packages := \
     CtsAccelerationTestStubs \
     CtsAppTestStubs \
+    CtsAtraceTestApp \
     CtsCertInstallerApp \
     CtsDeviceAdmin \
     CtsDeviceOpenGl \
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 6c515fd..98e8acd 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -1495,6 +1495,18 @@
             -->
         </activity>
 
+        <activity android:name=".audio.AudioRoutingNotificationsActivity"
+                  android:label="@string/audio_routingnotifications_test">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_audio" />
+            <!--
+            <meta-data android:name="test_required_features" android:value="android.hardware.microphone" />
+            -->
+        </activity>
+
         <service android:name=".tv.MockTvInputService"
             android:permission="android.permission.BIND_TV_INPUT">
             <intent-filter>
diff --git a/apps/CtsVerifier/res/layout/audio_routingnotifications_test.xml b/apps/CtsVerifier/res/layout/audio_routingnotifications_test.xml
new file mode 100644
index 0000000..cef30d6
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/audio_routingnotifications_test.xml
@@ -0,0 +1,99 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:padding="10dip"
+        android:orientation="vertical">
+
+  <TextView
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:scrollbars="vertical"
+      android:gravity="bottom"
+      android:id="@+id/info_text"
+      android:text="@string/audio_dev_routingnotification_instructions" />
+
+  <LinearLayout
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:orientation="vertical"
+      android:id="@+id/audioTrackRoutingLayout">
+      <TextView
+          android:layout_width="match_parent"
+          android:layout_height="wrap_content"
+              android:text="@string/audio_routingnotification_playHeader"/>
+
+      <TextView
+          android:layout_width="match_parent"
+          android:layout_height="wrap_content"
+          android:id="@+id/audio_routingnotification_audioTrack_change"/>
+
+      <LinearLayout
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:orientation="horizontal">
+          <Button
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:id="@+id/audio_routingnotification_playBtn"
+              android:text="@string/audio_routingnotification_playBtn"/>
+
+          <Button
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:id="@+id/audio_routingnotification_playStopBtn"
+              android:text="@string/audio_routingnotification_playStopBtn"/>
+      </LinearLayout>
+    </LinearLayout>
+
+  <LinearLayout
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:orientation="vertical"
+      android:id="@+id/audioRecordRoutingLayout">
+      <TextView
+          android:layout_width="match_parent"
+          android:layout_height="wrap_content"
+              android:text="@string/audio_routingnotification_recHeader"/>
+
+      <TextView
+          android:layout_width="match_parent"
+          android:layout_height="wrap_content"
+          android:id="@+id/audio_routingnotification_audioRecord_change"/>
+
+      <LinearLayout
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:orientation="horizontal">
+          <Button
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:id="@+id/audio_routingnotification_recordBtn"
+              android:text="@string/audio_routingnotification_recBtn"/>
+
+          <Button
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:id="@+id/audio_routingnotification_recordStopBtn"
+              android:text="@string/audio_routingnotification_recStopBtn"/>
+      </LinearLayout>
+    </LinearLayout>
+
+  <include layout="@layout/pass_fail_buttons" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 1ccd6b7..d22f5ec 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -1615,4 +1615,23 @@
     <string name="audio_dev_notification_clearmsgs">Clear Messages</string>
     <string name="audio_dev_notification_connectMsg">CONNECT DETECTED</string>
     <string name="audio_dev_notification_disconnectMsg">DISCONNECT DETECTED</string>
+
+    <!--  Audio Routing Notifcations Test -->
+    <string name="audio_routingnotifications_test">Audio Routing Notifications Test</string>
+    <string name="audio_dev_routingnotification_instructions">
+          Click on the "Play" button in the AudioTrack Routing Notifictions section below to
+          start (silent) playback. Insert a wired headset. Observe a message acknowledging the
+          rerouting event below. Remove the wired headset and observe the new routing message.
+          Click on the "Stop" button to stop playback.\n
+          Repeat the process with "Record" and "Stop" button in the AudioRecord Routing
+          Notifications section below.
+    </string>
+    <string name="audio_routingnotification_playBtn">Play</string>
+    <string name="audio_routingnotification_playStopBtn">Stop</string>
+    <string name="audio_routingnotification_recBtn">Record</string>
+    <string name="audio_routingnotification_recStopBtn">Stop</string>
+    <string name="audio_routingnotification_playHeader">AudioTrack Routing Notifications</string>
+    <string name="audio_routingnotification_recHeader">AudioRecord Routing Notifications</string>
+    <string name="audio_routingnotification_trackRoutingMsg">AudioTrack rerouting</string>
+    <string name="audio_routingnotification_recordRoutingMsg">AudioRecord rerouting</string>
 </resources>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioRoutingNotificationsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioRoutingNotificationsActivity.java
new file mode 100644
index 0000000..b6a4255
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioRoutingNotificationsActivity.java
@@ -0,0 +1,146 @@
+/*
+ * 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.cts.verifier.audio;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import android.content.Context;
+
+import android.media.AudioDeviceCallback;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
+import android.media.AudioRecord;
+import android.media.AudioTrack;
+
+import android.os.Bundle;
+import android.os.Handler;
+
+import android.util.Log;
+
+import android.view.View;
+import android.view.View.OnClickListener;
+
+import android.widget.Button;
+import android.widget.TextView;
+
+/**
+ * Tests AudioTrack and AudioRecord (re)Routing messages.
+ */
+public class AudioRoutingNotificationsActivity extends PassFailButtons.Activity {
+    private static final String TAG = "AudioRoutingNotificationsActivity";
+
+    Context mContext;
+
+    OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
+
+    int mNumTrackNotifications = 0;
+    int mNumRecordNotifications = 0;
+
+    TrivialPlayer mAudioPlayer = new TrivialPlayer();
+    TrivialRecorder mAudioRecorder = new TrivialRecorder();
+
+    private class OnBtnClickListener implements OnClickListener {
+        @Override
+        public void onClick(View v) {
+            switch (v.getId()) {
+                case R.id.audio_routingnotification_playBtn:
+                    Log.i(TAG, "audio_routingnotification_playBtn");
+                    mAudioPlayer.start();
+                    break;
+
+                case R.id.audio_routingnotification_playStopBtn:
+                    Log.i(TAG, "audio_routingnotification_playStopBtn");
+                    mAudioPlayer.stop();
+                    break;
+
+                case R.id.audio_routingnotification_recordBtn:
+                    break;
+
+                case R.id.audio_routingnotification_recordStopBtn:
+                    break;
+            }
+        }
+    }
+
+    private class AudioTrackRoutingChangeListener implements AudioTrack.OnRoutingChangedListener {
+        public void onRoutingChanged(AudioTrack audioTrack) {
+            mNumTrackNotifications++;
+            TextView textView =
+                (TextView)findViewById(R.id.audio_routingnotification_audioTrack_change);
+            String msg = mContext.getResources().getString(
+                    R.string.audio_routingnotification_trackRoutingMsg);
+            AudioDeviceInfo routedDevice = audioTrack.getRoutedDevice();
+            CharSequence deviceName = routedDevice != null ? routedDevice.getProductName() : "none";
+            int deviceType = routedDevice != null ? routedDevice.getType() : -1;
+            textView.setText(msg + " - " +
+                             deviceName + " [0x" + Integer.toHexString(deviceType) + "]" +
+                             " - " + mNumTrackNotifications);
+        }
+    }
+
+    private class AudioRecordRoutingChangeListener implements AudioRecord.OnRoutingChangedListener {
+        public void onRoutingChanged(AudioRecord audioRecord) {
+            mNumRecordNotifications++;
+            TextView textView =
+                    (TextView)findViewById(R.id.audio_routingnotification_audioRecord_change);
+            String msg = mContext.getResources().getString(
+                    R.string.audio_routingnotification_recordRoutingMsg);
+            AudioDeviceInfo routedDevice = audioRecord.getRoutedDevice();
+            CharSequence deviceName = routedDevice != null ? routedDevice.getProductName() : "none";
+            int deviceType = routedDevice != null ? routedDevice.getType() : -1;
+            textView.setText(msg + " - " +
+                             deviceName + " [0x" + Integer.toHexString(deviceType) + "]" +
+                             " - " + mNumRecordNotifications);
+        }
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.audio_routingnotifications_test);
+
+        Button btn;
+        btn = (Button)findViewById(R.id.audio_routingnotification_playBtn);
+        btn.setOnClickListener(mBtnClickListener);
+        btn = (Button)findViewById(R.id.audio_routingnotification_playStopBtn);
+        btn.setOnClickListener(mBtnClickListener);
+        btn = (Button)findViewById(R.id.audio_routingnotification_recordBtn);
+        btn.setOnClickListener(mBtnClickListener);
+        btn = (Button)findViewById(R.id.audio_routingnotification_recordStopBtn);
+        btn.setOnClickListener(mBtnClickListener);
+
+        mContext = this;
+
+        AudioTrack audioTrack = mAudioPlayer.getAudioTrack();
+        audioTrack.addOnRoutingChangedListener(
+            new AudioTrackRoutingChangeListener(), new Handler());
+
+        AudioRecord audioRecord = mAudioRecorder.getAudioRecord();
+        audioRecord.addOnRoutingChangedListener(
+            new AudioRecordRoutingChangeListener(), new Handler());
+
+        setPassFailButtonClickListeners();
+    }
+
+    @Override
+    public void onBackPressed () {
+        mAudioPlayer.shutDown();
+        mAudioRecorder.shutDown();
+        super.onBackPressed();
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/TrivialPlayer.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/TrivialPlayer.java
new file mode 100644
index 0000000..af09504
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/TrivialPlayer.java
@@ -0,0 +1,111 @@
+/*
+ * 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.cts.verifier.audio;
+
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioTrack;
+
+import java.lang.InterruptedException;
+import java.lang.Math;
+import java.lang.Runnable;
+
+public class TrivialPlayer implements Runnable {
+    AudioTrack mAudioTrack;
+    int mBufferSize;
+
+    boolean mPlay;
+    boolean mIsPlaying;
+
+    short[] mAudioData;
+
+    Thread mFillerThread = null;
+
+    public TrivialPlayer() {
+        mBufferSize =
+                AudioTrack.getMinBufferSize(
+                    41000,
+                    AudioFormat.CHANNEL_OUT_STEREO,
+                    AudioFormat.ENCODING_PCM_16BIT);
+        mAudioTrack =
+            new AudioTrack(
+                AudioManager.STREAM_MUSIC,
+                41000,
+                AudioFormat.CHANNEL_OUT_STEREO,
+                AudioFormat.ENCODING_PCM_16BIT,
+                mBufferSize,
+                AudioTrack.MODE_STREAM);
+
+        mPlay = false;
+        mIsPlaying = false;
+
+        // setup audio data (silence will suffice)
+        mAudioData = new short[mBufferSize];
+        for (int index = 0; index < mBufferSize; index++) {
+            // mAudioData[index] = 0;
+            // keep this code since one might want to hear the playnig audio
+            // for debugging/verification.
+            mAudioData[index] =
+                (short)(((Math.random() * 2.0) - 1.0) * (double)Short.MAX_VALUE/2.0);
+        }
+    }
+
+    public AudioTrack getAudioTrack() { return mAudioTrack; }
+
+    public boolean isPlaying() {
+        synchronized (this) {
+            return mIsPlaying;
+        }
+    }
+
+    public void start() {
+        mPlay = true;
+        mFillerThread = new Thread(this);
+        mFillerThread.start();
+    }
+
+    public void stop() {
+        mPlay = false;
+        mFillerThread = null;
+    }
+
+    public void shutDown() {
+        stop();
+        while (isPlaying()) {
+            try {
+                Thread.sleep(10);
+            } catch (InterruptedException ex) {
+            }
+        }
+        mAudioTrack.release();
+    }
+
+    @Override
+    public void run() {
+        mAudioTrack.play();
+        synchronized (this) {
+            mIsPlaying = true;
+        }
+        while (mAudioTrack != null && mPlay) {
+            mAudioTrack.write(mAudioData, 0, mBufferSize);
+        }
+        synchronized (this) {
+            mIsPlaying = false;
+        }
+        mAudioTrack.stop();
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/TrivialRecorder.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/TrivialRecorder.java
new file mode 100644
index 0000000..f684681
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/TrivialRecorder.java
@@ -0,0 +1,104 @@
+/*
+ * 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.cts.verifier.audio;
+
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioRecord;
+
+import android.media.MediaRecorder;
+
+import java.lang.InterruptedException;
+import java.lang.Runnable;
+
+public class TrivialRecorder implements Runnable {
+    AudioRecord mAudioRecord;
+    int mBufferSize;
+
+    boolean mRecord;
+    boolean mIsRecording;
+
+    short[] mAudioData;
+
+    Thread mReaderThread = null;
+
+    public TrivialRecorder() {
+        mBufferSize =
+                AudioRecord.getMinBufferSize(
+                    41000,
+                    AudioFormat.CHANNEL_IN_MONO,
+                    AudioFormat.ENCODING_PCM_16BIT);
+        mAudioRecord =
+            new AudioRecord(
+                MediaRecorder.AudioSource.DEFAULT,
+                41000,
+                AudioFormat.CHANNEL_IN_MONO,
+                AudioFormat.ENCODING_PCM_16BIT,
+                mBufferSize);
+
+        mRecord = false;
+        mIsRecording = false;
+
+        // setup audio data (silence will suffice)
+        mAudioData = new short[mBufferSize];
+    }
+
+    public AudioRecord getAudioRecord() { return mAudioRecord; }
+
+    public boolean mIsRecording() {
+        synchronized (this) {
+            return mIsRecording;
+        }
+    }
+
+    public void start() {
+        mRecord = true;
+        mReaderThread = new Thread(this);
+        mReaderThread.start();
+    }
+
+    public void stop() {
+        mRecord = false;
+        mReaderThread = null;
+    }
+
+    public void shutDown() {
+        stop();
+        while (mIsRecording()) {
+            try {
+                Thread.sleep(10);
+            } catch (InterruptedException ex) {
+            }
+        }
+        mAudioRecord.release();
+    }
+
+    @Override
+    public void run() {
+        mAudioRecord.startRecording();
+        synchronized (this) {
+            mIsRecording = true;
+        }
+       while (mRecord) {
+            mAudioRecord.read(mAudioData, 0, mBufferSize);
+        }
+        mAudioRecord.stop();
+        synchronized (this) {
+            mIsRecording = false;
+        }
+    }
+}
diff --git a/hostsidetests/atrace/AtraceTestApp/Android.mk b/hostsidetests/atrace/AtraceTestApp/Android.mk
new file mode 100644
index 0000000..0eb7cfd
--- /dev/null
+++ b/hostsidetests/atrace/AtraceTestApp/Android.mk
@@ -0,0 +1,33 @@
+# Copyright (C) 2009 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
+LOCAL_PACKAGE_NAME := CtsAtraceTestApp
+
+# sign this app with a different cert than CtsSimpleAppInstallDiffCert
+#LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
+
+#LOCAL_DEX_PREOPT := false
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/atrace/AtraceTestApp/AndroidManifest.xml b/hostsidetests/atrace/AtraceTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..a86f7f0
--- /dev/null
+++ b/hostsidetests/atrace/AtraceTestApp/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+       package="com.android.cts.atracetestapp">
+    <!--
+    A simple app with a tracing section to test that apps tracing signals are
+    emitted by atrace.
+    -->
+    <application>
+        <activity android:name=".AtraceTestAppActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/hostsidetests/atrace/AtraceTestApp/src/com/android/cts/atracetestapp/AtraceTestAppActivity.java b/hostsidetests/atrace/AtraceTestApp/src/com/android/cts/atracetestapp/AtraceTestAppActivity.java
new file mode 100644
index 0000000..0269d0d
--- /dev/null
+++ b/hostsidetests/atrace/AtraceTestApp/src/com/android/cts/atracetestapp/AtraceTestAppActivity.java
@@ -0,0 +1,29 @@
+/*
+ * 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.cts.atracetestapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Trace;
+
+public class AtraceTestAppActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        Trace.beginSection("traceable-app-test-section");
+        super.onCreate(savedInstanceState);
+        Trace.endSection();
+    }
+}
diff --git a/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java b/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
index f7af31c..ee0511d 100644
--- a/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
+++ b/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
@@ -16,27 +16,40 @@
 
 package android.atrace.cts;
 
+import com.android.cts.tradefed.build.CtsBuildHelper;
 import com.android.ddmlib.Log;
+import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
 
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.StringReader;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * Test to check that atrace is usable, to enable usage of systrace.
  */
-public class AtraceHostTest extends DeviceTestCase {
+public class AtraceHostTest extends DeviceTestCase implements IBuildReceiver {
     private static final String TAG = "AtraceHostTest";
 
-    private ITestDevice mDevice;
+    private static final String TEST_APK = "CtsAtraceTestApp.apk";
+    private static final String TEST_PKG = "com.android.cts.atracetestapp";
 
+    private CtsBuildHelper mCtsBuild;
+
+    /**
+     * {@inheritDoc}
+     */
     @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mDevice = getDevice();
+    public void setBuild(IBuildInfo buildInfo) {
+        mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
     }
 
     // Collection of all userspace tags, and 'sched'
@@ -65,7 +78,7 @@
      * Tests that atrace exists and is runnable with no args
      */
     public void testSimpleRun() throws Exception {
-        String output = mDevice.executeShellCommand("atrace");
+        String output = getDevice().executeShellCommand("atrace");
         String[] lines = output.split("\\r?\\n");
 
         // check for expected stdout
@@ -80,7 +93,7 @@
      * Tests the output of "atrace --list_categories" to ensure required categories exist.
      */
     public void testCategories() throws Exception {
-        String output = mDevice.executeShellCommand("atrace --list_categories");
+        String output = getDevice().executeShellCommand("atrace --list_categories");
         String[] categories = output.split("\\r?\\n");
 
         Set<String> requiredCategories = new HashSet<String>(sRequiredCategoriesList);
@@ -101,4 +114,120 @@
             fail("Expected categories missing from atrace");
         }
     }
+
+
+    private static final String TRACE_MARKER_REGEX =
+            "\\s*(\\S+)-(\\d+)\\s+\\(\\s*(\\d+)\\).*tracing_mark_write:\\s*(B|E)(.*)";
+    /**
+     * Tests that atrace captures app launch, including app level tracing
+     */
+    public void testTracingContent() throws Exception {
+        String atraceOutput = null;
+        try {
+            // cleanup test apps that might be installed from previous partial test run
+            getDevice().uninstallPackage(TEST_PKG);
+
+            // install the test app
+            File testAppFile = mCtsBuild.getTestApp(TEST_APK);
+            String installResult = getDevice().installPackage(testAppFile, false);
+            assertNull(
+                    String.format("failed to install simple app. Reason: %s", installResult),
+                    installResult);
+
+            // capture a launch of the app with async tracing
+            String atraceArgs = "-a " + TEST_PKG + " -c -b 16000 view"; // TODO: zipping
+            getDevice().executeShellCommand("atrace --async_stop " + atraceArgs);
+            getDevice().executeShellCommand("atrace --async_start " + atraceArgs);
+            String start = getDevice().executeShellCommand("am start " + TEST_PKG);
+            getDevice().executeShellCommand("sleep 1");
+            atraceOutput = getDevice().executeShellCommand("atrace --async_dump " + atraceArgs);
+        } finally {
+            getDevice().uninstallPackage(TEST_PKG);
+        }
+        assertNotNull(atraceOutput);
+
+
+        // now parse the trace data (see external/chromium-trace/systrace.py)
+        final String MARKER = "TRACE:";
+        int dataStart = atraceOutput.indexOf(MARKER);
+        assertTrue(dataStart >= 0);
+        String traceData = atraceOutput.substring(dataStart + MARKER.length());
+
+        /**
+         * Pattern that matches standard begin/end userspace tracing.
+         *
+         * Groups are:
+         * 1 - truncated thread name
+         * 2 - tid
+         * 3 - pid
+         * 4 - B/E
+         * 5 - ignored, for grouping
+         * 6 - if B, section title, else null
+         */
+        final Pattern beginEndPattern = Pattern.compile(
+                "\\s*(\\S+)-(\\d+)\\s+\\(\\s*(\\d+)\\).*tracing_mark_write:\\s*(B|E)(\\|\\d+\\|(.+))?");
+
+        int appPid = -1;
+        String line;
+
+        // list of tags expected to be seen on app launch, in order.
+        String[] requiredSectionList = {
+                "traceable-app-test-section",
+                "inflate",
+                "performTraversals",
+                "measure",
+                "layout",
+                "draw",
+                "Record View#draw()"
+        };
+        int nextSectionIndex = 0;
+        int matches = 0;
+        try (BufferedReader reader = new BufferedReader(new StringReader(traceData))) {
+            while ((line = reader.readLine()) != null) {
+                Matcher matcher = beginEndPattern.matcher(line);
+                if (matcher.find()) {
+                    matches++;
+
+                    String truncatedThreadName = matcher.group(1);
+                    assertNotNull(truncatedThreadName);
+
+                    int tid = assertInt(matcher.group(2));
+                    assertTrue(tid > 0);
+                    int pid = assertInt(matcher.group(3));
+                    assertTrue(pid > 0);
+
+                    if (TEST_PKG.endsWith(truncatedThreadName)) {
+                        // should be something like "s.aptracetestapp" since beginning may be truncated
+                        if (appPid == -1) {
+                            appPid = pid;
+                        } else {
+                            assertEquals(appPid, pid);
+                        }
+
+                        if ("B".equals(matcher.group(4))) {
+                            String sectionTitle = matcher.group(6);
+                            if (nextSectionIndex < requiredSectionList.length
+                                    && requiredSectionList[nextSectionIndex].equals(sectionTitle)) {
+                                nextSectionIndex++;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        assertTrue("Unable to parse any userspace sections from atrace output",
+                matches != 0);
+        assertEquals("Didn't see required list of traced sections, in order",
+                requiredSectionList.length, nextSectionIndex);
+    }
+
+    private static int assertInt(String input) {
+        try {
+            return Integer.parseInt(input);
+        } catch (NumberFormatException e) {
+            fail("Expected an integer but found \"" + input + "\"");
+            // Won't be hit, above throws AssertException
+            return -1;
+        }
+    }
 }
diff --git a/hostsidetests/devicepolicy/app/IntentSender/Android.mk b/hostsidetests/devicepolicy/app/IntentSender/Android.mk
index 21d2866..e5246c5 100644
--- a/hostsidetests/devicepolicy/app/IntentSender/Android.mk
+++ b/hostsidetests/devicepolicy/app/IntentSender/Android.mk
@@ -24,7 +24,9 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := android.test.runner android-support-v4
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 ctstestrunner
 
 LOCAL_SDK_VERSION := current
 
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk b/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk
index b74a7b6..f4adb31 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk
@@ -24,9 +24,9 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := android.test.runner cts-junit android-support-v4
+LOCAL_JAVA_LIBRARIES := android.test.runner cts-junit
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 ctstestrunner
 
 LOCAL_SDK_VERSION := current
 
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PermissionsTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PermissionsTest.java
new file mode 100644
index 0000000..2faf158
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PermissionsTest.java
@@ -0,0 +1,100 @@
+/*
+ * 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.cts.managedprofile;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.UserManager;
+
+import com.android.cts.managedprofile.BaseManagedProfileTest;
+
+import org.junit.Ignore;
+
+/**
+ * Test Runtime Permissions APIs in DevicePolicyManager.
+ */
+public class PermissionsTest extends BaseManagedProfileTest {
+
+    private static final String SIMPLE_APP_PACKAGE_NAME = "com.android.cts.launcherapps.simpleapp";
+    private static final String PERMISSION_NAME = "android.permission.READ_CONTACTS";
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // Make sure we are running in a managed profile, otherwise risk wiping the primary user's
+        // data.
+        assertTrue(mDevicePolicyManager.isAdminActive(ADMIN_RECEIVER_COMPONENT));
+        assertTrue(mDevicePolicyManager.isProfileOwnerApp(
+                ADMIN_RECEIVER_COMPONENT.getPackageName()));
+    }
+
+    public void testPermissionGrantState() {
+        PackageManager pm = mContext.getPackageManager();
+        mDevicePolicyManager.setPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
+                SIMPLE_APP_PACKAGE_NAME, PERMISSION_NAME,
+                DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
+        assertTrue(mDevicePolicyManager.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
+                SIMPLE_APP_PACKAGE_NAME, PERMISSION_NAME) ==
+                DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
+        assertEquals(pm.checkPermission(PERMISSION_NAME, SIMPLE_APP_PACKAGE_NAME),
+                PackageManager.PERMISSION_DENIED);
+
+        mDevicePolicyManager.setPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
+                SIMPLE_APP_PACKAGE_NAME, PERMISSION_NAME,
+                DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT);
+        assertTrue(mDevicePolicyManager.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
+                SIMPLE_APP_PACKAGE_NAME, PERMISSION_NAME) ==
+                DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT);
+        // Should stay denied
+        assertEquals(pm.checkPermission(PERMISSION_NAME, SIMPLE_APP_PACKAGE_NAME),
+                PackageManager.PERMISSION_DENIED);
+
+        mDevicePolicyManager.setPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
+                SIMPLE_APP_PACKAGE_NAME, PERMISSION_NAME,
+                DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
+        assertTrue(mDevicePolicyManager.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
+                SIMPLE_APP_PACKAGE_NAME, PERMISSION_NAME) ==
+                DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
+        assertEquals(pm.checkPermission(PERMISSION_NAME, SIMPLE_APP_PACKAGE_NAME),
+                PackageManager.PERMISSION_GRANTED);
+
+        mDevicePolicyManager.setPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
+                SIMPLE_APP_PACKAGE_NAME, PERMISSION_NAME,
+                DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT);
+        assertTrue(mDevicePolicyManager.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
+                SIMPLE_APP_PACKAGE_NAME, PERMISSION_NAME) ==
+                DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT);
+        // Should stay granted
+        assertEquals(pm.checkPermission(PERMISSION_NAME, SIMPLE_APP_PACKAGE_NAME),
+                PackageManager.PERMISSION_GRANTED);
+
+        mDevicePolicyManager.setPermissionPolicy(ADMIN_RECEIVER_COMPONENT,
+                DevicePolicyManager.PERMISSION_POLICY_AUTO_DENY);
+        assertEquals(mDevicePolicyManager.getPermissionPolicy(ADMIN_RECEIVER_COMPONENT),
+                DevicePolicyManager.PERMISSION_POLICY_AUTO_DENY);
+
+        mDevicePolicyManager.setPermissionPolicy(ADMIN_RECEIVER_COMPONENT,
+                DevicePolicyManager.PERMISSION_POLICY_AUTO_GRANT);
+        assertEquals(mDevicePolicyManager.getPermissionPolicy(ADMIN_RECEIVER_COMPONENT),
+                DevicePolicyManager.PERMISSION_POLICY_AUTO_GRANT);
+
+        mDevicePolicyManager.setPermissionPolicy(ADMIN_RECEIVER_COMPONENT,
+                DevicePolicyManager.PERMISSION_POLICY_PROMPT);
+        assertEquals(mDevicePolicyManager.getPermissionPolicy(ADMIN_RECEIVER_COMPONENT),
+                DevicePolicyManager.PERMISSION_POLICY_PROMPT);
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/SimpleApp/AndroidManifest.xml b/hostsidetests/devicepolicy/app/SimpleApp/AndroidManifest.xml
index af74f57..791ae56 100644
--- a/hostsidetests/devicepolicy/app/SimpleApp/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/SimpleApp/AndroidManifest.xml
@@ -18,6 +18,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.cts.launcherapps.simpleapp">
 
+    <uses-permission android:name="android.permission.READ_CONTACTS"/>
+
     <application>
         <activity android:name=".SimpleActivity" >
             <intent-filter>
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index 5c2048e..7d8fa67 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -30,6 +30,8 @@
     private static final String MANAGED_PROFILE_PKG = "com.android.cts.managedprofile";
     private static final String MANAGED_PROFILE_APK = "CtsManagedProfileApp.apk";
 
+    private static final String SIMPLE_APP_APK = "CtsSimpleApp.apk";
+
     private static final String INTENT_SENDER_PKG = "com.android.cts.intent.sender";
     private static final String INTENT_SENDER_APK = "CtsIntentSenderApp.apk";
 
@@ -406,6 +408,15 @@
         }
     }
 
+    public void testPermissionGrant() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        installApp(SIMPLE_APP_APK);
+        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PermissionsTest",
+                "testPermissionGrantState", mUserId));
+    }
+
     private void disableActivityForUser(String activityName, int userId)
             throws DeviceNotAvailableException {
         String command = "am start -W --user " + userId
diff --git a/tests/tests/accounts/AndroidManifest.xml b/tests/tests/accounts/AndroidManifest.xml
index c671ff0..93529d0 100644
--- a/tests/tests/accounts/AndroidManifest.xml
+++ b/tests/tests/accounts/AndroidManifest.xml
@@ -43,10 +43,21 @@
             <intent-filter>
                 <action android:name="android.accounts.AccountAuthenticator" />
             </intent-filter>
-
             <meta-data android:name="android.accounts.AccountAuthenticator"
                        android:resource="@xml/authenticator" />
         </service>
+
+        <service android:name="MockCustomTokenAccountService" android:exported="true"
+                 android:process="android.accounts.cts">
+            <intent-filter>
+                <action android:name="android.accounts.AccountAuthenticator" />
+            </intent-filter>
+            <meta-data android:name="android.accounts.AccountAuthenticator"
+                       android:resource="@xml/custom_token_authenticator" />
+            <meta-data android:name="android.accounts.AccountAuthenticator.customTokens"
+                       android:value="1" />
+
+        </service>
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/accounts/res/drawable/ic_cts_minitab_selected_custom_account.png b/tests/tests/accounts/res/drawable/ic_cts_minitab_selected_custom_account.png
new file mode 100644
index 0000000..3fbbc94
--- /dev/null
+++ b/tests/tests/accounts/res/drawable/ic_cts_minitab_selected_custom_account.png
Binary files differ
diff --git a/tests/tests/accounts/res/drawable/ic_cts_selected_custom_account.png b/tests/tests/accounts/res/drawable/ic_cts_selected_custom_account.png
new file mode 100644
index 0000000..70e35c0
--- /dev/null
+++ b/tests/tests/accounts/res/drawable/ic_cts_selected_custom_account.png
Binary files differ
diff --git a/tests/tests/accounts/res/xml/custom_token_authenticator.xml b/tests/tests/accounts/res/xml/custom_token_authenticator.xml
new file mode 100644
index 0000000..3337917
--- /dev/null
+++ b/tests/tests/accounts/res/xml/custom_token_authenticator.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2009, 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.
+ */
+-->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the Account Manager. -->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:accountType="android.accounts.cts.custom.account.type"
+    android:icon="@drawable/ic_cts_selected_custom_account"
+    android:smallIcon="@drawable/ic_cts_minitab_selected_custom_account"
+    android:customTokens="true"
+    android:label="@string/label"
+/>
diff --git a/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java b/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java
index c582c79..0e84fb9 100644
--- a/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java
+++ b/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java
@@ -26,16 +26,19 @@
 import android.accounts.OperationCanceledException;
 import android.app.Activity;
 import android.content.Context;
-import android.content.Intent;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.StrictMode;
 import android.test.ActivityInstrumentationTestCase2;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * You can run those unit tests with the following command line:
@@ -52,13 +55,15 @@
     public static final String ACCOUNT_NAME_OTHER = "android.accounts.cts.account.name.other";
 
     public static final String ACCOUNT_TYPE = "android.accounts.cts.account.type";
-    public static final String ACCOUNT_TYPE_OTHER = "android.accounts.cts.account.type.other";
+    public static final String ACCOUNT_TYPE_CUSTOM = "android.accounts.cts.custom.account.type";
+    public static final String ACCOUNT_TYPE_ABSENT = "android.accounts.cts.account.type.absent";
 
     public static final String ACCOUNT_PASSWORD = "android.accounts.cts.account.password";
 
-    public static final String AUTH_TOKEN = "mockAuthToken";
     public static final String AUTH_TOKEN_TYPE = "mockAuthTokenType";
+    public static final String AUTH_EXPIRING_TOKEN_TYPE = "mockAuthExpiringTokenType";
     public static final String AUTH_TOKEN_LABEL = "mockAuthTokenLabel";
+    public static final long AUTH_TOKEN_DURATION_MILLIS = 10000L; // Ten seconds.
 
     public static final String FEATURE_1 = "feature.1";
     public static final String FEATURE_2 = "feature.2";
@@ -86,6 +91,9 @@
             MockAccountAuthenticator.ACCOUNT_NAME_FOR_NEW_REMOVE_API, ACCOUNT_TYPE);
     public static final Account ACCOUNT_SAME_TYPE = new Account(ACCOUNT_NAME_OTHER, ACCOUNT_TYPE);
 
+    public static final Account CUSTOM_TOKEN_ACCOUNT =
+            new Account(ACCOUNT_NAME,ACCOUNT_TYPE_CUSTOM);
+
     private static MockAccountAuthenticator mockAuthenticator;
     private static final int LATCH_TIMEOUT_MS = 500;
     private static AccountManager am;
@@ -130,16 +138,101 @@
         assertTrue(removeAccount(am, ACCOUNT_SAME_TYPE, mActivity, null /* callback */).getBoolean(
                 AccountManager.KEY_BOOLEAN_RESULT));
 
+        // Clean out any other accounts added during the tests.
+        Account[] ctsAccounts = am.getAccountsByType(ACCOUNT_TYPE);
+        Account[] ctsCustomAccounts = am.getAccountsByType(ACCOUNT_TYPE_CUSTOM);
+        ArrayList<Account> accounts = new ArrayList<>(Arrays.asList(ctsAccounts));
+        accounts.addAll(Arrays.asList(ctsCustomAccounts));
+        for (Account ctsAccount : accounts) {
+            removeAccount(am, ctsAccount, mActivity, null /* callback */);
+        }
+
         // need to clean up the authenticator cached data
         mockAuthenticator.clearData();
 
         super.tearDown();
     }
 
-    private void validateAccountAndAuthTokenResult(Bundle result) {
-        assertEquals(ACCOUNT_NAME, result.get(AccountManager.KEY_ACCOUNT_NAME));
-        assertEquals(ACCOUNT_TYPE, result.get(AccountManager.KEY_ACCOUNT_TYPE));
-        assertEquals(AUTH_TOKEN, result.get(AccountManager.KEY_AUTHTOKEN));
+    interface TokenFetcher {
+        public Bundle fetch(String tokenType)
+                throws OperationCanceledException, AuthenticatorException, IOException;
+        public Account getAccount();
+    }
+
+    private void validateSuccessfulTokenFetchingLifecycle(TokenFetcher fetcher, String tokenType)
+            throws OperationCanceledException, AuthenticatorException, IOException {
+        Account account = fetcher.getAccount();
+        Bundle expected = new Bundle();
+        expected.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
+        expected.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
+
+        // First fetch.
+        Bundle actual = fetcher.fetch(tokenType);
+        assertTrue(mockAuthenticator.isRecentlyCalled());
+        validateAccountAndAuthTokenResult(expected, actual);
+
+        /*
+         * On the second fetch the cache will be populated if we are using a authenticator with
+         * customTokens=false or we are using a scope that will cause the authenticator to set an
+         * expiration time (and that expiration time hasn't been reached).
+         */
+        actual = fetcher.fetch(tokenType);
+
+        boolean isCachingExpected =
+                ACCOUNT_TYPE.equals(account.type) || AUTH_EXPIRING_TOKEN_TYPE.equals(tokenType);
+        assertEquals(isCachingExpected, !mockAuthenticator.isRecentlyCalled());
+        validateAccountAndAuthTokenResult(expected, actual);
+
+        try {
+            // Delay further execution until expiring tokens can actually expire.
+            Thread.sleep(mockAuthenticator.getTokenDurationMillis() + 1L);
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+
+        /*
+         * With the time shift above, the third request will result in cache hits only from
+         * customToken=false authenticators.
+         */
+        actual = fetcher.fetch(tokenType);
+        isCachingExpected = ACCOUNT_TYPE.equals(account.type);
+        assertEquals(isCachingExpected, !mockAuthenticator.isRecentlyCalled());
+        validateAccountAndAuthTokenResult(expected, actual);
+
+        // invalidate token
+        String token = actual.getString(AccountManager.KEY_AUTHTOKEN);
+        am.invalidateAuthToken(account.type, token);
+
+        /*
+         * Upon invalidating the token, the cache should be clear regardless of authenticator.
+         */
+        actual = fetcher.fetch(tokenType);
+        assertTrue(mockAuthenticator.isRecentlyCalled());
+        validateAccountAndAuthTokenResult(expected, actual);
+    }
+
+    private void validateAccountAndAuthTokenResult(Bundle actual) {
+        assertEquals(
+                ACCOUNT.name,
+                actual.get(AccountManager.KEY_ACCOUNT_NAME));
+        assertEquals(
+                ACCOUNT.type,
+                actual.get(AccountManager.KEY_ACCOUNT_TYPE));
+        assertEquals(
+                mockAuthenticator.getLastTokenServed(),
+                actual.get(AccountManager.KEY_AUTHTOKEN));
+    }
+
+    private void validateAccountAndAuthTokenResult(Bundle expected, Bundle actual) {
+        assertEquals(
+                expected.get(AccountManager.KEY_ACCOUNT_NAME),
+                actual.get(AccountManager.KEY_ACCOUNT_NAME));
+        assertEquals(
+                expected.get(AccountManager.KEY_ACCOUNT_TYPE),
+                actual.get(AccountManager.KEY_ACCOUNT_TYPE));
+        assertEquals(
+                mockAuthenticator.getLastTokenServed(),
+                actual.get(AccountManager.KEY_AUTHTOKEN));
     }
 
     private void validateAccountAndNoAuthTokenResult(Bundle result) {
@@ -224,7 +317,6 @@
     private boolean removeAccount(AccountManager am, Account account,
             AccountManagerCallback<Boolean> callback) throws IOException, AuthenticatorException,
                 OperationCanceledException {
-
         AccountManagerFuture<Boolean> futureBoolean = am.removeAccount(account,
                 callback,
                 null /* handler */);
@@ -357,6 +449,7 @@
         final CountDownLatch latch = new CountDownLatch(1);
 
         AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
             public void run(AccountManagerFuture<Bundle> bundleFuture) {
                 Bundle resultBundle = null;
                 try {
@@ -483,9 +576,7 @@
     /**
      * Test addAccountExplicitly() and removeAccountExplictly().
      */
-    public void testAddAccountExplicitlyAndRemoveAccountExplicitly() throws IOException,
-            AuthenticatorException, OperationCanceledException {
-
+    public void testAddAccountExplicitlyAndRemoveAccountExplicitly() {
         final int expectedAccountsCount = getAccountsCount();
 
         addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null /* userData */);
@@ -581,7 +672,7 @@
         assertEquals(2, accounts.length);
 
         // Check if we dont have any account from the other type
-        accounts = am.getAccountsByType(ACCOUNT_TYPE_OTHER);
+        accounts = am.getAccountsByType(ACCOUNT_TYPE_ABSENT);
         assertEquals(0, accounts.length);
     }
 
@@ -684,6 +775,7 @@
         final CountDownLatch latch1 = new CountDownLatch(1);
 
         AccountManagerCallback<Account[]> callback1 = new AccountManagerCallback<Account[]>() {
+            @Override
             public void run(AccountManagerFuture<Account[]> accountsFuture) {
                 try {
                     Account[] accounts = accountsFuture.getResult();
@@ -724,6 +816,7 @@
         final CountDownLatch latch2 = new CountDownLatch(1);
 
         AccountManagerCallback<Account[]> callback2 = new AccountManagerCallback<Account[]>() {
+            @Override
             public void run(AccountManagerFuture<Account[]> accountsFuture) {
                 try {
                     Account[] accounts = accountsFuture.getResult();
@@ -765,25 +858,24 @@
      */
     public void testSetAndPeekAndInvalidateAuthToken() {
         addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null /* userData */);
-
-        am.setAuthToken(ACCOUNT, AUTH_TOKEN_TYPE, AUTH_TOKEN);
+        String expected = "x";
+        am.setAuthToken(ACCOUNT, AUTH_TOKEN_TYPE, expected);
 
         // Ask for the AuthToken
         String token = am.peekAuthToken(ACCOUNT, AUTH_TOKEN_TYPE);
         assertNotNull(token);
-        assertEquals(AUTH_TOKEN, token);
+        assertEquals(expected, token);
 
-        am.invalidateAuthToken(ACCOUNT_TYPE, AUTH_TOKEN);
+        am.invalidateAuthToken(ACCOUNT_TYPE, token);
         token = am.peekAuthToken(ACCOUNT, AUTH_TOKEN_TYPE);
         assertNull(token);
     }
 
     /**
-     * Test blockingGetAuthToken()
+     * Test successful blockingGetAuthToken() with customTokens=false authenticator.
      */
-    public void testBlockingGetAuthToken() throws IOException, AuthenticatorException,
-            OperationCanceledException {
-
+    public void testBlockingGetAuthToken_DefaultToken_Success()
+            throws IOException, AuthenticatorException, OperationCanceledException {
         addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null);
 
         String token = am.blockingGetAuthToken(ACCOUNT,
@@ -792,17 +884,61 @@
 
         // Ask for the AuthToken
         assertNotNull(token);
-        assertEquals(AUTH_TOKEN, token);
+        assertEquals(mockAuthenticator.getLastTokenServed(), token);
+    }
+
+    private static class BlockingGetAuthTokenFetcher implements TokenFetcher {
+        private final Account mAccount;
+
+        BlockingGetAuthTokenFetcher(Account account) {
+            mAccount = account;
+        }
+
+        @Override
+        public Bundle fetch(String tokenType)
+                throws OperationCanceledException, AuthenticatorException, IOException {
+            String token = am.blockingGetAuthToken(
+                    getAccount(),
+                    tokenType,
+                    false /* no failure notification */);
+            Bundle result = new Bundle();
+            result.putString(AccountManager.KEY_AUTHTOKEN, token);
+            result.putString(AccountManager.KEY_ACCOUNT_NAME, mAccount.name);
+            result.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccount.type);
+            return result;
+        }
+        @Override
+        public Account getAccount() {
+            return CUSTOM_TOKEN_ACCOUNT;
+        }
     }
 
     /**
-     * Test getAuthToken()
+     * Test successful blockingGetAuthToken() with customTokens=true authenticator.
      */
-    public void testGetAuthToken() throws IOException, AuthenticatorException,
-            OperationCanceledException {
+    public void testBlockingGetAuthToken_CustomToken_NoCaching_Success()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        addAccountExplicitly(CUSTOM_TOKEN_ACCOUNT, ACCOUNT_PASSWORD, null);
+        TokenFetcher f = new BlockingGetAuthTokenFetcher(CUSTOM_TOKEN_ACCOUNT);
+        validateSuccessfulTokenFetchingLifecycle(f, AUTH_TOKEN_TYPE);
+    }
 
+    /**
+     * Test successful blockingGetAuthToken() with customTokens=true authenticator.
+     */
+    public void testBlockingGetAuthToken_CustomToken_ExpiringCache_Success()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        addAccountExplicitly(CUSTOM_TOKEN_ACCOUNT, ACCOUNT_PASSWORD, null);
+        TokenFetcher f = new BlockingGetAuthTokenFetcher(CUSTOM_TOKEN_ACCOUNT);
+        validateSuccessfulTokenFetchingLifecycle(f, AUTH_EXPIRING_TOKEN_TYPE);
+    }
+
+    /**
+     * Test successful getAuthToken() using a future with customTokens=false authenticator.
+     */
+    public void testDeprecatedGetAuthTokenWithFuture_NoOptions_DefaultToken_Success()
+            throws IOException, AuthenticatorException, OperationCanceledException {
         addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null /* userData */);
-
         AccountManagerFuture<Bundle> futureBundle = am.getAuthToken(ACCOUNT,
                 AUTH_TOKEN_TYPE,
                 false /* no failure notification */,
@@ -820,6 +956,226 @@
     }
 
     /**
+     * Test successful getAuthToken() using a future with customTokens=false without
+     * expiring tokens.
+     */
+    public void testDeprecatedGetAuthTokenWithFuture_NoOptions_CustomToken_Success()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        addAccountExplicitly(CUSTOM_TOKEN_ACCOUNT, ACCOUNT_PASSWORD, null);
+        // validateSuccessfulTokenFetchingLifecycle(AccountManager am, TokenFetcher fetcher, String tokenType)
+        TokenFetcher f = new TokenFetcher() {
+            @Override
+            public Bundle fetch(String tokenType)
+                    throws OperationCanceledException, AuthenticatorException, IOException {
+                AccountManagerFuture<Bundle> futureBundle = am.getAuthToken(
+                        getAccount(),
+                        tokenType,
+                        false /* no failure notification */,
+                        null /* no callback */,
+                        null /* no handler */
+                );
+                Bundle actual = futureBundle.getResult();
+                assertTrue(futureBundle.isDone());
+                assertNotNull(actual);
+                return actual;
+            }
+
+            @Override
+            public Account getAccount() {
+                return CUSTOM_TOKEN_ACCOUNT;
+            }
+        };
+        validateSuccessfulTokenFetchingLifecycle(f, AUTH_EXPIRING_TOKEN_TYPE);
+        validateSuccessfulTokenFetchingLifecycle(f, AUTH_TOKEN_TYPE);
+    }
+
+    /**
+     * Test successful getAuthToken() using a future with customTokens=false without
+     * expiring tokens.
+     */
+    public void testGetAuthTokenWithFuture_Options_DefaultToken_Success()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null /* userData */);
+
+        AccountManagerFuture<Bundle> futureBundle = am.getAuthToken(ACCOUNT,
+                AUTH_TOKEN_TYPE,
+                OPTIONS_BUNDLE,
+                mActivity,
+                null /* no callback */,
+                null /* no handler */
+        );
+
+        Bundle resultBundle = futureBundle.getResult();
+
+        assertTrue(futureBundle.isDone());
+        assertNotNull(resultBundle);
+
+        // Assert returned result
+        validateAccountAndAuthTokenResult(resultBundle);
+
+        validateOptions(null, mockAuthenticator.mOptionsAddAccount);
+        validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials);
+        validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials);
+        validateOptions(OPTIONS_BUNDLE, mockAuthenticator.mOptionsGetAuthToken);
+        validateSystemOptions(mockAuthenticator.mOptionsGetAuthToken);
+    }
+
+    /**
+     * Test successful getAuthToken() using a future with customTokens=false without
+     * expiring tokens.
+     */
+    public void testGetAuthTokenWithFuture_Options_CustomToken_Success()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        addAccountExplicitly(CUSTOM_TOKEN_ACCOUNT, ACCOUNT_PASSWORD, null);
+        TokenFetcher fetcherWithOptions = new TokenFetcher() {
+            @Override
+            public Bundle fetch(String tokenType)
+                    throws OperationCanceledException, AuthenticatorException, IOException {
+                AccountManagerFuture<Bundle> futureBundle = am.getAuthToken(
+                        getAccount(),
+                        tokenType,
+                        OPTIONS_BUNDLE,
+                        false /* no failure notification */,
+                        null /* no callback */,
+                        null /* no handler */
+                );
+                Bundle actual = futureBundle.getResult();
+                assertTrue(futureBundle.isDone());
+                assertNotNull(actual);
+                return actual;
+            }
+
+            @Override
+            public Account getAccount() {
+                return CUSTOM_TOKEN_ACCOUNT;
+            }
+        };
+        validateSuccessfulTokenFetchingLifecycle(fetcherWithOptions, AUTH_TOKEN_TYPE);
+        validateSuccessfulTokenFetchingLifecycle(fetcherWithOptions, AUTH_EXPIRING_TOKEN_TYPE);
+    }
+
+
+    /**
+     * Test successful getAuthToken() using a future with customTokens=false without
+     * expiring tokens.
+     */
+    public void testGetAuthTokenWithCallback_Options_Handler_DefaultToken_Success()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null);
+        final HandlerThread handlerThread = new HandlerThread("accounts.test");
+        handlerThread.start();
+        TokenFetcher fetcherWithOptions = new TokenFetcher() {
+            @Override
+            public Bundle fetch(String tokenType)
+                    throws OperationCanceledException, AuthenticatorException, IOException {
+                final AtomicReference<Bundle> actualRef = new AtomicReference<>();
+                final CountDownLatch latch = new CountDownLatch(1);
+
+                AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+                    @Override
+                    public void run(AccountManagerFuture<Bundle> bundleFuture) {
+                        Bundle resultBundle = null;
+                        try {
+                            resultBundle = bundleFuture.getResult();
+                            actualRef.set(resultBundle);
+                        } catch (OperationCanceledException e) {
+                            fail("should not throw an OperationCanceledException");
+                        } catch (IOException e) {
+                            fail("should not throw an IOException");
+                        } catch (AuthenticatorException e) {
+                            fail("should not throw an AuthenticatorException");
+                        } finally {
+                            latch.countDown();
+                        }
+                    }
+                };
+
+                am.getAuthToken(getAccount(),
+                        tokenType,
+                        OPTIONS_BUNDLE,
+                        false /* no failure notification */,
+                        callback,
+                        new Handler(handlerThread.getLooper()));
+
+                // Wait with timeout for the callback to do its work
+                try {
+                    latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+                } catch (InterruptedException e) {
+                    fail("should not throw an InterruptedException");
+                }
+                return actualRef.get();
+            }
+
+            @Override
+            public Account getAccount() {
+                return ACCOUNT;
+            }
+        };
+        validateSuccessfulTokenFetchingLifecycle(fetcherWithOptions, AUTH_TOKEN_TYPE);
+        validateSuccessfulTokenFetchingLifecycle(fetcherWithOptions, AUTH_EXPIRING_TOKEN_TYPE);
+    }
+
+    /**
+     * Test successful getAuthToken() using a future with customTokens=false without
+     * expiring tokens.
+     */
+    public void testGetAuthTokenWithCallback_Options_Handler_CustomToken_Success()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        addAccountExplicitly(CUSTOM_TOKEN_ACCOUNT, ACCOUNT_PASSWORD, null);
+        final HandlerThread handlerThread = new HandlerThread("accounts.test");
+        handlerThread.start();
+        TokenFetcher fetcherWithOptions = new TokenFetcher() {
+            @Override
+            public Bundle fetch(String tokenType)
+                    throws OperationCanceledException, AuthenticatorException, IOException {
+                final AtomicReference<Bundle> actualRef = new AtomicReference<>();
+                final CountDownLatch latch = new CountDownLatch(1);
+
+                AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+                    @Override
+                    public void run(AccountManagerFuture<Bundle> bundleFuture) {
+                        Bundle resultBundle = null;
+                        try {
+                            resultBundle = bundleFuture.getResult();
+                            actualRef.set(resultBundle);
+                        } catch (OperationCanceledException e) {
+                            fail("should not throw an OperationCanceledException");
+                        } catch (IOException e) {
+                            fail("should not throw an IOException");
+                        } catch (AuthenticatorException e) {
+                            fail("should not throw an AuthenticatorException");
+                        } finally {
+                            latch.countDown();
+                        }
+                    }
+                };
+
+                am.getAuthToken(getAccount(),
+                        tokenType,
+                        OPTIONS_BUNDLE,
+                        false /* no failure notification */,
+                        callback,
+                        new Handler(handlerThread.getLooper()));
+
+                // Wait with timeout for the callback to do its work
+                try {
+                    latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+                } catch (InterruptedException e) {
+                    fail("should not throw an InterruptedException");
+                }
+                return actualRef.get();
+            }
+
+            @Override
+            public Account getAccount() {
+                return CUSTOM_TOKEN_ACCOUNT;
+            }
+        };
+        validateSuccessfulTokenFetchingLifecycle(fetcherWithOptions, AUTH_TOKEN_TYPE);
+        validateSuccessfulTokenFetchingLifecycle(fetcherWithOptions, AUTH_EXPIRING_TOKEN_TYPE);
+    }
+
+    /**
      * Test getAuthToken() with callback and handler
      */
     public void testGetAuthTokenWithCallbackAndHandler() throws IOException, AuthenticatorException,
@@ -837,6 +1193,7 @@
         final CountDownLatch latch = new CountDownLatch(1);
 
         AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
             public void run(AccountManagerFuture<Bundle> bundleFuture) {
 
                 Bundle resultBundle = null;
@@ -880,37 +1237,6 @@
     }
 
     /**
-     * test getAuthToken() with options
-     */
-    public void testGetAuthTokenWithOptions() throws IOException, AuthenticatorException,
-            OperationCanceledException {
-
-        addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null /* userData */);
-
-        AccountManagerFuture<Bundle> futureBundle = am.getAuthToken(ACCOUNT,
-                AUTH_TOKEN_TYPE,
-                OPTIONS_BUNDLE,
-                mActivity,
-                null /* no callback */,
-                null /* no handler */
-        );
-
-        Bundle resultBundle = futureBundle.getResult();
-
-        assertTrue(futureBundle.isDone());
-        assertNotNull(resultBundle);
-
-        // Assert returned result
-        validateAccountAndAuthTokenResult(resultBundle);
-
-        validateOptions(null, mockAuthenticator.mOptionsAddAccount);
-        validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials);
-        validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials);
-        validateOptions(OPTIONS_BUNDLE, mockAuthenticator.mOptionsGetAuthToken);
-        validateSystemOptions(mockAuthenticator.mOptionsGetAuthToken);
-    }
-
-    /**
      * test getAuthToken() with options and callback and handler
      */
     public void testGetAuthTokenWithOptionsAndCallback() throws IOException,
@@ -928,15 +1254,14 @@
         final CountDownLatch latch = new CountDownLatch(1);
 
         AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
             public void run(AccountManagerFuture<Bundle> bundleFuture) {
 
                 Bundle resultBundle = null;
                 try {
                     resultBundle = bundleFuture.getResult();
-
                     // Assert returned result
                     validateAccountAndAuthTokenResult(resultBundle);
-
                 } catch (OperationCanceledException e) {
                     fail("should not throw an OperationCanceledException");
                 } catch (IOException e) {
@@ -1039,7 +1364,6 @@
         validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials);
         validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials);
         validateOptions(null, mockAuthenticator.mOptionsGetAuthToken);
-
     }
 
     /**
@@ -1154,8 +1478,7 @@
     /**
      * Test confirmCredentials() with callback
      */
-    public void testConfirmCredentialsWithCallbackAndHandler() throws IOException,
-            AuthenticatorException, OperationCanceledException {
+    public void testConfirmCredentialsWithCallbackAndHandler() {
 
         addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null /* userData */);
 
@@ -1163,12 +1486,10 @@
         testConfirmCredentialsWithCallbackAndHandler(new Handler(Looper.getMainLooper()));
     }
 
-    private void testConfirmCredentialsWithCallbackAndHandler(Handler handler) throws IOException,
-            AuthenticatorException, OperationCanceledException {
-
+    private void testConfirmCredentialsWithCallbackAndHandler(Handler handler) {
         final CountDownLatch latch = new CountDownLatch(1);
-
         AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
             public void run(AccountManagerFuture<Bundle> bundleFuture) {
 
                 Bundle resultBundle = null;
@@ -1191,15 +1512,11 @@
                 }
             }
         };
-
         AccountManagerFuture<Bundle> futureBundle = am.confirmCredentials(ACCOUNT,
                 OPTIONS_BUNDLE,
                 mActivity,
                 callback,
                 handler);
-
-        // futureBundle.getResult();
-
         // Wait with timeout for the callback to do its work
         try {
             latch.await(3 * LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
@@ -1249,6 +1566,7 @@
         final CountDownLatch latch = new CountDownLatch(1);
 
         AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
             public void run(AccountManagerFuture<Bundle> bundleFuture) {
 
                 Bundle resultBundle = null;
@@ -1320,6 +1638,7 @@
         final CountDownLatch latch = new CountDownLatch(1);
 
         AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
             public void run(AccountManagerFuture<Bundle> bundleFuture) {
                 try {
                     // Assert returned result
@@ -1381,6 +1700,7 @@
         final CountDownLatch latch = new CountDownLatch(1);
 
         OnAccountsUpdateListener listener = new OnAccountsUpdateListener() {
+            @Override
             public void onAccountsUpdated(Account[] accounts) {
                 latch.countDown();
             }
@@ -1423,6 +1743,7 @@
         final CountDownLatch latch = new CountDownLatch(1);
 
         OnAccountsUpdateListener listener = new OnAccountsUpdateListener() {
+            @Override
             public void onAccountsUpdated(Account[] accounts) {
                 fail("should not be called");
             }
@@ -1513,6 +1834,7 @@
 
     private AccountManagerCallback<Boolean> getAssertTrueCallback(final CountDownLatch latch) {
         return new AccountManagerCallback<Boolean>() {
+            @Override
             public void run(AccountManagerFuture<Boolean> booleanFuture) {
                 try {
                     // Assert returned result should be TRUE
@@ -1528,6 +1850,7 @@
 
     private AccountManagerCallback<Boolean> getAssertFalseCallback(final CountDownLatch latch) {
         return new AccountManagerCallback<Boolean>() {
+            @Override
             public void run(AccountManagerFuture<Boolean> booleanFuture) {
                 try {
                     // Assert returned result should be FALSE
@@ -1613,7 +1936,7 @@
         Bundle options = new Bundle();
         options.putBoolean(MockAccountAuthenticator.KEY_RETURN_INTENT, true);
         // Not really confirming, but a way to get last authenticated timestamp
-        Bundle result = am.confirmCredentials(ACCOUNT,
+        Bundle result = am.confirmCredentials(account,
                 options,// OPTIONS_BUNDLE,
                 null, /* activity */
                 null /* callback */,
@@ -1631,8 +1954,7 @@
     /**
      * Tests that AccountManagerService is properly caching data.
      */
-    public void testGetsAreCached() throws IOException, AuthenticatorException,
-            OperationCanceledException {
+    public void testGetsAreCached() {
 
         // Add an account,
         assertEquals(false, isAccountPresent(am.getAccounts(), ACCOUNT));
diff --git a/tests/tests/accounts/src/android/accounts/cts/MockAccountAuthenticator.java b/tests/tests/accounts/src/android/accounts/cts/MockAccountAuthenticator.java
index eec4eff..faebd53 100644
--- a/tests/tests/accounts/src/android/accounts/cts/MockAccountAuthenticator.java
+++ b/tests/tests/accounts/src/android/accounts/cts/MockAccountAuthenticator.java
@@ -24,13 +24,17 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
+import android.util.Log;
 
 import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * A simple Mock Account Authenticator
  */
 public class MockAccountAuthenticator extends AbstractAccountAuthenticator {
+    private static String TAG = "AccountManagerTest";
 
     public static String KEY_ACCOUNT_INFO = "key_account_info";
     public static String KEY_ACCOUNT_AUTHENTICATOR_RESPONSE = "key_account_authenticator_response";
@@ -40,6 +44,9 @@
     public static String ACCOUNT_NAME_FOR_NEW_REMOVE_API1 = "call new removeAccount api";
 
     private final Context mContext;
+    private final AtomicInteger mTokenCounter  = new AtomicInteger(0);
+    private final AtomicBoolean mIsRecentlyCalled = new AtomicBoolean(false);
+
     AccountAuthenticatorResponse mResponse;
     String mAccountType;
     String mAuthTokenType;
@@ -52,6 +59,7 @@
     String[] mFeatures;
 
     final ArrayList<String> mockFeatureList = new ArrayList<String>();
+    private final long mTokenDurationMillis = 1000; // 1 second
 
     public MockAccountAuthenticator(Context context) {
         super(context);
@@ -62,6 +70,18 @@
         mockFeatureList.add(AccountManagerTest.FEATURE_2);
     }
 
+    public long getTokenDurationMillis() {
+        return mTokenDurationMillis;
+    }
+
+    public boolean isRecentlyCalled() {
+        return mIsRecentlyCalled.getAndSet(false);
+    }
+
+    public String getLastTokenServed() {
+        return Integer.toString(mTokenCounter.get());
+    }
+
     public AccountAuthenticatorResponse getResponse() {
         return mResponse;
     }
@@ -113,8 +133,9 @@
         Bundle result = new Bundle();
         result.putString(AccountManager.KEY_ACCOUNT_NAME, AccountManagerTest.ACCOUNT_NAME);
         result.putString(AccountManager.KEY_ACCOUNT_TYPE, AccountManagerTest.ACCOUNT_TYPE);
-        result.putString(AccountManager.KEY_AUTHTOKEN, AccountManagerTest.AUTH_TOKEN);
-
+        result.putString(
+                AccountManager.KEY_AUTHTOKEN,
+                Integer.toString(mTokenCounter.incrementAndGet()));
         return result;
     }
 
@@ -125,13 +146,11 @@
     public Bundle addAccount(AccountAuthenticatorResponse response, String accountType,
             String authTokenType, String[] requiredFeatures, Bundle options)
             throws NetworkErrorException {
-
         this.mResponse = response;
         this.mAccountType = accountType;
         this.mAuthTokenType = authTokenType;
         this.mRequiredFeatures = requiredFeatures;
         this.mOptionsAddAccount = options;
-
         return createResultBundle();
     }
 
@@ -141,12 +160,10 @@
     @Override
     public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account,
             String authTokenType, Bundle options) throws NetworkErrorException {
-
         this.mResponse = response;
         this.mAccount = account;
         this.mAuthTokenType = authTokenType;
         this.mOptionsUpdateCredentials = options;
-
         return createResultBundle();
     }
 
@@ -157,10 +174,8 @@
      */
     @Override
     public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
-
         this.mResponse = response;
         this.mAccountType = accountType;
-
         return createResultBundle();
     }
 
@@ -170,11 +185,9 @@
     @Override
     public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account,
             Bundle options) throws NetworkErrorException {
-
         this.mResponse = response;
         this.mAccount = account;
         this.mOptionsConfirmCredentials = options;
-
         Bundle result = new Bundle();
         if (options.containsKey(KEY_RETURN_INTENT)) {
             Intent intent = new Intent();
@@ -191,15 +204,35 @@
      * Gets the authtoken for an account.
      */
     @Override
-    public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account,
-            String authTokenType, Bundle options) throws NetworkErrorException {
-
+    public Bundle getAuthToken(
+            AccountAuthenticatorResponse response,
+            Account account,
+            String authTokenType,
+            Bundle options) throws NetworkErrorException {
+        Log.w(TAG, "MockAuth - getAuthToken@" + System.currentTimeMillis());
+        mIsRecentlyCalled.set(true);
         this.mResponse = response;
         this.mAccount = account;
         this.mAuthTokenType = authTokenType;
         this.mOptionsGetAuthToken = options;
+        Bundle result = new Bundle();
 
-        return createResultBundle();
+        result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
+        result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
+        String token;
+        if (AccountManagerTest.AUTH_EXPIRING_TOKEN_TYPE.equals(authTokenType)) {
+            /*
+             * The resultant token should simply be the expiration timestamp. E.g. the time after
+             * which getting a new AUTH_EXPIRING_TOKEN_TYPE typed token will return a different
+             * value.
+             */
+            long expiry = System.currentTimeMillis() + mTokenDurationMillis;
+            result.putLong(AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, expiry);
+        }
+        result.putString(
+                AccountManager.KEY_AUTHTOKEN,
+                Integer.toString(mTokenCounter.incrementAndGet()));
+        return result;
     }
 
     /**
@@ -208,7 +241,6 @@
     @Override
     public String getAuthTokenLabel(String authTokenType) {
         this.mAuthTokenType = authTokenType;
-
         return AccountManagerTest.AUTH_TOKEN_LABEL;
     }
 
@@ -261,4 +293,4 @@
         }
         return result;
     }
-}
\ No newline at end of file
+}
diff --git a/tests/tests/accounts/src/android/accounts/cts/MockCustomTokenAccountService.java b/tests/tests/accounts/src/android/accounts/cts/MockCustomTokenAccountService.java
new file mode 100644
index 0000000..ea06a41
--- /dev/null
+++ b/tests/tests/accounts/src/android/accounts/cts/MockCustomTokenAccountService.java
@@ -0,0 +1,13 @@
+package android.accounts.cts;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+public class MockCustomTokenAccountService extends Service {
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return AccountManagerTest.getMockAuthenticator(this).getIBinder();
+    }
+}
diff --git a/tests/tests/content/AndroidManifest.xml b/tests/tests/content/AndroidManifest.xml
index 6cddfd1..a20befb 100644
--- a/tests/tests/content/AndroidManifest.xml
+++ b/tests/tests/content/AndroidManifest.xml
@@ -43,6 +43,12 @@
             android:label="@string/permlab_costMoney"
             android:description="@string/permdesc_costMoney"/>
 
+    <permission android:name="com.android.cts.content.CALL_ABROAD_PERMISSION"
+                android:label="@string/permlab_callAbroad"
+                android:description="@string/permdesc_callAbroad"
+                android:protectionLevel="normal"
+                android:permissionGroup="android.permission-group.COST_MONEY" />
+
     <!-- Used for PackageManager test, don't delete! -->
     <uses-configuration/>
     <uses-feature android:name="android.hardware.camera" />
diff --git a/tests/tests/content/res/values/strings.xml b/tests/tests/content/res/values/strings.xml
index c546d8a..8ffb477 100644
--- a/tests/tests/content/res/values/strings.xml
+++ b/tests/tests/content/res/values/strings.xml
@@ -179,5 +179,7 @@
 
     <string name="permlab_costMoney">Cost money</string>
     <string name="permdesc_costMoney">Do things that can cost you money.</string>
+    <string name="permlab_callAbroad">Call abroad</string>
+    <string name="permdesc_callAbroad">Make calls abroad</string>
 
 </resources>
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java b/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
index aaab8c4..cb3de2a 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
@@ -107,10 +107,10 @@
         checkActivityInfoName(RECEIVER_NAME, broadcastReceivers);
 
         // Test queryPermissionsByGroup, queryContentProviders
-        String testPermissionsGroup = "android.permission-group.NETWORK";
+        String testPermissionsGroup = "android.permission-group.COST_MONEY";
         List<PermissionInfo> permissions = mPackageManager.queryPermissionsByGroup(
                 testPermissionsGroup, PackageManager.GET_META_DATA);
-        checkPermissionInfoName(PERMISSION_NAME, permissions);
+        checkPermissionInfoName("com.android.cts.content.CALL_ABROAD_PERMISSION", permissions);
 
         ApplicationInfo appInfo = mPackageManager.getApplicationInfo(PACKAGE_NAME, 0);
         List<ProviderInfo> providers = mPackageManager.queryContentProviders(PACKAGE_NAME,
@@ -148,17 +148,12 @@
     }
 
     private void checkPermissionInfoName(String expectedName, List<PermissionInfo> permissions) {
-        boolean isContained = false;
-        Iterator<PermissionInfo> infoIterator = permissions.iterator();
-        String current;
-        while (infoIterator.hasNext()) {
-            current = infoIterator.next().name;
-            if (current.equals(expectedName)) {
-                isContained = true;
-                break;
-            }
+        List<String> names = new ArrayList<String>();
+        for (PermissionInfo permission : permissions) {
+            names.add(permission.name);
         }
-        assertTrue(isContained);
+        boolean isContained = names.contains(expectedName);
+        assertTrue("Permission " + expectedName + " not present in " + names, isContained);
     }
 
     private void checkProviderInfoName(String expectedName, List<ProviderInfo> providers) {
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java
index 4a00adb..769e110 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java
@@ -190,6 +190,19 @@
         assertEquals(originalAlpha, d3.getAlpha());
     }
 
+    public void testReset() {
+        final AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) mResources.getDrawable(mResId);
+        // The AVD has a duration as 100ms.
+        mActivity.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                d1.reset();
+                assertFalse(d1.isRunning());
+            }
+        });
+
+    }
+
     public void testAddCallback() throws InterruptedException {
         MyCallback callback = new MyCallback();
         final AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) mResources.getDrawable(mResId);
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java
index fdb8dae..fdc7b7a 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java
@@ -21,6 +21,9 @@
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.PorterDuff.Mode;
+import android.graphics.PorterDuffColorFilter;
 import android.graphics.drawable.VectorDrawable;
 import android.graphics.drawable.Drawable.ConstantState;
 import android.test.AndroidTestCase;
@@ -288,4 +291,12 @@
 
         d2.setAlpha(originalAlpha);
     }
+
+    public void testColorFilter() {
+        PorterDuffColorFilter filter = new PorterDuffColorFilter(Color.RED, Mode.SRC_IN);
+        VectorDrawable vectorDrawable = new VectorDrawable();
+        vectorDrawable.setColorFilter(filter);
+
+        assertEquals(filter, vectorDrawable.getColorFilter());
+    }
 }
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/RawConverter.java b/tests/tests/hardware/src/android/hardware/camera2/cts/rs/RawConverter.java
index 8ca650f..a9a6fce 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/RawConverter.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/rs/RawConverter.java
@@ -77,7 +77,7 @@
      * polynomial approximates the default tonemapping curve used for ACR3.
      */
     private static final float[] DEFAULT_ACR3_TONEMAP_CURVE_COEFFS = new float[] {
-            1.041f, -2.973f, 2.932f, 0f
+            -1.087f,  1.643f,  0.443f, 0f
     };
 
     /**
diff --git a/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java b/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
index 577e830..d3f4ccd 100644
--- a/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
@@ -36,9 +36,8 @@
 import java.security.PublicKey;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateFactory;
-import java.security.interfaces.ECPrivateKey;
-import java.security.interfaces.ECPublicKey;
-import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.ECKey;
+import java.security.interfaces.RSAKey;
 import java.security.spec.PKCS8EncodedKeySpec;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -1090,14 +1089,18 @@
         final PrivateKey privKey = keyEntry.getPrivateKey();
         final PublicKey pubKey = keyEntry.getCertificate().getPublicKey();
 
-        if (expectedKey instanceof ECPrivateKey) {
+        if (expectedKey instanceof ECKey) {
+            assertTrue("Returned PrivateKey " + privKey.getClass() + " should be instanceof ECKey",
+                    privKey instanceof ECKey);
             assertEquals("Returned PrivateKey should be what we inserted",
-                    ((ECPrivateKey) expectedKey).getParams().getCurve(),
-                    ((ECPublicKey) pubKey).getParams().getCurve());
-        } else if (expectedKey instanceof RSAPrivateKey) {
+                    ((ECKey) expectedKey).getParams().getCurve(),
+                    ((ECKey) privKey).getParams().getCurve());
+        } else if (expectedKey instanceof RSAKey) {
+            assertTrue("Returned PrivateKey " + privKey.getClass() + " should be instanceof RSAKey",
+                    privKey instanceof RSAKey);
             assertEquals("Returned PrivateKey should be what we inserted",
-                    ((RSAPrivateKey) expectedKey).getModulus(),
-                    ((RSAPrivateKey) privKey).getModulus());
+                    ((RSAKey) expectedKey).getModulus(),
+                    ((RSAKey) privKey).getModulus());
         }
 
         assertNull("getFormat() should return null", privKey.getFormat());
@@ -1143,15 +1146,16 @@
         Key key = mKeyStore.getKey(TEST_ALIAS_1, null);
         assertNotNull("Key should exist", key);
 
-        assertTrue("Should be a RSAPrivateKey", key instanceof RSAPrivateKey);
+        assertTrue("Should be a PrivateKey", key instanceof PrivateKey);
+        assertTrue("Should be a RSAKey", key instanceof RSAKey);
 
-        RSAPrivateKey actualKey = (RSAPrivateKey) key;
+        RSAKey actualKey = (RSAKey) key;
 
         KeyFactory keyFact = KeyFactory.getInstance("RSA");
         PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1));
 
         assertEquals("Inserted key should be same as retrieved key",
-                ((RSAPrivateKey) expectedKey).getModulus(), actualKey.getModulus());
+                ((RSAKey) expectedKey).getModulus(), actualKey.getModulus());
     }
 
     public void testKeyStore_GetKey_Certificate_Unencrypted_Failure() throws Exception {
@@ -1893,14 +1897,17 @@
 
         kpg.generateKeyPair();
 
-        RSAPrivateKey key = (RSAPrivateKey) ks.getKey(alias, null);
-        assertNotNull(key);
-        String cipher = key.getAlgorithm() + "/NONE/NOPADDING";
+        PrivateKey privateKey = (PrivateKey) ks.getKey(alias, null);
+        assertNotNull(privateKey);
+        PublicKey publicKey = ks.getCertificate(alias).getPublicKey();
+        assertNotNull(publicKey);
+        String cipher = privateKey.getAlgorithm() + "/NONE/NOPADDING";
         Cipher encrypt = Cipher.getInstance(cipher);
         assertNotNull(encrypt);
-        encrypt.init(Cipher.ENCRYPT_MODE, key);
+        encrypt.init(Cipher.ENCRYPT_MODE, privateKey);
 
-        byte[] plainText = new byte[encrypt.getBlockSize()];
+        int modulusSizeBytes = (((RSAKey) publicKey).getModulus().bitLength() + 7) / 8;
+        byte[] plainText = new byte[modulusSizeBytes];
         Arrays.fill(plainText, (byte) 0xFF);
 
         // We expect a BadPaddingException here as the message size (plaintext)
diff --git a/tests/tests/location/src/android/location/cts/LocationTest.java b/tests/tests/location/src/android/location/cts/LocationTest.java
index b60b8b1..db2820c 100644
--- a/tests/tests/location/src/android/location/cts/LocationTest.java
+++ b/tests/tests/location/src/android/location/cts/LocationTest.java
@@ -437,7 +437,7 @@
         final long timeout = 500;
 
         // should refuse binding
-        IBinder binder = service.onBind(intent);
+        IBinder binder = service.callOnBind(intent);
         assertNull("onBind should always fail.", binder);
 
         // test if result consistent with the truth
@@ -445,7 +445,7 @@
         service.setEnabled(false);
         resultHandler.expectEnabled(false);
         resultHandler.expectMessage(true);
-        ret = service.onStartCommand(intent, SettingInjectorService.START_NOT_STICKY, 0);
+        ret = service.callOnStartCommand(intent, SettingInjectorService.START_NOT_STICKY, 0);
         assertEquals("onStartCommand return value invalid in (enabled == false) case.",
             ret, SettingInjectorService.START_NOT_STICKY);
         assertTrue("Message time out in (enabled == false case).",
@@ -455,7 +455,7 @@
         service.setEnabled(true);
         resultHandler.expectEnabled(true);
         resultHandler.expectMessage(true);
-        ret = service.onStartCommand(intent, SettingInjectorService.START_NOT_STICKY, 0);
+        ret = service.callOnStartCommand(intent, SettingInjectorService.START_NOT_STICKY, 0);
         assertEquals("onStartCommand return value invalid in (enabled == true) case.",
             ret, SettingInjectorService.START_NOT_STICKY);
         assertTrue("Message time out in (enabled == true) case.",
@@ -463,7 +463,7 @@
 
         // should not respond to the deprecated method
         resultHandler.expectMessage(false);
-        service.onStart(intent, 0);
+        service.callOnStart(intent, 0);
         resultHandler.waitForMessage(timeout);
     }
 
@@ -574,6 +574,20 @@
         public void setEnabled(boolean enabled) {
             mEnabled = enabled;
         }
+
+        // API coverage dashboard will not cound method call from derived class.
+        // Thus, it is necessary to make explicit call to SettingInjectorService public methods.
+        public IBinder callOnBind(Intent intent) {
+            return super.onBind(intent);
+        }
+
+        public void callOnStart(Intent intent, int startId) {
+            super.onStart(intent, startId);
+        }
+
+        public int callOnStartCommand(Intent intent, int flags, int startId) {
+            return super.onStartCommand(intent, flags, startId);
+        }
     }
 
 }
diff --git a/tests/tests/media/src/android/media/cts/DecoderTest.java b/tests/tests/media/src/android/media/cts/DecoderTest.java
index 9014f8d..ee40207 100644
--- a/tests/tests/media/src/android/media/cts/DecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/DecoderTest.java
@@ -1134,7 +1134,7 @@
 
     public void testCodecEarlyEOSHEVC() throws Exception {
         testCodecEarlyEOS(
-                R.raw.video_1280x720_mp4_hevc_1150kbps_30fps_aac_stereo_128kbps_48000hz,
+                R.raw.video_480x360_mp4_hevc_650kbps_30fps_aac_stereo_128kbps_48000hz,
                 120 /* eosframe */);
     }
 
diff --git a/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java b/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java
old mode 100644
new mode 100755
index d3d15a5..26e0c54
--- a/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java
@@ -70,6 +70,7 @@
                     "311660",   // MetroPCS
                     "310120",   // Sprint
                     "44050",    // KDDI
+                    "44051",    // KDDI
                     "44053",    // KDDI
                     "44054",    // KDDI
                     "44070",    // KDDI
@@ -129,6 +130,7 @@
             Arrays.asList(
                     "44010",    // NTT DOCOMO
                     "44020",    // SBM
+                    "44051",    // KDDI
                     "302720",   // Rogers
                     "30272",    // Rogers
                     "302370",   // Fido
@@ -167,6 +169,7 @@
             Arrays.asList(
                     "44010",    // NTT DOCOMO
                     "44020",    // SBM
+                    "44051",    // KDDI
                     "302720",   // Rogers
                     "30272",    // Rogers
                     "302370",   // Fido
diff --git a/tests/tests/text/src/android/text/cts/StaticLayoutTest.java b/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
index 3a64658..e3f0e0a 100644
--- a/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
+++ b/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
@@ -21,6 +21,7 @@
 import android.text.GetChars;
 import android.text.GraphicsOperations;
 import android.text.Layout.Alignment;
+import android.text.TextUtils.TruncateAt;
 import android.text.SpannableString;
 import android.text.SpannableStringBuilder;
 import android.text.SpannedString;
@@ -113,6 +114,104 @@
         }
     }
 
+    public void testBuilder() {
+        {
+            // Obtain.
+            StaticLayout.Builder builder = StaticLayout.Builder.obtain(LAYOUT_TEXT, 0,
+                    LAYOUT_TEXT.length(), mDefaultPaint, DEFAULT_OUTER_WIDTH);
+            StaticLayout layout = builder.build();
+            // Check values passed to obtain().
+            assertEquals(LAYOUT_TEXT, layout.getText());
+            assertEquals(mDefaultPaint, layout.getPaint());
+            assertEquals(DEFAULT_OUTER_WIDTH, layout.getWidth());
+            // Check default values.
+            assertEquals(TextDirectionHeuristics.FIRSTSTRONG_LTR,
+                    layout.getTextDirectionHeuristic());
+            assertEquals(Alignment.ALIGN_NORMAL, layout.getAlignment());
+            assertEquals(0.0f, layout.getSpacingAdd());
+            assertEquals(1.0f, layout.getSpacingMultiplier());
+            assertEquals(DEFAULT_OUTER_WIDTH, layout.getEllipsizedWidth());
+        }
+        {
+            // Obtain with null objects.
+            StaticLayout.Builder builder = StaticLayout.Builder.obtain(null, 0, 0, null, 0);
+            try {
+                StaticLayout layout = builder.build();
+                fail("should throw NullPointerException here");
+            } catch (NullPointerException e) {
+            }
+        }
+        {
+            // setText.
+            StaticLayout.Builder builder = StaticLayout.Builder.obtain(LAYOUT_TEXT, 0,
+                    LAYOUT_TEXT.length(), mDefaultPaint, DEFAULT_OUTER_WIDTH);
+            builder.setText(LAYOUT_TEXT_SINGLE_LINE);
+            StaticLayout layout = builder.build();
+            assertEquals(LAYOUT_TEXT_SINGLE_LINE, layout.getText());
+        }
+        {
+            // setAlignment.
+            StaticLayout.Builder builder = StaticLayout.Builder.obtain(LAYOUT_TEXT, 0,
+                    LAYOUT_TEXT.length(), mDefaultPaint, DEFAULT_OUTER_WIDTH);
+            builder.setAlignment(DEFAULT_ALIGN);
+            StaticLayout layout = builder.build();
+            assertEquals(DEFAULT_ALIGN, layout.getAlignment());
+        }
+        {
+            // setTextDirection.
+            StaticLayout.Builder builder = StaticLayout.Builder.obtain(LAYOUT_TEXT, 0,
+                    LAYOUT_TEXT.length(), mDefaultPaint, DEFAULT_OUTER_WIDTH);
+            builder.setTextDirection(TextDirectionHeuristics.RTL);
+            StaticLayout layout = builder.build();
+            // Always returns TextDirectionHeuristics.FIRSTSTRONG_LTR.
+            assertEquals(TextDirectionHeuristics.FIRSTSTRONG_LTR,
+                    layout.getTextDirectionHeuristic());
+        }
+        {
+            // setLineSpacing.
+            StaticLayout.Builder builder = StaticLayout.Builder.obtain(LAYOUT_TEXT, 0,
+                    LAYOUT_TEXT.length(), mDefaultPaint, DEFAULT_OUTER_WIDTH);
+            builder.setLineSpacing(1.0f, 2.0f);
+            StaticLayout layout = builder.build();
+            assertEquals(1.0f, layout.getSpacingAdd());
+            assertEquals(2.0f, layout.getSpacingMultiplier());
+        }
+        {
+            // setEllipsizedWidth and setEllipsize.
+            StaticLayout.Builder builder = StaticLayout.Builder.obtain(LAYOUT_TEXT, 0,
+                    LAYOUT_TEXT.length(), mDefaultPaint, DEFAULT_OUTER_WIDTH);
+            builder.setEllipsize(TruncateAt.END);
+            builder.setEllipsizedWidth(ELLIPSIZE_WIDTH);
+            StaticLayout layout = builder.build();
+            assertEquals(ELLIPSIZE_WIDTH, layout.getEllipsizedWidth());
+            assertEquals(DEFAULT_OUTER_WIDTH, layout.getWidth());
+            assertTrue(layout.getEllipsisCount(0) == 0);
+            assertTrue(layout.getEllipsisCount(5) > 0);
+        }
+        {
+            // setMaxLines.
+            StaticLayout.Builder builder = StaticLayout.Builder.obtain(LAYOUT_TEXT, 0,
+                    LAYOUT_TEXT.length(), mDefaultPaint, DEFAULT_OUTER_WIDTH);
+            builder.setMaxLines(1);
+            builder.setEllipsize(TruncateAt.END);
+            StaticLayout layout = builder.build();
+            assertTrue(layout.getEllipsisCount(0) > 0);
+            assertEquals(1, layout.getLineCount());
+        }
+        {
+            // Setter methods that cannot be directly tested.
+            // setBreakStrategy, setHyphenationFrequency, setIncludePad, and setIndents.
+            StaticLayout.Builder builder = StaticLayout.Builder.obtain(LAYOUT_TEXT, 0,
+                    LAYOUT_TEXT.length(), mDefaultPaint, DEFAULT_OUTER_WIDTH);
+            builder.setBreakStrategy(StaticLayout.BREAK_STRATEGY_HIGH_QUALITY);
+            builder.setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_FULL);
+            builder.setIncludePad(true);
+            builder.setIndents(null, null);
+            StaticLayout layout = builder.build();
+            assertNotNull(layout);
+        }
+    }
+
     /*
      * Get the line number corresponding to the specified vertical position.
      *  If you ask for a position above 0, you get 0. above 0 means pixel above the fire line
diff --git a/tests/uiautomator/test-apps/CtsUiAutomatorApp/Android.mk b/tests/uiautomator/test-apps/CtsUiAutomatorApp/Android.mk
index 60a0ba6..3827754 100644
--- a/tests/uiautomator/test-apps/CtsUiAutomatorApp/Android.mk
+++ b/tests/uiautomator/test-apps/CtsUiAutomatorApp/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_SDK_VERSION := current
 
 LOCAL_PACKAGE_NAME := CtsUiAutomatorApp
-LOCAL_JAVA_LIBRARIES = android-support-v4
+LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4
 
 LOCAL_PROGUARD_ENABLED := disabled