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