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.support.test.filters.SmallTest; 25 import android.test.AndroidTestCase; 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 setUp()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 testGetAppLinkType_NoText_NoIntent()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 testGetAppLinkType_NoText_InvalidIntent()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 testGetAppLinkType_NoText_ValidIntent()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 testGetAppLinkType_HasText_NoIntent()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 testGetAppLinkType_HasText_InvalidIntent()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 testGetAppLinkType_HasText_ValidIntent()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 assertAppLinkType(int expectedType, String inputPackageName, String appLinkText, Intent appLinkIntent)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 testComparator()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 return PARTNER_INPUT_ID.equals(inputId); 192 } 193 }); 194 Comparator<Channel> comparator = new TestChannelComparator(manager); 195 ComparatorTester<Channel> comparatorTester = 196 ComparatorTester.withoutEqualsTest(comparator); 197 comparatorTester.addComparableGroup( 198 new Channel.Builder().setInputId(PARTNER_INPUT_ID).build()); 199 comparatorTester.addComparableGroup( 200 new Channel.Builder().setInputId("1").build()); 201 comparatorTester.addComparableGroup( 202 new Channel.Builder().setInputId("1").setDisplayNumber("2").build()); 203 comparatorTester.addComparableGroup( 204 new Channel.Builder().setInputId("2").setDisplayNumber("1.0").build()); 205 206 // display name does not affect comparator 207 comparatorTester.addComparableGroup( 208 new Channel.Builder().setInputId("2").setDisplayNumber("1.62") 209 .setDisplayName("test1").build(), 210 new Channel.Builder().setInputId("2").setDisplayNumber("1.62") 211 .setDisplayName("test2").build(), 212 new Channel.Builder().setInputId("2").setDisplayNumber("1.62") 213 .setDisplayName("test3").build()); 214 comparatorTester.addComparableGroup( 215 new Channel.Builder().setInputId("2").setDisplayNumber("2.0").build()); 216 // Numeric display number sorting 217 comparatorTester.addComparableGroup( 218 new Channel.Builder().setInputId("2").setDisplayNumber("12.2").build()); 219 comparatorTester.test(); 220 } 221 222 /** 223 * Test Input Label handled by {@link com.android.tv.data.Channel.DefaultComparator}. 224 * 225 * <p>Sort partner inputs first, then sort by input label, then by input id. 226 * See <a href="http://b/23031603">b/23031603</a>. 227 */ testComparatorLabel()228 public void testComparatorLabel() { 229 230 TvInputManagerHelper manager = Mockito.mock(TvInputManagerHelper.class); 231 Mockito.when(manager.isPartnerInput(Matchers.anyString())).thenAnswer( 232 new Answer<Boolean>() { 233 @Override 234 public Boolean answer(InvocationOnMock invocation) throws Throwable { 235 String inputId = (String) invocation.getArguments()[0]; 236 return PARTNER_INPUT_ID.equals(inputId); 237 } 238 }); 239 Comparator<Channel> comparator = new ChannelComparatorWithDescriptionAsLabel(manager); 240 ComparatorTester<Channel> comparatorTester = 241 ComparatorTester.withoutEqualsTest(comparator); 242 243 comparatorTester.addComparableGroup( 244 new Channel.Builder().setInputId(PARTNER_INPUT_ID).setDescription("A").build()); 245 246 // The description is used as a label for this test. 247 comparatorTester.addComparableGroup( 248 new Channel.Builder().setDescription("A").setInputId("1").build()); 249 comparatorTester.addComparableGroup( 250 new Channel.Builder().setDescription("A").setInputId("2").build()); 251 comparatorTester.addComparableGroup( 252 new Channel.Builder().setDescription("B").setInputId("1").build()); 253 254 comparatorTester.test(); 255 } 256 257 private class TestChannelComparator extends Channel.DefaultComparator { TestChannelComparator(TvInputManagerHelper manager)258 public TestChannelComparator(TvInputManagerHelper manager) { 259 super(null, manager); 260 } 261 262 @Override getInputLabelForChannel(Channel channel)263 public String getInputLabelForChannel(Channel channel) { 264 return channel.getInputId(); 265 } 266 } 267 268 private static class ChannelComparatorWithDescriptionAsLabel extends Channel.DefaultComparator { ChannelComparatorWithDescriptionAsLabel(TvInputManagerHelper manager)269 public ChannelComparatorWithDescriptionAsLabel(TvInputManagerHelper manager) { 270 super(null, manager); 271 } 272 273 @Override getInputLabelForChannel(Channel channel)274 public String getInputLabelForChannel(Channel channel) { 275 return channel.getDescription(); 276 } 277 } 278 } 279