TV: add multiple tracks tests to CtsVerifier DO NOT MERGE
Bug: 18069561
Change-Id: I9a8dbb7b991a3cbbcf53be01cd17b9bb5aa4591f
(cherry picked from commit f570731f846a88a26766115fa78a35fdbe24f82a)
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 098cdad..563a65e 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -1483,6 +1483,17 @@
android:value="android.software.live_tv" />
</activity>
+ <activity android:name=".tv.MultipleTracksTestActivity"
+ android:label="@string/tv_multiple_tracks_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.MockTvInputSettingsActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 83af341..e8cc499 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -1387,6 +1387,29 @@
CtsVerifier channel is not set up. Please set up before proceeding.
</string>
+ <string name="tv_multiple_tracks_test">Live Channels app multiple tracks / subtitle test</string>
+ <string name="tv_multiple_tracks_test_info">
+ This test verifies that the default Live Channels app invokes proper mulitple tracks / subtitle
+ APIs in the framework.
+ </string>
+ <string name="tv_multiple_tracks_test_select_subtitle">
+ Press the \"Launch Live Channels\" button. Verify that the closed caption is off by default.
+ Set closed caption to English.
+ </string>
+ <string name="tv_multiple_tracks_test_verify_set_caption_enabled">
+ Caption should be enabled.
+ </string>
+ <string name="tv_multiple_tracks_test_verify_select_subtitle">
+ The English subtitle track should be selected.
+ </string>
+ <string name="tv_multiple_tracks_test_select_audio">
+ Press the \"Launch Live Channels\" button. Verify that the audio track is English by default.
+ Select Spanish audio track.
+ </string>
+ <string name="tv_multiple_tracks_test_verify_select_audio">
+ The Spanish audio track should be selected.
+ </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/MockTvInputService.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputService.java
index a6bb01a..f4460de 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputService.java
@@ -30,7 +30,9 @@
import android.media.tv.TvContentRating;
import android.media.tv.TvInputManager;
import android.media.tv.TvInputService;
+import android.media.tv.TvTrackInfo;
import android.net.Uri;
+import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.Surface;
@@ -40,26 +42,57 @@
import com.android.cts.verifier.R;
+import java.util.ArrayList;
+import java.util.List;
+
public class MockTvInputService extends TvInputService {
private static final String TAG = "MockTvInputService";
+ private static final String BROADCAST_ACTION = "action";
+ private static final String SELECT_TRACK_TYPE = "type";
+ private static final String SELECT_TRACK_ID = "id";
+ private static final String CAPTION_ENABLED = "enabled";
+
private static Object sLock = new Object();
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 Callback sSelectTrackCallback = null;
+ private static Callback sSetCaptionEnabledCallback = null;
private static TvContentRating sRating = null;
+ static final TvTrackInfo sEngAudioTrack =
+ new TvTrackInfo.Builder(TvTrackInfo.TYPE_AUDIO, "audio_eng")
+ .setAudioChannelCount(2)
+ .setAudioSampleRate(48000)
+ .setLanguage("eng")
+ .build();
+ static final TvTrackInfo sSpaAudioTrack =
+ new TvTrackInfo.Builder(TvTrackInfo.TYPE_AUDIO, "audio_spa")
+ .setAudioChannelCount(2)
+ .setAudioSampleRate(48000)
+ .setLanguage("spa")
+ .build();
+ static final TvTrackInfo sEngSubtitleTrack =
+ new TvTrackInfo.Builder(TvTrackInfo.TYPE_SUBTITLE, "subtitle_eng")
+ .setLanguage("eng")
+ .build();
+ static final TvTrackInfo sSpaSubtitleTrack =
+ new TvTrackInfo.Builder(TvTrackInfo.TYPE_SUBTITLE, "subtitle_spa")
+ .setLanguage("spa")
+ .build();
+
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
synchronized (sLock) {
if (sBroadcastCallback != null) {
- if (intent.getAction().equals(sExpectedBroadcastAction)) {
+ String expectedAction =
+ sBroadcastCallback.getBundle().getString(BROADCAST_ACTION);
+ if (intent.getAction().equals(expectedAction)) {
sBroadcastCallback.post();
sBroadcastCallback = null;
- sExpectedBroadcastAction = null;
}
}
}
@@ -75,7 +108,7 @@
static void expectBroadcast(View postTarget, String action, Runnable successCallback) {
synchronized (sLock) {
sBroadcastCallback = new Callback(postTarget, successCallback);
- sExpectedBroadcastAction = action;
+ sBroadcastCallback.getBundle().putString(BROADCAST_ACTION, action);
}
}
@@ -97,6 +130,22 @@
}
}
+ static void expectSelectTrack(int type, String id, View postTarget, Runnable successCallback) {
+ synchronized (sLock) {
+ sSelectTrackCallback = new Callback(postTarget, successCallback);
+ sSelectTrackCallback.getBundle().putInt(SELECT_TRACK_TYPE, type);
+ sSelectTrackCallback.getBundle().putString(SELECT_TRACK_ID, id);
+ }
+ }
+
+ static void expectSetCaptionEnabled(boolean enabled, View postTarget,
+ Runnable successCallback) {
+ synchronized (sLock) {
+ sSetCaptionEnabledCallback = new Callback(postTarget, successCallback);
+ sSetCaptionEnabledCallback.getBundle().putBoolean(CAPTION_ENABLED, enabled);
+ }
+ }
+
@Override
public void onCreate() {
super.onCreate();
@@ -122,10 +171,15 @@
private static class MockSessionImpl extends Session {
private final Context mContext;
private Surface mSurface = null;
+ private List<TvTrackInfo> mTracks = new ArrayList<>();
private MockSessionImpl(Context context) {
super(context);
mContext = context;
+ mTracks.add(sEngAudioTrack);
+ mTracks.add(sSpaAudioTrack);
+ mTracks.add(sEngSubtitleTrack);
+ mTracks.add(sSpaSubtitleTrack);
}
@Override
@@ -203,16 +257,39 @@
}
}
notifyVideoAvailable();
+ notifyTracksChanged(mTracks);
+ notifyTrackSelected(TvTrackInfo.TYPE_AUDIO, sEngAudioTrack.getId());
+ notifyTrackSelected(TvTrackInfo.TYPE_SUBTITLE, null);
return true;
}
@Override
public boolean onSelectTrack(int type, String trackId) {
+ synchronized (sLock) {
+ if (sSelectTrackCallback != null) {
+ Bundle bundle = sSelectTrackCallback.getBundle();
+ if (bundle.getInt(SELECT_TRACK_TYPE) == type
+ && bundle.getString(SELECT_TRACK_ID).equals(trackId)) {
+ sSelectTrackCallback.post();
+ sSelectTrackCallback = null;
+ }
+ }
+ }
+ notifyTrackSelected(type, trackId);
return true;
}
@Override
public void onSetCaptionEnabled(boolean enabled) {
+ synchronized (sLock) {
+ if (sSetCaptionEnabledCallback != null) {
+ Bundle bundle = sSetCaptionEnabledCallback.getBundle();
+ if (bundle.getBoolean(CAPTION_ENABLED) == enabled) {
+ sSetCaptionEnabledCallback.post();
+ sSetCaptionEnabledCallback = null;
+ }
+ }
+ }
}
@Override
@@ -230,6 +307,7 @@
private static class Callback {
private final View mPostTarget;
private final Runnable mAction;
+ private final Bundle mBundle = new Bundle();
Callback(View postTarget, Runnable action) {
mPostTarget = postTarget;
@@ -239,5 +317,9 @@
public void post() {
mPostTarget.post(mAction);
}
+
+ public Bundle getBundle() {
+ return mBundle;
+ }
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/MultipleTracksTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/MultipleTracksTestActivity.java
new file mode 100644
index 0000000..66af4c6
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/MultipleTracksTestActivity.java
@@ -0,0 +1,154 @@
+/*
+ * 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.media.tv.TvTrackInfo;
+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 multiple tracks and subtitle.
+ */
+public class MultipleTracksTestActivity extends TvAppVerifierActivity
+ implements View.OnClickListener {
+ private static final String TAG = "MultipleTracksTestActivity";
+
+ private static final long TIMEOUT_MS = 5l * 60l * 1000l; // 5 mins.
+
+ private View mSelectSubtitleItem;
+ private View mVerifySetCaptionEnabledItem;
+ private View mVerifySelectSubtitleItem;
+ private View mSelectAudioItem;
+ private View mVerifySelectAudioItem;
+
+ private Intent mTvAppIntent = null;
+
+ @Override
+ public void onClick(View v) {
+ final View postTarget = getPostTarget();
+
+ if (containsButton(mSelectSubtitleItem, v)) {
+ final Runnable failCallback = new Runnable() {
+ @Override
+ public void run() {
+ setPassState(mVerifySetCaptionEnabledItem, false);
+ setPassState(mVerifySelectSubtitleItem, false);
+ }
+ };
+ postTarget.postDelayed(failCallback, TIMEOUT_MS);
+ MockTvInputService.expectSetCaptionEnabled(true, postTarget, new Runnable() {
+ @Override
+ public void run() {
+ postTarget.removeCallbacks(failCallback);
+ setPassState(mSelectSubtitleItem, true);
+ setPassState(mVerifySetCaptionEnabledItem, true);
+ Integer tag = (Integer) mSelectAudioItem.getTag();
+ if (tag == 0) {
+ mSelectAudioItem.setTag(Integer.valueOf(1));
+ } else if (tag == 1) {
+ setButtonEnabled(mSelectAudioItem, true);
+ }
+ }
+ });
+ MockTvInputService.expectSelectTrack(TvTrackInfo.TYPE_SUBTITLE,
+ MockTvInputService.sEngSubtitleTrack.getId(), postTarget, new Runnable() {
+ @Override
+ public void run() {
+ postTarget.removeCallbacks(failCallback);
+ setPassState(mSelectSubtitleItem, true);
+ setPassState(mVerifySelectSubtitleItem, true);
+ Integer tag = (Integer) mSelectAudioItem.getTag();
+ if (tag == 0) {
+ mSelectAudioItem.setTag(Integer.valueOf(1));
+ } else if (tag == 1) {
+ setButtonEnabled(mSelectAudioItem, true);
+ }
+ }
+ });
+ } else if (containsButton(mSelectAudioItem, v)) {
+ final Runnable failCallback = new Runnable() {
+ @Override
+ public void run() {
+ setPassState(mVerifySelectAudioItem, false);
+ }
+ };
+ postTarget.postDelayed(failCallback, TIMEOUT_MS);
+ MockTvInputService.expectSelectTrack(TvTrackInfo.TYPE_AUDIO,
+ MockTvInputService.sSpaAudioTrack.getId(), postTarget, new Runnable() {
+ @Override
+ public void run() {
+ postTarget.removeCallbacks(failCallback);
+ setPassState(mSelectAudioItem, true);
+ setPassState(mVerifySelectAudioItem, 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() {
+ mSelectSubtitleItem = createUserItem(
+ R.string.tv_multiple_tracks_test_select_subtitle,
+ R.string.tv_launch_tv_app, this);
+ setButtonEnabled(mSelectSubtitleItem, true);
+ mVerifySetCaptionEnabledItem = createAutoItem(
+ R.string.tv_multiple_tracks_test_verify_set_caption_enabled);
+ mVerifySelectSubtitleItem = createAutoItem(
+ R.string.tv_multiple_tracks_test_verify_select_subtitle);
+ mSelectAudioItem = createUserItem(
+ R.string.tv_multiple_tracks_test_select_audio,
+ R.string.tv_launch_tv_app, this);
+ mSelectAudioItem.setTag(Integer.valueOf(0));
+ mVerifySelectAudioItem = createAutoItem(
+ R.string.tv_multiple_tracks_test_verify_select_audio);
+ }
+
+ @Override
+ protected void setInfoResources() {
+ setInfoResources(R.string.tv_multiple_tracks_test,
+ R.string.tv_multiple_tracks_test_info, -1);
+ }
+}