1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.tv;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import android.media.tv.TvTrackInfo;
22 import android.os.Bundle;
23 import android.view.LayoutInflater;
24 
25 import com.android.tv.common.flags.impl.DefaultLegacyFlags;
26 import com.android.tv.data.ProgramDataManager;
27 import com.android.tv.data.StreamInfo;
28 import com.android.tv.testing.TestSingletonApp;
29 import com.android.tv.testing.TvRobolectricTestRunner;
30 import com.android.tv.testing.constants.ConfigConstants;
31 import com.android.tv.ui.TunableTvView;
32 import com.android.tv.util.TvInputManagerHelper;
33 
34 import java.util.Arrays;
35 import java.util.List;
36 
37 import org.junit.Before;
38 import org.junit.Test;
39 import org.junit.runner.RunWith;
40 import org.robolectric.Robolectric;
41 import org.robolectric.RuntimeEnvironment;
42 import org.robolectric.annotation.Config;
43 import org.robolectric.shadow.api.Shadow;
44 
45 import java.util.Arrays;
46 
47 /** Tests for {@link TunableTvView} */
48 @RunWith(TvRobolectricTestRunner.class)
49 @Config(
50         sdk = ConfigConstants.SDK,
51         application = TestSingletonApp.class,
52         shadows = {ShadowTvView.class})
53 public class MainActivityRoboTest {
54     private ShadowTvView mShadowTvView;
55     private FakeMainActivity mMainActivity;
56 
57     @Before
setUp()58     public void setUp() {
59         mMainActivity = Robolectric.buildActivity(FakeMainActivity.class).create().get();
60         mShadowTvView = Shadow.extract(mMainActivity.getTvView().getTvView());
61         mShadowTvView.listener = mMainActivity.getListener();
62     }
63 
64     @Test
testSelectAudioTrack_autoSelect()65     public void testSelectAudioTrack_autoSelect() {
66         mShadowTvView.mAudioTrackCountChanged = false;
67         setTracks(
68                 TvTrackInfo.TYPE_AUDIO,
69                 buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "EN audio 1", "EN"),
70                 buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "FR audio 1", "FR"));
71         mMainActivity.selectAudioTrack("FR audio 1");
72         assertThat(mMainActivity.getSelectedTrack(TvTrackInfo.TYPE_AUDIO)).isEqualTo("FR audio 1");
73 
74         setTracks(
75                 TvTrackInfo.TYPE_AUDIO,
76                 buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "EN audio 2", "EN"),
77                 buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "FR audio 2", "FR"),
78                 buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "FR audio 3", "FR"));
79         mMainActivity.applyMultiAudio(null);
80         // FR audio 2 is selected according the previously selected track.
81         assertThat(mMainActivity.getSelectedTrack(TvTrackInfo.TYPE_AUDIO)).isEqualTo("FR audio 2");
82     }
83 
84     @Test
testSelectAudioTrack_audioTrackCountChanged()85     public void testSelectAudioTrack_audioTrackCountChanged() {
86         mShadowTvView.mAudioTrackCountChanged = true;
87         setTracks(
88                 TvTrackInfo.TYPE_AUDIO,
89                 buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "EN audio 1", "EN"),
90                 buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "FR audio 1", "FR"));
91         mMainActivity.selectAudioTrack("FR audio 1");
92         assertThat(mMainActivity.getSelectedTrack(TvTrackInfo.TYPE_AUDIO)).isEqualTo("FR audio 1");
93 
94         setTracks(
95                 TvTrackInfo.TYPE_AUDIO,
96                 buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "EN audio 2", "EN"),
97                 buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "FR audio 2", "FR"),
98                 buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "FR audio 3", "FR"));
99         mMainActivity.selectAudioTrack("FR audio 3");
100         // FR audio 3 is selected even if the track info has been changed
101         assertThat(mMainActivity.getSelectedTrack(TvTrackInfo.TYPE_AUDIO)).isEqualTo("FR audio 3");
102     }
103 
104     @Test
testSelectAudioTrack_audioTrackCountNotChanged()105     public void testSelectAudioTrack_audioTrackCountNotChanged() {
106         mShadowTvView.mAudioTrackCountChanged = false;
107         setTracks(
108                 TvTrackInfo.TYPE_AUDIO,
109                 buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "EN audio 1", "EN"),
110                 buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "FR audio 1", "FR"));
111         mMainActivity.selectAudioTrack("FR audio 1");
112         assertThat(mMainActivity.getSelectedTrack(TvTrackInfo.TYPE_AUDIO)).isEqualTo("FR audio 1");
113 
114         setTracks(
115                 TvTrackInfo.TYPE_AUDIO,
116                 buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "EN audio 2", "EN"),
117                 buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "FR audio 2", "FR"),
118                 buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "FR audio 3", "FR"));
119         mMainActivity.selectAudioTrack("FR audio 3");
120         assertThat(mMainActivity.getSelectedTrack(TvTrackInfo.TYPE_AUDIO)).isEqualTo("FR audio 3");
121     }
122 
123     @Test
testFindBestCaptionTrack_bestTrackMatch()124     public void testFindBestCaptionTrack_bestTrackMatch() {
125         List<TvTrackInfo> tracks = Arrays.asList(
126                 buildCaptionTrackForTesting("EN subtitle 1", "EN"),
127                 buildCaptionTrackForTesting("EN subtitle 2", "EN"),
128                 buildCaptionTrackForTesting("FR subtitle 1", "FR"),
129                 buildCaptionTrackForTesting("FR subtitle 2", "FR"));
130         List<String> preferredLanguages = Arrays.asList("DE", "FR");
131 
132         int trackIndex =
133                 MainActivity.findBestCaptionTrackIndex(
134                         tracks, "EN", preferredLanguages, "EN subtitle 2");
135         assertThat(trackIndex).isEqualTo(1);
136     }
137 
138     @Test
testFindBestCaptionTrack_selectedLanguageMatch()139     public void testFindBestCaptionTrack_selectedLanguageMatch() {
140         List<TvTrackInfo> tracks = Arrays.asList(
141                 buildCaptionTrackForTesting("EN subtitle 1", "EN"),
142                 buildCaptionTrackForTesting("EN subtitle 2", "EN"),
143                 buildCaptionTrackForTesting("FR subtitle 1", "FR"),
144                 buildCaptionTrackForTesting("FR subtitle 2", "FR"));
145         List<String> preferredLanguages = Arrays.asList("DE", "FR");
146 
147         int trackIndex =
148                 MainActivity.findBestCaptionTrackIndex(
149                         tracks, "EN", preferredLanguages, "EN subtitle 3");
150         assertThat(trackIndex).isEqualTo(0);
151     }
152 
153     @Test
testFindBestCaptionTrack_preferredLanguageMatch()154     public void testFindBestCaptionTrack_preferredLanguageMatch() {
155         List<TvTrackInfo> tracks = Arrays.asList(
156                 buildCaptionTrackForTesting("EN subtitle 1", "EN"),
157                 buildCaptionTrackForTesting("EN subtitle 2", "EN"),
158                 buildCaptionTrackForTesting("FR subtitle 1", "FR"),
159                 buildCaptionTrackForTesting("FR subtitle 2", "FR"));
160         List<String> preferredLanguages = Arrays.asList("DE", "FR");
161 
162         int trackIndex =
163                 MainActivity.findBestCaptionTrackIndex(
164                         tracks, "JA", preferredLanguages, "JA subtitle 4");
165         assertThat(trackIndex).isEqualTo(2);
166     }
167 
168     @Test
testFindBestCaptionTrack_higherPriorityPreferredLanguageMatch()169     public void testFindBestCaptionTrack_higherPriorityPreferredLanguageMatch() {
170         List<TvTrackInfo> tracks = Arrays.asList(
171                 buildCaptionTrackForTesting("EN subtitle 1", "EN"),
172                 buildCaptionTrackForTesting("EN subtitle 2", "EN"),
173                 buildCaptionTrackForTesting("FR subtitle 1", "FR"),
174                 buildCaptionTrackForTesting("FR subtitle 2", "FR"));
175         List<String> preferredLanguages = Arrays.asList("FR", "EN");
176 
177         int trackIndex =
178                 MainActivity.findBestCaptionTrackIndex(
179                         tracks, "JA", preferredLanguages, "JA subtitle 4");
180         assertThat(trackIndex).isEqualTo(2);
181     }
182 
183     @Test
testFindBestCaptionTrack_noMatch()184     public void testFindBestCaptionTrack_noMatch() {
185         List<TvTrackInfo> tracks = Arrays.asList(
186                 buildCaptionTrackForTesting("EN subtitle 1", "EN"),
187                 buildCaptionTrackForTesting("EN subtitle 2", "EN"),
188                 buildCaptionTrackForTesting("FR subtitle 1", "FR"),
189                 buildCaptionTrackForTesting("FR subtitle 2", "FR"));
190         List<String> preferredLanguages = Arrays.asList("DE", "IT");
191 
192         int trackIndex =
193                 MainActivity.findBestCaptionTrackIndex(
194                         tracks, "JA", preferredLanguages, "JA subtitle 4");
195         assertThat(trackIndex).isEqualTo(0);
196     }
197 
setTracks(int type, TvTrackInfo... tracks)198     private void setTracks(int type, TvTrackInfo... tracks) {
199         mShadowTvView.mTracks.put(type, Arrays.asList(tracks));
200         mShadowTvView.mSelectedTracks.put(type, null);
201     }
202 
buildTrackForTesting(int type, String id, String language)203     private TvTrackInfo buildTrackForTesting(int type, String id, String language) {
204         return new TvTrackInfo.Builder(type, id)
205                 .setLanguage(language)
206                 .setAudioChannelCount(0)
207                 .build();
208     }
209 
buildCaptionTrackForTesting(String id, String language)210     private TvTrackInfo buildCaptionTrackForTesting(String id, String language) {
211         return new TvTrackInfo.Builder(TvTrackInfo.TYPE_SUBTITLE, id)
212                 .setLanguage(language)
213                 .build();
214     }
215 
216     /** A {@link MainActivity} class for tests */
217     public static class FakeMainActivity extends MainActivity {
218         private MyOnTuneListener mListener;
219 
220         @Override
onCreate(Bundle savedInstanceState)221         protected void onCreate(Bundle savedInstanceState) {
222             // Override onCreate() to omit unnecessary member variables
223             mTvView =
224                     (TunableTvView)
225                             LayoutInflater.from(RuntimeEnvironment.application)
226                                     .inflate(R.layout.activity_tv, null)
227                                     .findViewById(R.id.main_tunable_tv_view);
228             DefaultLegacyFlags legacyFlags = DefaultLegacyFlags.DEFAULT;
229             mTvView.initialize(
230                     new ProgramDataManager(RuntimeEnvironment.application),
231                     new TvInputManagerHelper(RuntimeEnvironment.application, legacyFlags),
232                     legacyFlags);
233             mTvView.start();
234             mListener =
235                     new MyOnTuneListener() {
236                         @Override
237                         public void onStreamInfoChanged(
238                                 StreamInfo info, boolean allowAutoSelectionOfTrack) {
239                             applyMultiAudio(
240                                     allowAutoSelectionOfTrack
241                                             ? null
242                                             : getSelectedTrack(TvTrackInfo.TYPE_AUDIO));
243                         }
244                     };
245             mTvView.setOnTuneListener(mListener);
246         }
247 
getTvView()248         public TunableTvView getTvView() {
249             return mTvView;
250         }
251 
getListener()252         public MyOnTuneListener getListener() {
253             return mListener;
254         }
255     }
256 }
257