• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.data;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static com.google.common.truth.Truth.assertWithMessage;
21 
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.pm.ActivityInfo;
26 import android.content.pm.PackageManager;
27 import android.content.pm.PackageManager.NameNotFoundException;
28 import androidx.test.filters.SmallTest;
29 import androidx.test.runner.AndroidJUnit4;
30 import com.android.tv.data.api.Channel;
31 import com.android.tv.testing.ComparatorTester;
32 import com.android.tv.util.TvInputManagerHelper;
33 import java.util.Comparator;
34 import org.junit.Before;
35 import org.junit.Test;
36 import org.junit.runner.RunWith;
37 import org.mockito.Matchers;
38 import org.mockito.Mockito;
39 import org.mockito.invocation.InvocationOnMock;
40 import org.mockito.stubbing.Answer;
41 
42 /** Tests for {@link ChannelImpl}. */
43 @SmallTest
44 @RunWith(AndroidJUnit4.class)
45 public class ChannelImplTest {
46     // Used for testing TV inputs with invalid input package. This could happen when a TV input is
47     // uninstalled while drawing an app link card.
48     private static final String INVALID_TV_INPUT_PACKAGE_NAME = "com.android.tv.invalid_tv_input";
49     // Used for testing TV inputs defined inside of Live TV.
50     private static final String LIVE_CHANNELS_PACKAGE_NAME = "com.android.tv";
51     // Used for testing a TV input which doesn't have its leanback launcher activity.
52     private static final String NONE_LEANBACK_TV_INPUT_PACKAGE_NAME =
53             "com.android.tv.none_leanback_tv_input";
54     // Used for testing a TV input which has its leanback launcher activity.
55     private static final String LEANBACK_TV_INPUT_PACKAGE_NAME = "com.android.tv.leanback_tv_input";
56     private static final String TEST_APP_LINK_TEXT = "test_app_link_text";
57     private static final String PARTNER_INPUT_ID = "partner";
58     private static final ActivityInfo TEST_ACTIVITY_INFO = new ActivityInfo();
59 
60     private Context mMockContext;
61     private Intent mInvalidIntent;
62     private Intent mValidIntent;
63 
64     @Before
setUp()65     public void setUp() throws NameNotFoundException {
66         mInvalidIntent = new Intent(Intent.ACTION_VIEW);
67         mInvalidIntent.setComponent(new ComponentName(INVALID_TV_INPUT_PACKAGE_NAME, ".test"));
68         mValidIntent = new Intent(Intent.ACTION_VIEW);
69         mValidIntent.setComponent(new ComponentName(LEANBACK_TV_INPUT_PACKAGE_NAME, ".test"));
70         Intent liveChannelsIntent = new Intent(Intent.ACTION_VIEW);
71         liveChannelsIntent.setComponent(
72                 new ComponentName(LIVE_CHANNELS_PACKAGE_NAME, ".MainActivity"));
73         Intent leanbackTvInputIntent = new Intent(Intent.ACTION_VIEW);
74         leanbackTvInputIntent.setComponent(
75                 new ComponentName(LEANBACK_TV_INPUT_PACKAGE_NAME, ".test"));
76 
77         PackageManager mockPackageManager = Mockito.mock(PackageManager.class);
78         Mockito.when(
79                         mockPackageManager.getLeanbackLaunchIntentForPackage(
80                                 INVALID_TV_INPUT_PACKAGE_NAME))
81                 .thenReturn(null);
82         Mockito.when(
83                         mockPackageManager.getLeanbackLaunchIntentForPackage(
84                                 LIVE_CHANNELS_PACKAGE_NAME))
85                 .thenReturn(liveChannelsIntent);
86         Mockito.when(
87                         mockPackageManager.getLeanbackLaunchIntentForPackage(
88                                 NONE_LEANBACK_TV_INPUT_PACKAGE_NAME))
89                 .thenReturn(null);
90         Mockito.when(
91                         mockPackageManager.getLeanbackLaunchIntentForPackage(
92                                 LEANBACK_TV_INPUT_PACKAGE_NAME))
93                 .thenReturn(leanbackTvInputIntent);
94 
95         // Channel.getAppLinkIntent() calls initAppLinkTypeAndIntent() which calls
96         // Intent.resolveActivityInfo() which calls PackageManager.getActivityInfo().
97         Mockito.doAnswer(
98                         new Answer<ActivityInfo>() {
99                             @Override
100                             public ActivityInfo answer(InvocationOnMock invocation) {
101                                 // We only check the package name, since the class name can be
102                                 // changed
103                                 // when an intent is changed to an uri and created from the uri.
104                                 // (ex, ".className" -> "packageName.className")
105                                 return mValidIntent
106                                                 .getComponent()
107                                                 .getPackageName()
108                                                 .equals(
109                                                         ((ComponentName)
110                                                                         invocation
111                                                                                 .getArguments()[0])
112                                                                 .getPackageName())
113                                         ? TEST_ACTIVITY_INFO
114                                         : null;
115                             }
116                         })
117                 .when(mockPackageManager)
118                 .getActivityInfo(Mockito.<ComponentName>any(), Mockito.anyInt());
119 
120         mMockContext = Mockito.mock(Context.class);
121         Mockito.when(mMockContext.getApplicationContext()).thenReturn(mMockContext);
122         Mockito.when(mMockContext.getPackageName()).thenReturn(LIVE_CHANNELS_PACKAGE_NAME);
123         Mockito.when(mMockContext.getPackageManager()).thenReturn(mockPackageManager);
124     }
125 
126     @Test
testGetAppLinkType_NoText_NoIntent()127     public void testGetAppLinkType_NoText_NoIntent() {
128         assertAppLinkType(Channel.APP_LINK_TYPE_NONE, INVALID_TV_INPUT_PACKAGE_NAME, null, null);
129         assertAppLinkType(Channel.APP_LINK_TYPE_NONE, LIVE_CHANNELS_PACKAGE_NAME, null, null);
130         assertAppLinkType(
131                 Channel.APP_LINK_TYPE_NONE, NONE_LEANBACK_TV_INPUT_PACKAGE_NAME, null, null);
132         assertAppLinkType(Channel.APP_LINK_TYPE_APP, LEANBACK_TV_INPUT_PACKAGE_NAME, null, null);
133     }
134 
135     @Test
testGetAppLinkType_NoText_InvalidIntent()136     public void testGetAppLinkType_NoText_InvalidIntent() {
137         assertAppLinkType(
138                 Channel.APP_LINK_TYPE_NONE, INVALID_TV_INPUT_PACKAGE_NAME, null, mInvalidIntent);
139         assertAppLinkType(
140                 Channel.APP_LINK_TYPE_NONE, LIVE_CHANNELS_PACKAGE_NAME, null, mInvalidIntent);
141         assertAppLinkType(
142                 Channel.APP_LINK_TYPE_NONE,
143                 NONE_LEANBACK_TV_INPUT_PACKAGE_NAME,
144                 null,
145                 mInvalidIntent);
146         assertAppLinkType(
147                 Channel.APP_LINK_TYPE_APP, LEANBACK_TV_INPUT_PACKAGE_NAME, null, mInvalidIntent);
148     }
149 
150     @Test
testGetAppLinkType_NoText_ValidIntent()151     public void testGetAppLinkType_NoText_ValidIntent() {
152         assertAppLinkType(
153                 Channel.APP_LINK_TYPE_NONE, INVALID_TV_INPUT_PACKAGE_NAME, null, mValidIntent);
154         assertAppLinkType(
155                 Channel.APP_LINK_TYPE_NONE, LIVE_CHANNELS_PACKAGE_NAME, null, mValidIntent);
156         assertAppLinkType(
157                 Channel.APP_LINK_TYPE_NONE,
158                 NONE_LEANBACK_TV_INPUT_PACKAGE_NAME,
159                 null,
160                 mValidIntent);
161         assertAppLinkType(
162                 Channel.APP_LINK_TYPE_APP, LEANBACK_TV_INPUT_PACKAGE_NAME, null, mValidIntent);
163     }
164 
165     @Test
testGetAppLinkType_HasText_NoIntent()166     public void testGetAppLinkType_HasText_NoIntent() {
167         assertAppLinkType(
168                 Channel.APP_LINK_TYPE_NONE,
169                 INVALID_TV_INPUT_PACKAGE_NAME,
170                 TEST_APP_LINK_TEXT,
171                 null);
172         assertAppLinkType(
173                 Channel.APP_LINK_TYPE_NONE, LIVE_CHANNELS_PACKAGE_NAME, TEST_APP_LINK_TEXT, null);
174         assertAppLinkType(
175                 Channel.APP_LINK_TYPE_NONE,
176                 NONE_LEANBACK_TV_INPUT_PACKAGE_NAME,
177                 TEST_APP_LINK_TEXT,
178                 null);
179         assertAppLinkType(
180                 Channel.APP_LINK_TYPE_APP,
181                 LEANBACK_TV_INPUT_PACKAGE_NAME,
182                 TEST_APP_LINK_TEXT,
183                 null);
184     }
185 
186     @Test
testGetAppLinkType_HasText_InvalidIntent()187     public void testGetAppLinkType_HasText_InvalidIntent() {
188         assertAppLinkType(
189                 Channel.APP_LINK_TYPE_NONE,
190                 INVALID_TV_INPUT_PACKAGE_NAME,
191                 TEST_APP_LINK_TEXT,
192                 mInvalidIntent);
193         assertAppLinkType(
194                 Channel.APP_LINK_TYPE_NONE,
195                 LIVE_CHANNELS_PACKAGE_NAME,
196                 TEST_APP_LINK_TEXT,
197                 mInvalidIntent);
198         assertAppLinkType(
199                 Channel.APP_LINK_TYPE_NONE,
200                 NONE_LEANBACK_TV_INPUT_PACKAGE_NAME,
201                 TEST_APP_LINK_TEXT,
202                 mInvalidIntent);
203         assertAppLinkType(
204                 Channel.APP_LINK_TYPE_APP,
205                 LEANBACK_TV_INPUT_PACKAGE_NAME,
206                 TEST_APP_LINK_TEXT,
207                 mInvalidIntent);
208     }
209 
210     @Test
testGetAppLinkType_HasText_ValidIntent()211     public void testGetAppLinkType_HasText_ValidIntent() {
212         assertAppLinkType(
213                 Channel.APP_LINK_TYPE_CHANNEL,
214                 INVALID_TV_INPUT_PACKAGE_NAME,
215                 TEST_APP_LINK_TEXT,
216                 mValidIntent);
217         assertAppLinkType(
218                 Channel.APP_LINK_TYPE_CHANNEL,
219                 LIVE_CHANNELS_PACKAGE_NAME,
220                 TEST_APP_LINK_TEXT,
221                 mValidIntent);
222         assertAppLinkType(
223                 Channel.APP_LINK_TYPE_CHANNEL,
224                 NONE_LEANBACK_TV_INPUT_PACKAGE_NAME,
225                 TEST_APP_LINK_TEXT,
226                 mValidIntent);
227         assertAppLinkType(
228                 Channel.APP_LINK_TYPE_CHANNEL,
229                 LEANBACK_TV_INPUT_PACKAGE_NAME,
230                 TEST_APP_LINK_TEXT,
231                 mValidIntent);
232     }
233 
assertAppLinkType( int expectedType, String inputPackageName, String appLinkText, Intent appLinkIntent)234     private void assertAppLinkType(
235             int expectedType, String inputPackageName, String appLinkText, Intent appLinkIntent) {
236         // In ChannelImpl, Intent.URI_INTENT_SCHEME is used to parse the URI. So the same flag
237         // should be
238         // used when the URI is created.
239         ChannelImpl testChannel =
240                 new ChannelImpl.Builder()
241                         .setPackageName(inputPackageName)
242                         .setAppLinkText(appLinkText)
243                         .setAppLinkIntentUri(
244                                 appLinkIntent == null
245                                         ? null
246                                         : appLinkIntent.toUri(Intent.URI_INTENT_SCHEME))
247                         .build();
248         assertWithMessage("Unexpected app-link type for for " + testChannel)
249                 .that(testChannel.getAppLinkType(mMockContext))
250                 .isEqualTo(expectedType);
251     }
252 
253     @Test
testComparator()254     public void testComparator() {
255         TvInputManagerHelper manager = Mockito.mock(TvInputManagerHelper.class);
256         Mockito.when(manager.isPartnerInput(Matchers.anyString()))
257                 .thenAnswer(
258                         new Answer<Boolean>() {
259                             @Override
260                             public Boolean answer(InvocationOnMock invocation) throws Throwable {
261                                 String inputId = (String) invocation.getArguments()[0];
262                                 return PARTNER_INPUT_ID.equals(inputId);
263                             }
264                         });
265         Comparator<Channel> comparator = new TestChannelComparator(manager);
266         ComparatorTester<Channel> comparatorTester = ComparatorTester.withoutEqualsTest(comparator);
267         comparatorTester.addComparableGroup(
268                 new ChannelImpl.Builder().setInputId(PARTNER_INPUT_ID).build());
269         comparatorTester.addComparableGroup(new ChannelImpl.Builder().setInputId("1").build());
270         comparatorTester.addComparableGroup(
271                 new ChannelImpl.Builder().setInputId("1").setDisplayNumber("2").build());
272         comparatorTester.addComparableGroup(
273                 new ChannelImpl.Builder().setInputId("2").setDisplayNumber("1.0").build());
274 
275         // display name does not affect comparator
276         comparatorTester.addComparableGroup(
277                 new ChannelImpl.Builder()
278                         .setInputId("2")
279                         .setDisplayNumber("1.62")
280                         .setDisplayName("test1")
281                         .build(),
282                 new ChannelImpl.Builder()
283                         .setInputId("2")
284                         .setDisplayNumber("1.62")
285                         .setDisplayName("test2")
286                         .build(),
287                 new ChannelImpl.Builder()
288                         .setInputId("2")
289                         .setDisplayNumber("1.62")
290                         .setDisplayName("test3")
291                         .build());
292         comparatorTester.addComparableGroup(
293                 new ChannelImpl.Builder().setInputId("2").setDisplayNumber("2.0").build());
294         // Numeric display number sorting
295         comparatorTester.addComparableGroup(
296                 new ChannelImpl.Builder().setInputId("2").setDisplayNumber("12.2").build());
297         comparatorTester.test();
298     }
299 
300     /**
301      * Test Input Label handled by {@link ChannelImpl.DefaultComparator}.
302      *
303      * <p>Sort partner inputs first, then sort by input label, then by input id. See <a
304      * href="http://b/23031603">b/23031603</a>.
305      */
306     @Test
testComparatorLabel()307     public void testComparatorLabel() {
308         TvInputManagerHelper manager = Mockito.mock(TvInputManagerHelper.class);
309         Mockito.when(manager.isPartnerInput(Matchers.anyString()))
310                 .thenAnswer(
311                         new Answer<Boolean>() {
312                             @Override
313                             public Boolean answer(InvocationOnMock invocation) throws Throwable {
314                                 String inputId = (String) invocation.getArguments()[0];
315                                 return PARTNER_INPUT_ID.equals(inputId);
316                             }
317                         });
318         Comparator<Channel> comparator = new ChannelComparatorWithDescriptionAsLabel(manager);
319         ComparatorTester<Channel> comparatorTester = ComparatorTester.withoutEqualsTest(comparator);
320 
321         comparatorTester.addComparableGroup(
322                 new ChannelImpl.Builder().setInputId(PARTNER_INPUT_ID).setDescription("A").build());
323 
324         // The description is used as a label for this test.
325         comparatorTester.addComparableGroup(
326                 new ChannelImpl.Builder().setDescription("A").setInputId("1").build());
327         comparatorTester.addComparableGroup(
328                 new ChannelImpl.Builder().setDescription("A").setInputId("2").build());
329         comparatorTester.addComparableGroup(
330                 new ChannelImpl.Builder().setDescription("B").setInputId("1").build());
331 
332         comparatorTester.test();
333     }
334 
335     @Test
testNormalizeChannelNumber()336     public void testNormalizeChannelNumber() {
337         assertNormalizedDisplayNumber(null, null);
338         assertNormalizedDisplayNumber("", "");
339         assertNormalizedDisplayNumber("1", "1");
340         assertNormalizedDisplayNumber("abcde", "abcde");
341         assertNormalizedDisplayNumber("1-1", "1-1");
342         assertNormalizedDisplayNumber("1.1", "1-1");
343         assertNormalizedDisplayNumber("1 1", "1-1");
344         assertNormalizedDisplayNumber("1\u058a1", "1-1");
345         assertNormalizedDisplayNumber("1\u05be1", "1-1");
346         assertNormalizedDisplayNumber("1\u14001", "1-1");
347         assertNormalizedDisplayNumber("1\u18061", "1-1");
348         assertNormalizedDisplayNumber("1\u20101", "1-1");
349         assertNormalizedDisplayNumber("1\u20111", "1-1");
350         assertNormalizedDisplayNumber("1\u20121", "1-1");
351         assertNormalizedDisplayNumber("1\u20131", "1-1");
352         assertNormalizedDisplayNumber("1\u20141", "1-1");
353     }
354 
assertNormalizedDisplayNumber(String displayNumber, String normalized)355     private void assertNormalizedDisplayNumber(String displayNumber, String normalized) {
356         assertThat(ChannelImpl.normalizeDisplayNumber(displayNumber)).isEqualTo(normalized);
357     }
358 
359     private static final class TestChannelComparator extends ChannelImpl.DefaultComparator {
TestChannelComparator(TvInputManagerHelper manager)360         public TestChannelComparator(TvInputManagerHelper manager) {
361             super(null, manager);
362         }
363 
364         @Override
getInputLabelForChannel(Channel channel)365         public String getInputLabelForChannel(Channel channel) {
366             return channel.getInputId();
367         }
368     }
369 
370     private static final class ChannelComparatorWithDescriptionAsLabel
371             extends ChannelImpl.DefaultComparator {
ChannelComparatorWithDescriptionAsLabel(TvInputManagerHelper manager)372         public ChannelComparatorWithDescriptionAsLabel(TvInputManagerHelper manager) {
373             super(null, manager);
374         }
375 
376         @Override
getInputLabelForChannel(Channel channel)377         public String getInputLabelForChannel(Channel channel) {
378             return channel.getDescription();
379         }
380     }
381 }
382