TIF: Add test case for TvView.TvInputCallback#onDisconnected

Bug: 21422107
Change-Id: Ida0711e14fa43f6633d247a10e3ec5add317b9cf
diff --git a/tests/tests/tv/AndroidManifest.xml b/tests/tests/tv/AndroidManifest.xml
index cc64363..35b7331 100644
--- a/tests/tests/tv/AndroidManifest.xml
+++ b/tests/tests/tv/AndroidManifest.xml
@@ -85,16 +85,6 @@
                        android:resource="@xml/stub_tv_input_service" />
         </service>
 
-        <service android:name="android.media.tv.cts.TvInputServiceTest$FaultyTvInputService"
-                 android:permission="android.permission.BIND_TV_INPUT"
-                 android:process=":faultyTvInputService">
-            <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>
-
         <service android:name="android.media.tv.cts.HardwareSessionTest$HardwareProxyTvInputService"
                  android:permission="android.permission.BIND_TV_INPUT">
             <intent-filter>
@@ -104,6 +94,15 @@
                        android:resource="@xml/stub_tv_input_service" />
         </service>
 
+        <service android:name="android.media.tv.cts.FaultyTvInputService"
+                 android:permission="android.permission.BIND_TV_INPUT"
+                 android:process=":faultyTvInputService">
+            <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>
diff --git a/tests/tests/tv/src/android/media/tv/cts/FaultyTvInputService.java b/tests/tests/tv/src/android/media/tv/cts/FaultyTvInputService.java
new file mode 100644
index 0000000..bc66ee9
--- /dev/null
+++ b/tests/tests/tv/src/android/media/tv/cts/FaultyTvInputService.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2016 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.content.Context;
+import android.net.Uri;
+import android.os.Process;
+import android.view.Surface;
+
+/**
+ * A TvInputService for testing crash on TV input application.
+ */
+public class FaultyTvInputService extends StubTvInputService {
+    @Override
+    public Session onCreateSession(String inputId) {
+        return new FaultySession(this);
+    }
+
+    @Override
+    public RecordingSession onCreateRecordingSession(String inputId) {
+        return new FaultyRecordingSession(this);
+    }
+
+    public static class FaultySession extends Session {
+        FaultySession(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onRelease() { }
+
+        @Override
+        public boolean onTune(Uri ChannelUri) {
+            Process.killProcess(Process.myPid());
+            return false;
+        }
+
+        @Override
+        public boolean onSetSurface(Surface surface) {
+            return false;
+        }
+
+        @Override
+        public void onSetCaptionEnabled(boolean enabled) { }
+
+        @Override
+        public void onSetStreamVolume(float volume) { }
+    }
+
+    public static class FaultyRecordingSession extends RecordingSession {
+        FaultyRecordingSession(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onTune(Uri channelUri) {
+            Process.killProcess(Process.myPid());
+        }
+
+        @Override
+        public void onStartRecording(Uri programHint) { }
+
+        @Override
+        public void onStopRecording() { }
+
+        @Override
+        public void onRelease() { }
+    }
+}
diff --git a/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java b/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java
index 9b60967..597df50 100644
--- a/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java
@@ -32,7 +32,6 @@
 import android.media.tv.cts.TvInputServiceTest.CountingTvInputService.CountingRecordingSession;
 import android.net.Uri;
 import android.os.Bundle;
-import android.os.Process;
 import android.os.SystemClock;
 import android.test.ActivityInstrumentationTestCase2;
 import android.view.InputDevice;
@@ -1122,31 +1121,4 @@
             mDisconnectedCount = 0;
         }
     }
-
-    public static class FaultyTvInputService extends StubTvInputService {
-        @Override
-        public RecordingSession onCreateRecordingSession(String inputId) {
-            return new FaultyRecordingSession(this);
-        }
-
-        public static class FaultyRecordingSession extends RecordingSession {
-            FaultyRecordingSession(Context context) {
-                super(context);
-            }
-
-            @Override
-            public void onTune(Uri channelUri) {
-                Process.killProcess(android.os.Process.myPid());
-            }
-
-            @Override
-            public void onStartRecording(Uri programHint) { }
-
-            @Override
-            public void onStopRecording() { }
-
-            @Override
-            public void onRelease() { }
-        }
-    }
 }
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 6226435..79c0760 100644
--- a/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java
@@ -55,6 +55,7 @@
     private Instrumentation mInstrumentation;
     private TvInputManager mManager;
     private TvInputInfo mStubInfo;
+    private TvInputInfo mFaultyStubInfo;
     private final MockCallback mCallback = new MockCallback();
 
     private static class MockCallback extends TvInputCallback {
@@ -63,6 +64,7 @@
         private final Map<String, Integer> mTracksGenerationMap = new ArrayMap<>();
         private final Object mLock = new Object();
         private volatile int mConnectionFailedCount;
+        private volatile int mDisconnectedCount;
 
         public boolean isVideoAvailable(String inputId) {
             synchronized (mLock) {
@@ -82,20 +84,30 @@
             }
         }
 
-        public void resetConnectionFailedCount() {
+        public void resetCount() {
             mConnectionFailedCount = 0;
+            mDisconnectedCount = 0;
         }
 
         public int getConnectionFailedCount() {
             return mConnectionFailedCount;
         }
 
+        public int getDisconnectedCount() {
+            return mDisconnectedCount;
+        }
+
         @Override
         public void onConnectionFailed(String inputId) {
             mConnectionFailedCount++;
         }
 
         @Override
+        public void onDisconnected(String inputId) {
+            mDisconnectedCount++;
+        }
+
+        @Override
         public void onVideoAvailable(String inputId) {
             synchronized (mLock) {
                 mVideoAvailableMap.put(inputId, true);
@@ -163,6 +175,11 @@
         for (TvInputInfo info : mManager.getTvInputList()) {
             if (info.getServiceInfo().name.equals(StubTunerTvInputService.class.getName())) {
                 mStubInfo = info;
+            }
+            if (info.getServiceInfo().name.equals(FaultyTvInputService.class.getName())) {
+                mFaultyStubInfo = info;
+            }
+            if (mStubInfo != null && mFaultyStubInfo != null) {
                 break;
             }
         }
@@ -421,7 +438,7 @@
         if (!Utils.hasTvInputFramework(getActivity())) {
             return;
         }
-        mCallback.resetConnectionFailedCount();
+        mCallback.resetCount();
         mTvView.tune("invalid_input_id", TvContract.Channels.CONTENT_URI);
         mInstrumentation.waitForIdleSync();
         new PollingCheck(TIME_OUT_MS) {
@@ -432,6 +449,21 @@
         }.run();
     }
 
+    public void testDisconnected() throws Throwable {
+        if (!Utils.hasTvInputFramework(getActivity())) {
+            return;
+        }
+        mCallback.resetCount();
+        Uri fakeChannelUri = TvContract.buildChannelUri(0);
+        mTvView.tune(mFaultyStubInfo.getId(), fakeChannelUri);
+        new PollingCheck(TIME_OUT_MS) {
+            @Override
+            protected boolean check() {
+                return mCallback.getDisconnectedCount() > 0;
+            }
+        }.run();
+    }
+
     public void testSetZOrderMediaOverlay() throws Exception {
         if (!Utils.hasTvInputFramework(getActivity())) {
             return;