TV: Add parental control tests to CtsVerifier

- Test if parental control settings really go through framework.

Bug: 18069561
Change-Id: I87bfc9f6f5400e241200e63fbda2d8979c85d3d1
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 92a2367..d5cd98b 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -1377,7 +1377,19 @@
             <meta-data android:name="test_category" android:value="@string/test_category_other" />
         </activity>
 
-        <activity android:name=".tv.TvInputDiscoveryTestActivity" android:label="@string/tv">
+        <activity android:name=".tv.TvInputDiscoveryTestActivity"
+                android:label="@string/tv_input_discover_test">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_tv" />
+            <meta-data android:name="test_required_features"
+                    android:value="android.software.live_tv" />
+        </activity>
+
+        <activity android:name=".tv.ParentalControlTestActivity"
+                android:label="@string/tv_parental_control_test">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
@@ -1408,6 +1420,14 @@
                 android:resource="@xml/mock_tv_input_service" />
         </service>
 
+        <receiver android:name=".tv.TvInputReceiver">
+            <intent-filter>
+                <action android:name="android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS" />
+            </intent-filter>
+            <meta-data android:name="android.media.tv.metadata.CONTENT_RATING_SYSTEMS"
+                android:resource="@xml/mock_content_rating_systems" />
+        </receiver>
+
     </application>
 
 </manifest>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 757951c..4c6d3df 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -1402,22 +1402,23 @@
     <string name="js_any_connectivity_test">Device with no connectivity will not execute a job with an unmetered connectivity constraint.</string>
     <string name="js_no_connectivity_test">Device with no connectivity will still execute a job with no connectivity constraints.</string>
 
-    <!-- String for TV app Tests -->
-    <string name="tv">TV App Behavior Verifier</string>
-    <string name="tv_info">
-    This test verifies that the default TV app is invoked via intents and issues appropriate
-    calls to framework APIs, so that TV input apps work properly with the default TV app.
-    </string>
+    <!-- String for Live Channels app Tests -->
 
-    <string name="tv_input_discover_test">TV app input discoverability test</string>
+    <string name="tv_input_discover_test">3rd-party TV input app discoverability test</string>
+    <string name="tv_input_discover_test_info">
+    This test verifies that the pre-loaded Live Channels app is invoked via intents and issues
+    appropriate calls to framework APIs, so that TV input apps work properly with the pre-loaded
+    Live Channels app.
+    </string>
     <string name="tv_input_discover_test_go_to_setup">
-    Press the \"Launch TV app\" button, and set up the newly installed TV input: \"CTS Verifier\".
+    Press the \"Launch Live Channels\" button, and set up the newly installed TV input:
+    \"CTS Verifier\".
     </string>
     <string name="tv_input_discover_test_verify_setup">
     Setup activity must have been started.
     </string>
     <string name="tv_input_discover_test_tune_to_channel">
-    Press the \"Launch TV app\" button, and tune to the channel named \"Dummy\" from
+    Press the \"Launch Live Channels\" button, and tune to the channel named \"Dummy\" from
     \"CTS Verifier\" input. If necessary, configure the channel to be visible.
     </string>
     <string name="tv_input_discover_test_verify_tune">
@@ -1428,8 +1429,38 @@
     when you tune to the \"Dummy\" channel.
     </string>
 
-    <string name="tv_launch_tv_app">Launch TV app</string>
+    <string name="tv_parental_control_test">Live Channels app parental control test</string>
+    <string name="tv_parental_control_test_info">
+    This test verifies that the default Live Channels app invokes proper parental control APIs in
+    the framework.
+    </string>
+    <string name="tv_parental_control_test_turn_on_parental_control">
+    Press the \"Launch Live Channels\" button, and turn on the parental control. If it\'s on
+    already, turn it off and on again.
+    </string>
+    <string name="tv_parental_control_test_verify_receive_broadcast1">
+    TV input service must have received ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED broadcast.
+    </string>
+    <string name="tv_parental_control_test_block_tv_ma">
+    Press the \"Launch Live Channels\" button, and block \"Fake\" rating for \"CtsVerifier\" rating
+    system in the parental control settings. You may have to enable the rating system if it is
+    disabled by default. If it\'s already blocked, unblock, save, and then block again.
+    </string>
+    <string name="tv_parental_control_test_verify_receive_broadcast2">
+    TV input service must have received ACTION_BLOCKED_RATINGS_CHANGED broadcast.
+    </string>
+    <string name="tv_parental_control_test_block_unblock">
+    Press the \"Launch Live Channels\" button; verify that the channel is blocked visually.
+    Try unblock the screen by entering PIN; verify that it\'s unblocked visually.
+    </string>
+
+    <string name="tv_launch_tv_app">Launch Live Channels</string>
+    <string name="tv_channel_not_found">
+    CtsVerifier channel is not set up. Please set up before proceeding.
+    </string>
+
     <string name="overlay_view_text">Overlay View Dummy Text</string>
+    <string name="fake_rating">Fake</string>
 
     <!-- A list of fully-qualified test classes that should not be run. -->
     <string-array name="disabled_tests" />
diff --git a/apps/CtsVerifier/res/xml/mock_content_rating_systems.xml b/apps/CtsVerifier/res/xml/mock_content_rating_systems.xml
new file mode 100644
index 0000000..245d7f5
--- /dev/null
+++ b/apps/CtsVerifier/res/xml/mock_content_rating_systems.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright 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.
+-->
+
+<rating-system-definitions xmlns:android="http://schemas.android.com/apk/res/android"
+    android:versionCode="1">
+    <rating-system-definition android:name="CTS_VERIFIER"
+        android:title="CtsVerifier"
+        android:description="@string/app_name">
+        <rating-definition android:name="MOCK_FAKE"
+            android:title="Fake"
+            android:contentAgeHint="0"
+            android:description="@string/fake_rating" />
+    </rating-system-definition>
+</rating-system-definitions>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputService.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputService.java
index ae0a699..a6bb01a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputService.java
@@ -18,35 +18,101 @@
 
 import com.android.cts.verifier.R;
 
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.media.tv.TvContentRating;
+import android.media.tv.TvInputManager;
 import android.media.tv.TvInputService;
 import android.net.Uri;
-import android.util.Pair;
+import android.os.Handler;
+import android.os.Looper;
 import android.view.Surface;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.TextView;
 
+import com.android.cts.verifier.R;
+
 public class MockTvInputService extends TvInputService {
     private static final String TAG = "MockTvInputService";
 
     private static Object sLock = new Object();
-    private static Pair<View, Runnable> sTuneCallback = null;
-    private static Pair<View, Runnable> sOverlayViewCallback = null;
+    private static Callback sTuneCallback = null;
+    private static Callback sOverlayViewCallback = null;
+    private static Callback sBroadcastCallback = null;
+    private static String sExpectedBroadcastAction = null;
+    private static Callback sUnblockContentCallback = null;
+    private static TvContentRating sRating = null;
+
+    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            synchronized (sLock) {
+                if (sBroadcastCallback != null) {
+                    if (intent.getAction().equals(sExpectedBroadcastAction)) {
+                        sBroadcastCallback.post();
+                        sBroadcastCallback = null;
+                        sExpectedBroadcastAction = null;
+                    }
+                }
+            }
+        }
+    };
 
     static void expectTune(View postTarget, Runnable successCallback) {
         synchronized (sLock) {
-            sTuneCallback = Pair.create(postTarget, successCallback);
+            sTuneCallback = new Callback(postTarget, successCallback);
+        }
+    }
+
+    static void expectBroadcast(View postTarget, String action, Runnable successCallback) {
+        synchronized (sLock) {
+            sBroadcastCallback = new Callback(postTarget, successCallback);
+            sExpectedBroadcastAction = action;
+        }
+    }
+
+    static void expectUnblockContent(View postTarget, Runnable successCallback) {
+        synchronized (sLock) {
+            sUnblockContentCallback = new Callback(postTarget, successCallback);
+        }
+    }
+
+    static void setBlockRating(TvContentRating rating) {
+        synchronized (sLock) {
+            sRating = rating;
         }
     }
 
     static void expectOverlayView(View postTarget, Runnable successCallback) {
         synchronized (sLock) {
-            sOverlayViewCallback = Pair.create(postTarget, successCallback);
+            sOverlayViewCallback = new Callback(postTarget, successCallback);
         }
     }
 
     @Override
+    public void onCreate() {
+        super.onCreate();
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(TvInputManager.ACTION_BLOCKED_RATINGS_CHANGED);
+        intentFilter.addAction(TvInputManager.ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED);
+        registerReceiver(mBroadcastReceiver, intentFilter);
+    }
+
+    @Override
+    public void onDestroy() {
+        unregisterReceiver(mBroadcastReceiver);
+        super.onDestroy();
+    }
+
+    @Override
     public Session onCreateSession(String inputId) {
         Session session = new MockSessionImpl(this);
         session.setOverlayViewEnabled(true);
@@ -54,7 +120,8 @@
     }
 
     private static class MockSessionImpl extends Session {
-        private Context mContext;
+        private final Context mContext;
+        private Surface mSurface = null;
 
         private MockSessionImpl(Context context) {
             super(context);
@@ -65,6 +132,28 @@
         public void onRelease() {
         }
 
+        private void draw() {
+            Surface surface = mSurface;
+            if (surface == null) return;
+            if (!surface.isValid()) return;
+
+            Canvas c = surface.lockCanvas(null);
+            if (c == null) return;
+            try {
+                Bitmap b = BitmapFactory.decodeResource(
+                        mContext.getResources(), R.drawable.icon);
+                int srcWidth = b.getWidth();
+                int srcHeight = b.getHeight();
+                int dstWidth = c.getWidth();
+                int dstHeight = c.getHeight();
+                c.drawColor(Color.BLACK);
+                c.drawBitmap(b, new Rect(0, 0, srcWidth, srcHeight),
+                        new Rect(10, 10, dstWidth - 10, dstHeight - 10), null);
+            } finally {
+                surface.unlockCanvasAndPost(c);
+            }
+        }
+
         @Override
         public View onCreateOverlayView() {
             LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
@@ -75,13 +164,13 @@
                 @Override
                 public void onLayoutChange(View v, int left, int top, int right, int bottom,
                         int oldLeft, int oldTop, int oldRight, int oldBottom) {
-                    Pair<View, Runnable> overlayViewCallback = null;
+                    Callback overlayViewCallback = null;
                     synchronized (sLock) {
                         overlayViewCallback = sOverlayViewCallback;
                         sOverlayViewCallback = null;
                     }
                     if (overlayViewCallback != null) {
-                        overlayViewCallback.first.post(overlayViewCallback.second);
+                        overlayViewCallback.post();
                     }
                 }
             });
@@ -90,6 +179,8 @@
 
         @Override
         public boolean onSetSurface(Surface surface) {
+            mSurface = surface;
+            draw();
             return true;
         }
 
@@ -99,16 +190,19 @@
 
         @Override
         public boolean onTune(Uri channelUri) {
-            Pair<View, Runnable> tuneCallback = null;
             synchronized (sLock) {
-                tuneCallback = sTuneCallback;
-                sTuneCallback = null;
-            }
-            if (tuneCallback != null) {
-                tuneCallback.first.post(tuneCallback.second);
+                if (sRating != null) {
+                    notifyContentBlocked(sRating);
+                }
+                if (sTuneCallback != null) {
+                    sTuneCallback.post();
+                    sTuneCallback = null;
+                }
+                if (sRating == null) {
+                    notifyContentAllowed();
+                }
             }
             notifyVideoAvailable();
-            notifyContentAllowed();
             return true;
         }
 
@@ -120,5 +214,30 @@
         @Override
         public void onSetCaptionEnabled(boolean enabled) {
         }
+
+        @Override
+        public void onUnblockContent(TvContentRating unblockedRating) {
+            synchronized (sLock) {
+                if (sRating != null && sRating.equals(unblockedRating)) {
+                    sUnblockContentCallback.post();
+                    sRating = null;
+                    notifyContentAllowed();
+                }
+            }
+        }
+    }
+
+    private static class Callback {
+        private final View mPostTarget;
+        private final Runnable mAction;
+
+        Callback(View postTarget, Runnable action) {
+            mPostTarget = postTarget;
+            mAction = action;
+        }
+
+        public void post() {
+            mPostTarget.post(mAction);
+        }
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputSetupActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputSetupActivity.java
index 00f0091..81a8edc 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputSetupActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputSetupActivity.java
@@ -30,7 +30,7 @@
 public class MockTvInputSetupActivity extends Activity {
     private static final String TAG = "MockTvInputSetupActivity";
 
-    private static final String CHANNEL_NUMBER = "999-999";
+    private static final String CHANNEL_NUMBER = "999-0";
     private static final String CHANNEL_NAME = "Dummy";
 
     private static Object sLock = new Object();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/ParentalControlTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/ParentalControlTestActivity.java
new file mode 100644
index 0000000..284b485
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/ParentalControlTestActivity.java
@@ -0,0 +1,149 @@
+/*
+ * 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 com.android.cts.verifier.tv;
+
+import com.android.cts.verifier.R;
+
+import android.content.Intent;
+import android.database.Cursor;
+import android.media.tv.TvContentRating;
+import android.media.tv.TvContract;
+import android.media.tv.TvInputManager;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+/**
+ * Tests for verifying TV app behavior on parental control.
+ */
+public class ParentalControlTestActivity extends TvAppVerifierActivity
+        implements View.OnClickListener {
+    private static final String TAG = "ParentalControlTestActivity";
+
+    private static final long TIMEOUT_MS = 5l * 60l * 1000l;  // 5 mins.
+
+    private View mTurnOnParentalControlItem;
+    private View mVerifyReceiveBroadcast1Item;
+    private View mBlockTvMaItem;
+    private View mVerifyReceiveBroadcast2Item;
+    private View mBlockUnblockItem;
+
+    private Intent mTvAppIntent = null;
+
+    @Override
+    public void onClick(View v) {
+        final View postTarget = getPostTarget();
+
+        if (containsButton(mTurnOnParentalControlItem, v)) {
+            final Runnable failCallback = new Runnable() {
+                @Override
+                public void run() {
+                    setPassState(mVerifyReceiveBroadcast1Item, false);
+                }
+            };
+            postTarget.postDelayed(failCallback, TIMEOUT_MS);
+            MockTvInputService.expectBroadcast(postTarget,
+                    TvInputManager.ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED, new Runnable() {
+                @Override
+                public void run() {
+                    postTarget.removeCallbacks(failCallback);
+                    setPassState(mTurnOnParentalControlItem, true);
+                    setPassState(mVerifyReceiveBroadcast1Item, true);
+                    setButtonEnabled(mBlockTvMaItem, true);
+                }
+            });
+        } else if (containsButton(mBlockTvMaItem, v)) {
+            final Runnable failCallback = new Runnable() {
+                @Override
+                public void run() {
+                    setPassState(mVerifyReceiveBroadcast2Item, false);
+                }
+            };
+            postTarget.postDelayed(failCallback, TIMEOUT_MS);
+            MockTvInputService.expectBroadcast(postTarget,
+                    TvInputManager.ACTION_BLOCKED_RATINGS_CHANGED, new Runnable() {
+                @Override
+                public void run() {
+                    postTarget.removeCallbacks(failCallback);
+                    setPassState(mBlockTvMaItem, true);
+                    setPassState(mVerifyReceiveBroadcast2Item, true);
+                    setButtonEnabled(mBlockUnblockItem, true);
+                }
+            });
+        } else if (containsButton(mBlockUnblockItem, v)) {
+            final Runnable failCallback = new Runnable() {
+                @Override
+                public void run() {
+                    setPassState(mBlockUnblockItem, false);
+                }
+            };
+            postTarget.postDelayed(failCallback, TIMEOUT_MS);
+            MockTvInputService.setBlockRating(TvContentRating.createRating(
+                    "com.android.cts.verifier", "CTS_VERIFIER", "FAKE"));
+            MockTvInputService.expectUnblockContent(postTarget, new Runnable() {
+                @Override
+                public void run() {
+                    postTarget.removeCallbacks(failCallback);
+                    setPassState(mBlockUnblockItem, true);
+                    getPassButton().setEnabled(true);
+                }
+            });
+        }
+        if (mTvAppIntent == null) {
+            String[] projection = { TvContract.Channels._ID };
+            try (Cursor cursor = getContentResolver().query(TvContract.Channels.CONTENT_URI,
+                    projection, null, null, null)) {
+                if (cursor != null && cursor.moveToNext()) {
+                    mTvAppIntent = new Intent(Intent.ACTION_VIEW,
+                            TvContract.buildChannelUri(cursor.getLong(0)));
+                }
+            }
+            if (mTvAppIntent == null) {
+                Toast.makeText(this, R.string.tv_channel_not_found, Toast.LENGTH_SHORT).show();
+                return;
+            }
+        }
+        startActivity(mTvAppIntent);
+    }
+
+    @Override
+    protected void createTestItems() {
+        mTurnOnParentalControlItem = createUserItem(
+                R.string.tv_parental_control_test_turn_on_parental_control,
+                R.string.tv_launch_tv_app, this);
+        setButtonEnabled(mTurnOnParentalControlItem, true);
+        mVerifyReceiveBroadcast1Item = createAutoItem(
+                R.string.tv_parental_control_test_verify_receive_broadcast1);
+        mBlockTvMaItem = createUserItem(R.string.tv_parental_control_test_block_tv_ma,
+                R.string.tv_launch_tv_app, this);
+        mVerifyReceiveBroadcast2Item = createAutoItem(
+                R.string.tv_parental_control_test_verify_receive_broadcast2);
+        mBlockUnblockItem = createUserItem(R.string.tv_parental_control_test_block_unblock,
+                R.string.tv_launch_tv_app, this);
+    }
+
+    @Override
+    protected void setInfoResources() {
+        setInfoResources(R.string.tv_parental_control_test,
+                R.string.tv_parental_control_test_info, -1);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java
index cb6df8a..3529237 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java
@@ -30,14 +30,11 @@
 import android.widget.TextView;
 
 /**
- * Tests for verifying TV app behavior.
+ * Base class for TV app tests.
  */
 public abstract class TvAppVerifierActivity extends PassFailButtons.Activity {
     private static final String TAG = "TvAppVerifierActivity";
 
-    protected static final Intent TV_APP_INTENT = new Intent(Intent.ACTION_VIEW,
-            TvContract.buildChannelUri(0));
-
     private static final long TIMEOUT_MS = 5l * 60l * 1000l;  // 5 mins.
 
     private LayoutInflater mInflater;
@@ -59,7 +56,7 @@
         createTestItems();
         setContentView(view);
         setPassFailButtonClickListeners();
-        setInfoResources(R.string.tv, R.string.tv_info, -1);
+        setInfoResources();
 
         getPassButton().setEnabled(false);
     }
@@ -81,6 +78,8 @@
 
     protected abstract void createTestItems();
 
+    protected abstract void setInfoResources();
+
     /**
      * Call this to create a test step where the user must perform some action.
      */
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java
index a627a55..3d17a1a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java
@@ -16,17 +16,22 @@
 
 package com.android.cts.verifier.tv;
 
-import com.android.cts.verifier.R;
-
+import android.content.Intent;
+import android.media.tv.TvContract;
 import android.view.View;
 
+import com.android.cts.verifier.R;
+
 /**
- * Tests for verifying TV app behavior.
+ * Tests for verifying TV app behavior for third-party TV input apps.
  */
 public class TvInputDiscoveryTestActivity extends TvAppVerifierActivity
         implements View.OnClickListener {
     private static final String TAG = "TvInputDiscoveryTestActivity";
 
+    private static final Intent TV_APP_INTENT = new Intent(Intent.ACTION_VIEW,
+            TvContract.buildChannelUri(0));
+
     private static final long TIMEOUT_MS = 5l * 60l * 1000l;  // 5 mins.
 
     private View mGoToSetupItem;
@@ -109,4 +114,10 @@
             getPassButton().setEnabled(true);
         }
     }
+
+    @Override
+    protected void setInfoResources() {
+        setInfoResources(R.string.tv_input_discover_test,
+                R.string.tv_input_discover_test_info, -1);
+    }
 }