Add TvInputServiceTest, CTS for TvInputService.

Bug: 14070824, Bug: 16409584
Change-Id: I89b1be98185f9761a3c43ed1035222f07a588b67
diff --git a/tests/tests/tv/AndroidManifest.xml b/tests/tests/tv/AndroidManifest.xml
index 33c8e0b..66f4ac0 100644
--- a/tests/tests/tv/AndroidManifest.xml
+++ b/tests/tests/tv/AndroidManifest.xml
@@ -66,6 +66,15 @@
                        android:resource="@xml/stub_tv_input_service" />
         </service>
 
+        <service android:name="android.media.tv.cts.TvInputServiceTest$CountingTvInputService"
+                 android:permission="android.permission.BIND_TV_INPUT">
+            <intent-filter>
+                <action android:name="android.media.tv.TvInputService" />
+            </intent-filter>
+            <meta-data android:name="android.media.tv.input"
+                       android:resource="@xml/stub_tv_input_service" />
+        </service>
+
         <activity android:name="android.media.tv.cts.TvViewStubActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
diff --git a/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java b/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java
new file mode 100644
index 0000000..dc6e74d
--- /dev/null
+++ b/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2014 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.media.tv.cts;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.cts.util.PollingCheck;
+import android.database.Cursor;
+import android.test.ActivityInstrumentationTestCase2;
+import android.media.tv.TvContentRating;
+import android.media.tv.TvContract;
+import android.media.tv.TvInputInfo;
+import android.media.tv.TvInputManager;
+import android.media.tv.TvInputService;
+import android.media.tv.TvTrackInfo;
+import android.media.tv.TvView;
+import android.media.tv.TvInputService.Session;
+import android.media.tv.cts.TvInputServiceTest.CountingTvInputService.CountingSession;
+import android.net.Uri;
+import android.util.ArrayMap;
+import android.util.SparseIntArray;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.Surface;
+
+import com.android.cts.tv.R;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Test {@link android.media.tv.TvInputService}.
+ */
+public class TvInputServiceTest extends ActivityInstrumentationTestCase2<TvViewStubActivity> {
+    /** The maximum time to wait for an operation. */
+    private static final long TIME_OUT = 15000L;
+
+    private TvView mTvView;
+    private Activity mActivity;
+    private Instrumentation mInstrumentation;
+    private TvInputManager mManager;
+    private TvInputInfo mStubInfo;
+    private final StubListener mListener = new StubListener();
+
+    private static class StubListener extends TvView.TvInputListener {
+        private int mChannelRetunedCount;
+        private int mVideoAvailableCount;
+        private int mVideoUnavailableCount;
+        private int mTrackSelectedCount;
+        private int mTrackChangedCount;
+        private int mContentAllowedCount;
+        private int mContentBlockedCount;
+
+        @Override
+        public void onChannelRetuned(String inputId, Uri channelUri) {
+            mChannelRetunedCount++;
+        }
+
+        @Override
+        public void onVideoAvailable(String inputId) {
+            mVideoAvailableCount++;
+        }
+
+        @Override
+        public void onVideoUnavailable(String inputId, int reason) {
+            mVideoUnavailableCount++;
+        }
+
+        @Override
+        public void onTrackSelected(String inputId, int type, String trackId) {
+            mTrackSelectedCount++;
+        }
+
+        @Override
+        public void onTracksChanged(String inputId, List<TvTrackInfo> trackList) {
+            mTrackChangedCount++;
+        }
+
+        @Override
+        public void onContentAllowed(String inputId) {
+            mContentAllowedCount++;
+        }
+
+        @Override
+        public void onContentBlocked(String inputId, TvContentRating rating) {
+            mContentBlockedCount++;
+        }
+    }
+
+    public TvInputServiceTest() {
+        super(TvViewStubActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mActivity = getActivity();
+        mInstrumentation = getInstrumentation();
+        mTvView = (TvView) mActivity.findViewById(R.id.tvview);
+        mManager = (TvInputManager) mActivity.getSystemService(Context.TV_INPUT_SERVICE);
+        for (TvInputInfo info : mManager.getTvInputList()) {
+            if (info.getServiceInfo().name.equals(CountingTvInputService.class.getName())) {
+                mStubInfo = info;
+                break;
+            }
+        }
+        assertNotNull(mStubInfo);
+        mTvView.setTvInputListener(mListener);
+
+        CountingTvInputService.sSession = null;
+    }
+
+    public void testTvInputService() throws Throwable {
+        verifyCommandTune();
+        verifyCommandSetStreamVolume();
+        verifyCommandSetCaptionEnabled();
+        verifyCommandSelectTrack();
+        verifyCommandDispatchKeyEvent();
+        verifyCallbackChannelRetuned();
+        verifyCallbackVideoAvailable();
+        verifyCallbackVideoUnavailable();
+        verifyCallbackTracksChanged();
+        verifyCallbackTrackSelected();
+        verifyCallbackContentAllowed();
+        verifyCallbackContentBlocked();
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mTvView.reset();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    public void verifyCommandTune() {
+        Uri fakeChannelUri = TvContract.buildChannelUri(0);
+        mTvView.tune(mStubInfo.getId(), fakeChannelUri);
+        mInstrumentation.waitForIdleSync();
+        new PollingCheck(TIME_OUT) {
+            @Override
+            protected boolean check() {
+                CountingSession session = CountingTvInputService.sSession;
+                return session != null && session.mTuneCount > 0;
+            }
+        }.run();
+    }
+
+    public void verifyCommandSetStreamVolume() {
+        mTvView.setStreamVolume(1.0f);;
+        mInstrumentation.waitForIdleSync();
+        new PollingCheck(TIME_OUT) {
+            @Override
+            protected boolean check() {
+                CountingSession session = CountingTvInputService.sSession;
+                return session != null && session.mSetStreamVolumeCount > 0;
+            }
+        }.run();
+    }
+
+    public void verifyCommandSetCaptionEnabled() {
+        mTvView.setCaptionEnabled(true);
+        mInstrumentation.waitForIdleSync();
+        new PollingCheck(TIME_OUT) {
+            @Override
+            protected boolean check() {
+                CountingSession session = CountingTvInputService.sSession;
+                return session != null && session.mSetCaptionEnabledCount > 0;
+            }
+        }.run();
+    }
+
+    public void verifyCommandSelectTrack() {
+        mTvView.selectTrack(TvTrackInfo.TYPE_AUDIO, "dummyTrackId");
+        mInstrumentation.waitForIdleSync();
+        new PollingCheck(TIME_OUT) {
+            @Override
+            protected boolean check() {
+                CountingSession session = CountingTvInputService.sSession;
+                return session != null && session.mSetStreamVolumeCount > 0;
+            }
+        }.run();
+    }
+
+    public void verifyCommandDispatchKeyEvent() {
+        mTvView.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_K));
+        mInstrumentation.waitForIdleSync();
+        new PollingCheck(TIME_OUT) {
+            @Override
+            protected boolean check() {
+                CountingSession session = CountingTvInputService.sSession;
+                return session != null && session.mKeyDownCount > 0;
+            }
+        }.run();
+    }
+
+    public void verifyCallbackChannelRetuned() {
+        CountingSession session = CountingTvInputService.sSession;
+        assertNotNull(session);
+        Uri fakeChannelUri = TvContract.buildChannelUri(0);
+        session.notifyChannelRetuned(fakeChannelUri);
+        new PollingCheck(TIME_OUT) {
+            @Override
+            protected boolean check() {
+                return mListener.mChannelRetunedCount > 0;
+            }
+        }.run();
+    }
+
+    public void verifyCallbackVideoAvailable() {
+        CountingSession session = CountingTvInputService.sSession;
+        assertNotNull(session);
+        session.notifyVideoAvailable();
+        new PollingCheck(TIME_OUT) {
+            @Override
+            protected boolean check() {
+                return mListener.mVideoAvailableCount > 0;
+            }
+        }.run();
+    }
+
+    public void verifyCallbackVideoUnavailable() {
+        CountingSession session = CountingTvInputService.sSession;
+        assertNotNull(session);
+        session.notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_TUNING);
+        new PollingCheck(TIME_OUT) {
+            @Override
+            protected boolean check() {
+                return mListener.mVideoUnavailableCount > 0;
+            }
+        }.run();
+    }
+
+    public void verifyCallbackTracksChanged() {
+        CountingSession session = CountingTvInputService.sSession;
+        assertNotNull(session);
+        session.notifyTracksChanged(new ArrayList<TvTrackInfo>());
+        new PollingCheck(TIME_OUT) {
+            @Override
+            protected boolean check() {
+                return mListener.mTrackChangedCount > 0;
+            }
+        }.run();
+    }
+
+    public void verifyCallbackTrackSelected() {
+        CountingSession session = CountingTvInputService.sSession;
+        assertNotNull(session);
+        session.notifyTrackSelected(TvTrackInfo.TYPE_SUBTITLE, null);
+        new PollingCheck(TIME_OUT) {
+            @Override
+            protected boolean check() {
+                return mListener.mTrackSelectedCount > 0;
+            }
+        }.run();
+    }
+
+    public void verifyCallbackContentAllowed() {
+        CountingSession session = CountingTvInputService.sSession;
+        assertNotNull(session);
+        session.notifyContentAllowed();
+        new PollingCheck(TIME_OUT) {
+            @Override
+            protected boolean check() {
+                return mListener.mContentAllowedCount > 0;
+            }
+        }.run();
+    }
+
+    public void verifyCallbackContentBlocked() {
+        CountingSession session = CountingTvInputService.sSession;
+        assertNotNull(session);
+        TvContentRating rating = TvContentRating.createRating("android.media.tv", "US_TVPG",
+                "US_TVPG_TV_MA", "US_TVPG_S", "US_TVPG_V");
+        session.notifyContentBlocked(rating);
+        new PollingCheck(TIME_OUT) {
+            @Override
+            protected boolean check() {
+                return mListener.mContentBlockedCount > 0;
+            }
+        }.run();
+    }
+
+    public static class CountingTvInputService extends StubTvInputService {
+        static CountingTvInputService sInstance;
+        static CountingSession sSession;
+
+        @Override
+        public Session onCreateSession(String inputId) {
+            sSession = new CountingSession(this);
+            return sSession;
+        }
+
+        public static class CountingSession extends Session {
+            public volatile int mTuneCount;
+            public volatile int mSetStreamVolumeCount;
+            public volatile int mSetCaptionEnabledCount;
+            public volatile int mSelectTrackCount;
+            public volatile int mKeyDownCount;
+
+            CountingSession(Context context) {
+                super(context);
+            }
+
+            @Override
+            public void onRelease() {
+            }
+
+            @Override
+            public boolean onSetSurface(Surface surface) {
+                return false;
+            }
+
+            @Override
+            public boolean onTune(Uri channelUri) {
+                mTuneCount++;
+                return false;
+            }
+
+            @Override
+            public void onSetStreamVolume(float volume) {
+                mSetStreamVolumeCount++;
+            }
+
+            @Override
+            public void onSetCaptionEnabled(boolean enabled) {
+                mSetCaptionEnabledCount++;
+            }
+
+            @Override
+            public boolean onSelectTrack(int type, String id) {
+                mSelectTrackCount++;
+                return false;
+            }
+
+            @Override
+            public boolean onKeyDown(int keyCode, KeyEvent event) {
+                mKeyDownCount++;
+                return false;
+            }
+        }
+    }
+}
diff --git a/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java b/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java
index c4e8228..1092d9e 100644
--- a/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java
@@ -38,7 +38,7 @@
 import java.util.Map;
 
 /**
- * Test {@link TvView}.
+ * Test {@link android.media.tv.TvView}.
  */
 public class TvViewTest extends ActivityInstrumentationTestCase2<TvViewStubActivity> {
     /** The maximum time to wait for an operation. */