Add CTS Verifier for the app link API in TIF

Bug: 22368248
Change-Id: Ia32514af3fc79bf36aeb0d1db9eb823d400b8ec5
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index d3dcf07..4f5217d 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -1583,6 +1583,18 @@
                     android:value="android.software.live_tv" />
         </activity>
 
+        <activity android:name=".tv.AppLinkTestActivity"
+            android:label="@string/tv_app_link_test"
+            android:launchMode="singleTask">
+            <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=".screenpinning.ScreenPinningTestActivity"
             android:label="@string/screen_pinning_test">
             <intent-filter>
diff --git a/apps/CtsVerifier/res/drawable/app_link_img.png b/apps/CtsVerifier/res/drawable/app_link_img.png
new file mode 100644
index 0000000..851fc6f
--- /dev/null
+++ b/apps/CtsVerifier/res/drawable/app_link_img.png
Binary files differ
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 219a8b3..268dcfc 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -1895,7 +1895,6 @@
     Do you see the programs named \"Dummy Program\" and their descriptions
     "Dummy Program Description" in the EPG?
     </string>
-    <string name="tv_input_discover_test_yes">Yes</string>
 
     <string name="tv_parental_control_test">TV app parental controls test</string>
     <string name="tv_parental_control_test_info">
@@ -1984,6 +1983,24 @@
     The playback position should be moved to the next position.
     </string>
 
+    <string name="tv_app_link_test">TV app app-link test</string>
+    <string name="tv_app_link_test_info">
+    Verify that the bundled TV app supports linking to channel apps. If TV input service provides
+    links for its specific channels, TV app should show the links in a proper format.
+    </string>
+    <string name="tv_app_link_test_select_app_link">
+    Select the \"Launch TV app\" button, then check if you can see a menu with \"Cts App-Link Text\"
+    text in red background. If you see the link, select it to follow the link.
+    </string>
+    <string name="tv_app_link_test_verify_link_clicked">
+    The app-link must have been clicked and the activity should be changed correctly.
+    </string>
+    <string name="tv_input_link_test_verify_link_interface">
+    Do you see the app-link card similar to the image on the left?\n
+    1) You should see the poster art image, but the color could be differ.\n
+    2) You should see the text \"Cts App-Link Text\".\n
+    </string>
+
     <string name="overlay_view_text">Overlay View Dummy Text</string>
     <string name="fake_rating">Fake</string>
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/AppLinkTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/AppLinkTestActivity.java
new file mode 100644
index 0000000..43f293a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/AppLinkTestActivity.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.tv;
+
+import android.content.Intent;
+import android.database.Cursor;
+import android.graphics.drawable.Drawable;
+import android.media.tv.TvContract;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.cts.verifier.R;
+
+/**
+ * Tests for verifying TV app behavior for TV app-link.
+ */
+public class AppLinkTestActivity extends TvAppVerifierActivity implements View.OnClickListener {
+    private static final long TIMEOUT_MS = 5l * 60l * 1000l;  // 5 mins.
+
+    private boolean mSelectAppLinkItemPassed;
+    private View mSelectAppLinkItem;
+    private View mVerifyAppLinkIntentItem;
+    private View mVerifyAppLinkCardItem;
+
+    Runnable mSelectAppLinkFailCallback;
+
+    @Override
+    public void onClick(View v) {
+        final View postTarget = getPostTarget();
+
+        if (containsButton(mSelectAppLinkItem, v)) {
+            Intent tvAppIntent = null;
+            String[] projection = { TvContract.Channels._ID };
+            try (Cursor cursor = getContentResolver().query(
+                    TvContract.buildChannelsUriForInput(MockTvInputService.getInputId(this)),
+                    projection, null, null, null)) {
+                if (cursor != null && cursor.moveToNext()) {
+                    tvAppIntent = new Intent(Intent.ACTION_VIEW,
+                            TvContract.buildChannelUri(cursor.getLong(0)));
+                }
+            }
+            if (tvAppIntent == null) {
+                Toast.makeText(this, R.string.tv_channel_not_found, Toast.LENGTH_SHORT).show();
+                return;
+            }
+
+            mSelectAppLinkFailCallback = new Runnable() {
+                @Override
+                public void run() {
+                    mSelectAppLinkItemPassed = false;
+                    setPassState(mSelectAppLinkItem, false);
+                    setPassState(mVerifyAppLinkIntentItem, false);
+                }
+            };
+            postTarget.postDelayed(mSelectAppLinkFailCallback, TIMEOUT_MS);
+            mSelectAppLinkItemPassed = true;
+            setPassState(mSelectAppLinkItem, true);
+
+            startActivity(tvAppIntent);
+        } else if (containsButton(mVerifyAppLinkCardItem, v)) {
+            setPassState(mVerifyAppLinkCardItem, true);
+            getPassButton().setEnabled(true);
+        }
+    }
+
+    @Override
+    protected void onNewIntent(Intent intent) {
+        if (mSelectAppLinkItemPassed
+                && TextUtils.equals(MockTvInputSetupActivity.APP_LINK_TEST_VALUE,
+                        intent.getStringExtra(MockTvInputSetupActivity.APP_LINK_TEST_KEY))) {
+            getPostTarget().removeCallbacks(mSelectAppLinkFailCallback);
+            setPassState(mVerifyAppLinkIntentItem, true);
+            setButtonEnabled(mVerifyAppLinkCardItem, true);
+        }
+    }
+
+    @Override
+    protected void createTestItems() {
+        mSelectAppLinkItem = createUserItem(R.string.tv_app_link_test_select_app_link,
+                R.string.tv_launch_tv_app, this);
+        setButtonEnabled(mSelectAppLinkItem, true);
+        mVerifyAppLinkIntentItem = createAutoItem(
+                R.string.tv_app_link_test_verify_link_clicked);
+        mVerifyAppLinkCardItem = createUserItem(R.string.tv_input_link_test_verify_link_interface,
+                android.R.string.yes, this);
+        TextView instructions = (TextView) mVerifyAppLinkCardItem.findViewById(R.id.instructions);
+        Drawable image = getDrawable(R.drawable.app_link_img);
+        image.setBounds(0, 0, 317, 241);
+        instructions.setCompoundDrawablePadding(10);
+        instructions.setCompoundDrawables(image, null, null, null);
+    }
+
+    @Override
+    protected void setInfoResources() {
+        setInfoResources(R.string.tv_app_link_test, R.string.tv_app_link_test_info, -1);
+    }
+}
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 c05b753..43ed7da 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputSetupActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputSetupActivity.java
@@ -17,9 +17,12 @@
 package com.android.cts.verifier.tv;
 
 import android.app.Activity;
+import android.content.ComponentName;
 import android.content.ContentUris;
 import android.content.ContentValues;
+import android.content.Intent;
 import android.database.Cursor;
+import android.graphics.Color;
 import android.media.tv.TvContract;
 import android.media.tv.TvContract.Programs;
 import android.media.tv.TvInputInfo;
@@ -28,6 +31,8 @@
 import android.util.Pair;
 import android.view.View;
 
+import com.android.cts.verifier.R;
+
 import java.util.ArrayList;
 
 public class MockTvInputSetupActivity extends Activity {
@@ -38,6 +43,10 @@
 
     /* package-private */ static final String PROGRAM_TITLE = "Dummy Program";
     /* package-private */ static final String PROGRAM_DESCRIPTION = "Dummy Program Description";
+
+    /* package-private */ static final String APP_LINK_TEST_KEY = "app_link_test_key";
+    /* package-private */ static final String APP_LINK_TEST_VALUE = "app_link_test_value";
+    private static final String APP_LINK_TEXT = "Cts App-Link Text";
     private static final long PROGRAM_LENGTH_MILLIS = 60 * 60 * 1000;
     private static final int PROGRAM_COUNT = 24;
 
@@ -69,6 +78,18 @@
             values.put(TvContract.Channels.COLUMN_INPUT_ID, inputId);
             values.put(TvContract.Channels.COLUMN_DISPLAY_NUMBER, CHANNEL_NUMBER);
             values.put(TvContract.Channels.COLUMN_DISPLAY_NAME, CHANNEL_NAME);
+            values.put(TvContract.Channels.COLUMN_APP_LINK_TEXT, APP_LINK_TEXT);
+            values.put(TvContract.Channels.COLUMN_APP_LINK_COLOR, Color.RED);
+            values.put(TvContract.Channels.COLUMN_APP_LINK_ICON_URI,
+                    "android.resource://" + getPackageName() + "/" + R.drawable.icon);
+            values.put(TvContract.Channels.COLUMN_APP_LINK_POSTER_ART_URI,
+                    "android.resource://" + getPackageName() + "/" + R.raw.sns_texture);
+            Intent appLinkIntentUri = new Intent(this, AppLinkTestActivity.class);
+            appLinkIntentUri.putExtra(APP_LINK_TEST_KEY, APP_LINK_TEST_VALUE);
+            appLinkIntentUri.setFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
+            values.put(TvContract.Channels.COLUMN_APP_LINK_INTENT_URI,
+                    appLinkIntentUri.toUri(Intent.URI_INTENT_SCHEME));
+
             Uri channelUri = getContentResolver().insert(uri, values);
             // If the channel's ID happens to be zero, we add another and delete the one.
             if (ContentUris.parseId(channelUri) == 0) {
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 12e9652..acab18e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java
@@ -35,8 +35,6 @@
 public abstract class TvAppVerifierActivity extends PassFailButtons.Activity {
     private static final String TAG = "TvAppVerifierActivity";
 
-    private static final long TIMEOUT_MS = 5l * 60l * 1000l;  // 5 mins.
-
     private LayoutInflater mInflater;
     private ViewGroup mItemList;
     private View mPostTarget;
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 06f4f6f..e8e2cee 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java
@@ -25,8 +25,6 @@
 
 import com.android.cts.verifier.R;
 
-import java.util.List;
-
 /**
  * Tests for verifying TV app behavior for third-party TV input apps.
  */
@@ -131,7 +129,7 @@
         mGoToEpgItem = createUserItem(R.string.tv_input_discover_test_go_to_epg,
                 R.string.tv_launch_epg, this);
         mVerifyEpgItem = createUserItem(R.string.tv_input_discover_test_verify_epg,
-                R.string.tv_input_discover_test_yes, this);
+                android.R.string.yes, this);
     }
 
     @Override