/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.tv.data; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.support.test.filters.SmallTest; import android.test.AndroidTestCase; import com.android.tv.testing.ComparatorTester; import com.android.tv.util.TvInputManagerHelper; import org.mockito.Matchers; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import java.util.Comparator; /** * Tests for {@link Channel}. */ @SmallTest public class ChannelTest extends AndroidTestCase { // Used for testing TV inputs with invalid input package. This could happen when a TV input is // uninstalled while drawing an app link card. private static final String INVALID_TV_INPUT_PACKAGE_NAME = "com.android.tv.invalid_tv_input"; // Used for testing TV inputs defined inside of Live TV. private static final String LIVE_CHANNELS_PACKAGE_NAME = "com.android.tv"; // Used for testing a TV input which doesn't have its leanback launcher activity. private static final String NONE_LEANBACK_TV_INPUT_PACKAGE_NAME = "com.android.tv.none_leanback_tv_input"; // Used for testing a TV input which has its leanback launcher activity. private static final String LEANBACK_TV_INPUT_PACKAGE_NAME = "com.android.tv.leanback_tv_input"; private static final String TEST_APP_LINK_TEXT = "test_app_link_text"; private static final String PARTNER_INPUT_ID = "partner"; private static final ActivityInfo TEST_ACTIVITY_INFO = new ActivityInfo(); private Context mMockContext; private Intent mInvalidIntent; private Intent mValidIntent; @Override public void setUp() throws Exception { super.setUp(); mInvalidIntent = new Intent(Intent.ACTION_VIEW); mInvalidIntent.setComponent(new ComponentName(INVALID_TV_INPUT_PACKAGE_NAME, ".test")); mValidIntent = new Intent(Intent.ACTION_VIEW); mValidIntent.setComponent(new ComponentName(LEANBACK_TV_INPUT_PACKAGE_NAME, ".test")); Intent liveChannelsIntent = new Intent(Intent.ACTION_VIEW); liveChannelsIntent.setComponent( new ComponentName(LIVE_CHANNELS_PACKAGE_NAME, ".MainActivity")); Intent leanbackTvInputIntent = new Intent(Intent.ACTION_VIEW); leanbackTvInputIntent.setComponent( new ComponentName(LEANBACK_TV_INPUT_PACKAGE_NAME, ".test")); PackageManager mockPackageManager = Mockito.mock(PackageManager.class); Mockito.when(mockPackageManager.getLeanbackLaunchIntentForPackage( INVALID_TV_INPUT_PACKAGE_NAME)).thenReturn(null); Mockito.when(mockPackageManager.getLeanbackLaunchIntentForPackage( LIVE_CHANNELS_PACKAGE_NAME)).thenReturn(liveChannelsIntent); Mockito.when(mockPackageManager.getLeanbackLaunchIntentForPackage( NONE_LEANBACK_TV_INPUT_PACKAGE_NAME)).thenReturn(null); Mockito.when(mockPackageManager.getLeanbackLaunchIntentForPackage( LEANBACK_TV_INPUT_PACKAGE_NAME)).thenReturn(leanbackTvInputIntent); // Channel.getAppLinkIntent() calls initAppLinkTypeAndIntent() which calls // Intent.resolveActivityInfo() which calls PackageManager.getActivityInfo(). Mockito.doAnswer(new Answer() { @Override public ActivityInfo answer(InvocationOnMock invocation) { // We only check the package name, since the class name can be changed // when an intent is changed to an uri and created from the uri. // (ex, ".className" -> "packageName.className") return mValidIntent.getComponent().getPackageName().equals( ((ComponentName)invocation.getArguments()[0]).getPackageName()) ? TEST_ACTIVITY_INFO : null; } }).when(mockPackageManager).getActivityInfo(Mockito.any(), Mockito.anyInt()); mMockContext = Mockito.mock(Context.class); Mockito.when(mMockContext.getApplicationContext()).thenReturn(mMockContext); Mockito.when(mMockContext.getPackageName()).thenReturn(LIVE_CHANNELS_PACKAGE_NAME); Mockito.when(mMockContext.getPackageManager()).thenReturn(mockPackageManager); } public void testGetAppLinkType_NoText_NoIntent() { assertAppLinkType(Channel.APP_LINK_TYPE_NONE, INVALID_TV_INPUT_PACKAGE_NAME, null, null); assertAppLinkType(Channel.APP_LINK_TYPE_NONE, LIVE_CHANNELS_PACKAGE_NAME, null, null); assertAppLinkType(Channel.APP_LINK_TYPE_NONE, NONE_LEANBACK_TV_INPUT_PACKAGE_NAME, null, null); assertAppLinkType(Channel.APP_LINK_TYPE_APP, LEANBACK_TV_INPUT_PACKAGE_NAME, null, null); } public void testGetAppLinkType_NoText_InvalidIntent() { assertAppLinkType(Channel.APP_LINK_TYPE_NONE, INVALID_TV_INPUT_PACKAGE_NAME, null, mInvalidIntent); assertAppLinkType(Channel.APP_LINK_TYPE_NONE, LIVE_CHANNELS_PACKAGE_NAME, null, mInvalidIntent); assertAppLinkType(Channel.APP_LINK_TYPE_NONE, NONE_LEANBACK_TV_INPUT_PACKAGE_NAME, null, mInvalidIntent); assertAppLinkType(Channel.APP_LINK_TYPE_APP, LEANBACK_TV_INPUT_PACKAGE_NAME, null, mInvalidIntent); } public void testGetAppLinkType_NoText_ValidIntent() { assertAppLinkType(Channel.APP_LINK_TYPE_NONE, INVALID_TV_INPUT_PACKAGE_NAME, null, mValidIntent); assertAppLinkType(Channel.APP_LINK_TYPE_NONE, LIVE_CHANNELS_PACKAGE_NAME, null, mValidIntent); assertAppLinkType(Channel.APP_LINK_TYPE_NONE, NONE_LEANBACK_TV_INPUT_PACKAGE_NAME, null, mValidIntent); assertAppLinkType(Channel.APP_LINK_TYPE_APP, LEANBACK_TV_INPUT_PACKAGE_NAME, null, mValidIntent); } public void testGetAppLinkType_HasText_NoIntent() { assertAppLinkType(Channel.APP_LINK_TYPE_NONE, INVALID_TV_INPUT_PACKAGE_NAME, TEST_APP_LINK_TEXT, null); assertAppLinkType(Channel.APP_LINK_TYPE_NONE, LIVE_CHANNELS_PACKAGE_NAME, TEST_APP_LINK_TEXT, null); assertAppLinkType(Channel.APP_LINK_TYPE_NONE, NONE_LEANBACK_TV_INPUT_PACKAGE_NAME, TEST_APP_LINK_TEXT, null); assertAppLinkType(Channel.APP_LINK_TYPE_APP, LEANBACK_TV_INPUT_PACKAGE_NAME, TEST_APP_LINK_TEXT, null); } public void testGetAppLinkType_HasText_InvalidIntent() { assertAppLinkType(Channel.APP_LINK_TYPE_NONE, INVALID_TV_INPUT_PACKAGE_NAME, TEST_APP_LINK_TEXT, mInvalidIntent); assertAppLinkType(Channel.APP_LINK_TYPE_NONE, LIVE_CHANNELS_PACKAGE_NAME, TEST_APP_LINK_TEXT, mInvalidIntent); assertAppLinkType(Channel.APP_LINK_TYPE_NONE, NONE_LEANBACK_TV_INPUT_PACKAGE_NAME, TEST_APP_LINK_TEXT, mInvalidIntent); assertAppLinkType(Channel.APP_LINK_TYPE_APP, LEANBACK_TV_INPUT_PACKAGE_NAME, TEST_APP_LINK_TEXT, mInvalidIntent); } public void testGetAppLinkType_HasText_ValidIntent() { assertAppLinkType(Channel.APP_LINK_TYPE_CHANNEL, INVALID_TV_INPUT_PACKAGE_NAME, TEST_APP_LINK_TEXT, mValidIntent); assertAppLinkType(Channel.APP_LINK_TYPE_CHANNEL, LIVE_CHANNELS_PACKAGE_NAME, TEST_APP_LINK_TEXT, mValidIntent); assertAppLinkType(Channel.APP_LINK_TYPE_CHANNEL, NONE_LEANBACK_TV_INPUT_PACKAGE_NAME, TEST_APP_LINK_TEXT, mValidIntent); assertAppLinkType(Channel.APP_LINK_TYPE_CHANNEL, LEANBACK_TV_INPUT_PACKAGE_NAME, TEST_APP_LINK_TEXT, mValidIntent); } private void assertAppLinkType(int expectedType, String inputPackageName, String appLinkText, Intent appLinkIntent) { // In Channel, Intent.URI_INTENT_SCHEME is used to parse the URI. So the same flag should be // used when the URI is created. Channel testChannel = new Channel.Builder() .setPackageName(inputPackageName) .setAppLinkText(appLinkText) .setAppLinkIntentUri(appLinkIntent == null ? null : appLinkIntent.toUri( Intent.URI_INTENT_SCHEME)) .build(); assertEquals("Unexpected app-link type for for " + testChannel, expectedType, testChannel.getAppLinkType(mMockContext)); } public void testComparator() { TvInputManagerHelper manager = Mockito.mock(TvInputManagerHelper.class); Mockito.when(manager.isPartnerInput(Matchers.anyString())).thenAnswer( new Answer() { @Override public Boolean answer(InvocationOnMock invocation) throws Throwable { String inputId = (String) invocation.getArguments()[0]; return PARTNER_INPUT_ID.equals(inputId); } }); Comparator comparator = new TestChannelComparator(manager); ComparatorTester comparatorTester = ComparatorTester.withoutEqualsTest(comparator); comparatorTester.addComparableGroup( new Channel.Builder().setInputId(PARTNER_INPUT_ID).build()); comparatorTester.addComparableGroup( new Channel.Builder().setInputId("1").build()); comparatorTester.addComparableGroup( new Channel.Builder().setInputId("1").setDisplayNumber("2").build()); comparatorTester.addComparableGroup( new Channel.Builder().setInputId("2").setDisplayNumber("1.0").build()); // display name does not affect comparator comparatorTester.addComparableGroup( new Channel.Builder().setInputId("2").setDisplayNumber("1.62") .setDisplayName("test1").build(), new Channel.Builder().setInputId("2").setDisplayNumber("1.62") .setDisplayName("test2").build(), new Channel.Builder().setInputId("2").setDisplayNumber("1.62") .setDisplayName("test3").build()); comparatorTester.addComparableGroup( new Channel.Builder().setInputId("2").setDisplayNumber("2.0").build()); // Numeric display number sorting comparatorTester.addComparableGroup( new Channel.Builder().setInputId("2").setDisplayNumber("12.2").build()); comparatorTester.test(); } /** * Test Input Label handled by {@link com.android.tv.data.Channel.DefaultComparator}. * *

Sort partner inputs first, then sort by input label, then by input id. * See b/23031603. */ public void testComparatorLabel() { TvInputManagerHelper manager = Mockito.mock(TvInputManagerHelper.class); Mockito.when(manager.isPartnerInput(Matchers.anyString())).thenAnswer( new Answer() { @Override public Boolean answer(InvocationOnMock invocation) throws Throwable { String inputId = (String) invocation.getArguments()[0]; return PARTNER_INPUT_ID.equals(inputId); } }); Comparator comparator = new ChannelComparatorWithDescriptionAsLabel(manager); ComparatorTester comparatorTester = ComparatorTester.withoutEqualsTest(comparator); comparatorTester.addComparableGroup( new Channel.Builder().setInputId(PARTNER_INPUT_ID).setDescription("A").build()); // The description is used as a label for this test. comparatorTester.addComparableGroup( new Channel.Builder().setDescription("A").setInputId("1").build()); comparatorTester.addComparableGroup( new Channel.Builder().setDescription("A").setInputId("2").build()); comparatorTester.addComparableGroup( new Channel.Builder().setDescription("B").setInputId("1").build()); comparatorTester.test(); } private class TestChannelComparator extends Channel.DefaultComparator { public TestChannelComparator(TvInputManagerHelper manager) { super(null, manager); } @Override public String getInputLabelForChannel(Channel channel) { return channel.getInputId(); } } private static class ChannelComparatorWithDescriptionAsLabel extends Channel.DefaultComparator { public ChannelComparatorWithDescriptionAsLabel(TvInputManagerHelper manager) { super(null, manager); } @Override public String getInputLabelForChannel(Channel channel) { return channel.getDescription(); } } }