Merge change 3179 into donut

* changes:
  Integrate unsubmitted cupcake change 149411: 	CTS: added missed test cases for package android.text.method
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index cbaa74a..9cd2caf 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -127,6 +127,14 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="android.widget.cts.HorizontalScrollViewStubActivity"
+            android:label="HorizontalScrollViewStubActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
         <activity android:name="android.view.cts.UsingViewsStubActivity"
             android:label="Using Views Test">
             <intent-filter>
diff --git a/tests/res/layout/horizontal_scrollview.xml b/tests/res/layout/horizontal_scrollview.xml
new file mode 100644
index 0000000..0f88ab3
--- /dev/null
+++ b/tests/res/layout/horizontal_scrollview.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<android.widget.cts.MyHorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/horizontal_scroll_view"
+    android:layout_width="100px"
+    android:layout_height="100px">
+
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="250px"
+        android:layout_height="wrap_content">
+
+        <Button
+            android:id="@+id/first_horizontal_child"
+            android:layout_width="250px"
+            android:layout_height="100px"
+            android:text="@string/vertical_text_1"/>
+
+        <Button
+            android:layout_width="250px"
+            android:layout_height="100px"
+            android:text="@string/vertical_text_2"/>
+
+        <Button
+            android:layout_width="250px"
+            android:layout_height="100px"
+            android:text="@string/vertical_text_3"/>
+
+        <Button
+            android:layout_width="250px"
+            android:layout_height="100px"
+            android:text="@string/vertical_text_1"/>
+
+        <Button
+            android:layout_width="250px"
+            android:layout_height="100px"
+            android:text="@string/vertical_text_2"/>
+
+        <Button
+            android:layout_width="250px"
+            android:layout_height="100px"
+            android:text="@string/vertical_text_3"/>
+
+        <Button
+            android:layout_width="250px"
+            android:layout_height="100px"
+            android:text="@string/vertical_text_1"/>
+
+        <Button
+            android:layout_width="250px"
+            android:layout_height="100px"
+            android:text="@string/vertical_text_2"/>
+
+        <Button
+            android:layout_width="250px"
+            android:layout_height="100px"
+            android:text="@string/vertical_text_3"/>
+
+        <Button
+            android:layout_width="250px"
+            android:layout_height="100px"
+            android:text="@string/vertical_text_1"/>
+
+        <Button
+            android:layout_width="250px"
+            android:layout_height="100px"
+            android:text="@string/vertical_text_2"/>
+
+        <Button
+            android:layout_width="250px"
+            android:layout_height="100px"
+            android:text="@string/vertical_text_3"/>
+
+        <Button
+            android:layout_width="250px"
+            android:layout_height="100px"
+            android:text="@string/vertical_text_1"/>
+
+        <Button
+            android:layout_width="250px"
+            android:layout_height="100px"
+            android:text="@string/vertical_text_2"/>
+
+        <Button
+            android:id="@+id/last_horizontal_child"
+            android:layout_width="250px"
+            android:layout_height="100px"
+            android:text="@string/vertical_text_3"/>
+    </LinearLayout>
+
+</android.widget.cts.MyHorizontalScrollView>
diff --git a/tests/src/android/widget/cts/HorizontalScrollViewStubActivity.java b/tests/src/android/widget/cts/HorizontalScrollViewStubActivity.java
new file mode 100644
index 0000000..8dd6911
--- /dev/null
+++ b/tests/src/android/widget/cts/HorizontalScrollViewStubActivity.java
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+package android.widget.cts;
+
+import com.android.cts.stub.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class HorizontalScrollViewStubActivity extends Activity {
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.horizontal_scrollview);
+    }
+}
diff --git a/tests/src/android/widget/cts/MyHorizontalScrollView.java b/tests/src/android/widget/cts/MyHorizontalScrollView.java
new file mode 100644
index 0000000..639193a
--- /dev/null
+++ b/tests/src/android/widget/cts/MyHorizontalScrollView.java
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+package android.widget.cts;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.HorizontalScrollView;
+
+public class MyHorizontalScrollView extends HorizontalScrollView {
+    public MyHorizontalScrollView(Context context) {
+        super(context);
+    }
+
+    public MyHorizontalScrollView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public MyHorizontalScrollView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    @Override
+    protected int computeHorizontalScrollRange() {
+        return super.computeHorizontalScrollRange();
+    }
+
+    @Override
+    protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) {
+        return super.computeScrollDeltaToGetChildRectOnScreen(rect);
+    }
+
+    @Override
+    protected float getLeftFadingEdgeStrength() {
+        return super.getLeftFadingEdgeStrength();
+    }
+
+    @Override
+    protected float getRightFadingEdgeStrength() {
+        return super.getRightFadingEdgeStrength();
+    }
+
+    @Override
+    protected void measureChild(View child, int parentWidthMeasureSpec,
+            int parentHeightMeasureSpec) {
+        super.measureChild(child, parentWidthMeasureSpec, parentHeightMeasureSpec);
+    }
+
+    @Override
+    protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed,
+            int parentHeightMeasureSpec, int heightUsed) {
+        super.measureChildWithMargins(child, parentWidthMeasureSpec,
+                widthUsed, parentHeightMeasureSpec, heightUsed);
+    }
+}
diff --git a/tests/tests/permission/Android.mk b/tests/tests/permission/Android.mk
index 7988384..869c19b 100644
--- a/tests/tests/permission/Android.mk
+++ b/tests/tests/permission/Android.mk
@@ -25,8 +25,6 @@
 
 LOCAL_PACKAGE_NAME := CtsPermissionTestCases
 
-LOCAL_INSTRUMENTATION_FOR := android.core.tests.runner
-
 LOCAL_SDK_VERSION := current
 
 include $(BUILD_PACKAGE)
diff --git a/tests/tests/permission/AndroidManifest.xml b/tests/tests/permission/AndroidManifest.xml
index 1ddadd0..f824c7d 100644
--- a/tests/tests/permission/AndroidManifest.xml
+++ b/tests/tests/permission/AndroidManifest.xml
@@ -20,10 +20,27 @@
 
     <application>
         <uses-library android:name="android.test.runner" />
+        <activity android:name="android.permission.cts.PermissionStubActivity"
+                  android:label="PermissionStubActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST"/>
+            </intent-filter>
+        </activity>
     </application>
 
-    <instrumentation android:name="android.test.InstrumentationCtsTestRunner"
-                     android:targetPackage="android.core.tests.runner"
+    <!--
+        The CTS stubs package cannot be used as the target application here,
+        since that requires many permissions to be set. Instead, specify this
+        package itself as the target and include any stub activities needed.
+
+        This test package uses the default InstrumentationTestRunner, because
+        the InstrumentationCtsTestRunner is only available in the stubs
+        package. That runner cannot be added to this package either, since it
+        relies on hidden APIs.
+    -->
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="com.android.cts.permission"
                      android:label="CTS tests of com.android.cts.permission"/>
 
 </manifest>
diff --git a/tests/tests/permission/src/android/permission/cts/AudioPermissionTest.java b/tests/tests/permission/src/android/permission/cts/AudioPermissionTest.java
new file mode 100644
index 0000000..285e8eb
--- /dev/null
+++ b/tests/tests/permission/src/android/permission/cts/AudioPermissionTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+package android.permission.cts;
+
+import android.content.Context;
+import android.media.MediaPlayer;
+import android.media.MediaRecorder;
+import android.media.AudioManager;
+import android.net.Uri;
+import android.os.Environment;
+import android.test.AndroidTestCase;
+
+/**
+ * Test that audio-related Permissions are enforced.
+ */
+public class AudioPermissionTest extends AndroidTestCase {
+
+    static String PATH_PREFIX = Environment.getExternalStorageDirectory().toString();
+    static String AUDIO_CAPTURE_PATH = PATH_PREFIX + "this-should-not-exist.amr";
+    static int BEAUTY_SLEEP_INTERVAL = 5 * 1000;
+
+    MediaPlayer mMediaPlayer = null;
+    MediaRecorder mMediaRecorder = null;
+    boolean mRecorded = false;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mMediaRecorder = new MediaRecorder();
+    }
+
+    void testMicrophoneRecording() {
+        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
+        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
+        mMediaRecorder.setOutputFile(AUDIO_CAPTURE_PATH);
+
+        try {
+            mMediaRecorder.prepare();
+        }
+        catch (SecurityException e) {
+            // expected...?
+            return;
+        } catch (Exception e) {
+            fail("Could not prepare MediaRecorder: " + e.toString());
+        }
+
+        try {
+            mMediaRecorder.start();
+        } catch (SecurityException e) {
+            // expected
+            return;
+        }
+
+        try {
+            Thread.sleep(BEAUTY_SLEEP_INTERVAL);
+        } catch (InterruptedException e) {
+            // OK
+        }
+
+        try {
+            mMediaRecorder.stop();
+            mMediaRecorder.release();
+            mRecorded = true;
+            fail("Recorded from MediaRecorder.AudioSource.MIC");
+        } catch (SecurityException e) {
+            // expected
+            mRecorded = false;
+        }
+    }
+
+    void doRemoteMp3(Uri uri) {
+        try {
+            MediaPlayer plyr = new MediaPlayer();
+            plyr.setDataSource(mContext, uri);
+            plyr.setAudioStreamType(AudioManager.STREAM_MUSIC);
+            plyr.prepare();
+            plyr.seekTo(1000);    // Just to try.
+            plyr.start();
+            Thread.sleep(BEAUTY_SLEEP_INTERVAL / 10);
+            plyr.stop();
+            fail("We just downloaded a song off the Internet with no permissions, and uploaded arbitrary data in the query string");
+            plyr.release();
+        } catch (SecurityException e) {
+            // expected
+        } catch (Exception e) {
+            fail("Got further than we should have trying to load a remote media source");
+        }
+    }
+
+    void testRemoteMp3() {
+        doRemoteMp3(Uri.parse("http://labs.isecpartners.com/chris/noodle.mp3?secret=1234"));
+    }
+
+}
+
diff --git a/tests/tests/permission/src/android/permission/cts/NoActivityRelatedPermissionTest.java b/tests/tests/permission/src/android/permission/cts/NoActivityRelatedPermissionTest.java
new file mode 100644
index 0000000..1d0ba36
--- /dev/null
+++ b/tests/tests/permission/src/android/permission/cts/NoActivityRelatedPermissionTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+package android.permission.cts;
+
+import dalvik.annotation.TestTargetClass;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.view.WindowManager;
+import android.view.WindowManager.BadTokenException;
+
+/**
+ * Verify the Activity related operations require specific permissions.
+ */
+@TestTargetClass(Activity.class)
+public class NoActivityRelatedPermissionTest
+        extends ActivityInstrumentationTestCase2<PermissionStubActivity> {
+
+    private PermissionStubActivity mActivity;
+
+    public NoActivityRelatedPermissionTest() {
+        super("com.android.cts.permission", PermissionStubActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mActivity = getActivity();
+    }
+
+    /**
+     * Verify that adding window of different types in Window Manager requires permissions.
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#SYSTEM_ALERT_WINDOW}.
+     */
+    @UiThreadTest
+    public void testSystemAlertWindow() {
+        final int[] types = new int[] {
+                WindowManager.LayoutParams.TYPE_PHONE,
+                WindowManager.LayoutParams.TYPE_PRIORITY_PHONE,
+                WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
+                WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
+                WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
+            };
+
+        AlertDialog dialog = (AlertDialog) (mActivity.getDialog());
+        // Use normal window type will success
+        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION);
+        dialog.show();
+
+        // Test special window types which need to be check SYSTEM_ALERT_WINDOW
+        // permission.
+        for (int i = 0; i < types.length; i++) {
+            dialog = (AlertDialog) (mActivity.getDialog());
+            dialog.getWindow().setType(types[i]);
+            try {
+                dialog.show();
+                fail("Add dialog to Window Manager did not throw BadTokenException as expected");
+            } catch (BadTokenException e) {
+                // Expected
+            }
+        }
+    }
+
+    /**
+     * Verify that setting Activity's persistent attribute requires permissions.
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#PERSISTENT_ACTIVITY}.
+     */
+    @UiThreadTest
+    public void testSetPersistent() {
+        try {
+            mActivity.setPersistent(true);
+            fail("Activity.setPersistent() did not throw SecurityException as expected");
+        } catch (SecurityException e) {
+            // Expected
+        }
+    }
+
+    /**
+     * Verify that get task requires permissions.
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#GET_TASKS}
+     */
+    public void testGetTask() {
+        ActivityManager manager = (ActivityManager) getActivity()
+                .getSystemService(Context.ACTIVITY_SERVICE);
+        try {
+            manager.getRunningTasks(1);
+            fail("Activity.getRunningTasks did not throw SecurityException as expected");
+        } catch (SecurityException e) {
+            // Expected
+        }
+
+        try {
+            manager.getRecentTasks(1, 0);
+            fail("Activity.getRunningTasks did not throw SecurityException as expected");
+        } catch (SecurityException e) {
+            // Expected
+        }
+    }
+}
diff --git a/tests/tests/permission/src/android/permission/cts/NoAudioPermissionTest.java b/tests/tests/permission/src/android/permission/cts/NoAudioPermissionTest.java
new file mode 100644
index 0000000..b850c31
--- /dev/null
+++ b/tests/tests/permission/src/android/permission/cts/NoAudioPermissionTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+package android.permission.cts;
+
+import android.content.Context;
+import android.media.AudioManager;
+import android.test.AndroidTestCase;
+
+/**
+ * Verify the audio related operations require specific permissions.
+ */
+public class NoAudioPermissionTest extends AndroidTestCase {
+    private AudioManager mAudioManager;
+    private static final int MODE_COUNT = 3;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+        assertNotNull(mAudioManager);
+    }
+
+    /**
+     * Verify that AudioManager.setMicrophoneMute, AudioManager.setMode requires permissions.
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
+     */
+    public void testSetMicrophoneMute() {
+        boolean muteState = mAudioManager.isMicrophoneMute();
+        int originalMode = mAudioManager.getMode();
+        // If there is no permission of MODIFY_AUDIO_SETTINGS, setMicrophoneMute does nothing.
+        mAudioManager.setMicrophoneMute(!muteState);
+        assertEquals(muteState, mAudioManager.isMicrophoneMute());
+
+        // If there is no permission of MODIFY_AUDIO_SETTINGS, setMode does nothing.
+        assertTrue(AudioManager.MODE_NORMAL != AudioManager.MODE_RINGTONE);
+
+        mAudioManager.setMode(AudioManager.MODE_NORMAL);
+        assertEquals(originalMode, mAudioManager.getMode());
+
+        mAudioManager.setMode(AudioManager.MODE_RINGTONE);
+        assertEquals(originalMode, mAudioManager.getMode());
+    }
+
+    /**
+     * Verify that AudioManager.setRouting requires permissions.
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
+     */
+    @SuppressWarnings("deprecation")
+    public void testSetRouting() {
+        int[] defaultRoutes = new int[MODE_COUNT];
+        defaultRoutes[0] = mAudioManager.getRouting(AudioManager.MODE_NORMAL);
+        defaultRoutes[1] = mAudioManager.getRouting(AudioManager.MODE_RINGTONE);
+        defaultRoutes[2] = mAudioManager.getRouting(AudioManager.MODE_IN_CALL);
+
+        // If there is no permission of MODIFY_AUDIO_SETTINGS, setRouting does nothing.
+        // Please referring android.media.cts.AudioManagerTest#testRouting().
+        mAudioManager.setBluetoothScoOn(true);
+        mAudioManager.setRouting(AudioManager.MODE_IN_CALL, AudioManager.ROUTE_BLUETOOTH_SCO,
+                AudioManager.ROUTE_ALL);
+        assertEquals(defaultRoutes[0], getRouting(AudioManager.MODE_NORMAL));
+        assertEquals(defaultRoutes[1], getRouting(AudioManager.MODE_RINGTONE));
+        assertEquals(defaultRoutes[2], getRouting(AudioManager.MODE_IN_CALL));
+
+        mAudioManager.setRouting(AudioManager.MODE_NORMAL, AudioManager.ROUTE_SPEAKER,
+                AudioManager.ROUTE_ALL);
+        mAudioManager.setRouting(AudioManager.MODE_RINGTONE, AudioManager.ROUTE_SPEAKER,
+                AudioManager.ROUTE_ALL);
+        mAudioManager.setRouting(AudioManager.MODE_IN_CALL, AudioManager.ROUTE_SPEAKER,
+                AudioManager.ROUTE_ALL);
+        assertEquals(defaultRoutes[0], getRouting(AudioManager.MODE_NORMAL));
+        assertEquals(defaultRoutes[1], getRouting(AudioManager.MODE_RINGTONE));
+        assertEquals(defaultRoutes[2], getRouting(AudioManager.MODE_IN_CALL));
+
+        mAudioManager.setSpeakerphoneOn(true);
+        assertFalse(mAudioManager.isSpeakerphoneOn());
+        assertEquals(defaultRoutes[2], getRouting(AudioManager.MODE_IN_CALL));
+        mAudioManager.setSpeakerphoneOn(false);
+        assertFalse(mAudioManager.isSpeakerphoneOn());
+        assertEquals(defaultRoutes[2], getRouting(AudioManager.MODE_IN_CALL));
+
+        mAudioManager.setRouting(AudioManager.MODE_NORMAL, AudioManager.ROUTE_EARPIECE,
+                AudioManager.ROUTE_ALL);
+        mAudioManager.setRouting(AudioManager.MODE_RINGTONE, AudioManager.ROUTE_EARPIECE,
+                AudioManager.ROUTE_ALL);
+        mAudioManager.setRouting(AudioManager.MODE_IN_CALL, AudioManager.ROUTE_EARPIECE,
+                AudioManager.ROUTE_ALL);
+        assertEquals(defaultRoutes[0], getRouting(AudioManager.MODE_NORMAL));
+        assertEquals(defaultRoutes[1], getRouting(AudioManager.MODE_RINGTONE));
+        assertEquals(defaultRoutes[2], getRouting(AudioManager.MODE_IN_CALL));
+    }
+
+    @SuppressWarnings("deprecation")
+    private int getRouting(int mode) {
+        return mAudioManager.getRouting(mode);
+    }
+}
diff --git a/tests/tests/permission/src/android/permission/cts/NoReadLogsPermissionTest.java b/tests/tests/permission/src/android/permission/cts/NoReadLogsPermissionTest.java
new file mode 100644
index 0000000..aa6e02b
--- /dev/null
+++ b/tests/tests/permission/src/android/permission/cts/NoReadLogsPermissionTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+package android.permission.cts;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+/**
+ * Verify the read system log require specific permissions.
+ */
+public class NoReadLogsPermissionTest extends AndroidTestCase {
+    private static final String LOGTAG = "CTS";
+
+    /**
+     * Verify that we won't get the system log without a READ_LOGS permission.
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#READ_LOGS }.
+     * @throws IOException
+     */
+    public void testSetMicrophoneMute() throws IOException {
+        Process logcatProc = null;
+        BufferedReader reader = null;
+        try {
+            logcatProc = Runtime.getRuntime().exec(new String[]
+                    {"logcat", "-d", "AndroidRuntime:E :" + LOGTAG + ":V *:S" });
+            Log.d(LOGTAG, "no read logs permission test");
+
+            reader = new BufferedReader(new InputStreamReader(logcatProc.getInputStream()));
+
+            String line;
+            final StringBuilder log = new StringBuilder();
+            String separator = System.getProperty("line.separator");
+            while ((line = reader.readLine()) != null) {
+                log.append(line);
+                log.append(separator);
+            }
+            // no permission get empty log
+            assertEquals(0, log.length());
+
+        } finally {
+            if (reader != null) {
+                reader.close();
+            }
+        }
+    }
+}
diff --git a/tests/tests/permission/src/android/permission/cts/NoReadWritePermissionTest.java b/tests/tests/permission/src/android/permission/cts/NoReadWritePermissionTest.java
new file mode 100644
index 0000000..296649d
--- /dev/null
+++ b/tests/tests/permission/src/android/permission/cts/NoReadWritePermissionTest.java
@@ -0,0 +1,242 @@
+/*
+ * 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.
+ */
+
+package android.permission.cts;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.net.Uri;
+import android.provider.Browser;
+import android.provider.Contacts;
+import android.provider.Settings;
+import android.test.AndroidTestCase;
+
+/**
+ * Verify the location access without specific permissions.
+ */
+public class NoReadWritePermissionTest extends AndroidTestCase {
+    private ContentResolver mContentResolver;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mContentResolver = getContext().getContentResolver();
+    }
+
+    private void queryProvider(Uri uri) {
+        try {
+            mContentResolver.query(uri, null, null, null, null);
+            fail("read from provider did not throw SecurityException as expected.");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    private void insertProvider(Uri uri, ContentValues values) {
+        try {
+            mContentResolver.insert(uri, values);
+            fail("Write into provider did not throw SecurityException as expected.");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    /**
+     * Verify that read and write to calendar requires permissions.
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#READ_CALENDAR}
+     *   {@link android.Manifest.permission#WRITE_CALENDAR}
+     */
+    public void testReadWriteCalendar() {
+        Uri uri = Uri.parse("content://calendar/events/");
+
+        // read permission
+        queryProvider(uri);
+
+            // write permission
+        ContentValues values = new ContentValues();
+        values.put("eventTimezone", "EST");
+        values.put("calendar_id", 1);
+        values.put("title", "Party over thurr");
+        values.put("allDay", 0);
+        values.put("transparency", 0);
+        values.put("visibility", 0);
+        values.put("hasAlarm", 0);
+
+        insertProvider(uri, values);
+    }
+
+    /**
+     * Verify that read and write to contact requires permissions.
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#READ_CONTACTS}
+     *   {@link android.Manifest.permission#WRITE_CONTACTS}
+     */
+    public void testReadWriteContacts() {
+        Uri uri = Contacts.People.CONTENT_URI;
+
+        // read permission
+        queryProvider(uri);
+
+
+        // write permission
+        ContentValues values = new ContentValues();
+        values.put(Contacts.People.NAME, "New Contact");
+
+        insertProvider(uri, values);
+    }
+
+    /**
+     * Verify that read and write to sms requires permissions.
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#READ_SMS}
+     *   {@link android.Manifest.permission#WRITE_SMS}
+     */
+    public void testReadWriteSms() {
+        Uri uri = Uri.parse("content://sms/inbox");
+
+        // read permission
+        queryProvider(uri);
+
+        // write permission
+        ContentValues values = new ContentValues();
+        values.put("person", "google");
+
+        insertProvider(uri, values);
+    }
+
+    /**
+     * Verify that read and write to sync settings requires permissions.
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#READ_SYNC_SETTINGS}
+     *   {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}
+     */
+    public void testReadWriteSyncSettings() {
+        Uri uri = Uri.parse("content://sync/settings");
+
+        // read permission
+        queryProvider(uri);
+
+        // write permission
+        ContentValues values = new ContentValues();
+        values.put("name", "vendor");
+        values.put("value", "google");
+
+        insertProvider(uri, values);
+    }
+
+    /**
+     * Verify that read to sync stats requires permissions.
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#READ_SYNC_STATS}
+     */
+    public void testReadSyncStats() {
+        Uri uri = Uri.parse("content://sync/stats");
+
+        // read permission
+        queryProvider(uri);
+    }
+
+    /**
+     * Verify that write to apn settings requires permissions.
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#WRITE_APN_SETTINGS}
+     */
+    public void testWriteApnSettings() {
+        Uri uri = Uri.parse("content://telephony/carriers");
+
+        // write permission
+        ContentValues values = new ContentValues();
+        values.put("apn", "google");
+
+        insertProvider(uri, values);
+    }
+
+    /**
+     * Verify that write to settings requires permissions.
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#WRITE_SETTINGS}
+     */
+    public void testWriteSettings() {
+        Uri uri = Uri.parse("content://" + Settings.AUTHORITY + "/bookmarks");
+
+        // write permission
+        ContentValues values = new ContentValues();
+        values.put("title", "android");
+
+        insertProvider(uri, values);
+    }
+
+    /**
+     * Verify that read and write of subscribed feeds requires permissions.
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#SUBSCRIBED_FEEDS_READ}
+     *   {@link android.Manifest.permission#SUBSCRIBED_FEEDS_WRITE}
+     */
+    public void testReadSubscribedFeeds() {
+        Uri uri = Uri.parse("content://subscribedfeeds");
+
+        // read permission
+        queryProvider(uri);
+
+        // write permission
+        ContentValues values = new ContentValues();
+        values.put("feed", "android");
+
+        insertProvider(uri, values);
+    }
+
+    /**
+     * Verify that read and write to browser bookmarks requires permissions.
+     * <p>Requires Permission:
+     *   {@link com.android.browser.permission.READ_HISTORY_BOOKMARKS}
+         {@link com.android.browser.permission.WRITE_HISTORY_BOOKMARKS}
+     */
+    public void testReadWriteBookmarks() {
+        Uri uri = Browser.BOOKMARKS_URI;
+
+        // read permission
+        queryProvider(uri);
+
+        // write permission
+        ContentValues values = new ContentValues();
+        values.put(Browser.BookmarkColumns.TITLE, "android");
+        values.put(Browser.BookmarkColumns.URL, "http://developer.android.com");
+
+        insertProvider(uri, values);
+    }
+
+    /**
+     * Verify that read and write to browser history requires permissions.
+     * <p>Requires Permission:
+     *   {@link com.android.browser.permission.READ_HISTORY_BOOKMARKS}
+         {@link com.android.browser.permission.WRITE_HISTORY_BOOKMARKS}
+     */
+    public void testReadWriteHistory() {
+        Uri uri = Browser.SEARCHES_URI;
+
+        // read permission
+        queryProvider(uri);
+
+        // write permission
+        ContentValues values = new ContentValues();
+        values.put(Browser.SearchColumns.URL, "http://developer.android.com");
+        values.put(Browser.SearchColumns.DATE, "12/31/1999");
+
+        insertProvider(uri, values);
+    }
+}
+
diff --git a/tests/tests/permission/src/android/permission/cts/NoSystemFunctionPermissionTest.java b/tests/tests/permission/src/android/permission/cts/NoSystemFunctionPermissionTest.java
new file mode 100644
index 0000000..c3e1474
--- /dev/null
+++ b/tests/tests/permission/src/android/permission/cts/NoSystemFunctionPermissionTest.java
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+
+package android.permission.cts;
+
+import android.app.ActivityManager;
+import android.app.AlarmManager;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.os.Vibrator;
+import android.telephony.gsm.SmsManager;
+import android.test.AndroidTestCase;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.TimeZone;
+
+/**
+ * Verify the system function require specific permissions.
+ */
+@SuppressWarnings("deprecation")
+public class NoSystemFunctionPermissionTest extends AndroidTestCase {
+
+    /**
+     * Verify that ActivityManager.restartPackage() requires permissions.
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#RESTART_PACKAGES}.
+     */
+    public void testRestartPackage() {
+        ActivityManager activityManager = (ActivityManager) mContext.getSystemService(
+                Context.ACTIVITY_SERVICE);
+
+        try {
+            activityManager.restartPackage("packageName");
+            fail("ActivityManager.restartPackage() didn't throw SecurityException as expected.");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    /**
+     * Verify that AlarmManager.setTimeZone() requires permissions.
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#SET_TIME_ZONE}.
+     */
+    public void testSetTimeZone() {
+        AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(
+                Context.ALARM_SERVICE);
+        String[] timeZones = TimeZone.getAvailableIDs();
+        String timeZone = timeZones[0];
+
+        try {
+            alarmManager.setTimeZone(timeZone);
+            fail("AlarmManager.setTimeZone() did not throw SecurityException as expected.");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    /**
+     * Verify that setting wallpaper relate methods require permissions.
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#SET_WALLPAPER}.
+     * @throws IOException 
+     */
+    public void testSetWallpaper() throws IOException {
+        Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565);
+
+        try {
+            mContext.setWallpaper(bitmap);
+            fail("Context.setWallpaper(BitMap) did not throw SecurityException as expected.");
+        } catch (SecurityException e) {
+            // expected
+        }
+
+        try {
+            mContext.setWallpaper((InputStream) null);
+            fail("Context.setWallpaper(InputStream) did not throw SecurityException as expected.");
+        } catch (SecurityException e) {
+            // expected
+        }
+
+        try {
+            mContext.clearWallpaper();
+            fail("Context.clearWallpaper() did not throw SecurityException as expected.");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    /**
+     * Verify that Vibrator's vibrating related methods requires permissions.
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#VIBRATE}.
+     */
+    public void testVibrator() {
+        Vibrator vibrator = (Vibrator)getContext().getSystemService(Context.VIBRATOR_SERVICE);
+
+        try {
+            vibrator.cancel();
+            fail("Vibrator.cancel() did not throw SecurityException as expected.");
+        } catch (SecurityException e) {
+            // expected
+        }
+
+        try {
+            vibrator.vibrate(1);
+            fail("Vibrator.vibrate(long) did not throw SecurityException as expected.");
+        } catch (SecurityException e) {
+            // expected
+        }
+
+        long[] testPattern = {1, 1, 1, 1, 1};
+
+        try {
+            vibrator.vibrate(testPattern, 1);
+            fail("Vibrator.vibrate(long[], int) not throw SecurityException as expected.");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    /**
+     * Verify that sending sms requires permissions.
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#SMS}.
+     */
+    public void testSendSms() {
+        SmsManager smsManager = SmsManager.getDefault();
+        byte[] testData = new byte[10];
+        try {
+            smsManager.sendDataMessage("1233", "1233", (short) 0, testData, null, null);
+            fail("SmsManager.sendDataMessage() did not throw SecurityException as expected.");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+}
diff --git a/tests/tests/permission/src/android/permission/cts/NoWakeLockPermissionTest.java b/tests/tests/permission/src/android/permission/cts/NoWakeLockPermissionTest.java
new file mode 100644
index 0000000..0bc573e
--- /dev/null
+++ b/tests/tests/permission/src/android/permission/cts/NoWakeLockPermissionTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+
+package android.permission.cts;
+
+import android.content.Context;
+import android.media.MediaPlayer;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiManager.WifiLock;
+import android.os.PowerManager;
+import android.test.AndroidTestCase;
+
+/**
+ * Verify the Wake Lock related operations require specific permissions.
+ */
+public class NoWakeLockPermissionTest extends AndroidTestCase {
+    private PowerManager mPowerManager;
+
+    private PowerManager.WakeLock mWakeLock;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+        mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, "tag");
+    }
+
+    /**
+     * Verify that WifiManager.WifiLock.acquire() requires permissions.
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#WAKE_LOCK}.
+     */
+    public void testWifiLockAcquire() {
+        final WifiManager wifiManager = (WifiManager) mContext.getSystemService(
+                Context.WIFI_SERVICE);
+        final WifiLock wifiLock = wifiManager.createWifiLock("WakeLockPermissionTest");
+        try {
+            wifiLock.acquire();
+            fail("WifiManager.WifiLock.acquire() didn't throw SecurityException as expected");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    /**
+     * Verify that MediaPlayer.start() requires permissions.
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#WAKE_LOCK}.
+     */
+    public void testMediaPlayerWakeLock() {
+        final MediaPlayer mediaPlayer = new MediaPlayer();
+        mediaPlayer.setWakeMode(mContext, PowerManager.FULL_WAKE_LOCK);
+        try {
+            mediaPlayer.start();
+            fail("MediaPlayer.setWakeMode() did not throw SecurityException as expected");
+        } catch (SecurityException e) {
+            // expected
+        }
+
+        mediaPlayer.stop();
+    }
+
+    /**
+     * Verify that PowerManager.WakeLock.acquire() requires permissions.
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#WAKE_LOCK}.
+     */
+    public void testPowerManagerWakeLockAcquire() {
+        try {
+            mWakeLock.acquire();
+            fail("MediaPlayer.setWakeMode() did not throw SecurityException as expected");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    /**
+     * Verify that PowerManager.WakeLock.acquire(long) requires permissions.
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#WAKE_LOCK}.
+     */
+    public void testPowerManagerWakeLockAcquire2() {
+        // Tset acquire(long)
+        try {
+            mWakeLock.acquire(1);
+            fail("MediaPlayer.setWakeMode(long) did not throw SecurityException as expected");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    /**
+     * Verify that PowerManager.WakeLock.release() requires permissions.
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#WAKE_LOCK}.
+     */
+    public void testPowerManagerWakeLockRelease() {
+        mWakeLock.setReferenceCounted(false);
+        try {
+            mWakeLock.release();
+            fail("MediaPlayer.setWakeMode(long) did not throw SecurityException as expected");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+}
diff --git a/tests/tests/permission/src/android/permission/cts/PermissionStubActivity.java b/tests/tests/permission/src/android/permission/cts/PermissionStubActivity.java
new file mode 100644
index 0000000..dd61177
--- /dev/null
+++ b/tests/tests/permission/src/android/permission/cts/PermissionStubActivity.java
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+package android.permission.cts;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.os.Bundle;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.ListView;
+
+/**
+ * A minimal application for Window test.
+ */
+public class PermissionStubActivity extends Activity {
+    private ListView mListView;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mListView = new ListView(this);
+        mListView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+                LayoutParams.WRAP_CONTENT));
+
+        setContentView(mListView);
+    }
+
+    public Dialog getDialog() {
+        return new AlertDialog.Builder(PermissionStubActivity.this).create();
+    }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java b/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java
new file mode 100644
index 0000000..d26b217
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java
@@ -0,0 +1,897 @@
+/*
+ * 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.
+ */
+
+package android.widget.cts;
+
+import com.android.cts.stub.R;
+
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.ToBeFixed;
+
+import org.xmlpull.v1.XmlPullParser;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Rect;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.util.AttributeSet;
+import android.util.Xml;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup.LayoutParams;
+import android.view.animation.cts.DelayedCheck;
+import android.widget.HorizontalScrollView;
+import android.widget.TextView;
+
+/**
+ * Test {@link HorizontalScrollView}.
+ */
+@TestTargetClass(HorizontalScrollView.class)
+public class HorizontalScrollViewTest
+        extends ActivityInstrumentationTestCase2<HorizontalScrollViewStubActivity> {
+    private static final int ITEM_WIDTH  = 250;
+    private static final int ITEM_HEIGHT = 100;
+    private static final int ITEM_COUNT  = 15;
+    private static final int PAGE_WIDTH  = 100;
+    private static final int PAGE_HEIGHT = 100;
+    private static final int SCROLL_RIGHT = ITEM_WIDTH * ITEM_COUNT - PAGE_WIDTH;
+    private MyHorizontalScrollView mScrollView;
+    private Activity mActivity;
+
+    public HorizontalScrollViewTest() {
+        super("com.android.cts.stub", HorizontalScrollViewStubActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mActivity = getActivity();
+        mScrollView = (MyHorizontalScrollView) mActivity.findViewById(R.id.horizontal_scroll_view);
+    }
+
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "HorizontalScrollView",
+            args = {Context.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "HorizontalScrollView",
+            args = {Context.class, AttributeSet.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "HorizontalScrollView",
+            args = {Context.class, AttributeSet.class, int.class}
+        )
+    })
+    public void testConstructor() {
+        XmlPullParser parser = mActivity.getResources().getLayout(R.layout.horizontal_scrollview);
+        AttributeSet attrs = Xml.asAttributeSet(parser);
+        new HorizontalScrollView(mActivity);
+
+        new HorizontalScrollView(mActivity, attrs);
+
+        new HorizontalScrollView(mActivity, attrs, 0);
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "getMaxScrollAmount",
+        args = {}
+    )
+    public void testGetMaxScrollAmount() {
+        HorizontalScrollView scrollView = new HorizontalScrollView(mActivity);
+        scrollView.layout(0, 0, 100, 200);
+        assertEquals((100 - 0) / 2, scrollView.getMaxScrollAmount());
+
+        scrollView.layout(0, 0, 150, 100);
+        assertEquals((150 - 0) / 2, scrollView.getMaxScrollAmount());
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "addView",
+        args = {View.class}
+    )
+    @ToBeFixed(bug = "1695243", explanation = "Android API javadocs are incomplete."
+            + " @throws clause should be added into javadoc of "
+            + "HorizontalScrollView#addView(View) when there is already one child in the view.")
+    public void testAddView() {
+        HorizontalScrollView scrollView = new HorizontalScrollView(mActivity);
+        TextView child0 = new TextView(mActivity);
+        scrollView.addView(child0);
+        assertSame(child0, scrollView.getChildAt(0));
+
+        assertEquals(1, scrollView.getChildCount());
+        TextView child1 = new TextView(mActivity);
+        try {
+            scrollView.addView(child1);
+            fail("did not throw IllegalStateException when add more than one child");
+        } catch (IllegalStateException e) {
+            // expected
+        }
+        assertEquals(1, scrollView.getChildCount());
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "addView",
+        args = {View.class, int.class}
+    )
+    @ToBeFixed(bug = "1695243", explanation = "Android API javadocs are incomplete."
+            + " @throws clause should be added into javadoc of "
+            + "HorizontalScrollView#addView(View, int) when there "
+            + "is already one child in the view.")
+    public void testAddViewWithIndex() {
+        HorizontalScrollView scrollView = new HorizontalScrollView(mActivity);
+        TextView child0 = new TextView(mActivity);
+        scrollView.addView(child0, 0);
+        assertSame(child0, scrollView.getChildAt(0));
+
+        assertEquals(1, scrollView.getChildCount());
+        TextView child1 = new TextView(mActivity);
+        try {
+            scrollView.addView(child1, 1);
+            fail("did not throw IllegalStateException when add more than one child");
+        } catch (IllegalStateException e) {
+            // expected
+        }
+        assertEquals(1, scrollView.getChildCount());
+
+        scrollView.removeAllViews();
+        scrollView = new HorizontalScrollView(mActivity);
+        scrollView.addView(child0, -1);
+        assertSame(child0, scrollView.getChildAt(0));
+
+        assertEquals(1, scrollView.getChildCount());
+        child1 = new TextView(mActivity);
+        try {
+            scrollView.addView(child1, -1);
+            fail("did not throw IllegalStateException when add more than one child");
+        } catch (IllegalStateException e) {
+            // expected
+        }
+        assertEquals(1, scrollView.getChildCount());
+
+        scrollView.removeAllViews();
+        scrollView = new HorizontalScrollView(mActivity);
+        try {
+            scrollView.addView(child0, 1);
+            fail("did not throw IndexOutOfBoundsException when index is larger than 0");
+        } catch (IndexOutOfBoundsException e) {
+            // expected
+        }
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "addView",
+        args = {View.class, LayoutParams.class}
+    )
+    @ToBeFixed(bug = "1695243", explanation = "Android API javadocs are incomplete."
+            + " @throws clause should be added into javadoc of "
+            + "HorizontalScrollView#addView(View, LayoutParams) when there is already"
+            + " one child in the view or the layoutparams is null")
+    public void testAddViewWithLayoutParams() {
+        HorizontalScrollView scrollView = new HorizontalScrollView(mActivity);
+        TextView child0 = new TextView(mActivity);
+        scrollView.addView(child0, new ViewGroup.LayoutParams(200, 100));
+        assertSame(child0, scrollView.getChildAt(0));
+        assertEquals(200, child0.getLayoutParams().width);
+        assertEquals(100, child0.getLayoutParams().height);
+
+        assertEquals(1, scrollView.getChildCount());
+        TextView child1 = new TextView(mActivity);
+        try {
+            scrollView.addView(child1, new ViewGroup.LayoutParams(200, 100));
+            fail("did not throw IllegalStateException when add more than one child");
+        } catch (IllegalStateException e) {
+            // expected
+        }
+        assertEquals(1, scrollView.getChildCount());
+
+        scrollView.removeAllViews();
+        scrollView = new HorizontalScrollView(mActivity);
+        child0 = new TextView(mActivity);
+        try {
+            scrollView.addView(child0, null);
+            fail("did not throw NullPointerException when LayoutParams is null.");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "addView",
+        args = {View.class, int.class, LayoutParams.class}
+    )
+    @ToBeFixed(bug = "1695243", explanation = "Android API javadocs are incomplete."
+            + " @throws clause should be added into javadoc of "
+            + "HorizontalScrollView#addView(View, int, LayoutParams) when there is already"
+            + " one child in the view or the layoutparams is null")
+    public void testAddViewWithIndexAndLayoutParams() {
+        HorizontalScrollView scrollView = new HorizontalScrollView(mActivity);
+        TextView child0 = new TextView(mActivity);
+        scrollView.addView(child0, 0, new ViewGroup.LayoutParams(200, 100));
+        assertSame(child0, scrollView.getChildAt(0));
+        assertEquals(200, child0.getLayoutParams().width);
+        assertEquals(100, child0.getLayoutParams().height);
+
+        assertEquals(1, scrollView.getChildCount());
+        TextView child1 = new TextView(mActivity);
+        try {
+            scrollView.addView(child1, 0, new ViewGroup.LayoutParams(200, 100));
+            fail("did not throw IllegalStateException when add more than one child");
+        } catch (IllegalStateException e) {
+            // expected
+        }
+        assertEquals(1, scrollView.getChildCount());
+
+        scrollView.removeAllViews();
+        scrollView = new HorizontalScrollView(mActivity);
+        child0 = new TextView(mActivity);
+        try {
+            scrollView.addView(child0, null);
+            fail("did not throw NullPointerException when LayoutParams is null.");
+        } catch (NullPointerException e) {
+            // expected
+        }
+
+        scrollView.removeAllViews();
+        scrollView = new HorizontalScrollView(mActivity);
+        scrollView.addView(child0, -1, new ViewGroup.LayoutParams(300, 150));
+        assertSame(child0, scrollView.getChildAt(0));
+        assertEquals(300, child0.getLayoutParams().width);
+        assertEquals(150, child0.getLayoutParams().height);
+
+        assertEquals(1, scrollView.getChildCount());
+        child1 = new TextView(mActivity);
+        try {
+            scrollView.addView(child1, -1, new ViewGroup.LayoutParams(200, 100));
+            fail("did not throw IllegalStateException when add more than one child");
+        } catch (IllegalStateException e) {
+            // expected
+        }
+        assertEquals(1, scrollView.getChildCount());
+
+        scrollView.removeAllViews();
+        scrollView = new HorizontalScrollView(mActivity);
+        try {
+            scrollView.addView(child0, 1, new ViewGroup.LayoutParams(200, 100));
+            fail("did not throw IndexOutOfBoundsException when index is larger than 0");
+        } catch (IndexOutOfBoundsException e) {
+            // expected
+        }
+    }
+
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "isFillViewport",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setFillViewport",
+            args = {boolean.class}
+        )
+    })
+    public void testAccessFillViewport() {
+        HorizontalScrollView scrollView = new HorizontalScrollView(mActivity);
+        assertFalse(scrollView.isFillViewport());
+        scrollView.layout(0, 0, 100, 100);
+        assertFalse(scrollView.isLayoutRequested());
+
+        scrollView.setFillViewport(false);
+        assertFalse(scrollView.isFillViewport());
+        assertFalse(scrollView.isLayoutRequested());
+
+        scrollView.setFillViewport(true);
+        assertTrue(scrollView.isFillViewport());
+        assertTrue(scrollView.isLayoutRequested());
+
+        scrollView.layout(0, 0, 100, 100);
+        assertFalse(mScrollView.isLayoutRequested());
+
+        scrollView.setFillViewport(false);
+        assertFalse(scrollView.isFillViewport());
+        assertTrue(scrollView.isLayoutRequested());
+    }
+
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "isSmoothScrollingEnabled",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setSmoothScrollingEnabled",
+            args = {boolean.class}
+        )
+    })
+    public void testAccessSmoothScrollingEnabled() throws Throwable {
+        assertTrue(mScrollView.isSmoothScrollingEnabled());
+
+        // scroll immediately
+        mScrollView.setSmoothScrollingEnabled(false);
+        assertFalse(mScrollView.isSmoothScrollingEnabled());
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mScrollView.fullScroll(View.FOCUS_RIGHT);
+            }
+        });
+        assertEquals(SCROLL_RIGHT, mScrollView.getScrollX());
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mScrollView.fullScroll(View.FOCUS_LEFT);
+            }
+        });
+        assertEquals(0, mScrollView.getScrollX());
+
+        // smooth scroll
+        mScrollView.setSmoothScrollingEnabled(true);
+        assertTrue(mScrollView.isSmoothScrollingEnabled());
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mScrollView.fullScroll(View.FOCUS_RIGHT);
+            }
+        });
+        delayedCheckSmoothScrolling(0, SCROLL_RIGHT, 0, 0);
+        assertEquals(SCROLL_RIGHT, mScrollView.getScrollX());
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mScrollView.fullScroll(View.FOCUS_LEFT);
+            }
+        });
+        delayedCheckSmoothScrolling(SCROLL_RIGHT, 0, 0, 0);
+        assertEquals(0, mScrollView.getScrollX());
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "measureChild",
+        args = {View.class, int.class, int.class}
+    )
+    public void testMeasureChild() {
+        MyHorizontalScrollView scrollView = new MyHorizontalScrollView(mActivity);
+
+        MyView child = new MyView(mActivity);
+        child.setBackgroundDrawable(null);
+        child.setPadding(0, 0, 0, 0);
+        child.setMinimumWidth(30);
+        child.setLayoutParams(new ViewGroup.LayoutParams(100, 100));
+        child.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
+                MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY));
+
+        assertEquals(100, child.getMeasuredHeight());
+        assertEquals(100, child.getMeasuredWidth());
+
+        scrollView.measureChild(child, MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
+                MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY));
+
+        assertEquals(100, child.getMeasuredHeight());
+        assertEquals(30, child.getMeasuredWidth());
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "measureChildWithMargins",
+        args = {View.class, int.class, int.class, int.class, int.class}
+    )
+    public void testMeasureChildWithMargins() {
+        MyHorizontalScrollView scrollView = new MyHorizontalScrollView(mActivity);
+
+        MyView child = new MyView(mActivity);
+        child.setBackgroundDrawable(null);
+        child.setPadding(0, 0, 0, 0);
+        child.setMinimumWidth(30);
+        child.setLayoutParams(new ViewGroup.MarginLayoutParams(100, 100));
+        child.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
+                MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY));
+
+        assertEquals(100, child.getMeasuredHeight());
+        assertEquals(100, child.getMeasuredWidth());
+
+        scrollView.measureChildWithMargins(child,
+                MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 5,
+                MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 5);
+
+        assertEquals(100, child.getMeasuredHeight());
+        assertEquals(30, child.getMeasuredWidth());
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "pageScroll",
+        args = {int.class}
+    )
+    @UiThreadTest
+    public void testPageScroll() {
+        mScrollView.setSmoothScrollingEnabled(false);
+        assertEquals(0, mScrollView.getScrollX());
+
+        assertTrue(mScrollView.pageScroll(View.FOCUS_RIGHT));
+        assertEquals(PAGE_WIDTH, mScrollView.getScrollX());
+
+        mScrollView.scrollTo(SCROLL_RIGHT, PAGE_HEIGHT);
+        assertFalse(mScrollView.pageScroll(View.FOCUS_RIGHT));
+        assertEquals(SCROLL_RIGHT, mScrollView.getScrollX());
+
+        assertTrue(mScrollView.pageScroll(View.FOCUS_LEFT));
+        assertEquals(SCROLL_RIGHT - PAGE_WIDTH, mScrollView.getScrollX());
+
+        mScrollView.scrollTo(0, PAGE_HEIGHT);
+        assertFalse(mScrollView.pageScroll(View.FOCUS_LEFT));
+        assertEquals(0, mScrollView.getScrollX());
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "fullScroll",
+        args = {int.class}
+    )
+    @UiThreadTest
+    public void testFullScroll() {
+        mScrollView.setSmoothScrollingEnabled(false);
+        assertEquals(0, mScrollView.getScrollX());
+
+        assertTrue(mScrollView.fullScroll(View.FOCUS_RIGHT));
+        assertEquals(SCROLL_RIGHT, mScrollView.getScrollX());
+
+        assertFalse(mScrollView.fullScroll(View.FOCUS_RIGHT));
+        assertEquals(SCROLL_RIGHT, mScrollView.getScrollX());
+
+        assertTrue(mScrollView.fullScroll(View.FOCUS_LEFT));
+        assertEquals(0, mScrollView.getScrollX());
+
+        assertFalse(mScrollView.fullScroll(View.FOCUS_LEFT));
+        assertEquals(0, mScrollView.getScrollX());
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "arrowScroll",
+        args = {int.class}
+    )
+    @UiThreadTest
+    public void testArrowScroll() {
+        mScrollView.setSmoothScrollingEnabled(false);
+        assertEquals(0, mScrollView.getScrollX());
+
+        int x = mScrollView.getScrollX();
+        while (SCROLL_RIGHT != x) {
+            assertTrue(mScrollView.arrowScroll(View.FOCUS_RIGHT));
+            assertTrue(x <= mScrollView.getScrollX());
+            x = mScrollView.getScrollX();
+        }
+
+        assertFalse(mScrollView.arrowScroll(View.FOCUS_RIGHT));
+        assertEquals(SCROLL_RIGHT, mScrollView.getScrollX());
+
+        x = mScrollView.getScrollX();
+        while (0 != x) {
+            assertTrue(mScrollView.arrowScroll(View.FOCUS_LEFT));
+            assertTrue(x >= mScrollView.getScrollX());
+            x = mScrollView.getScrollX();
+        }
+
+        assertFalse(mScrollView.arrowScroll(View.FOCUS_LEFT));
+        assertEquals(0, mScrollView.getScrollX());
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "smoothScrollBy",
+        args = {int.class, int.class}
+    )
+    public void testSmoothScrollBy() throws Throwable {
+        assertEquals(0, mScrollView.getScrollX());
+        assertEquals(0, mScrollView.getScrollY());
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mScrollView.smoothScrollBy(SCROLL_RIGHT, 0);
+            }
+        });
+        delayedCheckSmoothScrolling(0, SCROLL_RIGHT, 0, 0);
+        assertEquals(SCROLL_RIGHT, mScrollView.getScrollX());
+        assertEquals(0, mScrollView.getScrollY());
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mScrollView.smoothScrollBy(-SCROLL_RIGHT, 0);
+            }
+        });
+        delayedCheckSmoothScrolling(SCROLL_RIGHT, 0, 0, 0);
+        assertEquals(0, mScrollView.getScrollX());
+        assertEquals(0, mScrollView.getScrollY());
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "smoothScrollTo",
+        args = {int.class, int.class}
+    )
+    public void testSmoothScrollTo() throws Throwable {
+        assertEquals(0, mScrollView.getScrollX());
+        assertEquals(0, mScrollView.getScrollY());
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mScrollView.smoothScrollTo(SCROLL_RIGHT, 0);
+            }
+        });
+        delayedCheckSmoothScrolling(0, SCROLL_RIGHT, 0, 0);
+        assertEquals(SCROLL_RIGHT, mScrollView.getScrollX());
+        assertEquals(0, mScrollView.getScrollY());
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mScrollView.smoothScrollTo(0, 0);
+            }
+        });
+        delayedCheckSmoothScrolling(SCROLL_RIGHT, 0, 0, 0);
+        assertEquals(0, mScrollView.getScrollX());
+        assertEquals(0, mScrollView.getScrollY());
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "computeScrollDeltaToGetChildRectOnScreen",
+        args = {android.graphics.Rect.class}
+    )
+    public void testComputeScrollDeltaToGetChildRectOnScreen() {
+        mScrollView.setSmoothScrollingEnabled(false);
+        int edge = mScrollView.getHorizontalFadingEdgeLength();
+
+        // Rect's width is smaller than scroll view
+        Rect rect = new Rect(0, 0, 0, 0);
+        assertEquals(0, mScrollView.computeScrollDeltaToGetChildRectOnScreen(rect));
+
+        rect = new Rect(edge, 0, PAGE_WIDTH, 0);
+        assertEquals(0, mScrollView.computeScrollDeltaToGetChildRectOnScreen(rect));
+
+        mScrollView.scrollTo(0, 0);
+        rect = new Rect(edge + 1, 0, PAGE_WIDTH, 0);
+        assertEquals(edge, mScrollView.computeScrollDeltaToGetChildRectOnScreen(rect));
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "computeHorizontalScrollRange",
+        args = {}
+    )
+    public void testComputeHorizontalScrollRange() {
+        assertTrue(mScrollView.getChildCount() > 0);
+        assertEquals(ITEM_WIDTH * ITEM_COUNT, mScrollView.computeHorizontalScrollRange());
+
+        MyScrollView myScrollView = new MyScrollView(mActivity);
+        assertEquals(0, myScrollView.getChildCount());
+        assertEquals(0, myScrollView.computeVerticalScrollRange());
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "requestChildFocus",
+        args = {View.class, View.class}
+    )
+    @UiThreadTest
+    public void testRequestChildFocus() {
+        mScrollView.setSmoothScrollingEnabled(false);
+
+        View firstChild = mScrollView.findViewById(R.id.first_horizontal_child);
+        View lastChild = mScrollView.findViewById(R.id.last_horizontal_child);
+        firstChild.requestFocus();
+
+        int scrollX = mScrollView.getScrollX();
+        mScrollView.requestChildFocus(lastChild, lastChild);
+        // check scrolling to the child which wants focus
+        assertTrue(mScrollView.getScrollX() > scrollX);
+
+        scrollX = mScrollView.getScrollX();
+        mScrollView.requestChildFocus(firstChild, firstChild);
+        // check scrolling to the child which wants focus
+        assertTrue(mScrollView.getScrollX() < scrollX);
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "requestChildRectangleOnScreen",
+        args = {View.class, Rect.class, boolean.class}
+    )
+    @UiThreadTest
+    public void testRequestChildRectangleOnScreen() {
+        mScrollView.setSmoothScrollingEnabled(false);
+        int edge = mScrollView.getHorizontalFadingEdgeLength();
+
+        View child = mScrollView.findViewById(R.id.first_horizontal_child);
+        final Rect originalRect = new Rect(0, 0, 10, 10);
+        final Rect newRect = new Rect(ITEM_WIDTH - 10, ITEM_HEIGHT - 10, ITEM_WIDTH, ITEM_HEIGHT);
+
+        assertFalse(mScrollView.requestChildRectangleOnScreen(child, originalRect, true));
+        assertEquals(0, mScrollView.getScrollX());
+        assertEquals(0, mScrollView.getScrollY());
+
+        assertTrue(mScrollView.requestChildRectangleOnScreen(child, newRect, true));
+        assertEquals(ITEM_WIDTH - mScrollView.getWidth() + edge, mScrollView.getScrollX());
+        assertEquals(0, mScrollView.getScrollY());
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "The method is simply called to make sure no exception is thrown.",
+        method = "requestLayout",
+        args = {}
+    )
+    @UiThreadTest
+    public void testRequestLayout() {
+        mScrollView.requestLayout();
+
+        assertTrue(mScrollView.isLayoutRequested());
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "fling",
+        args = {int.class}
+    )
+    @ToBeFixed(bug = "1695243", explanation = "As javadoc says, scrolls towards the left "
+            + "when velocityX is positive. But it scrolls to right actually.")
+    public void testFling() throws Throwable {
+        mScrollView.setSmoothScrollingEnabled(true);
+        assertEquals(0, mScrollView.getScrollX());
+
+        // fling towards right
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mScrollView.fling(2000);
+            }
+        });
+        delayedCheckFling(0, true);
+
+        final int currentX = mScrollView.getScrollX();
+        // fling towards left
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mScrollView.fling(-2000);
+            }
+        });
+        delayedCheckFling(currentX, false);
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "scrollTo",
+        args = {int.class, int.class}
+    )
+    @ToBeFixed(bug = "1695243", explanation = "scrollTo can not affect y.")
+    @UiThreadTest
+    public void testScrollTo() {
+        mScrollView.setSmoothScrollingEnabled(false);
+
+        mScrollView.scrollTo(10, 10);
+        assertEquals(0, mScrollView.getScrollY());
+        assertEquals(10, mScrollView.getScrollX());
+
+        mScrollView.scrollTo(PAGE_WIDTH, PAGE_HEIGHT);
+        assertEquals(0, mScrollView.getScrollY());
+        assertEquals(PAGE_WIDTH, mScrollView.getScrollX());
+
+        mScrollView.scrollTo(SCROLL_RIGHT, 0);
+        assertEquals(0, mScrollView.getScrollY());
+        assertEquals(SCROLL_RIGHT, mScrollView.getScrollX());
+
+        // reach the top and left
+        mScrollView.scrollTo(-10, -10);
+        assertEquals(0, mScrollView.getScrollY());
+        assertEquals(0, mScrollView.getScrollX());
+    }
+
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getLeftFadingEdgeStrength",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getRightFadingEdgeStrength",
+            args = {}
+        )
+    })
+    public void testGetHorizontalFadingEdgeStrengths() {
+        assertTrue(mScrollView.getChildCount() > 0);
+        assertTrue(mScrollView.getLeftFadingEdgeStrength() <= 1.0f);
+        assertTrue(mScrollView.getLeftFadingEdgeStrength() >= 0.0f);
+        assertTrue(mScrollView.getRightFadingEdgeStrength() <= 1.0f);
+        assertTrue(mScrollView.getRightFadingEdgeStrength() >= 0.0f);
+
+        MyScrollView myScrollView = new MyScrollView(mActivity);
+        assertEquals(0, myScrollView.getChildCount());
+        assertTrue(mScrollView.getLeftFadingEdgeStrength() <= 1.0f);
+        assertTrue(mScrollView.getLeftFadingEdgeStrength() >= 0.0f);
+        assertTrue(mScrollView.getRightFadingEdgeStrength() <= 1.0f);
+        assertTrue(mScrollView.getRightFadingEdgeStrength() >= 0.0f);
+    }
+
+    @TestTargetNew(
+        level = TestLevel.NOT_NECESSARY,
+        method = "onLayout",
+        args = {boolean.class, int.class, int.class, int.class, int.class}
+    )
+    public void testOnLayout() {
+        // onLayout() is implementation details, do NOT test
+    }
+
+    @TestTargetNew(
+        level = TestLevel.NOT_NECESSARY,
+        method = "onMeasure",
+        args = {int.class, int.class}
+    )
+    public void testOnMeasure() {
+        // onMeasure() is implementation details, do NOT test
+    }
+
+    @TestTargetNew(
+        level = TestLevel.NOT_NECESSARY,
+        method = "executeKeyEvent",
+        args = {KeyEvent.class}
+    )
+    public void testExecuteKeyEvent() {
+        // executeKeyEvent() is implementation details, do NOT test
+    }
+
+    @TestTargetNew(
+        level = TestLevel.NOT_NECESSARY,
+        method = "onRequestFocusInDescendants",
+        args = {int.class, Rect.class}
+    )
+    public void testOnRequestFocusInDescendants() {
+        // onRequestFocusInDescendants() is implementation details, do NOT test
+    }
+
+    @TestTargetNew(
+        level = TestLevel.NOT_NECESSARY,
+        method = "onSizeChanged",
+        args = {int.class, int.class, int.class, int.class}
+    )
+    public void testOnSizeChanged() {
+        // onSizeChanged() is implementation details, do NOT test
+    }
+
+    @TestTargetNew(
+        level = TestLevel.NOT_NECESSARY,
+        method = "dispatchKeyEvent",
+        args = {KeyEvent.class}
+    )
+    public void testDispatchKeyEvent() {
+        // dispatchKeyEvent() is implementation details, do NOT test
+    }
+
+    @TestTargetNew(
+        level = TestLevel.NOT_NECESSARY,
+        method = "onInterceptTouchEvent",
+        args = {MotionEvent.class}
+    )
+    public void testOnInterceptTouchEvent() {
+        // onInterceptTouchEvent() is implementation details, do NOT test
+    }
+
+    @TestTargetNew(
+        level = TestLevel.NOT_NECESSARY,
+        method = "onTouchEvent",
+        args = {MotionEvent.class}
+    )
+    public void testOnTouchEvent() {
+        // onTouchEvent() is implementation details, do NOT test
+    }
+
+    @TestTargetNew(
+        level = TestLevel.NOT_NECESSARY,
+        method = "computeScroll",
+        args = {}
+    )
+    public void testComputeScroll() {
+        // computeScroll() is implementation details, do NOT test
+    }
+
+    private boolean isInRange(int current, int from, int to) {
+        if (from < to) {
+            return current >= from && current <= to;
+        }
+        return current <= from && current >= to;
+    }
+
+    private void delayedCheckSmoothScrolling(final int fromX, final int toX,
+            final int fromY, final int toY) {
+
+        if (fromX == toX && fromY == toY) {
+            return;
+        }
+
+        if (fromY != toY) {
+            new DelayedCheck() {
+                @Override
+                protected boolean check() {
+                    return isInRange(mScrollView.getScrollY(), fromY, toY);
+                }
+            }.run();
+        }
+
+        if (fromX != toX) {
+            new DelayedCheck() {
+                @Override
+                protected boolean check() {
+                    return isInRange(mScrollView.getScrollX(), fromX, toX);
+                }
+            }.run();
+        }
+
+        new DelayedCheck() {
+            @Override
+            protected boolean check() {
+                return toX == mScrollView.getScrollX() && toY == mScrollView.getScrollY();
+            }
+        }.run();
+    }
+
+    private void delayedCheckFling(final int startPosition, final boolean movingRight) {
+        new DelayedCheck() {
+            @Override
+            protected boolean check() {
+                if (movingRight) {
+                    return mScrollView.getScrollX() > startPosition;
+                }
+                return mScrollView.getScrollX() < startPosition;
+            }
+        };
+
+        new DelayedCheck() {
+            private int mPreviousScrollX = mScrollView.getScrollX();
+
+            @Override
+            protected boolean check() {
+                if (mScrollView.getScrollX() == mPreviousScrollX) {
+                    return true;
+                } else {
+                    mPreviousScrollX = mScrollView.getScrollX();
+                    return false;
+                }
+            }
+        }.run();
+    }
+
+    private static class MyView extends View {
+        public MyView(Context context) {
+            super(context);
+        }
+    }
+}