diff options
Diffstat (limited to 'tests')
135 files changed, 7933 insertions, 6825 deletions
diff --git a/tests/common/Android.mk b/tests/common/Android.mk index 27c9f031..2e80aa2b 100644 --- a/tests/common/Android.mk +++ b/tests/common/Android.mk @@ -8,8 +8,12 @@ LOCAL_SRC_FILES := \ LOCAL_STATIC_JAVA_LIBRARIES := \ android-support-annotations \ + android-support-test \ + guava \ mockito-target \ - ub-uiautomator + platform-robolectric-3.6.1-prebuilt \ + truth-0-36-prebuilt-jar \ + ub-uiautomator \ # Link tv-common as shared library to avoid the problem of initialization of the constants LOCAL_JAVA_LIBRARIES := tv-common @@ -17,7 +21,7 @@ LOCAL_JAVA_LIBRARIES := tv-common LOCAL_INSTRUMENTATION_FOR := LiveTv LOCAL_MODULE := tv-test-common LOCAL_MODULE_TAGS := optional -LOCAL_SDK_VERSION := current +LOCAL_SDK_VERSION := system_current LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res LOCAL_AIDL_INCLUDES += $(LOCAL_PATH)/src diff --git a/tests/common/AndroidManifest.xml b/tests/common/AndroidManifest.xml index f3ed9a9f..8afd8dc9 100644 --- a/tests/common/AndroidManifest.xml +++ b/tests/common/AndroidManifest.xml @@ -18,6 +18,6 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.tv.testing" android:versionCode="1"> - <uses-sdk android:targetSdkVersion="23" android:minSdkVersion="21"/> + <uses-sdk android:targetSdkVersion="26" android:minSdkVersion="21"/> <application /> </manifest> diff --git a/tests/common/src/com/android/tv/input/TunerHelper.java b/tests/common/src/com/android/tv/input/TunerHelper.java index 126d5027..08c4b041 100644 --- a/tests/common/src/com/android/tv/input/TunerHelper.java +++ b/tests/common/src/com/android/tv/input/TunerHelper.java @@ -19,14 +19,11 @@ package com.android.tv.input; import android.net.Uri; import android.support.annotation.Nullable; import android.util.Log; - import java.util.ArrayList; import java.util.Iterator; import java.util.List; -/** - * A class to manage fake tuners for the tune and the recording. - */ +/** A class to manage fake tuners for the tune and the recording. */ public class TunerHelper { private static final String TAG = "TunerHelper"; private static final boolean DEBUG = false; @@ -38,9 +35,7 @@ public class TunerHelper { mTunerCount = tunerCount; } - /** - * Checks whether there are available tuners for the recording. - */ + /** Checks whether there are available tuners for the recording. */ public boolean tunerAvailableForRecording() { if (mTuners.size() < mTunerCount) { return true; @@ -54,8 +49,8 @@ public class TunerHelper { } /** - * Checks whether there is available tuner. - * If there's available tuner, it is assigned to the channel. + * Checks whether there is available tuner. If there's available tuner, it is assigned to the + * channel. */ public boolean tune(@Nullable Uri channelUri, boolean forRecording) { if (channelUri == null) { @@ -82,9 +77,7 @@ public class TunerHelper { return false; } - /** - * Releases the tuner which was being used for the tune. - */ + /** Releases the tuner which was being used for the tune. */ public void stopTune(@Nullable Uri channelUri) { if (channelUri == null) { return; @@ -110,9 +103,7 @@ public class TunerHelper { } } - /** - * Releases the tuner which was being used for the recording. - */ + /** Releases the tuner which was being used for the recording. */ public void stopRecording(@Nullable Uri channelUri) { if (channelUri == null) { return; @@ -146,7 +137,7 @@ public class TunerHelper { public boolean tuning; public boolean recording; - public Tuner (Uri channelUri, boolean forRecording) { + public Tuner(Uri channelUri, boolean forRecording) { this.channelUri = channelUri; this.tuning = !forRecording; this.recording = forRecording; diff --git a/tests/common/src/com/android/tv/testing/ChannelNumberSubject.java b/tests/common/src/com/android/tv/testing/ChannelNumberSubject.java new file mode 100644 index 00000000..ba4662ee --- /dev/null +++ b/tests/common/src/com/android/tv/testing/ChannelNumberSubject.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2017 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.testing; + +import android.support.annotation.Nullable; +import com.android.tv.data.ChannelNumber; +import com.google.common.truth.ComparableSubject; +import com.google.common.truth.FailureMetadata; +import com.google.common.truth.Subject; +import com.google.common.truth.Truth; + +/** Propositions for {@link ChannelNumber} subjects. */ +public final class ChannelNumberSubject + extends ComparableSubject<ChannelNumberSubject, ChannelNumber> { + private static final Subject.Factory<ChannelNumberSubject, ChannelNumber> FACTORY = + ChannelNumberSubject::new; + + public static Subject.Factory<ChannelNumberSubject, ChannelNumber> channelNumbers() { + return FACTORY; + } + + public static ChannelNumberSubject assertThat(@Nullable ChannelNumber actual) { + return Truth.assertAbout(channelNumbers()).that(actual); + } + + public ChannelNumberSubject(FailureMetadata failureMetadata, @Nullable ChannelNumber subject) { + super(failureMetadata, subject); + } + + public void displaysAs(int major) { + if (!getSubject().majorNumber.equals(Integer.toString(major)) + || getSubject().hasDelimiter) { + fail("displaysAs", major); + } + } + + public void displaysAs(int major, int minor) { + if (!getSubject().majorNumber.equals(Integer.toString(major)) + || !getSubject().minorNumber.equals(Integer.toString(minor)) + || !getSubject().hasDelimiter) { + fail("displaysAs", major + "-" + minor); + } + } + + public void isEmpty() { + if (!getSubject().majorNumber.isEmpty() + || !getSubject().minorNumber.isEmpty() + || getSubject().hasDelimiter) { + fail("isEmpty"); + } + } +} diff --git a/tests/common/src/com/android/tv/testing/ComparableTester.java b/tests/common/src/com/android/tv/testing/ComparableTester.java index fe6e72f5..4328deb9 100644 --- a/tests/common/src/com/android/tv/testing/ComparableTester.java +++ b/tests/common/src/com/android/tv/testing/ComparableTester.java @@ -16,22 +16,19 @@ package com.android.tv.testing; -import junit.framework.Assert; - import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; +import junit.framework.Assert; /** * Tester for {@link java.lang.Comparable}s. * - * <p> - * To use, create a new {@link ComparableTester} and add comparable groups - * where each group contains objects that are - * {@link java.util.Comparator#compare(Object, Object)} == 0 to each other. - * Groups are added in order asserting that all earlier groups have compare < 0 - * for all later groups. + * <p>To use, create a new {@link ComparableTester} and add comparable groups where each group + * contains objects that are {@link java.util.Comparator#compare(Object, Object)} == 0 to each + * other. Groups are added in order asserting that all earlier groups have compare < 0 for all later + * groups. * * <pre>{@code * new ComparableTester<String>() @@ -39,8 +36,7 @@ import java.util.List; * .addEquivalentGroup("World", "wORLD") * .addEquivalentGroup("ZEBRA") * .test(); - * } - * </pre> + * }</pre> * * @param <T> the type of objects to compare. */ @@ -74,8 +70,8 @@ public class ComparableTester<T extends Comparable<T>> { assertMore(more, less, moreGroup, lessGroup); } - private void assertLess(int left, int right, Collection<T> leftGroup, - Collection<T> rightGroup) { + private void assertLess( + int left, int right, Collection<T> leftGroup, Collection<T> rightGroup) { int leftSub = 0; for (T leftItem : leftGroup) { int rightSub = 0; @@ -83,14 +79,22 @@ public class ComparableTester<T extends Comparable<T>> { for (T rightItem : rightGroup) { String rightName = "Item[" + right + "," + (rightSub++) + "]"; Assert.assertEquals( - leftName + " " + leftItem + " compareTo " + rightName + " " + rightItem - + " is <0", true, leftItem.compareTo(rightItem) < 0); + leftName + + " " + + leftItem + + " compareTo " + + rightName + + " " + + rightItem + + " is <0", + true, + leftItem.compareTo(rightItem) < 0); } } } - private void assertMore(int left, int right, Collection<T> leftGroup, - Collection<T> rightGroup) { + private void assertMore( + int left, int right, Collection<T> leftGroup, Collection<T> rightGroup) { int leftSub = 0; for (T leftItem : leftGroup) { int rightSub = 0; @@ -98,8 +102,16 @@ public class ComparableTester<T extends Comparable<T>> { for (T rightItem : rightGroup) { String rightName = "Item[" + right + "," + (rightSub++) + "]"; Assert.assertEquals( - leftName + " " + leftItem + " compareTo " + rightName + " " + rightItem - + " is >0", true, leftItem.compareTo(rightItem) > 0); + leftName + + " " + + leftItem + + " compareTo " + + rightName + + " " + + rightItem + + " is >0", + true, + leftItem.compareTo(rightItem) > 0); } } } diff --git a/tests/common/src/com/android/tv/testing/ComparatorTester.java b/tests/common/src/com/android/tv/testing/ComparatorTester.java index 3774532f..6ebd8b4e 100644 --- a/tests/common/src/com/android/tv/testing/ComparatorTester.java +++ b/tests/common/src/com/android/tv/testing/ComparatorTester.java @@ -27,12 +27,9 @@ import java.util.List; /** * Tester for {@link Comparator} relationships between groups of T. * - * <p> - * To use, create a new {@link ComparatorTester} and add comparable groups - * where each group contains objects that are - * {@link Comparator#compare(Object, Object)} == 0 to each other. - * Groups are added in order asserting that all earlier groups have compare < 0 - * for all later groups. + * <p>To use, create a new {@link ComparatorTester} and add comparable groups where each group + * contains objects that are {@link Comparator#compare(Object, Object)} == 0 to each other. Groups + * are added in order asserting that all earlier groups have compare < 0 for all later groups. * * <pre>{@code * ComparatorTester @@ -41,8 +38,7 @@ import java.util.List; * .addComparableGroup("World", "wORLD") * .addComparableGroup("ZEBRA") * .test(); - * } - * </pre> + * }</pre> * * @param <T> the type of objects to compare. */ @@ -52,7 +48,6 @@ public class ComparatorTester<T> { private final Comparator<T> comparator; - public static <T> ComparatorTester<T> withoutEqualsTest(Comparator<T> comparator) { return new ComparatorTester<>(comparator); } @@ -80,7 +75,7 @@ public class ComparatorTester<T> { assertOrder(i, j, currentGroup, rhs); } } - //TODO: also test equals + // TODO: also test equals } private void assertOrder(int less, int more, List<T> lessGroup, List<T> moreGroup) { @@ -88,30 +83,48 @@ public class ComparatorTester<T> { assertMore(more, less, moreGroup, lessGroup); } - private void assertLess(int left, int right, Collection<T> leftGroup, - Collection<T> rightGroup) { + private void assertLess( + int left, int right, Collection<T> leftGroup, Collection<T> rightGroup) { int leftSub = 0; for (T leftItem : leftGroup) { int rightSub = 0; for (T rightItem : rightGroup) { String leftName = "Item[" + left + "," + (leftSub++) + "]"; String rName = "Item[" + right + "," + (rightSub++) + "]"; - assertEquals(leftName + " " + leftItem + " compareTo " + rName + " " + rightItem - + " is <0", true, comparator.compare(leftItem, rightItem) < 0); + assertEquals( + leftName + + " " + + leftItem + + " compareTo " + + rName + + " " + + rightItem + + " is <0", + true, + comparator.compare(leftItem, rightItem) < 0); } } } - private void assertMore(int left, int right, Collection<T> leftGroup, - Collection<T> rightGroup) { + private void assertMore( + int left, int right, Collection<T> leftGroup, Collection<T> rightGroup) { int leftSub = 0; for (T leftItem : leftGroup) { int rightSub = 0; for (T rightItem : rightGroup) { String leftName = "Item[" + left + "," + (leftSub++) + "]"; String rName = "Item[" + right + "," + (rightSub++) + "]"; - assertEquals(leftName + " " + leftItem + " compareTo " + rName + " " + rightItem - + " is >0", true, comparator.compare(leftItem, rightItem) > 0); + assertEquals( + leftName + + " " + + leftItem + + " compareTo " + + rName + + " " + + rightItem + + " is >0", + true, + comparator.compare(leftItem, rightItem) > 0); } } } @@ -120,9 +133,11 @@ public class ComparatorTester<T> { // Test everything against everything in both directions, including against itself. for (T leftItem : group) { for (T rightItem : group) { - assertEquals(leftItem + " compareTo " + rightItem, 0, + assertEquals( + leftItem + " compareTo " + rightItem, + 0, comparator.compare(leftItem, rightItem)); } } } -}
\ No newline at end of file +} diff --git a/tests/common/src/com/android/tv/testing/Constants.java b/tests/common/src/com/android/tv/testing/Constants.java deleted file mode 100644 index 4c9cb5fb..00000000 --- a/tests/common/src/com/android/tv/testing/Constants.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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.testing; - -import android.media.tv.TvTrackInfo; - -/** - * Constants for testing. - */ -public final class Constants { - public static final int FUNC_TEST_CHANNEL_COUNT = 100; - public static final int UNIT_TEST_CHANNEL_COUNT = 4; - public static final int JANK_TEST_CHANNEL_COUNT = 500; // TODO: increase to 1000 see b/23526997 - - public static final TvTrackInfo EN_STEREO_AUDIO_TRACK = new TvTrackInfo.Builder( - TvTrackInfo.TYPE_AUDIO, "English Stereo Audio").setLanguage("en") - .setAudioChannelCount(2).build(); - public static final TvTrackInfo GENERIC_AUDIO_TRACK = new TvTrackInfo.Builder( - TvTrackInfo.TYPE_AUDIO, "Generic Audio").build(); - - public static final TvTrackInfo FHD1080P50_VIDEO_TRACK = new TvTrackInfo.Builder( - TvTrackInfo.TYPE_VIDEO, "FHD Video").setVideoHeight(1080).setVideoWidth(1920) - .setVideoFrameRate(50).build(); - public static final TvTrackInfo SVGA_VIDEO_TRACK = new TvTrackInfo.Builder( - TvTrackInfo.TYPE_VIDEO, "SVGA Video").setVideoHeight(600).setVideoWidth(800).build(); - - private Constants() { - } -} diff --git a/tests/common/src/com/android/tv/testing/DbTestingUtils.java b/tests/common/src/com/android/tv/testing/DbTestingUtils.java new file mode 100644 index 00000000..53e26ca7 --- /dev/null +++ b/tests/common/src/com/android/tv/testing/DbTestingUtils.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2017 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.testing; + +import android.database.Cursor; +import java.util.ArrayList; +import java.util.List; + +/** Static utilities for testing using databases. */ +public final class DbTestingUtils { + + public static List<List<String>> toList(Cursor cursor) { + ArrayList<List<String>> result = new ArrayList<>(); + int colCount = cursor.getColumnCount(); + while (cursor.moveToNext()) { + List<String> row = new ArrayList<>(colCount); + for (int i = 0; i < colCount; i++) { + row.add(cursor.getString(i)); + } + result.add(row); + } + return result; + } + + private DbTestingUtils() {} +} diff --git a/tests/common/src/com/android/tv/testing/EpgTestData.java b/tests/common/src/com/android/tv/testing/EpgTestData.java new file mode 100644 index 00000000..49a92181 --- /dev/null +++ b/tests/common/src/com/android/tv/testing/EpgTestData.java @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2017 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.testing; + +import com.android.tv.data.ChannelImpl; +import com.android.tv.data.Lineup; +import com.android.tv.data.Program; +import com.android.tv.data.api.Channel; +import com.google.common.base.Function; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableListMultimap; +import com.google.common.collect.Iterables; +import com.google.common.collect.ListMultimap; +import java.util.concurrent.TimeUnit; + +/** EPG data for use in tests. */ +public abstract class EpgTestData { + + public static final android.support.media.tv.Channel CHANNEL_10 = + new android.support.media.tv.Channel.Builder() + .setDisplayName("Channel TEN") + .setDisplayNumber("10") + .build(); + public static final android.support.media.tv.Channel CHANNEL_11 = + new android.support.media.tv.Channel.Builder() + .setDisplayName("Channel Eleven") + .setDisplayNumber("11") + .build(); + public static final android.support.media.tv.Channel CHANNEL_90_2 = + new android.support.media.tv.Channel.Builder() + .setDisplayName("Channel Ninety dot Two") + .setDisplayNumber("90.2") + .build(); + + public static final Lineup LINEUP_1 = + new Lineup( + "lineup1", + Lineup.LINEUP_SATELLITE, + "Lineup one", + "Location one", + ImmutableList.of("1", "2.2")); + public static final Lineup LINEUP_2 = + new Lineup( + "lineup2", + Lineup.LINEUP_SATELLITE, + "Lineup two", + "Location two", + ImmutableList.of("1", "2.3")); + + public static final Lineup LINEUP_90210 = + new Lineup( + "test90210", + Lineup.LINEUP_BROADCAST_DIGITAL, + "Test 90210", + "Beverly Hills", + ImmutableList.of("90.2", "10")); + + // Programs start and end times are set relative to 0. + // Then when loaded they are offset by the {@link #getStartTimeMs}. + // Start and end time may be negative meaning they happen before "now". + + public static final Program PROGRAM_1 = + new Program.Builder() + .setTitle("Program 1") + .setStartTimeUtcMillis(0) + .setEndTimeUtcMillis(TimeUnit.MINUTES.toMillis(30)) + .build(); + + public static final Program PROGRAM_2 = + new Program.Builder() + .setTitle("Program 2") + .setStartTimeUtcMillis(TimeUnit.MINUTES.toMillis(30)) + .setEndTimeUtcMillis(TimeUnit.MINUTES.toMillis(60)) + .build(); + + public static final EpgTestData DATA_90210 = + new EpgTestData() { + + // Thursday, June 1, 2017 4:00:00 PM GMT-07:00 + private final long testStartTimeMs = 1496358000000L; + + @Override + public ListMultimap<String, Lineup> getLineups() { + ImmutableListMultimap.Builder<String, Lineup> builder = + ImmutableListMultimap.builder(); + return builder.putAll("90210", LINEUP_1, LINEUP_2, LINEUP_90210).build(); + } + + @Override + public ListMultimap<String, Channel> getLineupChannels() { + ImmutableListMultimap.Builder<String, Channel> builder = + ImmutableListMultimap.builder(); + return builder.putAll( + LINEUP_90210.getId(), toTvChannels(CHANNEL_90_2, CHANNEL_10)) + .putAll(LINEUP_1.getId(), toTvChannels(CHANNEL_10, CHANNEL_11)) + .build(); + } + + @Override + public ListMultimap<String, Program> getEpgPrograms() { + ImmutableListMultimap.Builder<String, Program> builder = + ImmutableListMultimap.builder(); + return builder.putAll( + CHANNEL_10.getDisplayNumber(), + EpgTestData.updateTime(getStartTimeMs(), PROGRAM_1)) + .putAll( + CHANNEL_11.getDisplayNumber(), + EpgTestData.updateTime(getStartTimeMs(), PROGRAM_2)) + .build(); + } + + @Override + public long getStartTimeMs() { + return testStartTimeMs; + } + }; + + public abstract ListMultimap<String, Lineup> getLineups(); + + public abstract ListMultimap<String, Channel> getLineupChannels(); + + public abstract ListMultimap<String, Program> getEpgPrograms(); + + /** The starting time for this test data */ + public abstract long getStartTimeMs(); + + /** + * Loads test data + * + * <p> + * + * <ul> + * <li>Sets clock to {@link #getStartTimeMs()} and boot time to 12 hours before that + * <li>Loads lineups + * <li>Loads lineupChannels + * <li>Loads epgPrograms + * </ul> + */ + public final void loadData(FakeClock clock, FakeEpgReader epgReader) { + clock.setBootTimeMillis(getStartTimeMs() + TimeUnit.HOURS.toMillis(-12)); + clock.setCurrentTimeMillis(getStartTimeMs()); + epgReader.zip2lineups.putAll(getLineups()); + epgReader.lineup2Channels.putAll(getLineupChannels()); + epgReader.epgChannelId2Programs.putAll(getEpgPrograms()); + } + + public final void loadData(TestSingletonApp testSingletonApp) { + loadData(testSingletonApp.fakeClock, testSingletonApp.epgReader); + } + + private static Iterable<Channel> toTvChannels(android.support.media.tv.Channel... channels) { + return Iterables.transform( + ImmutableList.copyOf(channels), + new Function<android.support.media.tv.Channel, Channel>() { + @Override + public Channel apply(android.support.media.tv.Channel original) { + return toTvChannel(original); + } + }); + } + + public static Channel toTvChannel(android.support.media.tv.Channel original) { + return new ChannelImpl.Builder() + .setDisplayName(original.getDisplayName()) + .setDisplayNumber(original.getDisplayNumber()) + // TODO implement the reset + .build(); + } + + /** Add time to the startTime and stopTime of each program */ + private static Iterable<Program> updateTime(long time, Program... programs) { + return Iterables.transform( + ImmutableList.copyOf(programs), + new Function<Program, Program>() { + @Override + public Program apply(Program p) { + return new Program.Builder(p) + .setStartTimeUtcMillis(p.getStartTimeUtcMillis() + time) + .setEndTimeUtcMillis(p.getEndTimeUtcMillis() + time) + .build(); + } + }); + } +} diff --git a/tests/common/src/com/android/tv/testing/FakeClock.java b/tests/common/src/com/android/tv/testing/FakeClock.java index d88e53a8..f5941939 100644 --- a/tests/common/src/com/android/tv/testing/FakeClock.java +++ b/tests/common/src/com/android/tv/testing/FakeClock.java @@ -16,8 +16,7 @@ package com.android.tv.testing; -import com.android.tv.util.Clock; - +import com.android.tv.common.util.Clock; import java.util.concurrent.TimeUnit; /** @@ -27,21 +26,20 @@ import java.util.concurrent.TimeUnit; * {@link #sleep(long)} is called. */ public class FakeClock implements Clock { - /** - * Creates a fake clock with the time set to now and the boot time set to now - 100,000. - */ + /** Creates a fake clock with the time set to now and the boot time set to now - 100,000. */ public static FakeClock createWithCurrentTime() { long now = System.currentTimeMillis(); return new FakeClock(now, now - 100_000); } - /** - * Creates a fake clock with the time set to zero. - */ + /** Creates a fake clock with the time set to zero. */ public static FakeClock createWithTimeOne() { return new FakeClock(1L, 0L); } - + /** Creates a fake clock with the time set to {@code time}. */ + public static FakeClock createWithTime(long time) { + return new FakeClock(time, 0L); + } private long mCurrentTimeMillis; @@ -95,9 +93,12 @@ public class FakeClock implements Clock { return mCurrentTimeMillis - mBootTimeMillis; } - /** - * Sleep does not block it just updates the current time. - */ + @Override + public long uptimeMillis() { + return elapsedRealtime(); + } + + /** Sleep does not block it just updates the current time. */ @Override public void sleep(long ms) { // TODO: implement blocking if needed. diff --git a/tests/common/src/com/android/tv/testing/FakeEpgFetcher.java b/tests/common/src/com/android/tv/testing/FakeEpgFetcher.java new file mode 100644 index 00000000..d1018a5c --- /dev/null +++ b/tests/common/src/com/android/tv/testing/FakeEpgFetcher.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2017 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.testing; + +import android.app.job.JobParameters; +import android.app.job.JobService; +import com.android.tv.data.epg.EpgFetcher; + +/** Fake {@link EpgFetcher} for testing. */ +public class FakeEpgFetcher implements EpgFetcher { + public boolean fetchStarted = false; + + @Override + public void startRoutineService() {} + + @Override + public void fetchImmediatelyIfNeeded() {} + + @Override + public void fetchImmediately() { + fetchStarted = true; + } + + @Override + public void onChannelScanStarted() {} + + @Override + public void onChannelScanFinished() {} + + @Override + public boolean executeFetchTaskIfPossible(JobService jobService, JobParameters params) { + return false; + } + + @Override + public void stopFetchingJob() { + fetchStarted = false; + } + + public void reset() { + fetchStarted = false; + } +} diff --git a/tests/common/src/com/android/tv/testing/FakeEpgReader.java b/tests/common/src/com/android/tv/testing/FakeEpgReader.java new file mode 100644 index 00000000..710ada55 --- /dev/null +++ b/tests/common/src/com/android/tv/testing/FakeEpgReader.java @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2017 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.testing; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.util.Range; +import com.android.tv.data.ChannelImpl; +import com.android.tv.data.ChannelNumber; +import com.android.tv.data.Lineup; +import com.android.tv.data.Program; +import com.android.tv.data.api.Channel; +import com.android.tv.data.epg.EpgReader; +import com.android.tv.dvr.data.SeriesInfo; +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import com.google.common.collect.LinkedListMultimap; +import com.google.common.collect.ListMultimap; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** Fake {@link EpgReader} for testing. */ +public final class FakeEpgReader implements EpgReader { + public final ListMultimap<String, Lineup> zip2lineups = LinkedListMultimap.create(2); + public final ListMultimap<String, Channel> lineup2Channels = LinkedListMultimap.create(2); + public final ListMultimap<String, Program> epgChannelId2Programs = LinkedListMultimap.create(2); + public final FakeClock fakeClock; + + public FakeEpgReader(FakeClock fakeClock) { + this.fakeClock = fakeClock; + } + + @Override + public boolean isAvailable() { + return true; + } + + @Override + public long getEpgTimestamp() { + return fakeClock.currentTimeMillis(); + } + + @Override + public void setRegionCode(String regionCode) {} + + @Override + public List<Lineup> getLineups(@NonNull String postalCode) { + return zip2lineups.get(postalCode); + } + + @Override + public List<String> getChannelNumbers(@NonNull String lineupId) { + return null; + } + + @Override + public Set<EpgChannel> getChannels(Set<Channel> inputChannels, @NonNull String lineupId) { + Set<EpgChannel> result = new HashSet<>(); + List<Channel> lineupChannels = lineup2Channels.get(lineupId); + for (Channel channel : lineupChannels) { + Channel match = + Iterables.find( + inputChannels, + new Predicate<Channel>() { + @Override + public boolean apply(@Nullable Channel inputChannel) { + return ChannelNumber.equivalent( + inputChannel.getDisplayNumber(), + channel.getDisplayNumber()); + } + }, + null); + if (match != null) { + ChannelImpl updatedChannel = new ChannelImpl.Builder(match).build(); + updatedChannel.setLogoUri(channel.getLogoUri()); + result.add(EpgChannel.createEpgChannel(updatedChannel, channel.getDisplayNumber())); + } + } + return result; + } + + @Override + public void preloadChannels(@NonNull String lineupId) {} + + @Override + public void clearCachedChannels(@NonNull String lineupId) {} + + @Override + public List<Program> getPrograms(EpgChannel epgChannel) { + return ImmutableList.copyOf( + Iterables.transform( + epgChannelId2Programs.get(epgChannel.getEpgChannelId()), + updateWith(epgChannel))); + } + + @Override + public Map<EpgChannel, Collection<Program>> getPrograms( + @NonNull Set<EpgChannel> epgChannels, long duration) { + Range<Long> validRange = + Range.create( + fakeClock.currentTimeMillis(), fakeClock.currentTimeMillis() + duration); + ImmutableMap.Builder<EpgChannel, Collection<Program>> mapBuilder = ImmutableMap.builder(); + for (EpgChannel epgChannel : epgChannels) { + Iterable<Program> programs = getPrograms(epgChannel); + + mapBuilder.put( + epgChannel, + ImmutableList.copyOf(Iterables.filter(programs, isProgramDuring(validRange)))); + } + return mapBuilder.build(); + } + + protected Function<Program, Program> updateWith(final EpgChannel channel) { + return new Function<Program, Program>() { + @Nullable + @Override + public Program apply(@Nullable Program program) { + return new Program.Builder(program) + .setChannelId(channel.getChannel().getId()) + .setPackageName(channel.getChannel().getPackageName()) + .build(); + } + }; + } + + /** + * True if the start time or the end time is {@link Range#contains contained (inclusive)} in the + * range + */ + protected Predicate<Program> isProgramDuring(final Range<Long> validRange) { + return new Predicate<Program>() { + @Override + public boolean apply(@Nullable Program program) { + return validRange.contains(program.getStartTimeUtcMillis()) + || validRange.contains(program.getEndTimeUtcMillis()); + } + }; + } + + @Override + public SeriesInfo getSeriesInfo(@NonNull String seriesId) { + return null; + } +} diff --git a/tests/common/src/com/android/tv/testing/FakeRemoteConfig.java b/tests/common/src/com/android/tv/testing/FakeRemoteConfig.java new file mode 100644 index 00000000..89e6a0a2 --- /dev/null +++ b/tests/common/src/com/android/tv/testing/FakeRemoteConfig.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2017 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.testing; + +import android.text.TextUtils; +import com.android.tv.common.config.api.RemoteConfig; +import java.util.HashMap; +import java.util.Map; + +/** Fake {@link RemoteConfig} suitable for testing. */ +public class FakeRemoteConfig implements RemoteConfig { + public final Map<String, String> values = new HashMap(); + + @Override + public void fetch(OnRemoteConfigUpdatedListener listener) {} + + @Override + public String getString(String key) { + return values.get(key); + } + + @Override + public boolean getBoolean(String key) { + String value = values.get(key); + return TextUtils.isEmpty(value) ? false : Boolean.valueOf(key); + } + + @Override + public long getLong(String key) { + return getLong(key, 0); + } + + @Override + public long getLong(String key, long defaultValue) { + if (values.containsKey(key)) { + String value = values.get(key); + return TextUtils.isEmpty(value) ? defaultValue : Long.valueOf(value); + } + return defaultValue; + } +} diff --git a/tests/common/src/com/android/tv/testing/FakeTvInputManager.java b/tests/common/src/com/android/tv/testing/FakeTvInputManager.java new file mode 100644 index 00000000..397b4052 --- /dev/null +++ b/tests/common/src/com/android/tv/testing/FakeTvInputManager.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2017 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.testing; + +import android.media.tv.TvContentRatingSystemInfo; +import android.media.tv.TvInputInfo; +import android.media.tv.TvInputManager; +import android.os.Handler; +import com.android.tv.util.TvInputManagerHelper; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** Fake implementation for testing. */ +public class FakeTvInputManager implements TvInputManagerHelper.TvInputManagerInterface { + + private final Map<String, Integer> mInputStateMap = new HashMap<>(); + private final Map<String, TvInputInfo> mInputMap = new HashMap<>(); + private final Map<TvInputManager.TvInputCallback, Handler> mCallbacks = new HashMap<>(); + + public void add(TvInputInfo inputInfo, int state) { + final String inputId = inputInfo.getId(); + if (mInputStateMap.containsKey(inputId)) { + throw new IllegalArgumentException("inputId " + inputId); + } + mInputMap.put(inputId, inputInfo); + mInputStateMap.put(inputId, state); + for (final Map.Entry<TvInputManager.TvInputCallback, Handler> e : mCallbacks.entrySet()) { + e.getValue() + .post( + new Runnable() { + @Override + public void run() { + e.getKey().onInputAdded(inputId); + } + }); + } + } + + public void setInputState(final String inputId, final int state) { + if (!mInputStateMap.containsKey(inputId)) { + throw new IllegalArgumentException("inputId " + inputId); + } + mInputStateMap.put(inputId, state); + for (final Map.Entry<TvInputManager.TvInputCallback, Handler> e : mCallbacks.entrySet()) { + e.getValue() + .post( + new Runnable() { + @Override + public void run() { + e.getKey().onInputStateChanged(inputId, state); + } + }); + } + } + + public void remove(final String inputId) { + mInputMap.remove(inputId); + mInputStateMap.remove(inputId); + for (final Map.Entry<TvInputManager.TvInputCallback, Handler> e : mCallbacks.entrySet()) { + e.getValue() + .post( + new Runnable() { + @Override + public void run() { + e.getKey().onInputRemoved(inputId); + } + }); + } + } + + @Override + public TvInputInfo getTvInputInfo(String inputId) { + return mInputMap.get(inputId); + } + + @Override + public Integer getInputState(String inputId) { + return mInputStateMap.get(inputId); + } + + @Override + public void registerCallback(TvInputManager.TvInputCallback internalCallback, Handler handler) { + mCallbacks.put(internalCallback, handler); + } + + @Override + public void unregisterCallback(TvInputManager.TvInputCallback internalCallback) { + mCallbacks.remove(internalCallback); + } + + @Override + public List<TvInputInfo> getTvInputList() { + return new ArrayList(mInputMap.values()); + } + + @Override + public List<TvContentRatingSystemInfo> getTvContentRatingSystemList() { + // TODO implement + return new ArrayList<>(); + } +} diff --git a/tests/common/src/com/android/tv/testing/FakeTvInputManagerHelper.java b/tests/common/src/com/android/tv/testing/FakeTvInputManagerHelper.java new file mode 100644 index 00000000..85bdcf04 --- /dev/null +++ b/tests/common/src/com/android/tv/testing/FakeTvInputManagerHelper.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2017 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.testing; + +import android.content.Context; +import com.android.tv.util.TvInputManagerHelper; + +/** Fake TvInputManagerHelper. */ +public class FakeTvInputManagerHelper extends TvInputManagerHelper { + + public FakeTvInputManagerHelper(Context context) { + super(context, new FakeTvInputManager()); + } + + public FakeTvInputManager getFakeTvInputManager() { + return (FakeTvInputManager) mTvInputManager; + } +} diff --git a/tests/common/src/com/android/tv/testing/FakeTvProvider.java b/tests/common/src/com/android/tv/testing/FakeTvProvider.java new file mode 100644 index 00000000..24c26f39 --- /dev/null +++ b/tests/common/src/com/android/tv/testing/FakeTvProvider.java @@ -0,0 +1,2605 @@ +/* + * Copyright (C) 2017 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.testing; + +import android.annotation.SuppressLint; +import android.content.ContentProvider; +import android.content.ContentProviderOperation; +import android.content.ContentProviderResult; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Context; +import android.content.OperationApplicationException; +import android.content.SharedPreferences; +import android.content.UriMatcher; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.database.DatabaseUtils; +import android.database.SQLException; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.database.sqlite.SQLiteQueryBuilder; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.media.tv.TvContract; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.ParcelFileDescriptor; +import android.os.ParcelFileDescriptor.AutoCloseInputStream; +import android.preference.PreferenceManager; +import android.provider.BaseColumns; +import android.support.annotation.VisibleForTesting; +import android.support.media.tv.TvContractCompat; +import android.support.media.tv.TvContractCompat.BaseTvColumns; +import android.support.media.tv.TvContractCompat.Channels; +import android.support.media.tv.TvContractCompat.PreviewPrograms; +import android.support.media.tv.TvContractCompat.Programs; +import android.support.media.tv.TvContractCompat.Programs.Genres; +import android.support.media.tv.TvContractCompat.RecordedPrograms; +import android.support.media.tv.TvContractCompat.WatchNextPrograms; +import android.text.TextUtils; +import android.util.Log; +import com.android.tv.util.SqlParams; +import java.io.ByteArrayOutputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Fake TV content provider suitable for unit tests. The contract between this provider and + * applications is defined in {@link TvContractCompat}. + */ +// TODO(b/62143348): remove when error prone check fixed +@SuppressWarnings({"AndroidApiChecker", "TryWithResources"}) +public class FakeTvProvider extends ContentProvider { + // TODO either make this a shadow or move it to the support library + + private static final boolean DEBUG = false; + private static final String TAG = "TvProvider"; + + static final int DATABASE_VERSION = 34; + static final String SHARED_PREF_BLOCKED_PACKAGES_KEY = "blocked_packages"; + static final String CHANNELS_TABLE = "channels"; + static final String PROGRAMS_TABLE = "programs"; + static final String RECORDED_PROGRAMS_TABLE = "recorded_programs"; + static final String PREVIEW_PROGRAMS_TABLE = "preview_programs"; + static final String WATCH_NEXT_PROGRAMS_TABLE = "watch_next_programs"; + static final String WATCHED_PROGRAMS_TABLE = "watched_programs"; + static final String PROGRAMS_TABLE_PACKAGE_NAME_INDEX = "programs_package_name_index"; + static final String PROGRAMS_TABLE_CHANNEL_ID_INDEX = "programs_channel_id_index"; + static final String PROGRAMS_TABLE_START_TIME_INDEX = "programs_start_time_index"; + static final String PROGRAMS_TABLE_END_TIME_INDEX = "programs_end_time_index"; + static final String WATCHED_PROGRAMS_TABLE_CHANNEL_ID_INDEX = + "watched_programs_channel_id_index"; + // The internal column in the watched programs table to indicate whether the current log entry + // is consolidated or not. Unconsolidated entries may have columns with missing data. + static final String WATCHED_PROGRAMS_COLUMN_CONSOLIDATED = "consolidated"; + static final String CHANNELS_COLUMN_LOGO = "logo"; + private static final String DATABASE_NAME = "tv.db"; + private static final String DELETED_CHANNELS_TABLE = "deleted_channels"; // Deprecated + private static final String DEFAULT_PROGRAMS_SORT_ORDER = + Programs.COLUMN_START_TIME_UTC_MILLIS + " ASC"; + private static final String DEFAULT_WATCHED_PROGRAMS_SORT_ORDER = + WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS + " DESC"; + private static final String CHANNELS_TABLE_INNER_JOIN_PROGRAMS_TABLE = + CHANNELS_TABLE + + " INNER JOIN " + + PROGRAMS_TABLE + + " ON (" + + CHANNELS_TABLE + + "." + + Channels._ID + + "=" + + PROGRAMS_TABLE + + "." + + Programs.COLUMN_CHANNEL_ID + + ")"; + + // Operation names for createSqlParams(). + private static final String OP_QUERY = "query"; + private static final String OP_UPDATE = "update"; + private static final String OP_DELETE = "delete"; + + private static final UriMatcher sUriMatcher; + private static final int MATCH_CHANNEL = 1; + private static final int MATCH_CHANNEL_ID = 2; + private static final int MATCH_CHANNEL_ID_LOGO = 3; + private static final int MATCH_PASSTHROUGH_ID = 4; + private static final int MATCH_PROGRAM = 5; + private static final int MATCH_PROGRAM_ID = 6; + private static final int MATCH_WATCHED_PROGRAM = 7; + private static final int MATCH_WATCHED_PROGRAM_ID = 8; + private static final int MATCH_RECORDED_PROGRAM = 9; + private static final int MATCH_RECORDED_PROGRAM_ID = 10; + private static final int MATCH_PREVIEW_PROGRAM = 11; + private static final int MATCH_PREVIEW_PROGRAM_ID = 12; + private static final int MATCH_WATCH_NEXT_PROGRAM = 13; + private static final int MATCH_WATCH_NEXT_PROGRAM_ID = 14; + + private static final int MAX_LOGO_IMAGE_SIZE = 256; + + private static final String EMPTY_STRING = ""; + + private static final Map<String, String> sChannelProjectionMap; + private static final Map<String, String> sProgramProjectionMap; + private static final Map<String, String> sWatchedProgramProjectionMap; + private static final Map<String, String> sRecordedProgramProjectionMap; + private static final Map<String, String> sPreviewProgramProjectionMap; + private static final Map<String, String> sWatchNextProgramProjectionMap; + + // TvContract hidden + private static final String PARAM_PACKAGE = "package"; + private static final String PARAM_PREVIEW = "preview"; + + private static boolean sInitialized; + + static { + sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); + sUriMatcher.addURI(TvContractCompat.AUTHORITY, "channel", MATCH_CHANNEL); + sUriMatcher.addURI(TvContractCompat.AUTHORITY, "channel/#", MATCH_CHANNEL_ID); + sUriMatcher.addURI(TvContractCompat.AUTHORITY, "channel/#/logo", MATCH_CHANNEL_ID_LOGO); + sUriMatcher.addURI(TvContractCompat.AUTHORITY, "passthrough/*", MATCH_PASSTHROUGH_ID); + sUriMatcher.addURI(TvContractCompat.AUTHORITY, "program", MATCH_PROGRAM); + sUriMatcher.addURI(TvContractCompat.AUTHORITY, "program/#", MATCH_PROGRAM_ID); + sUriMatcher.addURI(TvContractCompat.AUTHORITY, "watched_program", MATCH_WATCHED_PROGRAM); + sUriMatcher.addURI( + TvContractCompat.AUTHORITY, "watched_program/#", MATCH_WATCHED_PROGRAM_ID); + sUriMatcher.addURI(TvContractCompat.AUTHORITY, "recorded_program", MATCH_RECORDED_PROGRAM); + sUriMatcher.addURI( + TvContractCompat.AUTHORITY, "recorded_program/#", MATCH_RECORDED_PROGRAM_ID); + sUriMatcher.addURI(TvContractCompat.AUTHORITY, "preview_program", MATCH_PREVIEW_PROGRAM); + sUriMatcher.addURI( + TvContractCompat.AUTHORITY, "preview_program/#", MATCH_PREVIEW_PROGRAM_ID); + sUriMatcher.addURI( + TvContractCompat.AUTHORITY, "watch_next_program", MATCH_WATCH_NEXT_PROGRAM); + sUriMatcher.addURI( + TvContractCompat.AUTHORITY, "watch_next_program/#", MATCH_WATCH_NEXT_PROGRAM_ID); + + sChannelProjectionMap = new HashMap<>(); + sChannelProjectionMap.put(Channels._ID, CHANNELS_TABLE + "." + Channels._ID); + sChannelProjectionMap.put( + Channels.COLUMN_PACKAGE_NAME, CHANNELS_TABLE + "." + Channels.COLUMN_PACKAGE_NAME); + sChannelProjectionMap.put( + Channels.COLUMN_INPUT_ID, CHANNELS_TABLE + "." + Channels.COLUMN_INPUT_ID); + sChannelProjectionMap.put( + Channels.COLUMN_TYPE, CHANNELS_TABLE + "." + Channels.COLUMN_TYPE); + sChannelProjectionMap.put( + Channels.COLUMN_SERVICE_TYPE, CHANNELS_TABLE + "." + Channels.COLUMN_SERVICE_TYPE); + sChannelProjectionMap.put( + Channels.COLUMN_ORIGINAL_NETWORK_ID, + CHANNELS_TABLE + "." + Channels.COLUMN_ORIGINAL_NETWORK_ID); + sChannelProjectionMap.put( + Channels.COLUMN_TRANSPORT_STREAM_ID, + CHANNELS_TABLE + "." + Channels.COLUMN_TRANSPORT_STREAM_ID); + sChannelProjectionMap.put( + Channels.COLUMN_SERVICE_ID, CHANNELS_TABLE + "." + Channels.COLUMN_SERVICE_ID); + sChannelProjectionMap.put( + Channels.COLUMN_DISPLAY_NUMBER, + CHANNELS_TABLE + "." + Channels.COLUMN_DISPLAY_NUMBER); + sChannelProjectionMap.put( + Channels.COLUMN_DISPLAY_NAME, CHANNELS_TABLE + "." + Channels.COLUMN_DISPLAY_NAME); + sChannelProjectionMap.put( + Channels.COLUMN_NETWORK_AFFILIATION, + CHANNELS_TABLE + "." + Channels.COLUMN_NETWORK_AFFILIATION); + sChannelProjectionMap.put( + Channels.COLUMN_DESCRIPTION, CHANNELS_TABLE + "." + Channels.COLUMN_DESCRIPTION); + sChannelProjectionMap.put( + Channels.COLUMN_VIDEO_FORMAT, CHANNELS_TABLE + "." + Channels.COLUMN_VIDEO_FORMAT); + sChannelProjectionMap.put( + Channels.COLUMN_BROWSABLE, CHANNELS_TABLE + "." + Channels.COLUMN_BROWSABLE); + sChannelProjectionMap.put( + Channels.COLUMN_SEARCHABLE, CHANNELS_TABLE + "." + Channels.COLUMN_SEARCHABLE); + sChannelProjectionMap.put( + Channels.COLUMN_LOCKED, CHANNELS_TABLE + "." + Channels.COLUMN_LOCKED); + sChannelProjectionMap.put( + Channels.COLUMN_APP_LINK_ICON_URI, + CHANNELS_TABLE + "." + Channels.COLUMN_APP_LINK_ICON_URI); + sChannelProjectionMap.put( + Channels.COLUMN_APP_LINK_POSTER_ART_URI, + CHANNELS_TABLE + "." + Channels.COLUMN_APP_LINK_POSTER_ART_URI); + sChannelProjectionMap.put( + Channels.COLUMN_APP_LINK_TEXT, + CHANNELS_TABLE + "." + Channels.COLUMN_APP_LINK_TEXT); + sChannelProjectionMap.put( + Channels.COLUMN_APP_LINK_COLOR, + CHANNELS_TABLE + "." + Channels.COLUMN_APP_LINK_COLOR); + sChannelProjectionMap.put( + Channels.COLUMN_APP_LINK_INTENT_URI, + CHANNELS_TABLE + "." + Channels.COLUMN_APP_LINK_INTENT_URI); + sChannelProjectionMap.put( + Channels.COLUMN_INTERNAL_PROVIDER_DATA, + CHANNELS_TABLE + "." + Channels.COLUMN_INTERNAL_PROVIDER_DATA); + sChannelProjectionMap.put( + Channels.COLUMN_INTERNAL_PROVIDER_FLAG1, + CHANNELS_TABLE + "." + Channels.COLUMN_INTERNAL_PROVIDER_FLAG1); + sChannelProjectionMap.put( + Channels.COLUMN_INTERNAL_PROVIDER_FLAG2, + CHANNELS_TABLE + "." + Channels.COLUMN_INTERNAL_PROVIDER_FLAG2); + sChannelProjectionMap.put( + Channels.COLUMN_INTERNAL_PROVIDER_FLAG3, + CHANNELS_TABLE + "." + Channels.COLUMN_INTERNAL_PROVIDER_FLAG3); + sChannelProjectionMap.put( + Channels.COLUMN_INTERNAL_PROVIDER_FLAG4, + CHANNELS_TABLE + "." + Channels.COLUMN_INTERNAL_PROVIDER_FLAG4); + sChannelProjectionMap.put( + Channels.COLUMN_VERSION_NUMBER, + CHANNELS_TABLE + "." + Channels.COLUMN_VERSION_NUMBER); + sChannelProjectionMap.put( + Channels.COLUMN_TRANSIENT, CHANNELS_TABLE + "." + Channels.COLUMN_TRANSIENT); + sChannelProjectionMap.put( + Channels.COLUMN_INTERNAL_PROVIDER_ID, + CHANNELS_TABLE + "." + Channels.COLUMN_INTERNAL_PROVIDER_ID); + + sProgramProjectionMap = new HashMap<>(); + sProgramProjectionMap.put(Programs._ID, Programs._ID); + sProgramProjectionMap.put(Programs.COLUMN_PACKAGE_NAME, Programs.COLUMN_PACKAGE_NAME); + sProgramProjectionMap.put(Programs.COLUMN_CHANNEL_ID, Programs.COLUMN_CHANNEL_ID); + sProgramProjectionMap.put(Programs.COLUMN_TITLE, Programs.COLUMN_TITLE); + // COLUMN_SEASON_NUMBER is deprecated. Return COLUMN_SEASON_DISPLAY_NUMBER instead. + sProgramProjectionMap.put( + Programs.COLUMN_SEASON_NUMBER, + Programs.COLUMN_SEASON_DISPLAY_NUMBER + " AS " + Programs.COLUMN_SEASON_NUMBER); + sProgramProjectionMap.put( + Programs.COLUMN_SEASON_DISPLAY_NUMBER, Programs.COLUMN_SEASON_DISPLAY_NUMBER); + sProgramProjectionMap.put(Programs.COLUMN_SEASON_TITLE, Programs.COLUMN_SEASON_TITLE); + // COLUMN_EPISODE_NUMBER is deprecated. Return COLUMN_EPISODE_DISPLAY_NUMBER instead. + sProgramProjectionMap.put( + Programs.COLUMN_EPISODE_NUMBER, + Programs.COLUMN_EPISODE_DISPLAY_NUMBER + " AS " + Programs.COLUMN_EPISODE_NUMBER); + sProgramProjectionMap.put( + Programs.COLUMN_EPISODE_DISPLAY_NUMBER, Programs.COLUMN_EPISODE_DISPLAY_NUMBER); + sProgramProjectionMap.put(Programs.COLUMN_EPISODE_TITLE, Programs.COLUMN_EPISODE_TITLE); + sProgramProjectionMap.put( + Programs.COLUMN_START_TIME_UTC_MILLIS, Programs.COLUMN_START_TIME_UTC_MILLIS); + sProgramProjectionMap.put( + Programs.COLUMN_END_TIME_UTC_MILLIS, Programs.COLUMN_END_TIME_UTC_MILLIS); + sProgramProjectionMap.put(Programs.COLUMN_BROADCAST_GENRE, Programs.COLUMN_BROADCAST_GENRE); + sProgramProjectionMap.put(Programs.COLUMN_CANONICAL_GENRE, Programs.COLUMN_CANONICAL_GENRE); + sProgramProjectionMap.put( + Programs.COLUMN_SHORT_DESCRIPTION, Programs.COLUMN_SHORT_DESCRIPTION); + sProgramProjectionMap.put( + Programs.COLUMN_LONG_DESCRIPTION, Programs.COLUMN_LONG_DESCRIPTION); + sProgramProjectionMap.put(Programs.COLUMN_VIDEO_WIDTH, Programs.COLUMN_VIDEO_WIDTH); + sProgramProjectionMap.put(Programs.COLUMN_VIDEO_HEIGHT, Programs.COLUMN_VIDEO_HEIGHT); + sProgramProjectionMap.put(Programs.COLUMN_AUDIO_LANGUAGE, Programs.COLUMN_AUDIO_LANGUAGE); + sProgramProjectionMap.put(Programs.COLUMN_CONTENT_RATING, Programs.COLUMN_CONTENT_RATING); + sProgramProjectionMap.put(Programs.COLUMN_POSTER_ART_URI, Programs.COLUMN_POSTER_ART_URI); + sProgramProjectionMap.put(Programs.COLUMN_THUMBNAIL_URI, Programs.COLUMN_THUMBNAIL_URI); + sProgramProjectionMap.put(Programs.COLUMN_SEARCHABLE, Programs.COLUMN_SEARCHABLE); + sProgramProjectionMap.put( + Programs.COLUMN_RECORDING_PROHIBITED, Programs.COLUMN_RECORDING_PROHIBITED); + sProgramProjectionMap.put( + Programs.COLUMN_INTERNAL_PROVIDER_DATA, Programs.COLUMN_INTERNAL_PROVIDER_DATA); + sProgramProjectionMap.put( + Programs.COLUMN_INTERNAL_PROVIDER_FLAG1, Programs.COLUMN_INTERNAL_PROVIDER_FLAG1); + sProgramProjectionMap.put( + Programs.COLUMN_INTERNAL_PROVIDER_FLAG2, Programs.COLUMN_INTERNAL_PROVIDER_FLAG2); + sProgramProjectionMap.put( + Programs.COLUMN_INTERNAL_PROVIDER_FLAG3, Programs.COLUMN_INTERNAL_PROVIDER_FLAG3); + sProgramProjectionMap.put( + Programs.COLUMN_INTERNAL_PROVIDER_FLAG4, Programs.COLUMN_INTERNAL_PROVIDER_FLAG4); + sProgramProjectionMap.put(Programs.COLUMN_VERSION_NUMBER, Programs.COLUMN_VERSION_NUMBER); + sProgramProjectionMap.put( + Programs.COLUMN_REVIEW_RATING_STYLE, Programs.COLUMN_REVIEW_RATING_STYLE); + sProgramProjectionMap.put(Programs.COLUMN_REVIEW_RATING, Programs.COLUMN_REVIEW_RATING); + + sWatchedProgramProjectionMap = new HashMap<>(); + sWatchedProgramProjectionMap.put(WatchedPrograms._ID, WatchedPrograms._ID); + sWatchedProgramProjectionMap.put( + WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS, + WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS); + sWatchedProgramProjectionMap.put( + WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, + WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS); + sWatchedProgramProjectionMap.put( + WatchedPrograms.COLUMN_CHANNEL_ID, WatchedPrograms.COLUMN_CHANNEL_ID); + sWatchedProgramProjectionMap.put( + WatchedPrograms.COLUMN_TITLE, WatchedPrograms.COLUMN_TITLE); + sWatchedProgramProjectionMap.put( + WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS, + WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS); + sWatchedProgramProjectionMap.put( + WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS, + WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS); + sWatchedProgramProjectionMap.put( + WatchedPrograms.COLUMN_DESCRIPTION, WatchedPrograms.COLUMN_DESCRIPTION); + sWatchedProgramProjectionMap.put( + WatchedPrograms.COLUMN_INTERNAL_TUNE_PARAMS, + WatchedPrograms.COLUMN_INTERNAL_TUNE_PARAMS); + sWatchedProgramProjectionMap.put( + WatchedPrograms.COLUMN_INTERNAL_SESSION_TOKEN, + WatchedPrograms.COLUMN_INTERNAL_SESSION_TOKEN); + sWatchedProgramProjectionMap.put( + WATCHED_PROGRAMS_COLUMN_CONSOLIDATED, WATCHED_PROGRAMS_COLUMN_CONSOLIDATED); + + sRecordedProgramProjectionMap = new HashMap<>(); + sRecordedProgramProjectionMap.put(RecordedPrograms._ID, RecordedPrograms._ID); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_PACKAGE_NAME, RecordedPrograms.COLUMN_PACKAGE_NAME); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_INPUT_ID, RecordedPrograms.COLUMN_INPUT_ID); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_CHANNEL_ID, RecordedPrograms.COLUMN_CHANNEL_ID); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_TITLE, RecordedPrograms.COLUMN_TITLE); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_SEASON_DISPLAY_NUMBER, + RecordedPrograms.COLUMN_SEASON_DISPLAY_NUMBER); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_SEASON_TITLE, RecordedPrograms.COLUMN_SEASON_TITLE); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_EPISODE_DISPLAY_NUMBER, + RecordedPrograms.COLUMN_EPISODE_DISPLAY_NUMBER); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_EPISODE_TITLE, RecordedPrograms.COLUMN_EPISODE_TITLE); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_START_TIME_UTC_MILLIS, + RecordedPrograms.COLUMN_START_TIME_UTC_MILLIS); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_END_TIME_UTC_MILLIS, + RecordedPrograms.COLUMN_END_TIME_UTC_MILLIS); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_BROADCAST_GENRE, RecordedPrograms.COLUMN_BROADCAST_GENRE); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_CANONICAL_GENRE, RecordedPrograms.COLUMN_CANONICAL_GENRE); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_SHORT_DESCRIPTION, + RecordedPrograms.COLUMN_SHORT_DESCRIPTION); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_LONG_DESCRIPTION, RecordedPrograms.COLUMN_LONG_DESCRIPTION); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_VIDEO_WIDTH, RecordedPrograms.COLUMN_VIDEO_WIDTH); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_VIDEO_HEIGHT, RecordedPrograms.COLUMN_VIDEO_HEIGHT); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_AUDIO_LANGUAGE, RecordedPrograms.COLUMN_AUDIO_LANGUAGE); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_CONTENT_RATING, RecordedPrograms.COLUMN_CONTENT_RATING); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_POSTER_ART_URI, RecordedPrograms.COLUMN_POSTER_ART_URI); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_THUMBNAIL_URI, RecordedPrograms.COLUMN_THUMBNAIL_URI); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_SEARCHABLE, RecordedPrograms.COLUMN_SEARCHABLE); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_RECORDING_DATA_URI, + RecordedPrograms.COLUMN_RECORDING_DATA_URI); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_RECORDING_DATA_BYTES, + RecordedPrograms.COLUMN_RECORDING_DATA_BYTES); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS, + RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS, + RecordedPrograms.COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_DATA, + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_DATA); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1, + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2, + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3, + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4, + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_VERSION_NUMBER, RecordedPrograms.COLUMN_VERSION_NUMBER); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_REVIEW_RATING_STYLE, + RecordedPrograms.COLUMN_REVIEW_RATING_STYLE); + sRecordedProgramProjectionMap.put( + RecordedPrograms.COLUMN_REVIEW_RATING, RecordedPrograms.COLUMN_REVIEW_RATING); + + sPreviewProgramProjectionMap = new HashMap<>(); + sPreviewProgramProjectionMap.put(PreviewPrograms._ID, PreviewPrograms._ID); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_PACKAGE_NAME, PreviewPrograms.COLUMN_PACKAGE_NAME); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_CHANNEL_ID, PreviewPrograms.COLUMN_CHANNEL_ID); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_TITLE, PreviewPrograms.COLUMN_TITLE); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_SEASON_DISPLAY_NUMBER, + PreviewPrograms.COLUMN_SEASON_DISPLAY_NUMBER); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_SEASON_TITLE, PreviewPrograms.COLUMN_SEASON_TITLE); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_EPISODE_DISPLAY_NUMBER, + PreviewPrograms.COLUMN_EPISODE_DISPLAY_NUMBER); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_EPISODE_TITLE, PreviewPrograms.COLUMN_EPISODE_TITLE); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_CANONICAL_GENRE, PreviewPrograms.COLUMN_CANONICAL_GENRE); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_SHORT_DESCRIPTION, PreviewPrograms.COLUMN_SHORT_DESCRIPTION); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_LONG_DESCRIPTION, PreviewPrograms.COLUMN_LONG_DESCRIPTION); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_VIDEO_WIDTH, PreviewPrograms.COLUMN_VIDEO_WIDTH); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_VIDEO_HEIGHT, PreviewPrograms.COLUMN_VIDEO_HEIGHT); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_AUDIO_LANGUAGE, PreviewPrograms.COLUMN_AUDIO_LANGUAGE); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_CONTENT_RATING, PreviewPrograms.COLUMN_CONTENT_RATING); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_POSTER_ART_URI, PreviewPrograms.COLUMN_POSTER_ART_URI); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_THUMBNAIL_URI, PreviewPrograms.COLUMN_THUMBNAIL_URI); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_SEARCHABLE, PreviewPrograms.COLUMN_SEARCHABLE); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_DATA, + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_DATA); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1, + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2, + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3, + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4, + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_VERSION_NUMBER, PreviewPrograms.COLUMN_VERSION_NUMBER); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_ID, + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_ID); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_PREVIEW_VIDEO_URI, PreviewPrograms.COLUMN_PREVIEW_VIDEO_URI); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS, + PreviewPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_DURATION_MILLIS, PreviewPrograms.COLUMN_DURATION_MILLIS); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_INTENT_URI, PreviewPrograms.COLUMN_INTENT_URI); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_WEIGHT, PreviewPrograms.COLUMN_WEIGHT); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_TRANSIENT, PreviewPrograms.COLUMN_TRANSIENT); + sPreviewProgramProjectionMap.put(PreviewPrograms.COLUMN_TYPE, PreviewPrograms.COLUMN_TYPE); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_POSTER_ART_ASPECT_RATIO, + PreviewPrograms.COLUMN_POSTER_ART_ASPECT_RATIO); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO, + PreviewPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_LOGO_URI, PreviewPrograms.COLUMN_LOGO_URI); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_AVAILABILITY, PreviewPrograms.COLUMN_AVAILABILITY); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_STARTING_PRICE, PreviewPrograms.COLUMN_STARTING_PRICE); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_OFFER_PRICE, PreviewPrograms.COLUMN_OFFER_PRICE); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_RELEASE_DATE, PreviewPrograms.COLUMN_RELEASE_DATE); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_ITEM_COUNT, PreviewPrograms.COLUMN_ITEM_COUNT); + sPreviewProgramProjectionMap.put(PreviewPrograms.COLUMN_LIVE, PreviewPrograms.COLUMN_LIVE); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_INTERACTION_TYPE, PreviewPrograms.COLUMN_INTERACTION_TYPE); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_INTERACTION_COUNT, PreviewPrograms.COLUMN_INTERACTION_COUNT); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_AUTHOR, PreviewPrograms.COLUMN_AUTHOR); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_REVIEW_RATING_STYLE, + PreviewPrograms.COLUMN_REVIEW_RATING_STYLE); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_REVIEW_RATING, PreviewPrograms.COLUMN_REVIEW_RATING); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_BROWSABLE, PreviewPrograms.COLUMN_BROWSABLE); + sPreviewProgramProjectionMap.put( + PreviewPrograms.COLUMN_CONTENT_ID, PreviewPrograms.COLUMN_CONTENT_ID); + + sWatchNextProgramProjectionMap = new HashMap<>(); + sWatchNextProgramProjectionMap.put(WatchNextPrograms._ID, WatchNextPrograms._ID); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_PACKAGE_NAME, WatchNextPrograms.COLUMN_PACKAGE_NAME); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_TITLE, WatchNextPrograms.COLUMN_TITLE); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_SEASON_DISPLAY_NUMBER, + WatchNextPrograms.COLUMN_SEASON_DISPLAY_NUMBER); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_SEASON_TITLE, WatchNextPrograms.COLUMN_SEASON_TITLE); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_EPISODE_DISPLAY_NUMBER, + WatchNextPrograms.COLUMN_EPISODE_DISPLAY_NUMBER); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_EPISODE_TITLE, WatchNextPrograms.COLUMN_EPISODE_TITLE); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_CANONICAL_GENRE, WatchNextPrograms.COLUMN_CANONICAL_GENRE); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_SHORT_DESCRIPTION, + WatchNextPrograms.COLUMN_SHORT_DESCRIPTION); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_LONG_DESCRIPTION, + WatchNextPrograms.COLUMN_LONG_DESCRIPTION); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_VIDEO_WIDTH, WatchNextPrograms.COLUMN_VIDEO_WIDTH); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_VIDEO_HEIGHT, WatchNextPrograms.COLUMN_VIDEO_HEIGHT); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_AUDIO_LANGUAGE, WatchNextPrograms.COLUMN_AUDIO_LANGUAGE); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_CONTENT_RATING, WatchNextPrograms.COLUMN_CONTENT_RATING); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_POSTER_ART_URI, WatchNextPrograms.COLUMN_POSTER_ART_URI); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_THUMBNAIL_URI, WatchNextPrograms.COLUMN_THUMBNAIL_URI); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_SEARCHABLE, WatchNextPrograms.COLUMN_SEARCHABLE); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_DATA, + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_DATA); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1, + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2, + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3, + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4, + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_VERSION_NUMBER, WatchNextPrograms.COLUMN_VERSION_NUMBER); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_ID, + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_ID); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_PREVIEW_VIDEO_URI, + WatchNextPrograms.COLUMN_PREVIEW_VIDEO_URI); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS, + WatchNextPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_DURATION_MILLIS, WatchNextPrograms.COLUMN_DURATION_MILLIS); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_INTENT_URI, WatchNextPrograms.COLUMN_INTENT_URI); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_TRANSIENT, WatchNextPrograms.COLUMN_TRANSIENT); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_TYPE, WatchNextPrograms.COLUMN_TYPE); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_WATCH_NEXT_TYPE, WatchNextPrograms.COLUMN_WATCH_NEXT_TYPE); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_POSTER_ART_ASPECT_RATIO, + WatchNextPrograms.COLUMN_POSTER_ART_ASPECT_RATIO); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO, + WatchNextPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_LOGO_URI, WatchNextPrograms.COLUMN_LOGO_URI); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_AVAILABILITY, WatchNextPrograms.COLUMN_AVAILABILITY); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_STARTING_PRICE, WatchNextPrograms.COLUMN_STARTING_PRICE); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_OFFER_PRICE, WatchNextPrograms.COLUMN_OFFER_PRICE); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_RELEASE_DATE, WatchNextPrograms.COLUMN_RELEASE_DATE); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_ITEM_COUNT, WatchNextPrograms.COLUMN_ITEM_COUNT); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_LIVE, WatchNextPrograms.COLUMN_LIVE); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_INTERACTION_TYPE, + WatchNextPrograms.COLUMN_INTERACTION_TYPE); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_INTERACTION_COUNT, + WatchNextPrograms.COLUMN_INTERACTION_COUNT); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_AUTHOR, WatchNextPrograms.COLUMN_AUTHOR); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_REVIEW_RATING_STYLE, + WatchNextPrograms.COLUMN_REVIEW_RATING_STYLE); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_REVIEW_RATING, WatchNextPrograms.COLUMN_REVIEW_RATING); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_BROWSABLE, WatchNextPrograms.COLUMN_BROWSABLE); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_CONTENT_ID, WatchNextPrograms.COLUMN_CONTENT_ID); + sWatchNextProgramProjectionMap.put( + WatchNextPrograms.COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS, + WatchNextPrograms.COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS); + } + + // Mapping from broadcast genre to canonical genre. + private static Map<String, String> sGenreMap; + + private static final String PERMISSION_READ_TV_LISTINGS = "android.permission.READ_TV_LISTINGS"; + + private static final String PERMISSION_ACCESS_ALL_EPG_DATA = + "com.android.providers.tv.permission.ACCESS_ALL_EPG_DATA"; + + private static final String PERMISSION_ACCESS_WATCHED_PROGRAMS = + "com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS"; + + private static final String CREATE_RECORDED_PROGRAMS_TABLE_SQL = + "CREATE TABLE " + + RECORDED_PROGRAMS_TABLE + + " (" + + RecordedPrograms._ID + + " INTEGER PRIMARY KEY AUTOINCREMENT," + + RecordedPrograms.COLUMN_PACKAGE_NAME + + " TEXT NOT NULL," + + RecordedPrograms.COLUMN_INPUT_ID + + " TEXT NOT NULL," + + RecordedPrograms.COLUMN_CHANNEL_ID + + " INTEGER," + + RecordedPrograms.COLUMN_TITLE + + " TEXT," + + RecordedPrograms.COLUMN_SEASON_DISPLAY_NUMBER + + " TEXT," + + RecordedPrograms.COLUMN_SEASON_TITLE + + " TEXT," + + RecordedPrograms.COLUMN_EPISODE_DISPLAY_NUMBER + + " TEXT," + + RecordedPrograms.COLUMN_EPISODE_TITLE + + " TEXT," + + RecordedPrograms.COLUMN_START_TIME_UTC_MILLIS + + " INTEGER," + + RecordedPrograms.COLUMN_END_TIME_UTC_MILLIS + + " INTEGER," + + RecordedPrograms.COLUMN_BROADCAST_GENRE + + " TEXT," + + RecordedPrograms.COLUMN_CANONICAL_GENRE + + " TEXT," + + RecordedPrograms.COLUMN_SHORT_DESCRIPTION + + " TEXT," + + RecordedPrograms.COLUMN_LONG_DESCRIPTION + + " TEXT," + + RecordedPrograms.COLUMN_VIDEO_WIDTH + + " INTEGER," + + RecordedPrograms.COLUMN_VIDEO_HEIGHT + + " INTEGER," + + RecordedPrograms.COLUMN_AUDIO_LANGUAGE + + " TEXT," + + RecordedPrograms.COLUMN_CONTENT_RATING + + " TEXT," + + RecordedPrograms.COLUMN_POSTER_ART_URI + + " TEXT," + + RecordedPrograms.COLUMN_THUMBNAIL_URI + + " TEXT," + + RecordedPrograms.COLUMN_SEARCHABLE + + " INTEGER NOT NULL DEFAULT 1," + + RecordedPrograms.COLUMN_RECORDING_DATA_URI + + " TEXT," + + RecordedPrograms.COLUMN_RECORDING_DATA_BYTES + + " INTEGER," + + RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS + + " INTEGER," + + RecordedPrograms.COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS + + " INTEGER," + + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_DATA + + " BLOB," + + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1 + + " INTEGER," + + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2 + + " INTEGER," + + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3 + + " INTEGER," + + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4 + + " INTEGER," + + RecordedPrograms.COLUMN_VERSION_NUMBER + + " INTEGER," + + RecordedPrograms.COLUMN_REVIEW_RATING_STYLE + + " INTEGER," + + RecordedPrograms.COLUMN_REVIEW_RATING + + " TEXT," + + "FOREIGN KEY(" + + RecordedPrograms.COLUMN_CHANNEL_ID + + ") " + + "REFERENCES " + + CHANNELS_TABLE + + "(" + + Channels._ID + + ") " + + "ON UPDATE CASCADE ON DELETE SET NULL);"; + + private static final String CREATE_PREVIEW_PROGRAMS_TABLE_SQL = + "CREATE TABLE " + + PREVIEW_PROGRAMS_TABLE + + " (" + + PreviewPrograms._ID + + " INTEGER PRIMARY KEY AUTOINCREMENT," + + PreviewPrograms.COLUMN_PACKAGE_NAME + + " TEXT NOT NULL," + + PreviewPrograms.COLUMN_CHANNEL_ID + + " INTEGER," + + PreviewPrograms.COLUMN_TITLE + + " TEXT," + + PreviewPrograms.COLUMN_SEASON_DISPLAY_NUMBER + + " TEXT," + + PreviewPrograms.COLUMN_SEASON_TITLE + + " TEXT," + + PreviewPrograms.COLUMN_EPISODE_DISPLAY_NUMBER + + " TEXT," + + PreviewPrograms.COLUMN_EPISODE_TITLE + + " TEXT," + + PreviewPrograms.COLUMN_CANONICAL_GENRE + + " TEXT," + + PreviewPrograms.COLUMN_SHORT_DESCRIPTION + + " TEXT," + + PreviewPrograms.COLUMN_LONG_DESCRIPTION + + " TEXT," + + PreviewPrograms.COLUMN_VIDEO_WIDTH + + " INTEGER," + + PreviewPrograms.COLUMN_VIDEO_HEIGHT + + " INTEGER," + + PreviewPrograms.COLUMN_AUDIO_LANGUAGE + + " TEXT," + + PreviewPrograms.COLUMN_CONTENT_RATING + + " TEXT," + + PreviewPrograms.COLUMN_POSTER_ART_URI + + " TEXT," + + PreviewPrograms.COLUMN_THUMBNAIL_URI + + " TEXT," + + PreviewPrograms.COLUMN_SEARCHABLE + + " INTEGER NOT NULL DEFAULT 1," + + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_DATA + + " BLOB," + + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1 + + " INTEGER," + + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2 + + " INTEGER," + + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3 + + " INTEGER," + + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4 + + " INTEGER," + + PreviewPrograms.COLUMN_VERSION_NUMBER + + " INTEGER," + + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_ID + + " TEXT," + + PreviewPrograms.COLUMN_PREVIEW_VIDEO_URI + + " TEXT," + + PreviewPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS + + " INTEGER," + + PreviewPrograms.COLUMN_DURATION_MILLIS + + " INTEGER," + + PreviewPrograms.COLUMN_INTENT_URI + + " TEXT," + + PreviewPrograms.COLUMN_WEIGHT + + " INTEGER," + + PreviewPrograms.COLUMN_TRANSIENT + + " INTEGER NOT NULL DEFAULT 0," + + PreviewPrograms.COLUMN_TYPE + + " INTEGER NOT NULL," + + PreviewPrograms.COLUMN_POSTER_ART_ASPECT_RATIO + + " INTEGER," + + PreviewPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO + + " INTEGER," + + PreviewPrograms.COLUMN_LOGO_URI + + " TEXT," + + PreviewPrograms.COLUMN_AVAILABILITY + + " INTERGER," + + PreviewPrograms.COLUMN_STARTING_PRICE + + " TEXT," + + PreviewPrograms.COLUMN_OFFER_PRICE + + " TEXT," + + PreviewPrograms.COLUMN_RELEASE_DATE + + " TEXT," + + PreviewPrograms.COLUMN_ITEM_COUNT + + " INTEGER," + + PreviewPrograms.COLUMN_LIVE + + " INTEGER NOT NULL DEFAULT 0," + + PreviewPrograms.COLUMN_INTERACTION_TYPE + + " INTEGER," + + PreviewPrograms.COLUMN_INTERACTION_COUNT + + " INTEGER," + + PreviewPrograms.COLUMN_AUTHOR + + " TEXT," + + PreviewPrograms.COLUMN_REVIEW_RATING_STYLE + + " INTEGER," + + PreviewPrograms.COLUMN_REVIEW_RATING + + " TEXT," + + PreviewPrograms.COLUMN_BROWSABLE + + " INTEGER NOT NULL DEFAULT 1," + + PreviewPrograms.COLUMN_CONTENT_ID + + " TEXT," + + "FOREIGN KEY(" + + PreviewPrograms.COLUMN_CHANNEL_ID + + "," + + PreviewPrograms.COLUMN_PACKAGE_NAME + + ") REFERENCES " + + CHANNELS_TABLE + + "(" + + Channels._ID + + "," + + Channels.COLUMN_PACKAGE_NAME + + ") ON UPDATE CASCADE ON DELETE CASCADE" + + ");"; + private static final String CREATE_PREVIEW_PROGRAMS_PACKAGE_NAME_INDEX_SQL = + "CREATE INDEX preview_programs_package_name_index ON " + + PREVIEW_PROGRAMS_TABLE + + "(" + + PreviewPrograms.COLUMN_PACKAGE_NAME + + ");"; + private static final String CREATE_PREVIEW_PROGRAMS_CHANNEL_ID_INDEX_SQL = + "CREATE INDEX preview_programs_id_index ON " + + PREVIEW_PROGRAMS_TABLE + + "(" + + PreviewPrograms.COLUMN_CHANNEL_ID + + ");"; + private static final String CREATE_WATCH_NEXT_PROGRAMS_TABLE_SQL = + "CREATE TABLE " + + WATCH_NEXT_PROGRAMS_TABLE + + " (" + + WatchNextPrograms._ID + + " INTEGER PRIMARY KEY AUTOINCREMENT," + + WatchNextPrograms.COLUMN_PACKAGE_NAME + + " TEXT NOT NULL," + + WatchNextPrograms.COLUMN_TITLE + + " TEXT," + + WatchNextPrograms.COLUMN_SEASON_DISPLAY_NUMBER + + " TEXT," + + WatchNextPrograms.COLUMN_SEASON_TITLE + + " TEXT," + + WatchNextPrograms.COLUMN_EPISODE_DISPLAY_NUMBER + + " TEXT," + + WatchNextPrograms.COLUMN_EPISODE_TITLE + + " TEXT," + + WatchNextPrograms.COLUMN_CANONICAL_GENRE + + " TEXT," + + WatchNextPrograms.COLUMN_SHORT_DESCRIPTION + + " TEXT," + + WatchNextPrograms.COLUMN_LONG_DESCRIPTION + + " TEXT," + + WatchNextPrograms.COLUMN_VIDEO_WIDTH + + " INTEGER," + + WatchNextPrograms.COLUMN_VIDEO_HEIGHT + + " INTEGER," + + WatchNextPrograms.COLUMN_AUDIO_LANGUAGE + + " TEXT," + + WatchNextPrograms.COLUMN_CONTENT_RATING + + " TEXT," + + WatchNextPrograms.COLUMN_POSTER_ART_URI + + " TEXT," + + WatchNextPrograms.COLUMN_THUMBNAIL_URI + + " TEXT," + + WatchNextPrograms.COLUMN_SEARCHABLE + + " INTEGER NOT NULL DEFAULT 1," + + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_DATA + + " BLOB," + + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1 + + " INTEGER," + + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2 + + " INTEGER," + + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3 + + " INTEGER," + + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4 + + " INTEGER," + + WatchNextPrograms.COLUMN_VERSION_NUMBER + + " INTEGER," + + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_ID + + " TEXT," + + WatchNextPrograms.COLUMN_PREVIEW_VIDEO_URI + + " TEXT," + + WatchNextPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS + + " INTEGER," + + WatchNextPrograms.COLUMN_DURATION_MILLIS + + " INTEGER," + + WatchNextPrograms.COLUMN_INTENT_URI + + " TEXT," + + WatchNextPrograms.COLUMN_TRANSIENT + + " INTEGER NOT NULL DEFAULT 0," + + WatchNextPrograms.COLUMN_TYPE + + " INTEGER NOT NULL," + + WatchNextPrograms.COLUMN_WATCH_NEXT_TYPE + + " INTEGER," + + WatchNextPrograms.COLUMN_POSTER_ART_ASPECT_RATIO + + " INTEGER," + + WatchNextPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO + + " INTEGER," + + WatchNextPrograms.COLUMN_LOGO_URI + + " TEXT," + + WatchNextPrograms.COLUMN_AVAILABILITY + + " INTEGER," + + WatchNextPrograms.COLUMN_STARTING_PRICE + + " TEXT," + + WatchNextPrograms.COLUMN_OFFER_PRICE + + " TEXT," + + WatchNextPrograms.COLUMN_RELEASE_DATE + + " TEXT," + + WatchNextPrograms.COLUMN_ITEM_COUNT + + " INTEGER," + + WatchNextPrograms.COLUMN_LIVE + + " INTEGER NOT NULL DEFAULT 0," + + WatchNextPrograms.COLUMN_INTERACTION_TYPE + + " INTEGER," + + WatchNextPrograms.COLUMN_INTERACTION_COUNT + + " INTEGER," + + WatchNextPrograms.COLUMN_AUTHOR + + " TEXT," + + WatchNextPrograms.COLUMN_REVIEW_RATING_STYLE + + " INTEGER," + + WatchNextPrograms.COLUMN_REVIEW_RATING + + " TEXT," + + WatchNextPrograms.COLUMN_BROWSABLE + + " INTEGER NOT NULL DEFAULT 1," + + WatchNextPrograms.COLUMN_CONTENT_ID + + " TEXT," + + WatchNextPrograms.COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS + + " INTEGER" + + ");"; + private static final String CREATE_WATCH_NEXT_PROGRAMS_PACKAGE_NAME_INDEX_SQL = + "CREATE INDEX watch_next_programs_package_name_index ON " + + WATCH_NEXT_PROGRAMS_TABLE + + "(" + + WatchNextPrograms.COLUMN_PACKAGE_NAME + + ");"; + + private String mCallingPackage = "com.android.tv"; + + static class DatabaseHelper extends SQLiteOpenHelper { + private Context mContext; + + public static synchronized DatabaseHelper createInstance(Context context) { + return new DatabaseHelper(context); + } + + private DatabaseHelper(Context context) { + this(context, DATABASE_NAME, DATABASE_VERSION); + } + + @VisibleForTesting + DatabaseHelper(Context context, String databaseName, int databaseVersion) { + super(context, databaseName, null, databaseVersion); + mContext = context; + } + + @Override + public void onConfigure(SQLiteDatabase db) { + db.setForeignKeyConstraintsEnabled(true); + } + + @Override + public void onCreate(SQLiteDatabase db) { + if (DEBUG) { + Log.d(TAG, "Creating database"); + } + // Set up the database schema. + db.execSQL( + "CREATE TABLE " + + CHANNELS_TABLE + + " (" + + Channels._ID + + " INTEGER PRIMARY KEY AUTOINCREMENT," + + Channels.COLUMN_PACKAGE_NAME + + " TEXT NOT NULL," + + Channels.COLUMN_INPUT_ID + + " TEXT NOT NULL," + + Channels.COLUMN_TYPE + + " TEXT NOT NULL DEFAULT '" + + Channels.TYPE_OTHER + + "'," + + Channels.COLUMN_SERVICE_TYPE + + " TEXT NOT NULL DEFAULT '" + + Channels.SERVICE_TYPE_AUDIO_VIDEO + + "'," + + Channels.COLUMN_ORIGINAL_NETWORK_ID + + " INTEGER NOT NULL DEFAULT 0," + + Channels.COLUMN_TRANSPORT_STREAM_ID + + " INTEGER NOT NULL DEFAULT 0," + + Channels.COLUMN_SERVICE_ID + + " INTEGER NOT NULL DEFAULT 0," + + Channels.COLUMN_DISPLAY_NUMBER + + " TEXT," + + Channels.COLUMN_DISPLAY_NAME + + " TEXT," + + Channels.COLUMN_NETWORK_AFFILIATION + + " TEXT," + + Channels.COLUMN_DESCRIPTION + + " TEXT," + + Channels.COLUMN_VIDEO_FORMAT + + " TEXT," + + Channels.COLUMN_BROWSABLE + + " INTEGER NOT NULL DEFAULT 0," + + Channels.COLUMN_SEARCHABLE + + " INTEGER NOT NULL DEFAULT 1," + + Channels.COLUMN_LOCKED + + " INTEGER NOT NULL DEFAULT 0," + + Channels.COLUMN_APP_LINK_ICON_URI + + " TEXT," + + Channels.COLUMN_APP_LINK_POSTER_ART_URI + + " TEXT," + + Channels.COLUMN_APP_LINK_TEXT + + " TEXT," + + Channels.COLUMN_APP_LINK_COLOR + + " INTEGER," + + Channels.COLUMN_APP_LINK_INTENT_URI + + " TEXT," + + Channels.COLUMN_INTERNAL_PROVIDER_DATA + + " BLOB," + + Channels.COLUMN_INTERNAL_PROVIDER_FLAG1 + + " INTEGER," + + Channels.COLUMN_INTERNAL_PROVIDER_FLAG2 + + " INTEGER," + + Channels.COLUMN_INTERNAL_PROVIDER_FLAG3 + + " INTEGER," + + Channels.COLUMN_INTERNAL_PROVIDER_FLAG4 + + " INTEGER," + + CHANNELS_COLUMN_LOGO + + " BLOB," + + Channels.COLUMN_VERSION_NUMBER + + " INTEGER," + + Channels.COLUMN_TRANSIENT + + " INTEGER NOT NULL DEFAULT 0," + + Channels.COLUMN_INTERNAL_PROVIDER_ID + + " TEXT," + // Needed for foreign keys in other tables. + + "UNIQUE(" + + Channels._ID + + "," + + Channels.COLUMN_PACKAGE_NAME + + ")" + + ");"); + db.execSQL( + "CREATE TABLE " + + PROGRAMS_TABLE + + " (" + + Programs._ID + + " INTEGER PRIMARY KEY AUTOINCREMENT," + + Programs.COLUMN_PACKAGE_NAME + + " TEXT NOT NULL," + + Programs.COLUMN_CHANNEL_ID + + " INTEGER," + + Programs.COLUMN_TITLE + + " TEXT," + + Programs.COLUMN_SEASON_DISPLAY_NUMBER + + " TEXT," + + Programs.COLUMN_SEASON_TITLE + + " TEXT," + + Programs.COLUMN_EPISODE_DISPLAY_NUMBER + + " TEXT," + + Programs.COLUMN_EPISODE_TITLE + + " TEXT," + + Programs.COLUMN_START_TIME_UTC_MILLIS + + " INTEGER," + + Programs.COLUMN_END_TIME_UTC_MILLIS + + " INTEGER," + + Programs.COLUMN_BROADCAST_GENRE + + " TEXT," + + Programs.COLUMN_CANONICAL_GENRE + + " TEXT," + + Programs.COLUMN_SHORT_DESCRIPTION + + " TEXT," + + Programs.COLUMN_LONG_DESCRIPTION + + " TEXT," + + Programs.COLUMN_VIDEO_WIDTH + + " INTEGER," + + Programs.COLUMN_VIDEO_HEIGHT + + " INTEGER," + + Programs.COLUMN_AUDIO_LANGUAGE + + " TEXT," + + Programs.COLUMN_CONTENT_RATING + + " TEXT," + + Programs.COLUMN_POSTER_ART_URI + + " TEXT," + + Programs.COLUMN_THUMBNAIL_URI + + " TEXT," + + Programs.COLUMN_SEARCHABLE + + " INTEGER NOT NULL DEFAULT 1," + + Programs.COLUMN_RECORDING_PROHIBITED + + " INTEGER NOT NULL DEFAULT 0," + + Programs.COLUMN_INTERNAL_PROVIDER_DATA + + " BLOB," + + Programs.COLUMN_INTERNAL_PROVIDER_FLAG1 + + " INTEGER," + + Programs.COLUMN_INTERNAL_PROVIDER_FLAG2 + + " INTEGER," + + Programs.COLUMN_INTERNAL_PROVIDER_FLAG3 + + " INTEGER," + + Programs.COLUMN_INTERNAL_PROVIDER_FLAG4 + + " INTEGER," + + Programs.COLUMN_REVIEW_RATING_STYLE + + " INTEGER," + + Programs.COLUMN_REVIEW_RATING + + " TEXT," + + Programs.COLUMN_VERSION_NUMBER + + " INTEGER," + + "FOREIGN KEY(" + + Programs.COLUMN_CHANNEL_ID + + "," + + Programs.COLUMN_PACKAGE_NAME + + ") REFERENCES " + + CHANNELS_TABLE + + "(" + + Channels._ID + + "," + + Channels.COLUMN_PACKAGE_NAME + + ") ON UPDATE CASCADE ON DELETE CASCADE" + + ");"); + db.execSQL( + "CREATE INDEX " + + PROGRAMS_TABLE_PACKAGE_NAME_INDEX + + " ON " + + PROGRAMS_TABLE + + "(" + + Programs.COLUMN_PACKAGE_NAME + + ");"); + db.execSQL( + "CREATE INDEX " + + PROGRAMS_TABLE_CHANNEL_ID_INDEX + + " ON " + + PROGRAMS_TABLE + + "(" + + Programs.COLUMN_CHANNEL_ID + + ");"); + db.execSQL( + "CREATE INDEX " + + PROGRAMS_TABLE_START_TIME_INDEX + + " ON " + + PROGRAMS_TABLE + + "(" + + Programs.COLUMN_START_TIME_UTC_MILLIS + + ");"); + db.execSQL( + "CREATE INDEX " + + PROGRAMS_TABLE_END_TIME_INDEX + + " ON " + + PROGRAMS_TABLE + + "(" + + Programs.COLUMN_END_TIME_UTC_MILLIS + + ");"); + db.execSQL( + "CREATE TABLE " + + WATCHED_PROGRAMS_TABLE + + " (" + + WatchedPrograms._ID + + " INTEGER PRIMARY KEY AUTOINCREMENT," + + WatchedPrograms.COLUMN_PACKAGE_NAME + + " TEXT NOT NULL," + + WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS + + " INTEGER NOT NULL DEFAULT 0," + + WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS + + " INTEGER NOT NULL DEFAULT 0," + + WatchedPrograms.COLUMN_CHANNEL_ID + + " INTEGER," + + WatchedPrograms.COLUMN_TITLE + + " TEXT," + + WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS + + " INTEGER," + + WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS + + " INTEGER," + + WatchedPrograms.COLUMN_DESCRIPTION + + " TEXT," + + WatchedPrograms.COLUMN_INTERNAL_TUNE_PARAMS + + " TEXT," + + WatchedPrograms.COLUMN_INTERNAL_SESSION_TOKEN + + " TEXT NOT NULL," + + WATCHED_PROGRAMS_COLUMN_CONSOLIDATED + + " INTEGER NOT NULL DEFAULT 0," + + "FOREIGN KEY(" + + WatchedPrograms.COLUMN_CHANNEL_ID + + "," + + WatchedPrograms.COLUMN_PACKAGE_NAME + + ") REFERENCES " + + CHANNELS_TABLE + + "(" + + Channels._ID + + "," + + Channels.COLUMN_PACKAGE_NAME + + ") ON UPDATE CASCADE ON DELETE CASCADE" + + ");"); + db.execSQL( + "CREATE INDEX " + + WATCHED_PROGRAMS_TABLE_CHANNEL_ID_INDEX + + " ON " + + WATCHED_PROGRAMS_TABLE + + "(" + + WatchedPrograms.COLUMN_CHANNEL_ID + + ");"); + db.execSQL(CREATE_RECORDED_PROGRAMS_TABLE_SQL); + db.execSQL(CREATE_PREVIEW_PROGRAMS_TABLE_SQL); + db.execSQL(CREATE_PREVIEW_PROGRAMS_PACKAGE_NAME_INDEX_SQL); + db.execSQL(CREATE_PREVIEW_PROGRAMS_CHANNEL_ID_INDEX_SQL); + db.execSQL(CREATE_WATCH_NEXT_PROGRAMS_TABLE_SQL); + db.execSQL(CREATE_WATCH_NEXT_PROGRAMS_PACKAGE_NAME_INDEX_SQL); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + if (oldVersion < 23) { + Log.i( + TAG, + "Upgrading from version " + + oldVersion + + " to " + + newVersion + + ", data will be lost!"); + db.execSQL("DROP TABLE IF EXISTS " + DELETED_CHANNELS_TABLE); + db.execSQL("DROP TABLE IF EXISTS " + WATCHED_PROGRAMS_TABLE); + db.execSQL("DROP TABLE IF EXISTS " + PROGRAMS_TABLE); + db.execSQL("DROP TABLE IF EXISTS " + CHANNELS_TABLE); + + onCreate(db); + return; + } + + Log.i(TAG, "Upgrading from version " + oldVersion + " to " + newVersion + "."); + if (oldVersion <= 23) { + db.execSQL( + "ALTER TABLE " + + CHANNELS_TABLE + + " ADD " + + Channels.COLUMN_INTERNAL_PROVIDER_FLAG1 + + " INTEGER;"); + db.execSQL( + "ALTER TABLE " + + CHANNELS_TABLE + + " ADD " + + Channels.COLUMN_INTERNAL_PROVIDER_FLAG2 + + " INTEGER;"); + db.execSQL( + "ALTER TABLE " + + CHANNELS_TABLE + + " ADD " + + Channels.COLUMN_INTERNAL_PROVIDER_FLAG3 + + " INTEGER;"); + db.execSQL( + "ALTER TABLE " + + CHANNELS_TABLE + + " ADD " + + Channels.COLUMN_INTERNAL_PROVIDER_FLAG4 + + " INTEGER;"); + } + if (oldVersion <= 24) { + db.execSQL( + "ALTER TABLE " + + PROGRAMS_TABLE + + " ADD " + + Programs.COLUMN_INTERNAL_PROVIDER_FLAG1 + + " INTEGER;"); + db.execSQL( + "ALTER TABLE " + + PROGRAMS_TABLE + + " ADD " + + Programs.COLUMN_INTERNAL_PROVIDER_FLAG2 + + " INTEGER;"); + db.execSQL( + "ALTER TABLE " + + PROGRAMS_TABLE + + " ADD " + + Programs.COLUMN_INTERNAL_PROVIDER_FLAG3 + + " INTEGER;"); + db.execSQL( + "ALTER TABLE " + + PROGRAMS_TABLE + + " ADD " + + Programs.COLUMN_INTERNAL_PROVIDER_FLAG4 + + " INTEGER;"); + } + if (oldVersion <= 25) { + db.execSQL( + "ALTER TABLE " + + CHANNELS_TABLE + + " ADD " + + Channels.COLUMN_APP_LINK_ICON_URI + + " TEXT;"); + db.execSQL( + "ALTER TABLE " + + CHANNELS_TABLE + + " ADD " + + Channels.COLUMN_APP_LINK_POSTER_ART_URI + + " TEXT;"); + db.execSQL( + "ALTER TABLE " + + CHANNELS_TABLE + + " ADD " + + Channels.COLUMN_APP_LINK_TEXT + + " TEXT;"); + db.execSQL( + "ALTER TABLE " + + CHANNELS_TABLE + + " ADD " + + Channels.COLUMN_APP_LINK_COLOR + + " INTEGER;"); + db.execSQL( + "ALTER TABLE " + + CHANNELS_TABLE + + " ADD " + + Channels.COLUMN_APP_LINK_INTENT_URI + + " TEXT;"); + db.execSQL( + "ALTER TABLE " + + PROGRAMS_TABLE + + " ADD " + + Programs.COLUMN_SEARCHABLE + + " INTEGER NOT NULL DEFAULT 1;"); + } + if (oldVersion <= 28) { + db.execSQL( + "ALTER TABLE " + + PROGRAMS_TABLE + + " ADD " + + Programs.COLUMN_SEASON_TITLE + + " TEXT;"); + migrateIntegerColumnToTextColumn( + db, + PROGRAMS_TABLE, + Programs.COLUMN_SEASON_NUMBER, + Programs.COLUMN_SEASON_DISPLAY_NUMBER); + migrateIntegerColumnToTextColumn( + db, + PROGRAMS_TABLE, + Programs.COLUMN_EPISODE_NUMBER, + Programs.COLUMN_EPISODE_DISPLAY_NUMBER); + } + if (oldVersion <= 29) { + db.execSQL("DROP TABLE IF EXISTS " + RECORDED_PROGRAMS_TABLE); + db.execSQL(CREATE_RECORDED_PROGRAMS_TABLE_SQL); + } + if (oldVersion <= 30) { + db.execSQL( + "ALTER TABLE " + + PROGRAMS_TABLE + + " ADD " + + Programs.COLUMN_RECORDING_PROHIBITED + + " INTEGER NOT NULL DEFAULT 0;"); + } + if (oldVersion <= 32) { + db.execSQL( + "ALTER TABLE " + + CHANNELS_TABLE + + " ADD " + + Channels.COLUMN_TRANSIENT + + " INTEGER NOT NULL DEFAULT 0;"); + db.execSQL( + "ALTER TABLE " + + CHANNELS_TABLE + + " ADD " + + Channels.COLUMN_INTERNAL_PROVIDER_ID + + " TEXT;"); + db.execSQL( + "ALTER TABLE " + + PROGRAMS_TABLE + + " ADD " + + Programs.COLUMN_REVIEW_RATING_STYLE + + " INTEGER;"); + db.execSQL( + "ALTER TABLE " + + PROGRAMS_TABLE + + " ADD " + + Programs.COLUMN_REVIEW_RATING + + " TEXT;"); + if (oldVersion > 29) { + db.execSQL( + "ALTER TABLE " + + RECORDED_PROGRAMS_TABLE + + " ADD " + + RecordedPrograms.COLUMN_REVIEW_RATING_STYLE + + " INTEGER;"); + db.execSQL( + "ALTER TABLE " + + RECORDED_PROGRAMS_TABLE + + " ADD " + + RecordedPrograms.COLUMN_REVIEW_RATING + + " TEXT;"); + } + } + if (oldVersion <= 33) { + db.execSQL("DROP TABLE IF EXISTS " + PREVIEW_PROGRAMS_TABLE); + db.execSQL("DROP TABLE IF EXISTS " + WATCH_NEXT_PROGRAMS_TABLE); + db.execSQL(CREATE_PREVIEW_PROGRAMS_TABLE_SQL); + db.execSQL(CREATE_PREVIEW_PROGRAMS_PACKAGE_NAME_INDEX_SQL); + db.execSQL(CREATE_PREVIEW_PROGRAMS_CHANNEL_ID_INDEX_SQL); + db.execSQL(CREATE_WATCH_NEXT_PROGRAMS_TABLE_SQL); + db.execSQL(CREATE_WATCH_NEXT_PROGRAMS_PACKAGE_NAME_INDEX_SQL); + } + Log.i(TAG, "Upgrading from version " + oldVersion + " to " + newVersion + " is done."); + } + + @Override + public void onOpen(SQLiteDatabase db) { + // Call a static method on the TvProvider because changes to sInitialized must + // be guarded by a lock on the class. + initOnOpenIfNeeded(mContext, db); + } + + private static void migrateIntegerColumnToTextColumn( + SQLiteDatabase db, String table, String integerColumn, String textColumn) { + db.execSQL("ALTER TABLE " + table + " ADD " + textColumn + " TEXT;"); + db.execSQL( + "UPDATE " + + table + + " SET " + + textColumn + + " = CAST(" + + integerColumn + + " AS TEXT);"); + } + } + + private DatabaseHelper mOpenHelper; + private static SharedPreferences sBlockedPackagesSharedPreference; + private static Map<String, Boolean> sBlockedPackages; + + @Override + public boolean onCreate() { + if (DEBUG) { + Log.d(TAG, "Creating TvProvider"); + } + mOpenHelper = DatabaseHelper.createInstance(getContext()); + return true; + } + + @VisibleForTesting + String getCallingPackage_() { + return mCallingPackage; + } + + public void setCallingPackage(String packageName) { + mCallingPackage = packageName; + } + + void setOpenHelper(DatabaseHelper helper) { + mOpenHelper = helper; + } + + @Override + public String getType(Uri uri) { + switch (sUriMatcher.match(uri)) { + case MATCH_CHANNEL: + return Channels.CONTENT_TYPE; + case MATCH_CHANNEL_ID: + return Channels.CONTENT_ITEM_TYPE; + case MATCH_CHANNEL_ID_LOGO: + return "image/png"; + case MATCH_PASSTHROUGH_ID: + return Channels.CONTENT_ITEM_TYPE; + case MATCH_PROGRAM: + return Programs.CONTENT_TYPE; + case MATCH_PROGRAM_ID: + return Programs.CONTENT_ITEM_TYPE; + case MATCH_WATCHED_PROGRAM: + return WatchedPrograms.CONTENT_TYPE; + case MATCH_WATCHED_PROGRAM_ID: + return WatchedPrograms.CONTENT_ITEM_TYPE; + case MATCH_RECORDED_PROGRAM: + return RecordedPrograms.CONTENT_TYPE; + case MATCH_RECORDED_PROGRAM_ID: + return RecordedPrograms.CONTENT_ITEM_TYPE; + case MATCH_PREVIEW_PROGRAM: + return PreviewPrograms.CONTENT_TYPE; + case MATCH_PREVIEW_PROGRAM_ID: + return PreviewPrograms.CONTENT_ITEM_TYPE; + case MATCH_WATCH_NEXT_PROGRAM: + return WatchNextPrograms.CONTENT_TYPE; + case MATCH_WATCH_NEXT_PROGRAM_ID: + return WatchNextPrograms.CONTENT_ITEM_TYPE; + default: + throw new IllegalArgumentException("Unknown URI " + uri); + } + } + + @Override + public Bundle call(String method, String arg, Bundle extras) { + throw new UnsupportedOperationException(); + } + + @Override + public Cursor query( + Uri uri, + String[] projection, + String selection, + String[] selectionArgs, + String sortOrder) { + ensureInitialized(); + boolean needsToValidateSortOrder = !callerHasAccessAllEpgDataPermission(); + SqlParams params = createSqlParams(OP_QUERY, uri, selection, selectionArgs); + + SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder(); + queryBuilder.setStrict(needsToValidateSortOrder); + queryBuilder.setTables(params.getTables()); + String orderBy = null; + Map<String, String> projectionMap; + switch (params.getTables()) { + case PROGRAMS_TABLE: + projectionMap = sProgramProjectionMap; + orderBy = DEFAULT_PROGRAMS_SORT_ORDER; + break; + case WATCHED_PROGRAMS_TABLE: + projectionMap = sWatchedProgramProjectionMap; + orderBy = DEFAULT_WATCHED_PROGRAMS_SORT_ORDER; + break; + case RECORDED_PROGRAMS_TABLE: + projectionMap = sRecordedProgramProjectionMap; + break; + case PREVIEW_PROGRAMS_TABLE: + projectionMap = sPreviewProgramProjectionMap; + break; + case WATCH_NEXT_PROGRAMS_TABLE: + projectionMap = sWatchNextProgramProjectionMap; + break; + default: + projectionMap = sChannelProjectionMap; + break; + } + queryBuilder.setProjectionMap(createProjectionMapForQuery(projection, projectionMap)); + if (needsToValidateSortOrder) { + validateSortOrder(sortOrder, projectionMap.keySet()); + } + + // Use the default sort order only if no sort order is specified. + if (!TextUtils.isEmpty(sortOrder)) { + orderBy = sortOrder; + } + + // Get the database and run the query. + SQLiteDatabase db = mOpenHelper.getReadableDatabase(); + Cursor c = + queryBuilder.query( + db, + projection, + params.getSelection(), + params.getSelectionArgs(), + null, + null, + orderBy); + + // Tell the cursor what URI to watch, so it knows when its source data changes. + c.setNotificationUri(getContext().getContentResolver(), uri); + return c; + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + ensureInitialized(); + switch (sUriMatcher.match(uri)) { + case MATCH_CHANNEL: + // Preview channels are not necessarily associated with TV input service. + // Therefore, we fill a fake ID to meet not null restriction for preview channels. + if (values.get(Channels.COLUMN_INPUT_ID) == null + && TvContractCompat.PARAM_CHANNEL.equals( + values.get(Channels.COLUMN_TYPE))) { + values.put(Channels.COLUMN_INPUT_ID, EMPTY_STRING); + } + filterContentValues(values, sChannelProjectionMap); + return insertChannel(uri, values); + case MATCH_PROGRAM: + filterContentValues(values, sProgramProjectionMap); + return insertProgram(uri, values); + case MATCH_WATCHED_PROGRAM: + return insertWatchedProgram(uri, values); + case MATCH_RECORDED_PROGRAM: + filterContentValues(values, sRecordedProgramProjectionMap); + return insertRecordedProgram(uri, values); + case MATCH_PREVIEW_PROGRAM: + filterContentValues(values, sPreviewProgramProjectionMap); + return insertPreviewProgram(uri, values); + case MATCH_WATCH_NEXT_PROGRAM: + filterContentValues(values, sWatchNextProgramProjectionMap); + return insertWatchNextProgram(uri, values); + case MATCH_CHANNEL_ID: + case MATCH_CHANNEL_ID_LOGO: + case MATCH_PASSTHROUGH_ID: + case MATCH_PROGRAM_ID: + case MATCH_WATCHED_PROGRAM_ID: + case MATCH_RECORDED_PROGRAM_ID: + case MATCH_PREVIEW_PROGRAM_ID: + throw new UnsupportedOperationException("Cannot insert into that URI: " + uri); + default: + throw new IllegalArgumentException("Unknown URI " + uri); + } + } + + private Uri insertChannel(Uri uri, ContentValues values) { + if (TextUtils.equals( + values.getAsString(Channels.COLUMN_TYPE), TvContractCompat.Channels.TYPE_PREVIEW)) { + blockIllegalAccessFromBlockedPackage(); + } + // Mark the owner package of this channel. + values.put(Channels.COLUMN_PACKAGE_NAME, getCallingPackage_()); + blockIllegalAccessToChannelsSystemColumns(values); + + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + long rowId = db.insert(CHANNELS_TABLE, null, values); + if (rowId > 0) { + Uri channelUri = TvContractCompat.buildChannelUri(rowId); + notifyChange(channelUri); + return channelUri; + } + + throw new SQLException("Failed to insert row into " + uri); + } + + private Uri insertProgram(Uri uri, ContentValues values) { + if (!callerHasAccessAllEpgDataPermission() + || !values.containsKey(Programs.COLUMN_PACKAGE_NAME)) { + // Mark the owner package of this program. System app with a proper permission may + // change the owner of the program. + values.put(Programs.COLUMN_PACKAGE_NAME, getCallingPackage_()); + } + + checkAndConvertGenre(values); + checkAndConvertDeprecatedColumns(values); + + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + long rowId = db.insert(PROGRAMS_TABLE, null, values); + if (rowId > 0) { + Uri programUri = TvContractCompat.buildProgramUri(rowId); + notifyChange(programUri); + return programUri; + } + + throw new SQLException("Failed to insert row into " + uri); + } + + private Uri insertWatchedProgram(Uri uri, ContentValues values) { + if (DEBUG) { + Log.d(TAG, "insertWatchedProgram(uri=" + uri + ", values={" + values + "})"); + } + Long watchStartTime = values.getAsLong(WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS); + Long watchEndTime = values.getAsLong(WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS); + // The system sends only two kinds of watch events: + // 1. The user tunes to a new channel. (COLUMN_WATCH_START_TIME_UTC_MILLIS) + // 2. The user stops watching. (COLUMN_WATCH_END_TIME_UTC_MILLIS) + if (watchStartTime != null && watchEndTime == null) { + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + long rowId = db.insert(WATCHED_PROGRAMS_TABLE, null, values); + if (rowId > 0) { + return ContentUris.withAppendedId(WatchedPrograms.CONTENT_URI, rowId); + } + Log.w(TAG, "Failed to insert row for " + values + ". Channel does not exist."); + return null; + } else if (watchStartTime == null && watchEndTime != null) { + return null; + } + // All the other cases are invalid. + throw new IllegalArgumentException( + "Only one of COLUMN_WATCH_START_TIME_UTC_MILLIS and" + + " COLUMN_WATCH_END_TIME_UTC_MILLIS should be specified"); + } + + private Uri insertRecordedProgram(Uri uri, ContentValues values) { + // Mark the owner package of this program. + values.put(Programs.COLUMN_PACKAGE_NAME, getCallingPackage_()); + + checkAndConvertGenre(values); + + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + long rowId = db.insert(RECORDED_PROGRAMS_TABLE, null, values); + if (rowId > 0) { + Uri recordedProgramUri = TvContractCompat.buildRecordedProgramUri(rowId); + notifyChange(recordedProgramUri); + return recordedProgramUri; + } + + throw new SQLException("Failed to insert row into " + uri); + } + + private Uri insertPreviewProgram(Uri uri, ContentValues values) { + if (!values.containsKey(PreviewPrograms.COLUMN_TYPE)) { + throw new IllegalArgumentException( + "Missing the required column: " + PreviewPrograms.COLUMN_TYPE); + } + blockIllegalAccessFromBlockedPackage(); + // Mark the owner package of this program. + values.put(Programs.COLUMN_PACKAGE_NAME, getCallingPackage_()); + blockIllegalAccessToPreviewProgramsSystemColumns(values); + + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + long rowId = db.insert(PREVIEW_PROGRAMS_TABLE, null, values); + if (rowId > 0) { + Uri previewProgramUri = TvContractCompat.buildPreviewProgramUri(rowId); + notifyChange(previewProgramUri); + return previewProgramUri; + } + + throw new SQLException("Failed to insert row into " + uri); + } + + private Uri insertWatchNextProgram(Uri uri, ContentValues values) { + if (!values.containsKey(WatchNextPrograms.COLUMN_TYPE)) { + throw new IllegalArgumentException( + "Missing the required column: " + WatchNextPrograms.COLUMN_TYPE); + } + blockIllegalAccessFromBlockedPackage(); + if (!callerHasAccessAllEpgDataPermission() + || !values.containsKey(Programs.COLUMN_PACKAGE_NAME)) { + // Mark the owner package of this program. System app with a proper permission may + // change the owner of the program. + values.put(Programs.COLUMN_PACKAGE_NAME, getCallingPackage_()); + } + blockIllegalAccessToPreviewProgramsSystemColumns(values); + + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + long rowId = db.insert(WATCH_NEXT_PROGRAMS_TABLE, null, values); + if (rowId > 0) { + Uri watchNextProgramUri = TvContractCompat.buildWatchNextProgramUri(rowId); + notifyChange(watchNextProgramUri); + return watchNextProgramUri; + } + + throw new SQLException("Failed to insert row into " + uri); + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + SqlParams params = createSqlParams(OP_DELETE, uri, selection, selectionArgs); + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + int count; + switch (sUriMatcher.match(uri)) { + case MATCH_CHANNEL_ID_LOGO: + ContentValues values = new ContentValues(); + values.putNull(CHANNELS_COLUMN_LOGO); + count = + db.update( + params.getTables(), + values, + params.getSelection(), + params.getSelectionArgs()); + break; + case MATCH_CHANNEL: + case MATCH_PROGRAM: + case MATCH_WATCHED_PROGRAM: + case MATCH_RECORDED_PROGRAM: + case MATCH_PREVIEW_PROGRAM: + case MATCH_WATCH_NEXT_PROGRAM: + case MATCH_CHANNEL_ID: + case MATCH_PASSTHROUGH_ID: + case MATCH_PROGRAM_ID: + case MATCH_WATCHED_PROGRAM_ID: + case MATCH_RECORDED_PROGRAM_ID: + case MATCH_PREVIEW_PROGRAM_ID: + case MATCH_WATCH_NEXT_PROGRAM_ID: + count = + db.delete( + params.getTables(), + params.getSelection(), + params.getSelectionArgs()); + break; + default: + throw new IllegalArgumentException("Unknown URI " + uri); + } + if (count > 0) { + notifyChange(uri); + } + return count; + } + + @Override + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + SqlParams params = createSqlParams(OP_UPDATE, uri, selection, selectionArgs); + blockIllegalAccessToIdAndPackageName(uri, values); + boolean containImmutableColumn = false; + if (params.getTables().equals(CHANNELS_TABLE)) { + filterContentValues(values, sChannelProjectionMap); + containImmutableColumn = disallowModifyChannelType(values, params); + if (containImmutableColumn && sUriMatcher.match(uri) != MATCH_CHANNEL_ID) { + Log.i(TAG, "Updating failed. Attempt to change immutable column for channels."); + return 0; + } + blockIllegalAccessToChannelsSystemColumns(values); + } else if (params.getTables().equals(PROGRAMS_TABLE)) { + filterContentValues(values, sProgramProjectionMap); + checkAndConvertGenre(values); + checkAndConvertDeprecatedColumns(values); + } else if (params.getTables().equals(RECORDED_PROGRAMS_TABLE)) { + filterContentValues(values, sRecordedProgramProjectionMap); + checkAndConvertGenre(values); + } else if (params.getTables().equals(PREVIEW_PROGRAMS_TABLE)) { + filterContentValues(values, sPreviewProgramProjectionMap); + containImmutableColumn = disallowModifyChannelId(values, params); + if (containImmutableColumn && PreviewPrograms.CONTENT_URI.equals(uri)) { + Log.i( + TAG, + "Updating failed. Attempt to change unmodifiable column for " + + "preview programs."); + return 0; + } + blockIllegalAccessToPreviewProgramsSystemColumns(values); + } else if (params.getTables().equals(WATCH_NEXT_PROGRAMS_TABLE)) { + filterContentValues(values, sWatchNextProgramProjectionMap); + blockIllegalAccessToPreviewProgramsSystemColumns(values); + } + if (values.size() == 0) { + // All values may be filtered out, no need to update + return 0; + } + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + int count = + db.update( + params.getTables(), + values, + params.getSelection(), + params.getSelectionArgs()); + if (count > 0) { + notifyChange(uri); + } else if (containImmutableColumn) { + Log.i( + TAG, + "Updating failed. The item may not exist or attempt to change " + + "immutable column."); + } + return count; + } + + private synchronized void ensureInitialized() { + if (!sInitialized) { + // Database is not accessed before and the projection maps and the blocked package list + // are not updated yet. Gets database here to make it initialized. + mOpenHelper.getReadableDatabase(); + } + } + + private static synchronized void initOnOpenIfNeeded(Context context, SQLiteDatabase db) { + if (!sInitialized) { + updateProjectionMap(db, CHANNELS_TABLE, sChannelProjectionMap); + updateProjectionMap(db, PROGRAMS_TABLE, sProgramProjectionMap); + updateProjectionMap(db, WATCHED_PROGRAMS_TABLE, sWatchedProgramProjectionMap); + updateProjectionMap(db, RECORDED_PROGRAMS_TABLE, sRecordedProgramProjectionMap); + updateProjectionMap(db, PREVIEW_PROGRAMS_TABLE, sPreviewProgramProjectionMap); + updateProjectionMap(db, WATCH_NEXT_PROGRAMS_TABLE, sWatchNextProgramProjectionMap); + sBlockedPackagesSharedPreference = + PreferenceManager.getDefaultSharedPreferences(context); + sBlockedPackages = new ConcurrentHashMap<>(); + for (String packageName : + sBlockedPackagesSharedPreference.getStringSet( + SHARED_PREF_BLOCKED_PACKAGES_KEY, new HashSet<>())) { + sBlockedPackages.put(packageName, true); + } + sInitialized = true; + } + } + + private static void updateProjectionMap( + SQLiteDatabase db, String tableName, Map<String, String> projectionMap) { + try (Cursor cursor = db.rawQuery("SELECT * FROM " + tableName + " LIMIT 0", null)) { + for (String columnName : cursor.getColumnNames()) { + if (!projectionMap.containsKey(columnName)) { + projectionMap.put(columnName, tableName + '.' + columnName); + } + } + } + } + + private Map<String, String> createProjectionMapForQuery( + String[] projection, Map<String, String> projectionMap) { + if (projection == null) { + return projectionMap; + } + Map<String, String> columnProjectionMap = new HashMap<>(); + for (String columnName : projection) { + // Value NULL will be provided if the requested column does not exist in the database. + columnProjectionMap.put( + columnName, projectionMap.getOrDefault(columnName, "NULL as " + columnName)); + } + return columnProjectionMap; + } + + private void filterContentValues(ContentValues values, Map<String, String> projectionMap) { + Iterator<String> iter = values.keySet().iterator(); + while (iter.hasNext()) { + String columnName = iter.next(); + if (!projectionMap.containsKey(columnName)) { + iter.remove(); + } + } + } + + private SqlParams createSqlParams( + String operation, Uri uri, String selection, String[] selectionArgs) { + int match = sUriMatcher.match(uri); + SqlParams params = new SqlParams(null, selection, selectionArgs); + + // Control access to EPG data (excluding watched programs) when the caller doesn't have all + // access. + String prefix = match == MATCH_CHANNEL ? CHANNELS_TABLE + "." : ""; + if (!callerHasAccessAllEpgDataPermission() + && match != MATCH_WATCHED_PROGRAM + && match != MATCH_WATCHED_PROGRAM_ID) { + if (!TextUtils.isEmpty(selection)) { + throw new SecurityException("Selection not allowed for " + uri); + } + // Limit the operation only to the data that the calling package owns except for when + // the caller tries to read TV listings and has the appropriate permission. + if (operation.equals(OP_QUERY) && callerHasReadTvListingsPermission()) { + params.setWhere( + prefix + + BaseTvColumns.COLUMN_PACKAGE_NAME + + "=? OR " + + Channels.COLUMN_SEARCHABLE + + "=?", + getCallingPackage_(), + "1"); + } else { + params.setWhere( + prefix + BaseTvColumns.COLUMN_PACKAGE_NAME + "=?", getCallingPackage_()); + } + } + String packageName = uri.getQueryParameter(PARAM_PACKAGE); + if (packageName != null) { + params.appendWhere(prefix + BaseTvColumns.COLUMN_PACKAGE_NAME + "=?", packageName); + } + + switch (match) { + case MATCH_CHANNEL: + String genre = uri.getQueryParameter(TvContractCompat.PARAM_CANONICAL_GENRE); + if (genre == null) { + params.setTables(CHANNELS_TABLE); + } else { + if (!operation.equals(OP_QUERY)) { + throw new SecurityException( + capitalize(operation) + " not allowed for " + uri); + } + if (!Genres.isCanonical(genre)) { + throw new IllegalArgumentException("Not a canonical genre : " + genre); + } + params.setTables(CHANNELS_TABLE_INNER_JOIN_PROGRAMS_TABLE); + String curTime = String.valueOf(System.currentTimeMillis()); + params.appendWhere( + "LIKE(?, " + + Programs.COLUMN_CANONICAL_GENRE + + ") AND " + + Programs.COLUMN_START_TIME_UTC_MILLIS + + "<=? AND " + + Programs.COLUMN_END_TIME_UTC_MILLIS + + ">=?", + "%" + genre + "%", + curTime, + curTime); + } + String inputId = uri.getQueryParameter(TvContractCompat.PARAM_INPUT); + if (inputId != null) { + params.appendWhere(Channels.COLUMN_INPUT_ID + "=?", inputId); + } + boolean browsableOnly = + uri.getBooleanQueryParameter(TvContractCompat.PARAM_BROWSABLE_ONLY, false); + if (browsableOnly) { + params.appendWhere(Channels.COLUMN_BROWSABLE + "=1"); + } + String preview = uri.getQueryParameter(PARAM_PREVIEW); + if (preview != null) { + String previewSelection = + Channels.COLUMN_TYPE + + (preview.equals(String.valueOf(true)) ? "=?" : "!=?"); + params.appendWhere(previewSelection, Channels.TYPE_PREVIEW); + } + break; + case MATCH_CHANNEL_ID: + params.setTables(CHANNELS_TABLE); + params.appendWhere(Channels._ID + "=?", uri.getLastPathSegment()); + break; + case MATCH_PROGRAM: + params.setTables(PROGRAMS_TABLE); + String paramChannelId = uri.getQueryParameter(TvContractCompat.PARAM_CHANNEL); + if (paramChannelId != null) { + String channelId = String.valueOf(Long.parseLong(paramChannelId)); + params.appendWhere(Programs.COLUMN_CHANNEL_ID + "=?", channelId); + } + String paramStartTime = uri.getQueryParameter(TvContractCompat.PARAM_START_TIME); + String paramEndTime = uri.getQueryParameter(TvContractCompat.PARAM_END_TIME); + if (paramStartTime != null && paramEndTime != null) { + String startTime = String.valueOf(Long.parseLong(paramStartTime)); + String endTime = String.valueOf(Long.parseLong(paramEndTime)); + params.appendWhere( + Programs.COLUMN_START_TIME_UTC_MILLIS + + "<=? AND " + + Programs.COLUMN_END_TIME_UTC_MILLIS + + ">=? AND ?<=?", + endTime, + startTime, + startTime, + endTime); + } + break; + case MATCH_PROGRAM_ID: + params.setTables(PROGRAMS_TABLE); + params.appendWhere(Programs._ID + "=?", uri.getLastPathSegment()); + break; + case MATCH_WATCHED_PROGRAM: + if (!callerHasAccessWatchedProgramsPermission()) { + throw new SecurityException("Access not allowed for " + uri); + } + params.setTables(WATCHED_PROGRAMS_TABLE); + params.appendWhere(WATCHED_PROGRAMS_COLUMN_CONSOLIDATED + "=?", "1"); + break; + case MATCH_WATCHED_PROGRAM_ID: + if (!callerHasAccessWatchedProgramsPermission()) { + throw new SecurityException("Access not allowed for " + uri); + } + params.setTables(WATCHED_PROGRAMS_TABLE); + params.appendWhere(WatchedPrograms._ID + "=?", uri.getLastPathSegment()); + params.appendWhere(WATCHED_PROGRAMS_COLUMN_CONSOLIDATED + "=?", "1"); + break; + case MATCH_RECORDED_PROGRAM_ID: + params.appendWhere(RecordedPrograms._ID + "=?", uri.getLastPathSegment()); + // fall-through + case MATCH_RECORDED_PROGRAM: + params.setTables(RECORDED_PROGRAMS_TABLE); + paramChannelId = uri.getQueryParameter(TvContractCompat.PARAM_CHANNEL); + if (paramChannelId != null) { + String channelId = String.valueOf(Long.parseLong(paramChannelId)); + params.appendWhere(Programs.COLUMN_CHANNEL_ID + "=?", channelId); + } + break; + case MATCH_PREVIEW_PROGRAM_ID: + params.appendWhere(PreviewPrograms._ID + "=?", uri.getLastPathSegment()); + // fall-through + case MATCH_PREVIEW_PROGRAM: + params.setTables(PREVIEW_PROGRAMS_TABLE); + paramChannelId = uri.getQueryParameter(TvContractCompat.PARAM_CHANNEL); + if (paramChannelId != null) { + String channelId = String.valueOf(Long.parseLong(paramChannelId)); + params.appendWhere(PreviewPrograms.COLUMN_CHANNEL_ID + "=?", channelId); + } + break; + case MATCH_WATCH_NEXT_PROGRAM_ID: + params.appendWhere(WatchNextPrograms._ID + "=?", uri.getLastPathSegment()); + // fall-through + case MATCH_WATCH_NEXT_PROGRAM: + params.setTables(WATCH_NEXT_PROGRAMS_TABLE); + break; + case MATCH_CHANNEL_ID_LOGO: + if (operation.equals(OP_DELETE)) { + params.setTables(CHANNELS_TABLE); + params.appendWhere(Channels._ID + "=?", uri.getPathSegments().get(1)); + break; + } + // fall-through + case MATCH_PASSTHROUGH_ID: + throw new UnsupportedOperationException(operation + " not permmitted on " + uri); + default: + throw new IllegalArgumentException("Unknown URI " + uri); + } + return params; + } + + private static String capitalize(String str) { + return Character.toUpperCase(str.charAt(0)) + str.substring(1); + } + + @SuppressLint("DefaultLocale") + private void checkAndConvertGenre(ContentValues values) { + String canonicalGenres = values.getAsString(Programs.COLUMN_CANONICAL_GENRE); + + if (!TextUtils.isEmpty(canonicalGenres)) { + // Check if the canonical genres are valid. If not, clear them. + String[] genres = Genres.decode(canonicalGenres); + for (String genre : genres) { + if (!Genres.isCanonical(genre)) { + values.putNull(Programs.COLUMN_CANONICAL_GENRE); + canonicalGenres = null; + break; + } + } + } + + if (TextUtils.isEmpty(canonicalGenres)) { + // If the canonical genre is not set, try to map the broadcast genre to the canonical + // genre. + String broadcastGenres = values.getAsString(Programs.COLUMN_BROADCAST_GENRE); + if (!TextUtils.isEmpty(broadcastGenres)) { + Set<String> genreSet = new HashSet<>(); + String[] genres = Genres.decode(broadcastGenres); + for (String genre : genres) { + String canonicalGenre = sGenreMap.get(genre.toUpperCase()); + if (Genres.isCanonical(canonicalGenre)) { + genreSet.add(canonicalGenre); + } + } + if (genreSet.size() > 0) { + values.put( + Programs.COLUMN_CANONICAL_GENRE, + Genres.encode(genreSet.toArray(new String[genreSet.size()]))); + } + } + } + } + + private void checkAndConvertDeprecatedColumns(ContentValues values) { + if (values.containsKey(Programs.COLUMN_SEASON_NUMBER)) { + if (!values.containsKey(Programs.COLUMN_SEASON_DISPLAY_NUMBER)) { + values.put( + Programs.COLUMN_SEASON_DISPLAY_NUMBER, + values.getAsInteger(Programs.COLUMN_SEASON_NUMBER)); + } + values.remove(Programs.COLUMN_SEASON_NUMBER); + } + if (values.containsKey(Programs.COLUMN_EPISODE_NUMBER)) { + if (!values.containsKey(Programs.COLUMN_EPISODE_DISPLAY_NUMBER)) { + values.put( + Programs.COLUMN_EPISODE_DISPLAY_NUMBER, + values.getAsInteger(Programs.COLUMN_EPISODE_NUMBER)); + } + values.remove(Programs.COLUMN_EPISODE_NUMBER); + } + } + + // We might have more than one thread trying to make its way through applyBatch() so the + // notification coalescing needs to be thread-local to work correctly. + private final ThreadLocal<Set<Uri>> mTLBatchNotifications = new ThreadLocal<>(); + + private Set<Uri> getBatchNotificationsSet() { + return mTLBatchNotifications.get(); + } + + private void setBatchNotificationsSet(Set<Uri> batchNotifications) { + mTLBatchNotifications.set(batchNotifications); + } + + @Override + public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) + throws OperationApplicationException { + setBatchNotificationsSet(new HashSet<Uri>()); + Context context = getContext(); + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + db.beginTransaction(); + try { + ContentProviderResult[] results = super.applyBatch(operations); + db.setTransactionSuccessful(); + return results; + } finally { + db.endTransaction(); + final Set<Uri> notifications = getBatchNotificationsSet(); + setBatchNotificationsSet(null); + for (final Uri uri : notifications) { + context.getContentResolver().notifyChange(uri, null); + } + } + } + + @Override + public int bulkInsert(Uri uri, ContentValues[] values) { + setBatchNotificationsSet(new HashSet<Uri>()); + Context context = getContext(); + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + db.beginTransaction(); + try { + int result = super.bulkInsert(uri, values); + db.setTransactionSuccessful(); + return result; + } finally { + db.endTransaction(); + final Set<Uri> notifications = getBatchNotificationsSet(); + setBatchNotificationsSet(null); + for (final Uri notificationUri : notifications) { + context.getContentResolver().notifyChange(notificationUri, null); + } + } + } + + private void notifyChange(Uri uri) { + final Set<Uri> batchNotifications = getBatchNotificationsSet(); + if (batchNotifications != null) { + batchNotifications.add(uri); + } else { + getContext().getContentResolver().notifyChange(uri, null); + } + } + + private boolean callerHasReadTvListingsPermission() { + return getContext().checkCallingOrSelfPermission(PERMISSION_READ_TV_LISTINGS) + == PackageManager.PERMISSION_GRANTED; + } + + private boolean callerHasAccessAllEpgDataPermission() { + return getContext().checkCallingOrSelfPermission(PERMISSION_ACCESS_ALL_EPG_DATA) + == PackageManager.PERMISSION_GRANTED; + } + + private boolean callerHasAccessWatchedProgramsPermission() { + return getContext().checkCallingOrSelfPermission(PERMISSION_ACCESS_WATCHED_PROGRAMS) + == PackageManager.PERMISSION_GRANTED; + } + + private boolean callerHasModifyParentalControlsPermission() { + return getContext() + .checkCallingOrSelfPermission( + android.Manifest.permission.MODIFY_PARENTAL_CONTROLS) + == PackageManager.PERMISSION_GRANTED; + } + + private void blockIllegalAccessToIdAndPackageName(Uri uri, ContentValues values) { + if (values.containsKey(BaseColumns._ID)) { + int match = sUriMatcher.match(uri); + switch (match) { + case MATCH_CHANNEL_ID: + case MATCH_PROGRAM_ID: + case MATCH_PREVIEW_PROGRAM_ID: + case MATCH_RECORDED_PROGRAM_ID: + case MATCH_WATCH_NEXT_PROGRAM_ID: + case MATCH_WATCHED_PROGRAM_ID: + if (TextUtils.equals( + values.getAsString(BaseColumns._ID), uri.getLastPathSegment())) { + break; + } + // fall through + default: + throw new IllegalArgumentException("Not allowed to change ID."); + } + } + if (values.containsKey(BaseTvColumns.COLUMN_PACKAGE_NAME) + && !callerHasAccessAllEpgDataPermission() + && !TextUtils.equals( + values.getAsString(BaseTvColumns.COLUMN_PACKAGE_NAME), + getCallingPackage_())) { + throw new SecurityException("Not allowed to change package name."); + } + } + + private void blockIllegalAccessToChannelsSystemColumns(ContentValues values) { + if (values.containsKey(Channels.COLUMN_LOCKED) + && !callerHasModifyParentalControlsPermission()) { + throw new SecurityException("Not allowed to access Channels.COLUMN_LOCKED"); + } + Boolean hasAccessAllEpgDataPermission = null; + if (values.containsKey(Channels.COLUMN_BROWSABLE)) { + hasAccessAllEpgDataPermission = callerHasAccessAllEpgDataPermission(); + if (!hasAccessAllEpgDataPermission) { + throw new SecurityException("Not allowed to access Channels.COLUMN_BROWSABLE"); + } + } + } + + private void blockIllegalAccessToPreviewProgramsSystemColumns(ContentValues values) { + if (values.containsKey(PreviewPrograms.COLUMN_BROWSABLE) + && !callerHasAccessAllEpgDataPermission()) { + throw new SecurityException("Not allowed to access Programs.COLUMN_BROWSABLE"); + } + } + + private void blockIllegalAccessFromBlockedPackage() { + String callingPackageName = getCallingPackage_(); + if (sBlockedPackages.containsKey(callingPackageName)) { + throw new SecurityException( + "Not allowed to access " + + TvContractCompat.AUTHORITY + + ", " + + callingPackageName + + " is blocked"); + } + } + + private boolean disallowModifyChannelType(ContentValues values, SqlParams params) { + if (values.containsKey(Channels.COLUMN_TYPE)) { + params.appendWhere( + Channels.COLUMN_TYPE + "=?", values.getAsString(Channels.COLUMN_TYPE)); + return true; + } + return false; + } + + private boolean disallowModifyChannelId(ContentValues values, SqlParams params) { + if (values.containsKey(PreviewPrograms.COLUMN_CHANNEL_ID)) { + params.appendWhere( + PreviewPrograms.COLUMN_CHANNEL_ID + "=?", + values.getAsString(PreviewPrograms.COLUMN_CHANNEL_ID)); + return true; + } + return false; + } + + @Override + public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { + switch (sUriMatcher.match(uri)) { + case MATCH_CHANNEL_ID_LOGO: + return openLogoFile(uri, mode); + default: + throw new FileNotFoundException(uri.toString()); + } + } + + private ParcelFileDescriptor openLogoFile(Uri uri, String mode) throws FileNotFoundException { + long channelId = Long.parseLong(uri.getPathSegments().get(1)); + + SqlParams params = + new SqlParams(CHANNELS_TABLE, Channels._ID + "=?", String.valueOf(channelId)); + if (!callerHasAccessAllEpgDataPermission()) { + if (callerHasReadTvListingsPermission()) { + params.appendWhere( + Channels.COLUMN_PACKAGE_NAME + "=? OR " + Channels.COLUMN_SEARCHABLE + "=?", + getCallingPackage_(), + "1"); + } else { + params.appendWhere(Channels.COLUMN_PACKAGE_NAME + "=?", getCallingPackage_()); + } + } + + SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder(); + queryBuilder.setTables(params.getTables()); + + // We don't write the database here. + SQLiteDatabase db = mOpenHelper.getReadableDatabase(); + if (mode.equals("r")) { + String sql = + queryBuilder.buildQuery( + new String[] {CHANNELS_COLUMN_LOGO}, + params.getSelection(), + null, + null, + null, + null); + ParcelFileDescriptor fd = + DatabaseUtils.blobFileDescriptorForQuery(db, sql, params.getSelectionArgs()); + if (fd == null) { + throw new FileNotFoundException(uri.toString()); + } + return fd; + } else { + try (Cursor cursor = + queryBuilder.query( + db, + new String[] {Channels._ID}, + params.getSelection(), + params.getSelectionArgs(), + null, + null, + null)) { + if (cursor.getCount() < 1) { + // Fails early if corresponding channel does not exist. + // PipeMonitor may still fail to update DB later. + throw new FileNotFoundException(uri.toString()); + } + } + + try { + ParcelFileDescriptor[] pipeFds = ParcelFileDescriptor.createPipe(); + PipeMonitor pipeMonitor = new PipeMonitor(pipeFds[0], channelId, params); + pipeMonitor.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + return pipeFds[1]; + } catch (IOException ioe) { + FileNotFoundException fne = new FileNotFoundException(uri.toString()); + fne.initCause(ioe); + throw fne; + } + } + } + + /** + * Validates the sort order based on the given field set. + * + * @throws IllegalArgumentException if there is any unknown field. + */ + @SuppressLint("DefaultLocale") + private static void validateSortOrder(String sortOrder, Set<String> possibleFields) { + if (TextUtils.isEmpty(sortOrder) || possibleFields.isEmpty()) { + return; + } + String[] orders = sortOrder.split(","); + for (String order : orders) { + String field = + order.replaceAll("\\s+", " ") + .trim() + .toLowerCase() + .replace(" asc", "") + .replace(" desc", ""); + if (!possibleFields.contains(field)) { + throw new IllegalArgumentException("Illegal field in sort order " + order); + } + } + } + + private class PipeMonitor extends AsyncTask<Void, Void, Void> { + private final ParcelFileDescriptor mPfd; + private final long mChannelId; + private final SqlParams mParams; + + private PipeMonitor(ParcelFileDescriptor pfd, long channelId, SqlParams params) { + mPfd = pfd; + mChannelId = channelId; + mParams = params; + } + + @Override + protected Void doInBackground(Void... params) { + int count = 0; + try (AutoCloseInputStream is = new AutoCloseInputStream(mPfd); + ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + Bitmap bitmap = BitmapFactory.decodeStream(is); + if (bitmap == null) { + Log.e(TAG, "Failed to decode logo image for channel ID " + mChannelId); + return null; + } + + float scaleFactor = + Math.min( + 1f, + ((float) MAX_LOGO_IMAGE_SIZE) + / Math.max(bitmap.getWidth(), bitmap.getHeight())); + if (scaleFactor < 1f) { + bitmap = + Bitmap.createScaledBitmap( + bitmap, + (int) (bitmap.getWidth() * scaleFactor), + (int) (bitmap.getHeight() * scaleFactor), + false); + } + bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos); + byte[] bytes = baos.toByteArray(); + + ContentValues values = new ContentValues(); + values.put(CHANNELS_COLUMN_LOGO, bytes); + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + count = + db.update( + mParams.getTables(), + values, + mParams.getSelection(), + mParams.getSelectionArgs()); + if (count > 0) { + Uri uri = TvContractCompat.buildChannelLogoUri(mChannelId); + notifyChange(uri); + } + } catch (IOException e) { + Log.e(TAG, "Failed to write logo for channel ID " + mChannelId, e); + + } finally { + if (count == 0) { + try { + mPfd.closeWithError("Failed to write logo for channel ID " + mChannelId); + } catch (IOException ioe) { + Log.e(TAG, "Failed to close pipe", ioe); + } + } + } + return null; + } + } + + /** + * Column definitions for the TV programs that the user watched. Applications do not have access + * to this table. + * + * <p> + * + * <p>By default, the query results will be sorted by {@link + * WatchedPrograms#COLUMN_WATCH_START_TIME_UTC_MILLIS} in descending order. + * + * @hide + */ + public static final class WatchedPrograms implements BaseTvColumns { + + /** The content:// style URI for this table. */ + public static final Uri CONTENT_URI = + Uri.parse("content://" + TvContract.AUTHORITY + "/watched_program"); + + /** The MIME type of a directory of watched programs. */ + public static final String CONTENT_TYPE = "vnd.android.cursor.dir/watched_program"; + + /** The MIME type of a single item in this table. */ + public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watched_program"; + + /** + * The UTC time that the user started watching this TV program, in milliseconds since the + * epoch. + * + * <p> + * + * <p>Type: INTEGER (long) + */ + public static final String COLUMN_WATCH_START_TIME_UTC_MILLIS = + "watch_start_time_utc_millis"; + + /** + * The UTC time that the user stopped watching this TV program, in milliseconds since the + * epoch. + * + * <p> + * + * <p>Type: INTEGER (long) + */ + public static final String COLUMN_WATCH_END_TIME_UTC_MILLIS = "watch_end_time_utc_millis"; + + /** + * The ID of the TV channel that provides this TV program. + * + * <p> + * + * <p>This is a required field. + * + * <p> + * + * <p>Type: INTEGER (long) + */ + public static final String COLUMN_CHANNEL_ID = "channel_id"; + + /** + * The title of this TV program. + * + * <p> + * + * <p>Type: TEXT + */ + public static final String COLUMN_TITLE = "title"; + + /** + * The start time of this TV program, in milliseconds since the epoch. + * + * <p> + * + * <p>Type: INTEGER (long) + */ + public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis"; + + /** + * The end time of this TV program, in milliseconds since the epoch. + * + * <p> + * + * <p>Type: INTEGER (long) + */ + public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis"; + + /** + * The description of this TV program. + * + * <p> + * + * <p>Type: TEXT + */ + public static final String COLUMN_DESCRIPTION = "description"; + + /** + * Extra parameters given to {@link TvInputService.Session#tune(Uri, android.os.Bundle) + * TvInputService.Session.tune(Uri, android.os.Bundle)} when tuning to the channel that + * provides this TV program. (Used internally.) + * + * <p> + * + * <p>This column contains an encoded string that represents comma-separated key-value pairs + * of the tune parameters. (Ex. "[key1]=[value1], [key2]=[value2]"). '%' is used as an + * escape character for '%', '=', and ','. + * + * <p> + * + * <p>Type: TEXT + */ + public static final String COLUMN_INTERNAL_TUNE_PARAMS = "tune_params"; + + /** + * The session token of this TV program. (Used internally.) + * + * <p> + * + * <p>This contains a String representation of {@link IBinder} for {@link + * TvInputService.Session} that provides the current TV program. It is used internally to + * distinguish watched programs entries from different TV input sessions. + * + * <p> + * + * <p>Type: TEXT + */ + public static final String COLUMN_INTERNAL_SESSION_TOKEN = "session_token"; + + private WatchedPrograms() {} + } +} diff --git a/tests/common/src/com/android/tv/testing/SingletonProvider.java b/tests/common/src/com/android/tv/testing/SingletonProvider.java new file mode 100644 index 00000000..d9c2d409 --- /dev/null +++ b/tests/common/src/com/android/tv/testing/SingletonProvider.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2017 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.testing; + +import javax.inject.Provider; + +/** A Provider that always returns the same instance. */ +public class SingletonProvider<T> implements Provider<T> { + private final T t; + + private SingletonProvider(T t) { + this.t = t; + } + + @Override + public T get() { + return t; + } + + public static <S, T extends S> Provider<S> create(T t) { + return new SingletonProvider<S>(t); + } +} diff --git a/tests/common/src/com/android/tv/testing/TestSingletonApp.java b/tests/common/src/com/android/tv/testing/TestSingletonApp.java new file mode 100644 index 00000000..f55ed8d4 --- /dev/null +++ b/tests/common/src/com/android/tv/testing/TestSingletonApp.java @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2017 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.testing; + +import android.app.Application; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.media.tv.TvInputManager; +import android.os.AsyncTask; +import com.android.tv.InputSessionManager; +import com.android.tv.MainActivityWrapper; +import com.android.tv.TvSingletons; +import com.android.tv.analytics.Analytics; +import com.android.tv.analytics.Tracker; +import com.android.tv.common.BaseApplication; +import com.android.tv.common.config.api.RemoteConfig; +import com.android.tv.common.experiments.ExperimentLoader; +import com.android.tv.common.recording.RecordingStorageStatusManager; +import com.android.tv.common.util.Clock; +import com.android.tv.data.ChannelDataManager; +import com.android.tv.data.PreviewDataManager; +import com.android.tv.data.ProgramDataManager; +import com.android.tv.data.epg.EpgFetcher; +import com.android.tv.data.epg.EpgReader; +import com.android.tv.dvr.DvrDataManager; +import com.android.tv.dvr.DvrManager; +import com.android.tv.dvr.DvrScheduleManager; +import com.android.tv.dvr.DvrWatchedPositionManager; +import com.android.tv.dvr.recorder.RecordingScheduler; +import com.android.tv.perf.PerformanceMonitor; +import com.android.tv.perf.StubPerformanceMonitor; +import com.android.tv.testing.dvr.DvrDataManagerInMemoryImpl; +import com.android.tv.testing.testdata.TestData; +import com.android.tv.tuner.TunerInputController; +import com.android.tv.util.SetupUtils; +import com.android.tv.util.TvInputManagerHelper; +import com.android.tv.util.account.AccountHelper; +import java.util.concurrent.Executor; +import javax.inject.Provider; + +/** Test application for Live TV. */ +public class TestSingletonApp extends Application implements TvSingletons { + public final FakeClock fakeClock = FakeClock.createWithCurrentTime(); + public final FakeEpgReader epgReader = new FakeEpgReader(fakeClock); + public final FakeRemoteConfig remoteConfig = new FakeRemoteConfig(); + public final FakeEpgFetcher epgFetcher = new FakeEpgFetcher(); + + public FakeTvInputManagerHelper tvInputManagerHelper; + public SetupUtils setupUtils; + public DvrManager dvrManager; + public DvrDataManager mDvrDataManager; + + private final Provider<EpgReader> mEpgReaderProvider = SingletonProvider.create(epgReader); + private TunerInputController mTunerInputController; + private PerformanceMonitor mPerformanceMonitor; + private ChannelDataManager mChannelDataManager; + + @Override + public void onCreate() { + super.onCreate(); + mTunerInputController = + new TunerInputController( + ComponentName.unflattenFromString(getEmbeddedTunerInputId())); + + tvInputManagerHelper = new FakeTvInputManagerHelper(this); + setupUtils = SetupUtils.createForTvSingletons(this); + tvInputManagerHelper.start(); + mChannelDataManager = new ChannelDataManager(this, tvInputManagerHelper); + mChannelDataManager.start(); + mDvrDataManager = new DvrDataManagerInMemoryImpl(this, fakeClock); + // HACK reset the singleton for tests + BaseApplication.sSingletons = this; + } + + public void loadTestData(TestData testData, long durationMs) { + tvInputManagerHelper + .getFakeTvInputManager() + .add(testData.getTvInputInfo(), TvInputManager.INPUT_STATE_CONNECTED); + testData.init(this, fakeClock, durationMs); + } + + @Override + public Analytics getAnalytics() { + return null; + } + + @Override + public void handleInputCountChanged() {} + + @Override + public ChannelDataManager getChannelDataManager() { + return mChannelDataManager; + } + + @Override + public boolean isChannelDataManagerLoadFinished() { + return false; + } + + @Override + public ProgramDataManager getProgramDataManager() { + return null; + } + + @Override + public boolean isProgramDataManagerCurrentProgramsLoadFinished() { + return false; + } + + @Override + public PreviewDataManager getPreviewDataManager() { + return null; + } + + @Override + public DvrDataManager getDvrDataManager() { + return mDvrDataManager; + } + + @Override + public DvrScheduleManager getDvrScheduleManager() { + return null; + } + + @Override + public DvrManager getDvrManager() { + return dvrManager; + } + + @Override + public RecordingScheduler getRecordingScheduler() { + return null; + } + + @Override + public DvrWatchedPositionManager getDvrWatchedPositionManager() { + return null; + } + + @Override + public InputSessionManager getInputSessionManager() { + return null; + } + + @Override + public Tracker getTracker() { + return null; + } + + @Override + public TvInputManagerHelper getTvInputManagerHelper() { + return tvInputManagerHelper; + } + + @Override + public Provider<EpgReader> providesEpgReader() { + return mEpgReaderProvider; + } + + @Override + public EpgFetcher getEpgFetcher() { + return epgFetcher; + } + + @Override + public SetupUtils getSetupUtils() { + return setupUtils; + } + + @Override + public TunerInputController getTunerInputController() { + return mTunerInputController; + } + + @Override + public ExperimentLoader getExperimentLoader() { + return new ExperimentLoader(); + } + + @Override + public MainActivityWrapper getMainActivityWrapper() { + return null; + } + + @Override + public AccountHelper getAccountHelper() { + return null; + } + + @Override + public Clock getClock() { + return fakeClock; + } + + @Override + public RecordingStorageStatusManager getRecordingStorageStatusManager() { + return null; + } + + @Override + public RemoteConfig getRemoteConfig() { + return remoteConfig; + } + + @Override + public Intent getTunerSetupIntent(Context context) { + return null; + } + + @Override + public boolean isRunningInMainProcess() { + return false; + } + + @Override + public PerformanceMonitor getPerformanceMonitor() { + if (mPerformanceMonitor == null) { + mPerformanceMonitor = new StubPerformanceMonitor(); + } + return mPerformanceMonitor; + } + + @Override + public String getEmbeddedTunerInputId() { + return "com.android.tv/.tuner.tvinput.TunerTvInputService"; + } + + @Override + public Executor getDbExecutor() { + return AsyncTask.SERIAL_EXECUTOR; + } +} diff --git a/tests/unit/src/com/android/tv/BaseMainActivityTestCase.java b/tests/common/src/com/android/tv/testing/activities/BaseMainActivityTestCase.java index e6f1af7e..666f8181 100644 --- a/tests/unit/src/com/android/tv/BaseMainActivityTestCase.java +++ b/tests/common/src/com/android/tv/testing/activities/BaseMainActivityTestCase.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.tv; +package com.android.tv.testing.activities; import static android.support.test.InstrumentationRegistry.getInstrumentation; @@ -21,23 +21,19 @@ import android.content.Context; import android.os.SystemClock; import android.support.test.rule.ActivityTestRule; import android.text.TextUtils; - -import com.android.tv.data.Channel; +import com.android.tv.MainActivity; import com.android.tv.data.ChannelDataManager; -import com.android.tv.testing.ChannelInfo; +import com.android.tv.data.api.Channel; +import com.android.tv.testing.data.ChannelInfo; import com.android.tv.testing.testinput.ChannelStateData; import com.android.tv.testing.testinput.TestInputControlConnection; import com.android.tv.testing.testinput.TestInputControlUtils; import com.android.tv.testing.testinput.TvTestInputConstants; - +import java.util.List; import org.junit.Before; import org.junit.Rule; -import java.util.List; - -/** - * Base TestCase for tests that need a {@link MainActivity}. - */ +/** Base TestCase for tests that need a {@link MainActivity}. */ public abstract class BaseMainActivityTestCase { private static final String TAG = "BaseMainActivityTest"; private static final int CHANNEL_LOADING_CHECK_INTERVAL_MS = 10; @@ -54,8 +50,11 @@ public abstract class BaseMainActivityTestCase { public void setUp() { mActivity = mActivityTestRule.getActivity(); // TODO: ensure the SampleInputs are setup. - getInstrumentation().getTargetContext() - .bindService(TestInputControlUtils.createIntent(), mConnection, + getInstrumentation() + .getTargetContext() + .bindService( + TestInputControlUtils.createIntent(), + mConnection, Context.BIND_AUTO_CREATE); } @@ -73,17 +72,17 @@ public abstract class BaseMainActivityTestCase { */ protected void tuneToChannel(final Channel channel) { // Run on UI thread so views can be modified - getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - mActivity.tuneToChannel(channel); - } - }); + getInstrumentation() + .runOnMainSync( + new Runnable() { + @Override + public void run() { + mActivity.tuneToChannel(channel); + } + }); } - /** - * Sleep until @{@link ChannelDataManager#isDbLoadFinished()} is true. - */ + /** Sleep until @{@link ChannelDataManager#isDbLoadFinished()} is true. */ protected void waitUntilChannelLoadingFinish() { ChannelDataManager channelDataManager = mActivity.getChannelDataManager(); while (!channelDataManager.isDbLoadFinished()) { @@ -102,9 +101,7 @@ public abstract class BaseMainActivityTestCase { tuneToChannel(c); } - /** - * Tune to channel. - */ + /** Tune to channel. */ protected void tuneToChannel(ChannelInfo channel) { tuneToChannel(channel.name); } @@ -112,13 +109,14 @@ public abstract class BaseMainActivityTestCase { /** * Update the channel state to {@code data} then tune to that channel. * - * @param data the state to update the channel with. + * @param data the state to update the channel with. * @param channel the channel to tune to */ protected void updateThenTune(ChannelStateData data, ChannelInfo channel) { if (channel.equals(TvTestInputConstants.CH_1_DEFAULT_DONT_MODIFY)) { throw new IllegalArgumentException( - "By convention " + TvTestInputConstants.CH_1_DEFAULT_DONT_MODIFY.name + "By convention " + + TvTestInputConstants.CH_1_DEFAULT_DONT_MODIFY.name + " should not be modified."); } mConnection.updateChannelState(channel, data); @@ -128,7 +126,7 @@ public abstract class BaseMainActivityTestCase { private Channel findChannelWithName(String displayName) { waitUntilChannelLoadingFinish(); Channel channel = null; - List <Channel> channelList = mActivity.getChannelDataManager().getChannelList(); + List<Channel> channelList = mActivity.getChannelDataManager().getChannelList(); for (Channel c : channelList) { if (TextUtils.equals(c.getDisplayName(), displayName)) { channel = c; diff --git a/tests/common/src/com/android/tv/testing/constants/ConfigConstants.java b/tests/common/src/com/android/tv/testing/constants/ConfigConstants.java new file mode 100644 index 00000000..890c51e0 --- /dev/null +++ b/tests/common/src/com/android/tv/testing/constants/ConfigConstants.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2017 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.testing.constants; + +import android.os.Build; + +/** Constants for Robolectic Config. */ +public final class ConfigConstants { + + public static final String MANIFEST = "vendor/unbundled_google/packages/TV/AndroidManifest.xml"; + public static final int SDK = Build.VERSION_CODES.M; + + private ConfigConstants() {} +} diff --git a/tests/common/src/com/android/tv/testing/constants/Constants.java b/tests/common/src/com/android/tv/testing/constants/Constants.java new file mode 100644 index 00000000..09e1ada1 --- /dev/null +++ b/tests/common/src/com/android/tv/testing/constants/Constants.java @@ -0,0 +1,47 @@ +/* + * 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.testing.constants; + +import android.media.tv.TvTrackInfo; + +/** Constants for testing. */ +public final class Constants { + public static final int FUNC_TEST_CHANNEL_COUNT = 100; + public static final int UNIT_TEST_CHANNEL_COUNT = 4; + public static final int JANK_TEST_CHANNEL_COUNT = 500; // TODO: increase to 1000 see b/23526997 + + public static final TvTrackInfo EN_STEREO_AUDIO_TRACK = + new TvTrackInfo.Builder(TvTrackInfo.TYPE_AUDIO, "English Stereo Audio") + .setLanguage("en") + .setAudioChannelCount(2) + .build(); + public static final TvTrackInfo GENERIC_AUDIO_TRACK = + new TvTrackInfo.Builder(TvTrackInfo.TYPE_AUDIO, "Generic Audio").build(); + + public static final TvTrackInfo FHD1080P50_VIDEO_TRACK = + new TvTrackInfo.Builder(TvTrackInfo.TYPE_VIDEO, "FHD Video") + .setVideoHeight(1080) + .setVideoWidth(1920) + .setVideoFrameRate(50) + .build(); + public static final TvTrackInfo SVGA_VIDEO_TRACK = + new TvTrackInfo.Builder(TvTrackInfo.TYPE_VIDEO, "SVGA Video") + .setVideoHeight(600) + .setVideoWidth(800) + .build(); + + private Constants() {} +} diff --git a/tests/common/src/com/android/tv/testing/TvContentRatingConstants.java b/tests/common/src/com/android/tv/testing/constants/TvContentRatingConstants.java index c4c96fed..e1a3d906 100644 --- a/tests/common/src/com/android/tv/testing/TvContentRatingConstants.java +++ b/tests/common/src/com/android/tv/testing/constants/TvContentRatingConstants.java @@ -14,20 +14,21 @@ * limitations under the License. */ -package com.android.tv.testing; +package com.android.tv.testing.constants; import android.media.tv.TvContentRating; -/** - * Constants for the content rating strings. - */ +/** Constants for the content rating strings. */ public final class TvContentRatingConstants { /** * A content rating object. * * <p>Domain: com.android.tv + * * <p>Rating system: US_TV + * * <p>Rating: US_TV_Y7 + * * <p>Sub ratings: US_TV_FV */ public static final TvContentRating CONTENT_RATING_US_TV_Y7_US_TV_FV = @@ -39,7 +40,9 @@ public final class TvContentRatingConstants { * A content rating object. * * <p>Domain: com.android.tv + * * <p>Rating system: US_TV + * * <p>Rating: US_TV_MA */ public static final TvContentRating CONTENT_RATING_US_TV_MA = @@ -51,11 +54,14 @@ public final class TvContentRatingConstants { * A content rating object. * * <p>Domain: com.android.tv + * * <p>Rating system: US_TV + * * <p>Rating: US_TV_PG + * * <p>Sub ratings: US_TV_L, US_TV_S */ public static final TvContentRating CONTENT_RATING_US_TV_PG_US_TV_L_US_TV_S = - TvContentRating.createRating("com.android.tv", "US_TV", "US_TV_PG", "US_TV_L", - "US_TV_S"); + TvContentRating.createRating( + "com.android.tv", "US_TV", "US_TV_PG", "US_TV_L", "US_TV_S"); } diff --git a/tests/common/src/com/android/tv/testing/ChannelInfo.java b/tests/common/src/com/android/tv/testing/data/ChannelInfo.java index 946c0b55..e39c057d 100644 --- a/tests/common/src/com/android/tv/testing/ChannelInfo.java +++ b/tests/common/src/com/android/tv/testing/data/ChannelInfo.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.tv.testing; +package com.android.tv.testing.data; import android.content.ContentResolver; import android.content.Context; @@ -23,14 +23,12 @@ import android.media.tv.TvContract; import android.net.Uri; import android.support.annotation.Nullable; import android.util.SparseArray; - import java.util.Objects; -/** - * Channel Information. - */ +/** Channel Information. */ public final class ChannelInfo { private static final SparseArray<String> VIDEO_HEIGHT_TO_FORMAT_MAP = new SparseArray<>(); + static { VIDEO_HEIGHT_TO_FORMAT_MAP.put(480, TvContract.Channels.VIDEO_FORMAT_480P); VIDEO_HEIGHT_TO_FORMAT_MAP.put(576, TvContract.Channels.VIDEO_FORMAT_576P); @@ -41,9 +39,9 @@ public final class ChannelInfo { } public static final String[] PROJECTION = { - TvContract.Channels.COLUMN_DISPLAY_NUMBER, - TvContract.Channels.COLUMN_DISPLAY_NAME, - TvContract.Channels.COLUMN_ORIGINAL_NETWORK_ID, + TvContract.Channels.COLUMN_DISPLAY_NUMBER, + TvContract.Channels.COLUMN_DISPLAY_NAME, + TvContract.Channels.COLUMN_ORIGINAL_NETWORK_ID, }; public final String number; @@ -67,14 +65,15 @@ public final class ChannelInfo { * Create a channel info for TVTestInput. * * @param context a context to insert logo. It can be null if logo isn't needed. - * @param channelNumber a channel number to be use as an identifier. - * {@link #originalNetworkId} will be assigned the same value, too. + * @param channelNumber a channel number to be use as an identifier. {@link #originalNetworkId} + * will be assigned the same value, too. */ public static ChannelInfo create(@Nullable Context context, int channelNumber) { - Builder builder = new Builder() - .setNumber(String.valueOf(channelNumber)) - .setName("Channel " + channelNumber) - .setOriginalNetworkId(channelNumber); + Builder builder = + new Builder() + .setNumber(String.valueOf(channelNumber)) + .setName("Channel " + channelNumber) + .setOriginalNetworkId(channelNumber); if (context != null) { // tests/input/tools/get_test_logos.sh only stores 1000 logos. builder.setLogoUrl(getUriStringForChannelLogo(context, channelNumber)); @@ -88,7 +87,9 @@ public final class ChannelInfo { .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE) .authority(context.getPackageName()) .path("drawable") - .appendPath("ch_" + index + "_logo").build().toString(); + .appendPath("ch_" + index + "_logo") + .build() + .toString(); } public static ChannelInfo fromCursor(Cursor c) { @@ -109,10 +110,22 @@ public final class ChannelInfo { return builder.build(); } - private ChannelInfo(String number, String name, String logoUrl, int originalNetworkId, - int videoWidth, int videoHeight, float videoPixelAspectRatio, int audioChannel, - int audioLanguageCount, boolean hasClosedCaption, ProgramInfo program, - String appLinkText, int appLinkColor, String appLinkIconUri, String appLinkPosterArtUri, + private ChannelInfo( + String number, + String name, + String logoUrl, + int originalNetworkId, + int videoWidth, + int videoHeight, + float videoPixelAspectRatio, + int audioChannel, + int audioLanguageCount, + boolean hasClosedCaption, + ProgramInfo program, + String appLinkText, + int appLinkColor, + String appLinkIconUri, + String appLinkPosterArtUri, String appLinkIntentUri) { this.number = number; this.name = name; @@ -139,20 +152,35 @@ public final class ChannelInfo { @Override public String toString() { return "Channel{" - + "number=" + number - + ", name=" + name - + ", logoUri=" + logoUrl - + ", originalNetworkId=" + originalNetworkId - + ", videoWidth=" + videoWidth - + ", videoHeight=" + videoHeight - + ", audioChannel=" + audioChannel - + ", audioLanguageCount=" + audioLanguageCount - + ", hasClosedCaption=" + hasClosedCaption - + ", appLinkText=" + appLinkText - + ", appLinkColor=" + appLinkColor - + ", appLinkIconUri=" + appLinkIconUri - + ", appLinkPosterArtUri=" + appLinkPosterArtUri - + ", appLinkIntentUri=" + appLinkIntentUri + "}"; + + "number=" + + number + + ", name=" + + name + + ", logoUri=" + + logoUrl + + ", originalNetworkId=" + + originalNetworkId + + ", videoWidth=" + + videoWidth + + ", videoHeight=" + + videoHeight + + ", audioChannel=" + + audioChannel + + ", audioLanguageCount=" + + audioLanguageCount + + ", hasClosedCaption=" + + hasClosedCaption + + ", appLinkText=" + + appLinkText + + ", appLinkColor=" + + appLinkColor + + ", appLinkIconUri=" + + appLinkIconUri + + ", appLinkPosterArtUri=" + + appLinkPosterArtUri + + ", appLinkIntentUri=" + + appLinkIntentUri + + "}"; } @Override @@ -164,21 +192,21 @@ public final class ChannelInfo { return false; } ChannelInfo that = (ChannelInfo) o; - return Objects.equals(originalNetworkId, that.originalNetworkId) && - Objects.equals(videoWidth, that.videoWidth) && - Objects.equals(videoHeight, that.videoHeight) && - Objects.equals(audioChannel, that.audioChannel) && - Objects.equals(audioLanguageCount, that.audioLanguageCount) && - Objects.equals(hasClosedCaption, that.hasClosedCaption) && - Objects.equals(appLinkColor, that.appLinkColor) && - Objects.equals(number, that.number) && - Objects.equals(name, that.name) && - Objects.equals(logoUrl, that.logoUrl) && - Objects.equals(program, that.program) && - Objects.equals(appLinkText, that.appLinkText) && - Objects.equals(appLinkIconUri, that.appLinkIconUri) && - Objects.equals(appLinkPosterArtUri, that.appLinkPosterArtUri) && - Objects.equals(appLinkIntentUri, that.appLinkIntentUri); + return Objects.equals(originalNetworkId, that.originalNetworkId) + && Objects.equals(videoWidth, that.videoWidth) + && Objects.equals(videoHeight, that.videoHeight) + && Objects.equals(audioChannel, that.audioChannel) + && Objects.equals(audioLanguageCount, that.audioLanguageCount) + && Objects.equals(hasClosedCaption, that.hasClosedCaption) + && Objects.equals(appLinkColor, that.appLinkColor) + && Objects.equals(number, that.number) + && Objects.equals(name, that.name) + && Objects.equals(logoUrl, that.logoUrl) + && Objects.equals(program, that.program) + && Objects.equals(appLinkText, that.appLinkText) + && Objects.equals(appLinkIconUri, that.appLinkIconUri) + && Objects.equals(appLinkPosterArtUri, that.appLinkPosterArtUri) + && Objects.equals(appLinkIntentUri, that.appLinkIntentUri); } @Override @@ -186,17 +214,15 @@ public final class ChannelInfo { return Objects.hash(number, name, originalNetworkId); } - /** - * Builder class for {@code ChannelInfo}. - */ + /** Builder class for {@code ChannelInfo}. */ public static class Builder { private String mNumber; private String mName; private String mLogoUrl = null; private int mOriginalNetworkId; - private int mVideoWidth = 1920; // Width for HD video. - private int mVideoHeight = 1080; // Height for HD video. - private float mVideoPixelAspectRatio = 1.0f; //default value + private int mVideoWidth = 1920; // Width for HD video. + private int mVideoHeight = 1080; // Height for HD video. + private float mVideoPixelAspectRatio = 1.0f; // default value private int mAudioChannel; private int mAudioLanguageCount; private boolean mHasClosedCaption; @@ -207,8 +233,7 @@ public final class ChannelInfo { private String mAppLinkPosterArtUri; private String mAppLinkIntentUri; - public Builder() { - } + public Builder() {} public Builder(ChannelInfo other) { mNumber = other.number; @@ -305,11 +330,23 @@ public final class ChannelInfo { } public ChannelInfo build() { - return new ChannelInfo(mNumber, mName, mLogoUrl, mOriginalNetworkId, - mVideoWidth, mVideoHeight, mVideoPixelAspectRatio, mAudioChannel, - mAudioLanguageCount, mHasClosedCaption, mProgram, mAppLinkText, mAppLinkColor, - mAppLinkIconUri, mAppLinkPosterArtUri, mAppLinkIntentUri); - + return new ChannelInfo( + mNumber, + mName, + mLogoUrl, + mOriginalNetworkId, + mVideoWidth, + mVideoHeight, + mVideoPixelAspectRatio, + mAudioChannel, + mAudioLanguageCount, + mHasClosedCaption, + mProgram, + mAppLinkText, + mAppLinkColor, + mAppLinkIconUri, + mAppLinkPosterArtUri, + mAppLinkIntentUri); } } } diff --git a/tests/common/src/com/android/tv/testing/ChannelUtils.java b/tests/common/src/com/android/tv/testing/data/ChannelUtils.java index bfb766d6..920c7087 100644 --- a/tests/common/src/com/android/tv/testing/ChannelUtils.java +++ b/tests/common/src/com/android/tv/testing/data/ChannelUtils.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.tv.testing; +package com.android.tv.testing.data; import android.content.ContentResolver; import android.content.ContentValues; @@ -27,24 +27,22 @@ import android.support.annotation.WorkerThread; import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; - import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -/** - * Static helper methods for working with {@link android.media.tv.TvContract}. - */ +/** Static helper methods for working with {@link android.media.tv.TvContract}. */ public class ChannelUtils { private static final String TAG = "ChannelUtils"; private static final boolean DEBUG = false; /** - * Query and return the map of (channel_id, ChannelInfo). - * See: {@link ChannelInfo#fromCursor(Cursor)}. + * Query and return the map of (channel_id, ChannelInfo). See: {@link + * com.android.tv.testing.data.ChannelInfo#fromCursor(Cursor)}. */ @WorkerThread public static Map<Long, ChannelInfo> queryChannelInfoMapForTvInput( @@ -55,8 +53,8 @@ public class ChannelUtils { String[] projections = new String[ChannelInfo.PROJECTION.length + 1]; projections[0] = Channels._ID; System.arraycopy(ChannelInfo.PROJECTION, 0, projections, 1, ChannelInfo.PROJECTION.length); - try (Cursor cursor = context.getContentResolver() - .query(uri, projections, null, null, null)) { + try (Cursor cursor = + context.getContentResolver().query(uri, projections, null, null, null)) { if (cursor != null) { while (cursor.moveToNext()) { map.put(cursor.getLong(0), ChannelInfo.fromCursor(cursor)); @@ -113,10 +111,14 @@ public class ChannelUtils { Long rowId = existingChannelsMap.get(channel.originalNetworkId); Uri uri; if (rowId == null) { - if (DEBUG) Log.d(TAG, "Inserting "+ channel); + if (DEBUG) { + Log.d(TAG, "Inserting " + channel); + } uri = resolver.insert(TvContract.Channels.CONTENT_URI, values); } else { - if (DEBUG) Log.d(TAG, "Updating "+ channel); + if (DEBUG) { + Log.d(TAG, "Updating " + channel); + } uri = TvContract.buildChannelUri(rowId); resolver.update(uri, values, null, null); existingChannelsMap.remove(channel.originalNetworkId); @@ -149,6 +151,14 @@ public class ChannelUtils { // Prevent instantiation. } + public static List<ChannelInfo> createChannelInfos(Context context, int channelCount) { + List<ChannelInfo> channels = new ArrayList<>(); + for (int i = 1; i <= channelCount; i++) { + channels.add(ChannelInfo.create(context, i)); + } + return channels; + } + public static class InsertLogosTask extends AsyncTask<Map<Uri, String>, Void, Void> { private final Context mContext; diff --git a/tests/common/src/com/android/tv/testing/ProgramInfo.java b/tests/common/src/com/android/tv/testing/data/ProgramInfo.java index b1aaea6b..6d801425 100644 --- a/tests/common/src/com/android/tv/testing/ProgramInfo.java +++ b/tests/common/src/com/android/tv/testing/data/ProgramInfo.java @@ -14,80 +14,83 @@ * limitations under the License. */ -package com.android.tv.testing; +package com.android.tv.testing.data; import android.content.Context; import android.database.Cursor; import android.media.tv.TvContentRating; import android.media.tv.TvContract; - +import com.android.tv.testing.R; +import com.android.tv.testing.utils.Utils; +import java.util.Arrays; import java.util.Objects; import java.util.concurrent.TimeUnit; public final class ProgramInfo { - /** - * If this is specify for title, it will be generated by adding index. - */ + /** If this is specify for title, it will be generated by adding index. */ public static final String GEN_TITLE = ""; /** - * If this is specify for episode title, it will be generated by adding index. - * Also, season and episode numbers would be generated, too. - * see: {@link #build} for detail. + * If this is specify for episode title, it will be generated by adding index. Also, season and + * episode numbers would be generated, too. see: {@link #build} for detail. */ public static final String GEN_EPISODE = ""; + private static final int SEASON_MAX = 10; private static final int EPISODE_MAX = 12; /** - * If this is specify for poster art, - * it will be selected one of {@link #POSTER_ARTS_RES} in order. + * If this is specify for poster art, it will be selected one of {@link #POSTER_ARTS_RES} in + * order. */ public static final String GEN_POSTER = "GEN"; + private static final int[] POSTER_ARTS_RES = { - 0, - R.drawable.blue, - R.drawable.red_large, - R.drawable.green, - R.drawable.red, - R.drawable.green_large, - R.drawable.blue_small}; + 0, + R.drawable.blue, + R.drawable.red_large, + R.drawable.green, + R.drawable.red, + R.drawable.green_large, + R.drawable.blue_small + }; /** - * If this is specified for duration, - * it will be selected one of {@link #DURATIONS_MS} in order. + * If this is specified for duration, it will be selected one of {@link #DURATIONS_MS} in order. */ public static final int GEN_DURATION = -1; + private static final long[] DURATIONS_MS = { - TimeUnit.MINUTES.toMillis(15), - TimeUnit.MINUTES.toMillis(45), - TimeUnit.MINUTES.toMillis(90), - TimeUnit.MINUTES.toMillis(60), - TimeUnit.MINUTES.toMillis(30), - TimeUnit.MINUTES.toMillis(45), - TimeUnit.MINUTES.toMillis(60), - TimeUnit.MINUTES.toMillis(90), - TimeUnit.HOURS.toMillis(5)}; - private static long DURATIONS_SUM_MS; + TimeUnit.MINUTES.toMillis(15), + TimeUnit.MINUTES.toMillis(45), + TimeUnit.MINUTES.toMillis(90), + TimeUnit.MINUTES.toMillis(60), + TimeUnit.MINUTES.toMillis(30), + TimeUnit.MINUTES.toMillis(45), + TimeUnit.MINUTES.toMillis(60), + TimeUnit.MINUTES.toMillis(90), + TimeUnit.HOURS.toMillis(5) + }; + private static long durationsSumMs; + static { - DURATIONS_SUM_MS = 0; + durationsSumMs = 0; for (long duration : DURATIONS_MS) { - DURATIONS_SUM_MS += duration; + durationsSumMs += duration; } } - /** - * If this is specified for genre, - * it will be selected one of {@link #GENRES} in order. - */ + /** If this is specified for genre, it will be selected one of {@link #GENRES} in order. */ public static final String GEN_GENRE = "GEN"; + private static final String[] GENRES = { - "", - TvContract.Programs.Genres.SPORTS, - TvContract.Programs.Genres.NEWS, - TvContract.Programs.Genres.SHOPPING, - TvContract.Programs.Genres.DRAMA, - TvContract.Programs.Genres.ENTERTAINMENT}; + "", + TvContract.Programs.Genres.SPORTS, + TvContract.Programs.Genres.NEWS, + TvContract.Programs.Genres.SHOPPING, + TvContract.Programs.Genres.DRAMA, + TvContract.Programs.Genres.ENTERTAINMENT + }; public final String title; public final String episode; @@ -118,9 +121,17 @@ public final class ProgramInfo { return builder.build(); } - public ProgramInfo(String title, String episode, int seasonNumber, int episodeNumber, - String posterArtUri, String description, long durationMs, - TvContentRating[] contentRatings, String genre, String resourceUri) { + public ProgramInfo( + String title, + String episode, + int seasonNumber, + int episodeNumber, + String posterArtUri, + String description, + long durationMs, + TvContentRating[] contentRatings, + String genre, + String resourceUri) { this.title = title; this.episode = episode; this.seasonNumber = seasonNumber; @@ -141,8 +152,9 @@ public final class ProgramInfo { } /** - * Get index of the program whose start time equals or less than {@code timeMs} and - * end time more than {@code timeMs}. + * Get index of the program whose start time equals or less than {@code timeMs} and end time + * more than {@code timeMs}. + * * @param timeMs target time in millis to find a program. * @param channelId used to add complexity to the index between two consequence channels. */ @@ -151,8 +163,8 @@ public final class ProgramInfo { return Math.max((int) (timeMs / durationMs), 0); } long startTimeMs = channelId * DURATIONS_MS[((int) (channelId % DURATIONS_MS.length))]; - int index = (int) ((timeMs - startTimeMs) / DURATIONS_SUM_MS) * DURATIONS_MS.length; - startTimeMs += (index / DURATIONS_MS.length) * DURATIONS_SUM_MS; + int index = (int) ((timeMs - startTimeMs) / durationsSumMs) * DURATIONS_MS.length; + startTimeMs += (index / DURATIONS_MS.length) * durationsSumMs; while (startTimeMs + DURATIONS_MS[index % DURATIONS_MS.length] < timeMs) { startTimeMs += DURATIONS_MS[index % DURATIONS_MS.length]; index++; @@ -162,14 +174,16 @@ public final class ProgramInfo { /** * Returns the start time for the program with the position. + * * @param index index returned by {@link #getIndex} */ public long getStartTimeMs(int index, long channelId) { if (durationMs != GEN_DURATION) { return index * durationMs; } - long startTimeMs = channelId * DURATIONS_MS[((int) (channelId % DURATIONS_MS.length))] - + (index / DURATIONS_MS.length) * DURATIONS_SUM_MS; + long startTimeMs = + channelId * DURATIONS_MS[((int) (channelId % DURATIONS_MS.length))] + + (index / DURATIONS_MS.length) * durationsSumMs; for (int i = 0; i < index % DURATIONS_MS.length; i++) { startTimeMs += DURATIONS_MS[i]; } @@ -177,9 +191,9 @@ public final class ProgramInfo { } /** - * Return complete {@link ProgramInfo} with the generated value. - * See: {@link #GEN_TITLE}, {@link #GEN_EPISODE}, {@link #GEN_POSTER}, {@link #GEN_DURATION}, - * {@link #GEN_GENRE}. + * Return complete {@link ProgramInfo} with the generated value. See: {@link #GEN_TITLE}, {@link + * #GEN_EPISODE}, {@link #GEN_POSTER}, {@link #GEN_DURATION}, {@link #GEN_GENRE}. + * * @param index index returned by {@link #getIndex} */ public ProgramInfo build(Context context, int index) { @@ -196,8 +210,8 @@ public final class ProgramInfo { episode != null ? (index % SEASON_MAX + 1) : seasonNumber, episode != null ? (index % EPISODE_MAX + 1) : episodeNumber, GEN_POSTER.equals(posterArtUri) - ? Utils.getUriStringForResource(context, - POSTER_ARTS_RES[index % POSTER_ARTS_RES.length]) + ? Utils.getUriStringForResource( + context, POSTER_ARTS_RES[index % POSTER_ARTS_RES.length]) : posterArtUri, description, durationMs == GEN_DURATION ? DURATIONS_MS[index % DURATIONS_MS.length] : durationMs, @@ -208,9 +222,13 @@ public final class ProgramInfo { @Override public String toString() { - return "ProgramInfo{title=" + title - + ", episode=" + episode - + ", durationMs=" + durationMs + "}"; + return "ProgramInfo{title=" + + title + + ", episode=" + + episode + + ", durationMs=" + + durationMs + + "}"; } @Override @@ -222,16 +240,16 @@ public final class ProgramInfo { return false; } ProgramInfo that = (ProgramInfo) o; - return Objects.equals(seasonNumber, that.seasonNumber) && - Objects.equals(episodeNumber, that.episodeNumber) && - Objects.equals(durationMs, that.durationMs) && - Objects.equals(title, that.title) && - Objects.equals(episode, that.episode) && - Objects.equals(posterArtUri, that.posterArtUri) && - Objects.equals(description, that.description) && - Objects.equals(genre, that.genre) && - Objects.equals(contentRatings, that.contentRatings) && - Objects.equals(resourceUri, that.resourceUri); + return Objects.equals(seasonNumber, that.seasonNumber) + && Objects.equals(episodeNumber, that.episodeNumber) + && Objects.equals(durationMs, that.durationMs) + && Objects.equals(title, that.title) + && Objects.equals(episode, that.episode) + && Objects.equals(posterArtUri, that.posterArtUri) + && Objects.equals(description, that.description) + && Objects.equals(genre, that.genre) + && Arrays.equals(contentRatings, that.contentRatings) + && Objects.equals(resourceUri, that.resourceUri); } @Override @@ -302,8 +320,17 @@ public final class ProgramInfo { } public ProgramInfo build() { - return new ProgramInfo(mTitle, mEpisode, mSeasonNumber, mEpisodeNumber, mPosterArtUri, - mDescription, mDurationMs, mContentRatings, mGenre, mResourceUri); + return new ProgramInfo( + mTitle, + mEpisode, + mSeasonNumber, + mEpisodeNumber, + mPosterArtUri, + mDescription, + mDurationMs, + mContentRatings, + mGenre, + mResourceUri); } } } diff --git a/tests/common/src/com/android/tv/testing/ProgramUtils.java b/tests/common/src/com/android/tv/testing/data/ProgramUtils.java index 08c6a033..21647719 100644 --- a/tests/common/src/com/android/tv/testing/ProgramUtils.java +++ b/tests/common/src/com/android/tv/testing/data/ProgramUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.tv.testing; +package com.android.tv.testing.data; import android.content.ContentUris; import android.content.ContentValues; @@ -25,36 +25,57 @@ import android.media.tv.TvContract; import android.media.tv.TvContract.Programs; import android.net.Uri; import android.util.Log; - import com.android.tv.common.TvContentRatingCache; - +import com.android.tv.common.util.Clock; import java.util.ArrayList; +import java.util.Map; import java.util.concurrent.TimeUnit; -public class ProgramUtils { +/** Static utilities for using Programs in tests */ +public final class ProgramUtils { private static final String TAG = "ProgramUtils"; private static final boolean DEBUG = false; - // Populate program data for a week. - private static final long PROGRAM_INSERT_DURATION_MS = TimeUnit.DAYS.toMillis(7); + /** Populate program data for a week */ + public static final long PROGRAM_INSERT_DURATION_MS = TimeUnit.DAYS.toMillis(7); + private static final int MAX_DB_INSERT_COUNT_AT_ONCE = 500; /** - * Populate programs by repeating given program information. - * This method will populate programs without any gap nor overlapping - * starting from the current time. + * Populate programs by repeating given program information. This method will populate programs + * without any gap nor overlapping starting from the current time. */ - public static void populatePrograms(Context context, Uri channelUri, ProgramInfo program) { + public static void populatePrograms( + Context context, Uri channelUri, ProgramInfo program, Clock clock) { + populatePrograms(context, channelUri, program, clock, PROGRAM_INSERT_DURATION_MS); + } + + public static void populatePrograms( + Context context, + Uri channelUri, + ProgramInfo program, + Clock clock, + long programInsertDurationMs) { + long currentTimeMs = clock.currentTimeMillis(); + long targetEndTimeMs = currentTimeMs + programInsertDurationMs; + populatePrograms(context, channelUri, program, currentTimeMs, targetEndTimeMs); + } + + public static void populatePrograms( + Context context, + Uri channelUri, + ProgramInfo program, + long currentTimeMs, + long targetEndTimeMs) { ContentValues values = new ContentValues(); long channelId = ContentUris.parseId(channelUri); values.put(Programs.COLUMN_CHANNEL_ID, channelId); values.put(Programs.COLUMN_SHORT_DESCRIPTION, program.description); - values.put(Programs.COLUMN_CONTENT_RATING, + values.put( + Programs.COLUMN_CONTENT_RATING, TvContentRatingCache.contentRatingsToString(program.contentRatings)); - long currentTimeMs = System.currentTimeMillis(); - long targetEndTimeMs = currentTimeMs + PROGRAM_INSERT_DURATION_MS; long timeMs = getLastProgramEndTimeMs(context, channelUri, currentTimeMs, targetEndTimeMs); if (timeMs <= 0) { timeMs = currentTimeMs; @@ -81,11 +102,12 @@ public class ProgramUtils { list.add(new ContentValues(values)); timeMs += programAt.durationMs; - if (list.size() >= MAX_DB_INSERT_COUNT_AT_ONCE - || timeMs >= targetEndTimeMs) { + if (list.size() >= MAX_DB_INSERT_COUNT_AT_ONCE || timeMs >= targetEndTimeMs) { try { - context.getContentResolver().bulkInsert(Programs.CONTENT_URI, - list.toArray(new ContentValues[list.size()])); + context.getContentResolver() + .bulkInsert( + Programs.CONTENT_URI, + list.toArray(new ContentValues[list.size()])); } catch (SQLiteException e) { Log.e(TAG, "Can't insert EPG.", e); return; @@ -110,4 +132,16 @@ public class ProgramUtils { } private ProgramUtils() {} + + public static void updateProgramForAllChannelsOf( + Context context, String inputId, Clock clock, long durationMs) { + // Reload channels so we have the ids. + Map<Long, ChannelInfo> channelIdToInfoMap = + ChannelUtils.queryChannelInfoMapForTvInput(context, inputId); + for (Long channelId : channelIdToInfoMap.keySet()) { + ProgramInfo programInfo = ProgramInfo.create(); + populatePrograms( + context, TvContract.buildChannelUri(channelId), programInfo, clock, durationMs); + } + } } diff --git a/tests/unit/src/com/android/tv/dvr/DvrDataManagerInMemoryImpl.java b/tests/common/src/com/android/tv/testing/dvr/DvrDataManagerInMemoryImpl.java index 0a7ab46c..b8a055c7 100644 --- a/tests/unit/src/com/android/tv/dvr/DvrDataManagerInMemoryImpl.java +++ b/tests/common/src/com/android/tv/testing/dvr/DvrDataManagerInMemoryImpl.java @@ -14,24 +14,22 @@ * limitations under the License */ -package com.android.tv.dvr; +package com.android.tv.testing.dvr; import android.content.Context; -import android.os.Build; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.test.filters.SdkSuppress; import android.text.TextUtils; import android.util.Log; import android.util.Range; - import com.android.tv.common.SoftPreconditions; +import com.android.tv.common.util.Clock; +import com.android.tv.dvr.BaseDvrDataManager; +import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.data.RecordedProgram; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.data.ScheduledRecording.RecordingState; import com.android.tv.dvr.data.SeriesRecording; -import com.android.tv.util.Clock; - import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -40,9 +38,8 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicLong; /** A DVR Data manager that stores values in memory suitable for testing. */ -@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N) public final class DvrDataManagerInMemoryImpl extends BaseDvrDataManager { - private final static String TAG = "DvrDataManagerInMemory"; + private static final String TAG = "DvrDataManagerInMemory"; private final AtomicLong mNextId = new AtomicLong(1); private final Map<Long, ScheduledRecording> mScheduledRecordings = new HashMap<>(); private final Map<Long, RecordedProgram> mRecordedPrograms = new HashMap<>(); @@ -81,6 +78,7 @@ public final class DvrDataManagerInMemoryImpl extends BaseDvrDataManager { return new ArrayList<>(mScheduledRecordings.values()); } + @Override public List<SeriesRecording> getSeriesRecordings() { return new ArrayList<>(mSeriesRecordings.values()); } @@ -99,7 +97,7 @@ public final class DvrDataManagerInMemoryImpl extends BaseDvrDataManager { @Override public long getNextScheduledStartTimeAfter(long startTime) { - List<ScheduledRecording> temp = getNonStartedScheduledRecordings(); + List<ScheduledRecording> temp = getNonStartedScheduledRecordings(); Collections.sort(temp, ScheduledRecording.START_TIME_COMPARATOR); for (ScheduledRecording r : temp) { if (r.getStartTimeMs() > startTime) { @@ -110,8 +108,8 @@ public final class DvrDataManagerInMemoryImpl extends BaseDvrDataManager { } @Override - public List<ScheduledRecording> getScheduledRecordings(Range<Long> period, - @RecordingState int state) { + public List<ScheduledRecording> getScheduledRecordings( + Range<Long> period, @RecordingState int state) { List<ScheduledRecording> temp = getScheduledRecordingsPrograms(); List<ScheduledRecording> result = new ArrayList<>(); for (ScheduledRecording r : temp) { @@ -144,19 +142,20 @@ public final class DvrDataManagerInMemoryImpl extends BaseDvrDataManager { return result; } - /** - * Add a new scheduled recording. - */ + /** Add a new scheduled recording. */ @Override public void addScheduledRecording(ScheduledRecording... scheduledRecordings) { + addScheduledRecording(false, scheduledRecordings); + } + + public void addScheduledRecording(boolean keepIds, ScheduledRecording... scheduledRecordings) { for (ScheduledRecording r : scheduledRecordings) { - addScheduledRecordingInternal(r); + addScheduledRecordingInternal(r, keepIds); } } - public void addRecordedProgram(RecordedProgram recordedProgram) { - addRecordedProgramInternal(recordedProgram); + addRecordedProgramInternal(recordedProgram, false); } public void updateRecordedProgram(RecordedProgram r) { @@ -174,26 +173,43 @@ public final class DvrDataManagerInMemoryImpl extends BaseDvrDataManager { notifyRecordedProgramsRemoved(scheduledRecording); } - public ScheduledRecording addScheduledRecordingInternal(ScheduledRecording scheduledRecording) { - SoftPreconditions - .checkState(scheduledRecording.getId() == ScheduledRecording.ID_NOT_SET, TAG, - "expected id of " + ScheduledRecording.ID_NOT_SET + " but was " - + scheduledRecording); - scheduledRecording = ScheduledRecording.buildFrom(scheduledRecording) - .setId(mNextId.incrementAndGet()) - .build(); + return addScheduledRecordingInternal(scheduledRecording, false); + } + + public ScheduledRecording addScheduledRecordingInternal( + ScheduledRecording scheduledRecording, boolean keepId) { + if (!keepId) { + SoftPreconditions.checkState( + scheduledRecording.getId() == ScheduledRecording.ID_NOT_SET, + TAG, + "expected id of " + + ScheduledRecording.ID_NOT_SET + + " but was " + + scheduledRecording); + scheduledRecording = + ScheduledRecording.buildFrom(scheduledRecording) + .setId(mNextId.incrementAndGet()) + .build(); + } mScheduledRecordings.put(scheduledRecording.getId(), scheduledRecording); notifyScheduledRecordingAdded(scheduledRecording); return scheduledRecording; } - public RecordedProgram addRecordedProgramInternal(RecordedProgram recordedProgram) { - SoftPreconditions.checkState(recordedProgram.getId() == RecordedProgram.ID_NOT_SET, TAG, - "expected id of " + RecordedProgram.ID_NOT_SET + " but was " + recordedProgram); - recordedProgram = RecordedProgram.buildFrom(recordedProgram) - .setId(mNextId.incrementAndGet()) - .build(); + public RecordedProgram addRecordedProgramInternal( + RecordedProgram recordedProgram, boolean keepId) { + if (!keepId) { + SoftPreconditions.checkState( + recordedProgram.getId() == RecordedProgram.ID_NOT_SET, + TAG, + "expected id of " + RecordedProgram.ID_NOT_SET + " but was " + recordedProgram); + recordedProgram = + RecordedProgram + .buildFrom(recordedProgram) + .setId(mNextId.incrementAndGet()) + .build(); + } mRecordedPrograms.put(recordedProgram.getId(), recordedProgram); notifyRecordedProgramsAdded(recordedProgram); return recordedProgram; @@ -265,7 +281,7 @@ public final class DvrDataManagerInMemoryImpl extends BaseDvrDataManager { public ScheduledRecording getScheduledRecordingForProgramId(long programId) { for (ScheduledRecording r : mScheduledRecordings.values()) { if (r.getProgramId() == programId) { - return r; + return r; } } return null; diff --git a/tests/common/src/com/android/tv/testing/dvr/RecordingTestUtils.java b/tests/common/src/com/android/tv/testing/dvr/RecordingTestUtils.java index a9bfa97a..72bac8fc 100644 --- a/tests/common/src/com/android/tv/testing/dvr/RecordingTestUtils.java +++ b/tests/common/src/com/android/tv/testing/dvr/RecordingTestUtils.java @@ -17,40 +17,37 @@ package com.android.tv.testing.dvr; import com.android.tv.dvr.data.ScheduledRecording; - import junit.framework.Assert; -/** - * Static utils for using {@link ScheduledRecording} in tests. - */ +/** Static utils for using {@link ScheduledRecording} in tests. */ public final class RecordingTestUtils { private static final String INPUT_ID = "input_id"; private static final int CHANNEL_ID = 273; - public static ScheduledRecording createTestRecordingWithIdAndPeriod(long id, String inputId, - long channelId, long startTime, long endTime) { + public static ScheduledRecording createTestRecordingWithIdAndPeriod( + long id, String inputId, long channelId, long startTime, long endTime) { return ScheduledRecording.builder(inputId, channelId, startTime, endTime) .setId(id) .setChannelId(channelId) .build(); } - public static ScheduledRecording createTestRecordingWithPeriod(String inputId, - long channelId, long startTime, long endTime) { - return createTestRecordingWithIdAndPeriod(ScheduledRecording.ID_NOT_SET, inputId, channelId, - startTime, endTime); + public static ScheduledRecording createTestRecordingWithPeriod( + String inputId, long channelId, long startTime, long endTime) { + return createTestRecordingWithIdAndPeriod( + ScheduledRecording.ID_NOT_SET, inputId, channelId, startTime, endTime); } - public static ScheduledRecording createTestRecordingWithPriorityAndPeriod(long channelId, - long priority, long startTime, long endTime) { + public static ScheduledRecording createTestRecordingWithPriorityAndPeriod( + long channelId, long priority, long startTime, long endTime) { return ScheduledRecording.builder(INPUT_ID, CHANNEL_ID, startTime, endTime) .setChannelId(channelId) .setPriority(priority) .build(); } - public static ScheduledRecording createTestRecordingWithIdAndPriorityAndPeriod(long id, - long channelId, long priority, long startTime, long endTime) { + public static ScheduledRecording createTestRecordingWithIdAndPriorityAndPeriod( + long id, long channelId, long priority, long startTime, long endTime) { return ScheduledRecording.builder(INPUT_ID, CHANNEL_ID, startTime, endTime) .setId(id) .setChannelId(channelId) @@ -58,11 +55,12 @@ public final class RecordingTestUtils { .build(); } - public static ScheduledRecording normalizePriority(ScheduledRecording orig){ + public static ScheduledRecording normalizePriority(ScheduledRecording orig) { return ScheduledRecording.buildFrom(orig).setPriority(orig.getId()).build(); } - public static void assertRecordingEquals(ScheduledRecording expected, ScheduledRecording actual) { + public static void assertRecordingEquals( + ScheduledRecording expected, ScheduledRecording actual) { Assert.assertEquals("id", expected.getId(), actual.getId()); Assert.assertEquals("channel", expected.getChannelId(), actual.getChannelId()); Assert.assertEquals("programId", expected.getProgramId(), actual.getProgramId()); @@ -70,9 +68,11 @@ public final class RecordingTestUtils { Assert.assertEquals("start time", expected.getStartTimeMs(), actual.getStartTimeMs()); Assert.assertEquals("end time", expected.getEndTimeMs(), actual.getEndTimeMs()); Assert.assertEquals("state", expected.getState(), actual.getState()); - Assert.assertEquals("parent series recording", expected.getSeriesRecordingId(), + Assert.assertEquals( + "parent series recording", + expected.getSeriesRecordingId(), actual.getSeriesRecordingId()); } - private RecordingTestUtils() { } + private RecordingTestUtils() {} } diff --git a/tests/common/src/com/android/tv/testing/robo/ContentProviders.java b/tests/common/src/com/android/tv/testing/robo/ContentProviders.java new file mode 100644 index 00000000..aaaa11df --- /dev/null +++ b/tests/common/src/com/android/tv/testing/robo/ContentProviders.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 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.testing.robo; + +import android.content.ContentProvider; +import android.content.pm.ProviderInfo; +import org.robolectric.Robolectric; +import org.robolectric.android.controller.ContentProviderController; +import org.robolectric.shadows.ShadowContentResolver; + +/** Static utilities for using content providers in tests. */ +public final class ContentProviders { + + /** Builds creates and register a ContentProvider with the given authority. */ + public static <T extends ContentProvider> T register(Class<T> providerClass, String authority) { + ProviderInfo info = new ProviderInfo(); + info.authority = authority; + ContentProviderController<T> contentProviderController = + Robolectric.buildContentProvider(providerClass); + T provider = contentProviderController.create(info).get(); + provider.onCreate(); + ShadowContentResolver.registerProviderInternal(authority, provider); + return provider; + } + + private ContentProviders() {} +} diff --git a/tests/common/src/com/android/tv/testing/robo/RobotTestAppHelper.java b/tests/common/src/com/android/tv/testing/robo/RobotTestAppHelper.java new file mode 100644 index 00000000..9eb79298 --- /dev/null +++ b/tests/common/src/com/android/tv/testing/robo/RobotTestAppHelper.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2018 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.testing.robo; + +import android.media.tv.TvContract; +import com.android.tv.testing.FakeTvProvider; +import com.android.tv.testing.TestSingletonApp; +import com.android.tv.testing.testdata.TestData; +import java.util.concurrent.TimeUnit; +import org.robolectric.Robolectric; + +/** Static utilities for using {@link TestSingletonApp} in roboletric tests. */ +public final class RobotTestAppHelper { + + public static void loadTestData(TestSingletonApp app, TestData testData) { + ContentProviders.register(FakeTvProvider.class, TvContract.AUTHORITY); + app.loadTestData(testData, TimeUnit.DAYS.toMillis(1)); + Robolectric.flushBackgroundThreadScheduler(); + Robolectric.flushForegroundThreadScheduler(); + } + + private RobotTestAppHelper() {} +} diff --git a/tests/common/src/com/android/tv/testing/shadows/ShadowMediaSession.java b/tests/common/src/com/android/tv/testing/shadows/ShadowMediaSession.java new file mode 100644 index 00000000..5a2c41e6 --- /dev/null +++ b/tests/common/src/com/android/tv/testing/shadows/ShadowMediaSession.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2017 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.testing.shadows; + +import android.app.PendingIntent; +import android.content.Context; +import android.media.MediaMetadata; +import android.media.session.MediaSession; +import android.media.session.PlaybackState; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +/** Shadow {@link MediaSession}. */ +@Implements(MediaSession.class) +public class ShadowMediaSession { + + public MediaSession.Callback mCallback; + public PendingIntent mMediaButtonReceiver; + public PendingIntent mSessionActivity; + public PlaybackState mPlaybackState; + public MediaMetadata mMediaMetadata; + public int mFlags; + public boolean mActive; + public boolean mReleased; + + /** Stand-in for the MediaSession constructor with the same parameters. */ + public void __constructor__(Context context, String tag, int userID) { + // This empty method prevents the real MediaSession constructor from being called. + } + + @Implementation + public void setCallback(MediaSession.Callback callback) { + mCallback = callback; + } + + @Implementation + public void setMediaButtonReceiver(PendingIntent mbr) { + mMediaButtonReceiver = mbr; + } + + @Implementation + public void setSessionActivity(PendingIntent activity) { + mSessionActivity = activity; + } + + @Implementation + public void setPlaybackState(PlaybackState state) { + mPlaybackState = state; + } + + @Implementation + public void setMetadata(MediaMetadata metadata) { + mMediaMetadata = metadata; + } + + @Implementation + public void setFlags(int flags) { + mFlags = flags; + } + + @Implementation + public boolean isActive() { + return mActive; + } + + @Implementation + public void setActive(boolean active) { + mActive = active; + } + + @Implementation + public void release() { + mReleased = true; + } +} diff --git a/tests/common/src/com/android/tv/testing/testdata/TestData.java b/tests/common/src/com/android/tv/testing/testdata/TestData.java new file mode 100644 index 00000000..e7e52348 --- /dev/null +++ b/tests/common/src/com/android/tv/testing/testdata/TestData.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2018 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.testing.testdata; + +import android.content.Context; +import android.media.tv.TvInputInfo; +import com.android.tv.common.util.Clock; +import com.android.tv.testing.data.ChannelInfo; +import com.android.tv.testing.data.ChannelUtils; +import com.android.tv.testing.data.ProgramUtils; +import com.android.tv.testing.utils.TestUtils; +import java.util.List; + +/** + * A set of test data. + * + * <p>contains: + * + * <ul> + * <li>InputID + * <li>Channel List + * </ul> + * + * Call {@link #init(Context)}, to update the TvProvider data base with the given values. + */ +public abstract class TestData { + private List<ChannelInfo> channelList; + + protected abstract List<ChannelInfo> createChannels(Context context); + + public void init(Context context, Clock clock, long durationMs) { + channelList = createChannels(context); + ChannelUtils.updateChannels(context, getInputId(), channelList); + ProgramUtils.updateProgramForAllChannelsOf(context, getInputId(), clock, durationMs); + } + + public abstract TvInputInfo getTvInputInfo(); + + public final String getInputId() { + return getTvInputInfo().getId(); + } + + public static final TestData DEFAULT_10_CHANNELS = + new TestData() { + private TvInputInfo mTvInputInfo = createTvInputInfo(); + + private TvInputInfo createTvInputInfo() { + try { + return TestUtils.createTvInputInfo( + TestUtils.createResolveInfo( + "com.android.tv.testing.testdata", + "com.android.tv.testing.testdata.Default10Channels"), + "com.android.tv.testing.testdata/.Default10Channels", + null, + TvInputInfo.TYPE_TUNER, + true); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected List<ChannelInfo> createChannels(Context context) { + return ChannelUtils.createChannelInfos(context, 10); + } + + @Override + public TvInputInfo getTvInputInfo() { + return mTvInputInfo; + } + }; +} diff --git a/tests/common/src/com/android/tv/testing/testinput/ChannelState.java b/tests/common/src/com/android/tv/testing/testinput/ChannelState.java index 1b8f63cd..3e8bab33 100644 --- a/tests/common/src/com/android/tv/testing/testinput/ChannelState.java +++ b/tests/common/src/com/android/tv/testing/testinput/ChannelState.java @@ -16,24 +16,16 @@ package com.android.tv.testing.testinput; import android.media.tv.TvTrackInfo; - -import com.android.tv.testing.Constants; - +import com.android.tv.testing.constants.Constants; import java.util.Collections; import java.util.List; -/** - * Versioned state information for a channel. - */ +/** Versioned state information for a channel. */ public class ChannelState { - /** - * The video track a channel has by default. - */ + /** The video track a channel has by default. */ public static final TvTrackInfo DEFAULT_VIDEO_TRACK = Constants.FHD1080P50_VIDEO_TRACK; - /** - * The video track a channel has by default. - */ + /** The video track a channel has by default. */ public static final TvTrackInfo DEFAULT_AUDIO_TRACK = Constants.EN_STEREO_AUDIO_TRACK; /** * The channel is "tuned" and video available. @@ -47,27 +39,23 @@ public class ChannelState { * Default ChannelState with version @{value #CHANNEL_VERSION_DEFAULT} and default {@link * ChannelStateData}. */ - public static final ChannelState DEFAULT = new ChannelState(CHANNEL_VERSION_DEFAULT, - new ChannelStateData()); + public static final ChannelState DEFAULT = + new ChannelState(CHANNEL_VERSION_DEFAULT, new ChannelStateData()); + private final int mVersion; private final ChannelStateData mData; - private ChannelState(int version, ChannelStateData channelStateData) { mVersion = version; mData = channelStateData; } - /** - * Returns the id of the selected audio track, or null if none is selected. - */ + /** Returns the id of the selected audio track, or null if none is selected. */ public String getSelectedAudioTrackId() { return mData.mSelectedAudioTrackId; } - /** - * Returns the id of the selected audio track, or null if none is selected. - */ + /** Returns the id of the selected audio track, or null if none is selected. */ public String getSelectedVideoTrackId() { return mData.mSelectedVideoTrackId; } @@ -82,9 +70,8 @@ public class ChannelState { } /** - * Tune status is either {@link #TUNE_STATUS_VIDEO_AVAILABLE} or a {@link - * android.media.tv.TvInputService.Session#notifyVideoUnavailable(int) video unavailable - * reason} + * Tune status is either {@link #TUNE_STATUS_VIDEO_AVAILABLE} or a {@link + * android.media.tv.TvInputService.Session#notifyVideoUnavailable(int) video unavailable reason} */ public int getTuneStatus() { return mData.mTuneStatus; diff --git a/tests/common/src/com/android/tv/testing/testinput/ChannelStateData.java b/tests/common/src/com/android/tv/testing/testinput/ChannelStateData.java index 9bac9d12..cdeb1f5c 100644 --- a/tests/common/src/com/android/tv/testing/testinput/ChannelStateData.java +++ b/tests/common/src/com/android/tv/testing/testinput/ChannelStateData.java @@ -19,25 +19,23 @@ package com.android.tv.testing.testinput; import android.media.tv.TvTrackInfo; import android.os.Parcel; import android.os.Parcelable; - import java.util.ArrayList; import java.util.List; -/** - * Mutable unversioned channel state. - */ +/** Mutable unversioned channel state. */ public final class ChannelStateData implements Parcelable { - public static final Creator<ChannelStateData> CREATOR = new Creator<ChannelStateData>() { - @Override - public ChannelStateData createFromParcel(Parcel in) { - return new ChannelStateData(in); - } + public static final Creator<ChannelStateData> CREATOR = + new Creator<ChannelStateData>() { + @Override + public ChannelStateData createFromParcel(Parcel in) { + return new ChannelStateData(in); + } - @Override - public ChannelStateData[] newArray(int size) { - return new ChannelStateData[size]; - } - }; + @Override + public ChannelStateData[] newArray(int size) { + return new ChannelStateData[size]; + } + }; public final List<TvTrackInfo> mTvTrackInfos = new ArrayList<>(); public int mTuneStatus = ChannelState.TUNE_STATUS_VIDEO_AVAILABLE; @@ -71,9 +69,6 @@ public final class ChannelStateData implements Parcelable { @Override public String toString() { - return "{" - + "tune=" + mTuneStatus - + ", tracks=" + mTvTrackInfos - + "}"; + return "{" + "tune=" + mTuneStatus + ", tracks=" + mTvTrackInfos + "}"; } } diff --git a/tests/common/src/com/android/tv/testing/testinput/TestInputControlConnection.java b/tests/common/src/com/android/tv/testing/testinput/TestInputControlConnection.java index 9b3f8835..071b1d3c 100644 --- a/tests/common/src/com/android/tv/testing/testinput/TestInputControlConnection.java +++ b/tests/common/src/com/android/tv/testing/testinput/TestInputControlConnection.java @@ -21,8 +21,7 @@ import android.os.IBinder; import android.os.RemoteException; import android.os.SystemClock; import android.util.Log; - -import com.android.tv.testing.ChannelInfo; +import com.android.tv.testing.data.ChannelInfo; /** * Connection for controlling the Test TV Input Service. @@ -47,9 +46,7 @@ public class TestInputControlConnection implements ServiceConnection { mControl = null; } - /** - * Is the service currently connected. - */ + /** Is the service currently connected. */ public boolean isBound() { return mControl != null; } @@ -58,7 +55,7 @@ public class TestInputControlConnection implements ServiceConnection { * Update the state of the channel. * * @param channel the channel to update. - * @param data the new state for the channel. + * @param data the new state for the channel. */ public void updateChannelState(ChannelInfo channel, ChannelStateData data) { waitUntilBound(); @@ -69,9 +66,7 @@ public class TestInputControlConnection implements ServiceConnection { } } - /** - * Sleep until {@link #isBound()} is true; - */ + /** Sleep until {@link #isBound()} is true; */ public void waitUntilBound() { while (!isBound()) { SystemClock.sleep(BOUND_CHECK_INTERVAL_MS); diff --git a/tests/common/src/com/android/tv/testing/testinput/TestInputControlUtils.java b/tests/common/src/com/android/tv/testing/testinput/TestInputControlUtils.java index 54aacf20..330afa9b 100644 --- a/tests/common/src/com/android/tv/testing/testinput/TestInputControlUtils.java +++ b/tests/common/src/com/android/tv/testing/testinput/TestInputControlUtils.java @@ -18,16 +18,16 @@ package com.android.tv.testing.testinput; import android.content.ComponentName; import android.content.Intent; -/** - * Static utils for {@link ITestInputControl}. - */ +/** Static utils for {@link ITestInputControl}. */ public final class TestInputControlUtils { public static Intent createIntent() { - return new Intent().setComponent(new ComponentName("com.android.tv.testinput", - "com.android.tv.testinput.TestInputControlService")); + return new Intent() + .setComponent( + new ComponentName( + "com.android.tv.testinput", + "com.android.tv.testinput.TestInputControlService")); } - private TestInputControlUtils() { - } + private TestInputControlUtils() {} } diff --git a/tests/common/src/com/android/tv/testing/testinput/TvTestInputConstants.java b/tests/common/src/com/android/tv/testing/testinput/TvTestInputConstants.java index 498addfd..27d3036c 100644 --- a/tests/common/src/com/android/tv/testing/testinput/TvTestInputConstants.java +++ b/tests/common/src/com/android/tv/testing/testinput/TvTestInputConstants.java @@ -15,25 +15,22 @@ */ package com.android.tv.testing.testinput; -import com.android.tv.testing.ChannelInfo; +import com.android.tv.testing.data.ChannelInfo; -/** - * Constants for interacting with TvTestInput. - */ +/** Constants for interacting with TvTestInput. */ public final class TvTestInputConstants { /** * Channel 1. * - * <p> By convention Channel 1 should not be changed. Test often start by tuning to this - * channel. + * <p>By convention Channel 1 should not be changed. Test often start by tuning to this channel. */ public static final ChannelInfo CH_1_DEFAULT_DONT_MODIFY = ChannelInfo.create(null, 1); /** * Channel 2. * - * <p> By convention the state of Channel 2 is changed by tests. Testcases should explicitly - * set the state of this channel before using it in tests. + * <p>By convention the state of Channel 2 is changed by tests. Testcases should explicitly set + * the state of this channel before using it in tests. */ public static final ChannelInfo CH_2 = ChannelInfo.create(null, 2); } diff --git a/tests/common/src/com/android/tv/testing/uihelper/BaseUiDeviceHelper.java b/tests/common/src/com/android/tv/testing/uihelper/BaseUiDeviceHelper.java index 3a2f5509..21b05d67 100644 --- a/tests/common/src/com/android/tv/testing/uihelper/BaseUiDeviceHelper.java +++ b/tests/common/src/com/android/tv/testing/uihelper/BaseUiDeviceHelper.java @@ -18,9 +18,7 @@ package com.android.tv.testing.uihelper; import android.content.res.Resources; import android.support.test.uiautomator.UiDevice; -/** - * Base class for building UiAutomator Helper classes. - */ +/** Base class for building UiAutomator Helper classes. */ public abstract class BaseUiDeviceHelper { protected final UiDevice mUiDevice; protected final Resources mTargetResources; diff --git a/tests/common/src/com/android/tv/testing/uihelper/ByResource.java b/tests/common/src/com/android/tv/testing/uihelper/ByResource.java index a76ee1d3..47b8d9f9 100644 --- a/tests/common/src/com/android/tv/testing/uihelper/ByResource.java +++ b/tests/common/src/com/android/tv/testing/uihelper/ByResource.java @@ -19,9 +19,7 @@ import android.content.res.Resources; import android.support.test.uiautomator.By; import android.support.test.uiautomator.BySelector; -/** - * Convenience methods for creating {@link BySelector}s using resource ids. - */ +/** Convenience methods for creating {@link BySelector}s using resource ids. */ public final class ByResource { /** @@ -44,6 +42,5 @@ public final class ByResource { return By.text(text); } - private ByResource() { - } + private ByResource() {} } diff --git a/tests/common/src/com/android/tv/testing/uihelper/Constants.java b/tests/common/src/com/android/tv/testing/uihelper/Constants.java index 8dd8e14a..4b522914 100644 --- a/tests/common/src/com/android/tv/testing/uihelper/Constants.java +++ b/tests/common/src/com/android/tv/testing/uihelper/Constants.java @@ -17,6 +17,7 @@ package com.android.tv.testing.uihelper; import android.support.test.uiautomator.By; import android.support.test.uiautomator.BySelector; +import com.android.tv.common.CommonConstants; public final class Constants { @@ -24,7 +25,7 @@ public final class Constants { public static final int MIN_EXTRA_TIMEOUT = 10; public static final long MAX_SHOW_DELAY_MILLIS = 200; public static final long MAX_FOCUSED_DELAY_MILLIS = 1000; - public static final String TV_APP_PACKAGE = "com.android.tv"; + public static final String TV_APP_PACKAGE = CommonConstants.BASE_PACKAGE; public static final BySelector TV_VIEW = By.res(TV_APP_PACKAGE, "main_tunable_tv_view"); public static final BySelector CHANNEL_BANNER = By.res(TV_APP_PACKAGE, "channel_banner_view"); public static final BySelector KEYPAD_CHANNEL_SWITCH = By.res(TV_APP_PACKAGE, "channel_number"); @@ -35,6 +36,5 @@ public final class Constants { public static final BySelector DVR_SCHEDULES = By.res(TV_APP_PACKAGE, "dvr_schedules"); public static final BySelector FOCUSED_VIEW = By.focused(true); - private Constants() { - } + private Constants() {} } diff --git a/tests/common/src/com/android/tv/testing/uihelper/DialogHelper.java b/tests/common/src/com/android/tv/testing/uihelper/DialogHelper.java index 9e4040a8..2ac4b648 100644 --- a/tests/common/src/com/android/tv/testing/uihelper/DialogHelper.java +++ b/tests/common/src/com/android/tv/testing/uihelper/DialogHelper.java @@ -24,12 +24,9 @@ import android.content.res.Resources; import android.support.test.uiautomator.BySelector; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.Until; - import com.android.tv.R; -/** - * Helper for testing {@link DialogFragment}s. - */ +/** Helper for testing {@link DialogFragment}s. */ public class DialogHelper extends BaseUiDeviceHelper { private final BySelector byPinDialog; @@ -39,7 +36,9 @@ public class DialogHelper extends BaseUiDeviceHelper { } public void assertWaitForPinDialogOpen() { - assertWaitForCondition(mUiDevice, Until.hasObject(byPinDialog), + assertWaitForCondition( + mUiDevice, + Until.hasObject(byPinDialog), Constants.MAX_SHOW_DELAY_MILLIS + mTargetResources.getInteger(R.integer.pin_dialog_anim_duration)); } diff --git a/tests/common/src/com/android/tv/testing/uihelper/LiveChannelsUiDeviceHelper.java b/tests/common/src/com/android/tv/testing/uihelper/LiveChannelsUiDeviceHelper.java index 1dc0f020..4b7c1f89 100644 --- a/tests/common/src/com/android/tv/testing/uihelper/LiveChannelsUiDeviceHelper.java +++ b/tests/common/src/com/android/tv/testing/uihelper/LiveChannelsUiDeviceHelper.java @@ -1,3 +1,18 @@ +/* + * Copyright (C) 2017 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.testing.uihelper; import static com.android.tv.testing.uihelper.UiDeviceAsserts.waitForCondition; @@ -11,31 +26,28 @@ import android.support.test.uiautomator.BySelector; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.Until; import android.util.Log; - -import com.android.tv.testing.Utils; - +import com.android.tv.common.CommonConstants; +import com.android.tv.testing.utils.Utils; import junit.framework.Assert; -/** - * Helper for testing the Live TV Application. - */ +/** Helper for testing the Live TV Application. */ public class LiveChannelsUiDeviceHelper extends BaseUiDeviceHelper { private static final String TAG = "LiveChannelsUiDevice"; private static final int APPLICATION_START_TIMEOUT_MSEC = 5000; private final Context mContext; - public LiveChannelsUiDeviceHelper(UiDevice uiDevice, Resources targetResources, - Context context) { + public LiveChannelsUiDeviceHelper( + UiDevice uiDevice, Resources targetResources, Context context) { super(uiDevice, targetResources); mContext = context; } public void assertAppStarted() { assertTrue("TvActivity should be enabled.", Utils.isTvActivityEnabled(mContext)); - Intent intent = mContext.getPackageManager() - .getLaunchIntentForPackage(Constants.TV_APP_PACKAGE); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); // Clear out any previous instances + Intent intent = + mContext.getPackageManager().getLaunchIntentForPackage(Constants.TV_APP_PACKAGE); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); // Clear out any previous instances mContext.startActivity(intent); // Wait for idle state before checking the channel banner because waitForCondition() has // timeout. @@ -43,8 +55,10 @@ public class LiveChannelsUiDeviceHelper extends BaseUiDeviceHelper { // Make sure that the activity is resumed. waitForCondition(mUiDevice, Until.hasObject(Constants.TV_VIEW)); - Assert.assertTrue(Constants.TV_APP_PACKAGE + " did not start", mUiDevice - .wait(Until.hasObject(By.pkg(Constants.TV_APP_PACKAGE).depth(0)), + Assert.assertTrue( + Constants.TV_APP_PACKAGE + " did not start", + mUiDevice.wait( + Until.hasObject(By.pkg(Constants.TV_APP_PACKAGE).depth(0)), APPLICATION_START_TIMEOUT_MSEC)); BySelector welcome = ByResource.id(mTargetResources, com.android.tv.R.id.intro); if (mUiDevice.hasObject(welcome)) { @@ -54,9 +68,9 @@ public class LiveChannelsUiDeviceHelper extends BaseUiDeviceHelper { } public void assertAppStopped() { - while(mUiDevice.hasObject(By.pkg(Constants.TV_APP_PACKAGE).depth(0))) { + while (mUiDevice.hasObject(By.pkg(CommonConstants.BASE_PACKAGE).depth(0))) { mUiDevice.pressBack(); mUiDevice.waitForIdle(); } } -}
\ No newline at end of file +} diff --git a/tests/common/src/com/android/tv/testing/uihelper/MenuHelper.java b/tests/common/src/com/android/tv/testing/uihelper/MenuHelper.java index 80d53242..c8ea85ac 100644 --- a/tests/common/src/com/android/tv/testing/uihelper/MenuHelper.java +++ b/tests/common/src/com/android/tv/testing/uihelper/MenuHelper.java @@ -25,33 +25,30 @@ import android.support.test.uiautomator.Direction; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject2; import android.support.test.uiautomator.Until; - import com.android.tv.R; - import junit.framework.Assert; -/** - * Helper for testing {@link com.android.tv.menu.Menu}. - */ +/** Helper for testing {@link com.android.tv.menu.Menu}. */ public class MenuHelper extends BaseUiDeviceHelper { private final BySelector byChannels; public MenuHelper(UiDevice uiDevice, Resources targetResources) { super(uiDevice, targetResources); - byChannels = ByResource.id(mTargetResources, R.id.item_list) - .hasDescendant(ByResource.text(mTargetResources, R.string.menu_title_channels)); + byChannels = + ByResource.id(mTargetResources, R.id.item_list) + .hasDescendant( + ByResource.text(mTargetResources, R.string.menu_title_channels)); } public BySelector getByChannels() { return byChannels; } - /** - * Navigate to the menu item with the text {@code itemTextResId} in the row with text - * {@code rowTitleResId}. - * <p> - * Fails if the menu item can not be navigated to. + * Navigate to the menu item with the text {@code itemTextResId} in the row with text {@code + * rowTitleResId}. + * + * <p>Fails if the menu item can not be navigated to. * * @param rowTitleResId the resource id of the string in the desired row title. * @param itemTextResId the resource id of the string in the desired item. @@ -62,17 +59,20 @@ public class MenuHelper extends BaseUiDeviceHelper { BySelector byListView = ByResource.id(mTargetResources, R.id.list_view); UiObject2 listView = row.findObject(byListView); Assert.assertNotNull( - "Menu row '" + mTargetResources.getString(rowTitleResId) + "' does not have a " - + byListView, listView); + "Menu row '" + + mTargetResources.getString(rowTitleResId) + + "' does not have a " + + byListView, + listView); return assertNavigateToRowItem(listView, itemTextResId); } /** * Navigate to the menu row with the text title {@code rowTitleResId}. - * <p> - * Fails if the menu row can not be navigated to. - * We can't navigate to the Play controls row with this method, because the row doesn't have the - * title when it is selected. Use {@link #assertNavigateToPlayControlsRow} for the row instead. + * + * <p>Fails if the menu row can not be navigated to. We can't navigate to the Play controls row + * with this method, because the row doesn't have the title when it is selected. Use {@link + * #assertNavigateToPlayControlsRow} for the row instead. * * @param rowTitleResId the resource id of the string in the desired row title. * @return the row navigated to. @@ -82,14 +82,17 @@ public class MenuHelper extends BaseUiDeviceHelper { UiObject2 menu = mUiDevice.findObject(MENU); // TODO: handle play controls. They have a different dom structure and navigation sometimes // can get stuck on that row. - return UiDeviceAsserts.assertNavigateTo(mUiDevice, menu, - By.hasDescendant(ByResource.text(mTargetResources, rowTitleResId)), Direction.DOWN); + return UiDeviceAsserts.assertNavigateTo( + mUiDevice, + menu, + By.hasDescendant(ByResource.text(mTargetResources, rowTitleResId)), + Direction.DOWN); } /** * Navigate to the Play controls row. - * <p> - * Fails if the row can not be navigated to. + * + * <p>Fails if the row can not be navigated to. * * @see #assertNavigateToRow */ @@ -103,27 +106,28 @@ public class MenuHelper extends BaseUiDeviceHelper { /** * Navigate to the menu item in the given {@code row} with the text {@code itemTextResId} . - * <p> - * Fails if the menu item can not be navigated to. * - * @param row the container to look for menu items in. + * <p>Fails if the menu item can not be navigated to. + * + * @param row the container to look for menu items in. * @param itemTextResId the resource id of the string in the desired item. * @return the item navigated to. */ public UiObject2 assertNavigateToRowItem(UiObject2 row, int itemTextResId) { - return UiDeviceAsserts.assertNavigateTo(mUiDevice, row, + return UiDeviceAsserts.assertNavigateTo( + mUiDevice, + row, By.hasDescendant(ByResource.text(mTargetResources, itemTextResId)), Direction.RIGHT); } public UiObject2 assertPressOptionsSettings() { - return assertPressMenuItem(R.string.menu_title_options, - R.string.options_item_settings); + return assertPressMenuItem(R.string.menu_title_options, R.string.options_item_settings); } public UiObject2 assertPressOptionsClosedCaptions() { - return assertPressMenuItem(R.string.menu_title_options, - R.string.options_item_closed_caption); + return assertPressMenuItem( + R.string.menu_title_options, R.string.options_item_closed_caption); } public UiObject2 assertPressOptionsDisplayMode() { @@ -135,20 +139,19 @@ public class MenuHelper extends BaseUiDeviceHelper { } public UiObject2 assertPressProgramGuide() { - return assertPressMenuItem(R.string.menu_title_channels, - R.string.channels_item_program_guide); + return assertPressMenuItem( + R.string.menu_title_channels, R.string.channels_item_program_guide); } public UiObject2 assertPressDvrLibrary() { - return assertPressMenuItem(R.string.menu_title_channels, - R.string.channels_item_dvr); + return assertPressMenuItem(R.string.menu_title_channels, R.string.channels_item_dvr); } /** - * Navigate to the menu item with the text {@code itemTextResId} in the row with text - * {@code rowTitleResId}. - * <p> - * Fails if the menu item can not be navigated to. + * Navigate to the menu item with the text {@code itemTextResId} in the row with text {@code + * rowTitleResId}. + * + * <p>Fails if the menu item can not be navigated to. * * @param rowTitleResId the resource id of the string in the desired row title. * @param itemTextResId the resource id of the string in the desired item. @@ -161,17 +164,15 @@ public class MenuHelper extends BaseUiDeviceHelper { return item; } - /** - * Waits until the menu is visible. - */ + /** Waits until the menu is visible. */ public void assertWaitForMenu() { UiDeviceAsserts.assertWaitForCondition(mUiDevice, Until.hasObject(MENU)); } /** - * Show the menu. - * <p> - * Fails if the menu does not appear in {@link Constants#MAX_SHOW_DELAY_MILLIS}. + * Show the menu. + * + * <p>Fails if the menu does not appear in {@link Constants#MAX_SHOW_DELAY_MILLIS}. */ public void showMenu() { if (!mUiDevice.hasObject(MENU)) { diff --git a/tests/common/src/com/android/tv/testing/uihelper/SidePanelHelper.java b/tests/common/src/com/android/tv/testing/uihelper/SidePanelHelper.java index 98a19a41..ba015260 100644 --- a/tests/common/src/com/android/tv/testing/uihelper/SidePanelHelper.java +++ b/tests/common/src/com/android/tv/testing/uihelper/SidePanelHelper.java @@ -22,15 +22,11 @@ import android.support.test.uiautomator.BySelector; import android.support.test.uiautomator.Direction; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject2; - import com.android.tv.R; import com.android.tv.ui.sidepanel.SideFragment; - import junit.framework.Assert; -/** - * Helper for testing {@link SideFragment}s. - */ +/** Helper for testing {@link SideFragment}s. */ public class SidePanelHelper extends BaseUiDeviceHelper { public SidePanelHelper(UiDevice uiDevice, Resources targetResources) { @@ -54,6 +50,7 @@ public class SidePanelHelper extends BaseUiDeviceHelper { String title = mTargetResources.getString(resId); return assertNavigateToItem(title, direction); } + public UiObject2 assertNavigateToItem(String title) { return assertNavigateToItem(title, Direction.DOWN); } @@ -63,7 +60,7 @@ public class SidePanelHelper extends BaseUiDeviceHelper { UiObject2 sidePanelList = mUiDevice.findObject(sidePanelSelector); Assert.assertNotNull(sidePanelSelector + " not found", sidePanelList); - return UiDeviceAsserts.assertNavigateTo(mUiDevice, sidePanelList, - By.hasDescendant(By.text(title)), direction); + return UiDeviceAsserts.assertNavigateTo( + mUiDevice, sidePanelList, By.hasDescendant(By.text(title)), direction); } } diff --git a/tests/common/src/com/android/tv/testing/uihelper/UiDeviceAsserts.java b/tests/common/src/com/android/tv/testing/uihelper/UiDeviceAsserts.java index c096d7d2..28ea163e 100644 --- a/tests/common/src/com/android/tv/testing/uihelper/UiDeviceAsserts.java +++ b/tests/common/src/com/android/tv/testing/uihelper/UiDeviceAsserts.java @@ -27,12 +27,9 @@ import android.support.test.uiautomator.SearchCondition; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject2; import android.support.test.uiautomator.Until; - import junit.framework.Assert; -/** - * Asserts for {@link UiDevice}s. - */ +/** Asserts for {@link UiDevice}s. */ public final class UiDeviceAsserts { public static void assertHas(UiDevice uiDevice, BySelector bySelector, boolean expected) { @@ -46,25 +43,25 @@ public final class UiDeviceAsserts { } /** - * Assert that {@code searchCondition} becomes true within - * {@value Constants#MAX_SHOW_DELAY_MILLIS} milliseconds. + * Assert that {@code searchCondition} becomes true within {@value + * Constants#MAX_SHOW_DELAY_MILLIS} milliseconds. * - * @param uiDevice the device under test. + * @param uiDevice the device under test. * @param searchCondition the condition to wait for. */ - public static void assertWaitForCondition(UiDevice uiDevice, - SearchCondition<Boolean> searchCondition) { + public static void assertWaitForCondition( + UiDevice uiDevice, SearchCondition<Boolean> searchCondition) { assertWaitForCondition(uiDevice, searchCondition, Constants.MAX_SHOW_DELAY_MILLIS); } /** * Assert that {@code searchCondition} becomes true within {@code timeout} milliseconds. * - * @param uiDevice the device under test. + * @param uiDevice the device under test. * @param searchCondition the condition to wait for. */ - public static void assertWaitForCondition(UiDevice uiDevice, - SearchCondition<Boolean> searchCondition, long timeout) { + public static void assertWaitForCondition( + UiDevice uiDevice, SearchCondition<Boolean> searchCondition, long timeout) { boolean result = waitForCondition(uiDevice, searchCondition, timeout); assertTrue(searchCondition + " not true after " + timeout / 1000.0 + " seconds.", result); } @@ -72,52 +69,55 @@ public final class UiDeviceAsserts { /** * Wait until {@code searchCondition} becomes true. * - * @param uiDevice The device under test. + * @param uiDevice The device under test. * @param searchCondition The condition to wait for. * @return {@code true} if the condition is met, otherwise {@code false}. */ - public static boolean waitForCondition(UiDevice uiDevice, - SearchCondition<Boolean> searchCondition) { + public static boolean waitForCondition( + UiDevice uiDevice, SearchCondition<Boolean> searchCondition) { return waitForCondition(uiDevice, searchCondition, Constants.MAX_SHOW_DELAY_MILLIS); } - private static boolean waitForCondition(UiDevice uiDevice, - SearchCondition<Boolean> searchCondition, long timeout) { - long adjustedTimeout = timeout + Math.max(Constants.MIN_EXTRA_TIMEOUT, - (long) (timeout * Constants.EXTRA_TIMEOUT_PERCENT)); + private static boolean waitForCondition( + UiDevice uiDevice, SearchCondition<Boolean> searchCondition, long timeout) { + long adjustedTimeout = + timeout + + Math.max( + Constants.MIN_EXTRA_TIMEOUT, + (long) (timeout * Constants.EXTRA_TIMEOUT_PERCENT)); return uiDevice.wait(searchCondition, adjustedTimeout); } /** * Navigates through the focus items in a container returning the container child that has a * descendant matching the {@code selector}. - * <p> - * The navigation starts in the {@code direction} specified and - * {@link Direction#reverse(Direction) reverses} once if needed. Fails if there is not a - * focused - * descendant, or if after completing both directions no focused child has a descendant - * matching + * + * <p>The navigation starts in the {@code direction} specified and {@link + * Direction#reverse(Direction) reverses} once if needed. Fails if there is not a focused + * descendant, or if after completing both directions no focused child has a descendant matching * {@code selector}. - * <p> - * Fails if the menu item can not be navigated to. * - * @param uiDevice the device under test. + * <p>Fails if the menu item can not be navigated to. + * + * @param uiDevice the device under test. * @param container contains children to navigate over. - * @param selector the selector for the object to navigate to. + * @param selector the selector for the object to navigate to. * @param direction the direction to start navigating. * @return the object navigated to. */ - public static UiObject2 assertNavigateTo(UiDevice uiDevice, UiObject2 container, - BySelector selector, Direction direction) { + public static UiObject2 assertNavigateTo( + UiDevice uiDevice, UiObject2 container, BySelector selector, Direction direction) { int count = 0; while (count < 2) { BySelector hasFocusedDescendant = By.hasDescendant(FOCUSED_VIEW); UiObject2 focusedChild = null; - SearchCondition<Boolean> untilHasFocusedDescendant = Until - .hasObject(hasFocusedDescendant); + SearchCondition<Boolean> untilHasFocusedDescendant = + Until.hasObject(hasFocusedDescendant); - boolean result = container.wait(untilHasFocusedDescendant, - UiObject2Asserts.getAdjustedTimeout(Constants.MAX_SHOW_DELAY_MILLIS)); + boolean result = + container.wait( + untilHasFocusedDescendant, + UiObject2Asserts.getAdjustedTimeout(Constants.MAX_SHOW_DELAY_MILLIS)); if (!result) { // HACK: Try direction anyways because play control does not always have a // focused item. @@ -147,6 +147,5 @@ public final class UiDeviceAsserts { return null; } - private UiDeviceAsserts() { - } + private UiDeviceAsserts() {} } diff --git a/tests/common/src/com/android/tv/testing/uihelper/UiDeviceUtils.java b/tests/common/src/com/android/tv/testing/uihelper/UiDeviceUtils.java index 98eff906..d5545023 100644 --- a/tests/common/src/com/android/tv/testing/uihelper/UiDeviceUtils.java +++ b/tests/common/src/com/android/tv/testing/uihelper/UiDeviceUtils.java @@ -15,21 +15,11 @@ */ package com.android.tv.testing.uihelper; -import static junit.framework.Assert.assertTrue; - -import android.app.Instrumentation; -import android.app.UiAutomation; -import android.os.Build; -import android.os.SystemClock; -import android.support.test.uiautomator.Configurator; import android.support.test.uiautomator.Direction; import android.support.test.uiautomator.UiDevice; -import android.view.InputDevice; import android.view.KeyEvent; -/** - * Static utility methods for {@link UiDevice}. - */ +/** Static utility methods for {@link UiDevice}. */ public final class UiDeviceUtils { public static void pressDpad(UiDevice uiDevice, Direction direction) { @@ -51,7 +41,6 @@ public final class UiDeviceUtils { } } - public static void pressKeys(UiDevice uiDevice, int... keyCodes) { for (int k : keyCodes) { uiDevice.pressKeyCode(k); @@ -60,8 +49,8 @@ public final class UiDeviceUtils { /** * Parses the string and sends the corresponding individual key presses. - * <p> - * <b>Note:</b> only handles 0-9, '.', and '-'. + * + * <p><b>Note:</b> only handles 0-9, '.', and '-'. */ public static void pressKeys(UiDevice uiDevice, String keys) { for (char c : keys.toCharArray()) { @@ -77,59 +66,5 @@ public final class UiDeviceUtils { } } - /** - * Sends the DPAD Center key presses with the {@code repeat} count. - * TODO: Remove instrumentation argument once migrated to JUnit4. - */ - public static void pressDPadCenter(Instrumentation instrumentation, int repeat) { - pressKey(instrumentation, KeyEvent.KEYCODE_DPAD_CENTER, repeat); - } - - private static void pressKey(Instrumentation instrumentation, int keyCode, int repeat) { - UiDevice.getInstance(instrumentation).waitForIdle(); - for (int i = 0; i < repeat; ++i) { - assertPressKeyDown(instrumentation, keyCode, false); - if (i < repeat - 1) { - assertPressKeyUp(instrumentation, keyCode, false); - } - } - // Send last key event synchronously. - assertPressKeyUp(instrumentation, keyCode, true); - } - - private static void assertPressKeyDown(Instrumentation instrumentation, int keyCode, - boolean sync) { - assertPressKey(instrumentation, KeyEvent.ACTION_DOWN, keyCode, sync); - } - - private static void assertPressKeyUp(Instrumentation instrumentation, int keyCode, - boolean sync) { - assertPressKey(instrumentation, KeyEvent.ACTION_UP, keyCode, sync); - } - - private static void assertPressKey(Instrumentation instrumentation, int action, int keyCode, - boolean sync) { - long eventTime = SystemClock.uptimeMillis(); - KeyEvent event = new KeyEvent(eventTime, eventTime, action, keyCode, 0, 0, -1, 0, 0, - InputDevice.SOURCE_KEYBOARD); - assertTrue("Failed to inject key up event:" + event, - injectEvent(instrumentation, event, sync)); - } - - private static boolean injectEvent(Instrumentation instrumentation, KeyEvent event, - boolean sync) { - return getUiAutomation(instrumentation).injectInputEvent(event, sync); - } - - private static UiAutomation getUiAutomation(Instrumentation instrumentation) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - int flags = Configurator.getInstance().getUiAutomationFlags(); - return instrumentation.getUiAutomation(flags); - } else { - return instrumentation.getUiAutomation(); - } - } - - private UiDeviceUtils() { - } + private UiDeviceUtils() {} } diff --git a/tests/common/src/com/android/tv/testing/uihelper/UiObject2Asserts.java b/tests/common/src/com/android/tv/testing/uihelper/UiObject2Asserts.java index aba29f0e..ee02d7f7 100644 --- a/tests/common/src/com/android/tv/testing/uihelper/UiObject2Asserts.java +++ b/tests/common/src/com/android/tv/testing/uihelper/UiObject2Asserts.java @@ -20,41 +20,40 @@ import static junit.framework.Assert.assertTrue; import android.support.test.uiautomator.SearchCondition; import android.support.test.uiautomator.UiObject2; -/** - * Asserts for {@link UiObject2}s. - */ +/** Asserts for {@link UiObject2}s. */ public final class UiObject2Asserts { /** - * Assert that {@code searchCondition} becomes true within - * {@value Constants#MAX_SHOW_DELAY_MILLIS} milliseconds. + * Assert that {@code searchCondition} becomes true within {@value + * Constants#MAX_SHOW_DELAY_MILLIS} milliseconds. * - * @param uiObject the device under test. + * @param uiObject the device under test. * @param searchCondition the condition to wait for. */ - public static void assertWaitForCondition(UiObject2 uiObject, - SearchCondition<Boolean> searchCondition) { + public static void assertWaitForCondition( + UiObject2 uiObject, SearchCondition<Boolean> searchCondition) { assertWaitForCondition(uiObject, searchCondition, Constants.MAX_SHOW_DELAY_MILLIS); } /** * Assert that {@code searchCondition} becomes true within {@code timeout} milliseconds. * - * @param uiObject the device under test. + * @param uiObject the device under test. * @param searchCondition the condition to wait for. */ - public static void assertWaitForCondition(UiObject2 uiObject, - SearchCondition<Boolean> searchCondition, long timeout) { + public static void assertWaitForCondition( + UiObject2 uiObject, SearchCondition<Boolean> searchCondition, long timeout) { long adjustedTimeout = getAdjustedTimeout(timeout); boolean result = uiObject.wait(searchCondition, adjustedTimeout); assertTrue(searchCondition + " not true after " + timeout / 1000.0 + " seconds.", result); } public static long getAdjustedTimeout(long timeout) { - return timeout + Math.max( - Constants.MIN_EXTRA_TIMEOUT, (long) (timeout * Constants.EXTRA_TIMEOUT_PERCENT)); + return timeout + + Math.max( + Constants.MIN_EXTRA_TIMEOUT, + (long) (timeout * Constants.EXTRA_TIMEOUT_PERCENT)); } - private UiObject2Asserts() { - } + private UiObject2Asserts() {} } diff --git a/tests/common/src/com/android/tv/testing/uihelper/UiObject2Utils.java b/tests/common/src/com/android/tv/testing/uihelper/UiObject2Utils.java index 2a997a67..2f3779c5 100644 --- a/tests/common/src/com/android/tv/testing/uihelper/UiObject2Utils.java +++ b/tests/common/src/com/android/tv/testing/uihelper/UiObject2Utils.java @@ -19,9 +19,7 @@ import android.graphics.Point; import android.support.test.uiautomator.Direction; import android.support.test.uiautomator.UiObject2; -/** - * Static utility methods for {@link UiObject2}s. - */ +/** Static utility methods for {@link UiObject2}s. */ public class UiObject2Utils { public static boolean hasSiblingInDirection(UiObject2 theUiObject, Direction direction) { @@ -56,6 +54,5 @@ public class UiObject2Utils { return false; } - private UiObject2Utils() { - } + private UiObject2Utils() {} } diff --git a/tests/common/src/com/android/tv/testing/utils/TestUtils.java b/tests/common/src/com/android/tv/testing/utils/TestUtils.java new file mode 100644 index 00000000..6604c9ad --- /dev/null +++ b/tests/common/src/com/android/tv/testing/utils/TestUtils.java @@ -0,0 +1,193 @@ +/* + * 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.testing.utils; + +import android.content.pm.ApplicationInfo; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.graphics.drawable.Icon; +import android.hardware.hdmi.HdmiDeviceInfo; +import android.media.tv.TvInputInfo; +import android.os.Build; +import android.os.Bundle; +import java.lang.reflect.Constructor; + +/** A class that includes convenience methods for testing. */ +public class TestUtils { + /** Creates a {@link TvInputInfo}. */ + public static TvInputInfo createTvInputInfo( + ResolveInfo service, String id, String parentId, int type, boolean isHardwareInput) + throws Exception { + return createTvInputInfo(service, id, parentId, type, isHardwareInput, false, 0); + } + + /** + * Creates a {@link TvInputInfo}. + * + * <p>If this is called on MNC, {@code canRecord} and {@code tunerCount} are ignored. + */ + public static TvInputInfo createTvInputInfo( + ResolveInfo service, + String id, + String parentId, + int type, + boolean isHardwareInput, + boolean canRecord, + int tunerCount) + throws Exception { + // Create a mock TvInputInfo by using private constructor + // Note that mockito doesn't support mock/spy on final object. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + return createTvInputInfoForO( + service, id, parentId, type, isHardwareInput, canRecord, tunerCount); + + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + return createTvInputInfoForNyc( + service, id, parentId, type, isHardwareInput, canRecord, tunerCount); + } + return createTvInputInfoForMnc(service, id, parentId, type, isHardwareInput); + } + + /** + * private TvInputInfo(ResolveInfo service, String id, int type, boolean isHardwareInput, + * CharSequence label, int labelResId, Icon icon, Icon iconStandby, Icon iconDisconnected, + * String setupActivity, boolean canRecord, int tunerCount, HdmiDeviceInfo hdmiDeviceInfo, + * boolean isConnectedToHdmiSwitch, String parentId, Bundle extras) { + */ + private static TvInputInfo createTvInputInfoForO( + ResolveInfo service, + String id, + String parentId, + int type, + boolean isHardwareInput, + boolean canRecord, + int tunerCount) + throws Exception { + Constructor<TvInputInfo> constructor = + TvInputInfo.class.getDeclaredConstructor( + ResolveInfo.class, + String.class, + int.class, + boolean.class, + CharSequence.class, + int.class, + Icon.class, + Icon.class, + Icon.class, + String.class, + boolean.class, + int.class, + HdmiDeviceInfo.class, + boolean.class, + String.class, + Bundle.class); + constructor.setAccessible(true); + return constructor.newInstance( + service, + id, + type, + isHardwareInput, + null, + 0, + null, + null, + null, + null, + canRecord, + tunerCount, + null, + false, + parentId, + null); + } + + /** + * private TvInputInfo(ResolveInfo service, String id, int type, boolean isHardwareInput, + * CharSequence label, int labelResId, Icon icon, Icon iconStandby, Icon iconDisconnected, + * String setupActivity, String settingsActivity, boolean canRecord, int tunerCount, + * HdmiDeviceInfo hdmiDeviceInfo, boolean isConnectedToHdmiSwitch, String parentId, Bundle + * extras) { + */ + private static TvInputInfo createTvInputInfoForNyc( + ResolveInfo service, + String id, + String parentId, + int type, + boolean isHardwareInput, + boolean canRecord, + int tunerCount) + throws Exception { + Constructor<TvInputInfo> constructor = + TvInputInfo.class.getDeclaredConstructor( + ResolveInfo.class, + String.class, + int.class, + boolean.class, + CharSequence.class, + int.class, + Icon.class, + Icon.class, + Icon.class, + String.class, + String.class, + boolean.class, + int.class, + HdmiDeviceInfo.class, + boolean.class, + String.class, + Bundle.class); + constructor.setAccessible(true); + return constructor.newInstance( + service, + id, + type, + isHardwareInput, + null, + 0, + null, + null, + null, + null, + null, + canRecord, + tunerCount, + null, + false, + parentId, + null); + } + + private static TvInputInfo createTvInputInfoForMnc( + ResolveInfo service, String id, String parentId, int type, boolean isHardwareInput) + throws Exception { + Constructor<TvInputInfo> constructor = + TvInputInfo.class.getDeclaredConstructor( + ResolveInfo.class, String.class, String.class, int.class, boolean.class); + constructor.setAccessible(true); + return constructor.newInstance(service, id, parentId, type, isHardwareInput); + } + + public static ResolveInfo createResolveInfo(String packageName, String name) { + ResolveInfo resolveInfo = new ResolveInfo(); + resolveInfo.serviceInfo = new ServiceInfo(); + resolveInfo.serviceInfo.packageName = packageName; + resolveInfo.serviceInfo.name = name; + resolveInfo.serviceInfo.metaData = new Bundle(); + resolveInfo.serviceInfo.applicationInfo = new ApplicationInfo(); + return resolveInfo; + } +} diff --git a/tests/common/src/com/android/tv/testing/Utils.java b/tests/common/src/com/android/tv/testing/utils/Utils.java index b2b4036e..a116db0b 100644 --- a/tests/common/src/com/android/tv/testing/Utils.java +++ b/tests/common/src/com/android/tv/testing/utils/Utils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.tv.testing; +package com.android.tv.testing.utils; import android.content.ComponentName; import android.content.ContentResolver; @@ -26,9 +26,8 @@ import android.media.tv.TvInputInfo; import android.media.tv.TvInputManager; import android.net.Uri; import android.util.Log; - -import com.android.tv.common.TvCommonUtils; - +import com.android.tv.common.CommonConstants; +import com.android.tv.common.util.CommonUtils; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -40,12 +39,10 @@ import java.util.Random; /** * An utility class for testing. * - * <p>This class is also used to check whether TV app is running in tests or not. - * - * @see TvCommonUtils#isRunningInTest + * @see CommonUtils#isRunningInTest */ public final class Utils { - private static final String TAG ="Utils"; + private static final String TAG = "Utils"; private static final long DEFAULT_RANDOM_SEED = getSeed(); @@ -55,10 +52,12 @@ public final class Utils { } Resources res = context.getResources(); return new Uri.Builder() - .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE) - .authority(res.getResourcePackageName(resId)) - .path(res.getResourceTypeName(resId)) - .appendPath(res.getResourceEntryName(resId)).build().toString(); + .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE) + .authority(res.getResourcePackageName(resId)) + .path(res.getResourceTypeName(resId)) + .appendPath(res.getResourceEntryName(resId)) + .build() + .toString(); } public static void copy(InputStream is, OutputStream os) throws IOException { @@ -91,8 +90,8 @@ public final class Utils { } /** - * Return the Random class which is needed to make random data for testing. - * Default seed of the random is today's date. + * Return the Random class which is needed to make random data for testing. Default seed of the + * random is today's date. */ public static Random createTestRandom() { return new Random(DEFAULT_RANDOM_SEED); @@ -106,17 +105,15 @@ public final class Utils { return Long.valueOf(today); } - private Utils() {} - - /** - * Checks whether TvActivity is enabled or not. - */ + /** Checks whether TvActivity is enabled or not. */ public static boolean isTvActivityEnabled(Context context) { PackageManager pm = context.getPackageManager(); - ComponentName name = new ComponentName("com.android.tv", - "com.android.tv.TvActivity"); + ComponentName name = + new ComponentName(CommonConstants.BASE_PACKAGE, "com.android.tv.TvActivity"); int enabled = pm.getComponentEnabledSetting(name); return enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; } + + private Utils() {} } diff --git a/tests/func/Android.mk b/tests/func/Android.mk index e89ba25b..855e8ebf 100644 --- a/tests/func/Android.mk +++ b/tests/func/Android.mk @@ -14,9 +14,11 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ tv-test-common \ ub-uiautomator \ +LOCAL_JAVA_LIBRARIES := android.test.base.stubs + LOCAL_INSTRUMENTATION_FOR := LiveTv -LOCAL_SDK_VERSION := current -LOCAL_MIN_SDK_VERSION := 23 # M +LOCAL_SDK_VERSION := system_current +LOCAL_PROGUARD_ENABLED := disabled include $(BUILD_PACKAGE) diff --git a/tests/func/AndroidManifest.xml b/tests/func/AndroidManifest.xml index 29b018e1..708dc220 100644 --- a/tests/func/AndroidManifest.xml +++ b/tests/func/AndroidManifest.xml @@ -18,7 +18,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.tv.tests.ui" > - <uses-sdk android:targetSdkVersion="23" android:minSdkVersion="21" /> + <uses-sdk android:targetSdkVersion="26" android:minSdkVersion="21" /> <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" diff --git a/tests/func/src/com/android/tv/tests/ui/ChannelBannerViewTest.java b/tests/func/src/com/android/tv/tests/ui/ChannelBannerViewTest.java index d8a4aec1..600b52b6 100644 --- a/tests/func/src/com/android/tv/tests/ui/ChannelBannerViewTest.java +++ b/tests/func/src/com/android/tv/tests/ui/ChannelBannerViewTest.java @@ -16,37 +16,48 @@ package com.android.tv.tests.ui; -import static com.android.tv.testing.uihelper.UiDeviceAsserts.assertWaitForCondition; - -import android.support.test.filters.SmallTest; +import android.support.test.filters.MediumTest; import android.support.test.uiautomator.Until; - import com.android.tv.R; import com.android.tv.testing.uihelper.Constants; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link com.android.tv.ui.ChannelBannerView} */ +@MediumTest +@RunWith(JUnit4.class) +public class ChannelBannerViewTest { + @Rule public final LiveChannelsTestController controller = new LiveChannelsTestController(); -@SmallTest -public class ChannelBannerViewTest extends LiveChannelsTestCase { // Channel banner show duration with the grace period. private long mShowDurationMillis; - @Override - protected void setUp() throws Exception { - super.setUp(); - mLiveChannelsHelper.assertAppStarted(); - mShowDurationMillis = mTargetResources.getInteger(R.integer.channel_banner_show_duration) - + Constants.MAX_SHOW_DELAY_MILLIS; + @Before + public void setUp() throws Exception { + controller.liveChannelsHelper.assertAppStarted(); + mShowDurationMillis = + controller.getTargetResources().getInteger(R.integer.channel_banner_show_duration) + + Constants.MAX_SHOW_DELAY_MILLIS; } + @Ignore("b/73727914") + @Test public void testChannelBannerAppearDisappear() { - mDevice.pressDPadCenter(); - assertWaitForCondition(mDevice, Until.hasObject(Constants.CHANNEL_BANNER)); - assertWaitForCondition(mDevice, Until.gone(Constants.CHANNEL_BANNER), mShowDurationMillis); + controller.pressDPadCenter(); + controller.assertWaitForCondition(Until.hasObject(Constants.CHANNEL_BANNER)); + controller.assertWaitForCondition( + Until.gone(Constants.CHANNEL_BANNER), mShowDurationMillis); } + @Test public void testChannelBannerShownWhenTune() { - mDevice.pressDPadDown(); - assertWaitForCondition(mDevice, Until.hasObject(Constants.CHANNEL_BANNER)); - mDevice.pressDPadUp(); - assertWaitForCondition(mDevice, Until.hasObject(Constants.CHANNEL_BANNER)); + controller.pressDPadDown(); + controller.assertWaitForCondition(Until.hasObject(Constants.CHANNEL_BANNER)); + controller.pressDPadUp(); + controller.assertWaitForCondition(Until.hasObject(Constants.CHANNEL_BANNER)); } } diff --git a/tests/func/src/com/android/tv/tests/ui/ChannelSourcesTest.java b/tests/func/src/com/android/tv/tests/ui/ChannelSourcesTest.java index cfa5eda7..53e27f1b 100644 --- a/tests/func/src/com/android/tv/tests/ui/ChannelSourcesTest.java +++ b/tests/func/src/com/android/tv/tests/ui/ChannelSourcesTest.java @@ -15,56 +15,64 @@ */ package com.android.tv.tests.ui; -import static com.android.tv.testing.uihelper.UiDeviceAsserts.assertWaitForCondition; - -import android.support.test.filters.LargeTest; +import android.support.test.filters.MediumTest; import android.support.test.uiautomator.BySelector; import android.support.test.uiautomator.Until; - import com.android.tv.R; import com.android.tv.testing.uihelper.ByResource; -import com.android.tv.testing.uihelper.UiDeviceUtils; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; -/** - * Tests for channel sources. - */ -@LargeTest -public class ChannelSourcesTest extends LiveChannelsTestCase { +/** Tests for channel sources. */ +@MediumTest +@RunWith(JUnit4.class) +public class ChannelSourcesTest { + @Rule public final LiveChannelsTestController controller = new LiveChannelsTestController(); private BySelector mBySettingsSidePanel; - @Override - protected void setUp() throws Exception { - super.setUp(); - mBySettingsSidePanel = mSidePanelHelper.bySidePanelTitled( - R.string.side_panel_title_settings); + @Before + public void before() throws Exception { + mBySettingsSidePanel = + controller.sidePanelHelper.bySidePanelTitled(R.string.side_panel_title_settings); } - //TODO: create a cancelable test channel setup. + // TODO: create a cancelable test channel setup. + @Test public void testSetup_cancel() { - mLiveChannelsHelper.assertAppStarted(); - mMenuHelper.assertPressOptionsSettings(); - assertWaitForCondition(mDevice, Until.hasObject(mBySettingsSidePanel)); + controller.liveChannelsHelper.assertAppStarted(); + controller.menuHelper.assertPressOptionsSettings(); + controller.assertWaitForCondition(Until.hasObject(mBySettingsSidePanel)); - mSidePanelHelper.assertNavigateToItem(R.string.settings_channel_source_item_setup); - mDevice.pressDPadCenter(); + controller.sidePanelHelper.assertNavigateToItem( + R.string.settings_channel_source_item_setup); + controller.pressDPadCenter(); - assertWaitForCondition(mDevice, - Until.hasObject(ByResource.text(mTargetResources, R.string.setup_sources_text))); - mDevice.pressBack(); + controller.assertWaitForCondition( + Until.hasObject( + ByResource.text( + controller.getTargetResources(), R.string.setup_sources_text))); + controller.pressBack(); } // SetupSourcesFragment should have no errors if side fragment item is clicked multiple times. + @Test public void testSetupTwice_cancel() { - mLiveChannelsHelper.assertAppStarted(); - mMenuHelper.assertPressOptionsSettings(); - assertWaitForCondition(mDevice, Until.hasObject(mBySettingsSidePanel)); + controller.liveChannelsHelper.assertAppStarted(); + controller.menuHelper.assertPressOptionsSettings(); + controller.assertWaitForCondition(Until.hasObject(mBySettingsSidePanel)); - mSidePanelHelper.assertNavigateToItem(R.string.settings_channel_source_item_setup); - UiDeviceUtils.pressDPadCenter(getInstrumentation(), 2); + controller.sidePanelHelper.assertNavigateToItem( + R.string.settings_channel_source_item_setup); + controller.pressDPadCenter(2); - assertWaitForCondition(mDevice, - Until.hasObject(ByResource.text(mTargetResources, R.string.setup_sources_text))); - mDevice.pressBack(); + controller.assertWaitForCondition( + Until.hasObject( + ByResource.text( + controller.getTargetResources(), R.string.setup_sources_text))); + controller.pressBack(); } } diff --git a/tests/func/src/com/android/tv/tests/ui/LiveChannelsAppTest.java b/tests/func/src/com/android/tv/tests/ui/LiveChannelsAppTest.java index 48224123..1a5ceb45 100644 --- a/tests/func/src/com/android/tv/tests/ui/LiveChannelsAppTest.java +++ b/tests/func/src/com/android/tv/tests/ui/LiveChannelsAppTest.java @@ -16,103 +16,116 @@ package com.android.tv.tests.ui; -import static com.android.tv.testing.uihelper.UiDeviceAsserts.assertHas; -import static com.android.tv.testing.uihelper.UiDeviceAsserts.assertWaitForCondition; - -import android.support.test.filters.LargeTest; +import android.support.test.filters.MediumTest; import android.support.test.uiautomator.BySelector; import android.support.test.uiautomator.Until; - import com.android.tv.R; import com.android.tv.testing.testinput.ChannelStateData; import com.android.tv.testing.testinput.TvTestInputConstants; import com.android.tv.testing.uihelper.Constants; import com.android.tv.testing.uihelper.DialogHelper; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Basic tests for the LiveChannels app. */ +@MediumTest +@RunWith(JUnit4.class) +public class LiveChannelsAppTest { + @Rule public final LiveChannelsTestController controller = new LiveChannelsTestController(); -/** - * Basic tests for the LiveChannels app. - */ -@LargeTest -public class LiveChannelsAppTest extends LiveChannelsTestCase { private BySelector mBySettingsSidePanel; - @Override - protected void setUp() throws Exception { - super.setUp(); - mLiveChannelsHelper.assertAppStarted(); - pressKeysForChannel(TvTestInputConstants.CH_1_DEFAULT_DONT_MODIFY); - getInstrumentation().waitForIdleSync(); - mBySettingsSidePanel = mSidePanelHelper.bySidePanelTitled( - R.string.side_panel_title_settings); + @Before + public void setUp() throws Exception { + controller.liveChannelsHelper.assertAppStarted(); + controller.pressKeysForChannel(TvTestInputConstants.CH_1_DEFAULT_DONT_MODIFY); + controller.waitForIdleSync(); + mBySettingsSidePanel = + controller.sidePanelHelper.bySidePanelTitled(R.string.side_panel_title_settings); } + @Test public void testSettingsCancel() { - mMenuHelper.assertPressOptionsSettings(); - BySelector byChannelSourcesSidePanel = mSidePanelHelper - .bySidePanelTitled(R.string.settings_channel_source_item_customize_channels); - assertWaitForCondition(mDevice, Until.hasObject(byChannelSourcesSidePanel)); - mDevice.pressBack(); - assertWaitForCondition(mDevice, Until.gone(byChannelSourcesSidePanel)); - assertHas(mDevice, Constants.MENU, false); + controller.menuHelper.assertPressOptionsSettings(); + BySelector byChannelSourcesSidePanel = + controller.sidePanelHelper.bySidePanelTitled( + R.string.settings_channel_source_item_customize_channels); + controller.assertWaitForCondition(Until.hasObject(byChannelSourcesSidePanel)); + controller.pressBack(); + controller.assertWaitForCondition(Until.gone(byChannelSourcesSidePanel)); + controller.assertHas(Constants.MENU, false); } + @Test public void testClosedCaptionsCancel() { - mMenuHelper.assertPressOptionsClosedCaptions(); - BySelector byClosedCaptionSidePanel = mSidePanelHelper - .bySidePanelTitled(R.string.side_panel_title_closed_caption); - assertWaitForCondition(mDevice, Until.hasObject(byClosedCaptionSidePanel)); - mDevice.pressBack(); - assertWaitForCondition(mDevice, Until.gone(byClosedCaptionSidePanel)); - assertHas(mDevice, Constants.MENU, false); + controller.menuHelper.assertPressOptionsClosedCaptions(); + BySelector byClosedCaptionSidePanel = + controller.sidePanelHelper.bySidePanelTitled( + R.string.side_panel_title_closed_caption); + controller.assertWaitForCondition(Until.hasObject(byClosedCaptionSidePanel)); + controller.pressBack(); + controller.assertWaitForCondition(Until.gone(byClosedCaptionSidePanel)); + controller.assertHas(Constants.MENU, false); } + @Test public void testDisplayModeCancel() { ChannelStateData data = new ChannelStateData(); - data.mTvTrackInfos.add(com.android.tv.testing.Constants.SVGA_VIDEO_TRACK); - data.mSelectedVideoTrackId = com.android.tv.testing.Constants.SVGA_VIDEO_TRACK - .getId(); - updateThenTune(data, TvTestInputConstants.CH_2); + data.mTvTrackInfos.add(com.android.tv.testing.constants.Constants.SVGA_VIDEO_TRACK); + data.mSelectedVideoTrackId = + com.android.tv.testing.constants.Constants.SVGA_VIDEO_TRACK.getId(); + controller.updateThenTune(data, TvTestInputConstants.CH_2); - mMenuHelper.assertPressOptionsDisplayMode(); - BySelector byDisplayModeSidePanel = mSidePanelHelper - .bySidePanelTitled(R.string.side_panel_title_display_mode); - assertWaitForCondition(mDevice, Until.hasObject(byDisplayModeSidePanel)); - mDevice.pressBack(); - assertWaitForCondition(mDevice, Until.gone(byDisplayModeSidePanel)); - assertHas(mDevice, Constants.MENU, false); + controller.menuHelper.assertPressOptionsDisplayMode(); + BySelector byDisplayModeSidePanel = + controller.sidePanelHelper.bySidePanelTitled( + R.string.side_panel_title_display_mode); + controller.assertWaitForCondition(Until.hasObject(byDisplayModeSidePanel)); + controller.pressBack(); + controller.assertWaitForCondition(Until.gone(byDisplayModeSidePanel)); + controller.assertHas(Constants.MENU, false); } + @Test public void testMenu() { - mDevice.pressMenu(); + controller.pressMenu(); - assertWaitForCondition(mDevice, Until.hasObject(Constants.MENU)); - assertHas(mDevice, mMenuHelper.getByChannels(), true); + controller.assertWaitForCondition(Until.hasObject(Constants.MENU)); + controller.assertHas(controller.menuHelper.getByChannels(), true); } + @Test public void testMultiAudioCancel() { ChannelStateData data = new ChannelStateData(); - data.mTvTrackInfos.add(com.android.tv.testing.Constants.GENERIC_AUDIO_TRACK); - updateThenTune(data, TvTestInputConstants.CH_2); + data.mTvTrackInfos.add(com.android.tv.testing.constants.Constants.GENERIC_AUDIO_TRACK); + controller.updateThenTune(data, TvTestInputConstants.CH_2); - mMenuHelper.assertPressOptionsMultiAudio(); - BySelector byMultiAudioSidePanel = mSidePanelHelper - .bySidePanelTitled(R.string.side_panel_title_multi_audio); - assertWaitForCondition(mDevice, Until.hasObject(byMultiAudioSidePanel)); - mDevice.pressBack(); - assertWaitForCondition(mDevice, Until.gone(byMultiAudioSidePanel)); - assertHas(mDevice, Constants.MENU, false); + controller.menuHelper.assertPressOptionsMultiAudio(); + BySelector byMultiAudioSidePanel = + controller.sidePanelHelper.bySidePanelTitled(R.string.side_panel_title_multi_audio); + controller.assertWaitForCondition(Until.hasObject(byMultiAudioSidePanel)); + controller.pressBack(); + controller.assertWaitForCondition(Until.gone(byMultiAudioSidePanel)); + controller.assertHas(Constants.MENU, false); } + @Ignore("b/72156196") + @Test public void testPinCancel() { - mMenuHelper.showMenu(); - mMenuHelper.assertPressOptionsSettings(); - assertWaitForCondition(mDevice, Until.hasObject(mBySettingsSidePanel)); - mSidePanelHelper.assertNavigateToItem(R.string.settings_parental_controls); - mDevice.pressDPadCenter(); - DialogHelper dialogHelper = new DialogHelper(mDevice, mTargetResources); + controller.menuHelper.showMenu(); + controller.menuHelper.assertPressOptionsSettings(); + controller.assertWaitForCondition(Until.hasObject(mBySettingsSidePanel)); + controller.sidePanelHelper.assertNavigateToItem(R.string.settings_parental_controls); + controller.pressDPadCenter(); + DialogHelper dialogHelper = + new DialogHelper(controller.getUiDevice(), controller.getTargetResources()); dialogHelper.assertWaitForPinDialogOpen(); - mDevice.pressBack(); + controller.pressBack(); dialogHelper.assertWaitForPinDialogClose(); - assertHas(mDevice, Constants.MENU, false); + controller.assertHas(Constants.MENU, false); } } diff --git a/tests/func/src/com/android/tv/tests/ui/LiveChannelsTestCase.java b/tests/func/src/com/android/tv/tests/ui/LiveChannelsTestCase.java deleted file mode 100644 index e306e6c6..00000000 --- a/tests/func/src/com/android/tv/tests/ui/LiveChannelsTestCase.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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.tests.ui; - -import static com.android.tv.testing.uihelper.UiDeviceAsserts.assertWaitForCondition; - -import android.content.Context; -import android.content.res.Resources; -import android.support.test.uiautomator.UiDevice; -import android.support.test.uiautomator.Until; -import android.test.InstrumentationTestCase; - -import com.android.tv.testing.ChannelInfo; -import com.android.tv.testing.testinput.ChannelStateData; -import com.android.tv.testing.testinput.TestInputControlConnection; -import com.android.tv.testing.testinput.TestInputControlUtils; -import com.android.tv.testing.uihelper.Constants; -import com.android.tv.testing.uihelper.LiveChannelsUiDeviceHelper; -import com.android.tv.testing.uihelper.MenuHelper; -import com.android.tv.testing.uihelper.SidePanelHelper; -import com.android.tv.testing.uihelper.UiDeviceUtils; - -/** - * Base test case for LiveChannel UI tests. - */ -public abstract class LiveChannelsTestCase extends InstrumentationTestCase { - protected final TestInputControlConnection mConnection = new TestInputControlConnection(); - - protected UiDevice mDevice; - protected Resources mTargetResources; - protected MenuHelper mMenuHelper; - protected SidePanelHelper mSidePanelHelper; - protected LiveChannelsUiDeviceHelper mLiveChannelsHelper; - - @Override - protected void setUp() throws Exception { - super.setUp(); - Context context = getInstrumentation().getContext(); - context.bindService(TestInputControlUtils.createIntent(), mConnection, - Context.BIND_AUTO_CREATE); - mDevice = UiDevice.getInstance(getInstrumentation()); - mTargetResources = getInstrumentation().getTargetContext().getResources(); - mMenuHelper = new MenuHelper(mDevice, mTargetResources); - mSidePanelHelper = new SidePanelHelper(mDevice, mTargetResources); - mLiveChannelsHelper = new LiveChannelsUiDeviceHelper(mDevice, mTargetResources, context); - } - - @Override - protected void tearDown() throws Exception { - if (mConnection.isBound()) { - getInstrumentation().getContext().unbindService(mConnection); - } - - // TODO: robustly handle left over pops from failed tests. - // Clear any side panel, menu, ... - // Scene container should not be checked here because pressing the BACK key in some scenes - // might launch the home screen. - if (mDevice.hasObject(Constants.SIDE_PANEL) || mDevice.hasObject(Constants.MENU) || mDevice - .hasObject(Constants.PROGRAM_GUIDE)) { - mDevice.pressBack(); - } - // To destroy the activity to make sure next test case's activity launch check works well. - mDevice.pressBack(); - super.tearDown(); - } - - /** - * Send the keys for the channel number of {@code channel} and press the DPAD - * center. - * - * <p>Usually this will tune to the given channel. - */ - protected void pressKeysForChannel(ChannelInfo channel) { - UiDeviceUtils.pressKeys(mDevice, channel.number); - assertWaitForCondition(mDevice, Until.hasObject(Constants.KEYPAD_CHANNEL_SWITCH)); - mDevice.pressDPadCenter(); - } - - /** - * Update the channel state to {@code data} then tune to that channel. - * - * @param data the state to update the channel with. - * @param channel the channel to tune to - */ - protected void updateThenTune(ChannelStateData data, ChannelInfo channel) { - mConnection.updateChannelState(channel, data); - pressKeysForChannel(channel); - } -} diff --git a/tests/func/src/com/android/tv/tests/ui/LiveChannelsTestController.java b/tests/func/src/com/android/tv/tests/ui/LiveChannelsTestController.java new file mode 100644 index 00000000..03d30ca4 --- /dev/null +++ b/tests/func/src/com/android/tv/tests/ui/LiveChannelsTestController.java @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2018 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.tests.ui; + +import static junit.framework.Assert.assertTrue; + +import android.app.Instrumentation; +import android.app.UiAutomation; +import android.content.Context; +import android.content.res.Resources; +import android.os.Build; +import android.os.SystemClock; +import android.support.test.InstrumentationRegistry; +import android.support.test.uiautomator.BySelector; +import android.support.test.uiautomator.Configurator; +import android.support.test.uiautomator.SearchCondition; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.Until; +import android.view.InputDevice; +import android.view.KeyEvent; +import com.android.tv.testing.data.ChannelInfo; +import com.android.tv.testing.testinput.ChannelStateData; +import com.android.tv.testing.testinput.TestInputControlConnection; +import com.android.tv.testing.testinput.TestInputControlUtils; +import com.android.tv.testing.uihelper.Constants; +import com.android.tv.testing.uihelper.LiveChannelsUiDeviceHelper; +import com.android.tv.testing.uihelper.MenuHelper; +import com.android.tv.testing.uihelper.SidePanelHelper; +import com.android.tv.testing.uihelper.UiDeviceAsserts; +import com.android.tv.testing.uihelper.UiDeviceUtils; +import org.junit.rules.ExternalResource; + +/** UIHelpers and TestInputController for LiveChannels. */ +public class LiveChannelsTestController extends ExternalResource { + + private final TestInputControlConnection mConnection = new TestInputControlConnection(); + + public MenuHelper menuHelper; + public SidePanelHelper sidePanelHelper; + public LiveChannelsUiDeviceHelper liveChannelsHelper; + + private UiDevice mDevice; + private Resources mTargetResources; + private Instrumentation mInstrumentation; + + private void assertPressKeyUp(int keyCode, boolean sync) { + assertPressKey(KeyEvent.ACTION_UP, keyCode, sync); + } + + private void assertPressKey(int action, int keyCode, boolean sync) { + long eventTime = SystemClock.uptimeMillis(); + KeyEvent event = + new KeyEvent( + eventTime, + eventTime, + action, + keyCode, + 0, + 0, + -1, + 0, + 0, + InputDevice.SOURCE_KEYBOARD); + assertTrue("Failed to inject key up event:" + event, injectEvent(event, sync)); + } + + private UiAutomation getUiAutomation() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + int flags = Configurator.getInstance().getUiAutomationFlags(); + return mInstrumentation.getUiAutomation(flags); + } else { + return mInstrumentation.getUiAutomation(); + } + } + + @Override + protected void before() throws Exception { + mInstrumentation = InstrumentationRegistry.getInstrumentation(); + Context context = mInstrumentation.getContext(); + context.bindService( + TestInputControlUtils.createIntent(), mConnection, Context.BIND_AUTO_CREATE); + mDevice = UiDevice.getInstance(mInstrumentation); + mTargetResources = mInstrumentation.getTargetContext().getResources(); + menuHelper = new MenuHelper(mDevice, mTargetResources); + sidePanelHelper = new SidePanelHelper(mDevice, mTargetResources); + liveChannelsHelper = new LiveChannelsUiDeviceHelper(mDevice, mTargetResources, context); + } + + @Override + protected void after() { + if (mConnection.isBound()) { + mInstrumentation.getContext().unbindService(mConnection); + } + + // TODO: robustly handle left over pops from failed tests. + // Clear any side panel, menu, ... + // Scene container should not be checked here because pressing the BACK key in some scenes + // might launch the home screen. + if (mDevice.hasObject(Constants.SIDE_PANEL) + || mDevice.hasObject(Constants.MENU) + || mDevice.hasObject(Constants.PROGRAM_GUIDE)) { + mDevice.pressBack(); + } + // To destroy the activity to make sure next test case's activity launch check works well. + mDevice.pressBack(); + } + + /** + * Update the channel state to {@code data} then tune to that channel. + * + * @param data the state to update the channel with. + * @param channel the channel to tune to + */ + protected void updateThenTune(ChannelStateData data, ChannelInfo channel) { + mConnection.updateChannelState(channel, data); + pressKeysForChannel(channel); + } + + /** + * Send the keys for the channel number of {@code channel} and press the DPAD center. + * + * <p>Usually this will tune to the given channel. + */ + public void pressKeysForChannel(ChannelInfo channel) { + UiDeviceUtils.pressKeys(mDevice, channel.number); + UiDeviceAsserts.assertWaitForCondition( + mDevice, Until.hasObject(Constants.KEYPAD_CHANNEL_SWITCH)); + mDevice.pressDPadCenter(); + } + + public void assertHas(BySelector bySelector, boolean expected) { + UiDeviceAsserts.assertHas(mDevice, bySelector, expected); + } + + public void assertWaitForCondition(SearchCondition<Boolean> booleanSearchCondition) { + UiDeviceAsserts.assertWaitForCondition(mDevice, booleanSearchCondition); + } + + public void assertWaitForCondition(SearchCondition<Boolean> gone, long timeout) { + UiDeviceAsserts.assertWaitForCondition(mDevice, gone, timeout); + } + + public void assertWaitUntilFocused(BySelector bySelector) { + UiDeviceAsserts.assertWaitUntilFocused(mDevice, bySelector); + } + + public Resources getTargetResources() { + return mTargetResources; + } + + public UiDevice getUiDevice() { + return mDevice; + } + + public boolean injectEvent(KeyEvent event, boolean sync) { + return getUiAutomation().injectInputEvent(event, sync); + } + + public void pressBack() { + mDevice.pressBack(); + } + + public void pressDPadCenter() { + pressDPadCenter(1); + } + + public void pressDPadCenter(int repeat) { + UiDevice.getInstance(mInstrumentation).waitForIdle(); + for (int i = 0; i < repeat; ++i) { + assertPressKey(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, false); + if (i < repeat - 1) { + assertPressKeyUp(KeyEvent.KEYCODE_DPAD_CENTER, false); + } + } + // Send last key event synchronously. + assertPressKeyUp(KeyEvent.KEYCODE_DPAD_CENTER, true); + } + + public void pressDPadDown() { + mDevice.pressDPadDown(); + } + + public void pressDPadLeft() { + mDevice.pressDPadLeft(); + } + + public void pressDPadRight() { + mDevice.pressDPadRight(); + } + + public void pressDPadUp() { + mDevice.pressDPadUp(); + } + + public void pressEnter() { + mDevice.pressEnter(); + } + + public void pressHome() { + mDevice.pressHome(); + } + + public void pressKeyCode(int keyCode) { + mDevice.pressKeyCode(keyCode); + } + + public void pressMenu() { + mDevice.pressMenu(); + } + + public void waitForIdle() { + mDevice.waitForIdle(); + } + + public void waitForIdleSync() { + mInstrumentation.waitForIdleSync(); + } +} diff --git a/tests/func/src/com/android/tv/tests/ui/ParentalControlsTest.java b/tests/func/src/com/android/tv/tests/ui/ParentalControlsTest.java index 93d14bde..ee039d7c 100644 --- a/tests/func/src/com/android/tv/tests/ui/ParentalControlsTest.java +++ b/tests/func/src/com/android/tv/tests/ui/ParentalControlsTest.java @@ -16,139 +16,169 @@ package com.android.tv.tests.ui; -import static com.android.tv.testing.uihelper.UiDeviceAsserts.assertWaitForCondition; +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertTrue; -import android.support.test.filters.SmallTest; +import android.support.test.filters.MediumTest; import android.support.test.uiautomator.BySelector; import android.support.test.uiautomator.UiObject2; import android.support.test.uiautomator.Until; - import com.android.tv.R; import com.android.tv.testing.uihelper.ByResource; import com.android.tv.testing.uihelper.DialogHelper; +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; -@SmallTest -public class ParentalControlsTest extends LiveChannelsTestCase { - +/** Tests for {@link com.android.tv.ui.sidepanel.parentalcontrols.ParentalControlsFragment} */ +@MediumTest +@RunWith(JUnit4.class) +public class ParentalControlsTest { + @Rule public final LiveChannelsTestController controller = new LiveChannelsTestController(); private BySelector mBySettingsSidePanel; - @Override - protected void setUp() throws Exception { - super.setUp(); - mLiveChannelsHelper.assertAppStarted(); - mBySettingsSidePanel = mSidePanelHelper.bySidePanelTitled( - R.string.side_panel_title_settings); - prepareParentalControl(); + @Before + public void setUp() throws Exception { + + controller.liveChannelsHelper.assertAppStarted(); + mBySettingsSidePanel = + controller.sidePanelHelper.bySidePanelTitled(R.string.side_panel_title_settings); + // TODO(b/72154681): prepareParentalControl(); } - @Override - protected void tearDown() throws Exception { + @After + public void tearDown() throws Exception { switchParentalControl(R.string.option_toggle_parental_controls_on); - super.tearDown(); } + @Test + public void placeHolder() { + // there must be at least one test. + } + + @Ignore("b/72154681") + @Test public void testRatingDependentSelect() { // Show ratings fragment. - BySelector bySidePanel = mSidePanelHelper.bySidePanelTitled( - R.string.option_program_restrictions); - assertWaitForCondition(mDevice, Until.hasObject(bySidePanel)); - mSidePanelHelper.assertNavigateToItem(R.string.option_ratings); - mDevice.pressDPadCenter(); + BySelector bySidePanel = + controller.sidePanelHelper.bySidePanelTitled(R.string.option_program_restrictions); + controller.assertWaitForCondition(Until.hasObject(bySidePanel)); + controller.sidePanelHelper.assertNavigateToItem(R.string.option_ratings); + controller.pressDPadCenter(); // Block rating 6 and rating 12. Check if dependent select works well. - bySidePanel = mSidePanelHelper.bySidePanelTitled(R.string.option_ratings); - assertWaitForCondition(mDevice, Until.hasObject(bySidePanel)); + bySidePanel = controller.sidePanelHelper.bySidePanelTitled(R.string.option_ratings); + controller.assertWaitForCondition(Until.hasObject(bySidePanel)); // Test on blocking and unblocking Japanese rating. int blockAge = 6; int unBlockAge = 12; int maxAge = 20; int minAge = 4; for (int age = minAge; age <= maxAge; age++) { - UiObject2 ratingCheckBox = mSidePanelHelper.assertNavigateToItem(String.valueOf(age)) - .findObject(ByResource.id(mTargetResources, R.id.check_box)); + UiObject2 ratingCheckBox = + controller + .sidePanelHelper + .assertNavigateToItem(String.valueOf(age)) + .findObject( + ByResource.id(controller.getTargetResources(), R.id.check_box)); if (ratingCheckBox.isChecked()) { - mDevice.pressDPadCenter(); + controller.pressDPadCenter(); } } - mSidePanelHelper.assertNavigateToItem(String.valueOf(blockAge)); - mDevice.pressDPadCenter(); + controller.sidePanelHelper.assertNavigateToItem(String.valueOf(blockAge)); + controller.pressDPadCenter(); assertRatingViewIsChecked(minAge, maxAge, blockAge, true); - mSidePanelHelper.assertNavigateToItem(String.valueOf(unBlockAge)); - mDevice.pressDPadCenter(); + controller.sidePanelHelper.assertNavigateToItem(String.valueOf(unBlockAge)); + controller.pressDPadCenter(); assertRatingViewIsChecked(minAge, maxAge, unBlockAge, false); - mDevice.pressBack(); - mDevice.pressBack(); - getInstrumentation().waitForIdleSync(); + controller.pressBack(); + controller.pressBack(); + controller.waitForIdleSync(); } - private void assertRatingViewIsChecked(int minAge, int maxAge, int selectedAge, - boolean expectedValue) { + private void assertRatingViewIsChecked( + int minAge, int maxAge, int selectedAge, boolean expectedValue) { for (int age = minAge; age <= maxAge; age++) { - UiObject2 ratingCheckBox = mSidePanelHelper.assertNavigateToItem(String.valueOf(age)) - .findObject(ByResource.id(mTargetResources, R.id.check_box)); + UiObject2 ratingCheckBox = + controller + .sidePanelHelper + .assertNavigateToItem(String.valueOf(age)) + .findObject( + ByResource.id(controller.getTargetResources(), R.id.check_box)); if (age < selectedAge) { assertTrue("The lower rating age should be unblocked", !ratingCheckBox.isChecked()); } else if (age > selectedAge) { assertTrue("The higher rating age should be blocked", ratingCheckBox.isChecked()); } else { - assertEquals("The rating for age " + selectedAge + " isBlocked ", expectedValue, + assertEquals( + "The rating for age " + selectedAge + " isBlocked ", + expectedValue, ratingCheckBox.isChecked()); } } } /** - * Prepare the need for testRatingDependentSelect. - * 1. Turn on parental control if it's off. - * 2. Make sure Japan rating system is selected. + * Prepare the need for testRatingDependentSelect. 1. Turn on parental control if it's off. 2. + * Make sure Japan rating system is selected. */ private void prepareParentalControl() { showParentalControl(); switchParentalControl(R.string.option_toggle_parental_controls_off); // Show all rating systems. - mSidePanelHelper.assertNavigateToItem(R.string.option_program_restrictions); - mDevice.pressDPadCenter(); - BySelector bySidePanel = mSidePanelHelper.bySidePanelTitled( - R.string.option_program_restrictions); - assertWaitForCondition(mDevice, Until.hasObject(bySidePanel)); - mSidePanelHelper.assertNavigateToItem(R.string.option_country_rating_systems); - mDevice.pressDPadCenter(); - bySidePanel = mSidePanelHelper.bySidePanelTitled(R.string.option_country_rating_systems); - assertWaitForCondition(mDevice,Until.hasObject(bySidePanel)); - mSidePanelHelper.assertNavigateToItem(R.string.option_see_all_rating_systems); - mDevice.pressDPadCenter(); + controller.sidePanelHelper.assertNavigateToItem(R.string.option_program_restrictions); + controller.pressDPadCenter(); + BySelector bySidePanel = + controller.sidePanelHelper.bySidePanelTitled(R.string.option_program_restrictions); + controller.assertWaitForCondition(Until.hasObject(bySidePanel)); + controller.sidePanelHelper.assertNavigateToItem(R.string.option_country_rating_systems); + controller.pressDPadCenter(); + bySidePanel = + controller.sidePanelHelper.bySidePanelTitled( + R.string.option_country_rating_systems); + controller.assertWaitForCondition(Until.hasObject(bySidePanel)); + controller.sidePanelHelper.assertNavigateToItem(R.string.option_see_all_rating_systems); + controller.pressDPadCenter(); // Make sure Japan rating system is selected. - UiObject2 ratingSystemCheckBox = mSidePanelHelper.assertNavigateToItem("Japan") - .findObject(ByResource.id(mTargetResources, R.id.check_box)); + UiObject2 ratingSystemCheckBox = + controller + .sidePanelHelper + .assertNavigateToItem("Japan") + .findObject(ByResource.id(controller.getTargetResources(), R.id.check_box)); if (!ratingSystemCheckBox.isChecked()) { - mDevice.pressDPadCenter(); - getInstrumentation().waitForIdleSync(); + controller.pressDPadCenter(); + controller.waitForIdleSync(); } - mDevice.pressBack(); + controller.pressBack(); } private void switchParentalControl(int oppositeStateResId) { - BySelector bySidePanel = mSidePanelHelper.byViewText(oppositeStateResId); - if (mDevice.hasObject(bySidePanel)) { - mSidePanelHelper.assertNavigateToItem(oppositeStateResId); - mDevice.pressDPadCenter(); - getInstrumentation().waitForIdleSync(); + BySelector bySidePanel = controller.sidePanelHelper.byViewText(oppositeStateResId); + if (controller.getUiDevice().hasObject(bySidePanel)) { + controller.sidePanelHelper.assertNavigateToItem(oppositeStateResId); + controller.pressDPadCenter(); + controller.waitForIdleSync(); } } private void showParentalControl() { // Show menu and select parental controls. - mMenuHelper.showMenu(); - mMenuHelper.assertPressOptionsSettings(); - assertWaitForCondition(mDevice, Until.hasObject(mBySettingsSidePanel)); - mSidePanelHelper.assertNavigateToItem(R.string.settings_parental_controls); - mDevice.pressDPadCenter(); + controller.menuHelper.showMenu(); + controller.menuHelper.assertPressOptionsSettings(); + controller.assertWaitForCondition(Until.hasObject(mBySettingsSidePanel)); + controller.sidePanelHelper.assertNavigateToItem(R.string.settings_parental_controls); + controller.pressDPadCenter(); // Enter pin code. - DialogHelper dialogHelper = new DialogHelper(mDevice, mTargetResources); + DialogHelper dialogHelper = + new DialogHelper(controller.getUiDevice(), controller.getTargetResources()); dialogHelper.assertWaitForPinDialogOpen(); dialogHelper.enterPinCodes(); dialogHelper.assertWaitForPinDialogClose(); - BySelector bySidePanel = mSidePanelHelper.bySidePanelTitled( - R.string.menu_parental_controls); - assertWaitForCondition(mDevice, Until.hasObject(bySidePanel)); + BySelector bySidePanel = + controller.sidePanelHelper.bySidePanelTitled(R.string.menu_parental_controls); + controller.assertWaitForCondition(Until.hasObject(bySidePanel)); } } diff --git a/tests/func/src/com/android/tv/tests/ui/PlayControlsRowViewTest.java b/tests/func/src/com/android/tv/tests/ui/PlayControlsRowViewTest.java index 82c6a810..7c982782 100644 --- a/tests/func/src/com/android/tv/tests/ui/PlayControlsRowViewTest.java +++ b/tests/func/src/com/android/tv/tests/ui/PlayControlsRowViewTest.java @@ -19,121 +19,136 @@ package com.android.tv.tests.ui; import static com.android.tv.testing.uihelper.Constants.CHANNEL_BANNER; import static com.android.tv.testing.uihelper.Constants.FOCUSED_VIEW; import static com.android.tv.testing.uihelper.Constants.MENU; -import static com.android.tv.testing.uihelper.UiDeviceAsserts.assertWaitForCondition; +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; import android.support.test.filters.SmallTest; import android.support.test.uiautomator.BySelector; import android.support.test.uiautomator.UiObject2; import android.support.test.uiautomator.Until; import android.view.KeyEvent; - import com.android.tv.R; import com.android.tv.testing.testinput.TvTestInputConstants; +import com.android.tv.testing.uihelper.Constants; import com.android.tv.testing.uihelper.DialogHelper; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; @SmallTest -public class PlayControlsRowViewTest extends LiveChannelsTestCase { - private static final String BUTTON_ID_PLAY_PAUSE = "com.android.tv:id/play_pause"; +@RunWith(JUnit4.class) +public class PlayControlsRowViewTest { + private static final String BUTTON_ID_PLAY_PAUSE = Constants.TV_APP_PACKAGE + ":id/play_pause"; + @Rule public final LiveChannelsTestController controller = new LiveChannelsTestController(); private BySelector mBySettingsSidePanel; - @Override - protected void setUp() throws Exception { - super.setUp(); - mLiveChannelsHelper.assertAppStarted(); - pressKeysForChannel(TvTestInputConstants.CH_2); + @Before + public void setUp() throws Exception { + + controller.liveChannelsHelper.assertAppStarted(); + controller.pressKeysForChannel(TvTestInputConstants.CH_2); // Wait until KeypadChannelSwitchView closes. - assertWaitForCondition(mDevice, Until.hasObject(CHANNEL_BANNER)); + controller.assertWaitForCondition(Until.hasObject(CHANNEL_BANNER)); // Tune to a new channel to ensure that the channel is changed. - mDevice.pressDPadUp(); - getInstrumentation().waitForIdleSync(); - mBySettingsSidePanel = mSidePanelHelper.bySidePanelTitled( - R.string.side_panel_title_settings); + controller.pressDPadUp(); + controller.waitForIdleSync(); + mBySettingsSidePanel = + controller.sidePanelHelper.bySidePanelTitled(R.string.side_panel_title_settings); } - /** - * Test the normal case. The play/pause button should have focus initially. - */ + /** Test the normal case. The play/pause button should have focus initially. */ + @Ignore("b/72154153") + @Test public void testFocusedViewInNormalCase() { - mMenuHelper.showMenu(); - mMenuHelper.assertNavigateToPlayControlsRow(); + controller.menuHelper.showMenu(); + controller.menuHelper.assertNavigateToPlayControlsRow(); assertButtonHasFocus(BUTTON_ID_PLAY_PAUSE); - mDevice.pressBack(); + controller.pressBack(); } /** - * Tests the case when the forwarding action is disabled. - * In this case, the button corresponding to the action is disabled, so play/pause button should - * have the focus. + * Tests the case when the forwarding action is disabled. In this case, the button corresponding + * to the action is disabled, so play/pause button should have the focus. */ + @Test public void testFocusedViewWithDisabledActionForward() { // Fast forward button - mDevice.pressKeyCode(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD); - mMenuHelper.assertWaitForMenu(); + controller.pressKeyCode(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD); + controller.menuHelper.assertWaitForMenu(); assertButtonHasFocus(BUTTON_ID_PLAY_PAUSE); - mDevice.pressBack(); + controller.pressBack(); // Next button - mDevice.pressKeyCode(KeyEvent.KEYCODE_MEDIA_NEXT); - mMenuHelper.assertWaitForMenu(); + controller.pressKeyCode(KeyEvent.KEYCODE_MEDIA_NEXT); + controller.menuHelper.assertWaitForMenu(); assertButtonHasFocus(BUTTON_ID_PLAY_PAUSE); - mDevice.pressBack(); + controller.pressBack(); } + @Test public void testFocusedViewInMenu() { - mMenuHelper.showMenu(); - mDevice.pressKeyCode(KeyEvent.KEYCODE_MEDIA_PLAY); + controller.menuHelper.showMenu(); + controller.pressKeyCode(KeyEvent.KEYCODE_MEDIA_PLAY); assertButtonHasFocus(BUTTON_ID_PLAY_PAUSE); - mMenuHelper.assertNavigateToRow(R.string.menu_title_channels); - mDevice.pressKeyCode(KeyEvent.KEYCODE_MEDIA_NEXT); + controller.menuHelper.assertNavigateToRow(R.string.menu_title_channels); + controller.pressKeyCode(KeyEvent.KEYCODE_MEDIA_NEXT); assertButtonHasFocus(BUTTON_ID_PLAY_PAUSE); } + @Ignore("b/72154153") + @Test public void testKeepPausedWhileParentalControlChange() { // Pause the playback. - mDevice.pressKeyCode(KeyEvent.KEYCODE_MEDIA_PAUSE); - mMenuHelper.assertWaitForMenu(); + controller.pressKeyCode(KeyEvent.KEYCODE_MEDIA_PAUSE); + controller.menuHelper.assertWaitForMenu(); assertButtonHasFocus(BUTTON_ID_PLAY_PAUSE); // Show parental controls fragment. - mMenuHelper.assertPressOptionsSettings(); - assertWaitForCondition(mDevice, Until.hasObject(mBySettingsSidePanel)); - mSidePanelHelper.assertNavigateToItem(R.string.settings_parental_controls); - mDevice.pressDPadCenter(); - DialogHelper dialogHelper = new DialogHelper(mDevice, mTargetResources); + controller.menuHelper.assertPressOptionsSettings(); + controller.assertWaitForCondition(Until.hasObject(mBySettingsSidePanel)); + controller.sidePanelHelper.assertNavigateToItem(R.string.settings_parental_controls); + controller.pressDPadCenter(); + DialogHelper dialogHelper = + new DialogHelper(controller.getUiDevice(), controller.getTargetResources()); dialogHelper.assertWaitForPinDialogOpen(); dialogHelper.enterPinCodes(); dialogHelper.assertWaitForPinDialogClose(); - BySelector bySidePanel = mSidePanelHelper.bySidePanelTitled( - R.string.menu_parental_controls); - assertWaitForCondition(mDevice, Until.hasObject(bySidePanel)); - mDevice.pressEnter(); - mDevice.pressEnter(); - mDevice.pressBack(); - mDevice.pressBack(); + BySelector bySidePanel = + controller.sidePanelHelper.bySidePanelTitled(R.string.menu_parental_controls); + controller.assertWaitForCondition(Until.hasObject(bySidePanel)); + controller.pressEnter(); + controller.pressEnter(); + controller.pressBack(); + controller.pressBack(); // Return to the main menu. - mMenuHelper.assertWaitForMenu(); + controller.menuHelper.assertWaitForMenu(); assertButtonHasFocus(BUTTON_ID_PLAY_PAUSE); } + // TODO("b/70727167"): fix tests + @Test public void testKeepPausedAfterVisitingHome() { // Pause the playback. - mDevice.pressKeyCode(KeyEvent.KEYCODE_MEDIA_PAUSE); - mMenuHelper.assertWaitForMenu(); + controller.pressKeyCode(KeyEvent.KEYCODE_MEDIA_PAUSE); + controller.menuHelper.assertWaitForMenu(); assertButtonHasFocus(BUTTON_ID_PLAY_PAUSE); // Press HOME twice to visit the home screen and return to Live TV. - mDevice.pressHome(); + controller.pressHome(); // Wait until home screen is shown. - mDevice.waitForIdle(); - mDevice.pressHome(); + controller.waitForIdle(); + controller.pressHome(); // Wait until TV is resumed. - mDevice.waitForIdle(); + controller.waitForIdle(); // Return to the main menu. - mMenuHelper.assertWaitForMenu(); + controller.menuHelper.assertWaitForMenu(); assertButtonHasFocus(BUTTON_ID_PLAY_PAUSE); } private void assertButtonHasFocus(String buttonId) { - UiObject2 menu = mDevice.findObject(MENU); + UiObject2 menu = controller.getUiDevice().findObject(MENU); UiObject2 focusedView = menu.findObject(FOCUSED_VIEW); assertNotNull("Play controls row doesn't have a focused child.", focusedView); UiObject2 focusedButtonGroup = focusedView.getParent(); diff --git a/tests/func/src/com/android/tv/tests/ui/ProgramGuideTest.java b/tests/func/src/com/android/tv/tests/ui/ProgramGuideTest.java index 06c76b3b..4adf448a 100644 --- a/tests/func/src/com/android/tv/tests/ui/ProgramGuideTest.java +++ b/tests/func/src/com/android/tv/tests/ui/ProgramGuideTest.java @@ -15,28 +15,28 @@ */ package com.android.tv.tests.ui; -import static com.android.tv.testing.uihelper.UiDeviceAsserts.assertHas; -import static com.android.tv.testing.uihelper.UiDeviceAsserts.assertWaitForCondition; - -import android.support.test.filters.LargeTest; +import android.support.test.filters.MediumTest; import android.support.test.uiautomator.Until; - import com.android.tv.guide.ProgramGuide; import com.android.tv.testing.uihelper.Constants; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; -/** - * Tests for {@link ProgramGuide}. - */ -@LargeTest -public class ProgramGuideTest extends LiveChannelsTestCase { +/** Tests for {@link ProgramGuide}. */ +@MediumTest +@RunWith(JUnit4.class) +public class ProgramGuideTest { + @Rule public final LiveChannelsTestController controller = new LiveChannelsTestController(); + @Test public void testCancel() { - mLiveChannelsHelper.assertAppStarted(); - mMenuHelper.assertPressProgramGuide(); - assertWaitForCondition(mDevice, - Until.hasObject(Constants.PROGRAM_GUIDE)); - mDevice.pressBack(); - assertWaitForCondition(mDevice, Until.gone(Constants.PROGRAM_GUIDE)); - assertHas(mDevice, Constants.MENU, false); + controller.liveChannelsHelper.assertAppStarted(); + controller.menuHelper.assertPressProgramGuide(); + controller.assertWaitForCondition(Until.hasObject(Constants.PROGRAM_GUIDE)); + controller.pressBack(); + controller.assertWaitForCondition(Until.gone(Constants.PROGRAM_GUIDE)); + controller.assertHas(Constants.MENU, false); } } diff --git a/tests/func/src/com/android/tv/tests/ui/TimeoutTest.java b/tests/func/src/com/android/tv/tests/ui/TimeoutTest.java index 9bf2ac50..4b6befe4 100644 --- a/tests/func/src/com/android/tv/tests/ui/TimeoutTest.java +++ b/tests/func/src/com/android/tv/tests/ui/TimeoutTest.java @@ -15,40 +15,54 @@ */ package com.android.tv.tests.ui; -import static com.android.tv.testing.uihelper.UiDeviceAsserts.assertHas; -import static com.android.tv.testing.uihelper.UiDeviceAsserts.assertWaitForCondition; - import android.support.test.filters.LargeTest; import android.support.test.uiautomator.Until; - import com.android.tv.R; import com.android.tv.testing.uihelper.Constants; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; /** * Test timeout events like the menu despairing after no input. - * <p> - * <b>WARNING</b> some of these timeouts are 60 seconds. These tests will take a long time + * + * <p><b>WARNING</b> some of these timeouts are 60 seconds. These tests will take a long time * complete. */ @LargeTest -public class TimeoutTest extends LiveChannelsTestCase { +@RunWith(JUnit4.class) +public class TimeoutTest { + + @Rule public final LiveChannelsTestController controller = new LiveChannelsTestController(); + + @Test + public void placeholder() { + // There must be at least one test + } + @Ignore("b/73727914") + @Test public void testMenu() { - mLiveChannelsHelper.assertAppStarted(); - mDevice.pressMenu(); + controller.liveChannelsHelper.assertAppStarted(); + controller.pressMenu(); - assertWaitForCondition(mDevice, Until.hasObject(Constants.MENU)); - assertWaitForCondition(mDevice, Until.gone(Constants.MENU), - mTargetResources.getInteger(R.integer.menu_show_duration)); + controller.assertWaitForCondition(Until.hasObject(Constants.MENU)); + controller.assertWaitForCondition( + Until.gone(Constants.MENU), + controller.getTargetResources().getInteger(R.integer.menu_show_duration)); } + @Ignore("b/73727914") + @Test public void testProgramGuide() { - mLiveChannelsHelper.assertAppStarted(); - mMenuHelper.assertPressProgramGuide(); - assertWaitForCondition(mDevice, - Until.hasObject(Constants.PROGRAM_GUIDE)); - assertWaitForCondition(mDevice, Until.gone(Constants.PROGRAM_GUIDE), - mTargetResources.getInteger(R.integer.program_guide_show_duration)); - assertHas(mDevice, Constants.MENU, false); + controller.liveChannelsHelper.assertAppStarted(); + controller.menuHelper.assertPressProgramGuide(); + controller.assertWaitForCondition(Until.hasObject(Constants.PROGRAM_GUIDE)); + controller.assertWaitForCondition( + Until.gone(Constants.PROGRAM_GUIDE), + controller.getTargetResources().getInteger(R.integer.program_guide_show_duration)); + controller.assertHas(Constants.MENU, false); } } diff --git a/tests/func/src/com/android/tv/tests/ui/dvr/DvrLibraryTest.java b/tests/func/src/com/android/tv/tests/ui/dvr/DvrLibraryTest.java index d88e67ad..d0ebed91 100644 --- a/tests/func/src/com/android/tv/tests/ui/dvr/DvrLibraryTest.java +++ b/tests/func/src/com/android/tv/tests/ui/dvr/DvrLibraryTest.java @@ -16,8 +16,6 @@ package com.android.tv.tests.ui.dvr; -import static com.android.tv.testing.uihelper.UiDeviceAsserts.assertHas; -import static com.android.tv.testing.uihelper.UiDeviceAsserts.assertWaitForCondition; import static com.android.tv.testing.uihelper.UiDeviceAsserts.assertWaitUntilFocused; import android.os.Build; @@ -25,195 +23,302 @@ import android.support.test.filters.MediumTest; import android.support.test.filters.SdkSuppress; import android.support.test.uiautomator.By; import android.support.test.uiautomator.BySelector; -import android.support.test.uiautomator.UiObject2; import android.support.test.uiautomator.Until; - import com.android.tv.R; import com.android.tv.testing.uihelper.ByResource; import com.android.tv.testing.uihelper.Constants; -import com.android.tv.tests.ui.LiveChannelsTestCase; - +import com.android.tv.tests.ui.LiveChannelsTestController; import java.util.regex.Pattern; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +/** Test the DVR library UI */ @MediumTest +@RunWith(JUnit4.class) @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N) -public class DvrLibraryTest extends LiveChannelsTestCase { +public class DvrLibraryTest { private static final String PROGRAM_NAME_PREFIX = "Title("; + @Rule public final LiveChannelsTestController controller = new LiveChannelsTestController(); + private BySelector mRecentRow; private BySelector mScheduledRow; private BySelector mSeriesRow; private BySelector mFullScheduleCard; - @Override - protected void setUp() throws Exception { - super.setUp(); - mRecentRow = By.hasDescendant(ByResource.text(mTargetResources, R.string.dvr_main_recent)); - mScheduledRow = By.hasDescendant( - ByResource.text(mTargetResources, R.string.dvr_main_scheduled)); - mSeriesRow = By.hasDescendant(ByResource.text(mTargetResources, R.string.dvr_main_series)); - mFullScheduleCard = By.focusable(true).hasDescendant( - ByResource.text(mTargetResources, R.string.dvr_full_schedule_card_view_title)); - mLiveChannelsHelper.assertAppStarted(); + @Before + public void setUp() throws Exception { + + mRecentRow = + By.hasDescendant( + ByResource.text(controller.getTargetResources(), R.string.dvr_main_recent)); + mScheduledRow = + By.hasDescendant( + ByResource.text( + controller.getTargetResources(), R.string.dvr_main_scheduled)); + mSeriesRow = + By.hasDescendant( + ByResource.text(controller.getTargetResources(), R.string.dvr_main_series)); + mFullScheduleCard = + By.focusable(true) + .hasDescendant( + ByResource.text( + controller.getTargetResources(), + R.string.dvr_full_schedule_card_view_title)); + controller.liveChannelsHelper.assertAppStarted(); } + @Test + public void placeholder() { + // TODO(b/72153742): three must be at least one test + } + + @Ignore("b/72153742") + @Test public void testCancel() { - mMenuHelper.assertPressDvrLibrary(); - assertWaitForCondition(mDevice, Until.hasObject(Constants.DVR_LIBRARY)); - mDevice.pressBack(); - assertWaitForCondition(mDevice, Until.gone(Constants.DVR_LIBRARY)); - assertHas(mDevice, Constants.MENU, false); + controller.menuHelper.assertPressDvrLibrary(); + controller.assertWaitForCondition(Until.hasObject(Constants.DVR_LIBRARY)); + controller.pressBack(); + controller.assertWaitForCondition(Until.gone(Constants.DVR_LIBRARY)); + controller.assertHas(Constants.MENU, false); } + @Ignore("b/72153742") + @Test public void testEmptyLibrary() { - mMenuHelper.assertPressDvrLibrary(); - assertWaitForCondition(mDevice, Until.hasObject(Constants.DVR_LIBRARY)); + controller.menuHelper.assertPressDvrLibrary(); + controller.assertWaitForCondition(Until.hasObject(Constants.DVR_LIBRARY)); // DVR Library is empty, only Scheduled row and Full schedule card should be displayed. - assertHas(mDevice, mRecentRow, false); - assertHas(mDevice, mScheduledRow, true); - assertHas(mDevice, mSeriesRow, false); + controller.assertHas(mRecentRow, false); + controller.assertHas(mScheduledRow, true); + controller.assertHas(mSeriesRow, false); - mDevice.pressDPadCenter(); - assertWaitUntilFocused(mDevice, mFullScheduleCard); - mDevice.pressDPadCenter(); - assertWaitForCondition(mDevice, Until.gone(Constants.DVR_LIBRARY)); + controller.pressDPadCenter(); + assertWaitUntilFocused(controller.getUiDevice(), mFullScheduleCard); + controller.pressDPadCenter(); + controller.assertWaitForCondition(Until.gone(Constants.DVR_LIBRARY)); // Empty schedules screen should be shown. - assertHas(mDevice, Constants.DVR_SCHEDULES, true); - assertHas(mDevice, ByResource.text(mTargetResources, R.string.dvr_schedules_empty_state), + controller.assertHas(Constants.DVR_SCHEDULES, true); + controller.assertHas( + ByResource.text( + controller.getTargetResources(), R.string.dvr_schedules_empty_state), true); // Close the DVR library. - mDevice.pressBack(); - assertWaitForCondition(mDevice, Until.hasObject(Constants.DVR_LIBRARY)); - mDevice.pressBack(); - assertWaitForCondition(mDevice, Until.gone(Constants.DVR_LIBRARY)); + controller.pressBack(); + controller.assertWaitForCondition(Until.hasObject(Constants.DVR_LIBRARY)); + controller.pressBack(); + controller.assertWaitForCondition(Until.gone(Constants.DVR_LIBRARY)); } + @Ignore("b/72153742") + @Test public void testScheduleRecordings() { - BySelector newScheduleCard = By.focusable(true).hasDescendant( - By.textStartsWith(PROGRAM_NAME_PREFIX)).hasDescendant(By.textEndsWith("today")); - BySelector seriesCardWithOneSchedule = By.focusable(true).hasDescendant( - By.textStartsWith(PROGRAM_NAME_PREFIX)).hasDescendant(By.text(mTargetResources - .getQuantityString(R.plurals.dvr_count_scheduled_recordings, 1, 1))); - BySelector seriesCardWithOneRecordedProgram = By.focusable(true).hasDescendant( - By.textStartsWith(PROGRAM_NAME_PREFIX)).hasDescendant(By.text(mTargetResources - .getQuantityString(R.plurals.dvr_count_new_recordings, 1, 1))); - Pattern watchButton = Pattern.compile("^" + mTargetResources - .getString(R.string.dvr_detail_watch).toUpperCase() + "\n.*$"); - - mMenuHelper.showMenu(); - mMenuHelper.assertNavigateToPlayControlsRow(); - mDevice.pressDPadRight(); - mDevice.pressDPadCenter(); - assertWaitForCondition(mDevice, Until.hasObject( - ByResource.text(mTargetResources, R.string.dvr_action_record_episode))); - mDevice.pressDPadCenter(); - assertWaitForCondition(mDevice, Until.gone( - ByResource.text(mTargetResources, R.string.dvr_action_record_episode))); - - mMenuHelper.assertPressDvrLibrary(); - assertWaitForCondition(mDevice, Until.hasObject(Constants.DVR_LIBRARY)); + BySelector newScheduleCard = + By.focusable(true) + .hasDescendant(By.textStartsWith(PROGRAM_NAME_PREFIX)) + .hasDescendant(By.textEndsWith("today")); + BySelector seriesCardWithOneSchedule = + By.focusable(true) + .hasDescendant(By.textStartsWith(PROGRAM_NAME_PREFIX)) + .hasDescendant( + By.text( + controller + .getTargetResources() + .getQuantityString( + R.plurals.dvr_count_scheduled_recordings, + 1, + 1))); + BySelector seriesCardWithOneRecordedProgram = + By.focusable(true) + .hasDescendant(By.textStartsWith(PROGRAM_NAME_PREFIX)) + .hasDescendant( + By.text( + controller + .getTargetResources() + .getQuantityString( + R.plurals.dvr_count_new_recordings, 1, 1))); + Pattern watchButton = + Pattern.compile( + "^" + + controller + .getTargetResources() + .getString(R.string.dvr_detail_watch) + .toUpperCase() + + "\n.*$"); + + controller.menuHelper.showMenu(); + controller.menuHelper.assertNavigateToPlayControlsRow(); + controller.pressDPadRight(); + controller.pressDPadCenter(); + controller.assertWaitForCondition( + Until.hasObject( + ByResource.text( + controller.getTargetResources(), + R.string.dvr_action_record_episode))); + controller.pressDPadCenter(); + controller.assertWaitForCondition( + Until.gone( + ByResource.text( + controller.getTargetResources(), + R.string.dvr_action_record_episode))); + + controller.menuHelper.assertPressDvrLibrary(); + controller.assertWaitForCondition(Until.hasObject(Constants.DVR_LIBRARY)); // Schedule should be automatically added to the series. - assertHas(mDevice, mRecentRow, false); - assertHas(mDevice, mScheduledRow, true); - assertHas(mDevice, mSeriesRow, true); - String programName = mDevice.findObject(By.textStartsWith(PROGRAM_NAME_PREFIX)).getText(); + controller.assertHas(mRecentRow, false); + controller.assertHas(mScheduledRow, true); + controller.assertHas(mSeriesRow, true); + String programName = + controller + .getUiDevice() + .findObject(By.textStartsWith(PROGRAM_NAME_PREFIX)) + .getText(); // Move to scheduled row, there should be one new schedule and one full schedule card. - mDevice.pressDPadRight(); - assertWaitUntilFocused(mDevice, newScheduleCard); - mDevice.pressDPadRight(); - assertWaitUntilFocused(mDevice, mFullScheduleCard); + controller.pressDPadRight(); + controller.assertWaitUntilFocused(newScheduleCard); + controller.pressDPadRight(); + controller.assertWaitUntilFocused(mFullScheduleCard); // Enters the full schedule, there should be one schedule in the full schedule. - mDevice.pressDPadCenter(); - assertWaitForCondition(mDevice, Until.gone(Constants.DVR_LIBRARY)); - assertHas(mDevice, Constants.DVR_SCHEDULES, true); - assertHas(mDevice, ByResource.text(mTargetResources, R.string.dvr_schedules_empty_state), + controller.pressDPadCenter(); + controller.assertWaitForCondition(Until.gone(Constants.DVR_LIBRARY)); + controller.assertHas(Constants.DVR_SCHEDULES, true); + controller.assertHas( + ByResource.text( + controller.getTargetResources(), R.string.dvr_schedules_empty_state), false); - assertHas(mDevice, By.textStartsWith(programName), true); + controller.assertHas(By.textStartsWith(programName), true); // Moves to the series card, clicks it, the detail page should be shown with "View schedule" // button. - mDevice.pressBack(); - assertWaitForCondition(mDevice, Until.hasObject(Constants.DVR_LIBRARY)); - mDevice.pressDPadLeft(); - assertWaitUntilFocused(mDevice, newScheduleCard); - mDevice.pressDPadDown(); - assertWaitUntilFocused(mDevice, seriesCardWithOneSchedule); - mDevice.pressDPadCenter(); - assertWaitForCondition(mDevice, Until.gone(Constants.DVR_LIBRARY)); - assertHas(mDevice, By.text(mTargetResources - .getString(R.string.dvr_detail_view_schedule).toUpperCase()), true); - assertHas(mDevice, By.text(watchButton), false); - assertHas(mDevice, By.text(mTargetResources - .getString(R.string.dvr_detail_series_delete).toUpperCase()), false); + controller.pressBack(); + controller.assertWaitForCondition(Until.hasObject(Constants.DVR_LIBRARY)); + controller.pressDPadLeft(); + controller.assertWaitUntilFocused(newScheduleCard); + controller.pressDPadDown(); + controller.assertWaitUntilFocused(seriesCardWithOneSchedule); + controller.pressDPadCenter(); + controller.assertWaitForCondition(Until.gone(Constants.DVR_LIBRARY)); + controller.assertHas( + By.text( + controller + .getTargetResources() + .getString(R.string.dvr_detail_view_schedule) + .toUpperCase()), + true); + controller.assertHas(By.text(watchButton), false); + controller.assertHas( + By.text( + controller + .getTargetResources() + .getString(R.string.dvr_detail_series_delete) + .toUpperCase()), + false); // Clicks the new schedule, the detail page should be shown with "Stop recording" button. - mDevice.pressBack(); - assertWaitForCondition(mDevice, Until.hasObject(Constants.DVR_LIBRARY)); - assertWaitUntilFocused(mDevice, seriesCardWithOneSchedule); - mDevice.pressDPadUp(); - assertWaitUntilFocused(mDevice, newScheduleCard); - mDevice.pressDPadCenter(); - assertWaitForCondition(mDevice, Until.gone(Constants.DVR_LIBRARY)); - assertHas(mDevice, By.text(mTargetResources - .getString(R.string.dvr_detail_stop_recording).toUpperCase()), true); + controller.pressBack(); + controller.assertWaitForCondition(Until.hasObject(Constants.DVR_LIBRARY)); + controller.assertWaitUntilFocused(seriesCardWithOneSchedule); + controller.pressDPadUp(); + controller.assertWaitUntilFocused(newScheduleCard); + controller.pressDPadCenter(); + controller.assertWaitForCondition(Until.gone(Constants.DVR_LIBRARY)); + controller.assertHas( + By.text( + controller + .getTargetResources() + .getString(R.string.dvr_detail_stop_recording) + .toUpperCase()), + true); // Stops the recording - mDevice.pressDPadCenter(); - assertWaitForCondition(mDevice, Until.hasObject( - ByResource.text(mTargetResources, R.string.dvr_action_stop))); - mDevice.pressDPadCenter(); - assertWaitForCondition(mDevice, Until.gone( - ByResource.text(mTargetResources, R.string.dvr_action_stop))); - assertWaitForCondition(mDevice, Until.hasObject(Constants.DVR_LIBRARY)); - assertWaitUntilFocused(mDevice, mFullScheduleCard); + controller.pressDPadCenter(); + controller.assertWaitForCondition( + Until.hasObject( + ByResource.text( + controller.getTargetResources(), R.string.dvr_action_stop))); + controller.pressDPadCenter(); + controller.assertWaitForCondition( + Until.gone( + ByResource.text( + controller.getTargetResources(), R.string.dvr_action_stop))); + controller.assertWaitForCondition(Until.hasObject(Constants.DVR_LIBRARY)); + controller.assertWaitUntilFocused(mFullScheduleCard); // Moves to series' detail page again, now it should have two more buttons - mDevice.pressDPadDown(); - assertWaitUntilFocused(mDevice, seriesCardWithOneRecordedProgram); - mDevice.pressDPadCenter(); - assertWaitForCondition(mDevice, Until.gone(Constants.DVR_LIBRARY)); - assertHas(mDevice, By.text(watchButton), true); - assertHas(mDevice, By.text(mTargetResources - .getString(R.string.dvr_detail_view_schedule).toUpperCase()), true); - assertHas(mDevice, By.text(mTargetResources - .getString(R.string.dvr_detail_series_delete).toUpperCase()), true); + controller.pressDPadDown(); + controller.assertWaitUntilFocused(seriesCardWithOneRecordedProgram); + controller.pressDPadCenter(); + controller.assertWaitForCondition(Until.gone(Constants.DVR_LIBRARY)); + controller.assertHas(By.text(watchButton), true); + controller.assertHas( + By.text( + controller + .getTargetResources() + .getString(R.string.dvr_detail_view_schedule) + .toUpperCase()), + true); + controller.assertHas( + By.text( + controller + .getTargetResources() + .getString(R.string.dvr_detail_series_delete) + .toUpperCase()), + true); // Moves to the recent row and clicks the recent recorded program. - mDevice.pressBack(); - assertWaitForCondition(mDevice, Until.hasObject(Constants.DVR_LIBRARY)); - assertWaitUntilFocused(mDevice, seriesCardWithOneRecordedProgram); - mDevice.pressDPadUp(); - assertWaitUntilFocused(mDevice, mFullScheduleCard); - mDevice.pressDPadUp(); - assertWaitUntilFocused(mDevice, By.focusable(true).hasDescendant(By.text(programName))); - mDevice.pressDPadCenter(); - assertWaitForCondition(mDevice, Until.gone(Constants.DVR_LIBRARY)); - assertHas(mDevice, By.text(mTargetResources - .getString(R.string.dvr_detail_watch).toUpperCase()), true); - assertHas(mDevice, By.text(mTargetResources - .getString(R.string.dvr_detail_delete).toUpperCase()), true); + controller.pressBack(); + controller.assertWaitForCondition(Until.hasObject(Constants.DVR_LIBRARY)); + controller.assertWaitUntilFocused(seriesCardWithOneRecordedProgram); + controller.pressDPadUp(); + controller.assertWaitUntilFocused(mFullScheduleCard); + controller.pressDPadUp(); + controller.assertWaitUntilFocused(By.focusable(true).hasDescendant(By.text(programName))); + controller.pressDPadCenter(); + controller.assertWaitForCondition(Until.gone(Constants.DVR_LIBRARY)); + controller.assertHas( + By.text( + controller + .getTargetResources() + .getString(R.string.dvr_detail_watch) + .toUpperCase()), + true); + controller.assertHas( + By.text( + controller + .getTargetResources() + .getString(R.string.dvr_detail_delete) + .toUpperCase()), + true); // Moves to the delete button and clicks to remove the recorded program. - mDevice.pressDPadRight(); - assertWaitUntilFocused(mDevice, By.text(mTargetResources - .getString(R.string.dvr_detail_delete).toUpperCase())); - mDevice.pressDPadCenter(); - assertWaitForCondition(mDevice, Until.hasObject(Constants.DVR_LIBRARY)); - assertWaitUntilFocused(mDevice, mFullScheduleCard); + controller.pressDPadRight(); + controller.assertWaitUntilFocused( + By.text( + controller + .getTargetResources() + .getString(R.string.dvr_detail_delete) + .toUpperCase())); + controller.pressDPadCenter(); + controller.assertWaitForCondition(Until.hasObject(Constants.DVR_LIBRARY)); + controller.assertWaitUntilFocused(mFullScheduleCard); // DVR Library should be empty now. - assertHas(mDevice, mRecentRow, false); - assertHas(mDevice, mScheduledRow, true); - assertHas(mDevice, mSeriesRow, false); + controller.assertHas(mRecentRow, false); + controller.assertHas(mScheduledRow, true); + controller.assertHas(mSeriesRow, false); // Close the DVR library. - mDevice.pressBack(); - assertWaitForCondition(mDevice, Until.gone(Constants.DVR_LIBRARY)); + controller.pressBack(); + controller.assertWaitForCondition(Until.gone(Constants.DVR_LIBRARY)); } } diff --git a/tests/func/src/com/android/tv/tests/ui/sidepanel/CustomizeChannelListFragmentTest.java b/tests/func/src/com/android/tv/tests/ui/sidepanel/CustomizeChannelListFragmentTest.java index deeb9bfd..09b855e2 100644 --- a/tests/func/src/com/android/tv/tests/ui/sidepanel/CustomizeChannelListFragmentTest.java +++ b/tests/func/src/com/android/tv/tests/ui/sidepanel/CustomizeChannelListFragmentTest.java @@ -16,37 +16,48 @@ package com.android.tv.tests.ui.sidepanel; -import static com.android.tv.testing.uihelper.UiDeviceAsserts.assertWaitForCondition; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertTrue; import android.graphics.Point; -import android.support.test.filters.LargeTest; +import android.support.test.filters.MediumTest; import android.support.test.uiautomator.BySelector; import android.support.test.uiautomator.Direction; import android.support.test.uiautomator.UiObject2; import android.support.test.uiautomator.Until; - import com.android.tv.R; import com.android.tv.testing.uihelper.Constants; -import com.android.tv.tests.ui.LiveChannelsTestCase; +import com.android.tv.tests.ui.LiveChannelsTestController; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for @{link {@link com.android.tv.ui.sidepanel.CustomizeChannelListFragment} */ +@MediumTest +@RunWith(JUnit4.class) +public class CustomizeChannelListFragmentTest { -@LargeTest -public class CustomizeChannelListFragmentTest extends LiveChannelsTestCase { + @Rule public final LiveChannelsTestController controller = new LiveChannelsTestController(); private BySelector mBySettingsSidePanel; private UiObject2 mTvView; private Point mNormalTvViewCenter; - @Override - protected void setUp() throws Exception { - super.setUp(); - mLiveChannelsHelper.assertAppStarted(); - mTvView = mDevice.findObject(Constants.TV_VIEW); + @Before + public void setUp() throws Exception { + + controller.liveChannelsHelper.assertAppStarted(); + mTvView = controller.getUiDevice().findObject(Constants.TV_VIEW); mNormalTvViewCenter = mTvView.getVisibleCenter(); assertNotNull(mNormalTvViewCenter); - pressKeysForChannel(com.android.tv.testing.testinput.TvTestInputConstants.CH_2); + controller.pressKeysForChannel(com.android.tv.testing.testinput.TvTestInputConstants.CH_2); // Wait until KeypadChannelSwitchView closes. - assertWaitForCondition(mDevice, Until.hasObject(Constants.CHANNEL_BANNER)); - mBySettingsSidePanel = mSidePanelHelper.bySidePanelTitled( - R.string.side_panel_title_settings); + controller.assertWaitForCondition(Until.hasObject(Constants.CHANNEL_BANNER)); + mBySettingsSidePanel = + controller.sidePanelHelper.bySidePanelTitled(R.string.side_panel_title_settings); } private void assertShrunkenTvView(boolean shrunkenExpected) { @@ -58,60 +69,71 @@ public class CustomizeChannelListFragmentTest extends LiveChannelsTestCase { } } + @Test public void testCustomizeChannelList_noraml() { // Show customize channel list fragment - mMenuHelper.assertPressOptionsSettings(); - assertWaitForCondition(mDevice, Until.hasObject(mBySettingsSidePanel)); - mSidePanelHelper.assertNavigateToItem( + controller.menuHelper.assertPressOptionsSettings(); + controller.assertWaitForCondition(Until.hasObject(mBySettingsSidePanel)); + controller.sidePanelHelper.assertNavigateToItem( R.string.settings_channel_source_item_customize_channels); - mDevice.pressDPadCenter(); - BySelector bySidePanel = mSidePanelHelper.bySidePanelTitled( - R.string.side_panel_title_edit_channels_for_an_input); - assertWaitForCondition(mDevice, Until.hasObject(bySidePanel)); + controller.pressDPadCenter(); + BySelector bySidePanel = + controller.sidePanelHelper.bySidePanelTitled( + R.string.side_panel_title_edit_channels_for_an_input); + controller.assertWaitForCondition(Until.hasObject(bySidePanel)); assertShrunkenTvView(true); // Show group by fragment - mSidePanelHelper.assertNavigateToItem(R.string.edit_channels_item_group_by, Direction.UP); - mDevice.pressDPadCenter(); - bySidePanel = mSidePanelHelper.bySidePanelTitled(R.string.side_panel_title_group_by); - assertWaitForCondition(mDevice, Until.hasObject(bySidePanel)); + controller.sidePanelHelper.assertNavigateToItem( + R.string.edit_channels_item_group_by, Direction.UP); + controller.pressDPadCenter(); + bySidePanel = + controller.sidePanelHelper.bySidePanelTitled(R.string.side_panel_title_group_by); + controller.assertWaitForCondition(Until.hasObject(bySidePanel)); assertShrunkenTvView(true); // Back to customize channel list fragment - mDevice.pressBack(); - bySidePanel = mSidePanelHelper.bySidePanelTitled( - R.string.side_panel_title_edit_channels_for_an_input); - assertWaitForCondition(mDevice, Until.hasObject(bySidePanel)); + controller.pressBack(); + bySidePanel = + controller.sidePanelHelper.bySidePanelTitled( + R.string.side_panel_title_edit_channels_for_an_input); + controller.assertWaitForCondition(Until.hasObject(bySidePanel)); assertShrunkenTvView(true); // Return to the main menu. - mDevice.pressBack(); - assertWaitForCondition(mDevice, Until.hasObject(mBySettingsSidePanel)); + controller.pressBack(); + controller.assertWaitForCondition(Until.hasObject(mBySettingsSidePanel)); assertShrunkenTvView(false); } + @Ignore("b/73727914") + @Test public void testCustomizeChannelList_timeout() { // Show customize channel list fragment - mMenuHelper.assertPressOptionsSettings(); - assertWaitForCondition(mDevice, Until.hasObject(mBySettingsSidePanel)); - mSidePanelHelper.assertNavigateToItem( + controller.menuHelper.assertPressOptionsSettings(); + controller.assertWaitForCondition(Until.hasObject(mBySettingsSidePanel)); + controller.sidePanelHelper.assertNavigateToItem( R.string.settings_channel_source_item_customize_channels); - mDevice.pressDPadCenter(); - BySelector bySidePanel = mSidePanelHelper.bySidePanelTitled( - R.string.side_panel_title_edit_channels_for_an_input); - assertWaitForCondition(mDevice, Until.hasObject(bySidePanel)); + controller.pressDPadCenter(); + BySelector bySidePanel = + controller.sidePanelHelper.bySidePanelTitled( + R.string.side_panel_title_edit_channels_for_an_input); + controller.assertWaitForCondition(Until.hasObject(bySidePanel)); assertShrunkenTvView(true); // Show group by fragment - mSidePanelHelper.assertNavigateToItem(R.string.edit_channels_item_group_by, Direction.UP); - mDevice.pressDPadCenter(); - bySidePanel = mSidePanelHelper.bySidePanelTitled(R.string.side_panel_title_group_by); - assertWaitForCondition(mDevice, Until.hasObject(bySidePanel)); + controller.sidePanelHelper.assertNavigateToItem( + R.string.edit_channels_item_group_by, Direction.UP); + controller.pressDPadCenter(); + bySidePanel = + controller.sidePanelHelper.bySidePanelTitled(R.string.side_panel_title_group_by); + controller.assertWaitForCondition(Until.hasObject(bySidePanel)); assertShrunkenTvView(true); // Wait for time-out to return to the main menu. - assertWaitForCondition(mDevice, Until.gone(bySidePanel), - mTargetResources.getInteger(R.integer.side_panel_show_duration)); + controller.assertWaitForCondition( + Until.gone(bySidePanel), + controller.getTargetResources().getInteger(R.integer.side_panel_show_duration)); assertShrunkenTvView(false); } } diff --git a/tests/input/Android.mk b/tests/input/Android.mk index 2efd32b9..46b5621c 100644 --- a/tests/input/Android.mk +++ b/tests/input/Android.mk @@ -8,7 +8,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_PROGUARD_ENABLED := disabled # Overlay view related functionality requires system APIs. LOCAL_SDK_VERSION := system_current -LOCAL_MIN_SDK_VERSION := 23 # M +LOCAL_PROGUARD_ENABLED := disabled LOCAL_STATIC_JAVA_LIBRARIES := \ tv-test-common \ diff --git a/tests/input/AndroidManifest.xml b/tests/input/AndroidManifest.xml index 14491449..9b5df2ff 100644 --- a/tests/input/AndroidManifest.xml +++ b/tests/input/AndroidManifest.xml @@ -18,7 +18,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.tv.testinput"> - <uses-sdk android:targetSdkVersion="23" android:minSdkVersion="23"/> + <uses-sdk android:targetSdkVersion="26" android:minSdkVersion="23"/> <!-- Required to update or read existing channel and program information in TvProvider. --> <uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA" /> diff --git a/tests/input/func.sh b/tests/input/func.sh new file mode 100644 index 00000000..3b2af4da --- /dev/null +++ b/tests/input/func.sh @@ -0,0 +1,24 @@ +#!/system/bin/sh +# +# Copyright (C) 2017 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. + +# text fixture setup for unit tests + + +echo "text fixture setup for func tests" + +am instrument \ + -e testSetupMode func \ + -w com.android.tv.testinput/.instrument.TestSetupInstrumentation
\ No newline at end of file diff --git a/tests/input/jank.sh b/tests/input/jank.sh new file mode 100644 index 00000000..c6311a4d --- /dev/null +++ b/tests/input/jank.sh @@ -0,0 +1,24 @@ +#!/system/bin/sh +# +# Copyright (C) 2017 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. + +# text fixture setup for unit tests + + +echo "text fixture setup for func tests" + +am instrument \ + -e testSetupMode jank \ + -w com.android.tv.testinput/.instrument.TestSetupInstrumentation
\ No newline at end of file diff --git a/tests/input/src/com/android/tv/testinput/TestInputControl.java b/tests/input/src/com/android/tv/testinput/TestInputControl.java index cd85c86e..5e5ec32a 100644 --- a/tests/input/src/com/android/tv/testinput/TestInputControl.java +++ b/tests/input/src/com/android/tv/testinput/TestInputControl.java @@ -21,28 +21,26 @@ import android.net.Uri; import android.os.RemoteException; import android.util.Log; import android.util.LongSparseArray; - -import com.android.tv.testing.ChannelInfo; -import com.android.tv.testing.ChannelUtils; +import com.android.tv.testing.data.ChannelInfo; +import com.android.tv.testing.data.ChannelUtils; import com.android.tv.testing.testinput.ChannelState; import com.android.tv.testing.testinput.ChannelStateData; import com.android.tv.testing.testinput.ITestInputControl; - import java.util.Map; /** * Maintains state for the {@link TestTvInputService}. * - * <p>Maintains the current state for every channel. A default is sent if the state is not + * <p>Maintains the current state for every channel. A default is sent if the state is not * explicitly set. The state is versioned so TestTvInputService can tell if onNotifyXXX events need * to be sent. * - * <p> Test update the state using @{link ITestInputControl} via {@link TestInputControlService}. + * <p>Test update the state using @{link ITestInputControl} via {@link TestInputControlService}. */ class TestInputControl extends ITestInputControl.Stub { - private final static String TAG = "TestInputControl"; - private final static TestInputControl INSTANCE = new TestInputControl(); + private static final String TAG = "TestInputControl"; + private static final TestInputControl INSTANCE = new TestInputControl(); private final LongSparseArray<ChannelInfo> mId2ChannelInfoMap = new LongSparseArray<>(); private final LongSparseArray<ChannelState> mOrigId2StateMap = new LongSparseArray<>(); @@ -50,8 +48,7 @@ class TestInputControl extends ITestInputControl.Stub { private java.lang.String mInputId; private boolean initialized; - private TestInputControl() { - } + private TestInputControl() {} public static TestInputControl getInstance() { return INSTANCE; @@ -73,8 +70,13 @@ class TestInputControl extends ITestInputControl.Stub { for (Long channelId : channelIdToInfoMap.keySet()) { mId2ChannelInfoMap.put(channelId, channelIdToInfoMap.get(channelId)); } - Log.i(TAG, "Initialized channel map for " + mInputId + " with " + mId2ChannelInfoMap.size() - + " channels"); + Log.i( + TAG, + "Initialized channel map for " + + mInputId + + " with " + + mId2ChannelInfoMap.size() + + " channels"); } public ChannelInfo getChannelInfo(Uri channelUri) { diff --git a/tests/input/src/com/android/tv/testinput/TestInputControlService.java b/tests/input/src/com/android/tv/testinput/TestInputControlService.java index 4a5668cc..4a1306ed 100644 --- a/tests/input/src/com/android/tv/testinput/TestInputControlService.java +++ b/tests/input/src/com/android/tv/testinput/TestInputControlService.java @@ -20,8 +20,8 @@ import android.content.Intent; import android.os.IBinder; /** - * Testcases communicate to the {@link TestInputControl} via - * {@link com.android.tv.testing.testinput.ITestInputControl}. + * Testcases communicate to the {@link TestInputControl} via {@link + * com.android.tv.testing.testinput.ITestInputControl}. */ public class TestInputControlService extends Service { diff --git a/tests/input/src/com/android/tv/testinput/TestTvInputService.java b/tests/input/src/com/android/tv/testinput/TestTvInputService.java index 621ceacb..840587c9 100644 --- a/tests/input/src/com/android/tv/testinput/TestTvInputService.java +++ b/tests/input/src/com/android/tv/testinput/TestTvInputService.java @@ -41,17 +41,13 @@ import android.os.Message; import android.util.Log; import android.view.KeyEvent; import android.view.Surface; - import com.android.tv.input.TunerHelper; -import com.android.tv.testing.ChannelInfo; +import com.android.tv.testing.data.ChannelInfo; import com.android.tv.testing.testinput.ChannelState; - import java.util.Date; import java.util.concurrent.TimeUnit; -/** - * Simple TV input service which provides test channels. - */ +/** Simple TV input service which provides test channels. */ public class TestTvInputService extends TvInputService { private static final String TAG = "TestTvInputService"; private static final int REFRESH_DELAY_MS = 1000 / 5; @@ -93,9 +89,7 @@ public class TestTvInputService extends TvInputService { return new SimpleRecordingSessionImpl(this, inputId); } - /** - * Simple session implementation that just display some text. - */ + /** Simple session implementation that just display some text. */ private class SimpleSessionImpl extends Session { private static final int MSG_SEEK = 1000; private static final int SEEK_DELAY_MS = 300; @@ -118,28 +112,36 @@ public class TestTvInputService extends TvInputService { // The current playback speed rate. private float mSpeed; - private final Handler mHandler = new Handler(Looper.myLooper()) { - @Override - public void handleMessage(Message msg) { - if (msg.what == MSG_SEEK) { - // Actually, this input doesn't play any videos, it just shows the image. - // So we should simulate the playback here by changing the current playback - // position periodically in order to test the time shift. - // If the playback is paused, the current playback position doesn't need to be - // changed. - if (mPausedTimeMs == 0) { - long currentTimeMs = System.currentTimeMillis(); - mCurrentPositionMs += (long) ((currentTimeMs - - mLastCurrentPositionUpdateTimeMs) * mSpeed); - mCurrentPositionMs = Math.max(mRecordStartTimeMs, - Math.min(mCurrentPositionMs, currentTimeMs)); - mLastCurrentPositionUpdateTimeMs = currentTimeMs; + private final Handler mHandler = + new Handler(Looper.myLooper()) { + @Override + public void handleMessage(Message msg) { + if (msg.what == MSG_SEEK) { + // Actually, this input doesn't play any videos, it just shows the + // image. + // So we should simulate the playback here by changing the current + // playback + // position periodically in order to test the time shift. + // If the playback is paused, the current playback position doesn't need + // to be + // changed. + if (mPausedTimeMs == 0) { + long currentTimeMs = System.currentTimeMillis(); + mCurrentPositionMs += + (long) + ((currentTimeMs - mLastCurrentPositionUpdateTimeMs) + * mSpeed); + mCurrentPositionMs = + Math.max( + mRecordStartTimeMs, + Math.min(mCurrentPositionMs, currentTimeMs)); + mLastCurrentPositionUpdateTimeMs = currentTimeMs; + } + sendEmptyMessageDelayed(MSG_SEEK, SEEK_DELAY_MS); + } + super.handleMessage(msg); } - sendEmptyMessageDelayed(MSG_SEEK, SEEK_DELAY_MS); - } - super.handleMessage(msg); - } - }; + }; SimpleSessionImpl(Context context) { super(context); @@ -213,7 +215,8 @@ public class TestTvInputService extends TvInputService { mChannelUri = channelUri; ChannelInfo info = mBackend.getChannelInfo(channelUri); synchronized (mDrawRunnable) { - if (info == null || mChannel == null + if (info == null + || mChannel == null || mChannel.originalNetworkId != info.originalNetworkId) { mCurrentState = null; } @@ -231,8 +234,9 @@ public class TestTvInputService extends TvInputService { Log.i(TAG, "Tuning to " + mChannel); } notifyTimeShiftStatusChanged(TvInputManager.TIME_SHIFT_STATUS_AVAILABLE); - mRecordStartTimeMs = mCurrentPositionMs = mLastCurrentPositionUpdateTimeMs - = System.currentTimeMillis(); + mRecordStartTimeMs = + mCurrentPositionMs = + mLastCurrentPositionUpdateTimeMs = System.currentTimeMillis(); mPausedTimeMs = 0; mHandler.sendEmptyMessageDelayed(MSG_SEEK, SEEK_DELAY_MS); mSpeed = 1; @@ -269,8 +273,8 @@ public class TestTvInputService extends TvInputService { @Override public void onTimeShiftPause() { - mCurrentPositionMs = mPausedTimeMs = mLastCurrentPositionUpdateTimeMs - = System.currentTimeMillis(); + mCurrentPositionMs = + mPausedTimeMs = mLastCurrentPositionUpdateTimeMs = System.currentTimeMillis(); } @Override @@ -283,8 +287,9 @@ public class TestTvInputService extends TvInputService { @Override public void onTimeShiftSeekTo(long timeMs) { mLastCurrentPositionUpdateTimeMs = System.currentTimeMillis(); - mCurrentPositionMs = Math.max(mRecordStartTimeMs, - Math.min(timeMs, mLastCurrentPositionUpdateTimeMs)); + mCurrentPositionMs = + Math.max( + mRecordStartTimeMs, Math.min(timeMs, mLastCurrentPositionUpdateTimeMs)); } @Override @@ -354,14 +359,14 @@ public class TestTvInputService extends TvInputService { } } - private void update(ChannelState oldState, ChannelState newState, - ChannelInfo currentChannel) { + private void update( + ChannelState oldState, ChannelState newState, ChannelInfo currentChannel) { Log.i(TAG, "Updating channel " + currentChannel.number + " state to " + newState); notifyTracksChanged(newState.getTrackInfoList()); if (oldState == null || oldState.getTuneStatus() != newState.getTuneStatus()) { if (newState.getTuneStatus() == ChannelState.TUNE_STATUS_VIDEO_AVAILABLE) { notifyVideoAvailable(); - //TODO handle parental controls. + // TODO handle parental controls. notifyContentAllowed(); setAudioTrack(newState.getSelectedAudioTrackId()); setVideoTrack(newState.getSelectedVideoTrackId()); @@ -379,20 +384,20 @@ public class TestTvInputService extends TvInputService { private class SimpleRecordingSessionImpl extends RecordingSession { private final String[] PROGRAM_PROJECTION = { - Programs.COLUMN_TITLE, - Programs.COLUMN_EPISODE_TITLE, - Programs.COLUMN_SHORT_DESCRIPTION, - Programs.COLUMN_POSTER_ART_URI, - Programs.COLUMN_THUMBNAIL_URI, - Programs.COLUMN_CANONICAL_GENRE, - Programs.COLUMN_CONTENT_RATING, - Programs.COLUMN_START_TIME_UTC_MILLIS, - Programs.COLUMN_END_TIME_UTC_MILLIS, - Programs.COLUMN_VIDEO_WIDTH, - Programs.COLUMN_VIDEO_HEIGHT, - Programs.COLUMN_SEASON_DISPLAY_NUMBER, - Programs.COLUMN_SEASON_TITLE, - Programs.COLUMN_EPISODE_DISPLAY_NUMBER, + Programs.COLUMN_TITLE, + Programs.COLUMN_EPISODE_TITLE, + Programs.COLUMN_SHORT_DESCRIPTION, + Programs.COLUMN_POSTER_ART_URI, + Programs.COLUMN_THUMBNAIL_URI, + Programs.COLUMN_CANONICAL_GENRE, + Programs.COLUMN_CONTENT_RATING, + Programs.COLUMN_START_TIME_UTC_MILLIS, + Programs.COLUMN_END_TIME_UTC_MILLIS, + Programs.COLUMN_VIDEO_WIDTH, + Programs.COLUMN_VIDEO_HEIGHT, + Programs.COLUMN_SEASON_DISPLAY_NUMBER, + Programs.COLUMN_SEASON_TITLE, + Programs.COLUMN_EPISODE_DISPLAY_NUMBER, }; private final String mInputId; @@ -442,8 +447,14 @@ public class TestTvInputService extends TvInputService { long time = System.currentTimeMillis(); if (programHintUri != null) { // Retrieves program info from mProgramHintUri - try (Cursor c = getContentResolver().query(programHintUri, - PROGRAM_PROJECTION, null, null, null)) { + try (Cursor c = + getContentResolver() + .query( + programHintUri, + PROGRAM_PROJECTION, + null, + null, + null)) { if (c != null && c.getCount() > 0) { storeRecordedProgram(c, startTime, endTime); return null; @@ -453,11 +464,19 @@ public class TestTvInputService extends TvInputService { } } // Retrieves the current program - try (Cursor c = getContentResolver().query( - TvContract.buildProgramsUriForChannel(channelUri, startTime, - endTime - startTime < MAX_COMMAND_DELAY ? startTime : - endTime - MAX_COMMAND_DELAY), - PROGRAM_PROJECTION, null, null, null)) { + try (Cursor c = + getContentResolver() + .query( + TvContract.buildProgramsUriForChannel( + channelUri, + startTime, + endTime - startTime < MAX_COMMAND_DELAY + ? startTime + : endTime - MAX_COMMAND_DELAY), + PROGRAM_PROJECTION, + null, + null, + null)) { if (c != null && c.getCount() == 1) { storeRecordedProgram(c, startTime, endTime); return null; @@ -472,10 +491,9 @@ public class TestTvInputService extends TvInputService { private void storeRecordedProgram(Cursor c, long startTime, long endTime) { ContentValues values = new ContentValues(); values.put(RecordedPrograms.COLUMN_INPUT_ID, mInputId); - values.put(RecordedPrograms.COLUMN_CHANNEL_ID, - ContentUris.parseId(channelUri)); - values.put(RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS, - endTime - startTime); + values.put(RecordedPrograms.COLUMN_CHANNEL_ID, ContentUris.parseId(channelUri)); + values.put( + RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS, endTime - startTime); if (c != null) { int index = 0; c.moveToNext(); @@ -492,15 +510,15 @@ public class TestTvInputService extends TvInputService { values.put(Programs.COLUMN_VIDEO_HEIGHT, c.getLong(index++)); values.put(Programs.COLUMN_SEASON_DISPLAY_NUMBER, c.getString(index++)); values.put(Programs.COLUMN_SEASON_TITLE, c.getString(index++)); - values.put(Programs.COLUMN_EPISODE_DISPLAY_NUMBER, - c.getString(index++)); + values.put(Programs.COLUMN_EPISODE_DISPLAY_NUMBER, c.getString(index++)); } else { values.put(RecordedPrograms.COLUMN_TITLE, "No program info"); values.put(RecordedPrograms.COLUMN_START_TIME_UTC_MILLIS, startTime); values.put(RecordedPrograms.COLUMN_END_TIME_UTC_MILLIS, endTime); } - Uri uri = getContentResolver() - .insert(TvContract.RecordedPrograms.CONTENT_URI, values); + Uri uri = + getContentResolver() + .insert(TvContract.RecordedPrograms.CONTENT_URI, values); notifyRecordingStopped(uri); } }.execute(); diff --git a/tests/input/src/com/android/tv/testinput/TestTvInputSetupActivity.java b/tests/input/src/com/android/tv/testinput/TestTvInputSetupActivity.java index a793ac71..c9153d1c 100644 --- a/tests/input/src/com/android/tv/testinput/TestTvInputSetupActivity.java +++ b/tests/input/src/com/android/tv/testinput/TestTvInputSetupActivity.java @@ -22,24 +22,17 @@ import android.app.Dialog; import android.app.DialogFragment; import android.content.Context; import android.content.DialogInterface; -import android.media.tv.TvContract; import android.media.tv.TvInputInfo; import android.os.Bundle; import android.util.Log; - -import com.android.tv.testing.ChannelInfo; -import com.android.tv.testing.ChannelUtils; -import com.android.tv.testing.Constants; -import com.android.tv.testing.ProgramInfo; -import com.android.tv.testing.ProgramUtils; - -import java.util.ArrayList; +import com.android.tv.common.util.Clock; +import com.android.tv.testing.constants.Constants; +import com.android.tv.testing.data.ChannelInfo; +import com.android.tv.testing.data.ChannelUtils; +import com.android.tv.testing.data.ProgramUtils; import java.util.List; -import java.util.Map; -/** - * The setup activity for {@link TestTvInputService}. - */ +/** The setup activity for {@link TestTvInputService}. */ public class TestTvInputSetupActivity extends Activity { private static final String TAG = "TestTvInputSetup"; private String mInputId; @@ -60,45 +53,41 @@ public class TestTvInputSetupActivity extends Activity { public static void registerChannels(Context context, String inputId, int channelCount) { Log.i(TAG, "Registering " + channelCount + " channels"); - List<ChannelInfo> channels = new ArrayList<>(); - for (int i = 1; i <= channelCount; i++) { - channels.add(ChannelInfo.create(context, i)); - } + List<ChannelInfo> channels = ChannelUtils.createChannelInfos(context, channelCount); ChannelUtils.updateChannels(context, inputId, channels); - - // Reload channels so we have the ids. - Map<Long, ChannelInfo> channelIdToInfoMap = - ChannelUtils.queryChannelInfoMapForTvInput(context, inputId); - for (Long channelId : channelIdToInfoMap.keySet()) { - ProgramInfo programInfo = ProgramInfo.create(); - ProgramUtils.populatePrograms(context, TvContract.buildChannelUri(channelId), - programInfo); - } + ProgramUtils.updateProgramForAllChannelsOf( + context, inputId, Clock.SYSTEM, ProgramUtils.PROGRAM_INSERT_DURATION_MS); } public static class MyAlertDialogFragment extends DialogFragment { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { - return new AlertDialog.Builder(getActivity()).setTitle(R.string.simple_setup_title) + return new AlertDialog.Builder(getActivity()) + .setTitle(R.string.simple_setup_title) .setMessage(R.string.simple_setup_message) - .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int whichButton) { - // TODO: add UI to ask how many channels - ((TestTvInputSetupActivity) getActivity()) - .registerChannels(Constants.UNIT_TEST_CHANNEL_COUNT); - // Sets the results so that the application can process the - // registered channels properly. - getActivity().setResult(Activity.RESULT_OK); - getActivity().finish(); - } - }).setNegativeButton(android.R.string.cancel, + .setPositiveButton( + android.R.string.ok, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int whichButton) { + // TODO: add UI to ask how many channels + ((TestTvInputSetupActivity) getActivity()) + .registerChannels(Constants.UNIT_TEST_CHANNEL_COUNT); + // Sets the results so that the application can process the + // registered channels properly. + getActivity().setResult(Activity.RESULT_OK); + getActivity().finish(); + } + }) + .setNegativeButton( + android.R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int whichButton) { getActivity().finish(); } - }).create(); + }) + .create(); } } } diff --git a/tests/input/src/com/android/tv/testinput/instrument/TestSetupInstrumentation.java b/tests/input/src/com/android/tv/testinput/instrument/TestSetupInstrumentation.java index 48e485c5..a4bd45c0 100644 --- a/tests/input/src/com/android/tv/testinput/instrument/TestSetupInstrumentation.java +++ b/tests/input/src/com/android/tv/testinput/instrument/TestSetupInstrumentation.java @@ -21,22 +21,24 @@ import android.app.Instrumentation; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; - -import com.android.tv.testing.Constants; +import com.android.tv.testing.constants.Constants; import com.android.tv.testinput.TestTvInputService; import com.android.tv.testinput.TestTvInputSetupActivity; /** - * An instrumentation utility to set up the needed inputs, channels, programs and other settings - * for automated unit tests. + * An instrumentation utility to set up the needed inputs, channels, programs and other settings for + * automated unit tests. + * + * <p> * - * <p><pre>{@code + * <pre>{@code * adb shell am instrument \ * -e testSetupMode {func,jank,unit} \ * -w com.android.tv.testinput/.instrument.TestSetupInstrumentation * }</pre> * * <p>Optional arguments are: + * * <pre> * -e channelCount number * </pre> @@ -82,23 +84,26 @@ public class TestSetupInstrumentation extends Instrumentation { private void setup() throws TestSetupException { final String testSetupMode = mArguments.getString(TEST_SETUP_MODE_ARG); if (TextUtils.isEmpty(testSetupMode)) { - Log.i(TAG, "Performing no setup actions because " + TEST_SETUP_MODE_ARG - + " was not passed as an argument"); + Log.i( + TAG, + "Performing no setup actions because " + + TEST_SETUP_MODE_ARG + + " was not passed as an argument"); } else { Log.i(TAG, "Running setup for " + testSetupMode + " tests."); int channelCount; switch (testSetupMode) { case "func": - channelCount = getArgumentAsInt(CHANNEL_COUNT_ARG, - Constants.FUNC_TEST_CHANNEL_COUNT); + channelCount = + getArgumentAsInt(CHANNEL_COUNT_ARG, Constants.FUNC_TEST_CHANNEL_COUNT); break; case "jank": - channelCount = getArgumentAsInt(CHANNEL_COUNT_ARG, - Constants.JANK_TEST_CHANNEL_COUNT); + channelCount = + getArgumentAsInt(CHANNEL_COUNT_ARG, Constants.JANK_TEST_CHANNEL_COUNT); break; case "unit": - channelCount = getArgumentAsInt(CHANNEL_COUNT_ARG, - Constants.UNIT_TEST_CHANNEL_COUNT); + channelCount = + getArgumentAsInt(CHANNEL_COUNT_ARG, Constants.UNIT_TEST_CHANNEL_COUNT); break; default: throw new TestSetupException( @@ -114,8 +119,14 @@ public class TestSetupInstrumentation extends Instrumentation { try { return Integer.parseInt(stringValue); } catch (NumberFormatException e) { - Log.w(TAG, "Unable to parse arg " + arg + " with value " + stringValue - + " to a integer.", e); + Log.w( + TAG, + "Unable to parse arg " + + arg + + " with value " + + stringValue + + " to a integer.", + e); } } return defaultValue; diff --git a/tests/input/tools/get_test_logos.sh b/tests/input/tools/get_test_logos.sh new file mode 100755 index 00000000..4dd87a3a --- /dev/null +++ b/tests/input/tools/get_test_logos.sh @@ -0,0 +1,57 @@ +#!/bin/bash +# +# Copyright (C) 2017 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. + +BASE="http://www.google.com/chart?chs=32&chst=d_simple_text_icon_above" + +# From http://developers.google.com/chart/image/docs/gallery/dynamic_icons#basic-icons +icons=( + academy activities airport amusement aquarium + art-gallery atm baby bank-dollar bank-euro + bank-intl bank-pound bank-yen bar barber + beach beer bicycle books bowling + bus cafe camping car-dealer car-rental + car-repair casino caution cemetery-grave cemetery-tomb + cinema civic-building computer corporate courthouse + fire flag floral helicopter home + info landslide legal location locomotive + medical mobile motorcycle music parking + pet petrol phone picnic postal + repair restaurant sail school scissors + ship shoppingbag shoppingcart ski snack + snow sport star swim taxi train + truck wc-female wc-male wc + wheelchair + ) + +# The 500s from https://spec.googleplex.com/quantumpalette# +colors=( + DB4437 E91E63 9C27B0 673AB7 3F51B5 + 4285F4 03A9F4 00BCD4 009688 0F9D58 + 8BC34A CDDC39 FFEB3B F4B400 FF9800 + FF5722 795548 9E9E9E 607D8B +) + + +# See https://developers.google.com/chart/image/docs/gallery/dynamic_icons +for n in `seq 1 80`; +do + i=n%76 + c=$(($RANDOM%19)) + # <font_size>|<font_fill_color>|<icon_name>|<icon_size>|<icon_fill_color>|<icon_and_text_border_color> + url=${BASE}"&chld=Ch+"${n}"|7|00F|${icons[${i}]}|24|${colors[${c}]}|FFF" + echo ${url} + curl ${url} -o tests/input/res/drawable-xhdpi/ch_${n}_logo.png +done;
\ No newline at end of file diff --git a/tests/input/unit.sh b/tests/input/unit.sh new file mode 100644 index 00000000..a14d3292 --- /dev/null +++ b/tests/input/unit.sh @@ -0,0 +1,24 @@ +#!/system/bin/sh +# +# Copyright (C) 2017 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. + +# text fixture setup for unit tests + + +echo "text fixture setup for unit tests" + +am instrument \ + -e testSetupMode unit \ + -w com.android.tv.testinput/.instrument.TestSetupInstrumentation
\ No newline at end of file diff --git a/tests/jank/Android.mk b/tests/jank/Android.mk index b71ea1b7..1b67ac3f 100644 --- a/tests/jank/Android.mk +++ b/tests/jank/Android.mk @@ -15,9 +15,11 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ ub-janktesthelper \ ub-uiautomator \ +LOCAL_JAVA_LIBRARIES := android.test.base.stubs + LOCAL_INSTRUMENTATION_FOR := LiveTv -LOCAL_SDK_VERSION := current -LOCAL_MIN_SDK_VERSION := 23 # M +LOCAL_SDK_VERSION := system_current +LOCAL_PROGUARD_ENABLED := disabled include $(BUILD_PACKAGE) diff --git a/tests/jank/AndroidManifest.xml b/tests/jank/AndroidManifest.xml index fa09917d..5ea72b44 100644 --- a/tests/jank/AndroidManifest.xml +++ b/tests/jank/AndroidManifest.xml @@ -18,7 +18,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.tv.tests.jank" > - <uses-sdk android:targetSdkVersion="23" android:minSdkVersion="21" /> + <uses-sdk android:targetSdkVersion="26" android:minSdkVersion="21" /> <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" diff --git a/tests/jank/src/com/android/tv/tests/jank/ChannelZappingJankTest.java b/tests/jank/src/com/android/tv/tests/jank/ChannelZappingJankTest.java index ef936e32..eee2328b 100644 --- a/tests/jank/src/com/android/tv/tests/jank/ChannelZappingJankTest.java +++ b/tests/jank/src/com/android/tv/tests/jank/ChannelZappingJankTest.java @@ -19,9 +19,7 @@ import android.support.test.filters.MediumTest; import android.support.test.jank.GfxMonitor; import android.support.test.jank.JankTest; -/** - * Jank tests for channel zapping. - */ +/** Jank tests for channel zapping. */ @MediumTest public class ChannelZappingJankTest extends LiveChannelsTestCase { private static final String TAG = "ChannelZappingJankTest"; @@ -29,15 +27,17 @@ public class ChannelZappingJankTest extends LiveChannelsTestCase { private static final String STARTING_CHANNEL = "13"; /** - * The minimum number of frames expected during each jank test. - * If there is less the test will fail. To be safe we loop the action in each test to create - * twice this many frames under normal conditions. - * <p>At least 100 frams should be chosen so there will be enough frame - * for the 90th, 95th, and 98th percentile measurements are significant. + * The minimum number of frames expected during each jank test. If there is less the test will + * fail. To be safe we loop the action in each test to create twice this many frames under + * normal conditions. + * + * <p>At least 100 frams should be chosen so there will be enough frame for the 90th, 95th, and + * 98th percentile measurements are significant. * * @see <a href="http://go/janktesthelper-best-practices">Jank Test Helper Best Practices</a> */ private static final int EXPECTED_FRAMES = 100; + private static final int WARM_UP_CHANNEL_ZAPPING_COUNT = 2; @Override @@ -46,11 +46,10 @@ public class ChannelZappingJankTest extends LiveChannelsTestCase { Utils.pressKeysForChannelNumber(STARTING_CHANNEL, mDevice); } - @JankTest(expectedFrames = EXPECTED_FRAMES, - beforeTest = "warmChannelZapping") + @JankTest(expectedFrames = EXPECTED_FRAMES, beforeTest = "warmChannelZapping") @GfxMonitor(processName = Utils.LIVE_CHANNELS_PROCESS_NAME) public void testChannelZapping() { - int frameCountForOneChannelZapping = 40; // measured by hand + int frameCountForOneChannelZapping = 40; // measured by hand int repeat = EXPECTED_FRAMES * 2 / frameCountForOneChannelZapping; for (int i = 0; i < repeat; i++) { mDevice.pressDPadUp(); diff --git a/tests/jank/src/com/android/tv/tests/jank/LiveChannelsTestCase.java b/tests/jank/src/com/android/tv/tests/jank/LiveChannelsTestCase.java index 6de01036..507e9dd5 100644 --- a/tests/jank/src/com/android/tv/tests/jank/LiveChannelsTestCase.java +++ b/tests/jank/src/com/android/tv/tests/jank/LiveChannelsTestCase.java @@ -18,12 +18,9 @@ package com.android.tv.tests.jank; import android.content.res.Resources; import android.support.test.jank.JankTestBase; import android.support.test.uiautomator.UiDevice; - import com.android.tv.testing.uihelper.LiveChannelsUiDeviceHelper; -/** - * Base test case for LiveChannel jank tests. - */ +/** Base test case for LiveChannel jank tests. */ abstract class LiveChannelsTestCase extends JankTestBase { protected UiDevice mDevice; protected Resources mTargetResources; @@ -34,8 +31,9 @@ abstract class LiveChannelsTestCase extends JankTestBase { super.setUp(); mDevice = UiDevice.getInstance(getInstrumentation()); mTargetResources = getInstrumentation().getTargetContext().getResources(); - mLiveChannelsHelper = new LiveChannelsUiDeviceHelper(mDevice, mTargetResources, - getInstrumentation().getContext()); + mLiveChannelsHelper = + new LiveChannelsUiDeviceHelper( + mDevice, mTargetResources, getInstrumentation().getContext()); mLiveChannelsHelper.assertAppStarted(); } diff --git a/tests/jank/src/com/android/tv/tests/jank/MenuJankTest.java b/tests/jank/src/com/android/tv/tests/jank/MenuJankTest.java index 411a0bb9..ea80eb3d 100644 --- a/tests/jank/src/com/android/tv/tests/jank/MenuJankTest.java +++ b/tests/jank/src/com/android/tv/tests/jank/MenuJankTest.java @@ -18,26 +18,25 @@ package com.android.tv.tests.jank; import android.support.test.filters.MediumTest; import android.support.test.jank.GfxMonitor; import android.support.test.jank.JankTest; - import com.android.tv.testing.uihelper.MenuHelper; -/** - * Jank tests for the program guide. - */ +/** Jank tests for the program guide. */ @MediumTest public class MenuJankTest extends LiveChannelsTestCase { private static final String STARTING_CHANNEL = "1"; /** - * The minimum number of frames expected during each jank test. - * If there is less the test will fail. To be safe we loop the action in each test to create - * twice this many frames under normal conditions. + * The minimum number of frames expected during each jank test. If there is less the test will + * fail. To be safe we loop the action in each test to create twice this many frames under + * normal conditions. + * * <p>200 is chosen so there will be enough frame for the 90th, 95th, and 98th percentile * measurements are significant. * * @see <a href="http://go/janktesthelper-best-practices">Jank Test Helper Best Practices</a> */ private static final int EXPECTED_FRAMES = 200; + protected MenuHelper mMenuHelper; @Override @@ -47,8 +46,7 @@ public class MenuJankTest extends LiveChannelsTestCase { Utils.pressKeysForChannelNumber(STARTING_CHANNEL, mDevice); } - @JankTest(expectedFrames = EXPECTED_FRAMES, - beforeTest = "fillTheMenuRowWithPreviousChannels") + @JankTest(expectedFrames = EXPECTED_FRAMES, beforeTest = "fillTheMenuRowWithPreviousChannels") @GfxMonitor(processName = Utils.LIVE_CHANNELS_PROCESS_NAME) public void testShowMenu() { int frames = 40; // measured by hand. diff --git a/tests/jank/src/com/android/tv/tests/jank/ProgramGuideJankTest.java b/tests/jank/src/com/android/tv/tests/jank/ProgramGuideJankTest.java index d8860dd7..57d38ba9 100644 --- a/tests/jank/src/com/android/tv/tests/jank/ProgramGuideJankTest.java +++ b/tests/jank/src/com/android/tv/tests/jank/ProgramGuideJankTest.java @@ -21,23 +21,21 @@ import android.support.test.filters.MediumTest; import android.support.test.jank.GfxMonitor; import android.support.test.jank.JankTest; import android.support.test.uiautomator.Until; - import com.android.tv.R; import com.android.tv.testing.uihelper.ByResource; import com.android.tv.testing.uihelper.Constants; import com.android.tv.testing.uihelper.MenuHelper; -/** - * Jank tests for the program guide. - */ +/** Jank tests for the program guide. */ @MediumTest public class ProgramGuideJankTest extends LiveChannelsTestCase { private static final String STARTING_CHANNEL = "13"; /** - * The minimum number of frames expected during each jank test. - * If there is less the test will fail. To be safe we loop the action in each test to create - * twice this many frames under normal conditions. + * The minimum number of frames expected during each jank test. If there is less the test will + * fail. To be safe we loop the action in each test to create twice this many frames under + * normal conditions. + * * <p>200 is chosen so there will be enough frame for the 90th, 95th, and 98th percentile * measurements are significant. * @@ -54,8 +52,7 @@ public class ProgramGuideJankTest extends LiveChannelsTestCase { Utils.pressKeysForChannelNumber(STARTING_CHANNEL, mDevice); } - @JankTest(expectedFrames = EXPECTED_FRAMES, - beforeTest = "warmProgramGuide") + @JankTest(expectedFrames = EXPECTED_FRAMES, beforeTest = "warmProgramGuide") @GfxMonitor(processName = Utils.LIVE_CHANNELS_PROCESS_NAME) public void testShowClearProgramGuide() { int frames = 53; // measured by hand @@ -66,24 +63,28 @@ public class ProgramGuideJankTest extends LiveChannelsTestCase { } } - @JankTest(expectedFrames = EXPECTED_FRAMES, - beforeLoop = "showAndFocusProgramGuide", - afterLoop = "clearProgramGuide") + @JankTest( + expectedFrames = EXPECTED_FRAMES, + beforeLoop = "showAndFocusProgramGuide", + afterLoop = "clearProgramGuide" + ) @GfxMonitor(processName = Utils.LIVE_CHANNELS_PROCESS_NAME) public void testScrollDown() { - int frames = 20; // measured by hand + int frames = 20; // measured by hand int repeat = EXPECTED_FRAMES * 2 / frames; for (int i = 0; i < repeat; i++) { mDevice.pressDPadDown(); } } - @JankTest(expectedFrames = EXPECTED_FRAMES, - beforeLoop = "showAndFocusProgramGuide", - afterLoop = "clearProgramGuide") + @JankTest( + expectedFrames = EXPECTED_FRAMES, + beforeLoop = "showAndFocusProgramGuide", + afterLoop = "clearProgramGuide" + ) @GfxMonitor(processName = Utils.LIVE_CHANNELS_PROCESS_NAME) public void testScrollRight() { - int frames = 30; // measured by hand + int frames = 30; // measured by hand int repeat = EXPECTED_FRAMES * 2 / frames; for (int i = 0; i < repeat; i++) { mDevice.pressDPadRight(); @@ -92,8 +93,8 @@ public class ProgramGuideJankTest extends LiveChannelsTestCase { private void selectProgramGuideMenuItem() { mMenuHelper.showMenu(); - mMenuHelper.assertNavigateToMenuItem(R.string.menu_title_channels, - R.string.channels_item_program_guide); + mMenuHelper.assertNavigateToMenuItem( + R.string.menu_title_channels, R.string.channels_item_program_guide); mDevice.waitForIdle(); } diff --git a/tests/jank/src/com/android/tv/tests/jank/Utils.java b/tests/jank/src/com/android/tv/tests/jank/Utils.java index cd1f7eff..4ad0f643 100644 --- a/tests/jank/src/com/android/tv/tests/jank/Utils.java +++ b/tests/jank/src/com/android/tv/tests/jank/Utils.java @@ -15,19 +15,16 @@ */ package com.android.tv.tests.jank; -import com.android.tv.testing.uihelper.UiDeviceUtils; - import android.support.test.uiautomator.UiDevice; +import com.android.tv.testing.uihelper.UiDeviceUtils; public final class Utils { /** Live TV process name */ public static final String LIVE_CHANNELS_PROCESS_NAME = "com.android.tv"; - private Utils() { } + private Utils() {} - /** - * Presses channel number to tune to {@code channel}. - */ + /** Presses channel number to tune to {@code channel}. */ public static void pressKeysForChannelNumber(String channel, UiDevice uiDevice) { UiDeviceUtils.pressKeys(uiDevice, channel); uiDevice.pressDPadCenter(); diff --git a/tests/tunerscripts/measure-tuning-time.awk b/tests/tunerscripts/measure-tuning-time.awk new file mode 100644 index 00000000..e7febcf1 --- /dev/null +++ b/tests/tunerscripts/measure-tuning-time.awk @@ -0,0 +1,32 @@ +# Awk script to measure tuning time statistics from logcat dump + +BEGIN { + n = 0; + sum = 0; +} + +# Collect tuning time with "Video available in <time> ms" message +/Video available in/ { + n++; + tune_time = $11; + sum += tune_time; + if (n == 1) { + min = tune_time; + max = tune_time; + } else { + if (tune_time < min) { + min = tune_time + } + if (tune_time > max) { + max = tune_time + } + } +} + +END { + average = sum / n; + print "Average tune time", average, "ms"; + print "Minimum tune time", min, "ms"; + print "Maximum tune time", max, "ms"; +} + diff --git a/tests/tunerscripts/usbtuner-test.sh b/tests/tunerscripts/usbtuner-test.sh new file mode 100755 index 00000000..b8c15841 --- /dev/null +++ b/tests/tunerscripts/usbtuner-test.sh @@ -0,0 +1,159 @@ +#!/bin/bash +# +# Copyright (C) 2017 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. +# +# usage: usbtuner-test.sh <test_case> [channel] +# +# To test repeated channel change, run: +# +# ./usbtuner-test.sh <1 or 3> +# +# To test watching a fixed channel, run: +# +# ./usbtuner-test.sh 2 +# +# Case 2 uses the last-viewed channel by TV app. Give a channel number +# as a 2nd parameter if you want to use the channel for testing, like below: +# +# ./usbtuner-test.sh 2 6-1 +# +# The script assumes that: +# 1) Browsing by keydown event circulates among the USB input channels only +# 2) When started, TV app should tune to one of the channels provided by the USB input +# +# The test result is logged in the doc: https://goo.gl/MsPBf7 + +function start_tv { + disable_analytics_report + adb shell am force-stop com.android.tv + adb shell am start -n com.android.tv/.MainActivity > /dev/null + sleep 5 +} + +function log_begin { + adb shell dumpsys meminfo -d --package com.android.tv.tuner > meminfo-begin.txt +} + +function tune { + adb shell input text $1 + adb shell input keyevent KEYCODE_DPAD_CENTER + sleep 5 # Wait enough for tuning +} + +function browse { + for i in {1..50}; do + adb shell input keyevent DPAD_DOWN + sleep 10 # Tune and watch the channel for a while + done; +} + +function browse_heavily { + for i in {1..60}; do + echo "$(date '+%x %X') ======== Test #$i of 60 ========" + clear_logcat + for j in {1..60}; do + adb shell input keyevent DPAD_DOWN + sleep $(( $RANDOM % 3 )) # Sleep for 0 - 2 seconds + done; + measure_tuning_time + done; +} + +function clear_logcat { + adb logcat -c +} + +function measure_tuning_time { + timeout 1 adb logcat -s TvInputSessionImpl | awk -f $(dirname $0)/measure-tuning-time.awk +} + +function log_end { + adb shell dumpsys meminfo -d --package com.android.tv.tuner > meminfo-end.txt +} + +function stop_tv { + # Stop TV by running other app (Settings) + adb shell am start com.android.tv.settings/com.android.tv.settings.MainSettings + restore_analytics_setting +} + +function output { + echo "Cut and paste this" + sed -n 33,46p meminfo-begin.txt | cut -f 2 -d ":" -s | awk '{print $1}' + sed -n 33,46p meminfo-end.txt | cut -f 2 -d ":" -s | awk '{print $1}' +} + +function disable_analytics_report { + tracker=$(adb shell getprop tv_use_tracker | tr -d '[[:space:]]') + adb shell setprop tv_use_tracker false +} + +function restore_analytics_setting { + if [ "${tracker}" == "" ]; then + adb shell setprop tv_use_tracker "" + else + adb shell setprop tv_use_tracker ${tracker} + fi +} + +function control_c { + restore_analytics_setting + echo "Exiting..." + exit 1 +} + +# Entry point + +trap control_c SIGINT + +case "$1" in + 1) + echo "Runing test 1" + start_tv + log_begin + clear_logcat + browse # Repeat channel change for about 10 minutes + measure_tuning_time + log_end + stop_tv + output + ;; + 2) + echo "Runing test 2" + start_tv + log_begin + if [ "$2" != "" ]; then + tune $2 + fi + sleep 600 # 10 minutes + log_end + stop_tv + output + ;; + 3) + echo "Runing test 3" + start_tv + log_begin + browse_heavily # Repeat channel change for about 3 hours + log_end + stop_tv + output + ;; + *) + echo "usage: usbtuner-test.sh <1|2|3> [channel]" + exit 1 + ;; +esac + diff --git a/tests/unit/Android.mk b/tests/unit/Android.mk index 3632fe94..a425bcfe 100644 --- a/tests/unit/Android.mk +++ b/tests/unit/Android.mk @@ -12,6 +12,11 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ mockito-target \ tv-test-common \ +LOCAL_JAVA_LIBRARIES := \ + android.test.runner.stubs \ + android.test.base.stubs \ + android.test.mock.stubs \ + LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/../common/res @@ -20,7 +25,7 @@ LOCAL_PACKAGE_NAME := TVUnitTests LOCAL_INSTRUMENTATION_FOR := LiveTv LOCAL_SDK_VERSION := system_current -LOCAL_MIN_SDK_VERSION := 23 # M +LOCAL_PROGUARD_ENABLED := disabled include $(BUILD_PACKAGE) diff --git a/tests/unit/AndroidManifest.xml b/tests/unit/AndroidManifest.xml index d073f8ac..9134a1c1 100644 --- a/tests/unit/AndroidManifest.xml +++ b/tests/unit/AndroidManifest.xml @@ -18,7 +18,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.tv.tests" > - <uses-sdk android:targetSdkVersion="23" android:minSdkVersion="23" /> + <uses-sdk android:targetSdkVersion="26" android:minSdkVersion="23" /> <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" diff --git a/tests/unit/src/com/android/tv/CurrentPositionMediatorTest.java b/tests/unit/src/com/android/tv/CurrentPositionMediatorTest.java index f2917181..abadde31 100644 --- a/tests/unit/src/com/android/tv/CurrentPositionMediatorTest.java +++ b/tests/unit/src/com/android/tv/CurrentPositionMediatorTest.java @@ -18,16 +18,18 @@ package com.android.tv; import static com.android.tv.TimeShiftManager.INVALID_TIME; import static com.android.tv.TimeShiftManager.REQUEST_TIMEOUT_MS; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotSame; +import static com.google.common.truth.Truth.assertWithMessage; import android.support.test.annotation.UiThreadTest; import android.support.test.filters.MediumTest; - +import android.support.test.runner.AndroidJUnit4; +import com.android.tv.testing.activities.BaseMainActivityTestCase; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; @MediumTest +@RunWith(AndroidJUnit4.class) public class CurrentPositionMediatorTest extends BaseMainActivityTestCase { private TimeShiftManager.CurrentPositionMediator mMediator; @@ -51,8 +53,12 @@ public class CurrentPositionMediatorTest extends BaseMainActivityTestCase { public void testOnSeekRequested() { long seekToTimeMs = System.currentTimeMillis() - REQUEST_TIMEOUT_MS * 3; mMediator.onSeekRequested(seekToTimeMs); - assertNotSame("Seek request time", INVALID_TIME, mMediator.mSeekRequestTimeMs); - assertEquals("Current position", seekToTimeMs, mMediator.mCurrentPositionMs); + assertWithMessage("Seek request time") + .that(mMediator.mSeekRequestTimeMs) + .isNotSameAs(INVALID_TIME); + assertWithMessage("Current position") + .that(mMediator.mCurrentPositionMs) + .isEqualTo(seekToTimeMs); } @UiThreadTest @@ -62,9 +68,15 @@ public class CurrentPositionMediatorTest extends BaseMainActivityTestCase { long newCurrentTimeMs = seekToTimeMs + REQUEST_TIMEOUT_MS; mMediator.onSeekRequested(seekToTimeMs); mMediator.onCurrentPositionChanged(newCurrentTimeMs); - assertNotSame("Seek request time", INVALID_TIME, mMediator.mSeekRequestTimeMs); - assertNotSame("Current position", seekToTimeMs, mMediator.mCurrentPositionMs); - assertNotSame("Current position", newCurrentTimeMs, mMediator.mCurrentPositionMs); + assertWithMessage("Seek request time") + .that(mMediator.mSeekRequestTimeMs) + .isNotSameAs(INVALID_TIME); + assertWithMessage("Current position") + .that(mMediator.mCurrentPositionMs) + .isNotSameAs(seekToTimeMs); + assertWithMessage("Current position") + .that(mMediator.mCurrentPositionMs) + .isNotSameAs(newCurrentTimeMs); } @UiThreadTest @@ -77,9 +89,13 @@ public class CurrentPositionMediatorTest extends BaseMainActivityTestCase { assertCurrentPositionMediator(INVALID_TIME, newCurrentTimeMs); } - private void assertCurrentPositionMediator(long expectedSeekRequestTimeMs, - long expectedCurrentPositionMs) { - assertEquals("Seek request time", expectedSeekRequestTimeMs, mMediator.mSeekRequestTimeMs); - assertEquals("Current position", expectedCurrentPositionMs, mMediator.mCurrentPositionMs); + private void assertCurrentPositionMediator( + long expectedSeekRequestTimeMs, long expectedCurrentPositionMs) { + assertWithMessage("Seek request time") + .that(mMediator.mSeekRequestTimeMs) + .isEqualTo(expectedSeekRequestTimeMs); + assertWithMessage("Current position") + .that(mMediator.mCurrentPositionMs) + .isEqualTo(expectedCurrentPositionMs); } } diff --git a/tests/unit/src/com/android/tv/FeaturesTest.java b/tests/unit/src/com/android/tv/FeaturesTest.java index 9d61e757..e19f4b7c 100644 --- a/tests/unit/src/com/android/tv/FeaturesTest.java +++ b/tests/unit/src/com/android/tv/FeaturesTest.java @@ -16,21 +16,21 @@ package com.android.tv; -import static org.junit.Assert.assertFalse; +import static com.google.common.truth.Truth.assertThat; import android.support.test.filters.SmallTest; - +import android.support.test.runner.AndroidJUnit4; import org.junit.Test; +import org.junit.runner.RunWith; -/** - * Test for features. - */ +/** Test for features. */ @SmallTest +@RunWith(AndroidJUnit4.class) public class FeaturesTest { @Test public void testPropertyFeatureKeyLength() { // This forces the class to be loaded and verifies all PropertyFeature key lengths. // If any keys are too long the test will fail to load. - assertFalse(Features.TEST_FEATURE.isEnabled(null)); + assertThat(TvFeatures.TEST_FEATURE.isEnabled(null)).isFalse(); } } diff --git a/tests/unit/src/com/android/tv/MainActivityTest.java b/tests/unit/src/com/android/tv/MainActivityTest.java index 15805032..c5df21a9 100644 --- a/tests/unit/src/com/android/tv/MainActivityTest.java +++ b/tests/unit/src/com/android/tv/MainActivityTest.java @@ -16,31 +16,30 @@ package com.android.tv; import static android.support.test.InstrumentationRegistry.getInstrumentation; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; import android.support.test.filters.MediumTest; +import android.support.test.runner.AndroidJUnit4; import android.view.View; import android.widget.TextView; - -import com.android.tv.data.Channel; +import com.android.tv.data.api.Channel; +import com.android.tv.testing.activities.BaseMainActivityTestCase; import com.android.tv.testing.testinput.TvTestInputConstants; import com.android.tv.ui.ChannelBannerView; - -import org.junit.Test; - import java.util.List; +import org.junit.Test; +import org.junit.runner.RunWith; -/** - * Tests for {@link MainActivity}. - */ +/** Tests for {@link MainActivity}. */ @MediumTest +@RunWith(AndroidJUnit4.class) public class MainActivityTest extends BaseMainActivityTestCase { @Test public void testInitialConditions() { waitUntilChannelLoadingFinish(); List<Channel> channelList = mActivity.getChannelDataManager().getChannelList(); - assertTrue("Expected at least one channel", channelList.size() > 0); + assertWithMessage("Expected at least one channel").that(channelList.size() > 0).isTrue(); } @Test @@ -61,17 +60,19 @@ public class MainActivityTest extends BaseMainActivityTestCase { private void showProgramGuide() { // Run on UI thread so views can be modified - getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - mActivity.getOverlayManager().showProgramGuide(); - } - }); + getInstrumentation() + .runOnMainSync( + new Runnable() { + @Override + public void run() { + mActivity.getOverlayManager().showProgramGuide(); + } + }); } private void assertChannelName(String displayName) { TextView channelNameView = (TextView) mActivity.findViewById(R.id.channel_name); - assertEquals("Channel Name", displayName, channelNameView.getText()); + assertWithMessage("Channel Name").that(channelNameView.getText()).isEqualTo(displayName); } private void assertProgramGuide(boolean isShown) { @@ -83,12 +84,13 @@ public class MainActivityTest extends BaseMainActivityTestCase { return (ChannelBannerView) v; } - private View assertExpectedBannerSceneClassShown(Class<ChannelBannerView> expectedClass, - boolean expectedShown) { - View v = assertViewIsShown(expectedClass.getSimpleName(), R.id.scene_transition_common, - expectedShown); + private View assertExpectedBannerSceneClassShown( + Class<ChannelBannerView> expectedClass, boolean expectedShown) { + View v = + assertViewIsShown( + expectedClass.getSimpleName(), R.id.scene_transition_common, expectedShown); if (v != null) { - assertEquals(expectedClass, v.getClass()); + assertThat(v.getClass()).isEqualTo(expectedClass); } return v; } @@ -102,7 +104,7 @@ public class MainActivityTest extends BaseMainActivityTestCase { return null; } } - assertEquals(viewName + " shown", expected, view.isShown()); + assertWithMessage(viewName + " shown").that(view.isShown()).isEqualTo(expected); return view; } } diff --git a/tests/unit/src/com/android/tv/TimeShiftManagerTest.java b/tests/unit/src/com/android/tv/TimeShiftManagerTest.java index 052b5d19..cb523045 100644 --- a/tests/unit/src/com/android/tv/TimeShiftManagerTest.java +++ b/tests/unit/src/com/android/tv/TimeShiftManagerTest.java @@ -22,14 +22,17 @@ import static com.android.tv.TimeShiftManager.TIME_SHIFT_ACTION_ID_JUMP_TO_PREVI import static com.android.tv.TimeShiftManager.TIME_SHIFT_ACTION_ID_PAUSE; import static com.android.tv.TimeShiftManager.TIME_SHIFT_ACTION_ID_PLAY; import static com.android.tv.TimeShiftManager.TIME_SHIFT_ACTION_ID_REWIND; -import static org.junit.Assert.assertEquals; +import static com.google.common.truth.Truth.assertWithMessage; import android.support.test.filters.MediumTest; - +import android.support.test.runner.AndroidJUnit4; +import com.android.tv.testing.activities.BaseMainActivityTestCase; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; @MediumTest +@RunWith(AndroidJUnit4.class) public class TimeShiftManagerTest extends BaseMainActivityTestCase { private TimeShiftManager mTimeShiftManager; @@ -85,19 +88,30 @@ public class TimeShiftManagerTest extends BaseMainActivityTestCase { mTimeShiftManager.enableAction(TIME_SHIFT_ACTION_ID_JUMP_TO_NEXT, enabled); } - private void assertActionState(boolean playEnabled, boolean pauseEnabled, boolean rewindEnabled, - boolean fastForwardEnabled, boolean jumpToPreviousEnabled, boolean jumpToNextEnabled) { - assertEquals("Play Action", playEnabled, - mTimeShiftManager.isActionEnabled(TIME_SHIFT_ACTION_ID_PLAY)); - assertEquals("Pause Action", pauseEnabled, - mTimeShiftManager.isActionEnabled(TIME_SHIFT_ACTION_ID_PAUSE)); - assertEquals("Rewind Action", rewindEnabled, - mTimeShiftManager.isActionEnabled(TIME_SHIFT_ACTION_ID_REWIND)); - assertEquals("Fast Forward Action", fastForwardEnabled, - mTimeShiftManager.isActionEnabled(TIME_SHIFT_ACTION_ID_FAST_FORWARD)); - assertEquals("Jump To Previous Action", jumpToPreviousEnabled, - mTimeShiftManager.isActionEnabled(TIME_SHIFT_ACTION_ID_JUMP_TO_PREVIOUS)); - assertEquals("Jump To Next Action", jumpToNextEnabled, - mTimeShiftManager.isActionEnabled(TIME_SHIFT_ACTION_ID_JUMP_TO_NEXT)); + private void assertActionState( + boolean playEnabled, + boolean pauseEnabled, + boolean rewindEnabled, + boolean fastForwardEnabled, + boolean jumpToPreviousEnabled, + boolean jumpToNextEnabled) { + assertWithMessage("Play Action") + .that(mTimeShiftManager.isActionEnabled(TIME_SHIFT_ACTION_ID_PLAY)) + .isEqualTo(playEnabled); + assertWithMessage("Pause Action") + .that(mTimeShiftManager.isActionEnabled(TIME_SHIFT_ACTION_ID_PAUSE)) + .isEqualTo(pauseEnabled); + assertWithMessage("Rewind Action") + .that(mTimeShiftManager.isActionEnabled(TIME_SHIFT_ACTION_ID_REWIND)) + .isEqualTo(rewindEnabled); + assertWithMessage("Fast Forward Action") + .that(mTimeShiftManager.isActionEnabled(TIME_SHIFT_ACTION_ID_FAST_FORWARD)) + .isEqualTo(fastForwardEnabled); + assertWithMessage("Jump To Previous Action") + .that(mTimeShiftManager.isActionEnabled(TIME_SHIFT_ACTION_ID_JUMP_TO_PREVIOUS)) + .isEqualTo(jumpToPreviousEnabled); + assertWithMessage("Jump To Next Action") + .that(mTimeShiftManager.isActionEnabled(TIME_SHIFT_ACTION_ID_JUMP_TO_NEXT)) + .isEqualTo(jumpToNextEnabled); } } diff --git a/tests/unit/src/com/android/tv/data/ChannelDataManagerTest.java b/tests/unit/src/com/android/tv/data/ChannelDataManagerTest.java index 7a4a4982..96c1f7a1 100644 --- a/tests/unit/src/com/android/tv/data/ChannelDataManagerTest.java +++ b/tests/unit/src/com/android/tv/data/ChannelDataManagerTest.java @@ -18,9 +18,8 @@ package com.android.tv.data; import static android.support.test.InstrumentationRegistry.getInstrumentation; import static android.support.test.InstrumentationRegistry.getTargetContext; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; import android.content.ContentProvider; import android.content.ContentUris; @@ -31,7 +30,9 @@ import android.database.Cursor; import android.media.tv.TvContract; import android.media.tv.TvContract.Channels; import android.net.Uri; +import android.os.AsyncTask; import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; import android.test.MoreAsserts; import android.test.mock.MockContentProvider; import android.test.mock.MockContentResolver; @@ -39,30 +40,30 @@ import android.test.mock.MockCursor; import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; - -import com.android.tv.testing.ChannelInfo; -import com.android.tv.testing.Constants; +import com.android.tv.data.api.Channel; +import com.android.tv.testing.constants.Constants; +import com.android.tv.testing.data.ChannelInfo; import com.android.tv.util.TvInputManagerHelper; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Matchers; -import org.mockito.Mockito; - import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Matchers; +import org.mockito.Mockito; /** * Test for {@link ChannelDataManager} * - * A test method may include tests for multiple methods to minimize the DB access. - * Note that all the methods of {@link ChannelDataManager} should be called from the UI thread. + * <p>A test method may include tests for multiple methods to minimize the DB access. Note that all + * the methods of {@link ChannelDataManager} should be called from the UI thread. */ @SmallTest +@RunWith(AndroidJUnit4.class) public class ChannelDataManagerTest { private static final boolean DEBUG = false; private static final String TAG = "ChannelDataManagerTest"; @@ -80,73 +81,89 @@ public class ChannelDataManagerTest { @Before public void setUp() { - assertTrue("More than 2 channels to test", Constants.UNIT_TEST_CHANNEL_COUNT > 2); + assertWithMessage("More than 2 channels to test") + .that(Constants.UNIT_TEST_CHANNEL_COUNT > 2) + .isTrue(); mContentProvider = new FakeContentProvider(getTargetContext()); mContentResolver = new FakeContentResolver(); mContentResolver.addProvider(TvContract.AUTHORITY, mContentProvider); mListener = new TestChannelDataManagerListener(); - getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - TvInputManagerHelper mockHelper = Mockito.mock(TvInputManagerHelper.class); - Mockito.when(mockHelper.hasTvInputInfo(Matchers.anyString())).thenReturn(true); - mChannelDataManager = new ChannelDataManager(getTargetContext(), mockHelper, - mContentResolver); - mChannelDataManager.addListener(mListener); - } - }); + getInstrumentation() + .runOnMainSync( + new Runnable() { + @Override + public void run() { + TvInputManagerHelper mockHelper = + Mockito.mock(TvInputManagerHelper.class); + Mockito.when(mockHelper.hasTvInputInfo(Matchers.anyString())) + .thenReturn(true); + mChannelDataManager = + new ChannelDataManager( + getTargetContext(), + mockHelper, + AsyncTask.SERIAL_EXECUTOR, + mContentResolver); + mChannelDataManager.addListener(mListener); + } + }); } @After public void tearDown() { - getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - mChannelDataManager.stop(); - } - }); + getInstrumentation() + .runOnMainSync( + new Runnable() { + @Override + public void run() { + mChannelDataManager.stop(); + } + }); } private void startAndWaitForComplete() throws InterruptedException { - getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - mChannelDataManager.start(); - } - }); - assertTrue(mListener.loadFinishedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS)); + getInstrumentation() + .runOnMainSync( + new Runnable() { + @Override + public void run() { + mChannelDataManager.start(); + } + }); + assertThat(mListener.loadFinishedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS)) + .isTrue(); } private void restart() throws InterruptedException { - getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - mChannelDataManager.stop(); - mListener.reset(); - } - }); + getInstrumentation() + .runOnMainSync( + new Runnable() { + @Override + public void run() { + mChannelDataManager.stop(); + mListener.reset(); + } + }); startAndWaitForComplete(); } @Test public void testIsDbLoadFinished() throws InterruptedException { startAndWaitForComplete(); - assertTrue(mChannelDataManager.isDbLoadFinished()); + assertThat(mChannelDataManager.isDbLoadFinished()).isTrue(); } /** - * Test for following methods - * - {@link ChannelDataManager#getChannelCount} - * - {@link ChannelDataManager#getChannelList} - * - {@link ChannelDataManager#getChannel} + * Test for following methods - {@link ChannelDataManager#getChannelCount} - {@link + * ChannelDataManager#getChannelList} - {@link ChannelDataManager#getChannel} */ @Test public void testGetChannels() throws InterruptedException { startAndWaitForComplete(); // Test {@link ChannelDataManager#getChannelCount} - assertEquals(Constants.UNIT_TEST_CHANNEL_COUNT, mChannelDataManager.getChannelCount()); + assertThat(mChannelDataManager.getChannelCount()) + .isEqualTo(Constants.UNIT_TEST_CHANNEL_COUNT); // Test {@link ChannelDataManager#getChannelList} List<ChannelInfo> channelInfoList = new ArrayList<>(); @@ -157,36 +174,32 @@ public class ChannelDataManagerTest { for (Channel channel : channelList) { boolean found = false; for (ChannelInfo channelInfo : channelInfoList) { - if (TextUtils.equals(channelInfo.name, channel.getDisplayName()) - && TextUtils.equals(channelInfo.name, channel.getDisplayName())) { + if (TextUtils.equals(channelInfo.name, channel.getDisplayName())) { found = true; channelInfoList.remove(channelInfo); break; } } - assertTrue("Cannot find (" + channel + ")", found); + assertWithMessage("Cannot find (" + channel + ")").that(found).isTrue(); } // Test {@link ChannelDataManager#getChannelIndex()} for (Channel channel : channelList) { - assertEquals(channel, mChannelDataManager.getChannel(channel.getId())); + assertThat(mChannelDataManager.getChannel(channel.getId())).isEqualTo(channel); } } - /** - * Test for {@link ChannelDataManager#getChannelCount} when no channel is available. - */ + /** Test for {@link ChannelDataManager#getChannelCount} when no channel is available. */ @Test public void testGetChannels_noChannels() throws InterruptedException { mContentProvider.clear(); startAndWaitForComplete(); - assertEquals(0, mChannelDataManager.getChannelCount()); + assertThat(mChannelDataManager.getChannelCount()).isEqualTo(0); } /** - * Test for following methods and channel listener with notifying change. - * - {@link ChannelDataManager#updateBrowsable} - * - {@link ChannelDataManager#applyUpdatedValuesToDb} + * Test for following methods and channel listener with notifying change. - {@link + * ChannelDataManager#updateBrowsable} - {@link ChannelDataManager#applyUpdatedValuesToDb} */ @Test public void testBrowsable() throws InterruptedException { @@ -197,9 +210,9 @@ public class ChannelDataManagerTest { List<Channel> browsableChannelList = mChannelDataManager.getBrowsableChannelList(); for (Channel browsableChannel : browsableChannelList) { boolean found = channelList.remove(browsableChannel); - assertTrue("Cannot find (" + browsableChannel + ")", found); + assertWithMessage("Cannot find (" + browsableChannel + ")").that(found).isTrue(); } - assertEquals(0, channelList.size()); + assertThat(channelList).isEmpty(); // Prepare for next tests. channelList = mChannelDataManager.getChannelList(); @@ -210,8 +223,8 @@ public class ChannelDataManagerTest { // Test {@link ChannelDataManager#updateBrowsable} & notification. mChannelDataManager.updateBrowsable(channel1.getId(), false, false); - assertTrue(mListener.channelBrowsableChangedCalled); - assertFalse(mChannelDataManager.getBrowsableChannelList().contains(channel1)); + assertThat(mListener.channelBrowsableChangedCalled).isTrue(); + assertThat(mChannelDataManager.getBrowsableChannelList()).doesNotContain(channel1); MoreAsserts.assertContentsInAnyOrder(channelListener.updatedChannels, channel1); channelListener.reset(); @@ -221,14 +234,13 @@ public class ChannelDataManagerTest { mChannelDataManager.applyUpdatedValuesToDb(); restart(); browsableChannelList = mChannelDataManager.getBrowsableChannelList(); - assertEquals(Constants.UNIT_TEST_CHANNEL_COUNT - 1, browsableChannelList.size()); - assertFalse(browsableChannelList.contains(channel1)); + assertThat(browsableChannelList).hasSize(Constants.UNIT_TEST_CHANNEL_COUNT - 1); + assertThat(browsableChannelList).doesNotContain(channel1); } /** - * Test for following methods and channel listener without notifying change. - * - {@link ChannelDataManager#updateBrowsable} - * - {@link ChannelDataManager#applyUpdatedValuesToDb} + * Test for following methods and channel listener without notifying change. - {@link + * ChannelDataManager#updateBrowsable} - {@link ChannelDataManager#applyUpdatedValuesToDb} */ @Test public void testBrowsable_skipNotification() throws InterruptedException { @@ -247,10 +259,10 @@ public class ChannelDataManagerTest { mChannelDataManager.updateBrowsable(channel1.getId(), false, true); mChannelDataManager.updateBrowsable(channel2.getId(), false, true); mChannelDataManager.updateBrowsable(channel1.getId(), true, true); - assertFalse(mListener.channelBrowsableChangedCalled); + assertThat(mListener.channelBrowsableChangedCalled).isFalse(); List<Channel> browsableChannelList = mChannelDataManager.getBrowsableChannelList(); - assertTrue(browsableChannelList.contains(channel1)); - assertFalse(browsableChannelList.contains(channel2)); + assertThat(browsableChannelList).contains(channel1); + assertThat(browsableChannelList).doesNotContain(channel2); // Test {@link ChannelDataManager#applyUpdatedValuesToDb} // Disable the update notification to avoid the unwanted call of "onLoadFinished". @@ -258,14 +270,13 @@ public class ChannelDataManagerTest { mChannelDataManager.applyUpdatedValuesToDb(); restart(); browsableChannelList = mChannelDataManager.getBrowsableChannelList(); - assertEquals(Constants.UNIT_TEST_CHANNEL_COUNT - 1, browsableChannelList.size()); - assertFalse(browsableChannelList.contains(channel2)); + assertThat(browsableChannelList).hasSize(Constants.UNIT_TEST_CHANNEL_COUNT - 1); + assertThat(browsableChannelList).doesNotContain(channel2); } /** - * Test for following methods and channel listener. - * - {@link ChannelDataManager#updateLocked} - * - {@link ChannelDataManager#applyUpdatedValuesToDb} + * Test for following methods and channel listener. - {@link ChannelDataManager#updateLocked} - + * {@link ChannelDataManager#applyUpdatedValuesToDb} */ @Test public void testLocked() throws InterruptedException { @@ -274,7 +285,7 @@ public class ChannelDataManagerTest { // Test if all channels aren't locked at the first time. List<Channel> channelList = mChannelDataManager.getChannelList(); for (Channel channel : channelList) { - assertFalse(channel + " is locked", channel.isLocked()); + assertWithMessage(channel + " is locked").that(channel.isLocked()).isFalse(); } // Prepare for next tests. @@ -282,22 +293,20 @@ public class ChannelDataManagerTest { // Test {@link ChannelDataManager#updateLocked} mChannelDataManager.updateLocked(channel.getId(), true); - assertTrue(mChannelDataManager.getChannel(channel.getId()).isLocked()); + assertThat(mChannelDataManager.getChannel(channel.getId()).isLocked()).isTrue(); // Test {@link ChannelDataManager#applyUpdatedValuesToDb}. // Disable the update notification to avoid the unwanted call of "onLoadFinished". mContentResolver.mNotifyDisabled = true; mChannelDataManager.applyUpdatedValuesToDb(); restart(); - assertTrue(mChannelDataManager.getChannel(channel.getId()).isLocked()); + assertThat(mChannelDataManager.getChannel(channel.getId()).isLocked()).isTrue(); // Cleanup mChannelDataManager.updateLocked(channel.getId(), false); } - /** - * Test ChannelDataManager when channels in TvContract are updated, removed, or added. - */ + /** Test ChannelDataManager when channels in TvContract are updated, removed, or added. */ @Test public void testChannelListChanged() throws InterruptedException { startAndWaitForComplete(); @@ -308,9 +317,10 @@ public class ChannelDataManagerTest { ChannelInfo testChannelInfo = ChannelInfo.create(getTargetContext(), (int) testChannelId); testChannelId = Constants.UNIT_TEST_CHANNEL_COUNT + 1; mContentProvider.simulateInsert(testChannelInfo); - assertTrue( - mListener.channelListUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS)); - assertEquals(Constants.UNIT_TEST_CHANNEL_COUNT + 1, mChannelDataManager.getChannelCount()); + assertThat(mListener.channelListUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS)) + .isTrue(); + assertThat(mChannelDataManager.getChannelCount()) + .isEqualTo(Constants.UNIT_TEST_CHANNEL_COUNT + 1); // Test channel update mListener.reset(); @@ -319,39 +329,45 @@ public class ChannelDataManagerTest { mChannelDataManager.addChannelListener(testChannelId, channelListener); String newName = testChannelInfo.name + "_test"; mContentProvider.simulateUpdate(testChannelId, newName); - assertTrue( - mListener.channelListUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS)); - assertTrue( - channelListener.channelChangedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS)); - assertEquals(0, channelListener.removedChannels.size()); - assertEquals(1, channelListener.updatedChannels.size()); + assertThat(mListener.channelListUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS)) + .isTrue(); + assertThat( + channelListener.channelChangedLatch.await( + WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS)) + .isTrue(); + assertThat(channelListener.removedChannels).isEmpty(); + assertThat(channelListener.updatedChannels).hasSize(1); Channel updatedChannel = channelListener.updatedChannels.get(0); - assertEquals(testChannelId, updatedChannel.getId()); - assertEquals(testChannelInfo.number, updatedChannel.getDisplayNumber()); - assertEquals(newName, updatedChannel.getDisplayName()); - assertEquals(Constants.UNIT_TEST_CHANNEL_COUNT + 1, - mChannelDataManager.getChannelCount()); + assertThat(updatedChannel.getId()).isEqualTo(testChannelId); + assertThat(updatedChannel.getDisplayNumber()).isEqualTo(testChannelInfo.number); + assertThat(updatedChannel.getDisplayName()).isEqualTo(newName); + assertThat(mChannelDataManager.getChannelCount()) + .isEqualTo(Constants.UNIT_TEST_CHANNEL_COUNT + 1); // Test channel remove. mListener.reset(); channelListener.reset(); mContentProvider.simulateDelete(testChannelId); - assertTrue( - mListener.channelListUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS)); - assertTrue( - channelListener.channelChangedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS)); - assertEquals(1, channelListener.removedChannels.size()); - assertEquals(0, channelListener.updatedChannels.size()); + assertThat(mListener.channelListUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS)) + .isTrue(); + assertThat( + channelListener.channelChangedLatch.await( + WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS)) + .isTrue(); + assertThat(channelListener.removedChannels).hasSize(1); + assertThat(channelListener.updatedChannels).isEmpty(); Channel removedChannel = channelListener.removedChannels.get(0); - assertEquals(newName, removedChannel.getDisplayName()); - assertEquals(testChannelInfo.number, removedChannel.getDisplayNumber()); - assertEquals(Constants.UNIT_TEST_CHANNEL_COUNT, mChannelDataManager.getChannelCount()); + assertThat(removedChannel.getDisplayName()).isEqualTo(newName); + assertThat(removedChannel.getDisplayNumber()).isEqualTo(testChannelInfo.number); + assertThat(mChannelDataManager.getChannelCount()) + .isEqualTo(Constants.UNIT_TEST_CHANNEL_COUNT); } - private class ChannelInfoWrapper { + private static class ChannelInfoWrapper { public ChannelInfo channelInfo; public boolean browsable; public boolean locked; + public ChannelInfoWrapper(ChannelInfo channelInfo) { this.channelInfo = channelInfo; browsable = true; @@ -366,8 +382,14 @@ public class ChannelDataManagerTest { public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) { super.notifyChange(uri, observer, syncToNetwork); if (DEBUG) { - Log.d(TAG, "onChanged(uri=" + uri + ", observer=" + observer + ") - Notification " - + (mNotifyDisabled ? "disabled" : "enabled")); + Log.d( + TAG, + "onChanged(uri=" + + uri + + ", observer=" + + observer + + ") - Notification " + + (mNotifyDisabled ? "disabled" : "enabled")); } if (mNotifyDisabled) { return; @@ -390,19 +412,23 @@ public class ChannelDataManagerTest { public FakeContentProvider(Context context) { super(context); for (int i = 1; i <= Constants.UNIT_TEST_CHANNEL_COUNT; i++) { - mChannelInfoList.put(i, - new ChannelInfoWrapper(ChannelInfo.create(getTargetContext(), i))); + mChannelInfoList.put( + i, new ChannelInfoWrapper(ChannelInfo.create(getTargetContext(), i))); } } /** - * Implementation of {@link ContentProvider#query}. - * This assumes that {@link ChannelDataManager} queries channels - * with empty {@code selection}. (i.e. channels are always queries for all) + * Implementation of {@link ContentProvider#query}. This assumes that {@link + * ChannelDataManager} queries channels with empty {@code selection}. (i.e. channels are + * always queries for all) */ @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] - selectionArgs, String sortOrder) { + public Cursor query( + Uri uri, + String[] projection, + String selection, + String[] selectionArgs, + String sortOrder) { if (DEBUG) { Log.d(TAG, "dump query"); Log.d(TAG, " uri=" + uri); @@ -414,9 +440,8 @@ public class ChannelDataManagerTest { } /** - * Implementation of {@link ContentProvider#update}. - * This assumes that {@link ChannelDataManager} update channels - * only for changing browsable and locked. + * Implementation of {@link ContentProvider#update}. This assumes that {@link + * ChannelDataManager} update channels only for changing browsable and locked. */ @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { @@ -434,8 +459,9 @@ public class ChannelDataManagerTest { } } else { // See {@link Utils#buildSelectionForIds} for the syntax. - String selectionForId = selection.substring( - selection.indexOf("(") + 1, selection.lastIndexOf(")")); + String selectionForId = + selection.substring( + selection.indexOf("(") + 1, selection.lastIndexOf(")")); String[] ids = selectionForId.split(", "); if (ids != null) { for (String id : ids) { @@ -476,27 +502,25 @@ public class ChannelDataManagerTest { } /** - * Simulates channel data insert. - * This assigns original network ID (the same with channel number) to channel ID. + * Simulates channel data insert. This assigns original network ID (the same with channel + * number) to channel ID. */ public void simulateInsert(ChannelInfo testChannelInfo) { long channelId = testChannelInfo.originalNetworkId; - mChannelInfoList.put((int) channelId, new ChannelInfoWrapper( - ChannelInfo.create(getTargetContext(), (int) channelId))); + mChannelInfoList.put( + (int) channelId, + new ChannelInfoWrapper( + ChannelInfo.create(getTargetContext(), (int) channelId))); mContentResolver.notifyChange(TvContract.buildChannelUri(channelId), null); } - /** - * Simulates channel data delete. - */ + /** Simulates channel data delete. */ public void simulateDelete(long channelId) { mChannelInfoList.remove((int) channelId); mContentResolver.notifyChange(TvContract.buildChannelUri(channelId), null); } - /** - * Simulates channel data update. - */ + /** Simulates channel data update. */ public void simulateUpdate(long channelId, String newName) { ChannelInfoWrapper channel = mChannelInfoList.get((int) channelId); ChannelInfo.Builder builder = new ChannelInfo.Builder(channel.channelInfo); @@ -506,8 +530,9 @@ public class ChannelDataManagerTest { } private void assertChannelUri(Uri uri) { - assertTrue("Uri(" + uri + ") isn't channel uri", - uri.toString().startsWith(Channels.CONTENT_URI.toString())); + assertWithMessage("Uri(" + uri + ") isn't channel uri") + .that(uri.toString().startsWith(Channels.CONTENT_URI.toString())) + .isTrue(); } public void clear() { @@ -528,20 +553,21 @@ public class ChannelDataManagerTest { } private class FakeCursor extends MockCursor { - private final String[] ALL_COLUMNS = { - Channels._ID, - Channels.COLUMN_DISPLAY_NAME, - Channels.COLUMN_DISPLAY_NUMBER, - Channels.COLUMN_INPUT_ID, - Channels.COLUMN_VIDEO_FORMAT, - Channels.COLUMN_ORIGINAL_NETWORK_ID, - COLUMN_BROWSABLE, - COLUMN_LOCKED}; + private final String[] allColumns = { + Channels._ID, + Channels.COLUMN_DISPLAY_NAME, + Channels.COLUMN_DISPLAY_NUMBER, + Channels.COLUMN_INPUT_ID, + Channels.COLUMN_VIDEO_FORMAT, + Channels.COLUMN_ORIGINAL_NETWORK_ID, + COLUMN_BROWSABLE, + COLUMN_LOCKED + }; private final String[] mColumns; private int mPosition; public FakeCursor(String[] columns) { - mColumns = (columns == null) ? ALL_COLUMNS : columns; + mColumns = (columns == null) ? allColumns : columns; mPosition = -1; } @@ -566,6 +592,7 @@ public class ChannelDataManagerTest { switch (columnName) { case Channels._ID: return mContentProvider.keyAt(mPosition); + default: // fall out } if (DEBUG) { Log.d(TAG, "Column (" + columnName + ") is ignored in getLong()"); @@ -586,6 +613,7 @@ public class ChannelDataManagerTest { return DUMMY_INPUT_ID; case Channels.COLUMN_VIDEO_FORMAT: return channel.channelInfo.getVideoFormat(); + default: // fall out } if (DEBUG) { Log.d(TAG, "Column (" + columnName + ") is ignored in getString()"); @@ -604,6 +632,7 @@ public class ChannelDataManagerTest { return channel.browsable ? 1 : 0; case COLUMN_LOCKED: return channel.locked ? 1 : 0; + default: // fall out } if (DEBUG) { Log.d(TAG, "Column (" + columnName + ") is ignored in getInt()"); @@ -627,7 +656,7 @@ public class ChannelDataManagerTest { } } - private class TestChannelDataManagerListener implements ChannelDataManager.Listener { + private static class TestChannelDataManagerListener implements ChannelDataManager.Listener { public CountDownLatch loadFinishedLatch = new CountDownLatch(1); public CountDownLatch channelListUpdatedLatch = new CountDownLatch(1); public boolean channelBrowsableChangedCalled; @@ -654,7 +683,7 @@ public class ChannelDataManagerTest { } } - private class TestChannelDataManagerChannelListener + private static class TestChannelDataManagerChannelListener implements ChannelDataManager.ChannelListener { public CountDownLatch channelChangedLatch = new CountDownLatch(1); public final List<Channel> removedChannels = new ArrayList<>(); diff --git a/tests/unit/src/com/android/tv/data/ChannelImplTest.java b/tests/unit/src/com/android/tv/data/ChannelImplTest.java new file mode 100644 index 00000000..b791a7e4 --- /dev/null +++ b/tests/unit/src/com/android/tv/data/ChannelImplTest.java @@ -0,0 +1,381 @@ +/* + * 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 static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import com.android.tv.data.api.Channel; +import com.android.tv.testing.ComparatorTester; +import com.android.tv.util.TvInputManagerHelper; +import java.util.Comparator; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Matchers; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +/** Tests for {@link ChannelImpl}. */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class ChannelImplTest { + // 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; + + @Before + public void setUp() throws NameNotFoundException { + 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<ActivityInfo>() { + @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.<ComponentName>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); + } + + @Test + 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); + } + + @Test + 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); + } + + @Test + 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); + } + + @Test + 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); + } + + @Test + 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); + } + + @Test + 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 ChannelImpl, Intent.URI_INTENT_SCHEME is used to parse the URI. So the same flag + // should be + // used when the URI is created. + ChannelImpl testChannel = + new ChannelImpl.Builder() + .setPackageName(inputPackageName) + .setAppLinkText(appLinkText) + .setAppLinkIntentUri( + appLinkIntent == null + ? null + : appLinkIntent.toUri(Intent.URI_INTENT_SCHEME)) + .build(); + assertWithMessage("Unexpected app-link type for for " + testChannel) + .that(testChannel.getAppLinkType(mMockContext)) + .isEqualTo(expectedType); + } + + @Test + public void testComparator() { + TvInputManagerHelper manager = Mockito.mock(TvInputManagerHelper.class); + Mockito.when(manager.isPartnerInput(Matchers.anyString())) + .thenAnswer( + new Answer<Boolean>() { + @Override + public Boolean answer(InvocationOnMock invocation) throws Throwable { + String inputId = (String) invocation.getArguments()[0]; + return PARTNER_INPUT_ID.equals(inputId); + } + }); + Comparator<Channel> comparator = new TestChannelComparator(manager); + ComparatorTester<Channel> comparatorTester = ComparatorTester.withoutEqualsTest(comparator); + comparatorTester.addComparableGroup( + new ChannelImpl.Builder().setInputId(PARTNER_INPUT_ID).build()); + comparatorTester.addComparableGroup(new ChannelImpl.Builder().setInputId("1").build()); + comparatorTester.addComparableGroup( + new ChannelImpl.Builder().setInputId("1").setDisplayNumber("2").build()); + comparatorTester.addComparableGroup( + new ChannelImpl.Builder().setInputId("2").setDisplayNumber("1.0").build()); + + // display name does not affect comparator + comparatorTester.addComparableGroup( + new ChannelImpl.Builder() + .setInputId("2") + .setDisplayNumber("1.62") + .setDisplayName("test1") + .build(), + new ChannelImpl.Builder() + .setInputId("2") + .setDisplayNumber("1.62") + .setDisplayName("test2") + .build(), + new ChannelImpl.Builder() + .setInputId("2") + .setDisplayNumber("1.62") + .setDisplayName("test3") + .build()); + comparatorTester.addComparableGroup( + new ChannelImpl.Builder().setInputId("2").setDisplayNumber("2.0").build()); + // Numeric display number sorting + comparatorTester.addComparableGroup( + new ChannelImpl.Builder().setInputId("2").setDisplayNumber("12.2").build()); + comparatorTester.test(); + } + + /** + * Test Input Label handled by {@link ChannelImpl.DefaultComparator}. + * + * <p>Sort partner inputs first, then sort by input label, then by input id. See <a + * href="http://b/23031603">b/23031603</a>. + */ + @Test + public void testComparatorLabel() { + TvInputManagerHelper manager = Mockito.mock(TvInputManagerHelper.class); + Mockito.when(manager.isPartnerInput(Matchers.anyString())) + .thenAnswer( + new Answer<Boolean>() { + @Override + public Boolean answer(InvocationOnMock invocation) throws Throwable { + String inputId = (String) invocation.getArguments()[0]; + return PARTNER_INPUT_ID.equals(inputId); + } + }); + Comparator<Channel> comparator = new ChannelComparatorWithDescriptionAsLabel(manager); + ComparatorTester<Channel> comparatorTester = ComparatorTester.withoutEqualsTest(comparator); + + comparatorTester.addComparableGroup( + new ChannelImpl.Builder().setInputId(PARTNER_INPUT_ID).setDescription("A").build()); + + // The description is used as a label for this test. + comparatorTester.addComparableGroup( + new ChannelImpl.Builder().setDescription("A").setInputId("1").build()); + comparatorTester.addComparableGroup( + new ChannelImpl.Builder().setDescription("A").setInputId("2").build()); + comparatorTester.addComparableGroup( + new ChannelImpl.Builder().setDescription("B").setInputId("1").build()); + + comparatorTester.test(); + } + + @Test + public void testNormalizeChannelNumber() { + assertNormalizedDisplayNumber(null, null); + assertNormalizedDisplayNumber("", ""); + assertNormalizedDisplayNumber("1", "1"); + assertNormalizedDisplayNumber("abcde", "abcde"); + assertNormalizedDisplayNumber("1-1", "1-1"); + assertNormalizedDisplayNumber("1.1", "1-1"); + assertNormalizedDisplayNumber("1 1", "1-1"); + assertNormalizedDisplayNumber("1\u058a1", "1-1"); + assertNormalizedDisplayNumber("1\u05be1", "1-1"); + assertNormalizedDisplayNumber("1\u14001", "1-1"); + assertNormalizedDisplayNumber("1\u18061", "1-1"); + assertNormalizedDisplayNumber("1\u20101", "1-1"); + assertNormalizedDisplayNumber("1\u20111", "1-1"); + assertNormalizedDisplayNumber("1\u20121", "1-1"); + assertNormalizedDisplayNumber("1\u20131", "1-1"); + assertNormalizedDisplayNumber("1\u20141", "1-1"); + } + + private void assertNormalizedDisplayNumber(String displayNumber, String normalized) { + assertThat(ChannelImpl.normalizeDisplayNumber(displayNumber)).isEqualTo(normalized); + } + + private static final class TestChannelComparator extends ChannelImpl.DefaultComparator { + public TestChannelComparator(TvInputManagerHelper manager) { + super(null, manager); + } + + @Override + public String getInputLabelForChannel(Channel channel) { + return channel.getInputId(); + } + } + + private static final class ChannelComparatorWithDescriptionAsLabel + extends ChannelImpl.DefaultComparator { + public ChannelComparatorWithDescriptionAsLabel(TvInputManagerHelper manager) { + super(null, manager); + } + + @Override + public String getInputLabelForChannel(Channel channel) { + return channel.getDescription(); + } + } +} diff --git a/tests/unit/src/com/android/tv/data/ChannelNumberTest.java b/tests/unit/src/com/android/tv/data/ChannelNumberTest.java deleted file mode 100644 index 827dcdbd..00000000 --- a/tests/unit/src/com/android/tv/data/ChannelNumberTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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 static com.android.tv.data.ChannelNumber.parseChannelNumber; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -import android.support.test.filters.SmallTest; - -import com.android.tv.testing.ComparableTester; - -import org.junit.Test; - -/** - * Tests for {@link ChannelNumber}. - */ -@SmallTest -public class ChannelNumberTest { - /** - * Test method for {@link ChannelNumber#ChannelNumber()}. - */ - @Test - public void testChannelNumber() { - assertChannelEquals(new ChannelNumber(), "", false, ""); - } - - /** - * Test method for - * {@link com.android.tv.data.ChannelNumber#parseChannelNumber(java.lang.String)}. - */ - @Test - public void testParseChannelNumber() { - assertNull(parseChannelNumber("")); - assertNull(parseChannelNumber("-")); - assertNull(parseChannelNumber("abcd12")); - assertNull(parseChannelNumber("12abcd")); - assertNull(parseChannelNumber("-12")); - assertChannelEquals(parseChannelNumber("1"), "1", false, ""); - assertChannelEquals(parseChannelNumber("1234-4321"), "1234", true, "4321"); - assertChannelEquals(parseChannelNumber("3-4"), "3", true, "4"); - assertChannelEquals(parseChannelNumber("5-6"), "5", true, "6"); - } - - /** - * Test method for {@link ChannelNumber#compareTo(com.android.tv.data.ChannelNumber)}. - */ - @Test - public void testCompareTo() { - new ComparableTester<ChannelNumber>() - .addEquivalentGroup(parseChannelNumber("1"), parseChannelNumber("1")) - .addEquivalentGroup(parseChannelNumber("2")) - .addEquivalentGroup(parseChannelNumber("2-1")) - .addEquivalentGroup(parseChannelNumber("2-2")) - .addEquivalentGroup(parseChannelNumber("2-10")) - .addEquivalentGroup(parseChannelNumber("3")) - .addEquivalentGroup(parseChannelNumber("4"), parseChannelNumber("4-0")) - .addEquivalentGroup(parseChannelNumber("10")) - .addEquivalentGroup(parseChannelNumber("100")) - .test(); - } - - /** - * Test method for {@link ChannelNumber#compare(java.lang.String, java.lang.String)}. - */ - @Test - public void testCompare() { - // Only need to test nulls, the reset is tested by testCompareTo - assertEquals("compareTo(null,null)", 0, ChannelNumber.compare(null, null)); - assertEquals("compareTo(1,1)", 0, ChannelNumber.compare("1", "1")); - assertEquals("compareTo(null,1)<0", true, ChannelNumber.compare(null, "1") < 0); - assertEquals("compareTo(mal-formatted,1)<0", true, ChannelNumber.compare("abcd", "1") < 0); - assertEquals("compareTo(mal-formatted,1)<0", true, ChannelNumber.compare(".4", "1") < 0); - assertEquals("compareTo(1,null)>0", true, ChannelNumber.compare("1", null) > 0); - } - - private void assertChannelEquals(ChannelNumber actual, String expectedMajor, - boolean expectedHasDelimiter, String expectedMinor) { - assertEquals(actual + " major", actual.majorNumber, expectedMajor); - assertEquals(actual + " hasDelimiter", actual.hasDelimiter, expectedHasDelimiter); - assertEquals(actual + " minor", actual.minorNumber, expectedMinor); - } - -} diff --git a/tests/unit/src/com/android/tv/data/ChannelTest.java b/tests/unit/src/com/android/tv/data/ChannelTest.java deleted file mode 100644 index 69fcb858..00000000 --- a/tests/unit/src/com/android/tv/data/ChannelTest.java +++ /dev/null @@ -1,312 +0,0 @@ -/* - * 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 static org.junit.Assert.assertEquals; - -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.support.test.filters.SmallTest; - -import com.android.tv.testing.ComparatorTester; -import com.android.tv.util.TvInputManagerHelper; - -import org.junit.Before; -import org.junit.Test; -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 { - // 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; - - @Before - public void setUp() throws NameNotFoundException { - 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<ActivityInfo>() { - @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.<ComponentName>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); - } - - @Test - 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); - } - - @Test - 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); - } - - @Test - 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); - } - - @Test - 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); - } - - @Test - 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); - } - - @Test - 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)); - } - - @Test - public void testComparator() { - - TvInputManagerHelper manager = Mockito.mock(TvInputManagerHelper.class); - Mockito.when(manager.isPartnerInput(Matchers.anyString())).thenAnswer( - new Answer<Boolean>() { - @Override - public Boolean answer(InvocationOnMock invocation) throws Throwable { - String inputId = (String) invocation.getArguments()[0]; - return PARTNER_INPUT_ID.equals(inputId); - } - }); - Comparator<Channel> comparator = new TestChannelComparator(manager); - ComparatorTester<Channel> 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}. - * - * <p>Sort partner inputs first, then sort by input label, then by input id. - * See <a href="http://b/23031603">b/23031603</a>. - */ - @Test - public void testComparatorLabel() { - TvInputManagerHelper manager = Mockito.mock(TvInputManagerHelper.class); - Mockito.when(manager.isPartnerInput(Matchers.anyString())).thenAnswer( - new Answer<Boolean>() { - @Override - public Boolean answer(InvocationOnMock invocation) throws Throwable { - String inputId = (String) invocation.getArguments()[0]; - return PARTNER_INPUT_ID.equals(inputId); - } - }); - Comparator<Channel> comparator = new ChannelComparatorWithDescriptionAsLabel(manager); - ComparatorTester<Channel> 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(); - } - - @Test - public void testNormalizeChannelNumber() { - assertNormalizedDisplayNumber(null, null); - assertNormalizedDisplayNumber("", ""); - assertNormalizedDisplayNumber("1", "1"); - assertNormalizedDisplayNumber("abcde", "abcde"); - assertNormalizedDisplayNumber("1-1", "1-1"); - assertNormalizedDisplayNumber("1.1", "1-1"); - assertNormalizedDisplayNumber("1 1", "1-1"); - assertNormalizedDisplayNumber("1\u058a1", "1-1"); - assertNormalizedDisplayNumber("1\u05be1", "1-1"); - assertNormalizedDisplayNumber("1\u14001", "1-1"); - assertNormalizedDisplayNumber("1\u18061", "1-1"); - assertNormalizedDisplayNumber("1\u20101", "1-1"); - assertNormalizedDisplayNumber("1\u20111", "1-1"); - assertNormalizedDisplayNumber("1\u20121", "1-1"); - assertNormalizedDisplayNumber("1\u20131", "1-1"); - assertNormalizedDisplayNumber("1\u20141", "1-1"); - } - - private void assertNormalizedDisplayNumber(String displayNumber, String normalized) { - assertEquals(normalized, Channel.normalizeDisplayNumber(displayNumber)); - } - - 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(); - } - } -} diff --git a/tests/unit/src/com/android/tv/data/GenreItemTest.java b/tests/unit/src/com/android/tv/data/GenreItemTest.java deleted file mode 100644 index fdbcb599..00000000 --- a/tests/unit/src/com/android/tv/data/GenreItemTest.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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 static android.support.test.InstrumentationRegistry.getTargetContext; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import android.media.tv.TvContract.Programs.Genres; -import android.os.Build; -import android.support.test.filters.SmallTest; - -import org.junit.Test; - -/** - * Tests for {@link Channel}. - */ -@SmallTest -public class GenreItemTest { - private static final String INVALID_GENRE = "INVALID GENRE"; - - @Test - public void testGetLabels() { - // Checks if no exception is thrown. - GenreItems.getLabels(getTargetContext()); - } - - @Test - public void testGetCanonicalGenre() { - int count = GenreItems.getGenreCount(); - assertNull(GenreItems.getCanonicalGenre(GenreItems.ID_ALL_CHANNELS)); - for (int i = 1; i < count; ++i) { - assertNotNull(GenreItems.getCanonicalGenre(i)); - } - } - - @Test - public void testGetId_base() { - int count = GenreItems.getGenreCount(); - assertEquals(GenreItems.ID_ALL_CHANNELS, GenreItems.getId(null)); - assertEquals(GenreItems.ID_ALL_CHANNELS, GenreItems.getId(INVALID_GENRE)); - assertInRange(GenreItems.getId(Genres.FAMILY_KIDS), 1, count - 1); - assertInRange(GenreItems.getId(Genres.SPORTS), 1, count - 1); - assertInRange(GenreItems.getId(Genres.SHOPPING), 1, count - 1); - assertInRange(GenreItems.getId(Genres.MOVIES), 1, count - 1); - assertInRange(GenreItems.getId(Genres.COMEDY), 1, count - 1); - assertInRange(GenreItems.getId(Genres.TRAVEL), 1, count - 1); - assertInRange(GenreItems.getId(Genres.DRAMA), 1, count - 1); - assertInRange(GenreItems.getId(Genres.EDUCATION), 1, count - 1); - assertInRange(GenreItems.getId(Genres.ANIMAL_WILDLIFE), 1, count - 1); - assertInRange(GenreItems.getId(Genres.NEWS), 1, count - 1); - assertInRange(GenreItems.getId(Genres.GAMING), 1, count - 1); - } - - @Test - public void testGetId_lmp_mr1() { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) { - assertEquals(GenreItems.ID_ALL_CHANNELS, GenreItems.getId(Genres.ARTS)); - assertEquals(GenreItems.ID_ALL_CHANNELS, GenreItems.getId(Genres.ENTERTAINMENT)); - assertEquals(GenreItems.ID_ALL_CHANNELS, GenreItems.getId(Genres.LIFE_STYLE)); - assertEquals(GenreItems.ID_ALL_CHANNELS, GenreItems.getId(Genres.MUSIC)); - assertEquals(GenreItems.ID_ALL_CHANNELS, GenreItems.getId(Genres.PREMIER)); - assertEquals(GenreItems.ID_ALL_CHANNELS, GenreItems.getId(Genres.TECH_SCIENCE)); - } else { - int count = GenreItems.getGenreCount(); - assertInRange(GenreItems.getId(Genres.ARTS), 1, count - 1); - assertInRange(GenreItems.getId(Genres.ENTERTAINMENT), 1, count - 1); - assertInRange(GenreItems.getId(Genres.LIFE_STYLE), 1, count - 1); - assertInRange(GenreItems.getId(Genres.MUSIC), 1, count - 1); - assertInRange(GenreItems.getId(Genres.PREMIER), 1, count - 1); - assertInRange(GenreItems.getId(Genres.TECH_SCIENCE), 1, count - 1); - } - } - - private void assertInRange(int value, int lower, int upper) { - assertTrue(value >= lower && value <= upper); - } -} diff --git a/tests/unit/src/com/android/tv/data/ProgramDataManagerTest.java b/tests/unit/src/com/android/tv/data/ProgramDataManagerTest.java deleted file mode 100644 index 5457051f..00000000 --- a/tests/unit/src/com/android/tv/data/ProgramDataManagerTest.java +++ /dev/null @@ -1,542 +0,0 @@ -/* - * 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 static android.support.test.InstrumentationRegistry.getTargetContext; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import android.content.Context; -import android.database.ContentObserver; -import android.database.Cursor; -import android.media.tv.TvContract; -import android.net.Uri; -import android.os.HandlerThread; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.SmallTest; -import android.test.mock.MockContentProvider; -import android.test.mock.MockContentResolver; -import android.test.mock.MockCursor; -import android.util.Log; -import android.util.SparseArray; - -import com.android.tv.testing.Constants; -import com.android.tv.testing.FakeClock; -import com.android.tv.testing.ProgramInfo; -import com.android.tv.util.Utils; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -/** - * Test for {@link com.android.tv.data.ProgramDataManager} - */ -@SmallTest -public class ProgramDataManagerTest { - private static final boolean DEBUG = false; - private static final String TAG = "ProgramDataManagerTest"; - - // Wait time for expected success. - private static final long WAIT_TIME_OUT_MS = 1000L; - // Wait time for expected failure. - private static final long FAILURE_TIME_OUT_MS = 300L; - - // TODO: Use TvContract constants, once they become public. - private static final String PARAM_CHANNEL = "channel"; - private static final String PARAM_START_TIME = "start_time"; - private static final String PARAM_END_TIME = "end_time"; - - private ProgramDataManager mProgramDataManager; - private FakeClock mClock; - private HandlerThread mHandlerThread; - private TestProgramDataManagerListener mListener; - private FakeContentResolver mContentResolver; - private FakeContentProvider mContentProvider; - - @Before - public void setUp() { - mClock = FakeClock.createWithCurrentTime(); - mListener = new TestProgramDataManagerListener(); - mContentProvider = new FakeContentProvider(getTargetContext()); - mContentResolver = new FakeContentResolver(); - mContentResolver.addProvider(TvContract.AUTHORITY, mContentProvider); - mHandlerThread = new HandlerThread(TAG); - mHandlerThread.start(); - mProgramDataManager = new ProgramDataManager( - mContentResolver, mClock, mHandlerThread.getLooper()); - mProgramDataManager.setPrefetchEnabled(true); - mProgramDataManager.addListener(mListener); - } - - @After - public void tearDown() { - mHandlerThread.quitSafely(); - mProgramDataManager.stop(); - } - - private void startAndWaitForComplete() throws InterruptedException { - mProgramDataManager.start(); - assertTrue(mListener.programUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS)); - } - - /** - * Test for {@link ProgramInfo#getIndex} and {@link ProgramInfo#getStartTimeMs}. - */ - @Test - public void testProgramUtils() { - ProgramInfo stub = ProgramInfo.create(); - for (long channelId = 1; channelId < Constants.UNIT_TEST_CHANNEL_COUNT; channelId++) { - int index = stub.getIndex(mClock.currentTimeMillis(), channelId); - long startTimeMs = stub.getStartTimeMs(index, channelId); - ProgramInfo programAt = stub.build(InstrumentationRegistry.getContext(), index); - assertTrue(startTimeMs <= mClock.currentTimeMillis()); - assertTrue(mClock.currentTimeMillis() < startTimeMs + programAt.durationMs); - } - } - - /** - * Test for following methods. - * - * <p> - * {@link ProgramDataManager#getCurrentProgram(long)}, - * {@link ProgramDataManager#getPrograms(long, long)}, - * {@link ProgramDataManager#setPrefetchTimeRange(long)}. - * </p> - */ - @Test - public void testGetPrograms() throws InterruptedException { - // Initial setup to test {@link ProgramDataManager#setPrefetchTimeRange(long)}. - long preventSnapDelayMs = ProgramDataManager.PROGRAM_GUIDE_SNAP_TIME_MS * 2; - long prefetchTimeRangeStartMs = System.currentTimeMillis() + preventSnapDelayMs; - mClock.setCurrentTimeMillis(prefetchTimeRangeStartMs + preventSnapDelayMs); - mProgramDataManager.setPrefetchTimeRange(prefetchTimeRangeStartMs); - - startAndWaitForComplete(); - - for (long channelId = 1; channelId <= Constants.UNIT_TEST_CHANNEL_COUNT; channelId++) { - Program currentProgram = mProgramDataManager.getCurrentProgram(channelId); - // Test {@link ProgramDataManager#getCurrentProgram(long)}. - assertTrue(currentProgram.getStartTimeUtcMillis() <= mClock.currentTimeMillis() - && mClock.currentTimeMillis() <= currentProgram.getEndTimeUtcMillis()); - - // Test {@link ProgramDataManager#getPrograms(long)}. - // Case #1: Normal case - List<Program> programs = - mProgramDataManager.getPrograms(channelId, mClock.currentTimeMillis()); - ProgramInfo stub = ProgramInfo.create(); - int index = stub.getIndex(mClock.currentTimeMillis(), channelId); - for (Program program : programs) { - ProgramInfo programInfoAt = stub.build(InstrumentationRegistry.getContext(), index); - long startTimeMs = stub.getStartTimeMs(index, channelId); - assertProgramEquals(startTimeMs, programInfoAt, program); - index++; - } - // Case #2: Corner cases where there's a program that starts at the start of the range. - long startTimeMs = programs.get(0).getStartTimeUtcMillis(); - programs = mProgramDataManager.getPrograms(channelId, startTimeMs); - assertEquals(startTimeMs, programs.get(0).getStartTimeUtcMillis()); - - // Test {@link ProgramDataManager#setPrefetchTimeRange(long)}. - programs = mProgramDataManager.getPrograms(channelId, - prefetchTimeRangeStartMs - TimeUnit.HOURS.toMillis(1)); - for (Program program : programs) { - assertTrue(program.getEndTimeUtcMillis() >= prefetchTimeRangeStartMs); - } - } - } - - /** - * Test for following methods. - * - * <p> - * {@link ProgramDataManager#addOnCurrentProgramUpdatedListener}, - * {@link ProgramDataManager#removeOnCurrentProgramUpdatedListener}. - * </p> - */ - @Test - public void testCurrentProgramListener() throws InterruptedException { - final long testChannelId = 1; - ProgramInfo stub = ProgramInfo.create(); - int index = stub.getIndex(mClock.currentTimeMillis(), testChannelId); - // Set current time to few seconds before the current program ends, - // so we can see if callback is called as expected. - long nextProgramStartTimeMs = stub.getStartTimeMs(index + 1, testChannelId); - ProgramInfo nextProgramInfo = stub.build(InstrumentationRegistry.getContext(), index + 1); - mClock.setCurrentTimeMillis(nextProgramStartTimeMs - (WAIT_TIME_OUT_MS / 2)); - - startAndWaitForComplete(); - // Note that changing current time doesn't affect the current program - // because current program is updated after waiting for the program's duration. - // See {@link ProgramDataManager#updateCurrentProgram}. - mClock.setCurrentTimeMillis(mClock.currentTimeMillis() + WAIT_TIME_OUT_MS); - TestProgramDataManagerOnCurrentProgramUpdatedListener listener = - new TestProgramDataManagerOnCurrentProgramUpdatedListener(); - mProgramDataManager.addOnCurrentProgramUpdatedListener(testChannelId, listener); - assertTrue( - listener.currentProgramUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS)); - assertEquals(testChannelId, listener.updatedChannelId); - Program currentProgram = mProgramDataManager.getCurrentProgram(testChannelId); - assertProgramEquals(nextProgramStartTimeMs, nextProgramInfo, currentProgram); - assertEquals(listener.updatedProgram, currentProgram); - } - - /** - * Test if program data is refreshed after the program insertion. - */ - @Test - public void testContentProviderUpdate() throws InterruptedException { - final long testChannelId = 1; - startAndWaitForComplete(); - // Force program data manager to update program data whenever it's changes. - mProgramDataManager.setProgramPrefetchUpdateWait(0); - mListener.reset(); - List<Program> programList = - mProgramDataManager.getPrograms(testChannelId, mClock.currentTimeMillis()); - assertNotNull(programList); - long lastProgramEndTime = programList.get(programList.size() - 1).getEndTimeUtcMillis(); - // Make change in content provider - mContentProvider.simulateAppend(testChannelId); - assertTrue(mListener.programUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS)); - programList = mProgramDataManager.getPrograms(testChannelId, mClock.currentTimeMillis()); - assertTrue( - lastProgramEndTime < programList.get(programList.size() - 1).getEndTimeUtcMillis()); - } - - /** - * Test for {@link ProgramDataManager#setPauseProgramUpdate(boolean)}. - */ - @Test - public void testSetPauseProgramUpdate() throws InterruptedException { - final long testChannelId = 1; - startAndWaitForComplete(); - // Force program data manager to update program data whenever it's changes. - mProgramDataManager.setProgramPrefetchUpdateWait(0); - mListener.reset(); - mProgramDataManager.setPauseProgramUpdate(true); - mContentProvider.simulateAppend(testChannelId); - assertFalse(mListener.programUpdatedLatch.await(FAILURE_TIME_OUT_MS, - TimeUnit.MILLISECONDS)); - } - - public static void assertProgramEquals(long expectedStartTime, ProgramInfo expectedInfo, - Program actualProgram) { - assertEquals("title", expectedInfo.title, actualProgram.getTitle()); - assertEquals("episode", expectedInfo.episode, actualProgram.getEpisodeTitle()); - assertEquals("description", expectedInfo.description, actualProgram.getDescription()); - assertEquals("startTime", expectedStartTime, actualProgram.getStartTimeUtcMillis()); - assertEquals("endTime", expectedStartTime + expectedInfo.durationMs, - actualProgram.getEndTimeUtcMillis()); - } - - private class FakeContentResolver extends MockContentResolver { - @Override - public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) { - super.notifyChange(uri, observer, syncToNetwork); - if (DEBUG) { - Log.d(TAG, "onChanged(uri=" + uri + ")"); - } - if (observer != null) { - observer.dispatchChange(false, uri); - } else { - mProgramDataManager.getContentObserver().dispatchChange(false, uri); - } - } - } - - private static class ProgramInfoWrapper { - private final int index; - private final long startTimeMs; - private final ProgramInfo programInfo; - - public ProgramInfoWrapper(int index, long startTimeMs, ProgramInfo programInfo) { - this.index = index; - this.startTimeMs = startTimeMs; - this.programInfo = programInfo; - } - } - - // This implements the minimal methods in content resolver - // and detailed assumptions are written in each method. - private class FakeContentProvider extends MockContentProvider { - private final SparseArray<List<ProgramInfoWrapper>> mProgramInfoList = new SparseArray<>(); - - /** - * Constructor for FakeContentProvider - * <p> - * This initializes program info assuming that - * channel IDs are 1, 2, 3, ... {@link Constants#UNIT_TEST_CHANNEL_COUNT}. - * </p> - */ - public FakeContentProvider(Context context) { - super(context); - long startTimeMs = Utils.floorTime( - mClock.currentTimeMillis() - ProgramDataManager.PROGRAM_GUIDE_SNAP_TIME_MS, - ProgramDataManager.PROGRAM_GUIDE_SNAP_TIME_MS); - long endTimeMs = startTimeMs + (ProgramDataManager.PROGRAM_GUIDE_MAX_TIME_RANGE / 2); - for (int i = 1; i <= Constants.UNIT_TEST_CHANNEL_COUNT; i++) { - List<ProgramInfoWrapper> programInfoList = new ArrayList<>(); - ProgramInfo stub = ProgramInfo.create(); - int index = stub.getIndex(startTimeMs, i); - long programStartTimeMs = stub.getStartTimeMs(index, i); - while (programStartTimeMs < endTimeMs) { - ProgramInfo programAt = stub.build(InstrumentationRegistry.getContext(), index); - programInfoList.add( - new ProgramInfoWrapper(index, programStartTimeMs, programAt)); - index++; - programStartTimeMs += programAt.durationMs; - } - mProgramInfoList.put(i, programInfoList); - } - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, - String[] selectionArgs, String sortOrder) { - if (DEBUG) { - Log.d(TAG, "dump query"); - Log.d(TAG, " uri=" + uri); - Log.d(TAG, " projection=" + Arrays.toString(projection)); - Log.d(TAG, " selection=" + selection); - } - long startTimeMs = Long.parseLong(uri.getQueryParameter(PARAM_START_TIME)); - long endTimeMs = Long.parseLong(uri.getQueryParameter(PARAM_END_TIME)); - if (startTimeMs == 0 || endTimeMs == 0) { - throw new UnsupportedOperationException(); - } - assertProgramUri(uri); - long channelId; - try { - channelId = Long.parseLong(uri.getQueryParameter(PARAM_CHANNEL)); - } catch (NumberFormatException e) { - channelId = -1; - } - return new FakeCursor(projection, channelId, startTimeMs, endTimeMs); - } - - /** - * Simulate program data appends at the end of the existing programs. - * This appends programs until the maximum program query range - * ({@link ProgramDataManager#PROGRAM_GUIDE_MAX_TIME_RANGE}) - * where we started with the inserting half of it. - */ - public void simulateAppend(long channelId) { - long endTimeMs = - mClock.currentTimeMillis() + ProgramDataManager.PROGRAM_GUIDE_MAX_TIME_RANGE; - List<ProgramInfoWrapper> programList = mProgramInfoList.get((int) channelId); - if (mProgramInfoList == null) { - return; - } - ProgramInfo stub = ProgramInfo.create(); - ProgramInfoWrapper last = programList.get(programList.size() - 1); - while (last.startTimeMs < endTimeMs) { - ProgramInfo nextProgramInfo = stub.build(InstrumentationRegistry.getContext(), - last.index + 1); - ProgramInfoWrapper next = new ProgramInfoWrapper(last.index + 1, - last.startTimeMs + last.programInfo.durationMs, nextProgramInfo); - programList.add(next); - last = next; - } - mContentResolver.notifyChange(TvContract.Programs.CONTENT_URI, null); - } - - private void assertProgramUri(Uri uri) { - assertTrue("Uri(" + uri + ") isn't channel uri", - uri.toString().startsWith(TvContract.Programs.CONTENT_URI.toString())); - } - - public ProgramInfoWrapper get(long channelId, int position) { - List<ProgramInfoWrapper> programList = mProgramInfoList.get((int) channelId); - if (programList == null || position >= programList.size()) { - return null; - } - return programList.get(position); - } - } - - private class FakeCursor extends MockCursor { - private final String[] ALL_COLUMNS = { - TvContract.Programs.COLUMN_CHANNEL_ID, - TvContract.Programs.COLUMN_TITLE, - TvContract.Programs.COLUMN_SHORT_DESCRIPTION, - TvContract.Programs.COLUMN_EPISODE_TITLE, - TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS, - TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS}; - private final String[] mColumns; - private final boolean mIsQueryForSingleChannel; - private final long mStartTimeMs; - private final long mEndTimeMs; - private final int mCount; - private long mChannelId; - private int mProgramPosition; - private ProgramInfoWrapper mCurrentProgram; - - /** - * Constructor - * @param columns the same as projection passed from {@link FakeContentProvider#query}. - * Can be null for query all. - * @param channelId channel ID to query programs belongs to the specified channel. - * Can be negative to indicate all channels. - * @param startTimeMs start of the time range to query programs. - * @param endTimeMs end of the time range to query programs. - */ - public FakeCursor(String[] columns, long channelId, long startTimeMs, long endTimeMs) { - mColumns = (columns == null) ? ALL_COLUMNS : columns; - mIsQueryForSingleChannel = (channelId > 0); - mChannelId = channelId; - mProgramPosition = -1; - mStartTimeMs = startTimeMs; - mEndTimeMs = endTimeMs; - int count = 0; - while (moveToNext()) { - count++; - } - mCount = count; - // Rewind channel Id and program index. - mChannelId = channelId; - mProgramPosition = -1; - if (DEBUG) { - Log.d(TAG, "FakeCursor(columns=" + Arrays.toString(columns) - + ", channelId=" + channelId + ", startTimeMs=" + startTimeMs - + ", endTimeMs=" + endTimeMs + ") has mCount=" + mCount); - } - } - - @Override - public String getColumnName(int columnIndex) { - return mColumns[columnIndex]; - } - - @Override - public int getColumnIndex(String columnName) { - for (int i = 0; i < mColumns.length; i++) { - if (mColumns[i].equalsIgnoreCase(columnName)) { - return i; - } - } - return -1; - } - - @Override - public int getInt(int columnIndex) { - if (DEBUG) { - Log.d(TAG, "Column (" + getColumnName(columnIndex) + ") is ignored in getInt()"); - } - return 0; - } - - @Override - public long getLong(int columnIndex) { - String columnName = getColumnName(columnIndex); - switch (columnName) { - case TvContract.Programs.COLUMN_CHANNEL_ID: - return mChannelId; - case TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS: - return mCurrentProgram.startTimeMs; - case TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS: - return mCurrentProgram.startTimeMs + mCurrentProgram.programInfo.durationMs; - } - if (DEBUG) { - Log.d(TAG, "Column (" + columnName + ") is ignored in getLong()"); - } - return 0; - } - - @Override - public String getString(int columnIndex) { - String columnName = getColumnName(columnIndex); - switch (columnName) { - case TvContract.Programs.COLUMN_TITLE: - return mCurrentProgram.programInfo.title; - case TvContract.Programs.COLUMN_SHORT_DESCRIPTION: - return mCurrentProgram.programInfo.description; - case TvContract.Programs.COLUMN_EPISODE_TITLE: - return mCurrentProgram.programInfo.episode; - } - if (DEBUG) { - Log.d(TAG, "Column (" + columnName + ") is ignored in getString()"); - } - return null; - } - - @Override - public int getCount() { - return mCount; - } - - @Override - public boolean moveToNext() { - while (true) { - ProgramInfoWrapper program = mContentProvider.get(mChannelId, ++mProgramPosition); - if (program == null || program.startTimeMs >= mEndTimeMs) { - if (mIsQueryForSingleChannel) { - return false; - } else { - if (++mChannelId > Constants.UNIT_TEST_CHANNEL_COUNT) { - return false; - } - mProgramPosition = -1; - } - } else if (program.startTimeMs + program.programInfo.durationMs >= mStartTimeMs) { - mCurrentProgram = program; - break; - } - } - return true; - } - - @Override - public void close() { - // No-op. - } - } - - private class TestProgramDataManagerListener implements ProgramDataManager.Listener { - public CountDownLatch programUpdatedLatch = new CountDownLatch(1); - - @Override - public void onProgramUpdated() { - programUpdatedLatch.countDown(); - } - - public void reset() { - programUpdatedLatch = new CountDownLatch(1); - } - } - - private class TestProgramDataManagerOnCurrentProgramUpdatedListener implements - OnCurrentProgramUpdatedListener { - public final CountDownLatch currentProgramUpdatedLatch = new CountDownLatch(1); - public long updatedChannelId = -1; - public Program updatedProgram = null; - - @Override - public void onCurrentProgramUpdated(long channelId, Program program) { - updatedChannelId = channelId; - updatedProgram = program; - currentProgramUpdatedLatch.countDown(); - } - } -} diff --git a/tests/unit/src/com/android/tv/data/ProgramTest.java b/tests/unit/src/com/android/tv/data/ProgramTest.java deleted file mode 100644 index 1d1f6c10..00000000 --- a/tests/unit/src/com/android/tv/data/ProgramTest.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * 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 static android.media.tv.TvContract.Programs.Genres.COMEDY; -import static android.media.tv.TvContract.Programs.Genres.FAMILY_KIDS; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - -import android.media.tv.TvContentRating; -import android.media.tv.TvContract.Programs.Genres; -import android.os.Parcel; -import android.support.test.filters.SmallTest; - -import com.android.tv.data.Program.CriticScore; - -import org.junit.Test; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * Tests for {@link Program}. - */ -@SmallTest -public class ProgramTest { - private static final int NOT_FOUND_GENRE = 987; - - private static final int FAMILY_GENRE_ID = GenreItems.getId(FAMILY_KIDS); - - private static final int COMEDY_GENRE_ID = GenreItems.getId(COMEDY); - - @Test - public void testBuild() { - Program program = new Program.Builder().build(); - assertEquals("isValid", false, program.isValid()); - } - - @Test - public void testNoGenres() { - Program program = new Program.Builder() - .setCanonicalGenres("") - .build(); - assertNullCanonicalGenres(program); - assertHasGenre(program, NOT_FOUND_GENRE, false); - assertHasGenre(program, FAMILY_GENRE_ID, false); - assertHasGenre(program, COMEDY_GENRE_ID, false); - assertHasGenre(program, GenreItems.ID_ALL_CHANNELS, true); - } - - @Test - public void testFamilyGenre() { - Program program = new Program.Builder() - .setCanonicalGenres(FAMILY_KIDS) - .build(); - assertCanonicalGenres(program, FAMILY_KIDS); - assertHasGenre(program, NOT_FOUND_GENRE, false); - assertHasGenre(program, FAMILY_GENRE_ID, true); - assertHasGenre(program, COMEDY_GENRE_ID, false); - assertHasGenre(program, GenreItems.ID_ALL_CHANNELS, true); - } - - @Test - public void testFamilyComedyGenre() { - Program program = new Program.Builder() - .setCanonicalGenres(FAMILY_KIDS + ", " + COMEDY) - .build(); - assertCanonicalGenres(program, FAMILY_KIDS, COMEDY); - assertHasGenre(program, NOT_FOUND_GENRE, false); - assertHasGenre(program, FAMILY_GENRE_ID, true); - assertHasGenre(program, COMEDY_GENRE_ID, true); - assertHasGenre(program, GenreItems.ID_ALL_CHANNELS, true); - } - - @Test - public void testOtherGenre() { - Program program = new Program.Builder() - .setCanonicalGenres("other") - .build(); - assertCanonicalGenres(program); - assertHasGenre(program, NOT_FOUND_GENRE, false); - assertHasGenre(program, FAMILY_GENRE_ID, false); - assertHasGenre(program, COMEDY_GENRE_ID, false); - assertHasGenre(program, GenreItems.ID_ALL_CHANNELS, true); - } - - @Test - public void testParcelable() { - List<CriticScore> criticScores = new ArrayList<>(); - criticScores.add(new CriticScore("1", "2", "3")); - criticScores.add(new CriticScore("4", "5", "6")); - TvContentRating[] ratings = new TvContentRating[2]; - ratings[0] = TvContentRating.unflattenFromString("1/2/3"); - ratings[1] = TvContentRating.unflattenFromString("4/5/6"); - Program p = new Program.Builder() - .setId(1) - .setPackageName("2") - .setChannelId(3) - .setTitle("4") - .setSeriesId("5") - .setEpisodeTitle("6") - .setSeasonNumber("7") - .setSeasonTitle("8") - .setEpisodeNumber("9") - .setStartTimeUtcMillis(10) - .setEndTimeUtcMillis(11) - .setDescription("12") - .setLongDescription("12-long") - .setVideoWidth(13) - .setVideoHeight(14) - .setCriticScores(criticScores) - .setPosterArtUri("15") - .setThumbnailUri("16") - .setCanonicalGenres(Genres.encode(Genres.SPORTS, Genres.SHOPPING)) - .setContentRatings(ratings) - .setRecordingProhibited(true) - .build(); - Parcel p1 = Parcel.obtain(); - Parcel p2 = Parcel.obtain(); - try { - p.writeToParcel(p1, 0); - byte[] bytes = p1.marshall(); - p2.unmarshall(bytes, 0, bytes.length); - p2.setDataPosition(0); - Program r2 = Program.fromParcel(p2); - assertEquals(p, r2); - } finally { - p1.recycle(); - p2.recycle(); - } - } - - @Test - public void testParcelableWithCriticScore() { - Program program = new Program.Builder() - .setTitle("MyTitle") - .addCriticScore(new CriticScore( - "default source", - "5/10", - "https://testurl/testimage.jpg")) - .build(); - Parcel parcel = Parcel.obtain(); - program.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - Program programFromParcel = Program.CREATOR.createFromParcel(parcel); - - assertNotNull(programFromParcel.getCriticScores()); - assertEquals(programFromParcel.getCriticScores().get(0).source, "default source"); - assertEquals(programFromParcel.getCriticScores().get(0).score, "5/10"); - assertEquals(programFromParcel.getCriticScores().get(0).logoUrl, - "https://testurl/testimage.jpg"); - } - - private static void assertNullCanonicalGenres(Program program) { - String[] actual = program.getCanonicalGenres(); - assertNull("Expected null canonical genres but was " + Arrays.toString(actual), actual); - } - - private static void assertCanonicalGenres(Program program, String... expected) { - assertEquals("canonical genres", Arrays.asList(expected), - Arrays.asList(program.getCanonicalGenres())); - } - - private static void assertHasGenre(Program program, int genreId, boolean expected) { - assertEquals("hasGenre(" + genreId + ")", expected, program.hasGenre(genreId)); - } -} diff --git a/tests/unit/src/com/android/tv/data/TvInputNewComparatorTest.java b/tests/unit/src/com/android/tv/data/TvInputNewComparatorTest.java index b4682dd9..8e892cce 100644 --- a/tests/unit/src/com/android/tv/data/TvInputNewComparatorTest.java +++ b/tests/unit/src/com/android/tv/data/TvInputNewComparatorTest.java @@ -19,26 +19,24 @@ package com.android.tv.data; import android.content.pm.ResolveInfo; import android.media.tv.TvInputInfo; import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; import android.util.Pair; - import com.android.tv.testing.ComparatorTester; +import com.android.tv.testing.utils.TestUtils; import com.android.tv.util.SetupUtils; -import com.android.tv.util.TestUtils; import com.android.tv.util.TvInputManagerHelper; - +import java.util.Comparator; +import java.util.LinkedHashMap; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.Matchers; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; -import java.util.Comparator; -import java.util.LinkedHashMap; - -/** - * Test for {@link TvInputNewComparator} - */ +/** Test for {@link TvInputNewComparator} */ @SmallTest +@RunWith(AndroidJUnit4.class) public class TvInputNewComparatorTest { @Test public void testComparator() throws Exception { @@ -51,45 +49,48 @@ public class TvInputNewComparatorTest { inputIdToNewInput.put("3_old_input", new Pair<>(false, true)); SetupUtils setupUtils = Mockito.mock(SetupUtils.class); - Mockito.when(setupUtils.isNewInput(Matchers.anyString())).thenAnswer( - new Answer<Boolean>() { - @Override - public Boolean answer(InvocationOnMock invocation) throws Throwable { - String inputId = (String) invocation.getArguments()[0]; - return inputIdToNewInput.get(inputId).first; - } - } - ); - Mockito.when(setupUtils.isSetupDone(Matchers.anyString())).thenAnswer( - new Answer<Boolean>() { - @Override - public Boolean answer(InvocationOnMock invocation) throws Throwable { - String inputId = (String) invocation.getArguments()[0]; - return inputIdToNewInput.get(inputId).second; - } - } - ); + Mockito.when(setupUtils.isNewInput(Matchers.anyString())) + .thenAnswer( + new Answer<Boolean>() { + @Override + public Boolean answer(InvocationOnMock invocation) throws Throwable { + String inputId = (String) invocation.getArguments()[0]; + return inputIdToNewInput.get(inputId).first; + } + }); + Mockito.when(setupUtils.isSetupDone(Matchers.anyString())) + .thenAnswer( + new Answer<Boolean>() { + @Override + public Boolean answer(InvocationOnMock invocation) throws Throwable { + String inputId = (String) invocation.getArguments()[0]; + return inputIdToNewInput.get(inputId).second; + } + }); TvInputManagerHelper inputManager = Mockito.mock(TvInputManagerHelper.class); - Mockito.when(inputManager.getDefaultTvInputInfoComparator()).thenReturn( - new Comparator<TvInputInfo>() { - @Override - public int compare(TvInputInfo lhs, TvInputInfo rhs) { - return lhs.getId().compareTo(rhs.getId()); - } - } - ); + Mockito.when(inputManager.getDefaultTvInputInfoComparator()) + .thenReturn( + new Comparator<TvInputInfo>() { + @Override + public int compare(TvInputInfo lhs, TvInputInfo rhs) { + return lhs.getId().compareTo(rhs.getId()); + } + }); TvInputNewComparator comparator = new TvInputNewComparator(setupUtils, inputManager); ComparatorTester<TvInputInfo> comparatorTester = ComparatorTester.withoutEqualsTest(comparator); ResolveInfo resolveInfo = TestUtils.createResolveInfo("test", "test"); for (String id : inputIdToNewInput.keySet()) { // Put mock resolveInfo to prevent NPE in {@link TvInputInfo#toString} - TvInputInfo info1 = TestUtils.createTvInputInfo( - resolveInfo, id, "test1", TvInputInfo.TYPE_TUNER, false); - TvInputInfo info2 = TestUtils.createTvInputInfo( - resolveInfo, id, "test2", TvInputInfo.TYPE_DISPLAY_PORT, true); - TvInputInfo info3 = TestUtils.createTvInputInfo( - resolveInfo, id, "test", TvInputInfo.TYPE_HDMI, true); + TvInputInfo info1 = + TestUtils.createTvInputInfo( + resolveInfo, id, "test1", TvInputInfo.TYPE_TUNER, false); + TvInputInfo info2 = + TestUtils.createTvInputInfo( + resolveInfo, id, "test2", TvInputInfo.TYPE_DISPLAY_PORT, true); + TvInputInfo info3 = + TestUtils.createTvInputInfo( + resolveInfo, id, "test", TvInputInfo.TYPE_HDMI, true); comparatorTester.addComparableGroup(info1, info2, info3); } comparatorTester.test(); diff --git a/tests/unit/src/com/android/tv/data/WatchedHistoryManagerTest.java b/tests/unit/src/com/android/tv/data/WatchedHistoryManagerTest.java index 7eea1be7..43bfde09 100644 --- a/tests/unit/src/com/android/tv/data/WatchedHistoryManagerTest.java +++ b/tests/unit/src/com/android/tv/data/WatchedHistoryManagerTest.java @@ -17,26 +17,24 @@ package com.android.tv.data; import static android.support.test.InstrumentationRegistry.getTargetContext; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static com.google.common.truth.Truth.assertThat; import android.os.Looper; import android.support.test.filters.MediumTest; - +import android.support.test.runner.AndroidJUnit4; import com.android.tv.data.WatchedHistoryManager.WatchedRecord; - +import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.Test; - -import java.util.concurrent.TimeUnit; +import org.junit.runner.RunWith; /** * Test for {@link com.android.tv.data.WatchedHistoryManagerTest} - * <p> - * This is a medium test because it load files which accessing SharedPreferences. + * + * <p>This is a medium test because it load files which accessing SharedPreferences. */ @MediumTest +@RunWith(AndroidJUnit4.class) public class WatchedHistoryManagerTest { // Wait time for expected success. private static final int MAX_HISTORY_SIZE = 100; @@ -56,13 +54,13 @@ public class WatchedHistoryManagerTest { private void startAndWaitForComplete() throws InterruptedException { mWatchedHistoryManager.start(); - assertTrue(mListener.mLoadFinished); + assertThat(mListener.mLoadFinished).isTrue(); } @Test public void testIsLoaded() throws InterruptedException { startAndWaitForComplete(); - assertTrue(mWatchedHistoryManager.isLoaded()); + assertThat(mWatchedHistoryManager.isLoaded()).isTrue(); } @Test @@ -71,16 +69,16 @@ public class WatchedHistoryManagerTest { long fakeId = 100000000; long time = System.currentTimeMillis(); long duration = TimeUnit.MINUTES.toMillis(10); - Channel channel = new Channel.Builder().setId(fakeId).build(); + ChannelImpl channel = new ChannelImpl.Builder().setId(fakeId).build(); mWatchedHistoryManager.logChannelViewStop(channel, time, duration); WatchedRecord record = mWatchedHistoryManager.getRecord(0); WatchedRecord recordFromSharedPreferences = mWatchedHistoryManager.getRecordFromSharedPreferences(0); - assertEquals(record.channelId, fakeId); - assertEquals(record.watchedStartTime, time - duration); - assertEquals(record.duration, duration); - assertEquals(record, recordFromSharedPreferences); + assertThat(fakeId).isEqualTo(record.channelId); + assertThat(time - duration).isEqualTo(record.watchedStartTime); + assertThat(duration).isEqualTo(record.duration); + assertThat(recordFromSharedPreferences).isEqualTo(record); } @Test @@ -92,28 +90,28 @@ public class WatchedHistoryManagerTest { int size = MAX_HISTORY_SIZE * 2; for (int i = 0; i < size; ++i) { - Channel channel = new Channel.Builder().setId(startChannelId + i).build(); + ChannelImpl channel = new ChannelImpl.Builder().setId(startChannelId + i).build(); mWatchedHistoryManager.logChannelViewStop(channel, time + duration * i, duration); } for (int i = 0; i < MAX_HISTORY_SIZE; ++i) { WatchedRecord record = mWatchedHistoryManager.getRecord(i); WatchedRecord recordFromSharedPreferences = mWatchedHistoryManager.getRecordFromSharedPreferences(i); - assertEquals(record, recordFromSharedPreferences); - assertEquals(record.channelId, startChannelId + size - 1 - i); + assertThat(recordFromSharedPreferences).isEqualTo(record); + assertThat(startChannelId + size - 1 - i).isEqualTo(record.channelId); } // Since the WatchedHistory is a circular queue, the value for 0 and maxHistorySize // are same. - assertEquals(mWatchedHistoryManager.getRecordFromSharedPreferences(0), - mWatchedHistoryManager.getRecordFromSharedPreferences(MAX_HISTORY_SIZE)); + assertThat(mWatchedHistoryManager.getRecordFromSharedPreferences(MAX_HISTORY_SIZE)) + .isEqualTo(mWatchedHistoryManager.getRecordFromSharedPreferences(0)); } @Test public void testWatchedRecordEquals() { - assertTrue(new WatchedRecord(1, 2, 3).equals(new WatchedRecord(1, 2, 3))); - assertFalse(new WatchedRecord(1, 2, 3).equals(new WatchedRecord(1, 2, 4))); - assertFalse(new WatchedRecord(1, 2, 3).equals(new WatchedRecord(1, 4, 3))); - assertFalse(new WatchedRecord(1, 2, 3).equals(new WatchedRecord(4, 2, 3))); + assertThat(new WatchedRecord(1, 2, 3).equals(new WatchedRecord(1, 2, 3))).isTrue(); + assertThat(new WatchedRecord(1, 2, 3).equals(new WatchedRecord(1, 2, 4))).isFalse(); + assertThat(new WatchedRecord(1, 2, 3).equals(new WatchedRecord(1, 4, 3))).isFalse(); + assertThat(new WatchedRecord(1, 2, 3).equals(new WatchedRecord(4, 2, 3))).isFalse(); } @Test @@ -122,12 +120,13 @@ public class WatchedHistoryManagerTest { long time = System.currentTimeMillis(); long duration = TimeUnit.MINUTES.toMillis(10); WatchedRecord record = new WatchedRecord(fakeId, time, duration); - WatchedRecord sameRecord = mWatchedHistoryManager.decode( - mWatchedHistoryManager.encode(record)); - assertEquals(record, sameRecord); + WatchedRecord sameRecord = + mWatchedHistoryManager.decode(mWatchedHistoryManager.encode(record)); + assertThat(sameRecord).isEqualTo(record); } - private class TestWatchedHistoryManagerListener implements WatchedHistoryManager.Listener { + private static final class TestWatchedHistoryManagerListener + implements WatchedHistoryManager.Listener { boolean mLoadFinished; @Override @@ -136,6 +135,6 @@ public class WatchedHistoryManagerTest { } @Override - public void onNewRecordAdded(WatchedRecord watchedRecord) { } + public void onNewRecordAdded(WatchedRecord watchedRecord) {} } } diff --git a/tests/unit/src/com/android/tv/dvr/BaseDvrDataManagerTest.java b/tests/unit/src/com/android/tv/dvr/BaseDvrDataManagerTest.java deleted file mode 100644 index 5f0ae15c..00000000 --- a/tests/unit/src/com/android/tv/dvr/BaseDvrDataManagerTest.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2016 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.dvr; - -import static android.support.test.InstrumentationRegistry.getContext; - -import android.os.Build; -import android.support.annotation.NonNull; -import android.support.test.filters.SdkSuppress; -import android.support.test.filters.SmallTest; -import android.test.MoreAsserts; - -import com.android.tv.common.feature.CommonFeatures; -import com.android.tv.common.feature.TestableFeature; -import com.android.tv.dvr.data.ScheduledRecording; -import com.android.tv.testing.FakeClock; -import com.android.tv.testing.dvr.RecordingTestUtils; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import java.util.List; -import java.util.concurrent.TimeUnit; - -/** Tests for {@link BaseDvrDataManager} using {@link DvrDataManagerInMemoryImpl}. */ -@SmallTest -@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N) -public class BaseDvrDataManagerTest { - private static final String INPUT_ID = "input_id"; - private static final int CHANNEL_ID = 273; - - private final TestableFeature mDvrFeature = CommonFeatures.DVR; - private DvrDataManagerInMemoryImpl mDvrDataManager; - private FakeClock mFakeClock; - - @Before - public void setUp() { - mDvrFeature.enableForTest(); - mFakeClock = FakeClock.createWithCurrentTime(); - mDvrDataManager = new DvrDataManagerInMemoryImpl(getContext(), mFakeClock); - } - - @After - public void tearDown() { - mDvrFeature.resetForTests(); - } - - @Test - public void testGetNonStartedScheduledRecordings() { - ScheduledRecording recording = mDvrDataManager - .addScheduledRecordingInternal(createNewScheduledRecordingStartingNow()); - List<ScheduledRecording> result = mDvrDataManager.getNonStartedScheduledRecordings(); - MoreAsserts.assertContentsInAnyOrder(result, recording); - } - - @Test - public void testGetNonStartedScheduledRecordings_past() { - mDvrDataManager.addScheduledRecordingInternal(createNewScheduledRecordingStartingNow()); - mFakeClock.increment(TimeUnit.MINUTES, 6); - List<ScheduledRecording> result = mDvrDataManager.getNonStartedScheduledRecordings(); - MoreAsserts.assertContentsInAnyOrder(result); - } - - @NonNull - private ScheduledRecording createNewScheduledRecordingStartingNow() { - return ScheduledRecording.buildFrom(RecordingTestUtils - .createTestRecordingWithIdAndPeriod( - ScheduledRecording.ID_NOT_SET, - INPUT_ID, CHANNEL_ID, - mFakeClock.currentTimeMillis(), - mFakeClock.currentTimeMillis() + TimeUnit.MINUTES.toMillis(5))) - .setState(ScheduledRecording.STATE_RECORDING_NOT_STARTED) - .build(); - } -} diff --git a/tests/unit/src/com/android/tv/dvr/DvrDataManagerImplTest.java b/tests/unit/src/com/android/tv/dvr/DvrDataManagerImplTest.java deleted file mode 100644 index 9771a2e5..00000000 --- a/tests/unit/src/com/android/tv/dvr/DvrDataManagerImplTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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.dvr; - -import static org.junit.Assert.assertEquals; - -import android.os.Build; -import android.support.test.filters.SdkSuppress; -import android.support.test.filters.SmallTest; - -import com.android.tv.dvr.data.ScheduledRecording; -import com.android.tv.testing.dvr.RecordingTestUtils; - -import org.junit.Test; - -import java.util.ArrayList; -import java.util.List; - -/** Tests for {@link DvrDataManagerImpl} */ -@SmallTest -@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N) -public class DvrDataManagerImplTest { - private static final String INPUT_ID = "input_id"; - private static final int CHANNEL_ID = 273; - - @Test - public void testGetNextScheduledStartTimeAfter() { - long id = 1; - List<ScheduledRecording> scheduledRecordings = new ArrayList<>(); - assertNextStartTime(scheduledRecordings, 0L, DvrDataManager.NEXT_START_TIME_NOT_FOUND); - scheduledRecordings.add(RecordingTestUtils - .createTestRecordingWithIdAndPeriod(id++, INPUT_ID, CHANNEL_ID, 10L, 20L)); - assertNextStartTime(scheduledRecordings, 9L, 10L); - assertNextStartTime(scheduledRecordings, 10L, DvrDataManager.NEXT_START_TIME_NOT_FOUND); - scheduledRecordings.add(RecordingTestUtils - .createTestRecordingWithIdAndPeriod(id++, INPUT_ID, CHANNEL_ID, 20L, 30L)); - assertNextStartTime(scheduledRecordings, 9L, 10L); - assertNextStartTime(scheduledRecordings, 10L, 20L); - assertNextStartTime(scheduledRecordings, 20L, DvrDataManager.NEXT_START_TIME_NOT_FOUND); - scheduledRecordings.add(RecordingTestUtils - .createTestRecordingWithIdAndPeriod(id++, INPUT_ID, CHANNEL_ID, 30L, 40L)); - assertNextStartTime(scheduledRecordings, 9L, 10L); - assertNextStartTime(scheduledRecordings, 10L, 20L); - assertNextStartTime(scheduledRecordings, 20L, 30L); - assertNextStartTime(scheduledRecordings, 30L, DvrDataManager.NEXT_START_TIME_NOT_FOUND); - scheduledRecordings.clear(); - scheduledRecordings.add(RecordingTestUtils - .createTestRecordingWithIdAndPeriod(id++, INPUT_ID, CHANNEL_ID, 10L, 20L)); - scheduledRecordings.add(RecordingTestUtils - .createTestRecordingWithIdAndPeriod(id++, INPUT_ID, CHANNEL_ID, 10L, 20L)); - scheduledRecordings.add(RecordingTestUtils - .createTestRecordingWithIdAndPeriod(id++, INPUT_ID, CHANNEL_ID, 10L, 20L)); - assertNextStartTime(scheduledRecordings, 9L, 10L); - assertNextStartTime(scheduledRecordings, 10L, DvrDataManager.NEXT_START_TIME_NOT_FOUND); - } - - private void assertNextStartTime(List<ScheduledRecording> scheduledRecordings, long startTime, - long expected) { - assertEquals("getNextScheduledStartTimeAfter()", expected, - DvrDataManagerImpl.getNextStartTimeAfter(scheduledRecordings, startTime)); - } -}
\ No newline at end of file diff --git a/tests/unit/src/com/android/tv/dvr/DvrScheduleManagerTest.java b/tests/unit/src/com/android/tv/dvr/DvrScheduleManagerTest.java deleted file mode 100644 index 1c77aa0e..00000000 --- a/tests/unit/src/com/android/tv/dvr/DvrScheduleManagerTest.java +++ /dev/null @@ -1,693 +0,0 @@ -/* - * Copyright (C) 2016 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.dvr; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import android.os.Build; -import android.support.test.filters.SdkSuppress; -import android.support.test.filters.SmallTest; -import android.test.MoreAsserts; -import android.util.Range; - -import com.android.tv.dvr.DvrScheduleManager.ConflictInfo; -import com.android.tv.dvr.data.ScheduledRecording; -import com.android.tv.testing.dvr.RecordingTestUtils; - -import org.junit.Test; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -/** Tests for {@link DvrScheduleManager} */ -@SmallTest -@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N) -public class DvrScheduleManagerTest { - private static final String INPUT_ID = "input_id"; - - @Test - public void testGetConflictingSchedules_emptySchedule() { - List<ScheduledRecording> schedules = new ArrayList<>(); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 1)); - } - - @Test - public void testGetConflictingSchedules_noConflict() { - long priority = 0; - long channelId = 0; - List<ScheduledRecording> schedules = new ArrayList<>(); - - schedules.add(RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(++channelId, - ++priority, 0L, 200L)); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 1)); - - schedules.add(RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(++channelId, - ++priority, 0L, 100L)); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 2)); - - schedules.add(RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(++channelId, - ++priority, 100L, 200L)); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 2)); - - schedules.add(RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(++channelId, - ++priority, 0L, 100L)); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 3)); - - schedules.add(RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(++channelId, - ++priority, 100L, 200L)); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 3)); - } - - @Test - public void testGetConflictingSchedules_noTuner() { - long priority = 0; - long channelId = 0; - List<ScheduledRecording> schedules = new ArrayList<>(); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 0)); - - schedules.add(RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(++channelId, - ++priority, 0L, 200L)); - assertEquals(schedules, DvrScheduleManager.getConflictingSchedules(schedules, 0)); - schedules.add(0, RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(++channelId, - ++priority, 0L, 100L)); - assertEquals(schedules, DvrScheduleManager.getConflictingSchedules(schedules, 0)); - } - - @Test - public void testGetConflictingSchedules_conflict() { - long priority = 0; - long channelId = 0; - List<ScheduledRecording> schedules = new ArrayList<>(); - - ScheduledRecording r1 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 200L); - schedules.add(r1); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 1)); - - ScheduledRecording r2 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 100L); - schedules.add(r2); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 1), - r1); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 2)); - - ScheduledRecording r3 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 100L, 200L); - schedules.add(r3); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 1), - r1); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 2)); - - ScheduledRecording r4 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 100L); - schedules.add(r4); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 1), - r2, r1); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 2), - r1); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 3)); - - ScheduledRecording r5 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 100L, 200L); - schedules.add(r5); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 1), - r3, r2, r1); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 2), - r1); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 3)); - - ScheduledRecording r6 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 10L, 90L); - schedules.add(r6); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 1), - r4, r3, r2, r1); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 2), - r2, r1); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 3), - r1); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 4)); - - ScheduledRecording r7 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 110L, 190L); - schedules.add(r7); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 1), - r5, r4, r3, r2, r1); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 2), - r3, r2, r1); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 3), - r1); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 4)); - - ScheduledRecording r8 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 50L, 150L); - schedules.add(r8); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 1), - r7, r6, r5, r4, r3, r2, r1); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 2), - r5, r4, r3, r2, r1); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 3), - r3, r2, r1); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 4), - r1); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 5)); - } - - @Test - public void testGetConflictingSchedules_conflict2() { - // The case when there is a long schedule. - long priority = 0; - long channelId = 0; - List<ScheduledRecording> schedules = new ArrayList<>(); - - ScheduledRecording r1 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 1000L); - schedules.add(r1); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 1)); - - ScheduledRecording r2 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 100L); - schedules.add(r2); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 1), - r1); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 2)); - - ScheduledRecording r3 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 100L, 200L); - schedules.add(r3); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 1), - r1); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 2)); - } - - @Test - public void testGetConflictingSchedules_reverseOrder() { - long priority = 0; - long channelId = 0; - List<ScheduledRecording> schedules = new ArrayList<>(); - - ScheduledRecording r1 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 200L); - schedules.add(0, r1); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 1)); - - ScheduledRecording r2 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 100L); - schedules.add(0, r2); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 1), - r1); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 2)); - - ScheduledRecording r3 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 100L, 200L); - schedules.add(0, r3); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 1), - r1); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 2)); - - ScheduledRecording r4 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 100L); - schedules.add(0, r4); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 1), - r2, r1); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 2), - r1); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 3)); - - ScheduledRecording r5 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 100L, 200L); - schedules.add(0, r5); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 1), - r3, r2, r1); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 2), - r1); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 3)); - - ScheduledRecording r6 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 10L, 90L); - schedules.add(0, r6); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 1), - r4, r3, r2, r1); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 2), - r2, r1); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 3), - r1); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 4)); - - ScheduledRecording r7 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 110L, 190L); - schedules.add(0, r7); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 1), - r5, r4, r3, r2, r1); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 2), - r3, r2, r1); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 3), - r1); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 4)); - - ScheduledRecording r8 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 50L, 150L); - schedules.add(0, r8); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 1), - r7, r6, r5, r4, r3, r2, r1); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 2), - r5, r4, r3, r2, r1); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 3), - r3, r2, r1); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 4), - r1); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 5)); - } - - @Test - public void testGetConflictingSchedules_period1() { - long priority = 0; - long channelId = 0; - List<ScheduledRecording> schedules = new ArrayList<>(); - - ScheduledRecording r1 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 200L); - schedules.add(r1); - ScheduledRecording r2 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 100L); - schedules.add(r2); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 1, - Collections.singletonList(new Range<>(10L, 20L))), r1); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 1, - Collections.singletonList(new Range<>(110L, 120L))), r1); - } - - @Test - public void testGetConflictingSchedules_period2() { - long priority = 0; - long channelId = 0; - List<ScheduledRecording> schedules = new ArrayList<>(); - - ScheduledRecording r1 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 200L); - schedules.add(r1); - ScheduledRecording r2 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 100L, 200L); - schedules.add(r2); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 1, - Collections.singletonList(new Range<>(10L, 20L))), r1); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 1, - Collections.singletonList(new Range<>(110L, 120L))), r1); - } - - @Test - public void testGetConflictingSchedules_period3() { - long priority = 0; - long channelId = 0; - List<ScheduledRecording> schedules = new ArrayList<>(); - - ScheduledRecording r1 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 100L); - schedules.add(r1); - ScheduledRecording r2 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 100L, 200L); - schedules.add(r2); - ScheduledRecording r3 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 100L); - schedules.add(r3); - ScheduledRecording r4 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 100L, 200L); - schedules.add(r4); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 1, - Collections.singletonList(new Range<>(10L, 20L))), r1); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 1, - Collections.singletonList(new Range<>(110L, 120L))), r2); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 1, - Collections.singletonList(new Range<>(50L, 150L))), r2, r1); - List<Range<Long>> ranges = new ArrayList<>(); - ranges.add(new Range<>(10L, 20L)); - ranges.add(new Range<>(110L, 120L)); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 1, - ranges), r2, r1); - } - - @Test - public void testGetConflictingSchedules_addSchedules1() { - long priority = 0; - long channelId = 0; - List<ScheduledRecording> schedules = new ArrayList<>(); - - ScheduledRecording r1 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 200L); - schedules.add(r1); - ScheduledRecording r2 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 100L); - schedules.add(r2); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules( - Collections.singletonList( - ScheduledRecording.builder(INPUT_ID, ++channelId, 10L, 20L) - .setPriority(++priority).build()), - schedules, 1), r2, r1); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules( - Collections.singletonList( - ScheduledRecording.builder(INPUT_ID, ++channelId, 110L, 120L) - .setPriority(++priority).build()), - schedules, 1), r1); - } - - @Test - public void testGetConflictingSchedules_addSchedules2() { - long priority = 0; - long channelId = 0; - List<ScheduledRecording> schedules = new ArrayList<>(); - - ScheduledRecording r1 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 200L); - schedules.add(r1); - ScheduledRecording r2 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 100L, 200L); - schedules.add(r2); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules( - Collections.singletonList( - ScheduledRecording.builder(INPUT_ID, ++channelId, 10L, 20L) - .setPriority(++priority).build()), - schedules, 1), r1); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules( - Collections.singletonList( - ScheduledRecording.builder(INPUT_ID, ++channelId, 110L, 120L) - .setPriority(++priority).build()), - schedules, 1), r2, r1); - } - - @Test - public void testGetConflictingSchedules_addLowestPriority() { - long priority = 0; - long channelId = 0; - List<ScheduledRecording> schedules = new ArrayList<>(); - - ScheduledRecording r1 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 400L); - schedules.add(r1); - ScheduledRecording r2 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 100L, 200L); - schedules.add(r2); - // Returning r1 even though r1 has the higher priority than the new one. That's because r1 - // starts at 0 and stops at 100, and the new one will be recorded successfully. - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules( - Collections.singletonList( - ScheduledRecording.builder(INPUT_ID, ++channelId, 200L, 300L) - .setPriority(0).build()), - schedules, 1), r1); - } - - @Test - public void testGetConflictingSchedules_sameChannel() { - long priority = 0; - long channelId = 1; - List<ScheduledRecording> schedules = new ArrayList<>(); - schedules.add(RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(channelId, - ++priority, 0L, 200L)); - schedules.add(RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(channelId, - ++priority, 0L, 200L)); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 3)); - } - - @Test - public void testGetConflictingSchedule_startEarlyAndFail() { - long priority = 0; - long channelId = 0; - List<ScheduledRecording> schedules = new ArrayList<>(); - ScheduledRecording r1 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 200L, 300L); - schedules.add(r1); - ScheduledRecording r2 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 400L); - schedules.add(r2); - ScheduledRecording r3 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 100L, 200L); - schedules.add(r3); - // r2 starts recording and fails when r3 starts. r1 is recorded successfully. - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 1), - r2); - } - - @Test - public void testGetConflictingSchedule_startLate() { - long priority = 0; - long channelId = 0; - List<ScheduledRecording> schedules = new ArrayList<>(); - ScheduledRecording r1 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 200L, 400L); - schedules.add(r1); - ScheduledRecording r2 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 100L, 300L); - schedules.add(r2); - ScheduledRecording r3 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 200L); - schedules.add(r3); - // r2 and r1 are clipped. - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedules(schedules, 1), - r2, r1); - } - - @Test - public void testGetConflictingSchedulesForTune_canTune() { - // Can tune to the recorded channel if tuner count is 1. - long priority = 0; - long channelId = 1; - List<ScheduledRecording> schedules = new ArrayList<>(); - schedules.add(RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(channelId, - ++priority, 0L, 200L)); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedulesForTune(INPUT_ID, - channelId, 0L, priority + 1, schedules, 1)); - } - - @Test - public void testGetConflictingSchedulesForTune_cannotTune() { - // Can't tune to a channel if other channel is recording and tuner count is 1. - long priority = 0; - long channelId = 1; - List<ScheduledRecording> schedules = new ArrayList<>(); - schedules.add(RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(channelId, - ++priority, 0L, 200L)); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedulesForTune( - INPUT_ID, channelId + 1, 0L, priority + 1, schedules, 1), schedules.get(0)); - } - - @Test - public void testGetConflictingSchedulesForWatching_otherChannels() { - // The other channels are to be recorded. - long priority = 0; - long channelToWatch = 1; - long channelId = 1; - List<ScheduledRecording> schedules = new ArrayList<>(); - ScheduledRecording r1 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 200L); - schedules.add(r1); - ScheduledRecording r2 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 200L); - schedules.add(r2); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedulesForWatching( - INPUT_ID, channelToWatch, 0L, ++priority, schedules, 3)); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedulesForWatching( - INPUT_ID, channelToWatch, 0L, ++priority, schedules, 2), r1); - } - - @Test - public void testGetConflictingSchedulesForWatching_sameChannel1() { - long priority = 0; - long channelToWatch = 1; - long channelId = 1; - List<ScheduledRecording> schedules = new ArrayList<>(); - ScheduledRecording r1 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - channelToWatch, ++priority, 0L, 200L); - schedules.add(r1); - ScheduledRecording r2 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 200L); - schedules.add(r2); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedulesForWatching( - INPUT_ID, channelToWatch, 0L, ++priority, schedules, 2)); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedulesForWatching( - INPUT_ID, channelToWatch, 0L, ++priority, schedules, 1), r2); - } - - @Test - public void testGetConflictingSchedulesForWatching_sameChannel2() { - long priority = 0; - long channelToWatch = 1; - long channelId = 1; - List<ScheduledRecording> schedules = new ArrayList<>(); - ScheduledRecording r1 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 200L); - schedules.add(r1); - ScheduledRecording r2 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - channelToWatch, ++priority, 0L, 200L); - schedules.add(r2); - MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedulesForWatching( - INPUT_ID, channelToWatch, 0L, ++priority, schedules, 2)); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedulesForWatching( - INPUT_ID, channelToWatch, 0L, ++priority, schedules, 1), r1); - } - - @Test - public void testGetConflictingSchedulesForWatching_sameChannelConflict1() { - long priority = 0; - long channelToWatch = 1; - long channelId = 1; - List<ScheduledRecording> schedules = new ArrayList<>(); - ScheduledRecording r1 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 200L); - schedules.add(r1); - ScheduledRecording r2 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - channelToWatch, ++priority, 0L, 200L); - schedules.add(r2); - ScheduledRecording r3 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - channelToWatch, ++priority, 0L, 200L); - schedules.add(r3); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedulesForWatching( - INPUT_ID, channelToWatch, 0L, ++priority, schedules, 3), r2); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedulesForWatching( - INPUT_ID, channelToWatch, 0L, ++priority, schedules, 2), r2); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedulesForWatching( - INPUT_ID, channelToWatch, 0L, ++priority, schedules, 1), r2, r1); - } - - @Test - public void testGetConflictingSchedulesForWatching_sameChannelConflict2() { - long priority = 0; - long channelToWatch = 1; - long channelId = 1; - List<ScheduledRecording> schedules = new ArrayList<>(); - ScheduledRecording r1 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - channelToWatch, ++priority, 0L, 200L); - schedules.add(r1); - ScheduledRecording r2 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - channelToWatch, ++priority, 0L, 200L); - schedules.add(r2); - ScheduledRecording r3 = RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 200L); - schedules.add(r3); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedulesForWatching( - INPUT_ID, channelToWatch, 0L, ++priority, schedules, 3), r1); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedulesForWatching( - INPUT_ID, channelToWatch, 0L, ++priority, schedules, 2), r1); - MoreAsserts.assertContentsInOrder(DvrScheduleManager.getConflictingSchedulesForWatching( - INPUT_ID, channelToWatch, 0L, ++priority, schedules, 1), r3, r1); - } - - @Test - public void testPartiallyConflictingSchedules() { - long priority = 100; - long channelId = 0; - List<ScheduledRecording> schedules = new ArrayList<>(Arrays.asList( - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(++channelId, - --priority, 0L, 400L), - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(++channelId, - --priority, 0L, 200L), - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(++channelId, - --priority, 200L, 500L), - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(++channelId, - --priority, 400L, 600L), - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(++channelId, - --priority, 700L, 800L), - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(++channelId, - --priority, 600L, 900L), - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(++channelId, - --priority, 800L, 900L), - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(++channelId, - --priority, 800L, 900L), - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(++channelId, - --priority, 750L, 850L), - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(++channelId, - --priority, 300L, 450L), - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(++channelId, - --priority, 50L, 900L) - )); - List<ConflictInfo> conflicts = DvrScheduleManager.getConflictingSchedulesInfo(schedules, 1); - - assertNotInList(schedules.get(0), conflicts); - assertFullConflict(schedules.get(1), conflicts); - assertPartialConflict(schedules.get(2), conflicts); - assertPartialConflict(schedules.get(3), conflicts); - assertNotInList(schedules.get(4), conflicts); - assertPartialConflict(schedules.get(5), conflicts); - assertNotInList(schedules.get(6), conflicts); - assertFullConflict(schedules.get(7), conflicts); - assertFullConflict(schedules.get(8), conflicts); - assertFullConflict(schedules.get(9), conflicts); - assertFullConflict(schedules.get(10), conflicts); - - conflicts = DvrScheduleManager.getConflictingSchedulesInfo(schedules, 2); - - assertNotInList(schedules.get(0), conflicts); - assertNotInList(schedules.get(1), conflicts); - assertNotInList(schedules.get(2), conflicts); - assertNotInList(schedules.get(3), conflicts); - assertNotInList(schedules.get(4), conflicts); - assertNotInList(schedules.get(5), conflicts); - assertNotInList(schedules.get(6), conflicts); - assertFullConflict(schedules.get(7), conflicts); - assertFullConflict(schedules.get(8), conflicts); - assertFullConflict(schedules.get(9), conflicts); - assertPartialConflict(schedules.get(10), conflicts); - - conflicts = DvrScheduleManager.getConflictingSchedulesInfo(schedules, 3); - - assertNotInList(schedules.get(0), conflicts); - assertNotInList(schedules.get(1), conflicts); - assertNotInList(schedules.get(2), conflicts); - assertNotInList(schedules.get(3), conflicts); - assertNotInList(schedules.get(4), conflicts); - assertNotInList(schedules.get(5), conflicts); - assertNotInList(schedules.get(6), conflicts); - assertNotInList(schedules.get(7), conflicts); - assertPartialConflict(schedules.get(8), conflicts); - assertNotInList(schedules.get(9), conflicts); - assertPartialConflict(schedules.get(10), conflicts); - } - - private void assertNotInList(ScheduledRecording schedule, List<ConflictInfo> conflicts) { - for (ConflictInfo conflictInfo : conflicts) { - if (conflictInfo.schedule.equals(schedule)) { - fail(schedule + " conflicts with others."); - } - } - } - - private void assertPartialConflict(ScheduledRecording schedule, List<ConflictInfo> conflicts) { - for (ConflictInfo conflictInfo : conflicts) { - if (conflictInfo.schedule.equals(schedule)) { - if (conflictInfo.partialConflict) { - return; - } else { - fail(schedule + " fully conflicts with others."); - } - } - } - fail(schedule + " doesn't conflict"); - } - - private void assertFullConflict(ScheduledRecording schedule, List<ConflictInfo> conflicts) { - for (ConflictInfo conflictInfo : conflicts) { - if (conflictInfo.schedule.equals(schedule)) { - if (!conflictInfo.partialConflict) { - return; - } else { - fail(schedule + " partially conflicts with others."); - } - } - } - fail(schedule + " doesn't conflict"); - } -}
\ No newline at end of file diff --git a/tests/unit/src/com/android/tv/dvr/ScheduledRecordingTest.java b/tests/unit/src/com/android/tv/dvr/ScheduledRecordingTest.java deleted file mode 100644 index b98af603..00000000 --- a/tests/unit/src/com/android/tv/dvr/ScheduledRecordingTest.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * 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.dvr; - -import static com.android.tv.testing.dvr.RecordingTestUtils.createTestRecordingWithIdAndPeriod; -import static com.android.tv.testing.dvr.RecordingTestUtils.normalizePriority; -import static junit.framework.TestCase.assertEquals; - -import android.os.Build; -import android.support.test.filters.SdkSuppress; -import android.support.test.filters.SmallTest; -import android.test.MoreAsserts; -import android.util.Range; - -import com.android.tv.data.Channel; -import com.android.tv.data.Program; -import com.android.tv.dvr.data.ScheduledRecording; -import com.android.tv.testing.dvr.RecordingTestUtils; - -import org.junit.Test; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -/** Tests for {@link ScheduledRecordingTest} */ -@SmallTest -@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N) -public class ScheduledRecordingTest { - private static final String INPUT_ID = "input_id"; - private static final int CHANNEL_ID = 273; - - @Test - public void testIsOverLapping() { - ScheduledRecording r = createTestRecordingWithIdAndPeriod(1, INPUT_ID, CHANNEL_ID, - 10L, 20L); - assertOverLapping(false, 1L, 9L, r); - - assertOverLapping(true, 1L, 20L, r); - assertOverLapping(false, 1L, 10L, r); - assertOverLapping(true, 10L, 19L, r); - assertOverLapping(true, 10L, 20L, r); - assertOverLapping(true, 11L, 20L, r); - assertOverLapping(true, 11L, 21L, r); - assertOverLapping(false, 20L, 21L, r); - - assertOverLapping(false, 21L, 29L, r); - } - - @Test - public void testBuildProgram() { - Channel c = new Channel.Builder().build(); - Program p = new Program.Builder().build(); - ScheduledRecording actual = ScheduledRecording.builder(INPUT_ID, p) - .setChannelId(c.getId()).build(); - assertEquals("type", ScheduledRecording.TYPE_PROGRAM, actual.getType()); - } - - @Test - public void testBuildTime() { - ScheduledRecording actual = createTestRecordingWithIdAndPeriod(1, INPUT_ID, CHANNEL_ID, - 10L, 20L); - assertEquals("type", ScheduledRecording.TYPE_TIMED, actual.getType()); - } - - @Test - public void testBuildFrom() { - ScheduledRecording expected = createTestRecordingWithIdAndPeriod(1, INPUT_ID, CHANNEL_ID, - 10L, 20L); - ScheduledRecording actual = ScheduledRecording.buildFrom(expected).build(); - RecordingTestUtils.assertRecordingEquals(expected, actual); - } - - @Test - public void testBuild_priority() { - ScheduledRecording a = normalizePriority( - createTestRecordingWithIdAndPeriod(1, INPUT_ID, CHANNEL_ID, 10L, 20L)); - ScheduledRecording b = normalizePriority( - createTestRecordingWithIdAndPeriod(2, INPUT_ID, CHANNEL_ID, 10L, 20L)); - ScheduledRecording c = normalizePriority( - createTestRecordingWithIdAndPeriod(3, INPUT_ID, CHANNEL_ID, 10L, 20L)); - - // default priority - MoreAsserts.assertContentsInOrder(sortByPriority(c, b, a), a, b, c); - - // make A preferred over B - a = ScheduledRecording.buildFrom(a).setPriority(b.getPriority() + 2).build(); - MoreAsserts.assertContentsInOrder(sortByPriority(a, b, c), b, c, a); - } - - public Collection<ScheduledRecording> sortByPriority(ScheduledRecording a, ScheduledRecording b, - ScheduledRecording c) { - List<ScheduledRecording> list = Arrays.asList(a, b, c); - Collections.sort(list, ScheduledRecording.PRIORITY_COMPARATOR); - return list; - } - - private void assertOverLapping(boolean expected, long lower, long upper, ScheduledRecording r) { - assertEquals("isOverlapping(Range(" + lower + "," + upper + "), recording " + r, expected, - r.isOverLapping(new Range<>(lower, upper))); - } -} diff --git a/tests/unit/src/com/android/tv/dvr/data/SeriesRecordingTest.java b/tests/unit/src/com/android/tv/dvr/data/SeriesRecordingTest.java deleted file mode 100644 index 790b2ee8..00000000 --- a/tests/unit/src/com/android/tv/dvr/data/SeriesRecordingTest.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2016 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.dvr.data; - -import static org.junit.Assert.assertEquals; - -import android.os.Build; -import android.os.Parcel; -import android.support.test.filters.SdkSuppress; -import android.support.test.filters.SmallTest; - -import com.android.tv.data.Program; - -import org.junit.Test; - -/** - * Tests for {@link SeriesRecording}. - */ -@SmallTest -@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N) -public class SeriesRecordingTest { - private static final String PROGRAM_TITLE = "MyProgram"; - private static final long CHANNEL_ID = 123; - private static final long OTHER_CHANNEL_ID = 321; - private static final String SERIES_ID = "SERIES_ID"; - private static final String OTHER_SERIES_ID = "OTHER_SERIES_ID"; - - private final SeriesRecording mBaseSeriesRecording = new SeriesRecording.Builder() - .setTitle(PROGRAM_TITLE).setChannelId(CHANNEL_ID).setSeriesId(SERIES_ID).build(); - private final SeriesRecording mSeriesRecordingSeason2 = SeriesRecording - .buildFrom(mBaseSeriesRecording).setStartFromSeason(2).build(); - private final SeriesRecording mSeriesRecordingSeason2Episode5 = SeriesRecording - .buildFrom(mSeriesRecordingSeason2).setStartFromEpisode(5).build(); - private final Program mBaseProgram = new Program.Builder().setTitle(PROGRAM_TITLE) - .setChannelId(CHANNEL_ID).setSeriesId(SERIES_ID).build(); - - @Test - public void testParcelable() { - SeriesRecording r1 = new SeriesRecording.Builder() - .setId(1) - .setChannelId(2) - .setPriority(3) - .setTitle("4") - .setDescription("5") - .setLongDescription("5-long") - .setSeriesId("6") - .setStartFromEpisode(7) - .setStartFromSeason(8) - .setChannelOption(SeriesRecording.OPTION_CHANNEL_ALL) - .setCanonicalGenreIds(new int[] {9, 10}) - .setPosterUri("11") - .setPhotoUri("12") - .build(); - Parcel p1 = Parcel.obtain(); - Parcel p2 = Parcel.obtain(); - try { - r1.writeToParcel(p1, 0); - byte[] bytes = p1.marshall(); - p2.unmarshall(bytes, 0, bytes.length); - p2.setDataPosition(0); - SeriesRecording r2 = SeriesRecording.fromParcel(p2); - assertEquals(r1, r2); - } finally { - p1.recycle(); - p2.recycle(); - } - } - - @Test - public void testDoesProgramMatch_simpleMatch() { - assertDoesProgramMatch(mBaseProgram, mBaseSeriesRecording, true); - } - - @Test - public void testDoesProgramMatch_differentSeriesId() { - Program program = new Program.Builder(mBaseProgram).setSeriesId(OTHER_SERIES_ID).build(); - assertDoesProgramMatch(program, mBaseSeriesRecording, false); - } - - @Test - public void testDoesProgramMatch_differentChannel() { - Program program = new Program.Builder(mBaseProgram).setChannelId(OTHER_CHANNEL_ID).build(); - assertDoesProgramMatch(program, mBaseSeriesRecording, false); - } - - @Test - public void testDoesProgramMatch_startFromSeason2() { - Program program = mBaseProgram; - assertDoesProgramMatch(program, mSeriesRecordingSeason2, true); - program = new Program.Builder(program).setSeasonNumber("1").build(); - assertDoesProgramMatch(program, mSeriesRecordingSeason2, false); - program = new Program.Builder(program).setSeasonNumber("2").build(); - assertDoesProgramMatch(program, mSeriesRecordingSeason2, true); - program = new Program.Builder(program).setSeasonNumber("3").build(); - assertDoesProgramMatch(program, mSeriesRecordingSeason2, true); - } - - @Test - public void testDoesProgramMatch_startFromSeason2episode5() { - Program program = mBaseProgram; - assertDoesProgramMatch(program, mSeriesRecordingSeason2Episode5, true); - program = new Program.Builder(program).setSeasonNumber("2").build(); - assertDoesProgramMatch(program, mSeriesRecordingSeason2Episode5, true); - program = new Program.Builder(program).setEpisodeNumber("4").build(); - assertDoesProgramMatch(program, mSeriesRecordingSeason2Episode5, false); - program = new Program.Builder(program).setEpisodeNumber("5").build(); - assertDoesProgramMatch(program, mSeriesRecordingSeason2Episode5, true); - program = new Program.Builder(program).setEpisodeNumber("6").build(); - assertDoesProgramMatch(program, mSeriesRecordingSeason2Episode5, true); - program = new Program.Builder(program).setSeasonNumber("3").setEpisodeNumber("1").build(); - assertDoesProgramMatch(program, mSeriesRecordingSeason2Episode5, true); - } - - private void assertDoesProgramMatch(Program p, SeriesRecording seriesRecording, - boolean expected) { - assertEquals(seriesRecording + " doesProgramMatch " + p, expected, - seriesRecording.matchProgram(p)); - } -} diff --git a/tests/unit/src/com/android/tv/dvr/provider/DvrDbSyncTest.java b/tests/unit/src/com/android/tv/dvr/provider/DvrDbSyncTest.java deleted file mode 100644 index 94f88a51..00000000 --- a/tests/unit/src/com/android/tv/dvr/provider/DvrDbSyncTest.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2016 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.dvr.provider; - -import static android.support.test.InstrumentationRegistry.getContext; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyObject; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.os.Build; -import android.support.test.filters.SdkSuppress; -import android.support.test.filters.SmallTest; - -import com.android.tv.data.ChannelDataManager; -import com.android.tv.data.Program; -import com.android.tv.dvr.DvrDataManagerImpl; -import com.android.tv.dvr.DvrManager; -import com.android.tv.dvr.data.ScheduledRecording; -import com.android.tv.dvr.data.SeriesRecording; -import com.android.tv.dvr.recorder.SeriesRecordingScheduler; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -/** - * Tests for {@link com.android.tv.dvr.DvrScheduleManager} - */ -@SmallTest -@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N) -public class DvrDbSyncTest { - private static final String INPUT_ID = "input_id"; - private static final long BASE_PROGRAM_ID = 1; - private static final long BASE_START_TIME_MS = 0; - private static final long BASE_END_TIME_MS = 1; - private static final String BASE_SEASON_NUMBER = "2"; - private static final String BASE_EPISODE_NUMBER = "3"; - private static final Program BASE_PROGRAM = new Program.Builder().setId(BASE_PROGRAM_ID) - .setStartTimeUtcMillis(BASE_START_TIME_MS).setEndTimeUtcMillis(BASE_END_TIME_MS) - .build(); - private static final Program BASE_SERIES_PROGRAM = new Program.Builder().setId(BASE_PROGRAM_ID) - .setStartTimeUtcMillis(BASE_START_TIME_MS).setEndTimeUtcMillis(BASE_END_TIME_MS) - .setSeasonNumber(BASE_SEASON_NUMBER).setEpisodeNumber(BASE_EPISODE_NUMBER).build(); - private static final ScheduledRecording BASE_SCHEDULE = - ScheduledRecording.builder(INPUT_ID, BASE_PROGRAM).build(); - private static final ScheduledRecording BASE_SERIES_SCHEDULE = - ScheduledRecording.builder(INPUT_ID, BASE_SERIES_PROGRAM).build(); - - private DvrDbSync mDbSync; - @Mock private DvrManager mDvrManager; - @Mock private DvrDataManagerImpl mDataManager; - @Mock private ChannelDataManager mChannelDataManager; - @Mock private SeriesRecordingScheduler mSeriesRecordingScheduler; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - when(mChannelDataManager.isDbLoadFinished()).thenReturn(true); - when(mDvrManager.addSeriesRecording(anyObject(), anyObject(), anyInt())) - .thenReturn(SeriesRecording.builder(INPUT_ID, BASE_PROGRAM).build()); - mDbSync = new DvrDbSync(getContext(), mDataManager, mChannelDataManager, - mDvrManager, mSeriesRecordingScheduler); - } - - @Test - public void testHandleUpdateProgram_null() { - addSchedule(BASE_PROGRAM_ID, BASE_SCHEDULE); - mDbSync.handleUpdateProgram(null, BASE_PROGRAM_ID); - verify(mDataManager).removeScheduledRecording(BASE_SCHEDULE); - } - - @Test - public void testHandleUpdateProgram_changeTimeNotStarted() { - addSchedule(BASE_PROGRAM_ID, BASE_SCHEDULE); - long startTimeMs = BASE_START_TIME_MS + 1; - long endTimeMs = BASE_END_TIME_MS + 1; - Program program = new Program.Builder(BASE_PROGRAM).setStartTimeUtcMillis(startTimeMs) - .setEndTimeUtcMillis(endTimeMs).build(); - mDbSync.handleUpdateProgram(program, BASE_PROGRAM_ID); - assertUpdateScheduleCalled(program); - } - - @Test - public void testHandleUpdateProgram_changeTimeInProgressNotCalled() { - addSchedule(BASE_PROGRAM_ID, ScheduledRecording.buildFrom(BASE_SCHEDULE) - .setState(ScheduledRecording.STATE_RECORDING_IN_PROGRESS).build()); - long startTimeMs = BASE_START_TIME_MS + 1; - Program program = new Program.Builder(BASE_PROGRAM).setStartTimeUtcMillis(startTimeMs) - .build(); - mDbSync.handleUpdateProgram(program, BASE_PROGRAM_ID); - verify(mDataManager, never()).updateScheduledRecording(anyObject()); - } - - @Test - public void testHandleUpdateProgram_changeSeason() { - addSchedule(BASE_PROGRAM_ID, BASE_SERIES_SCHEDULE); - String seasonNumber = BASE_SEASON_NUMBER + "1"; - String episodeNumber = BASE_EPISODE_NUMBER + "1"; - Program program = new Program.Builder(BASE_SERIES_PROGRAM).setSeasonNumber(seasonNumber) - .setEpisodeNumber(episodeNumber).build(); - mDbSync.handleUpdateProgram(program, BASE_PROGRAM_ID); - assertUpdateScheduleCalled(program); - } - - @Test - public void testHandleUpdateProgram_finished() { - addSchedule(BASE_PROGRAM_ID, ScheduledRecording.buildFrom(BASE_SERIES_SCHEDULE) - .setState(ScheduledRecording.STATE_RECORDING_FINISHED).build()); - String seasonNumber = BASE_SEASON_NUMBER + "1"; - String episodeNumber = BASE_EPISODE_NUMBER + "1"; - Program program = new Program.Builder(BASE_SERIES_PROGRAM).setSeasonNumber(seasonNumber) - .setEpisodeNumber(episodeNumber).build(); - mDbSync.handleUpdateProgram(program, BASE_PROGRAM_ID); - verify(mDataManager, never()).updateScheduledRecording(anyObject()); - } - - private void addSchedule(long programId, ScheduledRecording schedule) { - when(mDataManager.getScheduledRecordingForProgramId(programId)).thenReturn(schedule); - } - - private void assertUpdateScheduleCalled(Program program) { - verify(mDataManager).updateScheduledRecording( - eq(ScheduledRecording.builder(INPUT_ID, program).build())); - } -} diff --git a/tests/unit/src/com/android/tv/dvr/provider/EpisodicProgramLoadTaskTest.java b/tests/unit/src/com/android/tv/dvr/provider/EpisodicProgramLoadTaskTest.java deleted file mode 100644 index 216d4d5b..00000000 --- a/tests/unit/src/com/android/tv/dvr/provider/EpisodicProgramLoadTaskTest.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2016 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.dvr.provider; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import android.os.Build; -import android.support.test.filters.SdkSuppress; -import android.support.test.filters.SmallTest; - -import com.android.tv.dvr.data.SeasonEpisodeNumber; - -import org.junit.Test; - -import java.util.ArrayList; -import java.util.List; - -/** - * Tests for {@link EpisodicProgramLoadTask} - */ -@SmallTest -@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N) -public class EpisodicProgramLoadTaskTest { - private static final long SERIES_RECORDING_ID1 = 1; - private static final long SERIES_RECORDING_ID2 = 2; - private static final String SEASON_NUMBER1 = "SEASON NUMBER1"; - private static final String SEASON_NUMBER2 = "SEASON NUMBER2"; - private static final String EPISODE_NUMBER1 = "EPISODE NUMBER1"; - private static final String EPISODE_NUMBER2 = "EPISODE NUMBER2"; - - @Test - public void testEpisodeAlreadyScheduled_true() { - List<SeasonEpisodeNumber> seasonEpisodeNumbers = new ArrayList<>(); - SeasonEpisodeNumber seasonEpisodeNumber = new SeasonEpisodeNumber( - SERIES_RECORDING_ID1, SEASON_NUMBER1, EPISODE_NUMBER1); - seasonEpisodeNumbers.add(seasonEpisodeNumber); - assertTrue(seasonEpisodeNumbers.contains( - new SeasonEpisodeNumber(SERIES_RECORDING_ID1, SEASON_NUMBER1, EPISODE_NUMBER1))); - } - - @Test - public void testEpisodeAlreadyScheduled_false() { - List<SeasonEpisodeNumber> seasonEpisodeNumbers = new ArrayList<>(); - SeasonEpisodeNumber seasonEpisodeNumber = new SeasonEpisodeNumber( - SERIES_RECORDING_ID1, SEASON_NUMBER1, EPISODE_NUMBER1); - seasonEpisodeNumbers.add(seasonEpisodeNumber); - assertFalse(seasonEpisodeNumbers.contains( - new SeasonEpisodeNumber(SERIES_RECORDING_ID2, SEASON_NUMBER1, EPISODE_NUMBER1))); - assertFalse(seasonEpisodeNumbers.contains( - new SeasonEpisodeNumber(SERIES_RECORDING_ID1, SEASON_NUMBER2, EPISODE_NUMBER1))); - assertFalse(seasonEpisodeNumbers.contains( - new SeasonEpisodeNumber(SERIES_RECORDING_ID1, SEASON_NUMBER1, EPISODE_NUMBER2))); - } - - @Test - public void testEpisodeAlreadyScheduled_null() { - List<SeasonEpisodeNumber> seasonEpisodeNumbers = new ArrayList<>(); - SeasonEpisodeNumber seasonEpisodeNumber = new SeasonEpisodeNumber( - SERIES_RECORDING_ID1, SEASON_NUMBER1, EPISODE_NUMBER1); - seasonEpisodeNumbers.add(seasonEpisodeNumber); - assertFalse(seasonEpisodeNumbers.contains( - new SeasonEpisodeNumber(SERIES_RECORDING_ID1, null, EPISODE_NUMBER1))); - assertFalse(seasonEpisodeNumbers.contains( - new SeasonEpisodeNumber(SERIES_RECORDING_ID1, SEASON_NUMBER1, null))); - assertFalse(seasonEpisodeNumbers.contains( - new SeasonEpisodeNumber(SERIES_RECORDING_ID1, null, null))); - } -}
\ No newline at end of file diff --git a/tests/unit/src/com/android/tv/dvr/recorder/DvrRecordingServiceTest.java b/tests/unit/src/com/android/tv/dvr/recorder/DvrRecordingServiceTest.java index 8f7dcaf2..d510da32 100644 --- a/tests/unit/src/com/android/tv/dvr/recorder/DvrRecordingServiceTest.java +++ b/tests/unit/src/com/android/tv/dvr/recorder/DvrRecordingServiceTest.java @@ -16,24 +16,18 @@ package com.android.tv.dvr.recorder; -import static org.mockito.Mockito.verify; +import static com.google.common.truth.Truth.assertThat; import android.content.Intent; import android.os.Build; import android.support.test.filters.SdkSuppress; import android.support.test.filters.SmallTest; import android.test.ServiceTestCase; - import com.android.tv.common.feature.CommonFeatures; import com.android.tv.common.feature.TestableFeature; - -import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.MockitoAnnotations; -/** - * Tests for {@link DvrRecordingService}. - */ +/** Tests for {@link DvrRecordingService}. */ @SmallTest @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N) public class DvrRecordingServiceTest @@ -61,13 +55,13 @@ public class DvrRecordingServiceTest public void testStartService_null() throws Exception { // Not recording startService(null); - assertFalse(getService().mInForeground); + assertThat(getService().mInForeground).isFalse(); // Recording getService().startRecording(); startService(null); - assertTrue(getService().mInForeground); - assertTrue(getService().mIsRecording); + assertThat(getService().mInForeground).isTrue(); + assertThat(getService().mIsRecording).isTrue(); getService().reset(); } @@ -77,38 +71,38 @@ public class DvrRecordingServiceTest // Not recording startService(intent); - assertTrue(getService().mInForeground); - assertFalse(getService().mForegroundForUpcomingRecording); + assertThat(getService().mInForeground).isTrue(); + assertThat(getService().mForegroundForUpcomingRecording).isFalse(); getService().stopForegroundIfNotRecordingInternal(); - assertFalse(getService().mInForeground); + assertThat(getService().mInForeground).isFalse(); // Recording, ended quickly getService().startRecording(); startService(intent); - assertTrue(getService().mInForeground); - assertTrue(getService().mForegroundForUpcomingRecording); - assertTrue(getService().mIsRecording); + assertThat(getService().mInForeground).isTrue(); + assertThat(getService().mForegroundForUpcomingRecording).isTrue(); + assertThat(getService().mIsRecording).isTrue(); getService().stopRecording(); - assertFalse(getService().mInForeground); - assertFalse(getService().mIsRecording); + assertThat(getService().mInForeground).isFalse(); + assertThat(getService().mIsRecording).isFalse(); getService().stopForegroundIfNotRecordingInternal(); - assertFalse(getService().mInForeground); - assertFalse(getService().mIsRecording); + assertThat(getService().mInForeground).isFalse(); + assertThat(getService().mIsRecording).isFalse(); getService().reset(); // Recording, ended later getService().startRecording(); startService(intent); - assertTrue(getService().mInForeground); - assertTrue(getService().mForegroundForUpcomingRecording); - assertTrue(getService().mIsRecording); + assertThat(getService().mInForeground).isTrue(); + assertThat(getService().mForegroundForUpcomingRecording).isTrue(); + assertThat(getService().mIsRecording).isTrue(); getService().stopForegroundIfNotRecordingInternal(); - assertTrue(getService().mInForeground); - assertTrue(getService().mForegroundForUpcomingRecording); - assertTrue(getService().mIsRecording); + assertThat(getService().mInForeground).isTrue(); + assertThat(getService().mForegroundForUpcomingRecording).isTrue(); + assertThat(getService().mIsRecording).isTrue(); getService().stopRecording(); - assertFalse(getService().mInForeground); - assertFalse(getService().mIsRecording); + assertThat(getService().mInForeground).isFalse(); + assertThat(getService().mIsRecording).isFalse(); getService().reset(); } @@ -118,38 +112,39 @@ public class DvrRecordingServiceTest // Not recording startService(intent); - assertTrue(getService().mInForeground); - assertTrue(getService().mForegroundForUpcomingRecording); - assertFalse(getService().mIsRecording); + assertThat(getService().mInForeground).isTrue(); + assertThat(getService().mForegroundForUpcomingRecording).isTrue(); + assertThat(getService().mIsRecording).isFalse(); getService().startRecording(); - assertTrue(getService().mInForeground); - assertTrue(getService().mForegroundForUpcomingRecording); - assertTrue(getService().mIsRecording); + assertThat(getService().mInForeground).isTrue(); + assertThat(getService().mForegroundForUpcomingRecording).isTrue(); + assertThat(getService().mIsRecording).isTrue(); getService().stopRecording(); - assertFalse(getService().mInForeground); - assertFalse(getService().mIsRecording); + assertThat(getService().mInForeground).isFalse(); + assertThat(getService().mIsRecording).isFalse(); getService().reset(); // Recording getService().startRecording(); startService(intent); - assertTrue(getService().mInForeground); - assertTrue(getService().mForegroundForUpcomingRecording); - assertTrue(getService().mIsRecording); + assertThat(getService().mInForeground).isTrue(); + assertThat(getService().mForegroundForUpcomingRecording).isTrue(); + assertThat(getService().mIsRecording).isTrue(); getService().startRecording(); - assertTrue(getService().mInForeground); - assertTrue(getService().mForegroundForUpcomingRecording); - assertTrue(getService().mIsRecording); + assertThat(getService().mInForeground).isTrue(); + assertThat(getService().mForegroundForUpcomingRecording).isTrue(); + assertThat(getService().mIsRecording).isTrue(); getService().stopRecording(); - assertTrue(getService().mInForeground); - assertTrue(getService().mForegroundForUpcomingRecording); - assertTrue(getService().mIsRecording); + assertThat(getService().mInForeground).isTrue(); + assertThat(getService().mForegroundForUpcomingRecording).isTrue(); + assertThat(getService().mIsRecording).isTrue(); getService().stopRecording(); - assertFalse(getService().mInForeground); - assertFalse(getService().mIsRecording); + assertThat(getService().mInForeground).isFalse(); + assertThat(getService().mIsRecording).isFalse(); getService().reset(); } + /** Mock {@link DvrRecordingService}. */ public static class MockDvrRecordingService extends DvrRecordingService { private int mRecordingCount = 0; private boolean mInForeground; @@ -180,4 +175,4 @@ public class DvrRecordingServiceTest mIsRecording = false; } } -}
\ No newline at end of file +} diff --git a/tests/unit/src/com/android/tv/dvr/recorder/InputTaskSchedulerTest.java b/tests/unit/src/com/android/tv/dvr/recorder/InputTaskSchedulerTest.java deleted file mode 100644 index e5c27e2c..00000000 --- a/tests/unit/src/com/android/tv/dvr/recorder/InputTaskSchedulerTest.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright (C) 2016 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.dvr.recorder; - -import static android.support.test.InstrumentationRegistry.getContext; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyLong; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.timeout; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.app.AlarmManager; -import android.media.tv.TvInputInfo; -import android.os.Build; -import android.os.Looper; -import android.os.SystemClock; -import android.support.test.filters.SdkSuppress; -import android.support.test.filters.SmallTest; - -import com.android.tv.InputSessionManager; -import com.android.tv.data.Channel; -import com.android.tv.data.ChannelDataManager; -import com.android.tv.dvr.DvrManager; -import com.android.tv.dvr.WritableDvrDataManager; -import com.android.tv.dvr.data.ScheduledRecording; -import com.android.tv.dvr.recorder.InputTaskScheduler.RecordingTaskFactory; -import com.android.tv.testing.FakeClock; -import com.android.tv.testing.dvr.RecordingTestUtils; -import com.android.tv.util.Clock; -import com.android.tv.util.TestUtils; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; - -/** - * Tests for {@link InputTaskScheduler}. - */ -@SmallTest -@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N) -public class InputTaskSchedulerTest { - private static final String INPUT_ID = "input_id"; - private static final int CHANNEL_ID = 1; - private static final long LISTENER_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(1); - private static final int TUNER_COUNT_ONE = 1; - private static final int TUNER_COUNT_TWO = 2; - private static final long LOW_PRIORITY = 1; - private static final long HIGH_PRIORITY = 2; - - private FakeClock mFakeClock; - private InputTaskScheduler mScheduler; - @Mock private DvrManager mDvrManager; - @Mock private WritableDvrDataManager mDataManager; - @Mock private InputSessionManager mSessionManager; - @Mock private AlarmManager mMockAlarmManager; - @Mock private ChannelDataManager mChannelDataManager; - private List<RecordingTask> mRecordingTasks; - - @Before - public void setUp() throws Exception { - if (Looper.myLooper() == null) { - Looper.prepare(); - } - mRecordingTasks = new ArrayList(); - MockitoAnnotations.initMocks(this); - mFakeClock = FakeClock.createWithCurrentTime(); - TvInputInfo input = createTvInputInfo(TUNER_COUNT_ONE); - mScheduler = new InputTaskScheduler(getContext(), input, Looper.myLooper(), - mChannelDataManager, mDvrManager, mDataManager, mSessionManager, mFakeClock, - new RecordingTaskFactory() { - @Override - public RecordingTask createRecordingTask(ScheduledRecording scheduledRecording, - Channel channel, DvrManager dvrManager, - InputSessionManager sessionManager, WritableDvrDataManager dataManager, - Clock clock) { - RecordingTask task = mock(RecordingTask.class); - when(task.getPriority()).thenReturn(scheduledRecording.getPriority()); - when(task.getEndTimeMs()).thenReturn(scheduledRecording.getEndTimeMs()); - mRecordingTasks.add(task); - return task; - } - }); - } - - @Test - public void testAddSchedule_past() { - ScheduledRecording r = RecordingTestUtils.createTestRecordingWithPeriod(INPUT_ID, - CHANNEL_ID, 0L, 1L); - when(mDataManager.getScheduledRecording(anyLong())).thenReturn(r); - mScheduler.handleAddSchedule(r); - mScheduler.handleBuildSchedule(); - verify(mDataManager, timeout((int) LISTENER_TIMEOUT_MS).times(1)) - .changeState(any(ScheduledRecording.class), - eq(ScheduledRecording.STATE_RECORDING_FAILED)); - } - - @Test - public void testAddSchedule_start() { - mScheduler.handleAddSchedule(RecordingTestUtils.createTestRecordingWithPeriod(INPUT_ID, - CHANNEL_ID, mFakeClock.currentTimeMillis(), - mFakeClock.currentTimeMillis() + TimeUnit.HOURS.toMillis(1))); - mScheduler.handleBuildSchedule(); - verify(mRecordingTasks.get(0), timeout((int) LISTENER_TIMEOUT_MS).times(1)).start(); - } - - @Test - public void testAddSchedule_consecutiveNoStop() { - long startTimeMs = mFakeClock.currentTimeMillis(); - long endTimeMs = startTimeMs + TimeUnit.SECONDS.toMillis(1); - long id = 0; - mScheduler.handleAddSchedule( - RecordingTestUtils.createTestRecordingWithIdAndPriorityAndPeriod(++id, CHANNEL_ID, - LOW_PRIORITY, startTimeMs, endTimeMs)); - mScheduler.handleBuildSchedule(); - startTimeMs = endTimeMs; - endTimeMs = startTimeMs + TimeUnit.SECONDS.toMillis(1); - mScheduler.handleAddSchedule( - RecordingTestUtils.createTestRecordingWithIdAndPriorityAndPeriod(++id, CHANNEL_ID, - HIGH_PRIORITY, startTimeMs, endTimeMs)); - mScheduler.handleBuildSchedule(); - verify(mRecordingTasks.get(0), timeout((int) LISTENER_TIMEOUT_MS).times(1)).start(); - // The first schedule should not be stopped because the second one should wait for the end - // of the first schedule. - SystemClock.sleep(LISTENER_TIMEOUT_MS); - verify(mRecordingTasks.get(0), never()).stop(); - } - - @Test - public void testAddSchedule_consecutiveNoFail() { - long startTimeMs = mFakeClock.currentTimeMillis(); - long endTimeMs = startTimeMs + TimeUnit.SECONDS.toMillis(1); - long id = 0; - when(mDataManager.getScheduledRecording(anyLong())).thenReturn(ScheduledRecording - .builder(INPUT_ID, CHANNEL_ID, 0L, 0L).build()); - mScheduler.handleAddSchedule( - RecordingTestUtils.createTestRecordingWithIdAndPriorityAndPeriod(++id, CHANNEL_ID, - HIGH_PRIORITY, startTimeMs, endTimeMs)); - mScheduler.handleBuildSchedule(); - startTimeMs = endTimeMs; - endTimeMs = startTimeMs + TimeUnit.SECONDS.toMillis(1); - mScheduler.handleAddSchedule( - RecordingTestUtils.createTestRecordingWithIdAndPriorityAndPeriod(++id, CHANNEL_ID, - LOW_PRIORITY, startTimeMs, endTimeMs)); - mScheduler.handleBuildSchedule(); - verify(mRecordingTasks.get(0), timeout((int) LISTENER_TIMEOUT_MS).times(1)).start(); - SystemClock.sleep(LISTENER_TIMEOUT_MS); - verify(mRecordingTasks.get(0), never()).stop(); - // The second schedule should not fail because it can starts after the first one finishes. - SystemClock.sleep(LISTENER_TIMEOUT_MS); - verify(mDataManager, never()) - .changeState(any(ScheduledRecording.class), - eq(ScheduledRecording.STATE_RECORDING_FAILED)); - } - - @Test - public void testAddSchedule_consecutiveUseLessSession() throws Exception { - TvInputInfo input = createTvInputInfo(TUNER_COUNT_TWO); - mScheduler.updateTvInputInfo(input); - long startTimeMs = mFakeClock.currentTimeMillis(); - long endTimeMs = startTimeMs + TimeUnit.SECONDS.toMillis(1); - long id = 0; - mScheduler.handleAddSchedule( - RecordingTestUtils.createTestRecordingWithIdAndPriorityAndPeriod(++id, CHANNEL_ID, - LOW_PRIORITY, startTimeMs, endTimeMs)); - mScheduler.handleBuildSchedule(); - startTimeMs = endTimeMs; - endTimeMs = startTimeMs + TimeUnit.SECONDS.toMillis(1); - mScheduler.handleAddSchedule( - RecordingTestUtils.createTestRecordingWithIdAndPriorityAndPeriod(++id, CHANNEL_ID, - HIGH_PRIORITY, startTimeMs, endTimeMs)); - mScheduler.handleBuildSchedule(); - verify(mRecordingTasks.get(0), timeout((int) LISTENER_TIMEOUT_MS).times(1)).start(); - SystemClock.sleep(LISTENER_TIMEOUT_MS); - verify(mRecordingTasks.get(0), never()).stop(); - // The second schedule should wait until the first one finishes rather than creating a new - // session even though there are available tuners. - assertTrue(mRecordingTasks.size() == 1); - } - - @Test - public void testUpdateSchedule_noCancel() { - ScheduledRecording r = RecordingTestUtils.createTestRecordingWithPeriod(INPUT_ID, - CHANNEL_ID, mFakeClock.currentTimeMillis(), - mFakeClock.currentTimeMillis() + TimeUnit.HOURS.toMillis(1)); - mScheduler.handleAddSchedule(r); - mScheduler.handleBuildSchedule(); - mScheduler.handleUpdateSchedule(r); - SystemClock.sleep(LISTENER_TIMEOUT_MS); - verify(mRecordingTasks.get(0), never()).cancel(); - } - - @Test - public void testUpdateSchedule_cancel() { - ScheduledRecording r = RecordingTestUtils.createTestRecordingWithPeriod(INPUT_ID, - CHANNEL_ID, mFakeClock.currentTimeMillis(), - mFakeClock.currentTimeMillis() + TimeUnit.HOURS.toMillis(2)); - mScheduler.handleAddSchedule(r); - mScheduler.handleBuildSchedule(); - mScheduler.handleUpdateSchedule(ScheduledRecording.buildFrom(r) - .setStartTimeMs(mFakeClock.currentTimeMillis() + TimeUnit.HOURS.toMillis(1)) - .build()); - verify(mRecordingTasks.get(0), timeout((int) LISTENER_TIMEOUT_MS).times(1)).cancel(); - } - - private TvInputInfo createTvInputInfo(int tunerCount) throws Exception { - return TestUtils.createTvInputInfo(null, null, null, 0, false, true, tunerCount); - } -} diff --git a/tests/unit/src/com/android/tv/dvr/recorder/RecordingTaskTest.java b/tests/unit/src/com/android/tv/dvr/recorder/RecordingTaskTest.java deleted file mode 100644 index 37561a42..00000000 --- a/tests/unit/src/com/android/tv/dvr/recorder/RecordingTaskTest.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * 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.dvr.recorder; - -import static android.support.test.InstrumentationRegistry.getContext; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.anyLong; -import static org.mockito.Matchers.anyObject; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - -import android.os.Build; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.support.test.filters.SdkSuppress; -import android.support.test.filters.SmallTest; - -import com.android.tv.InputSessionManager; -import com.android.tv.InputSessionManager.RecordingSession; -import com.android.tv.common.feature.CommonFeatures; -import com.android.tv.common.feature.TestableFeature; -import com.android.tv.data.Channel; -import com.android.tv.dvr.DvrDataManagerInMemoryImpl; -import com.android.tv.dvr.DvrManager; -import com.android.tv.dvr.data.ScheduledRecording; -import com.android.tv.dvr.recorder.RecordingTask.State; -import com.android.tv.testing.FakeClock; -import com.android.tv.testing.dvr.RecordingTestUtils; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.util.concurrent.TimeUnit; - -/** - * Tests for {@link RecordingTask}. - */ -@SmallTest -@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N) -public class RecordingTaskTest { - private static final long DURATION = TimeUnit.MINUTES.toMillis(30); - private static final long START_OFFSET_MS = RecordingScheduler.MS_TO_WAKE_BEFORE_START; - private static final String INPUT_ID = "input_id"; - private static final int CHANNEL_ID = 273; - - private FakeClock mFakeClock; - private DvrDataManagerInMemoryImpl mDataManager; - @Mock Handler mMockHandler; - @Mock DvrManager mDvrManager; - @Mock InputSessionManager mMockSessionManager; - @Mock RecordingSession mMockRecordingSession; - private final TestableFeature mDvrFeature = CommonFeatures.DVR; - - @Before - public void setUp() { - mDvrFeature.enableForTest(); - if (Looper.myLooper() == null) { - Looper.prepare(); - } - MockitoAnnotations.initMocks(this); - mFakeClock = FakeClock.createWithCurrentTime(); - mDataManager = new DvrDataManagerInMemoryImpl(getContext(), mFakeClock); - } - - @After - public void tearDown() { - mDvrFeature.resetForTests(); - } - - @Test - public void testHandle_init() { - Channel channel = createTestChannel(); - ScheduledRecording r = createRecording(channel); - RecordingTask task = createRecordingTask(r, channel); - String inputId = channel.getInputId(); - when(mMockSessionManager.createRecordingSession(eq(inputId), anyString(), eq(task), - eq(mMockHandler), anyLong())).thenReturn(mMockRecordingSession); - when(mMockHandler.sendMessageAtTime(anyObject(), anyLong())).thenReturn(true); - assertTrue(task.handleMessage(createMessage(RecordingTask.MSG_INITIALIZE))); - assertEquals(State.CONNECTION_PENDING, task.getState()); - verify(mMockSessionManager).createRecordingSession(eq(inputId), anyString(), eq(task), - eq(mMockHandler), anyLong()); - verify(mMockRecordingSession).tune(eq(inputId), eq(channel.getUri())); - verifyNoMoreInteractions(mMockHandler, mMockRecordingSession, mMockSessionManager); - } - - private static Channel createTestChannel() { - return new Channel.Builder().setInputId(INPUT_ID).setId(CHANNEL_ID) - .setDisplayName("Test Ch " + CHANNEL_ID).build(); - } - - @Test - public void testOnConnected() { - Channel channel = createTestChannel(); - ScheduledRecording r = createRecording(channel); - mDataManager.addScheduledRecording(r); - RecordingTask task = createRecordingTask(r, channel); - String inputId = channel.getInputId(); - when(mMockSessionManager.createRecordingSession(eq(inputId), anyString(), eq(task), - eq(mMockHandler), anyLong())).thenReturn(mMockRecordingSession); - when(mMockHandler.sendMessageAtTime(anyObject(), anyLong())).thenReturn(true); - task.handleMessage(createMessage(RecordingTask.MSG_INITIALIZE)); - task.onTuned(channel.getUri()); - assertEquals(State.CONNECTED, task.getState()); - } - - private ScheduledRecording createRecording(Channel c) { - long startTime = mFakeClock.currentTimeMillis() + START_OFFSET_MS; - long endTime = startTime + DURATION; - return RecordingTestUtils.createTestRecordingWithPeriod(c.getInputId(), c.getId(), - startTime, endTime); - } - - private RecordingTask createRecordingTask(ScheduledRecording r, Channel channel) { - RecordingTask recordingTask = new RecordingTask(getContext(), r, channel, mDvrManager, - mMockSessionManager, mDataManager, mFakeClock); - recordingTask.setHandler(mMockHandler); - return recordingTask; - } - - private Message createMessage(int what) { - Message msg = new Message(); - msg.setTarget(mMockHandler); - msg.what = what; - return msg; - } -}
\ No newline at end of file diff --git a/tests/unit/src/com/android/tv/dvr/recorder/ScheduledProgramReaperTest.java b/tests/unit/src/com/android/tv/dvr/recorder/ScheduledProgramReaperTest.java deleted file mode 100644 index ca72e13f..00000000 --- a/tests/unit/src/com/android/tv/dvr/recorder/ScheduledProgramReaperTest.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2016 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.dvr.recorder; - -import static android.support.test.InstrumentationRegistry.getContext; -import static org.junit.Assert.assertTrue; - -import android.os.Build; -import android.support.test.filters.SdkSuppress; -import android.support.test.filters.SmallTest; -import android.test.MoreAsserts; - -import com.android.tv.common.feature.CommonFeatures; -import com.android.tv.common.feature.TestableFeature; -import com.android.tv.dvr.DvrDataManagerInMemoryImpl; -import com.android.tv.dvr.DvrManager; -import com.android.tv.dvr.data.ScheduledRecording; -import com.android.tv.testing.FakeClock; -import com.android.tv.testing.dvr.RecordingTestUtils; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.util.concurrent.TimeUnit; - -/** - * Tests for {@link ScheduledProgramReaper}. - */ -@SmallTest -@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N) -public class ScheduledProgramReaperTest { - private static final String INPUT_ID = "input_id"; - private static final int CHANNEL_ID = 273; - private static final long DURATION = TimeUnit.HOURS.toMillis(1); - - private ScheduledProgramReaper mReaper; - private FakeClock mFakeClock; - private DvrDataManagerInMemoryImpl mDvrDataManager; - @Mock private DvrManager mDvrManager; - private final TestableFeature mDvrFeature = CommonFeatures.DVR; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - mDvrFeature.enableForTest(); - mFakeClock = FakeClock.createWithTimeOne(); - mDvrDataManager = new DvrDataManagerInMemoryImpl(getContext(), mFakeClock); - mReaper = new ScheduledProgramReaper(mDvrDataManager, mFakeClock); - } - - @After - public void tearDown() { - mDvrFeature.resetForTests(); - } - - @Test - public void testRun_noRecordings() { - assertTrue(mDvrDataManager.getAllScheduledRecordings().isEmpty()); - mReaper.run(); - assertTrue(mDvrDataManager.getAllScheduledRecordings().isEmpty()); - } - - @Test - public void testRun_oneRecordingsTomorrow() { - ScheduledRecording recording = addNewScheduledRecordingForTomorrow(); - MoreAsserts - .assertContentsInAnyOrder(mDvrDataManager.getAllScheduledRecordings(), recording); - mReaper.run(); - MoreAsserts - .assertContentsInAnyOrder(mDvrDataManager.getAllScheduledRecordings(), recording); - } - - @Test - public void testRun_oneRecordingsStarted() { - ScheduledRecording recording = addNewScheduledRecordingForTomorrow(); - MoreAsserts - .assertContentsInAnyOrder(mDvrDataManager.getAllScheduledRecordings(), recording); - mFakeClock.increment(TimeUnit.DAYS); - mReaper.run(); - MoreAsserts - .assertContentsInAnyOrder(mDvrDataManager.getAllScheduledRecordings(), recording); - } - - @Test - public void testRun_oneRecordingsFinished() { - ScheduledRecording recording = addNewScheduledRecordingForTomorrow(); - MoreAsserts - .assertContentsInAnyOrder(mDvrDataManager.getAllScheduledRecordings(), recording); - mFakeClock.increment(TimeUnit.DAYS); - mFakeClock.increment(TimeUnit.MINUTES, 2); - mReaper.run(); - MoreAsserts - .assertContentsInAnyOrder(mDvrDataManager.getAllScheduledRecordings(), recording); - } - - @Test - public void testRun_oneRecordingsExpired() { - ScheduledRecording recording = addNewScheduledRecordingForTomorrow(); - MoreAsserts - .assertContentsInAnyOrder(mDvrDataManager.getAllScheduledRecordings(), recording); - mFakeClock.increment(TimeUnit.DAYS, 1 + ScheduledProgramReaper.DAYS); - mFakeClock.increment(TimeUnit.MILLISECONDS, DURATION); - // After the cutoff and enough so we can see on the clock - mFakeClock.increment(TimeUnit.SECONDS, 1); - - mReaper.run(); - assertTrue("Recordings after reaper at " + com.android.tv.util.Utils - .toIsoDateTimeString(mFakeClock.currentTimeMillis()), - mDvrDataManager.getAllScheduledRecordings().isEmpty()); - } - - private ScheduledRecording addNewScheduledRecordingForTomorrow() { - long startTime = mFakeClock.currentTimeMillis() + TimeUnit.DAYS.toMillis(1); - ScheduledRecording recording = RecordingTestUtils.createTestRecordingWithPeriod(INPUT_ID, - CHANNEL_ID, startTime, startTime + DURATION); - return mDvrDataManager.addScheduledRecordingInternal( - ScheduledRecording.buildFrom(recording) - .setState(ScheduledRecording.STATE_RECORDING_FINISHED).build()); - } -} diff --git a/tests/unit/src/com/android/tv/dvr/recorder/SchedulerTest.java b/tests/unit/src/com/android/tv/dvr/recorder/SchedulerTest.java deleted file mode 100644 index a5154729..00000000 --- a/tests/unit/src/com/android/tv/dvr/recorder/SchedulerTest.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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.dvr.recorder; - -import static android.support.test.InstrumentationRegistry.getTargetContext; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; - -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.os.Build; -import android.os.Looper; -import android.support.test.filters.SdkSuppress; -import android.support.test.filters.SmallTest; - -import com.android.tv.InputSessionManager; -import com.android.tv.common.feature.CommonFeatures; -import com.android.tv.common.feature.TestableFeature; -import com.android.tv.data.ChannelDataManager; -import com.android.tv.dvr.DvrDataManagerInMemoryImpl; -import com.android.tv.dvr.DvrManager; -import com.android.tv.dvr.data.ScheduledRecording; -import com.android.tv.testing.FakeClock; -import com.android.tv.testing.dvr.RecordingTestUtils; -import com.android.tv.util.TvInputManagerHelper; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; - -import java.util.concurrent.TimeUnit; - -/** - * Tests for {@link RecordingScheduler}. - */ -@SmallTest -@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N) -public class SchedulerTest { - private static final String INPUT_ID = "input_id"; - private static final int CHANNEL_ID = 273; - - private FakeClock mFakeClock; - private DvrDataManagerInMemoryImpl mDataManager; - private RecordingScheduler mScheduler; - @Mock DvrManager mDvrManager; - @Mock InputSessionManager mSessionManager; - @Mock AlarmManager mMockAlarmManager; - @Mock ChannelDataManager mChannelDataManager; - @Mock TvInputManagerHelper mInputManager; - private final TestableFeature mDvrFeature = CommonFeatures.DVR; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - mDvrFeature.enableForTest(); - mFakeClock = FakeClock.createWithCurrentTime(); - mDataManager = new DvrDataManagerInMemoryImpl(getTargetContext(), mFakeClock); - Mockito.when(mChannelDataManager.isDbLoadFinished()).thenReturn(true); - mScheduler = new RecordingScheduler(Looper.myLooper(), mDvrManager, mSessionManager, mDataManager, - mChannelDataManager, mInputManager, getTargetContext(), mFakeClock, - mMockAlarmManager); - } - - @After - public void tearDown() { - mDvrFeature.resetForTests(); - } - - @Test - public void testUpdate_none() { - mScheduler.updateAndStartServiceIfNeeded(); - verifyZeroInteractions(mMockAlarmManager); - } - - @Test - public void testUpdate_nextIn12Hours() { - long now = mFakeClock.currentTimeMillis(); - long startTime = now + TimeUnit.HOURS.toMillis(12); - ScheduledRecording r = RecordingTestUtils - .createTestRecordingWithPeriod(INPUT_ID, CHANNEL_ID, startTime, - startTime + TimeUnit.HOURS.toMillis(1)); - mDataManager.addScheduledRecording(r); - verify(mMockAlarmManager).setExactAndAllowWhileIdle( - eq(AlarmManager.RTC_WAKEUP), - eq(startTime - RecordingScheduler.MS_TO_WAKE_BEFORE_START), - any(PendingIntent.class)); - Mockito.reset(mMockAlarmManager); - mScheduler.updateAndStartServiceIfNeeded(); - verify(mMockAlarmManager).setExactAndAllowWhileIdle( - eq(AlarmManager.RTC_WAKEUP), - eq(startTime - RecordingScheduler.MS_TO_WAKE_BEFORE_START), - any(PendingIntent.class)); - } - - @Test - public void testStartsWithin() { - long now = mFakeClock.currentTimeMillis(); - long startTime = now + 3; - ScheduledRecording r = RecordingTestUtils - .createTestRecordingWithPeriod(INPUT_ID, CHANNEL_ID, startTime, startTime + 100); - assertFalse(mScheduler.startsWithin(r, 2)); - assertTrue(mScheduler.startsWithin(r, 3)); - } -}
\ No newline at end of file diff --git a/tests/unit/src/com/android/tv/dvr/recorder/SeriesRecordingSchedulerTest.java b/tests/unit/src/com/android/tv/dvr/recorder/SeriesRecordingSchedulerTest.java deleted file mode 100644 index 16fa1baf..00000000 --- a/tests/unit/src/com/android/tv/dvr/recorder/SeriesRecordingSchedulerTest.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2016 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.dvr.recorder; - -import static android.support.test.InstrumentationRegistry.getContext; - -import android.os.Build; -import android.support.test.filters.SdkSuppress; -import android.support.test.filters.SmallTest; -import android.test.MoreAsserts; -import android.util.LongSparseArray; - -import com.android.tv.common.feature.CommonFeatures; -import com.android.tv.common.feature.TestableFeature; -import com.android.tv.data.Program; -import com.android.tv.dvr.DvrDataManagerInMemoryImpl; -import com.android.tv.dvr.data.SeriesRecording; -import com.android.tv.testing.FakeClock; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * Tests for {@link SeriesRecordingScheduler} - */ -@SmallTest -@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N) -public class SeriesRecordingSchedulerTest { - private static final String PROGRAM_TITLE = "MyProgram"; - private static final long CHANNEL_ID = 123; - private static final long SERIES_RECORDING_ID1 = 1; - private static final String SERIES_ID = "SERIES_ID"; - private static final String SEASON_NUMBER1 = "SEASON NUMBER1"; - private static final String SEASON_NUMBER2 = "SEASON NUMBER2"; - private static final String EPISODE_NUMBER1 = "EPISODE NUMBER1"; - private static final String EPISODE_NUMBER2 = "EPISODE NUMBER2"; - - private final SeriesRecording mBaseSeriesRecording = new SeriesRecording.Builder() - .setTitle(PROGRAM_TITLE).setChannelId(CHANNEL_ID).setSeriesId(SERIES_ID).build(); - private final Program mBaseProgram = new Program.Builder().setTitle(PROGRAM_TITLE) - .setChannelId(CHANNEL_ID).setSeriesId(SERIES_ID).build(); - private final TestableFeature mDvrFeature = CommonFeatures.DVR; - - private DvrDataManagerInMemoryImpl mDataManager; - - @Before - public void setUp() { - mDvrFeature.enableForTest(); - FakeClock fakeClock = FakeClock.createWithCurrentTime(); - mDataManager = new DvrDataManagerInMemoryImpl(getContext(), fakeClock); - } - - @After - public void tearDown() { - mDvrFeature.resetForTests(); - } - - @Test - public void testPickOneProgramPerEpisode_onePerEpisode() { - SeriesRecording seriesRecording = SeriesRecording.buildFrom(mBaseSeriesRecording) - .setId(SERIES_RECORDING_ID1).build(); - mDataManager.addSeriesRecording(seriesRecording); - List<Program> programs = new ArrayList<>(); - Program program1 = new Program.Builder(mBaseProgram).setSeasonNumber(SEASON_NUMBER1) - .setEpisodeNumber(EPISODE_NUMBER1).build(); - programs.add(program1); - Program program2 = new Program.Builder(mBaseProgram).setSeasonNumber(SEASON_NUMBER2) - .setEpisodeNumber(EPISODE_NUMBER2).build(); - programs.add(program2); - LongSparseArray<List<Program>> result = SeriesRecordingScheduler.pickOneProgramPerEpisode( - mDataManager, Collections.singletonList(seriesRecording), programs); - MoreAsserts.assertContentsInAnyOrder(result.get(SERIES_RECORDING_ID1), program1, program2); - } - - @Test - public void testPickOneProgramPerEpisode_manyPerEpisode() { - SeriesRecording seriesRecording = SeriesRecording.buildFrom(mBaseSeriesRecording) - .setId(SERIES_RECORDING_ID1).build(); - mDataManager.addSeriesRecording(seriesRecording); - List<Program> programs = new ArrayList<>(); - Program program1 = new Program.Builder(mBaseProgram).setSeasonNumber(SEASON_NUMBER1) - .setEpisodeNumber(EPISODE_NUMBER1).setStartTimeUtcMillis(0).build(); - programs.add(program1); - Program program2 = new Program.Builder(program1).setStartTimeUtcMillis(1).build(); - programs.add(program2); - Program program3 = new Program.Builder(mBaseProgram).setSeasonNumber(SEASON_NUMBER2) - .setEpisodeNumber(EPISODE_NUMBER2).build(); - programs.add(program3); - Program program4 = new Program.Builder(program1).setStartTimeUtcMillis(1).build(); - programs.add(program4); - LongSparseArray<List<Program>> result = SeriesRecordingScheduler.pickOneProgramPerEpisode( - mDataManager, Collections.singletonList(seriesRecording), programs); - MoreAsserts.assertContentsInAnyOrder(result.get(SERIES_RECORDING_ID1), program1, program3); - } - - @Test - public void testPickOneProgramPerEpisode_nullEpisode() { - SeriesRecording seriesRecording = SeriesRecording.buildFrom(mBaseSeriesRecording) - .setId(SERIES_RECORDING_ID1).build(); - mDataManager.addSeriesRecording(seriesRecording); - List<Program> programs = new ArrayList<>(); - Program program1 = new Program.Builder(mBaseProgram).setStartTimeUtcMillis(0).build(); - programs.add(program1); - Program program2 = new Program.Builder(mBaseProgram).setStartTimeUtcMillis(1).build(); - programs.add(program2); - LongSparseArray<List<Program>> result = SeriesRecordingScheduler.pickOneProgramPerEpisode( - mDataManager, Collections.singletonList(seriesRecording), programs); - MoreAsserts.assertContentsInAnyOrder(result.get(SERIES_RECORDING_ID1), program1, program2); - } -} diff --git a/tests/unit/src/com/android/tv/dvr/ui/SortedArrayAdapterTest.java b/tests/unit/src/com/android/tv/dvr/ui/SortedArrayAdapterTest.java deleted file mode 100644 index 5667ee6b..00000000 --- a/tests/unit/src/com/android/tv/dvr/ui/SortedArrayAdapterTest.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (C) 2016 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.dvr.ui; - -import android.support.test.filters.SmallTest; -import android.support.v17.leanback.widget.ClassPresenterSelector; -import android.support.v17.leanback.widget.ObjectAdapter; - -import junit.framework.TestCase; - -import org.junit.Before; -import org.junit.Test; - -import java.util.Arrays; -import java.util.Comparator; -import java.util.Objects; - -/** - * Tests for {@link SortedArrayAdapter}. - */ -@SmallTest -public class SortedArrayAdapterTest extends TestCase { - public static final TestData P1 = TestData.create(1, "c"); - public static final TestData P2 = TestData.create(2, "b"); - public static final TestData P3 = TestData.create(3, "a"); - public static final TestData EXTRA = TestData.create(4, "k"); - private TestSortedArrayAdapter mAdapter; - - @Before - public void setUp() { - mAdapter = new TestSortedArrayAdapter(Integer.MAX_VALUE, null); - } - - @Test - public void testContents_empty() { - assertEmpty(); - } - - @Test - public void testAdd_one() { - mAdapter.add(P1); - assertNotEmpty(); - assertContentsInOrder(mAdapter, P1); - } - - @Test - public void testAdd_two() { - mAdapter.add(P1); - mAdapter.add(P2); - assertNotEmpty(); - assertContentsInOrder(mAdapter, P2, P1); - } - - @Test - public void testSetInitialItems_two() { - mAdapter.setInitialItems(Arrays.asList(P1, P2)); - assertNotEmpty(); - assertContentsInOrder(mAdapter, P2, P1); - } - - @Test - public void testMaxInitialCount() { - mAdapter = new TestSortedArrayAdapter(1, null); - mAdapter.setInitialItems(Arrays.asList(P1, P2)); - assertNotEmpty(); - assertEquals(mAdapter.size(), 1); - assertEquals(mAdapter.get(0), P2); - } - - @Test - public void testExtraItem() { - mAdapter = new TestSortedArrayAdapter(Integer.MAX_VALUE, EXTRA); - mAdapter.setInitialItems(Arrays.asList(P1, P2)); - assertNotEmpty(); - assertEquals(mAdapter.size(), 3); - assertEquals(mAdapter.get(0), P2); - assertEquals(mAdapter.get(2), EXTRA); - mAdapter.remove(P2); - mAdapter.remove(P1); - assertEquals(mAdapter.size(), 1); - assertEquals(mAdapter.get(0), EXTRA); - } - - @Test - public void testExtraItemWithMaxCount() { - mAdapter = new TestSortedArrayAdapter(1, EXTRA); - mAdapter.setInitialItems(Arrays.asList(P1, P2)); - assertNotEmpty(); - assertEquals(mAdapter.size(), 2); - assertEquals(mAdapter.get(0), P2); - assertEquals(mAdapter.get(1), EXTRA); - mAdapter.remove(P2); - assertEquals(mAdapter.size(), 1); - assertEquals(mAdapter.get(0), EXTRA); - } - - @Test - public void testRemove() { - mAdapter.add(P1); - mAdapter.add(P2); - assertNotEmpty(); - assertContentsInOrder(mAdapter, P2, P1); - mAdapter.remove(P3); - assertContentsInOrder(mAdapter, P2, P1); - mAdapter.remove(P2); - assertContentsInOrder(mAdapter, P1); - mAdapter.remove(P1); - assertEmpty(); - mAdapter.add(P1); - mAdapter.add(P2); - mAdapter.add(P3); - assertContentsInOrder(mAdapter, P3, P2, P1); - mAdapter.removeItems(0, 2); - assertContentsInOrder(mAdapter, P1); - mAdapter.add(P2); - mAdapter.add(P3); - mAdapter.addExtraItem(EXTRA); - assertContentsInOrder(mAdapter, P3, P2, P1, EXTRA); - mAdapter.removeItems(1, 1); - assertContentsInOrder(mAdapter, P3, P1, EXTRA); - mAdapter.removeItems(1, 2); - assertContentsInOrder(mAdapter, P3); - mAdapter.addExtraItem(EXTRA); - mAdapter.addExtraItem(P2); - mAdapter.add(P1); - assertContentsInOrder(mAdapter, P3, P1, EXTRA, P2); - mAdapter.removeItems(1, 2); - assertContentsInOrder(mAdapter, P3, P2); - mAdapter.add(P1); - assertContentsInOrder(mAdapter, P3, P1, P2); - } - - @Test - public void testReplace() { - mAdapter.add(P1); - mAdapter.add(P2); - assertNotEmpty(); - assertContentsInOrder(mAdapter, P2, P1); - mAdapter.replace(1, P3); - assertContentsInOrder(mAdapter, P3, P2); - mAdapter.replace(0, P1); - assertContentsInOrder(mAdapter, P2, P1); - mAdapter.addExtraItem(EXTRA); - assertContentsInOrder(mAdapter, P2, P1, EXTRA); - mAdapter.replace(2, P3); - assertContentsInOrder(mAdapter, P2, P1, P3); - } - - @Test - public void testChange_sorting() { - TestData p2_changed = TestData.create(2, "z changed"); - mAdapter.add(P1); - mAdapter.add(P2); - assertNotEmpty(); - assertContentsInOrder(mAdapter, P2, P1); - mAdapter.change(p2_changed); - assertContentsInOrder(mAdapter, P1, p2_changed); - } - - @Test - public void testChange_new() { - mAdapter.change(P1); - assertNotEmpty(); - assertContentsInOrder(mAdapter, P1); - } - - private void assertEmpty() { - assertEquals("empty", true, mAdapter.isEmpty()); - } - - private void assertNotEmpty() { - assertEquals("empty", false, mAdapter.isEmpty()); - } - - private static void assertContentsInOrder(ObjectAdapter adapter, Object... contents) { - int ex = contents.length; - assertEquals("size", ex, adapter.size()); - for (int i = 0; i < ex; i++) { - assertEquals("element " + 1, contents[i], adapter.get(i)); - } - } - - private static class TestData { - @Override - public String toString() { - return "TestData[" + mId + "]{" + mText + '}'; - } - - static TestData create(long first, String text) { - return new TestData(first, text); - } - - private final long mId; - private final String mText; - - private TestData(long id, String second) { - this.mId = id; - this.mText = second; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof TestData)) return false; - TestData that = (TestData) o; - return mId == that.mId && Objects.equals(mText, that.mText); - } - - @Override - public int hashCode() { - return Objects.hash(mId, mText); - } - } - - private static class TestSortedArrayAdapter extends SortedArrayAdapter<TestData> { - - private static final Comparator<TestData> TEXT_COMPARATOR = new Comparator<TestData>() { - @Override - public int compare(TestData lhs, TestData rhs) { - return lhs.mText.compareTo(rhs.mText); - } - }; - - TestSortedArrayAdapter(int maxInitialCount, Object extra) { - super(new ClassPresenterSelector(), TEXT_COMPARATOR, maxInitialCount); - if (extra != null) { - addExtraItem((TestData) extra); - } - } - - @Override - protected long getId(TestData item) { - return item.mId; - } - } -}
\ No newline at end of file diff --git a/tests/unit/src/com/android/tv/experiments/ExperimentsTest.java b/tests/unit/src/com/android/tv/experiments/ExperimentsTest.java deleted file mode 100644 index 3f827ce1..00000000 --- a/tests/unit/src/com/android/tv/experiments/ExperimentsTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2016 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.experiments; - -import static org.junit.Assert.assertEquals; - -import android.support.test.filters.SmallTest; - -import com.android.tv.common.BuildConfig; - -import junit.framework.Assert; - -import org.junit.Before; -import org.junit.Test; - -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.List; - -/** - * Tests for {@link Experiments}. - */ -@SmallTest -public class ExperimentsTest { - @Before - public void setUp() { - ExperimentFlag.initForTest(); - } - - - @Test - public void testEngOnlyDefault() { - assertEquals("ENABLE_DEVELOPER_FEATURES", Boolean.valueOf(BuildConfig.ENG), - Experiments.ENABLE_DEVELOPER_FEATURES.get()); - } - - -} diff --git a/tests/unit/src/com/android/tv/menu/MenuTest.java b/tests/unit/src/com/android/tv/menu/MenuTest.java index e8cfdbef..028a185d 100644 --- a/tests/unit/src/com/android/tv/menu/MenuTest.java +++ b/tests/unit/src/com/android/tv/menu/MenuTest.java @@ -16,24 +16,23 @@ package com.android.tv.menu; import static android.support.test.InstrumentationRegistry.getTargetContext; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static com.google.common.truth.Truth.assertWithMessage; import android.support.test.filters.SmallTest; - +import android.support.test.runner.AndroidJUnit4; import com.android.tv.menu.Menu.OnMenuVisibilityChangeListener; - import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.Matchers; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; -/** - * Tests for {@link Menu}. - */ +/** Tests for {@link Menu}. */ @SmallTest +@RunWith(AndroidJUnit4.class) public class MenuTest { private Menu mMenu; private IMenuView mMenuView; @@ -50,26 +49,27 @@ public class MenuTest { mMenu.disableAnimationForTest(); } + @Ignore("b/73727914") @Test public void testScheduleHide() { mMenu.show(Menu.REASON_NONE); setMenuVisible(true); - assertTrue("Hide is not scheduled", mMenu.isHideScheduled()); + assertWithMessage("Hide is not scheduled").that(mMenu.isHideScheduled()).isTrue(); mMenu.hide(false); setMenuVisible(false); - assertFalse("Hide is scheduled", mMenu.isHideScheduled()); + assertWithMessage("Hide is scheduled").that(mMenu.isHideScheduled()).isFalse(); mMenu.setKeepVisible(true); mMenu.show(Menu.REASON_NONE); setMenuVisible(true); - assertFalse("Hide is scheduled", mMenu.isHideScheduled()); + assertWithMessage("Hide is scheduled").that(mMenu.isHideScheduled()).isFalse(); mMenu.setKeepVisible(false); - assertTrue("Hide is not scheduled", mMenu.isHideScheduled()); + assertWithMessage("Hide is not scheduled").that(mMenu.isHideScheduled()).isTrue(); mMenu.setKeepVisible(true); - assertFalse("Hide is scheduled", mMenu.isHideScheduled()); + assertWithMessage("Hide is scheduled").that(mMenu.isHideScheduled()).isFalse(); mMenu.hide(false); setMenuVisible(false); - assertFalse("Hide is scheduled", mMenu.isHideScheduled()); + assertWithMessage("Hide is scheduled").that(mMenu.isHideScheduled()).isFalse(); } @Test @@ -83,8 +83,11 @@ public class MenuTest { Mockito.verify(mVisibilityChangeListener, Mockito.never()) .onMenuVisibilityChange(Matchers.eq(false)); // IMenuView.show should be called with the same parameter. - Mockito.verify(mMenuView).onShow(Matchers.eq(Menu.REASON_NONE), - Matchers.isNull(String.class), Matchers.isNull(Runnable.class)); + Mockito.verify(mMenuView) + .onShow( + Matchers.eq(Menu.REASON_NONE), + Matchers.isNull(String.class), + Matchers.isNull(Runnable.class)); mMenu.hide(true); setMenuVisible(false); // Listener should be called with "false" argument. @@ -104,8 +107,11 @@ public class MenuTest { Mockito.verify(mVisibilityChangeListener, Mockito.never()) .onMenuVisibilityChange(Matchers.eq(false)); // IMenuView.show should be called with the same parameter. - Mockito.verify(mMenuView).onShow(Matchers.eq(Menu.REASON_GUIDE), - Matchers.eq(ChannelsRow.ID), Matchers.isNull(Runnable.class)); + Mockito.verify(mMenuView) + .onShow( + Matchers.eq(Menu.REASON_GUIDE), + Matchers.eq(ChannelsRow.ID), + Matchers.isNull(Runnable.class)); mMenu.hide(false); setMenuVisible(false); // Listener should be called with "false" argument. @@ -125,8 +131,11 @@ public class MenuTest { Mockito.verify(mVisibilityChangeListener, Mockito.never()) .onMenuVisibilityChange(Matchers.eq(false)); // IMenuView.show should be called with the same parameter. - Mockito.verify(mMenuView).onShow(Matchers.eq(Menu.REASON_PLAY_CONTROLS_FAST_FORWARD), - Matchers.eq(PlayControlsRow.ID), Matchers.isNull(Runnable.class)); + Mockito.verify(mMenuView) + .onShow( + Matchers.eq(Menu.REASON_PLAY_CONTROLS_FAST_FORWARD), + Matchers.eq(PlayControlsRow.ID), + Matchers.isNull(Runnable.class)); mMenu.hide(false); setMenuVisible(false); // Listener should be called with "false" argument. @@ -136,11 +145,13 @@ public class MenuTest { } private void setMenuVisible(final boolean visible) { - Mockito.when(mMenuView.isVisible()).thenAnswer(new Answer<Boolean>() { - @Override - public Boolean answer(InvocationOnMock invocation) throws Throwable { - return visible; - } - }); + Mockito.when(mMenuView.isVisible()) + .thenAnswer( + new Answer<Boolean>() { + @Override + public Boolean answer(InvocationOnMock invocation) throws Throwable { + return visible; + } + }); } } diff --git a/tests/unit/src/com/android/tv/menu/TvOptionsRowAdapterTest.java b/tests/unit/src/com/android/tv/menu/TvOptionsRowAdapterTest.java index 49ba8514..0f815a7a 100644 --- a/tests/unit/src/com/android/tv/menu/TvOptionsRowAdapterTest.java +++ b/tests/unit/src/com/android/tv/menu/TvOptionsRowAdapterTest.java @@ -16,30 +16,28 @@ package com.android.tv.menu; import static android.support.test.InstrumentationRegistry.getInstrumentation; -import static org.junit.Assert.assertEquals; +import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.fail; import android.media.tv.TvTrackInfo; import android.os.SystemClock; import android.support.test.filters.MediumTest; +import android.support.test.runner.AndroidJUnit4; import android.text.TextUtils; - -import com.android.tv.BaseMainActivityTestCase; -import com.android.tv.testing.Constants; +import com.android.tv.testing.activities.BaseMainActivityTestCase; +import com.android.tv.testing.constants.Constants; import com.android.tv.testing.testinput.ChannelState; import com.android.tv.testing.testinput.ChannelStateData; import com.android.tv.testing.testinput.TvTestInputConstants; - -import org.junit.Before; -import org.junit.Test; - import java.util.Collections; import java.util.List; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; -/** - * Tests for {@link TvOptionsRowAdapter}. - */ +/** Tests for {@link TvOptionsRowAdapter}. */ @MediumTest +@RunWith(AndroidJUnit4.class) public class TvOptionsRowAdapterTest extends BaseMainActivityTestCase { private static final int WAIT_TRACK_EVENT_TIMEOUT_MS = 300; public static final int TRACK_CHECK_INTERVAL_MS = 10; @@ -56,12 +54,14 @@ public class TvOptionsRowAdapterTest extends BaseMainActivityTestCase { waitUntilAudioTracksHaveSize(1); waitUntilAudioTrackSelected(ChannelState.DEFAULT.getSelectedAudioTrackId()); // update should be called on the main thread to avoid the multi-thread problem. - getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - mTvOptionsRowAdapter.update(); - } - }); + getInstrumentation() + .runOnMainSync( + new Runnable() { + @Override + public void run() { + mTvOptionsRowAdapter.update(); + } + }); } @Test @@ -73,9 +73,10 @@ public class TvOptionsRowAdapterTest extends BaseMainActivityTestCase { waitUntilAudioTrackSelected(Constants.EN_STEREO_AUDIO_TRACK.getId()); boolean result = mTvOptionsRowAdapter.updateMultiAudioAction(); - assertEquals("update Action had change", true, result); - assertEquals("Multi Audio enabled", true, - MenuAction.SELECT_AUDIO_LANGUAGE_ACTION.isEnabled()); + assertWithMessage("update Action had change").that(result).isTrue(); + assertWithMessage("Multi Audio enabled") + .that(MenuAction.SELECT_AUDIO_LANGUAGE_ACTION.isEnabled()) + .isTrue(); } @Test @@ -90,9 +91,10 @@ public class TvOptionsRowAdapterTest extends BaseMainActivityTestCase { waitUntilAudioTrackSelected(Constants.GENERIC_AUDIO_TRACK.getId()); boolean result = mTvOptionsRowAdapter.updateMultiAudioAction(); - assertEquals("update Action had change", true, result); - assertEquals("Multi Audio enabled", false, - MenuAction.SELECT_AUDIO_LANGUAGE_ACTION.isEnabled()); + assertWithMessage("update Action had change").that(result).isTrue(); + assertWithMessage("Multi Audio enabled") + .that(MenuAction.SELECT_AUDIO_LANGUAGE_ACTION.isEnabled()) + .isFalse(); } @Test @@ -108,9 +110,10 @@ public class TvOptionsRowAdapterTest extends BaseMainActivityTestCase { waitUntilVideoTrackSelected(data.mSelectedVideoTrackId); boolean result = mTvOptionsRowAdapter.updateMultiAudioAction(); - assertEquals("update Action had change", true, result); - assertEquals("Multi Audio enabled", false, - MenuAction.SELECT_AUDIO_LANGUAGE_ACTION.isEnabled()); + assertWithMessage("update Action had change").that(result).isTrue(); + assertWithMessage("Multi Audio enabled") + .that(MenuAction.SELECT_AUDIO_LANGUAGE_ACTION.isEnabled()) + .isFalse(); } private void waitUntilAudioTracksHaveSize(int expected) { @@ -135,8 +138,13 @@ public class TvOptionsRowAdapterTest extends BaseMainActivityTestCase { } SystemClock.sleep(TRACK_CHECK_INTERVAL_MS); } - fail("Waited for " + WAIT_TRACK_EVENT_TIMEOUT_MS + " milliseconds for track size to be " - + expected + " but was " + size); + fail( + "Waited for " + + WAIT_TRACK_EVENT_TIMEOUT_MS + + " milliseconds for track size to be " + + expected + + " but was " + + size); } private void waitUntilAudioTrackSelected(String trackId) { @@ -158,7 +166,12 @@ public class TvOptionsRowAdapterTest extends BaseMainActivityTestCase { } SystemClock.sleep(TRACK_CHECK_INTERVAL_MS); } - fail("Waited for " + WAIT_TRACK_EVENT_TIMEOUT_MS + " milliseconds for track ID to be " - + trackId + " but was " + selectedTrackId); + fail( + "Waited for " + + WAIT_TRACK_EVENT_TIMEOUT_MS + + " milliseconds for track ID to be " + + trackId + + " but was " + + selectedTrackId); } } diff --git a/tests/unit/src/com/android/tv/recommendation/ChannelRecordTest.java b/tests/unit/src/com/android/tv/recommendation/ChannelRecordTest.java index db765109..e63bdc3a 100644 --- a/tests/unit/src/com/android/tv/recommendation/ChannelRecordTest.java +++ b/tests/unit/src/com/android/tv/recommendation/ChannelRecordTest.java @@ -17,22 +17,20 @@ package com.android.tv.recommendation; import static android.support.test.InstrumentationRegistry.getContext; -import static org.junit.Assert.assertEquals; +import static com.google.common.truth.Truth.assertThat; import android.support.test.filters.SmallTest; - -import com.android.tv.testing.Utils; - -import org.junit.Before; -import org.junit.Test; - +import android.support.test.runner.AndroidJUnit4; +import com.android.tv.testing.utils.Utils; import java.util.Random; import java.util.concurrent.TimeUnit; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; -/** - * Unit tests for {@link ChannelRecord}. - */ +/** Unit tests for {@link ChannelRecord}. */ @SmallTest +@RunWith(AndroidJUnit4.class) public class ChannelRecordTest { private static final int CHANNEL_RECORD_MAX_HISTORY_SIZE = ChannelRecord.MAX_HISTORY_SIZE; @@ -49,14 +47,14 @@ public class ChannelRecordTest { @Test public void testGetLastWatchEndTime_noHistory() { - assertEquals(0, mChannelRecord.getLastWatchEndTimeMs()); + assertThat(mChannelRecord.getLastWatchEndTimeMs()).isEqualTo(0); } @Test public void testGetLastWatchEndTime_oneHistory() { addWatchLog(); - assertEquals(mLatestWatchEndTimeMs, mChannelRecord.getLastWatchEndTimeMs()); + assertThat(mChannelRecord.getLastWatchEndTimeMs()).isEqualTo(mLatestWatchEndTimeMs); } @Test @@ -65,7 +63,7 @@ public class ChannelRecordTest { addWatchLog(); } - assertEquals(mLatestWatchEndTimeMs, mChannelRecord.getLastWatchEndTimeMs()); + assertThat(mChannelRecord.getLastWatchEndTimeMs()).isEqualTo(mLatestWatchEndTimeMs); } @Test @@ -74,19 +72,19 @@ public class ChannelRecordTest { addWatchLog(); } - assertEquals(mLatestWatchEndTimeMs, mChannelRecord.getLastWatchEndTimeMs()); + assertThat(mChannelRecord.getLastWatchEndTimeMs()).isEqualTo(mLatestWatchEndTimeMs); } @Test public void testGetTotalWatchDuration_noHistory() { - assertEquals(0, mChannelRecord.getTotalWatchDurationMs()); + assertThat(mChannelRecord.getTotalWatchDurationMs()).isEqualTo(0); } @Test public void testGetTotalWatchDuration_oneHistory() { long durationMs = addWatchLog(); - assertEquals(durationMs, mChannelRecord.getTotalWatchDurationMs()); + assertThat(mChannelRecord.getTotalWatchDurationMs()).isEqualTo(durationMs); } @Test @@ -97,7 +95,7 @@ public class ChannelRecordTest { totalWatchTimeMs += durationMs; } - assertEquals(totalWatchTimeMs, mChannelRecord.getTotalWatchDurationMs()); + assertThat(mChannelRecord.getTotalWatchDurationMs()).isEqualTo(totalWatchTimeMs); } @Test @@ -112,8 +110,9 @@ public class ChannelRecordTest { } } - // Only latest CHANNEL_RECORD_MAX_HISTORY_SIZE logs are remained. - assertEquals(totalWatchTimeMs - firstDurationMs, mChannelRecord.getTotalWatchDurationMs()); + // Only latest CHANNEL_RECORD_MAX_HISTORY_SIZE logs are remained. + assertThat(mChannelRecord.getTotalWatchDurationMs()) + .isEqualTo(totalWatchTimeMs - firstDurationMs); } /** @@ -126,8 +125,9 @@ public class ChannelRecordTest { mLatestWatchEndTimeMs += TimeUnit.SECONDS.toMillis(mRandom.nextInt(60) + 1); long durationMs = TimeUnit.SECONDS.toMillis(mRandom.nextInt(60) + 1); - mChannelRecord.logWatchHistory(new WatchedProgram(null, - mLatestWatchEndTimeMs, mLatestWatchEndTimeMs + durationMs)); + mChannelRecord.logWatchHistory( + new WatchedProgram( + null, mLatestWatchEndTimeMs, mLatestWatchEndTimeMs + durationMs)); mLatestWatchEndTimeMs += durationMs; return durationMs; diff --git a/tests/unit/src/com/android/tv/recommendation/EvaluatorTestCase.java b/tests/unit/src/com/android/tv/recommendation/EvaluatorTestCase.java index 853fb245..f62a5e05 100644 --- a/tests/unit/src/com/android/tv/recommendation/EvaluatorTestCase.java +++ b/tests/unit/src/com/android/tv/recommendation/EvaluatorTestCase.java @@ -20,19 +20,15 @@ import static android.support.test.InstrumentationRegistry.getContext; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import com.android.tv.data.Channel; +import com.android.tv.data.api.Channel; import com.android.tv.recommendation.RecommendationUtils.ChannelRecordSortedMapHelper; import com.android.tv.recommendation.Recommender.Evaluator; -import com.android.tv.testing.Utils; - -import org.junit.Before; - +import com.android.tv.testing.utils.Utils; import java.util.ArrayList; import java.util.List; +import org.junit.Before; -/** - * Base test case for Recommendation Evaluator Unit tests. - */ +/** Base test case for Recommendation Evaluator Unit tests. */ public abstract class EvaluatorTestCase<T extends Evaluator> { private static final long INVALID_CHANNEL_ID = -1; @@ -46,8 +42,8 @@ public abstract class EvaluatorTestCase<T extends Evaluator> { @Before public void setUp() { mChannelRecordSortedMap = new ChannelRecordSortedMapHelper(getContext()); - mDataManager = RecommendationUtils - .createMockRecommendationDataManager(mChannelRecordSortedMap); + mDataManager = + RecommendationUtils.createMockRecommendationDataManager(mChannelRecordSortedMap); Recommender mRecommender = new FakeRecommender(); mEvaluator = createEvaluator(); mEvaluator.setRecommender(mRecommender); @@ -55,9 +51,7 @@ public abstract class EvaluatorTestCase<T extends Evaluator> { mChannelRecordSortedMap.resetRandom(Utils.createTestRandom()); } - /** - * Each evaluator test has to create Evaluator in {@code mEvaluator}. - */ + /** Each evaluator test has to create Evaluator in {@code mEvaluator}. */ public abstract T createEvaluator(); public void addChannels(int numberOfChannels) { @@ -68,15 +62,16 @@ public abstract class EvaluatorTestCase<T extends Evaluator> { return mChannelRecordSortedMap.addChannel(); } - public void addRandomWatchLogs(long watchStartTimeMs, long watchEndTimeMs, - long maxWatchDurationMs) { - assertTrue(mChannelRecordSortedMap.addRandomWatchLogs(watchStartTimeMs, watchEndTimeMs, - maxWatchDurationMs)); + public void addRandomWatchLogs( + long watchStartTimeMs, long watchEndTimeMs, long maxWatchDurationMs) { + assertTrue( + mChannelRecordSortedMap.addRandomWatchLogs( + watchStartTimeMs, watchEndTimeMs, maxWatchDurationMs)); } public void addWatchLog(long channelId, long watchStartTimeMs, long durationTimeMs) { - assertTrue(mChannelRecordSortedMap.addWatchLog(channelId, watchStartTimeMs, - durationTimeMs)); + assertTrue( + mChannelRecordSortedMap.addWatchLog(channelId, watchStartTimeMs, durationTimeMs)); } public List<Long> getChannelIdListSorted() { @@ -86,31 +81,29 @@ public abstract class EvaluatorTestCase<T extends Evaluator> { public long getLatestWatchEndTimeMs() { long latestWatchEndTimeMs = 0; for (ChannelRecord channelRecord : mChannelRecordSortedMap.values()) { - latestWatchEndTimeMs = Math.max(latestWatchEndTimeMs, - channelRecord.getLastWatchEndTimeMs()); + latestWatchEndTimeMs = + Math.max(latestWatchEndTimeMs, channelRecord.getLastWatchEndTimeMs()); } return latestWatchEndTimeMs; } - /** - * Check whether scores of each channels are valid. - */ + /** Check whether scores of each channels are valid. */ protected void assertChannelScoresValid() { - assertEqualScores(Evaluator.NOT_RECOMMENDED, - mEvaluator.evaluateChannel(INVALID_CHANNEL_ID)); - assertEqualScores(Evaluator.NOT_RECOMMENDED, + assertEqualScores( + Evaluator.NOT_RECOMMENDED, mEvaluator.evaluateChannel(INVALID_CHANNEL_ID)); + assertEqualScores( + Evaluator.NOT_RECOMMENDED, mEvaluator.evaluateChannel(mChannelRecordSortedMap.size())); for (long channelId : mChannelRecordSortedMap.keySet()) { double score = mEvaluator.evaluateChannel(channelId); - assertTrue("Channel " + channelId + " score of " + score + "is not valid", + assertTrue( + "Channel " + channelId + " score of " + score + "is not valid", score == Evaluator.NOT_RECOMMENDED || (0.0 <= score && score <= 1.0)); } } - /** - * Notify that loading channels and watch logs are finished. - */ + /** Notify that loading channels and watch logs are finished. */ protected void notifyChannelAndWatchLogLoaded() { mEvaluator.onChannelRecordListChanged(new ArrayList<>(mChannelRecordSortedMap.values())); } @@ -125,15 +118,16 @@ public abstract class EvaluatorTestCase<T extends Evaluator> { private class FakeRecommender extends Recommender { public FakeRecommender() { - super(new Recommender.Listener() { - @Override - public void onRecommenderReady() { - } - - @Override - public void onRecommendationChanged() { - } - }, true, mDataManager); + super( + new Recommender.Listener() { + @Override + public void onRecommenderReady() {} + + @Override + public void onRecommendationChanged() {} + }, + true, + mDataManager); } @Override diff --git a/tests/unit/src/com/android/tv/recommendation/FavoriteChannelEvaluatorTest.java b/tests/unit/src/com/android/tv/recommendation/FavoriteChannelEvaluatorTest.java index ac701af9..e14320f0 100644 --- a/tests/unit/src/com/android/tv/recommendation/FavoriteChannelEvaluatorTest.java +++ b/tests/unit/src/com/android/tv/recommendation/FavoriteChannelEvaluatorTest.java @@ -16,19 +16,18 @@ package com.android.tv.recommendation; -import static org.junit.Assert.assertTrue; +import static com.google.common.truth.Truth.assertThat; import android.support.test.filters.SmallTest; - -import org.junit.Test; - +import android.support.test.runner.AndroidJUnit4; import java.util.List; import java.util.concurrent.TimeUnit; +import org.junit.Test; +import org.junit.runner.RunWith; -/** - * Unit tests for {@link FavoriteChannelEvaluator}. - */ +/** Unit tests for {@link FavoriteChannelEvaluator}. */ @SmallTest +@RunWith(AndroidJUnit4.class) public class FavoriteChannelEvaluatorTest extends EvaluatorTestCase<FavoriteChannelEvaluator> { private static final int DEFAULT_NUMBER_OF_CHANNELS = 4; private static final long DEFAULT_WATCH_START_TIME_MS = @@ -47,14 +46,16 @@ public class FavoriteChannelEvaluatorTest extends EvaluatorTestCase<FavoriteChan long channelId = addChannel().getId(); notifyChannelAndWatchLogLoaded(); - assertEqualScores(Recommender.Evaluator.NOT_RECOMMENDED, - mEvaluator.evaluateChannel(channelId)); + assertEqualScores( + Recommender.Evaluator.NOT_RECOMMENDED, mEvaluator.evaluateChannel(channelId)); } @Test public void testOneChannelWithRandomWatchLogs() { addChannel(); - addRandomWatchLogs(DEFAULT_WATCH_START_TIME_MS, DEFAULT_WATCH_END_TIME_MS, + addRandomWatchLogs( + DEFAULT_WATCH_START_TIME_MS, + DEFAULT_WATCH_END_TIME_MS, DEFAULT_MAX_WATCH_DURATION_MS); notifyChannelAndWatchLogLoaded(); @@ -68,15 +69,17 @@ public class FavoriteChannelEvaluatorTest extends EvaluatorTestCase<FavoriteChan List<Long> channelIdList = getChannelIdListSorted(); for (long channelId : channelIdList) { - assertEqualScores(Recommender.Evaluator.NOT_RECOMMENDED, - mEvaluator.evaluateChannel(channelId)); + assertEqualScores( + Recommender.Evaluator.NOT_RECOMMENDED, mEvaluator.evaluateChannel(channelId)); } } @Test public void testMultiChannelsWithRandomWatchLogs() { addChannels(DEFAULT_NUMBER_OF_CHANNELS); - addRandomWatchLogs(DEFAULT_WATCH_START_TIME_MS, DEFAULT_WATCH_END_TIME_MS, + addRandomWatchLogs( + DEFAULT_WATCH_START_TIME_MS, + DEFAULT_WATCH_END_TIME_MS, DEFAULT_MAX_WATCH_DURATION_MS); notifyChannelAndWatchLogLoaded(); @@ -103,7 +106,7 @@ public class FavoriteChannelEvaluatorTest extends EvaluatorTestCase<FavoriteChan double previousScore = Recommender.Evaluator.NOT_RECOMMENDED; for (long channelId : channelIdList) { double score = mEvaluator.evaluateChannel(channelId); - assertTrue(previousScore <= score); + assertThat(previousScore).isAtMost(score); previousScore = score; } } @@ -112,40 +115,54 @@ public class FavoriteChannelEvaluatorTest extends EvaluatorTestCase<FavoriteChan public void testTwoChannelsWithSameWatchDuration() { long channelOne = addChannel().getId(); long channelTwo = addChannel().getId(); - addWatchLog(channelOne, System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1), + addWatchLog( + channelOne, + System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1), TimeUnit.MINUTES.toMillis(30)); - addWatchLog(channelTwo, System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(30), + addWatchLog( + channelTwo, + System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(30), TimeUnit.MINUTES.toMillis(30)); notifyChannelAndWatchLogLoaded(); - assertTrue(mEvaluator.evaluateChannel(channelOne) == - mEvaluator.evaluateChannel(channelTwo)); + assertThat(mEvaluator.evaluateChannel(channelOne) == mEvaluator.evaluateChannel(channelTwo)) + .isTrue(); } @Test public void testTwoChannelsWithDifferentWatchDuration() { long channelOne = addChannel().getId(); long channelTwo = addChannel().getId(); - addWatchLog(channelOne, System.currentTimeMillis() - TimeUnit.HOURS.toMillis(3), + addWatchLog( + channelOne, + System.currentTimeMillis() - TimeUnit.HOURS.toMillis(3), TimeUnit.MINUTES.toMillis(30)); - addWatchLog(channelTwo, System.currentTimeMillis() - TimeUnit.HOURS.toMillis(2), + addWatchLog( + channelTwo, + System.currentTimeMillis() - TimeUnit.HOURS.toMillis(2), TimeUnit.HOURS.toMillis(1)); notifyChannelAndWatchLogLoaded(); - // Channel two was watched longer than channel one, so it's score is bigger. - assertTrue(mEvaluator.evaluateChannel(channelOne) < mEvaluator.evaluateChannel(channelTwo)); + // Channel two was watched longer than channel one, so it's score is bigger. + assertThat(mEvaluator.evaluateChannel(channelOne)) + .isLessThan(mEvaluator.evaluateChannel(channelTwo)); - addWatchLog(channelOne, System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1), + addWatchLog( + channelOne, + System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1), TimeUnit.HOURS.toMillis(1)); - // Now, channel one was watched longer than channel two, so it's score is bigger. - assertTrue(mEvaluator.evaluateChannel(channelOne) > mEvaluator.evaluateChannel(channelTwo)); + // Now, channel one was watched longer than channel two, so it's score is bigger. + assertThat(mEvaluator.evaluateChannel(channelOne)) + .isGreaterThan(mEvaluator.evaluateChannel(channelTwo)); } @Test public void testScoreIncreasesWithNewWatchLog() { long channelId = addChannel().getId(); - addRandomWatchLogs(DEFAULT_WATCH_START_TIME_MS, DEFAULT_WATCH_END_TIME_MS, + addRandomWatchLogs( + DEFAULT_WATCH_START_TIME_MS, + DEFAULT_WATCH_END_TIME_MS, DEFAULT_MAX_WATCH_DURATION_MS); notifyChannelAndWatchLogLoaded(); @@ -154,7 +171,7 @@ public class FavoriteChannelEvaluatorTest extends EvaluatorTestCase<FavoriteChan addWatchLog(channelId, latestWatchEndTimeMs, TimeUnit.MINUTES.toMillis(10)); - // Score must be increased because total watch duration of the channel increases. - assertTrue(previousScore <= mEvaluator.evaluateChannel(channelId)); + // Score must be increased because total watch duration of the channel increases. + assertThat(previousScore).isAtMost(mEvaluator.evaluateChannel(channelId)); } } diff --git a/tests/unit/src/com/android/tv/recommendation/RecentChannelEvaluatorTest.java b/tests/unit/src/com/android/tv/recommendation/RecentChannelEvaluatorTest.java index 8f092238..f8d6b220 100644 --- a/tests/unit/src/com/android/tv/recommendation/RecentChannelEvaluatorTest.java +++ b/tests/unit/src/com/android/tv/recommendation/RecentChannelEvaluatorTest.java @@ -16,21 +16,20 @@ package com.android.tv.recommendation; -import static org.junit.Assert.assertTrue; +import static com.google.common.truth.Truth.assertThat; import android.support.test.filters.SmallTest; - -import org.junit.Test; - +import android.support.test.runner.AndroidJUnit4; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; +import org.junit.Test; +import org.junit.runner.RunWith; -/** - * Unit tests for {@link RecentChannelEvaluator}. - */ +/** Unit tests for {@link RecentChannelEvaluator}. */ @SmallTest +@RunWith(AndroidJUnit4.class) public class RecentChannelEvaluatorTest extends EvaluatorTestCase<RecentChannelEvaluator> { private static final int DEFAULT_NUMBER_OF_CHANNELS = 4; private static final long DEFAULT_WATCH_START_TIME_MS = @@ -49,14 +48,16 @@ public class RecentChannelEvaluatorTest extends EvaluatorTestCase<RecentChannelE long channelId = addChannel().getId(); notifyChannelAndWatchLogLoaded(); - assertEqualScores(Recommender.Evaluator.NOT_RECOMMENDED, - mEvaluator.evaluateChannel(channelId)); + assertEqualScores( + Recommender.Evaluator.NOT_RECOMMENDED, mEvaluator.evaluateChannel(channelId)); } @Test public void testOneChannelWithRandomWatchLogs() { addChannel(); - addRandomWatchLogs(DEFAULT_WATCH_START_TIME_MS, DEFAULT_WATCH_END_TIME_MS, + addRandomWatchLogs( + DEFAULT_WATCH_START_TIME_MS, + DEFAULT_WATCH_END_TIME_MS, DEFAULT_MAX_WATCH_DURATION_MS); notifyChannelAndWatchLogLoaded(); @@ -70,15 +71,17 @@ public class RecentChannelEvaluatorTest extends EvaluatorTestCase<RecentChannelE List<Long> channelIdList = getChannelIdListSorted(); for (long channelId : channelIdList) { - assertEqualScores(Recommender.Evaluator.NOT_RECOMMENDED, - mEvaluator.evaluateChannel(channelId)); + assertEqualScores( + Recommender.Evaluator.NOT_RECOMMENDED, mEvaluator.evaluateChannel(channelId)); } } @Test public void testMultiChannelsWithRandomWatchLogs() { addChannels(DEFAULT_NUMBER_OF_CHANNELS); - addRandomWatchLogs(DEFAULT_WATCH_START_TIME_MS, DEFAULT_WATCH_END_TIME_MS, + addRandomWatchLogs( + DEFAULT_WATCH_START_TIME_MS, + DEFAULT_WATCH_END_TIME_MS, DEFAULT_MAX_WATCH_DURATION_MS); notifyChannelAndWatchLogLoaded(); @@ -103,7 +106,7 @@ public class RecentChannelEvaluatorTest extends EvaluatorTestCase<RecentChannelE double previousScore = Recommender.Evaluator.NOT_RECOMMENDED; for (long channelId : channelIdList) { double score = mEvaluator.evaluateChannel(channelId); - assertTrue(previousScore <= score); + assertThat(previousScore).isAtMost(score); previousScore = score; } } @@ -111,7 +114,9 @@ public class RecentChannelEvaluatorTest extends EvaluatorTestCase<RecentChannelE @Test public void testScoreIncreasesWithNewWatchLog() { addChannels(DEFAULT_NUMBER_OF_CHANNELS); - addRandomWatchLogs(DEFAULT_WATCH_START_TIME_MS, DEFAULT_WATCH_END_TIME_MS, + addRandomWatchLogs( + DEFAULT_WATCH_START_TIME_MS, + DEFAULT_WATCH_END_TIME_MS, DEFAULT_MAX_WATCH_DURATION_MS); notifyChannelAndWatchLogLoaded(); @@ -124,15 +129,17 @@ public class RecentChannelEvaluatorTest extends EvaluatorTestCase<RecentChannelE addWatchLog(channelId, latestWatchEndTimeMs, durationMs); latestWatchEndTimeMs += durationMs; - // Score must be increased because recentness of the log increases. - assertTrue(previousScore <= mEvaluator.evaluateChannel(channelId)); + // Score must be increased because recentness of the log increases. + assertThat(previousScore).isAtMost(mEvaluator.evaluateChannel(channelId)); } } @Test public void testScoreDecreasesWithIncrementOfWatchedLogUpdatedTime() { addChannels(DEFAULT_NUMBER_OF_CHANNELS); - addRandomWatchLogs(DEFAULT_WATCH_START_TIME_MS, DEFAULT_WATCH_END_TIME_MS, + addRandomWatchLogs( + DEFAULT_WATCH_START_TIME_MS, + DEFAULT_WATCH_END_TIME_MS, DEFAULT_MAX_WATCH_DURATION_MS); notifyChannelAndWatchLogLoaded(); @@ -148,8 +155,8 @@ public class RecentChannelEvaluatorTest extends EvaluatorTestCase<RecentChannelE addWatchLog(newChannelId, latestWatchedEndTimeMs, TimeUnit.MINUTES.toMillis(10)); for (long channelId : channelIdList) { - // Score must be decreased because LastWatchLogUpdateTime increases by new log. - assertTrue(mEvaluator.evaluateChannel(channelId) <= scores.get(channelId)); + // Score must be decreased because LastWatchLogUpdateTime increases by new log. + assertThat(mEvaluator.evaluateChannel(channelId)).isAtMost(scores.get(channelId)); } } } diff --git a/tests/unit/src/com/android/tv/recommendation/RecommendationUtils.java b/tests/unit/src/com/android/tv/recommendation/RecommendationUtils.java index b00ed16b..b929a0ae 100644 --- a/tests/unit/src/com/android/tv/recommendation/RecommendationUtils.java +++ b/tests/unit/src/com/android/tv/recommendation/RecommendationUtils.java @@ -17,50 +17,57 @@ package com.android.tv.recommendation; import android.content.Context; - -import com.android.tv.data.Channel; -import com.android.tv.testing.Utils; - -import org.mockito.Matchers; -import org.mockito.Mockito; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - +import com.android.tv.data.ChannelImpl; +import com.android.tv.data.api.Channel; +import com.android.tv.testing.utils.Utils; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Random; import java.util.TreeMap; import java.util.concurrent.TimeUnit; +import org.mockito.Matchers; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; public class RecommendationUtils { private static final long INVALID_CHANNEL_ID = -1; - /** - * Create a mock RecommendationDataManager backed by a {@link ChannelRecordSortedMapHelper}. - */ + /** Create a mock RecommendationDataManager backed by a {@link ChannelRecordSortedMapHelper}. */ public static RecommendationDataManager createMockRecommendationDataManager( final ChannelRecordSortedMapHelper channelRecordSortedMap) { RecommendationDataManager dataManager = Mockito.mock(RecommendationDataManager.class); - Mockito.doAnswer(new Answer<Integer>() { - @Override - public Integer answer(InvocationOnMock invocation) throws Throwable { - return channelRecordSortedMap.size(); - } - }).when(dataManager).getChannelRecordCount(); - Mockito.doAnswer(new Answer<Collection<ChannelRecord>>() { - @Override - public Collection<ChannelRecord> answer(InvocationOnMock invocation) throws Throwable { - return channelRecordSortedMap.values(); - } - }).when(dataManager).getChannelRecords(); - Mockito.doAnswer(new Answer<ChannelRecord>() { - @Override - public ChannelRecord answer(InvocationOnMock invocation) throws Throwable { - long channelId = (long) invocation.getArguments()[0]; - return channelRecordSortedMap.get(channelId); - } - }).when(dataManager).getChannelRecord(Matchers.anyLong()); + Mockito.doAnswer( + new Answer<Integer>() { + @Override + public Integer answer(InvocationOnMock invocation) throws Throwable { + return channelRecordSortedMap.size(); + } + }) + .when(dataManager) + .getChannelRecordCount(); + Mockito.doAnswer( + new Answer<Collection<ChannelRecord>>() { + @Override + public Collection<ChannelRecord> answer(InvocationOnMock invocation) + throws Throwable { + return channelRecordSortedMap.values(); + } + }) + .when(dataManager) + .getChannelRecords(); + Mockito.doAnswer( + new Answer<ChannelRecord>() { + @Override + public ChannelRecord answer(InvocationOnMock invocation) + throws Throwable { + long channelId = (long) invocation.getArguments()[0]; + return channelRecordSortedMap.get(channelId); + } + }) + .when(dataManager) + .getChannelRecord(Matchers.anyLong()); return dataManager; } @@ -82,9 +89,9 @@ public class RecommendationUtils { } /** - * Add new {@code numberOfChannels} channels by adding channel record to - * {@code channelRecordMap} with no history. - * This action corresponds to loading channels in the RecommendationDataManger. + * Add new {@code numberOfChannels} channels by adding channel record to {@code + * channelRecordMap} with no history. This action corresponds to loading channels in the + * RecommendationDataManger. */ public void addChannels(int numberOfChannels) { for (int i = 0; i < numberOfChannels; ++i) { @@ -100,21 +107,21 @@ public class RecommendationUtils { */ public Channel addChannel() { long channelId = size(); - Channel channel = new Channel.Builder().setId(channelId).build(); + ChannelImpl channel = new ChannelImpl.Builder().setId(channelId).build(); ChannelRecord channelRecord = new ChannelRecord(mContext, channel, false); put(channelId, channelRecord); return channel; } /** - * Add the watch logs which its durationTime is under {@code maxWatchDurationMs}. - * Add until latest watch end time becomes bigger than {@code watchEndTimeMs}, - * starting from {@code watchStartTimeMs}. + * Add the watch logs which its durationTime is under {@code maxWatchDurationMs}. Add until + * latest watch end time becomes bigger than {@code watchEndTimeMs}, starting from {@code + * watchStartTimeMs}. * * @return true if adding watch log success, otherwise false. */ - public boolean addRandomWatchLogs(long watchStartTimeMs, long watchEndTimeMs, - long maxWatchDurationMs) { + public boolean addRandomWatchLogs( + long watchStartTimeMs, long watchEndTimeMs, long maxWatchDurationMs) { long latestWatchEndTimeMs = watchStartTimeMs; long previousChannelId = INVALID_CHANNEL_ID; List<Long> channelIdList = new ArrayList<>(keySet()); @@ -143,13 +150,13 @@ public class RecommendationUtils { */ public boolean addWatchLog(long channelId, long watchStartTimeMs, long durationTimeMs) { ChannelRecord channelRecord = get(channelId); - if (channelRecord == null || - watchStartTimeMs + durationTimeMs > System.currentTimeMillis()) { + if (channelRecord == null + || watchStartTimeMs + durationTimeMs > System.currentTimeMillis()) { return false; } - channelRecord.logWatchHistory(new WatchedProgram(null, watchStartTimeMs, - watchStartTimeMs + durationTimeMs)); + channelRecord.logWatchHistory( + new WatchedProgram(null, watchStartTimeMs, watchStartTimeMs + durationTimeMs)); if (mRecommender != null) { mRecommender.onNewWatchLog(channelRecord); } diff --git a/tests/unit/src/com/android/tv/recommendation/RecommenderTest.java b/tests/unit/src/com/android/tv/recommendation/RecommenderTest.java index 85524a82..812a3eb1 100644 --- a/tests/unit/src/com/android/tv/recommendation/RecommenderTest.java +++ b/tests/unit/src/com/android/tv/recommendation/RecommenderTest.java @@ -17,20 +17,14 @@ package com.android.tv.recommendation; import static android.support.test.InstrumentationRegistry.getContext; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static com.google.common.truth.Truth.assertThat; import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; import android.test.MoreAsserts; - -import com.android.tv.data.Channel; +import com.android.tv.data.api.Channel; import com.android.tv.recommendation.RecommendationUtils.ChannelRecordSortedMapHelper; -import com.android.tv.testing.Utils; - -import org.junit.Before; -import org.junit.Test; - +import com.android.tv.testing.utils.Utils; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -39,8 +33,12 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; @SmallTest +@RunWith(AndroidJUnit4.class) public class RecommenderTest { private static final int DEFAULT_NUMBER_OF_CHANNELS = 5; private static final long DEFAULT_WATCH_START_TIME_MS = @@ -49,24 +47,27 @@ public class RecommenderTest { System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1); private static final long DEFAULT_MAX_WATCH_DURATION_MS = TimeUnit.HOURS.toMillis(1); - private final Comparator<Channel> CHANNEL_SORT_KEY_COMPARATOR = new Comparator<Channel>() { - @Override - public int compare(Channel lhs, Channel rhs) { - return mRecommender.getChannelSortKey(lhs.getId()) - .compareTo(mRecommender.getChannelSortKey(rhs.getId())); - } - }; - private final Runnable START_DATAMANAGER_RUNNABLE_ADD_FOUR_CHANNELS = new Runnable() { - @Override - public void run() { - // Add 4 channels in ChannelRecordMap for testing. Store the added channels to - // mChannels_1 ~ mChannels_4. They are sorted by channel id in increasing order. - mChannel_1 = mChannelRecordSortedMap.addChannel(); - mChannel_2 = mChannelRecordSortedMap.addChannel(); - mChannel_3 = mChannelRecordSortedMap.addChannel(); - mChannel_4 = mChannelRecordSortedMap.addChannel(); - } - }; + private final Comparator<Channel> mChannelSortKeyComparator = + new Comparator<Channel>() { + @Override + public int compare(Channel lhs, Channel rhs) { + return mRecommender + .getChannelSortKey(lhs.getId()) + .compareTo(mRecommender.getChannelSortKey(rhs.getId())); + } + }; + private final Runnable mStartDatamanagerRunnableAddFourChannels = + new Runnable() { + @Override + public void run() { + // Add 4 channels in ChannelRecordMap for testing. Store the added channels to + // mChannels_1 ~ mChannels_4. They are sorted by channel id in increasing order. + mChannel_1 = mChannelRecordSortedMap.addChannel(); + mChannel_2 = mChannelRecordSortedMap.addChannel(); + mChannel_3 = mChannelRecordSortedMap.addChannel(); + mChannel_4 = mChannelRecordSortedMap.addChannel(); + } + }; private RecommendationDataManager mDataManager; private Recommender mRecommender; @@ -82,133 +83,133 @@ public class RecommenderTest { @Before public void setUp() { mChannelRecordSortedMap = new ChannelRecordSortedMapHelper(getContext()); - mDataManager = RecommendationUtils - .createMockRecommendationDataManager(mChannelRecordSortedMap); + mDataManager = + RecommendationUtils.createMockRecommendationDataManager(mChannelRecordSortedMap); mChannelRecordSortedMap.resetRandom(Utils.createTestRandom()); } @Test public void testRecommendChannels_includeRecommendedOnly_allChannelsHaveNoScore() { - createRecommender(true, START_DATAMANAGER_RUNNABLE_ADD_FOUR_CHANNELS); - - // Recommender doesn't recommend any channels because all channels are not recommended. - assertEquals(0, mRecommender.recommendChannels().size()); - assertEquals(0, mRecommender.recommendChannels(-5).size()); - assertEquals(0, mRecommender.recommendChannels(0).size()); - assertEquals(0, mRecommender.recommendChannels(3).size()); - assertEquals(0, mRecommender.recommendChannels(4).size()); - assertEquals(0, mRecommender.recommendChannels(5).size()); + createRecommender(true, mStartDatamanagerRunnableAddFourChannels); + + // Recommender doesn't recommend any channels because all channels are not recommended. + assertThat(mRecommender.recommendChannels()).isEmpty(); + assertThat(mRecommender.recommendChannels(-5)).isEmpty(); + assertThat(mRecommender.recommendChannels(0)).isEmpty(); + assertThat(mRecommender.recommendChannels(3)).isEmpty(); + assertThat(mRecommender.recommendChannels(4)).isEmpty(); + assertThat(mRecommender.recommendChannels(5)).isEmpty(); } @Test public void testRecommendChannels_notIncludeRecommendedOnly_allChannelsHaveNoScore() { - createRecommender(false, START_DATAMANAGER_RUNNABLE_ADD_FOUR_CHANNELS); - - // Recommender recommends every channel because it recommends not-recommended channels too. - assertEquals(4, mRecommender.recommendChannels().size()); - assertEquals(0, mRecommender.recommendChannels(-5).size()); - assertEquals(0, mRecommender.recommendChannels(0).size()); - assertEquals(3, mRecommender.recommendChannels(3).size()); - assertEquals(4, mRecommender.recommendChannels(4).size()); - assertEquals(4, mRecommender.recommendChannels(5).size()); + createRecommender(false, mStartDatamanagerRunnableAddFourChannels); + + // Recommender recommends every channel because it recommends not-recommended channels too. + assertThat(mRecommender.recommendChannels()).hasSize(4); + assertThat(mRecommender.recommendChannels(-5)).isEmpty(); + assertThat(mRecommender.recommendChannels(0)).isEmpty(); + assertThat(mRecommender.recommendChannels(3)).hasSize(3); + assertThat(mRecommender.recommendChannels(4)).hasSize(4); + assertThat(mRecommender.recommendChannels(5)).hasSize(4); } @Test public void testRecommendChannels_includeRecommendedOnly_allChannelsHaveScore() { - createRecommender(true, START_DATAMANAGER_RUNNABLE_ADD_FOUR_CHANNELS); + createRecommender(true, mStartDatamanagerRunnableAddFourChannels); setChannelScores_scoreIncreasesAsChannelIdIncreases(); // recommendChannels must be sorted by score in decreasing order. // (i.e. sorted by channel ID in decreasing order in this case) - MoreAsserts.assertContentsInOrder(mRecommender.recommendChannels(), - mChannel_4, mChannel_3, mChannel_2, mChannel_1); - assertEquals(0, mRecommender.recommendChannels(-5).size()); - assertEquals(0, mRecommender.recommendChannels(0).size()); - MoreAsserts.assertContentsInOrder(mRecommender.recommendChannels(3), - mChannel_4, mChannel_3, mChannel_2); - MoreAsserts.assertContentsInOrder(mRecommender.recommendChannels(4), - mChannel_4, mChannel_3, mChannel_2, mChannel_1); - MoreAsserts.assertContentsInOrder(mRecommender.recommendChannels(5), - mChannel_4, mChannel_3, mChannel_2, mChannel_1); + MoreAsserts.assertContentsInOrder( + mRecommender.recommendChannels(), mChannel_4, mChannel_3, mChannel_2, mChannel_1); + assertThat(mRecommender.recommendChannels(-5)).isEmpty(); + assertThat(mRecommender.recommendChannels(0)).isEmpty(); + MoreAsserts.assertContentsInOrder( + mRecommender.recommendChannels(3), mChannel_4, mChannel_3, mChannel_2); + MoreAsserts.assertContentsInOrder( + mRecommender.recommendChannels(4), mChannel_4, mChannel_3, mChannel_2, mChannel_1); + MoreAsserts.assertContentsInOrder( + mRecommender.recommendChannels(5), mChannel_4, mChannel_3, mChannel_2, mChannel_1); } @Test public void testRecommendChannels_notIncludeRecommendedOnly_allChannelsHaveScore() { - createRecommender(false, START_DATAMANAGER_RUNNABLE_ADD_FOUR_CHANNELS); + createRecommender(false, mStartDatamanagerRunnableAddFourChannels); setChannelScores_scoreIncreasesAsChannelIdIncreases(); // recommendChannels must be sorted by score in decreasing order. // (i.e. sorted by channel ID in decreasing order in this case) - MoreAsserts.assertContentsInOrder(mRecommender.recommendChannels(), - mChannel_4, mChannel_3, mChannel_2, mChannel_1); - assertEquals(0, mRecommender.recommendChannels(-5).size()); - assertEquals(0, mRecommender.recommendChannels(0).size()); - MoreAsserts.assertContentsInOrder(mRecommender.recommendChannels(3), - mChannel_4, mChannel_3, mChannel_2); - MoreAsserts.assertContentsInOrder(mRecommender.recommendChannels(4), - mChannel_4, mChannel_3, mChannel_2, mChannel_1); - MoreAsserts.assertContentsInOrder(mRecommender.recommendChannels(5), - mChannel_4, mChannel_3, mChannel_2, mChannel_1); + MoreAsserts.assertContentsInOrder( + mRecommender.recommendChannels(), mChannel_4, mChannel_3, mChannel_2, mChannel_1); + assertThat(mRecommender.recommendChannels(-5)).isEmpty(); + assertThat(mRecommender.recommendChannels(0)).isEmpty(); + MoreAsserts.assertContentsInOrder( + mRecommender.recommendChannels(3), mChannel_4, mChannel_3, mChannel_2); + MoreAsserts.assertContentsInOrder( + mRecommender.recommendChannels(4), mChannel_4, mChannel_3, mChannel_2, mChannel_1); + MoreAsserts.assertContentsInOrder( + mRecommender.recommendChannels(5), mChannel_4, mChannel_3, mChannel_2, mChannel_1); } @Test public void testRecommendChannels_includeRecommendedOnly_fewChannelsHaveScore() { - createRecommender(true, START_DATAMANAGER_RUNNABLE_ADD_FOUR_CHANNELS); + createRecommender(true, mStartDatamanagerRunnableAddFourChannels); mEvaluator.setChannelScore(mChannel_1.getId(), 1.0); mEvaluator.setChannelScore(mChannel_2.getId(), 1.0); // Only two channels are recommended because recommender doesn't recommend other channels. - MoreAsserts.assertContentsInAnyOrder(mRecommender.recommendChannels(), - mChannel_1, mChannel_2); - assertEquals(0, mRecommender.recommendChannels(-5).size()); - assertEquals(0, mRecommender.recommendChannels(0).size()); - MoreAsserts.assertContentsInAnyOrder(mRecommender.recommendChannels(3), - mChannel_1, mChannel_2); - MoreAsserts.assertContentsInAnyOrder(mRecommender.recommendChannels(4), - mChannel_1, mChannel_2); - MoreAsserts.assertContentsInAnyOrder(mRecommender.recommendChannels(5), - mChannel_1, mChannel_2); + MoreAsserts.assertContentsInAnyOrder( + mRecommender.recommendChannels(), mChannel_1, mChannel_2); + assertThat(mRecommender.recommendChannels(-5)).isEmpty(); + assertThat(mRecommender.recommendChannels(0)).isEmpty(); + MoreAsserts.assertContentsInAnyOrder( + mRecommender.recommendChannels(3), mChannel_1, mChannel_2); + MoreAsserts.assertContentsInAnyOrder( + mRecommender.recommendChannels(4), mChannel_1, mChannel_2); + MoreAsserts.assertContentsInAnyOrder( + mRecommender.recommendChannels(5), mChannel_1, mChannel_2); } @Test public void testRecommendChannels_notIncludeRecommendedOnly_fewChannelsHaveScore() { - createRecommender(false, START_DATAMANAGER_RUNNABLE_ADD_FOUR_CHANNELS); + createRecommender(false, mStartDatamanagerRunnableAddFourChannels); mEvaluator.setChannelScore(mChannel_1.getId(), 1.0); mEvaluator.setChannelScore(mChannel_2.getId(), 1.0); - assertEquals(4, mRecommender.recommendChannels().size()); - MoreAsserts.assertContentsInAnyOrder(mRecommender.recommendChannels().subList(0, 2), - mChannel_1, mChannel_2); + assertThat(mRecommender.recommendChannels()).hasSize(4); + MoreAsserts.assertContentsInAnyOrder( + mRecommender.recommendChannels().subList(0, 2), mChannel_1, mChannel_2); - assertEquals(0, mRecommender.recommendChannels(-5).size()); - assertEquals(0, mRecommender.recommendChannels(0).size()); + assertThat(mRecommender.recommendChannels(-5)).isEmpty(); + assertThat(mRecommender.recommendChannels(0)).isEmpty(); - assertEquals(3, mRecommender.recommendChannels(3).size()); - MoreAsserts.assertContentsInAnyOrder(mRecommender.recommendChannels(3).subList(0, 2), - mChannel_1, mChannel_2); + assertThat(mRecommender.recommendChannels(3)).hasSize(3); + MoreAsserts.assertContentsInAnyOrder( + mRecommender.recommendChannels(3).subList(0, 2), mChannel_1, mChannel_2); - assertEquals(4, mRecommender.recommendChannels(4).size()); - MoreAsserts.assertContentsInAnyOrder(mRecommender.recommendChannels(4).subList(0, 2), - mChannel_1, mChannel_2); + assertThat(mRecommender.recommendChannels(4)).hasSize(4); + MoreAsserts.assertContentsInAnyOrder( + mRecommender.recommendChannels(4).subList(0, 2), mChannel_1, mChannel_2); - assertEquals(4, mRecommender.recommendChannels(5).size()); - MoreAsserts.assertContentsInAnyOrder(mRecommender.recommendChannels(5).subList(0, 2), - mChannel_1, mChannel_2); + assertThat(mRecommender.recommendChannels(5)).hasSize(4); + MoreAsserts.assertContentsInAnyOrder( + mRecommender.recommendChannels(5).subList(0, 2), mChannel_1, mChannel_2); } @Test public void testGetChannelSortKey_recommendAllChannels() { - createRecommender(true, START_DATAMANAGER_RUNNABLE_ADD_FOUR_CHANNELS); + createRecommender(true, mStartDatamanagerRunnableAddFourChannels); setChannelScores_scoreIncreasesAsChannelIdIncreases(); List<Channel> expectedChannelList = mRecommender.recommendChannels(); List<Channel> channelList = Arrays.asList(mChannel_1, mChannel_2, mChannel_3, mChannel_4); - Collections.sort(channelList, CHANNEL_SORT_KEY_COMPARATOR); + Collections.sort(channelList, mChannelSortKeyComparator); // Recommended channel list and channel list sorted by sort key must be the same. MoreAsserts.assertContentsInOrder(channelList, expectedChannelList.toArray()); @@ -218,17 +219,17 @@ public class RecommenderTest { @Test public void testGetChannelSortKey_recommendFewChannels() { // Test with recommending 3 channels. - createRecommender(true, START_DATAMANAGER_RUNNABLE_ADD_FOUR_CHANNELS); + createRecommender(true, mStartDatamanagerRunnableAddFourChannels); setChannelScores_scoreIncreasesAsChannelIdIncreases(); List<Channel> expectedChannelList = mRecommender.recommendChannels(3); - // A channel which is not recommended by the recommender has to get an invalid sort key. - assertEquals(Recommender.INVALID_CHANNEL_SORT_KEY, - mRecommender.getChannelSortKey(mChannel_1.getId())); + // A channel which is not recommended by the recommender has to get an invalid sort key. + assertThat(mRecommender.getChannelSortKey(mChannel_1.getId())) + .isEqualTo(Recommender.INVALID_CHANNEL_SORT_KEY); List<Channel> channelList = Arrays.asList(mChannel_2, mChannel_3, mChannel_4); - Collections.sort(channelList, CHANNEL_SORT_KEY_COMPARATOR); + Collections.sort(channelList, mChannelSortKeyComparator); MoreAsserts.assertContentsInOrder(channelList, expectedChannelList.toArray()); assertSortKeyNotInvalid(channelList); @@ -236,10 +237,10 @@ public class RecommenderTest { @Test public void testListener_onRecommendationChanged() { - createRecommender(true, START_DATAMANAGER_RUNNABLE_ADD_FOUR_CHANNELS); - // FakeEvaluator doesn't recommend a channel with empty watch log. As every channel - // doesn't have a watch log, nothing is recommended and recommendation isn't changed. - assertFalse(mOnRecommendationChanged); + createRecommender(true, mStartDatamanagerRunnableAddFourChannels); + // FakeEvaluator doesn't recommend a channel with empty watch log. As every channel + // doesn't have a watch log, nothing is recommended and recommendation isn't changed. + assertThat(mOnRecommendationChanged).isFalse(); // Set lastRecommendationUpdatedTimeUtcMs to check recommendation changed because, // recommender has a minimum recommendation update period. @@ -248,51 +249,63 @@ public class RecommenderTest { long latestWatchEndTimeMs = DEFAULT_WATCH_START_TIME_MS; for (long channelId : mChannelRecordSortedMap.keySet()) { mEvaluator.setChannelScore(channelId, 1.0); - // Add a log to recalculate the recommendation score. - assertTrue(mChannelRecordSortedMap.addWatchLog(channelId, latestWatchEndTimeMs, - TimeUnit.MINUTES.toMillis(10))); + // Add a log to recalculate the recommendation score. + assertThat( + mChannelRecordSortedMap.addWatchLog( + channelId, latestWatchEndTimeMs, TimeUnit.MINUTES.toMillis(10))) + .isTrue(); latestWatchEndTimeMs += TimeUnit.MINUTES.toMillis(10); } - // onRecommendationChanged must be called, because recommend channels are not empty, - // by setting score to each channel. - assertTrue(mOnRecommendationChanged); + // onRecommendationChanged must be called, because recommend channels are not empty, + // by setting score to each channel. + assertThat(mOnRecommendationChanged).isTrue(); } @Test public void testListener_onRecommenderReady() { - createRecommender(true, new Runnable() { - @Override - public void run() { - mChannelRecordSortedMap.addChannels(DEFAULT_NUMBER_OF_CHANNELS); - mChannelRecordSortedMap.addRandomWatchLogs(DEFAULT_WATCH_START_TIME_MS, - DEFAULT_WATCH_END_TIME_MS, DEFAULT_MAX_WATCH_DURATION_MS); - } - }); - - // After loading channels and watch logs are finished, recommender must be available to use. - assertTrue(mOnRecommenderReady); + createRecommender( + true, + new Runnable() { + @Override + public void run() { + mChannelRecordSortedMap.addChannels(DEFAULT_NUMBER_OF_CHANNELS); + mChannelRecordSortedMap.addRandomWatchLogs( + DEFAULT_WATCH_START_TIME_MS, + DEFAULT_WATCH_END_TIME_MS, + DEFAULT_MAX_WATCH_DURATION_MS); + } + }); + + // After loading channels and watch logs are finished, recommender must be available to use. + assertThat(mOnRecommenderReady).isTrue(); } private void assertSortKeyNotInvalid(List<Channel> channelList) { for (Channel channel : channelList) { - MoreAsserts.assertNotEqual(Recommender.INVALID_CHANNEL_SORT_KEY, + MoreAsserts.assertNotEqual( + Recommender.INVALID_CHANNEL_SORT_KEY, mRecommender.getChannelSortKey(channel.getId())); } } - private void createRecommender(boolean includeRecommendedOnly, - Runnable startDataManagerRunnable) { - mRecommender = new Recommender(new Recommender.Listener() { - @Override - public void onRecommenderReady() { - mOnRecommenderReady = true; - } - @Override - public void onRecommendationChanged() { - mOnRecommendationChanged = true; - } - }, includeRecommendedOnly, mDataManager); + private void createRecommender( + boolean includeRecommendedOnly, Runnable startDataManagerRunnable) { + mRecommender = + new Recommender( + new Recommender.Listener() { + @Override + public void onRecommenderReady() { + mOnRecommenderReady = true; + } + + @Override + public void onRecommendationChanged() { + mOnRecommendationChanged = true; + } + }, + includeRecommendedOnly, + mDataManager); mEvaluator = new FakeEvaluator(); mRecommender.registerEvaluator(mEvaluator); diff --git a/tests/unit/src/com/android/tv/recommendation/RoutineWatchEvaluatorTest.java b/tests/unit/src/com/android/tv/recommendation/RoutineWatchEvaluatorTest.java index 7b8e256d..39e6e9c5 100644 --- a/tests/unit/src/com/android/tv/recommendation/RoutineWatchEvaluatorTest.java +++ b/tests/unit/src/com/android/tv/recommendation/RoutineWatchEvaluatorTest.java @@ -16,23 +16,22 @@ package com.android.tv.recommendation; +import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import android.support.test.filters.SmallTest; -import android.test.MoreAsserts; - +import android.support.test.runner.AndroidJUnit4; import com.android.tv.data.Program; import com.android.tv.recommendation.RoutineWatchEvaluator.ProgramTime; - -import org.junit.Test; - -import java.util.Arrays; import java.util.Calendar; import java.util.List; -import java.util.TreeSet; import java.util.concurrent.TimeUnit; +import org.junit.Test; +import org.junit.runner.RunWith; +/** Tests for {@link RoutineWatchEvaluator}. */ @SmallTest +@RunWith(AndroidJUnit4.class) public class RoutineWatchEvaluatorTest extends EvaluatorTestCase<RoutineWatchEvaluator> { private static class ScoredItem implements Comparable<ScoredItem> { private final String mBase; @@ -67,13 +66,23 @@ public class RoutineWatchEvaluatorTest extends EvaluatorTestCase<RoutineWatchEva @Test public void testSplitTextToWords() { - assertSplitTextToWords(""); - assertSplitTextToWords("Google", "Google"); - assertSplitTextToWords("The Big Bang Theory", "The", "Big", "Bang", "Theory"); - assertSplitTextToWords("Hello, world!", "Hello", "world"); - assertSplitTextToWords("Adam's Rib", "Adam's", "Rib"); - assertSplitTextToWords("G.I. Joe", "G.I", "Joe"); - assertSplitTextToWords("A.I.", "A.I"); + assertThat(RoutineWatchEvaluator.splitTextToWords("")).containsExactly().inOrder(); + assertThat(RoutineWatchEvaluator.splitTextToWords("Google")) + .containsExactly("Google") + .inOrder(); + assertThat(RoutineWatchEvaluator.splitTextToWords("The Big Bang Theory")) + .containsExactly("The", "Big", "Bang", "Theory") + .inOrder(); + assertThat(RoutineWatchEvaluator.splitTextToWords("Hello, world!")) + .containsExactly("Hello", "world") + .inOrder(); + assertThat(RoutineWatchEvaluator.splitTextToWords("Adam's Rib")) + .containsExactly("Adam's", "Rib") + .inOrder(); + assertThat(RoutineWatchEvaluator.splitTextToWords("G.I. Joe")) + .containsExactly("G.I", "Joe") + .inOrder(); + assertThat(RoutineWatchEvaluator.splitTextToWords("A.I.")).containsExactly("A.I").inOrder(); } @Test @@ -102,7 +111,6 @@ public class RoutineWatchEvaluatorTest extends EvaluatorTestCase<RoutineWatchEva assertEqualScores(0.0, RoutineWatchEvaluator.calculateTitleMatchScore(" ", "foo")); } - @Test public void testCalculateTitleMatchScore_null() { assertEqualScores(0.0, RoutineWatchEvaluator.calculateTitleMatchScore(null, null)); @@ -113,11 +121,15 @@ public class RoutineWatchEvaluatorTest extends EvaluatorTestCase<RoutineWatchEva @Test public void testCalculateTitleMatchScore_longerMatchIsBetter() { String base = "foo bar baz"; - assertInOrder( - score(base, ""), - score(base, "bar"), - score(base, "foo bar"), - score(base, "foo bar baz")); + assertThat( + new ScoredItem[] { + score(base, ""), + score(base, "bar"), + score(base, "foo bar"), + score(base, "foo bar baz") + }) + .asList() + .isOrdered(); } @Test @@ -128,116 +140,154 @@ public class RoutineWatchEvaluatorTest extends EvaluatorTestCase<RoutineWatchEva int tomorrowDayOfWeek = (todayDayOfWeek % 7) + 1; // Today 00:00 - 01:00. - ProgramTime programTimeToday0000_0100 = ProgramTime.createFromProgram( - createDummyProgram(todayAtHourMin(0, 0), TimeUnit.HOURS.toMillis(1))); - assertProgramTime(todayDayOfWeek, hourMinuteToSec(0, 0), hourMinuteToSec(1, 0), - programTimeToday0000_0100); + ProgramTime programTimeToday0000to0100 = + ProgramTime.createFromProgram( + createDummyProgram(todayAtHourMin(0, 0), TimeUnit.HOURS.toMillis(1))); + assertProgramTime( + todayDayOfWeek, + hourMinuteToSec(0, 0), + hourMinuteToSec(1, 0), + programTimeToday0000to0100); // Today 23:30 - 24:30. - ProgramTime programTimeToday2330_2430 = ProgramTime.createFromProgram( - createDummyProgram(todayAtHourMin(23, 30), TimeUnit.HOURS.toMillis(1))); - assertProgramTime(todayDayOfWeek, hourMinuteToSec(23, 30), hourMinuteToSec(24, 30), - programTimeToday2330_2430); + ProgramTime programTimeToday2330to2430 = + ProgramTime.createFromProgram( + createDummyProgram(todayAtHourMin(23, 30), TimeUnit.HOURS.toMillis(1))); + assertProgramTime( + todayDayOfWeek, + hourMinuteToSec(23, 30), + hourMinuteToSec(24, 30), + programTimeToday2330to2430); // Tomorrow 00:00 - 01:00. - ProgramTime programTimeTomorrow0000_0100 = ProgramTime.createFromProgram( - createDummyProgram(tomorrowAtHourMin(0, 0), TimeUnit.HOURS.toMillis(1))); - assertProgramTime(tomorrowDayOfWeek, hourMinuteToSec(0, 0), hourMinuteToSec(1, 0), - programTimeTomorrow0000_0100); + ProgramTime programTimeTomorrow0000to0100 = + ProgramTime.createFromProgram( + createDummyProgram(tomorrowAtHourMin(0, 0), TimeUnit.HOURS.toMillis(1))); + assertProgramTime( + tomorrowDayOfWeek, + hourMinuteToSec(0, 0), + hourMinuteToSec(1, 0), + programTimeTomorrow0000to0100); // Tomorrow 23:30 - 24:30. - ProgramTime programTimeTomorrow2330_2430 = ProgramTime.createFromProgram( - createDummyProgram(tomorrowAtHourMin(23, 30), TimeUnit.HOURS.toMillis(1))); - assertProgramTime(tomorrowDayOfWeek, hourMinuteToSec(23, 30), hourMinuteToSec(24, 30), - programTimeTomorrow2330_2430); + ProgramTime programTimeTomorrow2330to2430 = + ProgramTime.createFromProgram( + createDummyProgram(tomorrowAtHourMin(23, 30), TimeUnit.HOURS.toMillis(1))); + assertProgramTime( + tomorrowDayOfWeek, + hourMinuteToSec(23, 30), + hourMinuteToSec(24, 30), + programTimeTomorrow2330to2430); // Today 18:00 - Tomorrow 12:00. - ProgramTime programTimeToday1800_3600 = ProgramTime.createFromProgram( - createDummyProgram(todayAtHourMin(18, 0), TimeUnit.HOURS.toMillis(18))); + ProgramTime programTimeToday1800to3600 = + ProgramTime.createFromProgram( + createDummyProgram(todayAtHourMin(18, 0), TimeUnit.HOURS.toMillis(18))); // Maximum duration of ProgramTime is 12 hours. // So, this program looks like it ends at Tomorrow 06:00 (30:00). - assertProgramTime(todayDayOfWeek, hourMinuteToSec(18, 0), hourMinuteToSec(30, 0), - programTimeToday1800_3600); + assertProgramTime( + todayDayOfWeek, + hourMinuteToSec(18, 0), + hourMinuteToSec(30, 0), + programTimeToday1800to3600); } @Test public void testCalculateOverlappedIntervalScore() { // Today 21:00 - 24:00. - ProgramTime programTimeToday2100_2400 = ProgramTime.createFromProgram( - createDummyProgram(todayAtHourMin(21, 0), TimeUnit.HOURS.toMillis(3))); + ProgramTime programTimeToday2100to2400 = + ProgramTime.createFromProgram( + createDummyProgram(todayAtHourMin(21, 0), TimeUnit.HOURS.toMillis(3))); // Today 22:00 - 01:00. - ProgramTime programTimeToday2200_0100 = ProgramTime.createFromProgram( - createDummyProgram(todayAtHourMin(22, 0), TimeUnit.HOURS.toMillis(3))); + ProgramTime programTimeToday2200to0100 = + ProgramTime.createFromProgram( + createDummyProgram(todayAtHourMin(22, 0), TimeUnit.HOURS.toMillis(3))); // Tomorrow 00:00 - 03:00. - ProgramTime programTimeTomorrow0000_0300 = ProgramTime.createFromProgram( - createDummyProgram(tomorrowAtHourMin(0, 0), TimeUnit.HOURS.toMillis(3))); + ProgramTime programTimeTomorrow0000to0300 = + ProgramTime.createFromProgram( + createDummyProgram(tomorrowAtHourMin(0, 0), TimeUnit.HOURS.toMillis(3))); // Tomorrow 20:00 - Tomorrow 23:00. - ProgramTime programTimeTomorrow2000_2300 = ProgramTime.createFromProgram( - createDummyProgram(tomorrowAtHourMin(20, 0), TimeUnit.HOURS.toMillis(3))); + ProgramTime programTimeTomorrow2000to2300 = + ProgramTime.createFromProgram( + createDummyProgram(tomorrowAtHourMin(20, 0), TimeUnit.HOURS.toMillis(3))); // Check intersection time and commutative law in all cases. int oneHourInSec = hourMinuteToSec(1, 0); - assertOverlappedIntervalScore(2 * oneHourInSec, true, programTimeToday2100_2400, - programTimeToday2200_0100); - assertOverlappedIntervalScore(0, false, programTimeToday2100_2400, - programTimeTomorrow0000_0300); - assertOverlappedIntervalScore(2 * oneHourInSec, false, programTimeToday2100_2400, - programTimeTomorrow2000_2300); - assertOverlappedIntervalScore(oneHourInSec, true, programTimeToday2200_0100, - programTimeTomorrow0000_0300); - assertOverlappedIntervalScore(oneHourInSec, false, programTimeToday2200_0100, - programTimeTomorrow2000_2300); - assertOverlappedIntervalScore(0, false, programTimeTomorrow0000_0300, - programTimeTomorrow2000_2300); + assertOverlappedIntervalScore( + 2 * oneHourInSec, true, programTimeToday2100to2400, programTimeToday2200to0100); + assertOverlappedIntervalScore( + 0, false, programTimeToday2100to2400, programTimeTomorrow0000to0300); + assertOverlappedIntervalScore( + 2 * oneHourInSec, false, programTimeToday2100to2400, programTimeTomorrow2000to2300); + assertOverlappedIntervalScore( + oneHourInSec, true, programTimeToday2200to0100, programTimeTomorrow0000to0300); + assertOverlappedIntervalScore( + oneHourInSec, false, programTimeToday2200to0100, programTimeTomorrow2000to2300); + assertOverlappedIntervalScore( + 0, false, programTimeTomorrow0000to0300, programTimeTomorrow2000to2300); } @Test public void testGetTimeOfDayInSec() { // Time was set as 00:00:00. So, getTimeOfDay must returns 0 (= 0 * 60 * 60 + 0 * 60 + 0). - assertEquals("TimeOfDayInSec", hourMinuteToSec(0, 0), + assertEquals( + "TimeOfDayInSec", + hourMinuteToSec(0, 0), RoutineWatchEvaluator.getTimeOfDayInSec(todayAtHourMin(0, 0))); // Time was set as 23:59:59. So, getTimeOfDay must returns 23 * 60 + 60 + 59 * 60 + 59. - assertEquals("TimeOfDayInSec", hourMinuteSecondToSec(23, 59, 59), + assertEquals( + "TimeOfDayInSec", + hourMinuteSecondToSec(23, 59, 59), RoutineWatchEvaluator.getTimeOfDayInSec(todayAtHourMinSec(23, 59, 59))); } - private void assertSplitTextToWords(String text, String... words) { - List<String> wordList = RoutineWatchEvaluator.splitTextToWords(text); - MoreAsserts.assertContentsInOrder(wordList, words); - } - - private void assertMaximumMatchedWordSequenceLength(int expectedLength, String text1, - String text2) { + private void assertMaximumMatchedWordSequenceLength( + int expectedLength, String text1, String text2) { List<String> wordList1 = RoutineWatchEvaluator.splitTextToWords(text1); List<String> wordList2 = RoutineWatchEvaluator.splitTextToWords(text2); - assertEquals("MaximumMatchedWordSequenceLength", expectedLength, + assertEquals( + "MaximumMatchedWordSequenceLength", + expectedLength, RoutineWatchEvaluator.calculateMaximumMatchedWordSequenceLength( wordList1, wordList2)); - assertEquals("MaximumMatchedWordSequenceLength", expectedLength, + assertEquals( + "MaximumMatchedWordSequenceLength", + expectedLength, RoutineWatchEvaluator.calculateMaximumMatchedWordSequenceLength( wordList2, wordList1)); } - private void assertProgramTime(int expectedWeekDay, int expectedStartTimeOfDayInSec, - int expectedEndTimeOfDayInSec, ProgramTime actualProgramTime) { + private void assertProgramTime( + int expectedWeekDay, + int expectedStartTimeOfDayInSec, + int expectedEndTimeOfDayInSec, + ProgramTime actualProgramTime) { assertEquals("Weekday", expectedWeekDay, actualProgramTime.weekDay); - assertEquals("StartTimeOfDayInSec", expectedStartTimeOfDayInSec, + assertEquals( + "StartTimeOfDayInSec", + expectedStartTimeOfDayInSec, actualProgramTime.startTimeOfDayInSec); - assertEquals("EndTimeOfDayInSec", expectedEndTimeOfDayInSec, + assertEquals( + "EndTimeOfDayInSec", + expectedEndTimeOfDayInSec, actualProgramTime.endTimeOfDayInSec); } - private void assertOverlappedIntervalScore(int expectedSeconds, boolean overlappedOnSameDay, - ProgramTime t1, ProgramTime t2) { + private void assertOverlappedIntervalScore( + int expectedSeconds, boolean overlappedOnSameDay, ProgramTime t1, ProgramTime t2) { double score = expectedSeconds; if (!overlappedOnSameDay) { score *= RoutineWatchEvaluator.MULTIPLIER_FOR_UNMATCHED_DAY_OF_WEEK; } // Two tests for testing commutative law. - assertEqualScores("OverlappedIntervalScore", score, + assertEqualScores( + "OverlappedIntervalScore", + score, RoutineWatchEvaluator.calculateOverlappedIntervalScore(t1, t2)); - assertEqualScores("OverlappedIntervalScore", score, + assertEqualScores( + "OverlappedIntervalScore", + score, RoutineWatchEvaluator.calculateOverlappedIntervalScore(t2, t1)); } @@ -270,12 +320,9 @@ public class RoutineWatchEvaluatorTest extends EvaluatorTestCase<RoutineWatchEva private Program createDummyProgram(Calendar startTime, long programDurationMs) { long startTimeMs = startTime.getTimeInMillis(); - return new Program.Builder().setStartTimeUtcMillis(startTimeMs) - .setEndTimeUtcMillis(startTimeMs + programDurationMs).build(); - } - - private static <T> void assertInOrder(T... items) { - TreeSet<T> copy = new TreeSet<>(Arrays.asList(items)); - MoreAsserts.assertContentsInOrder(copy, items); + return new Program.Builder() + .setStartTimeUtcMillis(startTimeMs) + .setEndTimeUtcMillis(startTimeMs + programDurationMs) + .build(); } } diff --git a/tests/unit/src/com/android/tv/search/LocalSearchProviderTest.java b/tests/unit/src/com/android/tv/search/LocalSearchProviderTest.java deleted file mode 100644 index b0d342c6..00000000 --- a/tests/unit/src/com/android/tv/search/LocalSearchProviderTest.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2017 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.search; - -import static android.support.test.InstrumentationRegistry.getTargetContext; -import static org.mockito.Mockito.clearInvocations; -import static org.mockito.Mockito.verify; - -import android.app.SearchManager; -import android.database.Cursor; -import android.net.Uri; -import android.support.test.filters.SmallTest; -import android.test.ProviderTestCase2; - -import com.android.tv.ApplicationSingletons; -import com.android.tv.TvApplication; -import com.android.tv.perf.PerformanceMonitor; -import com.android.tv.util.MockApplicationSingletons; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -/** Unit test for {@link LocalSearchProvider}. */ -@SmallTest -public class LocalSearchProviderTest extends ProviderTestCase2<LocalSearchProvider> { - private static final String AUTHORITY = "com.android.tv.search"; - private static final String KEYWORD = "keyword"; - private static final Uri BASE_SEARCH_URI = Uri.parse("content://" + AUTHORITY + "/" - + SearchManager.SUGGEST_URI_PATH_QUERY + "/" + KEYWORD); - private static final Uri WRONG_SERACH_URI = Uri.parse("content://" + AUTHORITY + "/wrong_path/" - + KEYWORD); - - private ApplicationSingletons mOldAppSingletons; - MockApplicationSingletons mMockAppSingletons; - @Mock PerformanceMonitor mMockPerformanceMointor; - @Mock SearchInterface mMockSearchInterface; - - public LocalSearchProviderTest() { - super(LocalSearchProvider.class, AUTHORITY); - } - - @Before - @Override - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - setContext(getTargetContext()); - mOldAppSingletons = TvApplication.sAppSingletons; - mMockAppSingletons = new MockApplicationSingletons(getTargetContext()); - mMockAppSingletons.setPerformanceMonitor(mMockPerformanceMointor); - TvApplication.sAppSingletons = mMockAppSingletons; - super.setUp(); - getProvider().setSearchInterface(mMockSearchInterface); - } - - @After - @Override - public void tearDown() throws Exception { - TvApplication.sAppSingletons = mOldAppSingletons; - super.tearDown(); - } - - @Test - public void testQuery_normalUri() { - verifyQueryWithArguments(null, null); - verifyQueryWithArguments(1, null); - verifyQueryWithArguments(null, 1); - verifyQueryWithArguments(1, 1); - } - - @Test - public void testQuery_invalidUri() { - try (Cursor c = getProvider().query(WRONG_SERACH_URI, null, null, null, null)) { - fail("Query with invalid URI should fail."); - } catch (IllegalArgumentException e) { - // Success. - } - } - - @Test - public void testQuery_invalidLimit() { - verifyQueryWithArguments(-1, null); - } - - @Test - public void testQuery_invalidAction() { - verifyQueryWithArguments(null, SearchInterface.ACTION_TYPE_START - 1); - verifyQueryWithArguments(null, SearchInterface.ACTION_TYPE_END + 1); - } - - private void verifyQueryWithArguments(Integer limit, Integer action) { - Uri uri = BASE_SEARCH_URI; - if (limit != null || action != null) { - Uri.Builder builder = uri.buildUpon(); - if (limit != null) { - builder.appendQueryParameter(SearchManager.SUGGEST_PARAMETER_LIMIT, - limit.toString()); - } - if (action != null) { - builder.appendQueryParameter(LocalSearchProvider.SUGGEST_PARAMETER_ACTION, - action.toString()); - } - uri = builder.build(); - } - try (Cursor c = getProvider().query(uri, null, null, null, null)) { - // Do nothing. - } - int expectedLimit = limit == null || limit <= 0 ? - LocalSearchProvider.DEFAULT_SEARCH_LIMIT : limit; - int expectedAction = (action == null || action < SearchInterface.ACTION_TYPE_START - || action > SearchInterface.ACTION_TYPE_END) ? - LocalSearchProvider.DEFAULT_SEARCH_ACTION : action; - verify(mMockSearchInterface).search(KEYWORD, expectedLimit, expectedAction); - clearInvocations(mMockSearchInterface); - } -} diff --git a/tests/unit/src/com/android/tv/tests/TvActivityTest.java b/tests/unit/src/com/android/tv/tests/TvActivityTest.java deleted file mode 100644 index aa33f770..00000000 --- a/tests/unit/src/com/android/tv/tests/TvActivityTest.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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.tests; - -import static android.support.test.InstrumentationRegistry.getTargetContext; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import android.support.test.filters.MediumTest; -import android.support.test.rule.ActivityTestRule; - -import com.android.tv.TvActivity; -import com.android.tv.testing.Utils; - -import org.junit.Rule; -import org.junit.Test; - -@MediumTest -public class TvActivityTest { - @Rule - public ActivityTestRule<TvActivity> mActivityTestRule = - new ActivityTestRule<>(TvActivity.class, false, false); - - @Test - public void testLifeCycle() { - assertTrue("TvActivity should be enabled.", Utils.isTvActivityEnabled(getTargetContext())); - assertNotNull(mActivityTestRule.launchActivity(null)); - } -} diff --git a/tests/unit/src/com/android/tv/util/MockApplicationSingletons.java b/tests/unit/src/com/android/tv/util/MockTvSingletons.java index 4cfc7f8a..6de1eb3e 100644 --- a/tests/unit/src/com/android/tv/util/MockApplicationSingletons.java +++ b/tests/unit/src/com/android/tv/util/MockTvSingletons.java @@ -17,34 +17,41 @@ package com.android.tv.util; import android.content.Context; - -import com.android.tv.ApplicationSingletons; +import android.content.Intent; import com.android.tv.InputSessionManager; import com.android.tv.MainActivityWrapper; import com.android.tv.TvApplication; +import com.android.tv.TvSingletons; import com.android.tv.analytics.Analytics; import com.android.tv.analytics.Tracker; -import com.android.tv.config.RemoteConfig; +import com.android.tv.common.config.api.RemoteConfig; +import com.android.tv.common.experiments.ExperimentLoader; +import com.android.tv.common.recording.RecordingStorageStatusManager; +import com.android.tv.common.util.Clock; import com.android.tv.data.ChannelDataManager; import com.android.tv.data.PreviewDataManager; import com.android.tv.data.ProgramDataManager; +import com.android.tv.data.epg.EpgFetcher; +import com.android.tv.data.epg.EpgReader; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.DvrManager; import com.android.tv.dvr.DvrScheduleManager; -import com.android.tv.dvr.DvrStorageStatusManager; import com.android.tv.dvr.DvrWatchedPositionManager; import com.android.tv.dvr.recorder.RecordingScheduler; import com.android.tv.perf.PerformanceMonitor; +import com.android.tv.testing.FakeClock; +import com.android.tv.tuner.TunerInputController; +import java.util.concurrent.Executor; +import javax.inject.Provider; -/** - * Mock {@link ApplicationSingletons} class. - */ -public class MockApplicationSingletons implements ApplicationSingletons { - private final TvApplication mApp; +/** Mock {@link TvSingletons} class. */ +public class MockTvSingletons implements TvSingletons { + public final FakeClock fakeClock = FakeClock.createWithCurrentTime(); + private final TvApplication mApp; private PerformanceMonitor mPerformanceMonitor; - public MockApplicationSingletons(Context context) { + public MockTvSingletons(Context context) { mApp = (TvApplication) context.getApplicationContext(); } @@ -54,6 +61,9 @@ public class MockApplicationSingletons implements ApplicationSingletons { } @Override + public void handleInputCountChanged() {} + + @Override public ChannelDataManager getChannelDataManager() { return mApp.getChannelDataManager(); } @@ -84,8 +94,13 @@ public class MockApplicationSingletons implements ApplicationSingletons { } @Override - public DvrStorageStatusManager getDvrStorageStatusManager() { - return mApp.getDvrStorageStatusManager(); + public Clock getClock() { + return fakeClock; + } + + @Override + public RecordingStorageStatusManager getRecordingStorageStatusManager() { + return mApp.getRecordingStorageStatusManager(); } @Override @@ -124,12 +139,37 @@ public class MockApplicationSingletons implements ApplicationSingletons { } @Override + public Provider<EpgReader> providesEpgReader() { + return mApp.providesEpgReader(); + } + + @Override + public EpgFetcher getEpgFetcher() { + return mApp.getEpgFetcher(); + } + + @Override + public SetupUtils getSetupUtils() { + return mApp.getSetupUtils(); + } + + @Override + public TunerInputController getTunerInputController() { + return mApp.getTunerInputController(); + } + + @Override + public ExperimentLoader getExperimentLoader() { + return mApp.getExperimentLoader(); + } + + @Override public MainActivityWrapper getMainActivityWrapper() { return mApp.getMainActivityWrapper(); } @Override - public AccountHelper getAccountHelper() { + public com.android.tv.util.account.AccountHelper getAccountHelper() { return mApp.getAccountHelper(); } @@ -139,6 +179,11 @@ public class MockApplicationSingletons implements ApplicationSingletons { } @Override + public Intent getTunerSetupIntent(Context context) { + return mApp.getTunerSetupIntent(context); + } + + @Override public boolean isRunningInMainProcess() { return mApp.isRunningInMainProcess(); } @@ -151,4 +196,14 @@ public class MockApplicationSingletons implements ApplicationSingletons { public void setPerformanceMonitor(PerformanceMonitor performanceMonitor) { mPerformanceMonitor = performanceMonitor; } + + @Override + public String getEmbeddedTunerInputId() { + return "com.android.tv/.tuner.tvinput.LiveTvTunerTvInputService"; + } + + @Override + public Executor getDbExecutor() { + return mApp.getDbExecutor(); + } } diff --git a/tests/unit/src/com/android/tv/util/MultiLongSparseArrayTest.java b/tests/unit/src/com/android/tv/util/MultiLongSparseArrayTest.java deleted file mode 100644 index 7335f207..00000000 --- a/tests/unit/src/com/android/tv/util/MultiLongSparseArrayTest.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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.util; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; - -import android.support.test.filters.SmallTest; -import android.test.MoreAsserts; - -import org.junit.Test; - -import java.util.Collections; - -/** - * Tests for {@link MultiLongSparseArray}. - */ -@SmallTest -public class MultiLongSparseArrayTest { - @Test - public void testEmpty() { - MultiLongSparseArray<String> sparseArray = new MultiLongSparseArray<>(); - assertSame(Collections.EMPTY_SET, sparseArray.get(0)); - } - - @Test - public void testOneElement() { - MultiLongSparseArray<String> sparseArray = new MultiLongSparseArray<>(); - sparseArray.put(0, "foo"); - MoreAsserts.assertContentsInAnyOrder(sparseArray.get(0), "foo"); - } - - @Test - public void testTwoElements() { - MultiLongSparseArray<String> sparseArray = new MultiLongSparseArray<>(); - sparseArray.put(0, "foo"); - sparseArray.put(0, "bar"); - MoreAsserts.assertContentsInAnyOrder(sparseArray.get(0), "foo", "bar"); - } - - - @Test - public void testClearEmptyCache() { - MultiLongSparseArray<String> sparseArray = new MultiLongSparseArray<>(); - sparseArray.clearEmptyCache(); - assertEquals(0, sparseArray.getEmptyCacheSize()); - sparseArray.put(0, "foo"); - sparseArray.remove(0, "foo"); - assertEquals(1, sparseArray.getEmptyCacheSize()); - sparseArray.clearEmptyCache(); - assertEquals(0, sparseArray.getEmptyCacheSize()); - } - - @Test - public void testMaxEmptyCacheSize() { - MultiLongSparseArray<String> sparseArray = new MultiLongSparseArray<>(); - sparseArray.clearEmptyCache(); - assertEquals(0, sparseArray.getEmptyCacheSize()); - for (int i = 0; i <= MultiLongSparseArray.DEFAULT_MAX_EMPTIES_KEPT + 2; i++) { - sparseArray.put(i, "foo"); - } - for (int i = 0; i <= MultiLongSparseArray.DEFAULT_MAX_EMPTIES_KEPT + 2; i++) { - sparseArray.remove(i, "foo"); - } - assertEquals(MultiLongSparseArray.DEFAULT_MAX_EMPTIES_KEPT, - sparseArray.getEmptyCacheSize()); - sparseArray.clearEmptyCache(); - assertEquals(0, sparseArray.getEmptyCacheSize()); - } - - @Test - public void testReuseEmptySets() { - MultiLongSparseArray<String> sparseArray = new MultiLongSparseArray<>(); - sparseArray.clearEmptyCache(); - assertEquals(0, sparseArray.getEmptyCacheSize()); - // create a bunch of sets - for (int i = 0; i <= MultiLongSparseArray.DEFAULT_MAX_EMPTIES_KEPT + 2; i++) { - sparseArray.put(i, "foo"); - } - // remove them so they are all put in the cache. - for (int i = 0; i <= MultiLongSparseArray.DEFAULT_MAX_EMPTIES_KEPT + 2; i++) { - sparseArray.remove(i, "foo"); - } - assertEquals(MultiLongSparseArray.DEFAULT_MAX_EMPTIES_KEPT, - sparseArray.getEmptyCacheSize()); - - // now create elements, that use the cached empty sets. - for (int i = 0; i < MultiLongSparseArray.DEFAULT_MAX_EMPTIES_KEPT; i++) { - sparseArray.put(10 + i, "bar"); - assertEquals(MultiLongSparseArray.DEFAULT_MAX_EMPTIES_KEPT - i - 1, - sparseArray.getEmptyCacheSize()); - } - } -} diff --git a/tests/unit/src/com/android/tv/util/ScaledBitmapInfoTest.java b/tests/unit/src/com/android/tv/util/ScaledBitmapInfoTest.java deleted file mode 100644 index 2714e2e9..00000000 --- a/tests/unit/src/com/android/tv/util/ScaledBitmapInfoTest.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.android.tv.util; - -import static org.junit.Assert.assertEquals; - -import android.graphics.Bitmap; -import android.support.test.filters.SmallTest; - -import com.android.tv.util.BitmapUtils.ScaledBitmapInfo; - -import org.junit.Test; - -/** - * Tests for {@link ScaledBitmapInfo}. - */ -@SmallTest -public class ScaledBitmapInfoTest { - private static final Bitmap B80x100 = Bitmap.createBitmap(80, 100, Bitmap.Config.RGB_565); - private static final Bitmap B960x1440 = Bitmap.createBitmap(960, 1440, Bitmap.Config.RGB_565); - - @Test - public void testSize_B100x100to50x50() { - ScaledBitmapInfo actual = BitmapUtils.createScaledBitmapInfo("B80x100", B80x100, 50, 50); - assertScaledBitmapSize(2, 40, 50, actual); - } - - @Test - public void testNeedsToReload_B100x100to50x50() { - ScaledBitmapInfo actual = BitmapUtils.createScaledBitmapInfo("B80x100", B80x100, 50, 50); - assertNeedsToReload(false, actual, 25, 25); - assertNeedsToReload(false, actual, 50, 50); - assertNeedsToReload(false, actual, 99, 99); - assertNeedsToReload(true, actual, 100, 100); - assertNeedsToReload(true, actual, 101, 101); - } - - /** - * Reproduces <a href="http://b/20488453">b/20488453</a>. - */ - @Test - public void testBug20488453() { - ScaledBitmapInfo actual = BitmapUtils - .createScaledBitmapInfo("B960x1440", B960x1440, 284, 160); - assertScaledBitmapSize(8, 107, 160, actual); - assertNeedsToReload(false, actual, 284, 160); - } - - private static void assertNeedsToReload(boolean expected, ScaledBitmapInfo scaledBitmap, - int reqWidth, int reqHeight) { - assertEquals(scaledBitmap.id + " needToReload(" + reqWidth + "," + reqHeight + ")", - expected, scaledBitmap.needToReload(reqWidth, reqHeight)); - } - - private static void assertScaledBitmapSize(int expectedInSampleSize, int expectedWidth, - int expectedHeight, ScaledBitmapInfo actual) { - assertEquals(actual.id + " inSampleSize", expectedInSampleSize, actual.inSampleSize); - assertEquals(actual.id + " width", expectedWidth, actual.bitmap.getWidth()); - assertEquals(actual.id + " height", expectedHeight, actual.bitmap.getHeight()); - } -} diff --git a/tests/unit/src/com/android/tv/util/TestUtils.java b/tests/unit/src/com/android/tv/util/TestUtils.java deleted file mode 100644 index d200733d..00000000 --- a/tests/unit/src/com/android/tv/util/TestUtils.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * 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.util; - -import android.content.pm.ResolveInfo; -import android.content.pm.ServiceInfo; -import android.graphics.drawable.Icon; -import android.hardware.hdmi.HdmiDeviceInfo; -import android.media.tv.TvInputInfo; -import android.os.Build; -import android.os.Bundle; - -import java.lang.reflect.Constructor; - -/** - * A class that includes convenience methods for testing. - */ -public class TestUtils { - /** - * Creates a {@link TvInputInfo}. - */ - public static TvInputInfo createTvInputInfo(ResolveInfo service, String id, String parentId, - int type, boolean isHardwareInput) throws Exception { - return createTvInputInfo(service, id, parentId, type, isHardwareInput, false, 0); - } - - /** - * Creates a {@link TvInputInfo}. - * <p> - * If this is called on MNC, {@code canRecord} and {@code tunerCount} are ignored. - */ - public static TvInputInfo createTvInputInfo(ResolveInfo service, String id, String parentId, - int type, boolean isHardwareInput, boolean canRecord, int tunerCount) throws Exception { - // Create a mock TvInputInfo by using private constructor - // Note that mockito doesn't support mock/spy on final object. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - return createTvInputInfoForO(service, id, parentId, type, isHardwareInput, canRecord, - tunerCount); - - } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - return createTvInputInfoForNyc(service, id, parentId, type, isHardwareInput, canRecord, - tunerCount); - } - return createTvInputInfoForMnc(service, id, parentId, type, isHardwareInput); - } - - /** - * private TvInputInfo(ResolveInfo service, String id, int type, boolean isHardwareInput, - * CharSequence label, int labelResId, Icon icon, Icon iconStandby, Icon iconDisconnected, - * String setupActivity, boolean canRecord, int tunerCount, HdmiDeviceInfo hdmiDeviceInfo, - * boolean isConnectedToHdmiSwitch, String parentId, Bundle extras) { - */ - private static TvInputInfo createTvInputInfoForO(ResolveInfo service, String id, - String parentId, int type, boolean isHardwareInput, boolean canRecord, int tunerCount) - throws Exception { - Constructor<TvInputInfo> constructor = TvInputInfo.class.getDeclaredConstructor( - ResolveInfo.class, String.class, int.class, boolean.class, CharSequence.class, - int.class, Icon.class, Icon.class, Icon.class, String.class, boolean.class, - int.class, HdmiDeviceInfo.class, boolean.class, String.class, Bundle.class); - constructor.setAccessible(true); - return constructor.newInstance(service, id, type, isHardwareInput, null, 0, null, null, - null, null, canRecord, tunerCount, null, false, parentId, null); - } - - /** - * private TvInputInfo(ResolveInfo service, String id, int type, boolean isHardwareInput, - * CharSequence label, int labelResId, Icon icon, Icon iconStandby, Icon iconDisconnected, - * String setupActivity, String settingsActivity, boolean canRecord, int tunerCount, - * HdmiDeviceInfo hdmiDeviceInfo, boolean isConnectedToHdmiSwitch, String parentId, - * Bundle extras) { - */ - private static TvInputInfo createTvInputInfoForNyc(ResolveInfo service, String id, - String parentId, int type, boolean isHardwareInput, boolean canRecord, int tunerCount) - throws Exception { - Constructor<TvInputInfo> constructor = TvInputInfo.class.getDeclaredConstructor( - ResolveInfo.class, String.class, int.class, boolean.class, CharSequence.class, - int.class, Icon.class, Icon.class, Icon.class, String.class, String.class, - boolean.class, int.class, HdmiDeviceInfo.class, boolean.class, String.class, - Bundle.class); - constructor.setAccessible(true); - return constructor.newInstance(service, id, type, isHardwareInput, null, 0, null, null, - null, null, null, canRecord, tunerCount, null, false, parentId, null); - } - - private static TvInputInfo createTvInputInfoForMnc(ResolveInfo service, String id, - String parentId, int type, boolean isHardwareInput) throws Exception { - Constructor<TvInputInfo> constructor = TvInputInfo.class.getDeclaredConstructor( - ResolveInfo.class, String.class, String.class, int.class, boolean.class); - constructor.setAccessible(true); - return constructor.newInstance(service, id, parentId, type, isHardwareInput); - } - - public static ResolveInfo createResolveInfo(String packageName, String name) { - ResolveInfo resolveInfo = new ResolveInfo(); - resolveInfo.serviceInfo = new ServiceInfo(); - resolveInfo.serviceInfo.packageName = packageName; - resolveInfo.serviceInfo.name = name; - resolveInfo.serviceInfo.metaData = new Bundle(); - return resolveInfo; - } -} diff --git a/tests/unit/src/com/android/tv/util/TvInputManagerHelperTest.java b/tests/unit/src/com/android/tv/util/TvInputManagerHelperTest.java index 404ee5d3..6dfed64a 100644 --- a/tests/unit/src/com/android/tv/util/TvInputManagerHelperTest.java +++ b/tests/unit/src/com/android/tv/util/TvInputManagerHelperTest.java @@ -21,22 +21,21 @@ import static android.support.test.InstrumentationRegistry.getContext; import android.content.pm.ResolveInfo; import android.media.tv.TvInputInfo; import android.support.test.filters.SmallTest; - +import android.support.test.runner.AndroidJUnit4; import com.android.tv.testing.ComparatorTester; - +import com.android.tv.testing.utils.TestUtils; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -/** - * Test for {@link TvInputManagerHelper} - */ +/** Test for {@link TvInputManagerHelper} */ @SmallTest +@RunWith(AndroidJUnit4.class) public class TvInputManagerHelperTest { final HashMap<String, TvInputInfoWrapper> TEST_INPUT_MAP = new HashMap<>(); @@ -45,18 +44,51 @@ public class TvInputManagerHelperTest { ResolveInfo resolveInfo = TestUtils.createResolveInfo("test", "test"); List<TvInputInfo> inputs = new ArrayList<>(); - inputs.add(createTvInputInfo(resolveInfo, "2_partner_input", null, 0, false, - "2_partner_input", null, true)); - inputs.add(createTvInputInfo(resolveInfo, "3_partner_input", null, 0, false, - "3_partner_input", null, true)); - inputs.add(createTvInputInfo(resolveInfo, "1_3rd_party_input", null, 0, false, - "1_3rd_party_input", null, false)); - inputs.add(createTvInputInfo(resolveInfo, "4_3rd_party_input", null, 0, false, - "4_3rd_party_input", null, false)); + inputs.add( + createTvInputInfo( + resolveInfo, + "2_partner_input", + null, + 0, + false, + "2_partner_input", + null, + true)); + inputs.add( + createTvInputInfo( + resolveInfo, + "3_partner_input", + null, + 0, + false, + "3_partner_input", + null, + true)); + inputs.add( + createTvInputInfo( + resolveInfo, + "1_3rd_party_input", + null, + 0, + false, + "1_3rd_party_input", + null, + false)); + inputs.add( + createTvInputInfo( + resolveInfo, + "4_3rd_party_input", + null, + 0, + false, + "4_3rd_party_input", + null, + false)); TvInputManagerHelper manager = createMockTvInputManager(); - ComparatorTester<TvInputInfo> comparatorTester = ComparatorTester.withoutEqualsTest( + ComparatorTester<TvInputInfo> comparatorTester = + ComparatorTester.withoutEqualsTest( new TvInputManagerHelper.InputComparatorInternal(manager)); for (TvInputInfo input : inputs) { comparatorTester.addComparableGroup(input); @@ -68,20 +100,54 @@ public class TvInputManagerHelperTest { public void testHardwareInputComparatorHdmi() { ResolveInfo resolveInfo = TestUtils.createResolveInfo("test", "test"); - TvInputInfo hdmi1 = createTvInputInfo(resolveInfo, "HDMI1", null, TvInputInfo.TYPE_HDMI, - true, "HDMI1", null, false); - TvInputInfo hdmi2 = createTvInputInfo(resolveInfo, "HDMI2", null, TvInputInfo.TYPE_HDMI, - true, "HDMI2", "DVD", false); - TvInputInfo hdmi3 = createTvInputInfo(resolveInfo, "HDMI3", null, TvInputInfo.TYPE_HDMI, - true, "HDMI3", "Cable", false); - TvInputInfo hdmi4 = createTvInputInfo(resolveInfo, "HDMI4", null, TvInputInfo.TYPE_HDMI, - true, "HDMI4", null, false); + TvInputInfo hdmi1 = + createTvInputInfo( + resolveInfo, + "HDMI1", + null, + TvInputInfo.TYPE_HDMI, + true, + "HDMI1", + null, + false); + TvInputInfo hdmi2 = + createTvInputInfo( + resolveInfo, + "HDMI2", + null, + TvInputInfo.TYPE_HDMI, + true, + "HDMI2", + "DVD", + false); + TvInputInfo hdmi3 = + createTvInputInfo( + resolveInfo, + "HDMI3", + null, + TvInputInfo.TYPE_HDMI, + true, + "HDMI3", + "Cable", + false); + TvInputInfo hdmi4 = + createTvInputInfo( + resolveInfo, + "HDMI4", + null, + TvInputInfo.TYPE_HDMI, + true, + "HDMI4", + null, + false); TvInputManagerHelper manager = createMockTvInputManager(); - ComparatorTester<TvInputInfo> comparatorTester = ComparatorTester.withoutEqualsTest( + ComparatorTester<TvInputInfo> comparatorTester = + ComparatorTester.withoutEqualsTest( new TvInputManagerHelper.HardwareInputComparator(getContext(), manager)); - comparatorTester.addComparableGroup(hdmi3) + comparatorTester + .addComparableGroup(hdmi3) .addComparableGroup(hdmi2) .addComparableGroup(hdmi1) .addComparableGroup(hdmi4) @@ -92,61 +158,111 @@ public class TvInputManagerHelperTest { public void testHardwareInputComparatorCec() { ResolveInfo resolveInfo = TestUtils.createResolveInfo("test", "test"); - TvInputInfo hdmi1 = createTvInputInfo(resolveInfo, "HDMI1", null, TvInputInfo.TYPE_HDMI, - true, "HDMI1", null, false); - TvInputInfo hdmi2 = createTvInputInfo(resolveInfo, "HDMI2", null, TvInputInfo.TYPE_HDMI, - true, "HDMI2", null, false); + TvInputInfo hdmi1 = + createTvInputInfo( + resolveInfo, + "HDMI1", + null, + TvInputInfo.TYPE_HDMI, + true, + "HDMI1", + null, + false); + TvInputInfo hdmi2 = + createTvInputInfo( + resolveInfo, + "HDMI2", + null, + TvInputInfo.TYPE_HDMI, + true, + "HDMI2", + null, + false); - TvInputInfo cec1 = createTvInputInfo(resolveInfo, "2_cec", "HDMI1", TvInputInfo.TYPE_HDMI, - true, "2_cec", null, false); - TvInputInfo cec2 = createTvInputInfo(resolveInfo, "1_cec", "HDMI2", TvInputInfo.TYPE_HDMI, - true, "1_cec", null, false); + TvInputInfo cec1 = + createTvInputInfo( + resolveInfo, + "2_cec", + "HDMI1", + TvInputInfo.TYPE_HDMI, + true, + "2_cec", + null, + false); + TvInputInfo cec2 = + createTvInputInfo( + resolveInfo, + "1_cec", + "HDMI2", + TvInputInfo.TYPE_HDMI, + true, + "1_cec", + null, + false); TvInputManagerHelper manager = createMockTvInputManager(); - ComparatorTester<TvInputInfo> comparatorTester = ComparatorTester.withoutEqualsTest( + ComparatorTester<TvInputInfo> comparatorTester = + ComparatorTester.withoutEqualsTest( new TvInputManagerHelper.HardwareInputComparator(getContext(), manager)); - comparatorTester.addComparableGroup(cec1) - .addComparableGroup(cec2) - .test(); + comparatorTester.addComparableGroup(cec1).addComparableGroup(cec2).test(); } private TvInputManagerHelper createMockTvInputManager() { TvInputManagerHelper manager = Mockito.mock(TvInputManagerHelper.class); - Mockito.doAnswer(new Answer<Boolean>() { - @Override - public Boolean answer(InvocationOnMock invocation) throws Throwable { - TvInputInfo info = (TvInputInfo) invocation.getArguments()[0]; - return TEST_INPUT_MAP.get(info.getId()).mIsPartnerInput; - } - }).when(manager).isPartnerInput(Mockito.<TvInputInfo>any()); - Mockito.doAnswer(new Answer<String>() { - @Override - public String answer(InvocationOnMock invocation) throws Throwable { - TvInputInfo info = (TvInputInfo) invocation.getArguments()[0]; - return TEST_INPUT_MAP.get(info.getId()).mLabel; - } - }).when(manager).loadLabel(Mockito.<TvInputInfo>any()); - Mockito.doAnswer(new Answer<String>() { - @Override - public String answer(InvocationOnMock invocation) throws Throwable { - TvInputInfo info = (TvInputInfo) invocation.getArguments()[0]; - return TEST_INPUT_MAP.get(info.getId()).mCustomLabel; - } - }).when(manager).loadCustomLabel(Mockito.<TvInputInfo>any()); - Mockito.doAnswer(new Answer<TvInputInfo>() { - @Override - public TvInputInfo answer(InvocationOnMock invocation) throws Throwable { - String inputId = (String) invocation.getArguments()[0]; - TvInputInfoWrapper inputWrapper = TEST_INPUT_MAP.get(inputId); - return inputWrapper == null ? null : inputWrapper.mInput; - } - }).when(manager).getTvInputInfo(Mockito.<String>any()); + Mockito.doAnswer( + new Answer<Boolean>() { + @Override + public Boolean answer(InvocationOnMock invocation) throws Throwable { + TvInputInfo info = (TvInputInfo) invocation.getArguments()[0]; + return TEST_INPUT_MAP.get(info.getId()).mIsPartnerInput; + } + }) + .when(manager) + .isPartnerInput(Mockito.<TvInputInfo>any()); + Mockito.doAnswer( + new Answer<String>() { + @Override + public String answer(InvocationOnMock invocation) throws Throwable { + TvInputInfo info = (TvInputInfo) invocation.getArguments()[0]; + return TEST_INPUT_MAP.get(info.getId()).mLabel; + } + }) + .when(manager) + .loadLabel(Mockito.<TvInputInfo>any()); + Mockito.doAnswer( + new Answer<String>() { + @Override + public String answer(InvocationOnMock invocation) throws Throwable { + TvInputInfo info = (TvInputInfo) invocation.getArguments()[0]; + return TEST_INPUT_MAP.get(info.getId()).mCustomLabel; + } + }) + .when(manager) + .loadCustomLabel(Mockito.<TvInputInfo>any()); + Mockito.doAnswer( + new Answer<TvInputInfo>() { + @Override + public TvInputInfo answer(InvocationOnMock invocation) + throws Throwable { + String inputId = (String) invocation.getArguments()[0]; + TvInputInfoWrapper inputWrapper = TEST_INPUT_MAP.get(inputId); + return inputWrapper == null ? null : inputWrapper.mInput; + } + }) + .when(manager) + .getTvInputInfo(Mockito.<String>any()); return manager; } - private TvInputInfo createTvInputInfo(ResolveInfo service, String id, - String parentId, int type, boolean isHardwareInput, String label, String customLabel, + private TvInputInfo createTvInputInfo( + ResolveInfo service, + String id, + String parentId, + int type, + boolean isHardwareInput, + String label, + String customLabel, boolean isPartnerInput) { TvInputInfoWrapper inputWrapper = new TvInputInfoWrapper(); try { diff --git a/tests/unit/src/com/android/tv/util/TvTrackInfoUtilsTest.java b/tests/unit/src/com/android/tv/util/TvTrackInfoUtilsTest.java index 4512bb7d..d84a90d4 100644 --- a/tests/unit/src/com/android/tv/util/TvTrackInfoUtilsTest.java +++ b/tests/unit/src/com/android/tv/util/TvTrackInfoUtilsTest.java @@ -16,24 +16,22 @@ package com.android.tv.util; import static com.android.tv.util.TvTrackInfoUtils.getBestTrackInfo; -import static org.junit.Assert.assertEquals; +import static com.google.common.truth.Truth.assertWithMessage; import android.media.tv.TvTrackInfo; import android.support.test.filters.SmallTest; - +import android.support.test.runner.AndroidJUnit4; import com.android.tv.testing.ComparatorTester; - -import org.junit.Test; - import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; +import org.junit.Test; +import org.junit.runner.RunWith; -/** - * Tests for {@link com.android.tv.util.TvTrackInfoUtils}. - */ +/** Tests for {@link com.android.tv.util.TvTrackInfoUtils}. */ @SmallTest +@RunWith(AndroidJUnit4.class) public class TvTrackInfoUtilsTest { private static final String UN_MATCHED_ID = "no matching ID"; @@ -54,57 +52,57 @@ public class TvTrackInfoUtilsTest { .build(); } - private static final List<TvTrackInfo> ALL = Arrays.asList(INFO_1_EN_1, INFO_2_EN_5, - INFO_3_FR_8, INFO_4_NULL_2, INFO_5_NULL_6); - private static final List<TvTrackInfo> NULL_LANGUAGE_TRACKS = Arrays.asList(INFO_4_NULL_2, - INFO_5_NULL_6); + private static final List<TvTrackInfo> ALL = + Arrays.asList(INFO_1_EN_1, INFO_2_EN_5, INFO_3_FR_8, INFO_4_NULL_2, INFO_5_NULL_6); + private static final List<TvTrackInfo> NULL_LANGUAGE_TRACKS = + Arrays.asList(INFO_4_NULL_2, INFO_5_NULL_6); @Test public void testGetBestTrackInfo_empty() { TvTrackInfo result = getBestTrackInfo(Collections.emptyList(), UN_MATCHED_ID, "en", 1); - assertEquals("best track ", null, result); + assertWithMessage("best track ").that(result).isEqualTo(null); } @Test public void testGetBestTrackInfo_exactMatch() { TvTrackInfo result = getBestTrackInfo(ALL, "1", "en", 1); - assertEquals("best track ", INFO_1_EN_1, result); + assertWithMessage("best track ").that(result).isEqualTo(INFO_1_EN_1); } @Test public void testGetBestTrackInfo_langAndChannelCountMatch() { TvTrackInfo result = getBestTrackInfo(ALL, UN_MATCHED_ID, "en", 5); - assertEquals("best track ", INFO_2_EN_5, result); + assertWithMessage("best track ").that(result).isEqualTo(INFO_2_EN_5); } @Test public void testGetBestTrackInfo_languageOnlyMatch() { TvTrackInfo result = getBestTrackInfo(ALL, UN_MATCHED_ID, "fr", 1); - assertEquals("best track ", INFO_3_FR_8, result); + assertWithMessage("best track ").that(result).isEqualTo(INFO_3_FR_8); } @Test public void testGetBestTrackInfo_channelCountOnlyMatchWithNullLanguage() { TvTrackInfo result = getBestTrackInfo(ALL, UN_MATCHED_ID, null, 8); - assertEquals("best track ", INFO_3_FR_8, result); + assertWithMessage("best track ").that(result).isEqualTo(INFO_3_FR_8); } @Test public void testGetBestTrackInfo_noMatches() { TvTrackInfo result = getBestTrackInfo(ALL, UN_MATCHED_ID, "kr", 1); - assertEquals("best track ", INFO_1_EN_1, result); + assertWithMessage("best track ").that(result).isEqualTo(INFO_1_EN_1); } @Test public void testGetBestTrackInfo_noMatchesWithNullLanguage() { TvTrackInfo result = getBestTrackInfo(ALL, UN_MATCHED_ID, null, 0); - assertEquals("best track ", INFO_1_EN_1, result); + assertWithMessage("best track ").that(result).isEqualTo(INFO_1_EN_1); } @Test public void testGetBestTrackInfo_channelCountAndIdMatch() { TvTrackInfo result = getBestTrackInfo(NULL_LANGUAGE_TRACKS, "5", null, 6); - assertEquals("best track ", INFO_5_NULL_6, result); + assertWithMessage("best track ").that(result).isEqualTo(INFO_5_NULL_6); } @Test @@ -112,15 +110,17 @@ public class TvTrackInfoUtilsTest { Comparator<TvTrackInfo> comparator = TvTrackInfoUtils.createComparator("1", "en", 1); ComparatorTester.withoutEqualsTest(comparator) // lang not match - .addComparableGroup(create("1", "kr", 1), create("2", "kr", 2), + .addComparableGroup( + create("1", "kr", 1), + create("2", "kr", 2), create("1", "ja", 1), create("1", "ch", 1)) - // lang match not count match - .addComparableGroup(create("2", "en", 2), create("3", "en", 3), - create("1", "en", 2)) - // lang and count match + // lang match not count match + .addComparableGroup( + create("2", "en", 2), create("3", "en", 3), create("1", "en", 2)) + // lang and count match .addComparableGroup(create("2", "en", 1), create("3", "en", 1)) - // all match + // all match .addComparableGroup(create("1", "en", 1), create("1", "en", 1)) .test(); } diff --git a/tests/unit/src/com/android/tv/util/UtilsTest_GetDurationString.java b/tests/unit/src/com/android/tv/util/UtilsTest_GetDurationString.java deleted file mode 100644 index e61802f5..00000000 --- a/tests/unit/src/com/android/tv/util/UtilsTest_GetDurationString.java +++ /dev/null @@ -1,273 +0,0 @@ -/* - * 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.util; - -import static android.support.test.InstrumentationRegistry.getContext; -import static org.junit.Assert.assertEquals; - -import android.support.test.filters.SmallTest; -import android.text.format.DateUtils; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import java.util.Calendar; -import java.util.GregorianCalendar; -import java.util.Locale; - -/** - * Tests for {@link com.android.tv.util.Utils#getDurationString}. - * <p/> - * This test uses deprecated flags {@link DateUtils#FORMAT_12HOUR} and - * {@link DateUtils#FORMAT_24HOUR} to run this test independent to system's 12/24h format. - * Note that changing system setting requires permission android.permission.WRITE_SETTINGS - * and it should be defined in TV app, not this test. - */ -@SmallTest -public class UtilsTest_GetDurationString { - // TODO: Mock Context so we can specify current time and locale for test. - private Locale mLocale; - private static final long DATE_THIS_YEAR_2_1_MS = getFebOfThisYearInMillis(1, 0, 0); - - // All possible list for a parameter to test parameter independent result. - private static final boolean[] PARAM_USE_SHORT_FORMAT = {false, true}; - - @Before - public void setUp() { - // Set locale to US - mLocale = Locale.getDefault(); - Locale.setDefault(Locale.US); - } - - @After - public void tearDown() { - // Revive system locale. - Locale.setDefault(mLocale); - } - - /** - * Return time in millis assuming that whose year is this year and month is Jan. - */ - private static long getJanOfThisYearInMillis(int date, int hour, int minutes) { - return new GregorianCalendar(getThisYear(), Calendar.JANUARY, date, hour, minutes) - .getTimeInMillis(); - } - - private static long getJanOfThisYearInMillis(int date, int hour) { - return getJanOfThisYearInMillis(date, hour, 0); - } - - /** - * Return time in millis assuming that whose year is this year and month is Feb. - */ - private static long getFebOfThisYearInMillis(int date, int hour, int minutes) { - return new GregorianCalendar(getThisYear(), Calendar.FEBRUARY, date, hour, minutes) - .getTimeInMillis(); - } - - private static long getFebOfThisYearInMillis(int date, int hour) { - return getFebOfThisYearInMillis(date, hour, 0); - } - - private static int getThisYear() { - return new GregorianCalendar().get(GregorianCalendar.YEAR); - } - - @Test - public void testSameDateAndTime() { - assertEquals("3:00 AM", Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(1, 3), getFebOfThisYearInMillis(1, 3), false, - DateUtils.FORMAT_12HOUR)); - assertEquals("03:00", Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(1, 3), getFebOfThisYearInMillis(1, 3), false, - DateUtils.FORMAT_24HOUR)); - } - - @Test - public void testDurationWithinToday() { - assertEquals("12:00 – 3:00 AM", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(1, 3), false, - DateUtils.FORMAT_12HOUR)); - assertEquals("00:00 – 03:00", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(1, 3), false, - DateUtils.FORMAT_24HOUR)); - } - - @Test - public void testDurationFromYesterdayToToday() { - assertEquals("Jan 31, 3:00 AM – Feb 1, 4:00 AM", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getJanOfThisYearInMillis(31, 3), getFebOfThisYearInMillis(1, 4), false, - DateUtils.FORMAT_12HOUR)); - assertEquals("Jan 31, 03:00 – Feb 1, 04:00", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getJanOfThisYearInMillis(31, 3), getFebOfThisYearInMillis(1, 4), false, - DateUtils.FORMAT_24HOUR)); - assertEquals("1/31, 11:30 PM – 12:30 AM", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getJanOfThisYearInMillis(31, 23, 30), getFebOfThisYearInMillis(1, 0, 30), - true, DateUtils.FORMAT_12HOUR)); - assertEquals("1/31, 23:30 – 00:30", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getJanOfThisYearInMillis(31, 23, 30), getFebOfThisYearInMillis(1, 0, 30), - true, DateUtils.FORMAT_24HOUR)); - } - - @Test - public void testDurationFromTodayToTomorrow() { - assertEquals("Feb 1, 3:00 AM – Feb 2, 4:00 AM", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(1, 3), getFebOfThisYearInMillis(2, 4), false, - DateUtils.FORMAT_12HOUR)); - assertEquals("Feb 1, 03:00 – Feb 2, 04:00", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(1, 3), getFebOfThisYearInMillis(2, 4), false, - DateUtils.FORMAT_24HOUR)); - assertEquals("2/1, 3:00 AM – 2/2, 4:00 AM", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(1, 3), getFebOfThisYearInMillis(2, 4), true, - DateUtils.FORMAT_12HOUR)); - assertEquals("2/1, 03:00 – 2/2, 04:00", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(1, 3), getFebOfThisYearInMillis(2, 4), true, - DateUtils.FORMAT_24HOUR)); - - assertEquals("Feb 1, 11:30 PM – Feb 2, 12:30 AM", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(1, 23, 30), getFebOfThisYearInMillis(2, 0, 30), - false, - DateUtils.FORMAT_12HOUR)); - assertEquals("Feb 1, 23:30 – Feb 2, 00:30", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(1, 23, 30), getFebOfThisYearInMillis(2, 0, 30), - false, - DateUtils.FORMAT_24HOUR)); - assertEquals("11:30 PM – 12:30 AM", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(1, 23, 30), getFebOfThisYearInMillis(2, 0, 30), - true, - DateUtils.FORMAT_12HOUR)); - assertEquals("23:30 – 00:30", Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(1, 23, 30), getFebOfThisYearInMillis(2, 0, 30), - true, - DateUtils.FORMAT_24HOUR)); - } - - @Test - public void testDurationWithinTomorrow() { - assertEquals("Feb 2, 2:00 – 4:00 AM", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(2, 2), getFebOfThisYearInMillis(2, 4), false, - DateUtils.FORMAT_12HOUR)); - assertEquals("Feb 2, 02:00 – 04:00", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(2, 2), getFebOfThisYearInMillis(2, 4), false, - DateUtils.FORMAT_24HOUR)); - assertEquals("2/2, 2:00 – 4:00 AM", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(2, 2), getFebOfThisYearInMillis(2, 4), true, - DateUtils.FORMAT_12HOUR)); - assertEquals("2/2, 02:00 – 04:00", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(2, 2), getFebOfThisYearInMillis(2, 4), true, - DateUtils.FORMAT_24HOUR)); - } - - @Test - public void testStartOfDay() { - assertEquals("12:00 – 1:00 AM", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(1, 1), false, - DateUtils.FORMAT_12HOUR)); - assertEquals("00:00 – 01:00", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(1, 1), false, - DateUtils.FORMAT_24HOUR)); - - assertEquals("Feb 2, 12:00 – 1:00 AM", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(2, 0), getFebOfThisYearInMillis(2, 1), false, - DateUtils.FORMAT_12HOUR)); - assertEquals("Feb 2, 00:00 – 01:00", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(2, 0), getFebOfThisYearInMillis(2, 1), false, - DateUtils.FORMAT_24HOUR)); - assertEquals("2/2, 12:00 – 1:00 AM", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(2, 0), getFebOfThisYearInMillis(2, 1), true, - DateUtils.FORMAT_12HOUR)); - assertEquals("2/2, 00:00 – 01:00", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(2, 0), getFebOfThisYearInMillis(2, 1), true, - DateUtils.FORMAT_24HOUR)); - } - - @Test - public void testEndOfDay() { - for (boolean useShortFormat : PARAM_USE_SHORT_FORMAT) { - assertEquals("11:00 PM – 12:00 AM", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(1, 23), getFebOfThisYearInMillis(2, 0), - useShortFormat, - DateUtils.FORMAT_12HOUR)); - assertEquals("23:00 – 00:00", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(1, 23), getFebOfThisYearInMillis(2, 0), - useShortFormat, - DateUtils.FORMAT_24HOUR)); - } - - assertEquals("Feb 2, 11:00 PM – 12:00 AM", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(2, 23), getFebOfThisYearInMillis(3, 0), false, - DateUtils.FORMAT_12HOUR)); - assertEquals("Feb 2, 23:00 – 00:00", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(2, 23), getFebOfThisYearInMillis(3, 0), false, - DateUtils.FORMAT_24HOUR)); - assertEquals("2/2, 11:00 PM – 12:00 AM", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(2, 23), getFebOfThisYearInMillis(3, 0), true, - DateUtils.FORMAT_12HOUR)); - assertEquals("2/2, 23:00 – 00:00", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(2, 23), getFebOfThisYearInMillis(3, 0), true, - DateUtils.FORMAT_24HOUR)); - assertEquals("2/2, 12:00 AM – 2/3, 12:00 AM", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(2, 0), getFebOfThisYearInMillis(3, 0), true, - DateUtils.FORMAT_12HOUR)); - assertEquals("2/2, 00:00 – 2/3, 00:00", - Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(2, 0), getFebOfThisYearInMillis(3, 0), true, - DateUtils.FORMAT_24HOUR)); - } - - @Test - public void testMidnight() { - for (boolean useShortFormat : PARAM_USE_SHORT_FORMAT) { - assertEquals("12:00 AM", Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - DATE_THIS_YEAR_2_1_MS, DATE_THIS_YEAR_2_1_MS, useShortFormat, - DateUtils.FORMAT_12HOUR)); - assertEquals("00:00", Utils.getDurationString(getContext(), DATE_THIS_YEAR_2_1_MS, - DATE_THIS_YEAR_2_1_MS, DATE_THIS_YEAR_2_1_MS, useShortFormat, - DateUtils.FORMAT_24HOUR)); - } - } -} diff --git a/tests/unit/src/com/android/tv/util/UtilsTest_GetMultiAudioString.java b/tests/unit/src/com/android/tv/util/UtilsTest_GetMultiAudioString.java deleted file mode 100644 index 1e75342b..00000000 --- a/tests/unit/src/com/android/tv/util/UtilsTest_GetMultiAudioString.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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.util; - -import static android.support.test.InstrumentationRegistry.getTargetContext; -import static org.junit.Assert.assertEquals; - -import android.content.Context; -import android.media.tv.TvTrackInfo; -import android.support.test.filters.SmallTest; - -import org.junit.Test; - -/** - * Tests for {@link com.android.tv.util.Utils#getMultiAudioString}. - */ -@SmallTest -public class UtilsTest_GetMultiAudioString { - private static final String TRACK_ID = "test_track_id"; - private static final int AUDIO_SAMPLE_RATE = 48000; - - @Test - public void testAudioTrackLanguage() { - Context context = getTargetContext(); - assertEquals("Korean", - Utils.getMultiAudioString(context, createAudioTrackInfo("kor"), false)); - assertEquals("English", - Utils.getMultiAudioString(context, createAudioTrackInfo("eng"), false)); - assertEquals("Unknown language", - Utils.getMultiAudioString(context, createAudioTrackInfo(null), false)); - assertEquals("Unknown language", - Utils.getMultiAudioString(context, createAudioTrackInfo(""), false)); - assertEquals("abc", Utils.getMultiAudioString(context, createAudioTrackInfo("abc"), false)); - } - - @Test - public void testAudioTrackCount() { - Context context = getTargetContext(); - assertEquals("English", - Utils.getMultiAudioString(context, createAudioTrackInfo("eng", -1), false)); - assertEquals("English", - Utils.getMultiAudioString(context, createAudioTrackInfo("eng", 0), false)); - assertEquals("English (mono)", - Utils.getMultiAudioString(context, createAudioTrackInfo("eng", 1), false)); - assertEquals("English (stereo)", - Utils.getMultiAudioString(context, createAudioTrackInfo("eng", 2), false)); - assertEquals("English (3 channels)", - Utils.getMultiAudioString(context, createAudioTrackInfo("eng", 3), false)); - assertEquals("English (4 channels)", - Utils.getMultiAudioString(context, createAudioTrackInfo("eng", 4), false)); - assertEquals("English (5 channels)", - Utils.getMultiAudioString(context, createAudioTrackInfo("eng", 5), false)); - assertEquals("English (5.1 surround)", - Utils.getMultiAudioString(context, createAudioTrackInfo("eng", 6), false)); - assertEquals("English (7 channels)", - Utils.getMultiAudioString(context, createAudioTrackInfo("eng", 7), false)); - assertEquals("English (7.1 surround)", - Utils.getMultiAudioString(context, createAudioTrackInfo("eng", 8), false)); - } - - @Test - public void testShowSampleRate() { - assertEquals("Korean (48kHz)", - Utils.getMultiAudioString(getTargetContext(), - createAudioTrackInfo("kor", 0), true)); - assertEquals("Korean (7.1 surround, 48kHz)", - Utils.getMultiAudioString(getTargetContext(), - createAudioTrackInfo("kor", 8), true)); - } - - private static TvTrackInfo createAudioTrackInfo(String language) { - return createAudioTrackInfo(language, 0); - } - - private static TvTrackInfo createAudioTrackInfo(String language, int channelCount) { - return new TvTrackInfo.Builder(TvTrackInfo.TYPE_AUDIO, TRACK_ID) - .setLanguage(language).setAudioChannelCount(channelCount) - .setAudioSampleRate(AUDIO_SAMPLE_RATE).build(); - } -} diff --git a/tests/unit/src/com/android/tv/util/UtilsTest_IsInGivenDay.java b/tests/unit/src/com/android/tv/util/UtilsTest_IsInGivenDay.java deleted file mode 100644 index 2b43abc1..00000000 --- a/tests/unit/src/com/android/tv/util/UtilsTest_IsInGivenDay.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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.util; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import android.support.test.filters.SmallTest; - -import org.junit.Test; - -import java.util.Calendar; -import java.util.GregorianCalendar; -import java.util.TimeZone; - -/** - * Tests for {@link com.android.tv.util.Utils#isInGivenDay}. - */ -@SmallTest -public class UtilsTest_IsInGivenDay { - @Test - public void testIsInGivenDay() { - assertTrue(Utils.isInGivenDay( - new GregorianCalendar(2015, Calendar.JANUARY, 1).getTimeInMillis(), - new GregorianCalendar(2015, Calendar.JANUARY, 1, 0, 30).getTimeInMillis())); - } - - @Test - public void testIsNotInGivenDay() { - assertFalse(Utils.isInGivenDay( - new GregorianCalendar(2015, Calendar.JANUARY, 1).getTimeInMillis(), - new GregorianCalendar(2015, Calendar.JANUARY, 2).getTimeInMillis())); - } - - @Test - public void testIfTimeZoneApplied() { - TimeZone timeZone = TimeZone.getDefault(); - - TimeZone.setDefault(TimeZone.getTimeZone("Asia/Seoul")); - - // 2015.01.01 00:00 in KST = 2014.12.31 15:00 in UTC - long date2015StartMs = - new GregorianCalendar(2015, Calendar.JANUARY, 1).getTimeInMillis(); - - // 2015.01.01 10:00 in KST = 2015.01.01 01:00 in UTC - long date2015Start10AMMs = - new GregorianCalendar(2015, Calendar.JANUARY, 1, 10, 0).getTimeInMillis(); - - // Those two times aren't in the same day in UTC, but they are in KST. - assertTrue(Utils.isInGivenDay(date2015StartMs, date2015Start10AMMs)); - - TimeZone.setDefault(timeZone); - } -} diff --git a/tests/unit/src/com/android/tv/util/ImageCacheTest.java b/tests/unit/src/com/android/tv/util/images/ImageCacheTest.java index a76194b8..b7715c4a 100644 --- a/tests/unit/src/com/android/tv/util/ImageCacheTest.java +++ b/tests/unit/src/com/android/tv/util/images/ImageCacheTest.java @@ -14,23 +14,22 @@ * limitations under the License. */ -package com.android.tv.util; +package com.android.tv.util.images; -import static com.android.tv.util.BitmapUtils.createScaledBitmapInfo; -import static org.junit.Assert.assertSame; +import static com.android.tv.util.images.BitmapUtils.createScaledBitmapInfo; +import static com.google.common.truth.Truth.assertWithMessage; import android.graphics.Bitmap; import android.support.test.filters.MediumTest; - -import com.android.tv.util.BitmapUtils.ScaledBitmapInfo; - +import android.support.test.runner.AndroidJUnit4; +import com.android.tv.util.images.BitmapUtils.ScaledBitmapInfo; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; -/** - * Tests for {@link ImageCache}. - */ +/** Tests for {@link ImageCache}. */ @MediumTest +@RunWith(AndroidJUnit4.class) public class ImageCacheTest { private static final Bitmap ORIG = Bitmap.createBitmap(100, 100, Bitmap.Config.RGB_565); @@ -47,34 +46,34 @@ public class ImageCacheTest { mImageCache = ImageCache.newInstance(0.1f); } - //TODO: Empty the cache in the setup. Try using @VisibleForTesting + // TODO: Empty the cache in the setup. Try using @VisibleForTesting @Test public void testPutIfLarger_smaller() throws Exception { - mImageCache.putIfNeeded( INFO_50); - assertSame("before", INFO_50, mImageCache.get(KEY)); + mImageCache.putIfNeeded(INFO_50); + assertWithMessage("before").that(mImageCache.get(KEY)).isSameAs(INFO_50); - mImageCache.putIfNeeded( INFO_25); - assertSame("after", INFO_50, mImageCache.get(KEY)); + mImageCache.putIfNeeded(INFO_25); + assertWithMessage("after").that(mImageCache.get(KEY)).isSameAs(INFO_50); } @Test public void testPutIfLarger_larger() throws Exception { - mImageCache.putIfNeeded( INFO_50); - assertSame("before", INFO_50, mImageCache.get(KEY)); + mImageCache.putIfNeeded(INFO_50); + assertWithMessage("before").that(mImageCache.get(KEY)).isSameAs(INFO_50); mImageCache.putIfNeeded(INFO_100); - assertSame("after", INFO_100, mImageCache.get(KEY)); + assertWithMessage("after").that(mImageCache.get(KEY)).isSameAs(INFO_100); } @Test public void testPutIfLarger_alreadyMax() throws Exception { - mImageCache.putIfNeeded( INFO_100); - assertSame("before", INFO_100, mImageCache.get(KEY)); + mImageCache.putIfNeeded(INFO_100); + assertWithMessage("before").that(mImageCache.get(KEY)).isSameAs(INFO_100); - mImageCache.putIfNeeded( INFO_200); - assertSame("after", INFO_100, mImageCache.get(KEY)); + mImageCache.putIfNeeded(INFO_200); + assertWithMessage("after").that(mImageCache.get(KEY)).isSameAs(INFO_100); } -}
\ No newline at end of file +} diff --git a/tests/unit/src/com/android/tv/util/images/ScaledBitmapInfoTest.java b/tests/unit/src/com/android/tv/util/images/ScaledBitmapInfoTest.java new file mode 100644 index 00000000..005775b6 --- /dev/null +++ b/tests/unit/src/com/android/tv/util/images/ScaledBitmapInfoTest.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2017 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.util.images; + +import static com.google.common.truth.Truth.assertWithMessage; + +import android.graphics.Bitmap; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import com.android.tv.util.images.BitmapUtils.ScaledBitmapInfo; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Tests for {@link ScaledBitmapInfo}. */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class ScaledBitmapInfoTest { + private static final Bitmap B80x100 = Bitmap.createBitmap(80, 100, Bitmap.Config.RGB_565); + private static final Bitmap B960x1440 = Bitmap.createBitmap(960, 1440, Bitmap.Config.RGB_565); + + @Test + public void testSize_B100x100to50x50() { + ScaledBitmapInfo actual = BitmapUtils.createScaledBitmapInfo("B80x100", B80x100, 50, 50); + assertScaledBitmapSize(2, 40, 50, actual); + } + + @Test + public void testNeedsToReload_B100x100to50x50() { + ScaledBitmapInfo actual = BitmapUtils.createScaledBitmapInfo("B80x100", B80x100, 50, 50); + assertNeedsToReload(false, actual, 25, 25); + assertNeedsToReload(false, actual, 50, 50); + assertNeedsToReload(false, actual, 99, 99); + assertNeedsToReload(true, actual, 100, 100); + assertNeedsToReload(true, actual, 101, 101); + } + + /** Reproduces <a href="http://b/20488453">b/20488453</a>. */ + @Test + public void testBug20488453() { + ScaledBitmapInfo actual = + BitmapUtils.createScaledBitmapInfo("B960x1440", B960x1440, 284, 160); + assertScaledBitmapSize(8, 107, 160, actual); + assertNeedsToReload(false, actual, 284, 160); + } + + private static void assertNeedsToReload( + boolean expected, ScaledBitmapInfo scaledBitmap, int reqWidth, int reqHeight) { + assertWithMessage(scaledBitmap.id + " needToReload(" + reqWidth + "," + reqHeight + ")") + .that(scaledBitmap.needToReload(reqWidth, reqHeight)) + .isEqualTo(expected); + } + + private static void assertScaledBitmapSize( + int expectedInSampleSize, + int expectedWidth, + int expectedHeight, + ScaledBitmapInfo actual) { + assertWithMessage(actual.id + " inSampleSize") + .that(actual.inSampleSize) + .isEqualTo(expectedInSampleSize); + assertWithMessage(actual.id + " width").that(actual.bitmap.getWidth()).isEqualTo(expectedWidth); + assertWithMessage(actual.id + " height") + .that(actual.bitmap.getHeight()) + .isEqualTo(expectedHeight); + } +} |