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