diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2020-04-28 20:27:19 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2020-04-28 20:27:19 +0000 |
commit | e8a0f1ba285fd06676de2bdb08456d588e8341e2 (patch) | |
tree | f4ba89447e2d7ac3355508e583a5cf0574c29af5 | |
parent | f61bdda7ea9f0ecaf4158715411dc025ed9a3061 (diff) | |
parent | d12bfa398c56027290a9e6e4fd14f635458ec581 (diff) | |
download | TV-q_tzdata_aml_297100000.tar.gz |
Snap for 6439596 from d12bfa398c56027290a9e6e4fd14f635458ec581 to qt-aml-tzdata-releaseq_tzdata_aml_297100400q_tzdata_aml_297100300q_tzdata_aml_297100000q_tzdata_aml_296200000q_tzdata_aml_295600118q_tzdata_aml_295600110q_tzdata_aml_295500002q_tzdata_aml_295500001q_tzdata_aml_294400310android-mainline-12.0.0_r54android-mainline-12.0.0_r111android-mainline-10.0.0_r13android-mainline-10.0.0_r12android-mainline-10.0.0_r11q_tzdata_aml_297100000android12-mainline-tzdata-releaseandroid10-mainline-tzdata-releaseandroid10-android13-mainline-tzdata-release
Change-Id: If4916a588c0e85189c29cccd566a4ac49ec6328e
537 files changed, 4194 insertions, 20555 deletions
@@ -14,8 +14,8 @@ // limitations under the License. // -version_name = "1.23-asop" -version_code = "417000410" +version_name = "1.20-asop" +version_code = "417000328" android_app { name: "LiveTv", @@ -44,13 +44,16 @@ android_app { static_libs: [ "android-support-annotations", "android-support-compat", - "android-support-v7-recyclerview", - "androidx.legacy_legacy-support-core-ui", - "androidx.leanback_leanback", - "androidx.leanback_leanback-preference", - "androidx.palette_palette", - "androidx.preference_preference", + "android-support-core-ui", "androidx.tvprovider_tvprovider", + "android-support-v4", + "android-support-v7-appcompat", + "android-support-v7-palette", + "android-support-v7-preference", + "android-support-v7-recyclerview", + "android-support-v14-preference", + "android-support-v17-leanback", + "android-support-v17-preference-leanback", "jsr330", "live-channels-partner-support", "live-tv-tuner-proto", @@ -59,7 +62,6 @@ android_app { "tv-auto-factory-jar", "tv-common", "tv-error-prone-annotations-jar", - "tv-javax-annotations-jar", "tv-lib-dagger", "tv-lib-exoplayer", "tv-lib-exoplayer-v2-core", diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 7110160f..a3988239 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -16,12 +16,12 @@ --> <!-- This manifest is for LiveTv --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" + xmlns:tools="http://schemas.android.com/tools" package="com.android.tv" > <uses-sdk android:minSdkVersion="23" - android:targetSdkVersion="28" /> + android:targetSdkVersion="27" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> @@ -79,7 +79,8 @@ android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/Theme.TV" - tools:replace="android:appComponentFactory" > + tools:replace="android:appComponentFactory"> + > <!-- providers are listed here to keep them separate from the internal versions --> <provider @@ -253,16 +254,12 @@ android:name="com.android.tv.recommendation.ChannelPreviewUpdater$ChannelPreviewUpdateService" android:permission="android.permission.BIND_JOB_SERVICE" /> - <receiver - android:name="com.android.tv.receiver.BootCompletedReceiver" - android:exported="true" > + <receiver android:name="com.android.tv.receiver.BootCompletedReceiver" > <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver> - <receiver - android:name="com.android.tv.receiver.PackageIntentsReceiver" - android:exported="true" > + <receiver android:name="com.android.tv.receiver.PackageIntentsReceiver" > <intent-filter> <action android:name="android.intent.action.PACKAGE_ADDED" /> <!-- PACKAGE_CHANGED for package enabled/disabled notification --> @@ -293,13 +290,11 @@ android:name="com.android.tv.dvr.recorder.DvrRecordingService" android:label="@string/dvr_service_name" /> - <receiver - android:name="com.android.tv.dvr.recorder.DvrStartRecordingReceiver" - android:exported="false" /> + <receiver android:name="com.android.tv.dvr.recorder.DvrStartRecordingReceiver" /> <service android:name="com.android.tv.data.epg.EpgFetchService" android:permission="android.permission.BIND_JOB_SERVICE" /> </application> -</manifest>
\ No newline at end of file +</manifest> @@ -2,6 +2,18 @@ __Live TV__ is the Open Source reference application for watching TV on Android TVs. +## Source + +The source of truth is an internal google repository (aka google3) at +cs/third_party/java_src/android_app/live_channels + +Changes are made in the google3 repository and automatically pushed here. + +The following files are only in the android repository and must be changed there. + +* *.mk +* \*\*/lib/\*.\* + ## AOSP instructions To install LiveTv diff --git a/assets/rating_sources.html b/assets/rating_sources.html index ff4a0052..50da7cc7 100644 --- a/assets/rating_sources.html +++ b/assets/rating_sources.html @@ -89,22 +89,4 @@ <pre> Source: http://www.mpaa.org/film-ratings/ </pre> -<ul> - <li>TV content rating system strings for DTMB</li> -</ul> -<pre> - Source: http://www.gb688.cn/bzgk/gb/newGbInfo?hcno=59E83CA701AEB4248E115BC043688FEC -</pre> -<ul> - <li>Implementations details of TV content rating system strings for New Zealand</li> -</ul> -<pre> - Source: https://bsa.govt.nz/images/03_BSA_FREE-TO-AIR-TV_CLASSIFICATIONS_DRAFT.pdf -</pre> -<ul> - <li>TV content rating system strings for Thailand</li> -</ul> -<pre> - Source: https://broadcast.nbtc.go.th/law/dwl.php?id=NjAwODAwMDAwMDAx&file=ZGF0YS9kb2N1bWVudC9sYXcvZG9jL3RoLzYwMDgwMDAwMDAwMS5wZGY= -</pre> </body></html> diff --git a/build.gradle b/build.gradle index 10cddcc1..23e3dbd1 100644 --- a/build.gradle +++ b/build.gradle @@ -18,28 +18,37 @@ /* * Experimental gradle configuration. This file may not be up to date. */ -apply plugin: 'com.android.application' buildscript { repositories { + mavenCentral() google() - jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.4.2' - classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.10' + classpath 'com.android.tools.build:gradle:3.1.4' + classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.6' } } - +apply plugin: 'com.android.application' android { compileSdkVersion 28 buildToolsVersion '28.0.3' - - compileOptions() { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + dexOptions { + preDexLibraries = false + additionalParameters=['--core-library'] + javaMaxHeapSize "6g" + } + android { + defaultConfig { + resConfigs "en" + } + } + defaultConfig { + minSdkVersion 23 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" } - buildTypes { debug { minifyEnabled false @@ -48,15 +57,10 @@ android { minifyEnabled true } } - - defaultConfig { - minSdkVersion 23 - resConfigs "en" - targetSdkVersion 28 - versionCode 1 - versionName "1.0" + compileOptions() { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 } - sourceSets { main { res.srcDirs = ['res', 'material_res'] @@ -66,33 +70,30 @@ android { } } -allprojects { - repositories { - google() - jcenter() - } +repositories { + mavenCentral() + jcenter() + google() } dependencies { - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.core:core:1.0.2' - implementation 'androidx.palette:palette:1.0.0' - implementation 'androidx.leanback:leanback:1.1.0-alpha02' - implementation 'androidx.recyclerview:recyclerview:1.0.0' - implementation 'androidx.recyclerview:recyclerview-selection:1.0.0' - implementation 'androidx.tvprovider:tvprovider:1.0.0' - - annotationProcessor 'com.google.auto.factory:auto-factory:1.0-beta6' - implementation 'com.google.auto.factory:auto-factory:1.0-beta6' - annotationProcessor 'com.google.auto.value:auto-value:1.5.3' - implementation 'com.google.auto.value:auto-value:1.5.3' - implementation 'com.google.dagger:dagger:2.23' - implementation 'com.google.dagger:dagger-android:2.23' - annotationProcessor 'com.google.dagger:dagger-android-processor:2.23' - annotationProcessor 'com.google.dagger:dagger-compiler:2.23' - implementation 'com.google.guava:guava:28.0-jre' + implementation 'androidx.appcompat:appcompat:1.0.2' + implementation 'androidx.palette:palette:1.0.0' + implementation 'androidx.leanback:leanback:1.0.0' + implementation "androidx.tvprovider:tvprovider:1.0.0" + implementation "androidx.recyclerview:recyclerview:1.0.0" + implementation "androidx.recyclerview:recyclerview-selection:1.0.0" + implementation "androidx.palette:palette:1.0.0" - implementation 'javax.inject:javax.inject:1' + implementation 'com.google.dagger:dagger:2.18' + implementation 'com.google.dagger:dagger-android:2.18' + annotationProcessor 'com.google.dagger:dagger-compiler:2.18' + annotationProcessor 'com.google.dagger:dagger-android-processor:2.18' - implementation project(':common') -} + /*Not building with latest one (1.6.3)*/ + annotationProcessor 'com.google.auto.value:auto-value:1.5.4' + implementation 'com.google.auto.value:auto-value:1.5.4' + implementation 'javax.inject:javax.inject:1' + implementation 'com.google.guava:guava:26.0-android' + implementation project(':common') +}
\ No newline at end of file diff --git a/common/Android.bp b/common/Android.bp index 728587f6..63759d40 100644 --- a/common/Android.bp +++ b/common/Android.bp @@ -28,28 +28,22 @@ android_library { resource_dirs: ["res"], libs: [ - "android-support-annotations", "tv-auto-value-jar", "tv-auto-factory-jar", + "android-support-annotations", "tv-error-prone-annotations-jar", - "tv-javax-annotations-jar", - + "tv-guava-android-jar", + "jsr330", + "tv-lib-dagger", + "tv-lib-exoplayer", + "tv-lib-exoplayer-v2-core", + "android-support-compat", + "android-support-core-ui", + "android-support-v7-recyclerview", + "android-support-v17-leanback", ], - static_libs: [ - "androidx.legacy_legacy-support-core-ui", - "androidx.appcompat_appcompat", - "androidx.preference_preference", - "androidx.leanback_leanback", - "androidx.tvprovider_tvprovider", - "tv-guava-android-jar", - "tv-guava-failureaccess-jar", - "jsr330", - "tv-lib-dagger", - "tv-lib-exoplayer", - "tv-lib-exoplayer-v2-core", - "tv-lib-dagger-android", - ], + static_libs: ["tv-lib-dagger-android"], plugins: [ "tv-auto-value", diff --git a/common/AndroidManifest.xml b/common/AndroidManifest.xml index eb7de572..7002d5fb 100644 --- a/common/AndroidManifest.xml +++ b/common/AndroidManifest.xml @@ -17,6 +17,6 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.tv.common" android:versionCode="1"> - <uses-sdk android:targetSdkVersion="28" android:minSdkVersion="23"/> + <uses-sdk android:targetSdkVersion="27" android:minSdkVersion="23"/> <application /> </manifest> diff --git a/common/build.gradle b/common/build.gradle index b7bc8865..f3714758 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -21,24 +21,37 @@ apply plugin: 'com.android.library' apply plugin: 'com.google.protobuf' - +buildscript { + repositories { + mavenCentral() + google() + } + dependencies { + classpath 'com.android.tools.build:gradle:3.1.4' + classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.6' + } +} android { compileSdkVersion 28 buildToolsVersion '28.0.3' + dexOptions { + preDexLibraries = false + additionalParameters = ['--core-library'] + javaMaxHeapSize "6g" + } - compileOptions() { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + android { + defaultConfig { + resConfigs "en" + } } defaultConfig { minSdkVersion 23 - resConfigs "en" targetSdkVersion 28 versionCode 1 versionName "1.0" } - buildTypes { debug { minifyEnabled false @@ -53,6 +66,10 @@ android { buildConfigField "boolean", "NO_JNI_TEST", "false" } } + compileOptions() { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } sourceSets { main { @@ -62,32 +79,29 @@ android { proto { srcDir 'src/com/android/tv/common/compat/internal' } - proto { - srcDir 'src/com/android/tv/common/flags/proto' - } } } } -dependencies { - implementation 'androidx.annotation:annotation:1.1.0' - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.leanback:leanback:1.1.0-alpha02' - implementation 'androidx.palette:palette:1.0.0' - implementation 'androidx.recyclerview:recyclerview:1.0.0' - implementation 'androidx.recyclerview:recyclerview-selection:1.0.0' - implementation 'androidx.tvprovider:tvprovider:1.0.0' +repositories { + mavenCentral() + google() +} - implementation 'com.google.android.exoplayer:exoplayer:r1.5.16' - implementation 'com.google.android.exoplayer:exoplayer-core:2.10.1' - annotationProcessor 'com.google.auto.value:auto-value:1.5.3' - implementation 'com.google.auto.value:auto-value:1.5.3' - implementation 'com.google.dagger:dagger:2.23' - implementation 'com.google.dagger:dagger-android:2.23' - annotationProcessor 'com.google.dagger:dagger-android-processor:2.23' - annotationProcessor 'com.google.dagger:dagger-compiler:2.23' - implementation 'com.google.guava:guava:28.0-jre' - implementation 'com.google.protobuf:protobuf-java:3.0.0' +dependencies { + implementation 'androidx.appcompat:appcompat:1.0.2' + implementation 'androidx.palette:palette:1.0.0' + implementation 'androidx.leanback:leanback:1.0.0' + implementation "androidx.tvprovider:tvprovider:1.0.0" + implementation "androidx.recyclerview:recyclerview:1.0.0" + implementation "androidx.recyclerview:recyclerview-selection:1.0.0" + implementation "androidx.palette:palette:1.0.0" + implementation 'com.google.guava:guava:26.0-android' + implementation 'com.google.protobuf:protobuf-java:3.0.0' + implementation 'com.google.dagger:dagger:2.18' + implementation 'com.google.dagger:dagger-android:2.18' + annotationProcessor 'com.google.dagger:dagger-compiler:2.18' + annotationProcessor 'com.google.dagger:dagger-android-processor:2.18' } protobuf { // Configure the protoc executable diff --git a/common/src/com/android/tv/common/BaseApplication.java b/common/src/com/android/tv/common/BaseApplication.java index 1a421209..45c32567 100644 --- a/common/src/com/android/tv/common/BaseApplication.java +++ b/common/src/com/android/tv/common/BaseApplication.java @@ -21,22 +21,17 @@ import android.content.Context; import android.os.Build; import android.os.StrictMode; import android.support.annotation.VisibleForTesting; - -import com.android.tv.common.dev.DeveloperPreferences; import com.android.tv.common.feature.CommonFeatures; import com.android.tv.common.recording.RecordingStorageStatusManager; import com.android.tv.common.util.Clock; import com.android.tv.common.util.CommonUtils; import com.android.tv.common.util.Debug; - -import dagger.Lazy; +import com.android.tv.common.util.SystemProperties; import dagger.android.DaggerApplication; -import javax.inject.Inject; - -/** The base application class for TV applications. */ +/** The base application class for Live TV applications. */ public abstract class BaseApplication extends DaggerApplication implements BaseSingletons { - @Inject Lazy<RecordingStorageStatusManager> mRecordingStorageStatusManager; + private RecordingStorageStatusManager mRecordingStorageStatusManager; /** * An instance of {@link BaseSingletons}. Note that this can be set directly only for the test @@ -70,7 +65,7 @@ public abstract class BaseApplication extends DaggerApplication implements BaseS // Only set StrictMode for ENG builds because the build server only produces userdebug // builds. - if (BuildConfig.ENG && DeveloperPreferences.ALLOW_STRICT_MODE.get(this)) { + if (BuildConfig.ENG && SystemProperties.ALLOW_STRICT_MODE.getValue()) { StrictMode.ThreadPolicy.Builder threadPolicyBuilder = new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog(); // TODO(b/69565157): Turn penaltyDeath on for VMPolicy when tests are fixed. @@ -104,6 +99,9 @@ public abstract class BaseApplication extends DaggerApplication implements BaseS @Override @TargetApi(Build.VERSION_CODES.N) public RecordingStorageStatusManager getRecordingStorageStatusManager() { - return mRecordingStorageStatusManager.get(); + if (mRecordingStorageStatusManager == null) { + mRecordingStorageStatusManager = new RecordingStorageStatusManager(this); + } + return mRecordingStorageStatusManager; } } diff --git a/common/src/com/android/tv/common/BaseSingletons.java b/common/src/com/android/tv/common/BaseSingletons.java index 8a3820d1..10530617 100644 --- a/common/src/com/android/tv/common/BaseSingletons.java +++ b/common/src/com/android/tv/common/BaseSingletons.java @@ -18,28 +18,15 @@ package com.android.tv.common; import com.android.tv.common.buildtype.HasBuildType; import com.android.tv.common.flags.has.HasCloudEpgFlags; +import com.android.tv.common.flags.has.HasConcurrentDvrPlaybackFlags; import com.android.tv.common.recording.RecordingStorageStatusManager; import com.android.tv.common.util.Clock; /** Injection point for the base app */ -public interface BaseSingletons extends HasCloudEpgFlags, HasBuildType { +public interface BaseSingletons + extends HasCloudEpgFlags, HasBuildType, HasConcurrentDvrPlaybackFlags { - /* - * Do not add any new methods here. - * - * To move a getter to Injection. - * 1. Make a type injectable @Singleton. - * 2. Mark the getter here as deprecated. - * 3. Lazily inject the object in TvApplication. - * 4. Move easy usages of getters to injection instead. - * 5. Delete the method when all usages are migrated. - */ - - /* @deprecated use injection instead. */ - @Deprecated Clock getClock(); - /* @deprecated use injection instead. */ - @Deprecated RecordingStorageStatusManager getRecordingStorageStatusManager(); } diff --git a/common/src/com/android/tv/common/buildtype/BuildTypeModule.java b/common/src/com/android/tv/common/buildtype/BuildTypeModule.java deleted file mode 100644 index 43f398d5..00000000 --- a/common/src/com/android/tv/common/buildtype/BuildTypeModule.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2019 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.common.buildtype; - -import dagger.Module; -import dagger.Provides; -import dagger.Reusable; - -/** Provides BuildType */ -@Module -public class BuildTypeModule { - private static final HasBuildType.BuildType BUILD_TYPE = - BuildTypeFactory.create().getBuildType(); - - @Provides - @Reusable - HasBuildType.BuildType providesBuildType() { - return BUILD_TYPE; - } -} diff --git a/common/src/com/android/tv/common/buildtype/HasBuildType.java b/common/src/com/android/tv/common/buildtype/HasBuildType.java index addac07e..7d5677c9 100644 --- a/common/src/com/android/tv/common/buildtype/HasBuildType.java +++ b/common/src/com/android/tv/common/buildtype/HasBuildType.java @@ -30,7 +30,5 @@ public interface HasBuildType { PROD } - /** @deprecated use injection instead. */ - @Deprecated BuildType getBuildType(); } diff --git a/common/src/com/android/tv/common/compat/TvInputInfoCompat.java b/common/src/com/android/tv/common/compat/TvInputInfoCompat.java index 2f06d943..685a3ed9 100644 --- a/common/src/com/android/tv/common/compat/TvInputInfoCompat.java +++ b/common/src/com/android/tv/common/compat/TvInputInfoCompat.java @@ -45,12 +45,13 @@ public class TvInputInfoCompat { private final Context mContext; private final TvInputInfo mTvInputInfo; - private boolean mAudioOnly; - private boolean mAudioAttributeInit = false; + private final boolean mAudioOnly; public TvInputInfoCompat(Context context, TvInputInfo tvInputInfo) { mContext = context; mTvInputInfo = tvInputInfo; + // TODO(b/112938832): use tvInputInfo.isAudioOnly() when SDK is updated + mAudioOnly = Boolean.parseBoolean(getExtras().get(ATTRIBUTE_NAME_AUDIO_ONLY)); } public TvInputInfo getTvInputInfo() { @@ -58,11 +59,6 @@ public class TvInputInfoCompat { } public boolean isAudioOnly() { - // TODO(b/112938832): use tvInputInfo.isAudioOnly() when SDK is updated - if (!mAudioAttributeInit) { - mAudioOnly = Boolean.parseBoolean(getExtras().get(ATTRIBUTE_NAME_AUDIO_ONLY)); - mAudioAttributeInit = true; - } return mAudioOnly; } diff --git a/common/src/com/android/tv/common/compat/internal/recording_commands.proto b/common/src/com/android/tv/common/compat/internal/recording_commands.proto index c247e781..ce59bfa0 100644 --- a/common/src/com/android/tv/common/compat/internal/recording_commands.proto +++ b/common/src/com/android/tv/common/compat/internal/recording_commands.proto @@ -19,7 +19,6 @@ // package and should not be used outside it. syntax = "proto3"; - package android.tv.common.compat.internal; option java_outer_classname = "RecordingCommands"; diff --git a/common/src/com/android/tv/common/compat/internal/recording_events.proto b/common/src/com/android/tv/common/compat/internal/recording_events.proto index fffa62ab..68db5ddf 100644 --- a/common/src/com/android/tv/common/compat/internal/recording_events.proto +++ b/common/src/com/android/tv/common/compat/internal/recording_events.proto @@ -18,7 +18,6 @@ // support new features on older devices. NOTE: this proto is internal to this // package and should not be used outside it. syntax = "proto3"; - package android.tv.common.compat.internal; option java_outer_classname = "RecordingEvents"; @@ -47,3 +46,4 @@ message RecordingStarted { // Recording URI. string uri = 1; } + diff --git a/common/src/com/android/tv/common/compat/internal/tif_commands.proto b/common/src/com/android/tv/common/compat/internal/tif_commands.proto index b69d4870..d5867703 100644 --- a/common/src/com/android/tv/common/compat/internal/tif_commands.proto +++ b/common/src/com/android/tv/common/compat/internal/tif_commands.proto @@ -19,7 +19,6 @@ // package and should not be used outside it. syntax = "proto3"; - package android.tv.common.compat.internal; option java_outer_classname = "Commands"; diff --git a/common/src/com/android/tv/common/compat/internal/tif_events.proto b/common/src/com/android/tv/common/compat/internal/tif_events.proto index b15a884a..6e71ae11 100644 --- a/common/src/com/android/tv/common/compat/internal/tif_events.proto +++ b/common/src/com/android/tv/common/compat/internal/tif_events.proto @@ -18,7 +18,6 @@ // support new features on older devices. NOTE: this proto is internal to this // package and should not be used outside it. syntax = "proto3"; - package android.tv.common.compat.internal; option java_outer_classname = "Events"; diff --git a/common/src/com/android/tv/common/customization/CustomizationManager.java b/common/src/com/android/tv/common/customization/CustomizationManager.java index 5a29d7c0..09ecaef8 100644 --- a/common/src/com/android/tv/common/customization/CustomizationManager.java +++ b/common/src/com/android/tv/common/customization/CustomizationManager.java @@ -97,8 +97,8 @@ public class CustomizationManager { /** * Returns {@code true} if there's a customization package installed and it specifies built-in - * tuner devices are available. The built-in tuner should support DVB API to be recognized by TV - * app. + * tuner devices are available. The built-in tuner should support DVB API to be recognized by + * Live TV. */ public static boolean hasLinuxDvbBuiltInTuner(Context context) { if (sHasLinuxDvbBuiltInTuner == null) { @@ -156,26 +156,11 @@ public class CustomizationManager { private static String getCustomizationPackageName(Context context) { if (sCustomizationPackage == null) { - sCustomizationPackage = ""; List<PackageInfo> packageInfos = context.getPackageManager() .getPackagesHoldingPermissions(CUSTOMIZE_PERMISSIONS, 0); - if (packageInfos.size() != 0) { - /** Iterate through all packages returning the first vendor customizer */ - for (PackageInfo packageInfo : packageInfos) { - if (packageInfo.packageName.startsWith("com.android") == false) { - sCustomizationPackage = packageInfo.packageName; - break; - } - } - - /** If no vendor package found, return first in the list */ - if (sCustomizationPackage == "") { - sCustomizationPackage = packageInfos.get(0).packageName; - } - } + sCustomizationPackage = packageInfos.size() == 0 ? "" : packageInfos.get(0).packageName; } - return sCustomizationPackage; } diff --git a/common/src/com/android/tv/common/dagger/ApplicationModule.java b/common/src/com/android/tv/common/dagger/ApplicationModule.java index be9cf885..4655f777 100644 --- a/common/src/com/android/tv/common/dagger/ApplicationModule.java +++ b/common/src/com/android/tv/common/dagger/ApplicationModule.java @@ -21,10 +21,8 @@ import android.content.Context; import android.os.Looper; import com.android.tv.common.dagger.annotations.ApplicationContext; import com.android.tv.common.dagger.annotations.MainLooper; -import com.android.tv.common.util.Clock; import dagger.Module; import dagger.Provides; -import dagger.Reusable; /** * Provides application-scope qualifiers for the {@link Application}, the application context, and @@ -59,10 +57,4 @@ public final class ApplicationModule { ContentResolver provideContentResolver() { return mApplication.getContentResolver(); } - - @Provides - @Reusable - static Clock providesClock() { - return Clock.SYSTEM; - } } diff --git a/common/src/com/android/tv/common/dagger/init/SafePreDaggerInitializer.java b/common/src/com/android/tv/common/dagger/init/SafePreDaggerInitializer.java deleted file mode 100644 index 9465d929..00000000 --- a/common/src/com/android/tv/common/dagger/init/SafePreDaggerInitializer.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2019 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.common.dagger.init; - -import android.content.Context; -import android.util.Log; - -/** - * Initializes objects one time only. - * - * <p>This is needed because ContentProviders can be created before Application.onCreate - */ -public final class SafePreDaggerInitializer { - private interface Initialize { - void init(Context context); - } - - private static final String TAG = "SafePreDaggerInitializer"; - - private static boolean initialized = false; - private static Context oldContext; - - private static final Initialize[] sList = - new Initialize[] { - /* Begin_AOSP_Comment_Out - com.google.android.libraries.phenotype.client.PhenotypeContext::setContext - End_AOSP_Comment_Out */ - }; - - public static synchronized void init(Context context) { - if (!initialized) { - for (Initialize i : sList) { - i.init(context); - } - oldContext = context; - initialized = true; - } else if (oldContext != context) { - Log.w( - TAG, - "init called more than once, skipping. Old context was " - + oldContext - + " new context is " - + context); - } - } - - private SafePreDaggerInitializer() {} -} diff --git a/common/src/com/android/tv/common/dev/DeveloperPreference.java b/common/src/com/android/tv/common/dev/DeveloperPreference.java deleted file mode 100644 index b1c401b0..00000000 --- a/common/src/com/android/tv/common/dev/DeveloperPreference.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2019 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.common.dev; - -import android.content.Context; -import android.content.SharedPreferences; -import android.support.annotation.Nullable; -import android.support.annotation.VisibleForTesting; - -/** Preferences available to developers */ -public abstract class DeveloperPreference<T> { - - private static final String PREFERENCE_FILE_NAME = - "com.android.tv.common.dev.DeveloperPreference"; - - /** - * Create a boolean developer preference. - * - * @param key the developer setting key. - * @param defaultValue the value to return if the setting is undefined or empty. - */ - public static DeveloperPreference<Boolean> create(String key, boolean defaultValue) { - return new DeveloperBooleanPreference(key, defaultValue); - } - - @VisibleForTesting - static final SharedPreferences getPreferences(Context context) { - return context.getSharedPreferences(PREFERENCE_FILE_NAME, Context.MODE_PRIVATE); - } - - /** - * Create a int developer preference. - * - * @param key the developer setting key. - * @param defaultValue the value to return if the setting is undefined or empty. - */ - public static DeveloperPreference<Integer> create(String key, int defaultValue) { - return new DeveloperIntegerPreference(key, defaultValue); - } - - final String mKey; - final T mDefaultValue; - private T mValue; - - private DeveloperPreference(String key, T defaultValue) { - mKey = key; - mValue = null; - mDefaultValue = defaultValue; - } - - /** Set the value. */ - public final void set(Context context, T value) { - mValue = value; - storeValue(context, value); - } - - protected abstract void storeValue(Context context, T value); - - /** Get the current value, or the default if the value is not set. */ - public final T get(Context context) { - mValue = getStoredValue(context); - return mValue; - } - - /** Get the current value, or the default if the value is not set or context is null. */ - public final T getDefaultIfContextNull(@Nullable Context context) { - return context == null ? mDefaultValue : getStoredValue(context); - } - - protected abstract T getStoredValue(Context context); - - /** - * Clears the current value. - * - * <p>Future calls to {@link #get(Context)} will return the default value. - */ - public final void clear(Context context) { - getPreferences(context).edit().remove(mKey); - } - - @Override - public final String toString() { - return "[" + mKey + "]=" + mValue + " Default value : " + mDefaultValue; - } - - private static final class DeveloperBooleanPreference extends DeveloperPreference<Boolean> { - - private DeveloperBooleanPreference(String key, Boolean defaultValue) { - super(key, defaultValue); - } - - @Override - public void storeValue(Context context, Boolean value) { - getPreferences(context).edit().putBoolean(mKey, value).apply(); - } - - @Override - public Boolean getStoredValue(Context context) { - return getPreferences(context).getBoolean(mKey, mDefaultValue); - } - } - - private static final class DeveloperIntegerPreference extends DeveloperPreference<Integer> { - - private DeveloperIntegerPreference(String key, Integer defaultValue) { - super(key, defaultValue); - } - - @Override - protected void storeValue(Context context, Integer value) { - getPreferences(context).edit().putInt(mKey, value).apply(); - } - - @Override - protected Integer getStoredValue(Context context) { - return getPreferences(context).getInt(mKey, mDefaultValue); - } - } -} diff --git a/common/src/com/android/tv/common/dev/DeveloperPreferences.java b/common/src/com/android/tv/common/dev/DeveloperPreferences.java deleted file mode 100644 index 9c83b649..00000000 --- a/common/src/com/android/tv/common/dev/DeveloperPreferences.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2019 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.common.dev; - -/** A class about the constants for TV Developer preferences. */ -public final class DeveloperPreferences { - - /** - * Allow Google Analytics for eng builds. - * - * <p>Defaults to {@code false}. - */ - public static final DeveloperPreference<Boolean> ALLOW_ANALYTICS_IN_ENG = - DeveloperPreference.create("tv_allow_analytics_in_eng", false); - - /** - * Allow Strict mode for debug builds. - * - * <p>Defaults to {@code true}. - */ - public static final DeveloperPreference<Boolean> ALLOW_STRICT_MODE = - DeveloperPreference.create("tv_allow_strict_mode", true); - - /** - * When true {@link android.view.KeyEvent}s are logged. - * - * <p>Defaults to {@code false}. - */ - public static final DeveloperPreference<Boolean> LOG_KEYEVENT = - DeveloperPreference.create("tv_log_keyevent", false); - - /** - * When true debug keys are used. - * - * <p>Defaults to {@code false}. - */ - public static final DeveloperPreference<Boolean> USE_DEBUG_KEYS = - DeveloperPreference.create("tv_use_debug_keys", false); - - /** - * Send {@link com.android.tv.analytics.Tracker} information. - * - * <p>Defaults to {@code true}. - */ - public static final DeveloperPreference<Boolean> USE_TRACKER = - DeveloperPreference.create("tv_use_tracker", true); - - /** - * Maximum buffer size in MegaBytes. - * - * <p>Defaults to 2MB. - */ - public static final DeveloperPreference<Integer> MAX_BUFFER_SIZE_MBYTES = - DeveloperPreference.create("tv.tuner.buffersize_mbytes", 2 * 1024); - - private DeveloperPreferences() {} -} diff --git a/common/src/com/android/tv/common/experiments/ExperimentFlag.java b/common/src/com/android/tv/common/experiments/ExperimentFlag.java new file mode 100644 index 00000000..b8370ad6 --- /dev/null +++ b/common/src/com/android/tv/common/experiments/ExperimentFlag.java @@ -0,0 +1,96 @@ +/* + * 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.common.experiments; + +import android.support.annotation.VisibleForTesting; +import com.android.tv.common.BuildConfig; + +import com.google.common.base.Supplier; + +/** Experiments return values based on user, device and other criteria. */ +public final class ExperimentFlag<T> { + + // NOTE: sAllowOverrides IS NEVER USED in the non AOSP version. + private static boolean sAllowOverrides = false; + + @VisibleForTesting + public static void initForTest() { + /* Begin_AOSP_Comment_Out + if (!BuildConfig.AOSP) { + PhenotypeFlag.initForTest(); + return; + } + End_AOSP_Comment_Out */ + sAllowOverrides = true; + } + + /** Returns a boolean experiment */ + public static ExperimentFlag<Boolean> createFlag( +// AOSP_Comment_Out Supplier<Boolean> phenotypeFlag, + boolean defaultValue) { + return new ExperimentFlag<>( +// AOSP_Comment_Out phenotypeFlag, + defaultValue); + } + + private final T mDefaultValue; +// AOSP_Comment_Out private final Supplier<T> mPhenotypeFlag; + +// AOSP_Comment_Out // NOTE: mOverrideValue IS NEVER USED in the non AOSP version. + private T mOverrideValue = null; + // mOverridden IS NEVER USED in the non AOSP version. + private boolean mOverridden = false; + + private ExperimentFlag( +// AOSP_Comment_Out Supplier<T> phenotypeFlag, + // NOTE: defaultValue IS NEVER USED in the non AOSP version. + T defaultValue) { + mDefaultValue = defaultValue; +// AOSP_Comment_Out mPhenotypeFlag = phenotypeFlag; + } + + /** Returns value for this experiment */ + public T get() { + /* Begin_AOSP_Comment_Out + if (!BuildConfig.AOSP) { + return mPhenotypeFlag.get(); + } + End_AOSP_Comment_Out */ + return sAllowOverrides && mOverridden ? mOverrideValue : mDefaultValue; + } + + @VisibleForTesting + public void override(T t) { + + if (sAllowOverrides) { + mOverridden = true; + mOverrideValue = t; + } + } + + @VisibleForTesting + public void resetOverride() { + mOverridden = false; + } + + /* Begin_AOSP_Comment_Out + @VisibleForTesting + T getAospDefaultValueForTesting() { + return mDefaultValue; + } + End_AOSP_Comment_Out */ +} diff --git a/common/src/com/android/tv/common/flags/impl/DefaultMessagesFlags.java b/common/src/com/android/tv/common/experiments/ExperimentLoader.java index f2130a33..5f012e11 100644 --- a/common/src/com/android/tv/common/flags/impl/DefaultMessagesFlags.java +++ b/common/src/com/android/tv/common/experiments/ExperimentLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * 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. @@ -13,18 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.tv.common.flags.impl; -/** - * Default flag values for {@link - * com.android.tv.common.flags.MessagesFlags}. - */ -public final class DefaultMessagesFlags - implements com.android.tv.common.flags.MessagesFlags { +package com.android.tv.common.experiments; - @Override - public boolean compiled() { - return true; - } +import android.content.Context; +/** Used to sync {@link ExperimentFlag}s. */ +public class ExperimentLoader { + + /** Starts a background task to update {@link ExperimentFlag}s */ + public void asyncRefreshExperiments(Context context) { + // Override for your experiment system + } } diff --git a/common/src/com/android/tv/common/experiments/Experiments.java b/common/src/com/android/tv/common/experiments/Experiments.java new file mode 100644 index 00000000..9bfdb547 --- /dev/null +++ b/common/src/com/android/tv/common/experiments/Experiments.java @@ -0,0 +1,64 @@ +/* + * 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.common.experiments; + +import static com.android.tv.common.experiments.ExperimentFlag.createFlag; + +import com.android.tv.common.BuildConfig; +// AOSP_Comment_Out import com.android.tv.common.flags.LiveChannels; + +/** + * Set of experiments visible in AOSP. + * + * <p>This file is maintained by hand. + */ +public final class Experiments { + public static final ExperimentFlag<Boolean> ENABLE_UNRATED_CONTENT_SETTINGS = + ExperimentFlag.createFlag( +// AOSP_Comment_Out LiveChannels::enableUnratedContentSettings, + false); + + /** Turn analytics on or off based on the System Checkbox for logging. */ + public static final ExperimentFlag<Boolean> ENABLE_ANALYTICS_VIA_CHECKBOX = + createFlag( +// AOSP_Comment_Out LiveChannels::enableAnalyticsViaCheckbox, + false); + + /** + * Allow developer features such as the dev menu and other aids. + * + * <p>These features are available to select users(aka fishfooders) on production builds. + */ + public static final ExperimentFlag<Boolean> ENABLE_DEVELOPER_FEATURES = + ExperimentFlag.createFlag( +// AOSP_Comment_Out LiveChannels::enableDeveloperFeatures, + BuildConfig.ENG); + + /** + * Allow QA features. + * + * <p>These features must be carefully limited, keeping QA differences to a minimum. + * + * <p>These features are available to select users(aka QA) on production builds. + */ + public static final ExperimentFlag<Boolean> ENABLE_QA_FEATURES = + ExperimentFlag.createFlag( +// AOSP_Comment_Out LiveChannels::enableQaFeatures, + false); + + private Experiments() {} +} diff --git a/common/src/com/android/tv/common/feature/CommonFeatures.java b/common/src/com/android/tv/common/feature/CommonFeatures.java index abe4c1df..04052a7c 100644 --- a/common/src/com/android/tv/common/feature/CommonFeatures.java +++ b/common/src/com/android/tv/common/feature/CommonFeatures.java @@ -23,14 +23,12 @@ import static com.android.tv.common.feature.TestableFeature.createTestableFeatur import android.content.Context; import android.util.Log; - import com.android.tv.common.flags.has.HasCloudEpgFlags; import com.android.tv.common.util.LocationUtils; - import com.android.tv.common.flags.CloudEpgFlags; /** - * List of {@link Feature} that affect more than just the TV app. + * List of {@link Feature} that affect more than just the Live TV app. * * <p>Remove the {@code Feature} once it is launched. */ @@ -54,7 +52,7 @@ public class CommonFeatures { * <p>Enables dvr recording regardless of storage status. */ public static final Feature FORCE_RECORDING_UNTIL_NO_SPACE = - DeveloperPreferenceFeature.create("force_recording_until_no_space", false); + PropertyFeature.create("force_recording_until_no_space", false); /** Show postal code fragment before channel scan. */ public static final Feature ENABLE_CLOUD_EPG_REGION = diff --git a/common/src/com/android/tv/common/feature/DeveloperPreferenceFeature.java b/common/src/com/android/tv/common/feature/DeveloperPreferenceFeature.java deleted file mode 100644 index 1f98547a..00000000 --- a/common/src/com/android/tv/common/feature/DeveloperPreferenceFeature.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2019 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.common.feature; - -import android.content.Context; - -import com.android.tv.common.dev.DeveloperPreference; - -/** A {@link Feature} based on {@link DeveloperPreference<Boolean>}. */ -public class DeveloperPreferenceFeature implements Feature { - - private final DeveloperPreference<Boolean> mPreference; - - /** - * Create a developer preference feature. - * - * @param key the developer setting key. - * @param defaultValue the value to return if the setting is undefined or empty. - */ - public static DeveloperPreferenceFeature create(String key, boolean defaultValue) { - return from(DeveloperPreference.create(key, defaultValue)); - } - - /** - * Create a developer preference feature from an exiting {@link DeveloperPreference<Boolean>}. - */ - public static DeveloperPreferenceFeature from( - DeveloperPreference<Boolean> developerPreference) { - return new DeveloperPreferenceFeature(developerPreference); - } - - private DeveloperPreferenceFeature(DeveloperPreference<Boolean> mPreference) { - this.mPreference = mPreference; - } - - @Override - public boolean isEnabled(Context context) { - return mPreference.get(context); - } - - @Override - public String toString() { - return mPreference.toString(); - } -} diff --git a/common/src/com/android/tv/common/feature/PermissionFeature.java b/common/src/com/android/tv/common/feature/ExperimentFeature.java index 02611785..820eda49 100644 --- a/common/src/com/android/tv/common/feature/PermissionFeature.java +++ b/common/src/com/android/tv/common/feature/ExperimentFeature.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * 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. @@ -17,22 +17,28 @@ package com.android.tv.common.feature; import android.content.Context; -import android.content.pm.PackageManager; +import com.android.tv.common.experiments.ExperimentFlag; -/** A feature that is only available when {@code permissionName} is granted. */ -public class PermissionFeature implements Feature { +/** A {@link Feature} base on an {@link ExperimentFlag}. */ +public final class ExperimentFeature implements Feature { - public static final PermissionFeature DVB_DEVICE_PERMISSION = - new PermissionFeature("android.permission.DVB_DEVICE"); + public static Feature from(ExperimentFlag<Boolean> flag) { + return new ExperimentFeature(flag); + } - private final String permissionName; + private final ExperimentFlag<Boolean> mFlag; - private PermissionFeature(String permissionName) { - this.permissionName = permissionName; + private ExperimentFeature(ExperimentFlag<Boolean> flag) { + mFlag = flag; } @Override public boolean isEnabled(Context context) { - return context.checkSelfPermission(permissionName) == PackageManager.PERMISSION_GRANTED; + return mFlag.get(); + } + + @Override + public String toString() { + return "ExperimentFeature for " + mFlag; } } diff --git a/common/src/com/android/tv/common/feature/FeatureUtils.java b/common/src/com/android/tv/common/feature/FeatureUtils.java index e6192cd4..aaed6c82 100644 --- a/common/src/com/android/tv/common/feature/FeatureUtils.java +++ b/common/src/com/android/tv/common/feature/FeatureUtils.java @@ -17,6 +17,7 @@ package com.android.tv.common.feature; import android.content.Context; +import com.android.tv.common.BuildConfig; import com.android.tv.common.util.CommonUtils; import java.util.Arrays; @@ -70,6 +71,23 @@ public class FeatureUtils { } }; } + /** + * A feature available in AOSP. + * + * @param googleFeature the feature used in non AOSP builds + * @param aospFeature the feature used in AOSP builds + */ + public static Feature aospFeature( +// AOSP_Comment_Out final Feature googleFeature, + final Feature aospFeature) { + /* Begin_AOSP_Comment_Out + if (!BuildConfig.AOSP) { + return googleFeature; + } else { + End_AOSP_Comment_Out */ + return aospFeature; +// AOSP_Comment_Out } + } /** * Returns a feature that is opposite of the given {@code feature}. diff --git a/common/src/com/android/tv/common/feature/Model.java b/common/src/com/android/tv/common/feature/Model.java index 450cd216..7aa5148e 100644 --- a/common/src/com/android/tv/common/feature/Model.java +++ b/common/src/com/android/tv/common/feature/Model.java @@ -21,11 +21,10 @@ import android.content.Context; /** Holder for {@link android.os.Build#MODEL} features. */ public interface Model { - ModelFeature ARCHER = new ModelFeature("Archer"); ModelFeature NEXUS_PLAYER = new ModelFeature("Nexus Player"); /** True when the {@link android.os.Build#MODEL} equals the {@code model} given. */ - final class ModelFeature implements Feature { + public static final class ModelFeature implements Feature { private final String mModel; private ModelFeature(String model) { diff --git a/common/src/com/android/tv/common/feature/Sdk.java b/common/src/com/android/tv/common/feature/Sdk.java index 54bc1bbd..4b0a925f 100644 --- a/common/src/com/android/tv/common/feature/Sdk.java +++ b/common/src/com/android/tv/common/feature/Sdk.java @@ -29,6 +29,8 @@ public final class Sdk { public static final Feature AT_LEAST_O = new AtLeast(VERSION_CODES.O); + public static final Feature AT_LEAST_P = new AtLeast(VERSION_CODES.P); // AOSP_OC:strip_line + private static final class AtLeast implements Feature { private final int versionCode; diff --git a/common/src/com/android/tv/common/flags/BackendKnobsFlags.java b/common/src/com/android/tv/common/flags/BackendKnobsFlags.java index 3b65df56..69bac7a0 100644 --- a/common/src/com/android/tv/common/flags/BackendKnobsFlags.java +++ b/common/src/com/android/tv/common/flags/BackendKnobsFlags.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License */ - package com.android.tv.common.flags; /** Flags for tuning non ui behavior */ @@ -27,8 +26,8 @@ public interface BackendKnobsFlags { */ boolean compiled(); - /** Number of channels to batch together when fetching programs */ - long epgFetcherChannelsPerProgramFetch(); + /** Enable fetching only part of the program data. */ + boolean enablePartialProgramFetch(); /** EPG fetcher interval in hours */ long epgFetcherIntervalHour(); @@ -36,6 +35,9 @@ public interface BackendKnobsFlags { /** Target channel count for EPG. It is used to adjust the EPG length */ long epgTargetChannelCount(); + /** Enables fetching a few hours of programs only when the epg is scrolled to that time. */ + boolean fetchProgramsAsNeeded(); + /** How many hours of programs are loaded in the program guide for during the initial fetch */ long programGuideInitialFetchHours(); diff --git a/common/src/com/android/tv/common/flags/CloudEpgFlags.java b/common/src/com/android/tv/common/flags/CloudEpgFlags.java index db2789c3..ab4c6a17 100755 --- a/common/src/com/android/tv/common/flags/CloudEpgFlags.java +++ b/common/src/com/android/tv/common/flags/CloudEpgFlags.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License */ - package com.android.tv.common.flags; /** Flags for Cloud EPG */ @@ -30,6 +29,6 @@ public interface CloudEpgFlags { /** Is the device in a region supported by Cloud Epg */ boolean supportedRegion(); - /** List of input ids that the TV app will update their EPG. */ + /** List of input ids that Live TV will update their EPG. */ String thirdPartyEpgInputsCsv(); } diff --git a/common/src/com/android/tv/common/flags/MessagesFlags.java b/common/src/com/android/tv/common/flags/ConcurrentDvrPlaybackFlags.java index 596442fe..1afff793 100755 --- a/common/src/com/android/tv/common/flags/MessagesFlags.java +++ b/common/src/com/android/tv/common/flags/ConcurrentDvrPlaybackFlags.java @@ -13,17 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License */ - package com.android.tv.common.flags; -/** - * Message flags. - * - * <p>Used to hide new messages until all translations are ready. - * - * <p>Production releases never include the messages protected by these flags. - */ -public interface MessagesFlags { +/** Flags allowing concurrent DVR playback */ +public interface ConcurrentDvrPlaybackFlags { /** * Whether or not this feature is compiled into this build. @@ -32,4 +25,10 @@ public interface MessagesFlags { * code generation. */ boolean compiled(); + + /** Enable playback of DVR playback during recording */ + boolean enabled(); + + /** Enable tuner using recording data for playback in onTune */ + boolean onTuneUsesRecording(); } diff --git a/common/src/com/android/tv/common/flags/DvrFlags.java b/common/src/com/android/tv/common/flags/DvrFlags.java deleted file mode 100755 index 9deae1f7..00000000 --- a/common/src/com/android/tv/common/flags/DvrFlags.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2019 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.common.flags; - -/** DVR flags */ -public interface DvrFlags { - - /** - * Whether or not this feature is compiled into this build. - * - * <p>This returns true by default, unless the is_compiled_selector parameter was set during - * code generation. - */ - boolean compiled(); - - /** Allow user to customize timings of program recordings. */ - boolean startEarlyEndLateEnabled(); - - /** Store and use the video aspect ratio in recordings. */ - boolean storeVideoAspectRatio(); -} diff --git a/common/src/com/android/tv/common/flags/LegacyFlags.java b/common/src/com/android/tv/common/flags/LegacyFlags.java deleted file mode 100755 index d0cb1e44..00000000 --- a/common/src/com/android/tv/common/flags/LegacyFlags.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2019 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.common.flags; - -/** Legacy flags */ -public interface LegacyFlags { - - /** - * Whether or not this feature is compiled into this build. - * - * <p>This returns true by default, unless the is_compiled_selector parameter was set during - * code generation. - */ - boolean compiled(); - - /** Enable Developer Features */ - boolean enableDeveloperFeatures(); - - /** Enable QA Features */ - boolean enableQaFeatures(); - - /** Enable Unrated Content Settings */ - boolean enableUnratedContentSettings(); -} diff --git a/common/src/com/android/tv/common/flags/SetupFlags.java b/common/src/com/android/tv/common/flags/SetupFlags.java deleted file mode 100755 index 0a7f2002..00000000 --- a/common/src/com/android/tv/common/flags/SetupFlags.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2019 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.common.flags; - -/** Flags for changing setup behavior */ -public interface SetupFlags { - - /** - * Whether or not this feature is compiled into this build. - * - * <p>This returns true by default, unless the is_compiled_selector parameter was set during - * code generation. - */ - boolean compiled(); - - /** Packages allowed to send intents to SetupPassthroughActivity. */ - com.android.tv.common.flags.proto.TypedFeatures.StringListParam - setupPassThroughPackageWhitelist(); - - /** Use a whitelist for packages allowed to start SetupPassthroughActivity */ - boolean useWhitelistForSetupPassThrough(); -} diff --git a/common/src/com/android/tv/common/flags/TunerFlags.java b/common/src/com/android/tv/common/flags/TunerFlags.java index 5ecfb5bf..5f899b90 100755 --- a/common/src/com/android/tv/common/flags/TunerFlags.java +++ b/common/src/com/android/tv/common/flags/TunerFlags.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License */ - package com.android.tv.common.flags; /** Flags for tuner */ @@ -27,6 +26,9 @@ public interface TunerFlags { */ boolean compiled(); + /** Tune using current recording if available. */ + boolean tuneUsingRecording(); + /** Enable using exoplayer V2 */ boolean useExoplayerV2(); } diff --git a/common/src/com/android/tv/common/flags/UiFlags.java b/common/src/com/android/tv/common/flags/UiFlags.java index 2bd8a59d..4c88d08a 100755 --- a/common/src/com/android/tv/common/flags/UiFlags.java +++ b/common/src/com/android/tv/common/flags/UiFlags.java @@ -13,10 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License */ - package com.android.tv.common.flags; -/** Flags for TV app UI */ +/** Flags for Live TV UI */ public interface UiFlags { /** @@ -27,9 +26,6 @@ public interface UiFlags { */ boolean compiled(); - /** Critic Ratings */ - boolean enableCriticRatings(); - /** * Number of days to be shown by Recording History. * @@ -38,5 +34,8 @@ public interface UiFlags { long maxHistoryDays(); /** Unhide the launcher all the time */ - boolean unhideLauncher(); + boolean uhideLauncher(); + + /** Use the Leanback Pin Picker */ + boolean useLeanbackPinPicker(); } diff --git a/common/src/com/android/tv/common/flags/StartupFlags.java b/common/src/com/android/tv/common/flags/has/HasConcurrentDvrPlaybackFlags.java index 2f64c9fe..b4710875 100755..100644 --- a/common/src/com/android/tv/common/flags/StartupFlags.java +++ b/common/src/com/android/tv/common/flags/has/HasConcurrentDvrPlaybackFlags.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * 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. @@ -13,20 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License */ +package com.android.tv.common.flags.has; -package com.android.tv.common.flags; +import android.content.Context; +import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags; -/** Flags for TV App startup */ -public interface StartupFlags { +/** Has {@link ConcurrentDvrPlaybackFlags} */ +public interface HasConcurrentDvrPlaybackFlags { - /** - * Whether or not this feature is compiled into this build. - * - * <p>This returns true by default, unless the is_compiled_selector parameter was set during - * code generation. - */ - boolean compiled(); + static ConcurrentDvrPlaybackFlags fromContext(Context context) { + return ((HasConcurrentDvrPlaybackFlags) HasUtils.getApplicationContext(context)) + .getConcurrentDvrPlaybackFlags(); + } - /** InputId's that will not be warmed up on MainActivity creation. */ - com.android.tv.common.flags.proto.TypedFeatures.StringListParam warmupInputidBlacklist(); + ConcurrentDvrPlaybackFlags getConcurrentDvrPlaybackFlags(); } diff --git a/common/src/com/android/tv/common/flags/impl/DefaultBackendKnobsFlags.java b/common/src/com/android/tv/common/flags/impl/DefaultBackendKnobsFlags.java index 5302842b..a189e473 100644 --- a/common/src/com/android/tv/common/flags/impl/DefaultBackendKnobsFlags.java +++ b/common/src/com/android/tv/common/flags/impl/DefaultBackendKnobsFlags.java @@ -25,8 +25,8 @@ public final class DefaultBackendKnobsFlags } @Override - public long epgFetcherChannelsPerProgramFetch() { - return 50; + public boolean enablePartialProgramFetch() { + return false; } @Override @@ -35,8 +35,13 @@ public final class DefaultBackendKnobsFlags } @Override + public boolean fetchProgramsAsNeeded() { + return false; + } + + @Override public long programGuideInitialFetchHours() { - return 4; + return 8; } @Override diff --git a/common/src/com/android/tv/common/flags/impl/DefaultDvrFlags.java b/common/src/com/android/tv/common/flags/impl/DefaultConcurrentDvrPlaybackFlags.java index 09f7b4f3..8d8c584a 100644 --- a/common/src/com/android/tv/common/flags/impl/DefaultDvrFlags.java +++ b/common/src/com/android/tv/common/flags/impl/DefaultConcurrentDvrPlaybackFlags.java @@ -15,9 +15,10 @@ */ package com.android.tv.common.flags.impl; -/** Flags for tuning non ui behavior. */ -public final class DefaultDvrFlags - implements com.android.tv.common.flags.DvrFlags { +import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags; + +/** Default flags for Concurrent DVR Playback */ +public final class DefaultConcurrentDvrPlaybackFlags implements ConcurrentDvrPlaybackFlags { @Override public boolean compiled() { @@ -25,12 +26,12 @@ public final class DefaultDvrFlags } @Override - public boolean startEarlyEndLateEnabled() { + public boolean enabled() { return false; } @Override - public boolean storeVideoAspectRatio() { + public boolean onTuneUsesRecording() { return false; } } diff --git a/common/src/com/android/tv/common/flags/impl/DefaultFlagsModule.java b/common/src/com/android/tv/common/flags/impl/DefaultFlagsModule.java index 10be34b5..49352364 100644 --- a/common/src/com/android/tv/common/flags/impl/DefaultFlagsModule.java +++ b/common/src/com/android/tv/common/flags/impl/DefaultFlagsModule.java @@ -18,12 +18,9 @@ package com.android.tv.common.flags.impl; import dagger.Module; import dagger.Provides; import dagger.Reusable; - import com.android.tv.common.flags.BackendKnobsFlags; import com.android.tv.common.flags.CloudEpgFlags; -import com.android.tv.common.flags.DvrFlags; -import com.android.tv.common.flags.LegacyFlags; -import com.android.tv.common.flags.StartupFlags; +import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags; import com.android.tv.common.flags.TunerFlags; import com.android.tv.common.flags.UiFlags; @@ -45,20 +42,8 @@ public class DefaultFlagsModule { @Provides @Reusable - DvrFlags provideDvrFlags() { - return new DefaultDvrFlags(); - } - - @Provides - @Reusable - LegacyFlags provideLegacyFlags() { - return DefaultLegacyFlags.DEFAULT; - } - - @Provides - @Reusable - StartupFlags provideStartupFlags() { - return new DefaultStartupFlags(); + ConcurrentDvrPlaybackFlags provideConcurrentDvrPlaybackFlags() { + return new DefaultConcurrentDvrPlaybackFlags(); } @Provides diff --git a/common/src/com/android/tv/common/flags/impl/DefaultLegacyFlags.java b/common/src/com/android/tv/common/flags/impl/DefaultLegacyFlags.java deleted file mode 100644 index 52142416..00000000 --- a/common/src/com/android/tv/common/flags/impl/DefaultLegacyFlags.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2019 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.common.flags.impl; - -import com.google.auto.value.AutoValue; -import com.android.tv.common.flags.LegacyFlags; - -/** Default {@link LegacyFlags}. */ -@AutoValue -public abstract class DefaultLegacyFlags implements LegacyFlags { - public static final DefaultLegacyFlags DEFAULT = DefaultLegacyFlags.builder().build(); - - public static Builder builder() { - return new AutoValue_DefaultLegacyFlags.Builder() - .compiled(true) - .enableDeveloperFeatures(false) - .enableQaFeatures(false) - .enableUnratedContentSettings(false); - } - - /** Builder for {@link LegacyFlags} */ - @AutoValue.Builder - public abstract static class Builder { - public abstract Builder compiled(boolean value); - - public abstract Builder enableDeveloperFeatures(boolean value); - - public abstract Builder enableQaFeatures(boolean value); - - public abstract Builder enableUnratedContentSettings(boolean value); - - public abstract DefaultLegacyFlags build(); - } -} diff --git a/common/src/com/android/tv/common/flags/impl/DefaultStartupFlags.java b/common/src/com/android/tv/common/flags/impl/DefaultStartupFlags.java deleted file mode 100644 index 3eb6edc6..00000000 --- a/common/src/com/android/tv/common/flags/impl/DefaultStartupFlags.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2019 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.common.flags.impl; - -import com.android.tv.common.flags.proto.TypedFeatures.StringListParam; -import com.android.tv.common.flags.StartupFlags; - -/** Default {@link StartupFlags} */ -public class DefaultStartupFlags implements StartupFlags { - @Override - public boolean compiled() { - return true; - } - - @Override - public StringListParam warmupInputidBlacklist() { - return StringListParam.getDefaultInstance(); - } -} diff --git a/common/src/com/android/tv/common/flags/impl/DefaultTunerFlags.java b/common/src/com/android/tv/common/flags/impl/DefaultTunerFlags.java index 2d12e368..195953bc 100644 --- a/common/src/com/android/tv/common/flags/impl/DefaultTunerFlags.java +++ b/common/src/com/android/tv/common/flags/impl/DefaultTunerFlags.java @@ -26,6 +26,11 @@ public class DefaultTunerFlags implements TunerFlags { } @Override + public boolean tuneUsingRecording() { + return false; + } + + @Override public boolean useExoplayerV2() { return false; } diff --git a/common/src/com/android/tv/common/flags/impl/DefaultUiFlags.java b/common/src/com/android/tv/common/flags/impl/DefaultUiFlags.java index 43f0dea0..fce45853 100644 --- a/common/src/com/android/tv/common/flags/impl/DefaultUiFlags.java +++ b/common/src/com/android/tv/common/flags/impl/DefaultUiFlags.java @@ -17,7 +17,7 @@ package com.android.tv.common.flags.impl; import com.android.tv.common.flags.UiFlags; -/** Default Flags for TV app UI */ +/** Default Flags for Live TV UI */ public class DefaultUiFlags implements UiFlags { @Override @@ -26,17 +26,17 @@ public class DefaultUiFlags implements UiFlags { } @Override - public boolean enableCriticRatings() { + public boolean uhideLauncher() { return false; } @Override - public boolean unhideLauncher() { + public boolean useLeanbackPinPicker() { return false; } @Override public long maxHistoryDays() { - return 0; + return 7; } } diff --git a/common/src/com/android/tv/common/flags/impl/SettableFlagsModule.java b/common/src/com/android/tv/common/flags/impl/SettableFlagsModule.java deleted file mode 100644 index ab4ebd34..00000000 --- a/common/src/com/android/tv/common/flags/impl/SettableFlagsModule.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2019 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.common.flags.impl; - -import dagger.Module; -import dagger.Provides; -import dagger.Reusable; - -import com.android.tv.common.flags.BackendKnobsFlags; -import com.android.tv.common.flags.CloudEpgFlags; -import com.android.tv.common.flags.DvrFlags; -import com.android.tv.common.flags.LegacyFlags; -import com.android.tv.common.flags.SetupFlags; -import com.android.tv.common.flags.StartupFlags; -import com.android.tv.common.flags.TunerFlags; -import com.android.tv.common.flags.UiFlags; - -/** Provides public fields for each flag so they can be changed before injection. */ -@Module -public class SettableFlagsModule { - - public DefaultBackendKnobsFlags backendKnobsFlags = new DefaultBackendKnobsFlags(); - public DefaultCloudEpgFlags cloudEpgFlags = new DefaultCloudEpgFlags(); - public DefaultDvrFlags dvrFlags = new DefaultDvrFlags(); - public DefaultLegacyFlags legacyFlags = DefaultLegacyFlags.DEFAULT; - public DefaultSetupFlags setupFlags = new DefaultSetupFlags(); - public DefaultStartupFlags startupFlags = new DefaultStartupFlags(); - public DefaultTunerFlags tunerFlags = new DefaultTunerFlags(); - public DefaultUiFlags uiFlags = new DefaultUiFlags(); - - @Provides - @Reusable - BackendKnobsFlags provideBackendKnobsFlags() { - return backendKnobsFlags; - } - - @Provides - @Reusable - CloudEpgFlags provideCloudEpgFlags() { - return cloudEpgFlags; - } - - @Provides - @Reusable - DvrFlags provideDvrFlags() { - return dvrFlags; - } - - @Provides - @Reusable - LegacyFlags provideLegacyFlags() { - return legacyFlags; - } - - @Provides - @Reusable - SetupFlags provideSetupFlags() { - return setupFlags; - } - - @Provides - @Reusable - StartupFlags provideStartupFlags() { - return startupFlags; - } - - @Provides - @Reusable - TunerFlags provideTunerFlags() { - return tunerFlags; - } - - @Provides - @Reusable - UiFlags provideUiFlags() { - return uiFlags; - } -} diff --git a/common/src/com/android/tv/common/flags/proto/typed-features.proto b/common/src/com/android/tv/common/flags/proto/typed-features.proto deleted file mode 100644 index 855d7311..00000000 --- a/common/src/com/android/tv/common/flags/proto/typed-features.proto +++ /dev/null @@ -1,20 +0,0 @@ -syntax = "proto2"; - -package android.tv.common.flags; - -option java_outer_classname = "TypedFeatures"; -option java_package = "com.android.tv.common.flags.proto"; - -// These messages are to specify feature params that are a list of integers. -message Int32ListParam { - repeated int32 element = 1; -} - -message Int64ListParam { - repeated int64 element = 1; -} - -// This message is to specify feature params that are a list of strings. -message StringListParam { - repeated string element = 1; -} diff --git a/common/src/com/android/tv/common/recording/RecordingStorageStatusManager.java b/common/src/com/android/tv/common/recording/RecordingStorageStatusManager.java index 3552a66f..0fb864bd 100644 --- a/common/src/com/android/tv/common/recording/RecordingStorageStatusManager.java +++ b/common/src/com/android/tv/common/recording/RecordingStorageStatusManager.java @@ -28,11 +28,8 @@ import android.support.annotation.AnyThread; import android.support.annotation.IntDef; import android.support.annotation.WorkerThread; import android.util.Log; - import com.android.tv.common.SoftPreconditions; -import com.android.tv.common.dagger.annotations.ApplicationContext; import com.android.tv.common.feature.CommonFeatures; - import java.io.File; import java.io.IOException; import java.lang.annotation.Retention; @@ -41,13 +38,10 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; -import javax.inject.Inject; -import javax.inject.Singleton; - /** Signals DVR storage status change such as plugging/unplugging. */ -@Singleton public class RecordingStorageStatusManager { private static final String TAG = "RecordingStorageStatusManager"; + private static final boolean DEBUG = false; /** Minimum storage size to support DVR */ public static final long MIN_STORAGE_SIZE_FOR_DVR_IN_BYTES = 50 * 1024 * 1024 * 1024L; // 50GB @@ -149,8 +143,7 @@ public class RecordingStorageStatusManager { * * @param context {@link Context} */ - @Inject - public RecordingStorageStatusManager(@ApplicationContext Context context) { + public RecordingStorageStatusManager(final Context context) { mContext = context; mMountedStorageStatus = getStorageStatusInternal(); mStorageValid = mMountedStorageStatus.isValidForDvr(); diff --git a/common/src/com/android/tv/common/singletons/HasTvInputId.java b/common/src/com/android/tv/common/singletons/HasTvInputId.java index 49cf3d2e..4bc0a21c 100644 --- a/common/src/com/android/tv/common/singletons/HasTvInputId.java +++ b/common/src/com/android/tv/common/singletons/HasTvInputId.java @@ -18,8 +18,8 @@ package com.android.tv.common.singletons; /** * Has TunerInputId. * - * <p>This is used buy both the tuner to get its input id and by the TV app to get the embedded - * tuner input id. + * <p>This is used buy both the tuner to get its input id and by the Live TV to get the + * embedded tuner input id. */ public interface HasTvInputId { diff --git a/common/src/com/android/tv/common/support/tvprovider/README.md b/common/src/com/android/tv/common/support/tvprovider/README.md deleted file mode 100644 index a24dc288..00000000 --- a/common/src/com/android/tv/common/support/tvprovider/README.md +++ /dev/null @@ -1,6 +0,0 @@ -## support provider - -This is preview code destined to be put in androidx.tvprovider.media.tv - - -All classes here must have an associated bug to move to androidx diff --git a/common/src/com/android/tv/common/support/tvprovider/TvContractCompatX.java b/common/src/com/android/tv/common/support/tvprovider/TvContractCompatX.java deleted file mode 100644 index 353e3421..00000000 --- a/common/src/com/android/tv/common/support/tvprovider/TvContractCompatX.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2019 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.common.support.tvprovider; - -import android.net.Uri; -import android.support.annotation.Nullable; -import androidx.tvprovider.media.tv.TvContractCompat; - -/** - * Extensions to the contract between the TV provider and applications. Contains definitions for the - * supported URIs and columns. - * - * <p>TODO(b/126921088): move this to androidx. - */ -public final class TvContractCompatX { - - /** - * Builds a URI that points to a specific channel. - * - * @param inputPackage the package of the input. - * @param internalProviderId the internal provider id - */ - public static Uri buildChannelUri( - @Nullable String inputPackage, @Nullable String internalProviderId) { - Uri.Builder uri = TvContractCompat.Channels.CONTENT_URI.buildUpon(); - if (inputPackage != null) { - uri.appendQueryParameter("package", inputPackage); - } - if (internalProviderId != null) { - uri.appendQueryParameter( - TvContractCompat.Channels.COLUMN_INTERNAL_PROVIDER_ID, internalProviderId); - } - return uri.build(); - } - - /** - * Builds a URI that points to all programs on a given channel. - * - * @param inputPackage the package of the input. - * @param internalProviderId the internal provider id - */ - public static Uri buildProgramsUriForChannel( - @Nullable String inputPackage, @Nullable String internalProviderId) { - Uri.Builder uri = TvContractCompat.Programs.CONTENT_URI.buildUpon(); - if (inputPackage != null) { - uri.appendQueryParameter("package", inputPackage); - } - if (internalProviderId != null) { - uri.appendQueryParameter( - TvContractCompat.Channels.COLUMN_INTERNAL_PROVIDER_ID, internalProviderId); - } - return uri.build(); - } - - /** - * Builds a URI that points to programs on a specific channel whose schedules overlap with the - * given time frame. - * - * @param inputPackage the package of the input. - * @param internalProviderId the internal provider id - * @param startTime The start time used to filter programs. The returned programs should have - * {@link TvContractCompat.Programs#COLUMN_END_TIME_UTC_MILLIS} that is greater than this - * time. - * @param endTime The end time used to filter programs. The returned programs should have {@link - * TvContractCompat.Programs#COLUMN_START_TIME_UTC_MILLIS} that is less than this time. - */ - public static Uri buildProgramsUriForChannel( - @Nullable String inputPackage, - @Nullable String internalProviderId, - long startTime, - long endTime) { - return buildProgramsUriForChannel(inputPackage, internalProviderId) - .buildUpon() - .appendQueryParameter(TvContractCompat.PARAM_START_TIME, String.valueOf(startTime)) - .appendQueryParameter(TvContractCompat.PARAM_END_TIME, String.valueOf(endTime)) - .build(); - } - - /** - * Builds a URI that points to programs whose schedules overlap with the given time frame. - * - * @param startTime The start time used to filter programs. The returned programs should have - * {@link TvContractCompat.Programs#COLUMN_END_TIME_UTC_MILLIS} that is greater than this - * time. - * @param endTime The end time used to filter programs. The returned programs should have {@link - * TvContractCompat.Programs#COLUMN_START_TIME_UTC_MILLIS} that is less than this time. - */ - public static Uri buildProgramsUri(long startTime, long endTime) { - return TvContractCompat.Programs.CONTENT_URI - .buildUpon() - .appendQueryParameter(TvContractCompat.PARAM_START_TIME, String.valueOf(startTime)) - .appendQueryParameter(TvContractCompat.PARAM_END_TIME, String.valueOf(endTime)) - .build(); - } -} diff --git a/common/src/com/android/tv/common/ui/setup/SetupGuidedStepFragment.java b/common/src/com/android/tv/common/ui/setup/SetupGuidedStepFragment.java index 2a6ceec5..3c76c269 100644 --- a/common/src/com/android/tv/common/ui/setup/SetupGuidedStepFragment.java +++ b/common/src/com/android/tv/common/ui/setup/SetupGuidedStepFragment.java @@ -19,11 +19,11 @@ package com.android.tv.common.ui.setup; import static android.content.Context.ACCESSIBILITY_SERVICE; import android.os.Bundle; -import androidx.leanback.app.GuidedStepFragment; -import androidx.leanback.widget.GuidanceStylist; -import androidx.leanback.widget.GuidedAction; -import androidx.leanback.widget.GuidedActionsStylist; -import androidx.leanback.widget.VerticalGridView; +import android.support.v17.leanback.app.GuidedStepFragment; +import android.support.v17.leanback.widget.GuidanceStylist; +import android.support.v17.leanback.widget.GuidedAction; +import android.support.v17.leanback.widget.GuidedActionsStylist; +import android.support.v17.leanback.widget.VerticalGridView; import android.view.LayoutInflater; import android.view.View; import android.view.View.AccessibilityDelegate; @@ -53,9 +53,9 @@ public abstract class SetupGuidedStepFragment extends GuidedStepFragment { LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = super.onCreateView(inflater, container, savedInstanceState); Bundle arguments = getArguments(); - view.findViewById(androidx.leanback.R.id.action_fragment_root) + view.findViewById(android.support.v17.leanback.R.id.action_fragment_root) .setPadding(0, 0, 0, 0); - mContentFragment = view.findViewById(androidx.leanback.R.id.content_fragment); + mContentFragment = view.findViewById(android.support.v17.leanback.R.id.content_fragment); LinearLayout.LayoutParams guidanceLayoutParams = (LinearLayout.LayoutParams) mContentFragment.getLayoutParams(); guidanceLayoutParams.weight = 0; @@ -69,7 +69,7 @@ public abstract class SetupGuidedStepFragment extends GuidedStepFragment { getResources() .getDimensionPixelOffset(R.dimen.setup_done_button_container_width); // Guided actions list - View list = view.findViewById(androidx.leanback.R.id.guidedactions_list); + View list = view.findViewById(android.support.v17.leanback.R.id.guidedactions_list); MarginLayoutParams marginLayoutParams = (MarginLayoutParams) list.getLayoutParams(); // Use content view to check layout direction while view is being created. if (getResources().getConfiguration().getLayoutDirection() @@ -93,12 +93,12 @@ public abstract class SetupGuidedStepFragment extends GuidedStepFragment { gridView.setWindowAlignmentOffset(offset); gridView.setWindowAlignmentOffsetPercent(0); gridView.setItemAlignmentOffsetPercent(0); - ((ViewGroup) view.findViewById(androidx.leanback.R.id.guidedactions_list)) + ((ViewGroup) view.findViewById(android.support.v17.leanback.R.id.guidedactions_list)) .setTransitionGroup(false); // Needed for the shared element transition. // content_frame is defined in leanback. ViewGroup group = - (ViewGroup) view.findViewById(androidx.leanback.R.id.content_frame); + (ViewGroup) view.findViewById(android.support.v17.leanback.R.id.content_frame); group.setClipChildren(false); group.setClipToPadding(false); return view; diff --git a/common/src/com/android/tv/common/ui/setup/SetupMultiPaneFragment.java b/common/src/com/android/tv/common/ui/setup/SetupMultiPaneFragment.java index ee00e9fb..c02d3f56 100644 --- a/common/src/com/android/tv/common/ui/setup/SetupMultiPaneFragment.java +++ b/common/src/com/android/tv/common/ui/setup/SetupMultiPaneFragment.java @@ -112,15 +112,15 @@ public abstract class SetupMultiPaneFragment extends SetupFragment { @Override protected int[] getParentIdsForDelay() { return new int[] { - androidx.leanback.R.id.content_fragment, - androidx.leanback.R.id.guidedactions_list + android.support.v17.leanback.R.id.content_fragment, + android.support.v17.leanback.R.id.guidedactions_list }; } @Override public int[] getSharedElementIds() { return new int[] { - androidx.leanback.R.id.action_fragment_background, R.id.done_button_container + android.support.v17.leanback.R.id.action_fragment_background, R.id.done_button_container }; } } diff --git a/common/src/com/android/tv/common/ui/setup/animation/TranslationAnimationCreator.java b/common/src/com/android/tv/common/ui/setup/animation/TranslationAnimationCreator.java index 59706936..13b89ea1 100644 --- a/common/src/com/android/tv/common/ui/setup/animation/TranslationAnimationCreator.java +++ b/common/src/com/android/tv/common/ui/setup/animation/TranslationAnimationCreator.java @@ -20,7 +20,7 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; import android.graphics.Path; -import androidx.leanback.R; +import android.support.v17.leanback.R; import android.transition.Transition; import android.transition.TransitionValues; import android.view.View; @@ -29,9 +29,9 @@ import android.view.View; * This class is used by Slide and Explode to create an animator that goes from the start position * to the end position. It takes into account the canceled position so that it will not blink out or * shift suddenly when the transition is interrupted. The original class is - * androidx.leanback.transition.TranslationAnimationCreator which is hidden. + * android.support.v17.leanback.transition.TranslationAnimationCreator which is hidden. */ -// Copied from androidx.leanback.transition.TransltaionAnimationCreator +// Copied from android.support.v17.leanback.transition.TransltaionAnimationCreator class TranslationAnimationCreator { /** * Creates an animator that can be used for x and/or y translations. When interrupted, it sets a diff --git a/common/src/com/android/tv/common/util/CommonUtils.java b/common/src/com/android/tv/common/util/CommonUtils.java index 662f819c..4513a879 100644 --- a/common/src/com/android/tv/common/util/CommonUtils.java +++ b/common/src/com/android/tv/common/util/CommonUtils.java @@ -22,8 +22,10 @@ import android.media.tv.TvInputInfo; import android.os.Build; import android.util.ArraySet; import android.util.Log; +import com.android.tv.common.BuildConfig; import com.android.tv.common.CommonConstants; import com.android.tv.common.actions.InputSetupActionUtils; +import com.android.tv.common.experiments.Experiments; import java.io.File; import java.text.SimpleDateFormat; import java.util.Date; @@ -51,7 +53,6 @@ public final class CommonUtils { static { BUNDLED_PACKAGE_SET.add("com.android.tv"); -// AOSP_Comment_Out BUNDLED_PACKAGE_SET.add(CommonConstants.BASE_PACKAGE); } private static Boolean sRunningInTest; @@ -122,11 +123,16 @@ public final class CommonUtils { return false; } - /** Returns true if the application is packaged with TV app. */ + /** Returns true if the application is packaged with Live TV. */ public static boolean isPackagedWithLiveChannels(Context context) { return (CommonConstants.BASE_PACKAGE.equals(context.getPackageName())); } + /** Returns true if the current user is a developer. */ + public static boolean isDeveloper() { + return BuildConfig.ENG || Experiments.ENABLE_DEVELOPER_FEATURES.get(); + } + /** Converts time in milliseconds to a ISO 8061 string. */ public static String toIsoDateTimeString(long timeMillis) { return ISO_8601.get().format(new Date(timeMillis)); diff --git a/common/src/com/android/tv/common/util/Debug.java b/common/src/com/android/tv/common/util/Debug.java index 8e826aef..ab908741 100644 --- a/common/src/com/android/tv/common/util/Debug.java +++ b/common/src/com/android/tv/common/util/Debug.java @@ -23,11 +23,11 @@ import java.util.concurrent.TimeUnit; /** A class only for help developers. */ public class Debug { /** - * A threshold of start up time, when the start up time of TV app is more than it, a warning - * will show to the developer. + * A threshold of start up time, when the start up time of Live TV is more than it, a + * warning will show to the developer. */ public static final long TIME_START_UP_DURATION_THRESHOLD = TimeUnit.SECONDS.toMillis(6); - /** Tag for measuring start up time of TV app. */ + /** Tag for measuring start up time of Live TV. */ public static final String TAG_START_UP_TIMER = "start_up_timer"; /** A global map for duration timers. */ diff --git a/common/src/com/android/tv/common/util/LocationUtils.java b/common/src/com/android/tv/common/util/LocationUtils.java index 9d44cf21..ee5119eb 100644 --- a/common/src/com/android/tv/common/util/LocationUtils.java +++ b/common/src/com/android/tv/common/util/LocationUtils.java @@ -16,7 +16,9 @@ package com.android.tv.common.util; +import android.Manifest; import android.content.Context; +import android.content.pm.PackageManager; import android.location.Address; import android.location.Geocoder; import android.location.Location; @@ -24,12 +26,13 @@ import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.TextUtils; import android.util.Log; - import com.android.tv.common.BuildConfig; + + + import java.io.IOException; import java.util.Collections; import java.util.HashSet; @@ -62,41 +65,19 @@ public class LocationUtils { if (sApplicationContext == null) { sApplicationContext = context.getApplicationContext(); } - /* Begin_AOSP_Comment_Out - if (!BuildConfig.AOSP) { - com.google.android.tv.livechannels.util.GoogleLocationUtilsHelper.startLocationUpdates( - context, LocationUtils::updateAddress); - return null; - } - End_AOSP_Comment_Out */ LocationUtilsHelper.startLocationUpdates(); return null; } - @Nullable - static String getCurrentPostalCode(Context context) throws IOException { - Address address = getCurrentAddress(context); - if (address != null) { - Log.i( - TAG, - "Current country and postal code is " - + address.getCountryName() - + ", " - + address.getPostalCode()); - return address.getPostalCode(); - } - return null; - } - /** The listener used when address is updated. */ public interface OnUpdateAddressListener { /** * Called when address is updated. * - * <p>This listener is removed when this method returns true. + * This listener is removed when this method returns true. * * @return {@code true} if the job has been finished and the listener needs to be removed; - * {@code false} otherwise. + * {@code false} otherwise. */ boolean onUpdateAddress(Address address); } @@ -104,8 +85,8 @@ public class LocationUtils { /** * Add an {@link OnUpdateAddressListener} instance. * - * <p>Note that the listener is removed automatically when {@link - * OnUpdateAddressListener#onUpdateAddress(Address)} is called and returns {@code true}. + * Note that the listener is removed automatically when + * {@link OnUpdateAddressListener#onUpdateAddress(Address)} is called and returns {@code true}. */ public static void addOnUpdateAddressListener(OnUpdateAddressListener listener) { sOnUpdateAddressListeners.add(listener); @@ -114,8 +95,8 @@ public class LocationUtils { /** * Remove an {@link OnUpdateAddressListener} instance if it exists. * - * <p>Note that the listener will be removed automatically when {@link - * OnUpdateAddressListener#onUpdateAddress(Address)} is called and returns {@code true}. + * Note that the listener will be removed automatically when + * {@link OnUpdateAddressListener#onUpdateAddress(Address)} is called and returns {@code true}. */ public static void removeOnUpdateAddressListener(OnUpdateAddressListener listener) { sOnUpdateAddressListeners.remove(listener); @@ -127,13 +108,6 @@ public class LocationUtils { if (sCountry != null) { return sCountry; } - /* Begin_AOSP_Comment_Out - if (!BuildConfig.AOSP) { - sCountry = - com.google.android.tv.livechannels.util.GoogleLocationUtilsHelper - .getDeviceCountry(context); - } - End_AOSP_Comment_Out */ if (TextUtils.isEmpty(sCountry)) { sCountry = context.getResources().getConfiguration().locale.getCountry(); } diff --git a/common/src/com/android/tv/common/util/NetworkTrafficTags.java b/common/src/com/android/tv/common/util/NetworkTrafficTags.java index 51b6c4dc..3c94aed6 100644 --- a/common/src/com/android/tv/common/util/NetworkTrafficTags.java +++ b/common/src/com/android/tv/common/util/NetworkTrafficTags.java @@ -20,7 +20,7 @@ import android.net.TrafficStats; import android.support.annotation.NonNull; import java.util.concurrent.Executor; -/** Constants for tagging network traffic in the TV app. */ +/** Constants for tagging network traffic in the Live channels app. */ public final class NetworkTrafficTags { public static final int DEFAULT_LIVE_CHANNELS = 1; @@ -43,16 +43,16 @@ public final class NetworkTrafficTags { @Override public void execute(final @NonNull Runnable command) { - // TODO(b/62038127): robolectric does not support lamdas in unbundled apps - delegateExecutor.execute( - () -> { - TrafficStats.setThreadStatsTag(tag); - try { - command.run(); - } finally { - TrafficStats.clearThreadStatsTag(); - } - }); + // TODO(b/62038127): robolectric does not support lamdas in unbundled apps + delegateExecutor.execute( + () -> { + TrafficStats.setThreadStatsTag(tag); + try { + command.run(); + } finally { + TrafficStats.clearThreadStatsTag(); + } + }); } } diff --git a/common/src/com/android/tv/common/util/PermissionUtils.java b/common/src/com/android/tv/common/util/PermissionUtils.java index e241b91a..ca1abdc4 100644 --- a/common/src/com/android/tv/common/util/PermissionUtils.java +++ b/common/src/com/android/tv/common/util/PermissionUtils.java @@ -26,9 +26,6 @@ public class PermissionUtils { private static Boolean sHasAccessAllEpgPermission; private static Boolean sHasAccessWatchedHistoryPermission; private static Boolean sHasModifyParentalControlsPermission; - private static Boolean sHasChangeHdmiCecActiveSource; - private static Boolean sHasReadContentRatingSystem; - public static boolean hasAccessAllEpg(Context context) { if (sHasAccessAllEpgPermission == null) { @@ -73,24 +70,4 @@ public class PermissionUtils { return context.checkSelfPermission("android.permission.WRITE_EXTERNAL_STORAGE") == PackageManager.PERMISSION_GRANTED; } - - public static boolean hasChangeHdmiCecActiveSource(Context context) { - if (sHasChangeHdmiCecActiveSource == null) { - sHasChangeHdmiCecActiveSource = - context.checkSelfPermission( - "android.permission.CHANGE_HDMI_CEC_ACTIVE_SOURCE") - == PackageManager.PERMISSION_GRANTED; - } - return sHasChangeHdmiCecActiveSource; - } - - public static boolean hasReadContetnRatingSystem(Context context) { - if (sHasReadContentRatingSystem == null) { - sHasReadContentRatingSystem = - context.checkSelfPermission( - "android.permission.READ_CONTENT_RATING_SYSTEMS") - == PackageManager.PERMISSION_GRANTED; - } - return sHasReadContentRatingSystem; - } } diff --git a/common/src/com/android/tv/common/util/PostalCodeUtils.java b/common/src/com/android/tv/common/util/PostalCodeUtils.java index 6ca3d48c..c0917af2 100644 --- a/common/src/com/android/tv/common/util/PostalCodeUtils.java +++ b/common/src/com/android/tv/common/util/PostalCodeUtils.java @@ -17,12 +17,12 @@ package com.android.tv.common.util; import android.content.Context; +import android.location.Address; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.text.TextUtils; import android.util.Log; - import com.android.tv.common.CommonPreferences; - import java.io.IOException; import java.util.HashMap; import java.util.Locale; @@ -62,7 +62,7 @@ public class PostalCodeUtils { /** Returns {@code true} if postal code has been changed */ public static boolean updatePostalCode(Context context) throws IOException, SecurityException, NoPostalCodeException { - String postalCode = LocationUtils.getCurrentPostalCode(context); + String postalCode = getPostalCode(context); String lastPostalCode = getLastPostalCode(context); if (TextUtils.isEmpty(postalCode)) { if (TextUtils.isEmpty(lastPostalCode)) { @@ -92,6 +92,21 @@ public class PostalCodeUtils { CommonPreferences.setLastPostalCode(context, postalCode); } + @Nullable + private static String getPostalCode(Context context) throws IOException, SecurityException { + Address address = LocationUtils.getCurrentAddress(context); + if (address != null) { + Log.i( + TAG, + "Current country and postal code is " + + address.getCountryName() + + ", " + + address.getPostalCode()); + return address.getPostalCode(); + } + return null; + } + /** An {@link java.lang.Exception} class to notify no valid postal or zip code is available. */ public static class NoPostalCodeException extends Exception { public NoPostalCodeException() {} diff --git a/common/src/com/android/tv/common/util/SystemProperties.java b/common/src/com/android/tv/common/util/SystemProperties.java index 72920b6b..6ac2907b 100644 --- a/common/src/com/android/tv/common/util/SystemProperties.java +++ b/common/src/com/android/tv/common/util/SystemProperties.java @@ -21,6 +21,25 @@ import com.android.tv.common.BooleanSystemProperty; /** A convenience class for getting TV related system properties. */ public final class SystemProperties { + /** Allow Google Analytics for eng builds. */ + public static final BooleanSystemProperty ALLOW_ANALYTICS_IN_ENG = + new BooleanSystemProperty("tv_allow_analytics_in_eng", false); + + /** Allow Strict mode for debug builds. */ + public static final BooleanSystemProperty ALLOW_STRICT_MODE = + new BooleanSystemProperty("tv_allow_strict_mode", true); + + /** When true {@link android.view.KeyEvent}s are logged. Defaults to false. */ + public static final BooleanSystemProperty LOG_KEYEVENT = + new BooleanSystemProperty("tv_log_keyevent", false); + /** When true debug keys are used. Defaults to false. */ + public static final BooleanSystemProperty USE_DEBUG_KEYS = + new BooleanSystemProperty("tv_use_debug_keys", false); + + /** Send {@link com.android.tv.analytics.Tracker} information. Defaults to {@code true}. */ + public static final BooleanSystemProperty USE_TRACKER = + new BooleanSystemProperty("tv_use_tracker", true); + /** Allow third party inputs. */ public static final BooleanSystemProperty ALLOW_THIRD_PARTY_INPUTS = new BooleanSystemProperty("ro.tv_allow_third_party_inputs", true); diff --git a/common/tests/robotests/src/com/android/tv/common/TvContentRatingCacheTest.java b/common/tests/robotests/src/com/android/tv/common/TvContentRatingCacheTest.java deleted file mode 100644 index 521b2205..00000000 --- a/common/tests/robotests/src/com/android/tv/common/TvContentRatingCacheTest.java +++ /dev/null @@ -1,222 +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.common; - -import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth.assertWithMessage; - -import android.content.ComponentCallbacks2; -import android.media.tv.TvContentRating; - -import com.android.tv.testing.constants.ConfigConstants; -import com.android.tv.testing.constants.TvContentRatingConstants; - -import com.google.common.collect.ImmutableList; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -/** Test for {@link TvContentRatingCache}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class TvContentRatingCacheTest { - /** US_TV_MA and US_TV_Y7 in order */ - public static final String MA_AND_Y7 = - TvContentRatingConstants.STRING_US_TV_MA - + "," - + TvContentRatingConstants.STRING_US_TV_Y7_US_TV_FV; - - /** US_TV_MA and US_TV_Y7 not in order */ - public static final String Y7_AND_MA = - TvContentRatingConstants.STRING_US_TV_Y7_US_TV_FV - + "," - + TvContentRatingConstants.STRING_US_TV_MA; - - final TvContentRatingCache mCache = TvContentRatingCache.getInstance(); - - @Before - public void setUp() { - mCache.performTrimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE); - } - - @After - public void tearDown() { - mCache.performTrimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE); - } - - @Test - public void testGetRatings_US_TV_MA() { - ImmutableList<TvContentRating> result = - mCache.getRatings(TvContentRatingConstants.STRING_US_TV_MA); - assertThat(result).contains(TvContentRatingConstants.CONTENT_RATING_US_TV_MA); - } - - @Test - public void testGetRatings_US_TV_MA_same() { - ImmutableList<TvContentRating> first = - mCache.getRatings(TvContentRatingConstants.STRING_US_TV_MA); - ImmutableList<TvContentRating> second = - mCache.getRatings(TvContentRatingConstants.STRING_US_TV_MA); - assertThat(first).isSameInstanceAs(second); - } - - @Test - public void testGetRatings_US_TV_MA_diffAfterClear() { - ImmutableList<TvContentRating> first = - mCache.getRatings(TvContentRatingConstants.STRING_US_TV_MA); - mCache.performTrimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE); - ImmutableList<TvContentRating> second = - mCache.getRatings(TvContentRatingConstants.STRING_US_TV_MA); - assertThat(first).isNotSameInstanceAs(second); - } - - @Test - public void testGetRatings_TWO_orderDoesNotMatter() { - ImmutableList<TvContentRating> first = mCache.getRatings(MA_AND_Y7); - ImmutableList<TvContentRating> second = mCache.getRatings(Y7_AND_MA); - assertThat(first).isSameInstanceAs(second); - } - - @Test - public void testContentRatingsToString_null() { - String result = TvContentRatingCache.contentRatingsToString(null); - assertWithMessage("ratings string").that(result).isNull(); - } - - @Test - public void testContentRatingsToString_none() { - String result = TvContentRatingCache.contentRatingsToString(ImmutableList.of()); - assertWithMessage("ratings string").that(result).isEmpty(); - } - - @Test - public void testContentRatingsToString_one() { - String result = - TvContentRatingCache.contentRatingsToString( - ImmutableList.of(TvContentRatingConstants.CONTENT_RATING_US_TV_MA)); - assertWithMessage("ratings string") - .that(result) - .isEqualTo(TvContentRatingConstants.STRING_US_TV_MA); - } - - @Test - public void testContentRatingsToString_twoInOrder() { - String result = - TvContentRatingCache.contentRatingsToString( - ImmutableList.of( - TvContentRatingConstants.CONTENT_RATING_US_TV_MA, - TvContentRatingConstants.CONTENT_RATING_US_TV_Y7_US_TV_FV)); - assertWithMessage("ratings string").that(result).isEqualTo(MA_AND_Y7); - } - - @Test - public void testContentRatingsToString_twoNotInOrder() { - String result = - TvContentRatingCache.contentRatingsToString( - ImmutableList.of( - TvContentRatingConstants.CONTENT_RATING_US_TV_Y7_US_TV_FV, - TvContentRatingConstants.CONTENT_RATING_US_TV_MA)); - assertWithMessage("ratings string").that(result).isEqualTo(MA_AND_Y7); - } - - @Test - public void testContentRatingsToString_double() { - String result = - TvContentRatingCache.contentRatingsToString( - ImmutableList.of( - TvContentRatingConstants.CONTENT_RATING_US_TV_MA, - TvContentRatingConstants.CONTENT_RATING_US_TV_MA)); - assertWithMessage("ratings string") - .that(result) - .isEqualTo(TvContentRatingConstants.STRING_US_TV_MA); - } - - @Test - public void testStringToContentRatings_null() { - assertThat(TvContentRatingCache.stringToContentRatings(null)).isEmpty(); - } - - @Test - public void testStringToContentRatings_none() { - assertThat(TvContentRatingCache.stringToContentRatings("")).isEmpty(); - } - - @Test - public void testStringToContentRatings_bad() { - assertThat(TvContentRatingCache.stringToContentRatings("bad")).isEmpty(); - } - - @Test - public void testStringToContentRatings_oneGoodOneBad() { - ImmutableList<TvContentRating> results = - TvContentRatingCache.stringToContentRatings( - TvContentRatingConstants.STRING_US_TV_Y7_US_TV_FV + ",bad"); - assertWithMessage("ratings") - .that(results) - .containsExactly(TvContentRatingConstants.CONTENT_RATING_US_TV_Y7_US_TV_FV); - } - - @Test - public void testStringToContentRatings_one() { - ImmutableList<TvContentRating> results = - TvContentRatingCache.stringToContentRatings( - TvContentRatingConstants.STRING_US_TV_Y7_US_TV_FV); - assertWithMessage("ratings") - .that(results) - .containsExactly(TvContentRatingConstants.CONTENT_RATING_US_TV_Y7_US_TV_FV); - } - - @Test - public void testStringToContentRatings_twoNotInOrder() { - ImmutableList<TvContentRating> results = - TvContentRatingCache.stringToContentRatings(Y7_AND_MA); - assertWithMessage("ratings") - .that(results) - .containsExactly( - TvContentRatingConstants.CONTENT_RATING_US_TV_MA, - TvContentRatingConstants.CONTENT_RATING_US_TV_Y7_US_TV_FV); - } - - @Test - public void testStringToContentRatings_twoInOrder() { - ImmutableList<TvContentRating> results = - TvContentRatingCache.stringToContentRatings(MA_AND_Y7); - assertWithMessage("ratings") - .that(results) - .containsExactly( - TvContentRatingConstants.CONTENT_RATING_US_TV_MA, - TvContentRatingConstants.CONTENT_RATING_US_TV_Y7_US_TV_FV); - } - - @Test - public void testStringToContentRatings_double() { - ImmutableList<TvContentRating> results = - TvContentRatingCache.stringToContentRatings( - TvContentRatingConstants.STRING_US_TV_MA - + "," - + TvContentRatingConstants.STRING_US_TV_MA); - assertWithMessage("ratings") - .that(results) - .containsExactly((TvContentRatingConstants.CONTENT_RATING_US_TV_MA)); - - assertThat(results).containsExactly(TvContentRatingConstants.CONTENT_RATING_US_TV_MA); - } -} diff --git a/common/tests/robotests/src/com/android/tv/common/actions/InputSetupActionUtilsTest.java b/common/tests/robotests/src/com/android/tv/common/actions/InputSetupActionUtilsTest.java deleted file mode 100644 index be586be5..00000000 --- a/common/tests/robotests/src/com/android/tv/common/actions/InputSetupActionUtilsTest.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * 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.common.actions; - -import static com.google.android.libraries.testing.truth.BundleSubject.assertThat; -import static com.google.common.truth.Truth.assertThat; - -import android.content.Intent; -import android.os.Bundle; - -import com.android.tv.testing.constants.ConfigConstants; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -/** Tests for {@link InputSetupActionUtils} */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class InputSetupActionUtilsTest { - - @Test - public void hasInputSetupAction_launchInputSetup() { - Intent intent = new Intent("com.android.tv.action.LAUNCH_INPUT_SETUP"); - assertThat(InputSetupActionUtils.hasInputSetupAction(intent)).isTrue(); - } - - @Test - public void hasInputSetupAction_googleLaunchInputSetup() { - Intent intent = new Intent("com.google.android.tv.action.LAUNCH_INPUT_SETUP"); - assertThat(InputSetupActionUtils.hasInputSetupAction(intent)).isTrue(); - } - - @Test - public void hasInputSetupAction_bad() { - Intent intent = new Intent("com.example.action.LAUNCH_INPUT_SETUP"); - assertThat(InputSetupActionUtils.hasInputSetupAction(intent)).isFalse(); - } - - @Test - public void getExtraActivityAfter_null() { - Intent intent = new Intent(); - assertThat(InputSetupActionUtils.getExtraActivityAfter(intent)).isNull(); - } - - @Test - public void getExtraActivityAfter_activityAfter() { - Intent intent = new Intent(); - Intent after = new Intent("after"); - intent.putExtra("com.android.tv.intent.extra.ACTIVITY_AFTER_COMPLETION", after); - assertThat(InputSetupActionUtils.getExtraActivityAfter(intent)).isEqualTo(after); - } - - @Test - public void getExtraActivityAfter_googleActivityAfter() { - Intent intent = new Intent(); - Intent after = new Intent("google_setup"); - intent.putExtra("com.google.android.tv.intent.extra.ACTIVITY_AFTER_COMPLETION", after); - assertThat(InputSetupActionUtils.getExtraActivityAfter(intent)).isEqualTo(after); - } - - @Test - public void getExtraSetupIntent_null() { - Intent intent = new Intent(); - assertThat(InputSetupActionUtils.getExtraSetupIntent(intent)).isNull(); - } - - @Test - public void getExtraSetupIntent_setupIntent() { - Intent intent = new Intent(); - Intent setup = new Intent("setup"); - intent.putExtra("com.android.tv.extra.SETUP_INTENT", setup); - assertThat(InputSetupActionUtils.getExtraSetupIntent(intent)).isEqualTo(setup); - } - - @Test - public void getExtraSetupIntent_googleSetupIntent() { - Intent intent = new Intent(); - Intent setup = new Intent("google_setup"); - intent.putExtra("com.google.android.tv.extra.SETUP_INTENT", setup); - assertThat(InputSetupActionUtils.getExtraSetupIntent(intent)).isEqualTo(setup); - } - - @Test - public void removeSetupIntent_empty() { - Bundle extras = new Bundle(); - InputSetupActionUtils.removeSetupIntent(extras); - assertThat(extras).exactlyMatches(new Bundle()); - } - - @Test - public void removeSetupIntent_other() { - Bundle extras = createTestBundle(); - Bundle expected = createTestBundle(); - InputSetupActionUtils.removeSetupIntent(extras); - assertThat(extras).exactlyMatches(expected); - } - - @Test - public void removeSetupIntent_setup() { - Bundle extras = createTestBundle(); - Bundle expected = createTestBundle(); - Intent setup = new Intent("setup"); - extras.putParcelable("com.android.tv.extra.SETUP_INTENT", setup); - InputSetupActionUtils.removeSetupIntent(extras); - assertThat(extras).exactlyMatches(expected); - } - - @Test - public void removeSetupIntent_googleSetup() { - Bundle extras = createTestBundle(); - Bundle expected = createTestBundle(); - Intent googleSetup = new Intent("googleSetup"); - extras.putParcelable("com.google.android.tv.extra.SETUP_INTENT", googleSetup); - InputSetupActionUtils.removeSetupIntent(extras); - assertThat(extras).exactlyMatches(expected); - } - - @Test - public void removeSetupIntent_bothSetups() { - Bundle extras = createTestBundle(); - Bundle expected = createTestBundle(); - Intent setup = new Intent("setup"); - extras.putParcelable("com.android.tv.extra.SETUP_INTENT", setup); - Intent googleSetup = new Intent("googleSetup"); - extras.putParcelable("com.google.android.tv.extra.SETUP_INTENT", googleSetup); - InputSetupActionUtils.removeSetupIntent(extras); - assertThat(extras).exactlyMatches(expected); - } - - private static Bundle createTestBundle() { - Bundle extras = new Bundle(); - extras.putInt("other", 1); - return extras; - } -} diff --git a/common/tests/robotests/src/com/android/tv/common/compat/TvInputInfoCompatTest.java b/common/tests/robotests/src/com/android/tv/common/compat/TvInputInfoCompatTest.java deleted file mode 100644 index 5c10c00b..00000000 --- a/common/tests/robotests/src/com/android/tv/common/compat/TvInputInfoCompatTest.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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.common.compat; - -import static com.google.common.truth.Truth.assertThat; - -import static junit.framework.Assert.fail; - -import android.content.pm.ResolveInfo; -import android.content.res.XmlResourceParser; -import android.media.tv.TvInputInfo; - -import androidx.test.InstrumentationRegistry; - -import com.android.tv.testing.constants.ConfigConstants; -import com.android.tv.testing.utils.TestUtils; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlPullParserFactory; - -import java.io.StringReader; - -/** Tests for {@link TvInputInfoCompat}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class TvInputInfoCompatTest { - private TvInputInfoCompat mTvInputInfoCompat; - private String mInputXml; - - @Before - public void setUp() throws Exception { - ResolveInfo resolveInfo = TestUtils.createResolveInfo("test", "test"); - TvInputInfo info = - TestUtils.createTvInputInfo( - resolveInfo, "test_input", "test1", TvInputInfo.TYPE_OTHER, false); - mTvInputInfoCompat = - new TvInputInfoCompat(InstrumentationRegistry.getTargetContext(), info) { - @Override - XmlPullParser getXmlResourceParser() { - XmlPullParser xpp = null; - try { - xpp = XmlPullParserFactory.newInstance().newPullParser(); - xpp.setInput(new StringReader(mInputXml)); - xpp.setFeature(XmlResourceParser.FEATURE_PROCESS_NAMESPACES, true); - } catch (XmlPullParserException e) { - fail("failed in setUp() " + e.getMessage()); - } - return xpp; - } - }; - } - - @Test - public void testGetAttributeValue_notTvInputTag() { - mInputXml = - "<not-tv-input xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" - + " android:setupActivity=\"\"\n" - + " android:settingsActivity=\"\"/>\n"; - assertThat(mTvInputInfoCompat.getExtras()).isEmpty(); - } - - @Test - public void testGetAttributeValue_noExtra() { - mInputXml = - "<not-tv-input xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" - + " android:setupActivity=\"\"\n" - + " android:settingsActivity=\"\"/>\n"; - assertThat(mTvInputInfoCompat.getExtras()).isEmpty(); - } - - @Test - public void testGetAttributeValue() { - mInputXml = - "<tv-input xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" - + " android:setupActivity=\"\"\n" - + " android:settingsActivity=\"\">\n" - + " <extra android:name=\"otherAttr1\" android:value=\"false\" />\n" - + " <extra android:name=\"otherAttr2\" android:value=\"false\" />\n" - + " <extra android:name=" - + " \"com.android.tv.common.compat.tvinputinfocompat.audioOnly\"" - + " android:value=\"true\" />\n" - + "</tv-input>"; - assertThat(mTvInputInfoCompat.getExtras()) - .containsExactly( - "otherAttr1", - "false", - "otherAttr2", - "false", - "com.android.tv.common.compat.tvinputinfocompat.audioOnly", - "true"); - } -} diff --git a/common/tests/robotests/src/com/android/tv/common/compat/internal/PrivateCommandTest.java b/common/tests/robotests/src/com/android/tv/common/compat/internal/PrivateCommandTest.java deleted file mode 100644 index aa9221fa..00000000 --- a/common/tests/robotests/src/com/android/tv/common/compat/internal/PrivateCommandTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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.common.compat.internal; - -import static org.mockito.Mockito.only; -import static org.mockito.Mockito.verify; - -import com.android.tv.common.compat.api.SessionCompatCommands; -import com.android.tv.testing.constants.ConfigConstants; - -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.testing.mockito.Mocks; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -/** - * Tests sending {@link Commands.PrivateCommand}s to a {@link SessionCompatCommands} from {@link - * TvViewCompatProcessor} via {@link TifSessionCompatProcessor}. - */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class PrivateCommandTest { - @Rule public final Mocks mocks = new Mocks(this); - - @Mock SessionCompatCommands mCallback; - - private TvViewCompatProcessor mTvViewCompatProcessor; - - @Before - public void setUp() { - TifSessionCompatProcessor sessionCompatProcessor = - new TifSessionCompatProcessor(null, mCallback); - mTvViewCompatProcessor = - new TvViewCompatProcessor(sessionCompatProcessor::handleAppPrivateCommand); - } - - @Test - public void notifyDevToast() throws InvalidProtocolBufferException { - mTvViewCompatProcessor.devMessage("Hello Developers"); - verify(mCallback, only()).onDevMessage("Hello Developers"); - } -} diff --git a/common/tests/robotests/src/com/android/tv/common/compat/internal/PrivateRecordingCommandTest.java b/common/tests/robotests/src/com/android/tv/common/compat/internal/PrivateRecordingCommandTest.java deleted file mode 100644 index 1a3c0916..00000000 --- a/common/tests/robotests/src/com/android/tv/common/compat/internal/PrivateRecordingCommandTest.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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.common.compat.internal; - -import static org.mockito.Mockito.only; -import static org.mockito.Mockito.verify; - -import com.android.tv.common.compat.api.RecordingSessionCompatCommands; -import com.android.tv.testing.constants.ConfigConstants; - -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.testing.mockito.Mocks; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -/** - * Tests sending {@link RecordingCommands.PrivateRecordingCommand}s to a {@link - * RecordingSessionCompatCommands} from {@link RecordingClientCompatProcessor} via {@link - * RecordingSessionCompatProcessor}. - */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class PrivateRecordingCommandTest { - @Rule public final Mocks mocks = new Mocks(this); - - @Mock private RecordingSessionCompatCommands mCallback; - - private RecordingClientCompatProcessor mCompatProcessor; - - @Before - public void setUp() { - RecordingSessionCompatProcessor sessionCompatProcessor = - new RecordingSessionCompatProcessor(null, mCallback); - mCompatProcessor = - new RecordingClientCompatProcessor( - sessionCompatProcessor::handleAppPrivateCommand, null); - } - - @Test - public void notifyDevToast() throws InvalidProtocolBufferException { - mCompatProcessor.devMessage("Hello Recorders"); - verify(mCallback, only()).onDevMessage("Hello Recorders"); - } -} diff --git a/common/tests/robotests/src/com/android/tv/common/compat/internal/RecordingSessionEventTest.java b/common/tests/robotests/src/com/android/tv/common/compat/internal/RecordingSessionEventTest.java deleted file mode 100644 index 3de3a6df..00000000 --- a/common/tests/robotests/src/com/android/tv/common/compat/internal/RecordingSessionEventTest.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.common.compat.internal; - -import static org.mockito.Mockito.only; -import static org.mockito.Mockito.verify; - -import com.android.tv.common.compat.api.RecordingClientCallbackCompatEvents; -import com.android.tv.testing.constants.ConfigConstants; - -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.testing.mockito.Mocks; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -/** - * Tests sending {@link RecordingEvents.RecordingSessionEvent}s to a {@link - * RecordingClientCallbackCompatEvents} from {@link RecordingSessionCompatProcessor} via {@link - * RecordingClientCompatProcessor}. - */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class RecordingSessionEventTest { - @Rule public final Mocks mocks = new Mocks(this); - - @Mock RecordingClientCallbackCompatEvents mCallback; - - private RecordingSessionCompatProcessor mCompatProcess; - - @Before - public void setUp() { - RecordingClientCompatProcessor compatProcessor = - new RecordingClientCompatProcessor(null, mCallback); - mCompatProcess = - new RecordingSessionCompatProcessor( - (event, data) -> compatProcessor.handleEvent("testinput", event, data), - null); - } - - @Test - public void notifyDevToast() throws InvalidProtocolBufferException { - mCompatProcess.notifyDevToast("Recording"); - verify(mCallback, only()).onDevToast("testinput", "Recording"); - } - - @Test - public void notifyRecordingStarted() throws InvalidProtocolBufferException { - mCompatProcess.notifyRecordingStarted("file:example"); - verify(mCallback, only()).onRecordingStarted("testinput", "file:example"); - } -} diff --git a/common/tests/robotests/src/com/android/tv/common/compat/internal/SessionEventTest.java b/common/tests/robotests/src/com/android/tv/common/compat/internal/SessionEventTest.java deleted file mode 100644 index e65297cc..00000000 --- a/common/tests/robotests/src/com/android/tv/common/compat/internal/SessionEventTest.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.common.compat.internal; - -import static org.mockito.Mockito.only; -import static org.mockito.Mockito.verify; - -import com.android.tv.common.compat.api.TvInputCallbackCompatEvents; -import com.android.tv.testing.constants.ConfigConstants; - -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.testing.mockito.Mocks; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -/** - * Tests sending {@link Events.SessionEvent}s to a {@link TvInputCallbackCompatEvents} from {@link - * TifSessionCompatProcessor} via {@link TvViewCompatProcessor}. - */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class SessionEventTest { - @Rule public final Mocks mocks = new Mocks(this); - - @Mock TvInputCallbackCompatEvents mCallback; - - private TifSessionCompatProcessor mCompatProcess; - - @Before - public void setUp() { - TvViewCompatProcessor tvViewCompatProcessor = new TvViewCompatProcessor(null); - tvViewCompatProcessor.setCallback(mCallback); - mCompatProcess = - new TifSessionCompatProcessor( - (event, data) -> - tvViewCompatProcessor.handleEvent("testinput", event, data), - null); - } - - @Test - public void notifyDevToast() throws InvalidProtocolBufferException { - mCompatProcess.notifyDevToast("testing"); - verify(mCallback, only()).onDevToast("testinput", "testing"); - } - - @Test - public void notifySignalStrength() throws InvalidProtocolBufferException { - mCompatProcess.notifySignalStrength(3); - verify(mCallback, only()).onSignalStrength("testinput", 3); - } -} diff --git a/common/tests/robotests/src/com/android/tv/common/dev/DeveloperPreferenceTest.java b/common/tests/robotests/src/com/android/tv/common/dev/DeveloperPreferenceTest.java deleted file mode 100644 index a9c15ada..00000000 --- a/common/tests/robotests/src/com/android/tv/common/dev/DeveloperPreferenceTest.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2019 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.common.dev; - -import static com.google.common.truth.Truth.assertThat; - -import com.android.tv.testing.constants.ConfigConstants; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -/** Test for {@link DeveloperPreference}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class DeveloperPreferenceTest { - - @Test - public void createBoolean_default_true() { - DeveloperPreference<Boolean> devPref = DeveloperPreference.create("test", true); - assertThat(devPref.get(RuntimeEnvironment.systemContext)).isTrue(); - DeveloperPreference.getPreferences(RuntimeEnvironment.systemContext) - .edit() - .putBoolean("test", false) - .apply(); - assertThat(devPref.get(RuntimeEnvironment.systemContext)).isFalse(); - } - - @Test - public void create_integer_default_one() { - DeveloperPreference<Integer> devPref = DeveloperPreference.create("test", 1); - assertThat(devPref.get(RuntimeEnvironment.systemContext)).isEqualTo(1); - DeveloperPreference.getPreferences(RuntimeEnvironment.systemContext) - .edit() - .putInt("test", 2) - .apply(); - assertThat(devPref.get(RuntimeEnvironment.systemContext)).isEqualTo(2); - } -} diff --git a/common/tests/robotests/src/com/android/tv/common/support/tis/BaseTvInputServiceTest.java b/common/tests/robotests/src/com/android/tv/common/support/tis/BaseTvInputServiceTest.java deleted file mode 100644 index 88b0215e..00000000 --- a/common/tests/robotests/src/com/android/tv/common/support/tis/BaseTvInputServiceTest.java +++ /dev/null @@ -1,147 +0,0 @@ -package com.android.tv.common.support.tis; - -import static com.google.common.truth.Truth.assertThat; - -import android.content.Intent; -import android.media.tv.TvContentRating; -import android.media.tv.TvInputManager; -import android.net.Uri; -import android.os.Build; -import android.support.annotation.Nullable; -import android.view.Surface; - -import com.android.tv.common.support.tis.TifSession.TifSessionCallbacks; -import com.android.tv.common.support.tis.TifSession.TifSessionFactory; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.android.controller.ServiceController; -import org.robolectric.annotation.Config; - -/** Tests for {@link BaseTvInputService}. */ -@RunWith(RobolectricTestRunner.class) -@Config(minSdk = Build.VERSION_CODES.LOLLIPOP, maxSdk = Build.VERSION_CODES.P) -public class BaseTvInputServiceTest { - - private static class TestTvInputService extends BaseTvInputService { - - private final SessionManager sessionManager = new SimpleSessionManager(1); - - private int parentalControlsChangedCount = 0; - private final TifSessionFactory sessionFactory; - - private TestTvInputService() { - super(); - this.sessionFactory = - new TifSessionFactory() { - @Override - public TifSession create(TifSessionCallbacks callbacks, String inputId) { - return new TifSession(callbacks) { - @Override - public boolean onSetSurface(@Nullable Surface surface) { - return false; - } - - @Override - public void onSurfaceChanged(int format, int width, int height) {} - - @Override - public void onSetStreamVolume(float volume) {} - - @Override - public boolean onTune(Uri channelUri) { - return false; - } - - @Override - public void onSetCaptionEnabled(boolean enabled) {} - - @Override - public void onUnblockContent(TvContentRating unblockedRating) {} - - @Override - public void onParentalControlsChanged() { - parentalControlsChangedCount++; - } - }; - } - }; - } - - @Override - protected TifSessionFactory getTifSessionFactory() { - return sessionFactory; - } - - @Override - protected SessionManager getSessionManager() { - return sessionManager; - } - - private int getParentalControlsChangedCount() { - return parentalControlsChangedCount; - } - } - - TestTvInputService tvInputService; - ServiceController<TestTvInputService> controller; - - @Before - public void setUp() { - controller = Robolectric.buildService(TestTvInputService.class); - tvInputService = controller.create().get(); - } - - @Test - public void createSession_once() { - assertThat(tvInputService.onCreateSession("test")).isNotNull(); - } - - @Test - public void createSession_twice() { - WrappedSession first = tvInputService.onCreateSession("test"); - assertThat(first).isNotNull(); - WrappedSession second = tvInputService.onCreateSession("test"); - assertThat(second).isNull(); - } - - @Test - public void createSession_release() { - WrappedSession first = tvInputService.onCreateSession("test"); - assertThat(first).isNotNull(); - first.onRelease(); - WrappedSession second = tvInputService.onCreateSession("test"); - assertThat(second).isNotNull(); - assertThat(second).isNotSameInstanceAs(first); - } - - @Test - public void testReceiver_actionEnabledChanged() { - tvInputService.getSessionManager().addSession(tvInputService.onCreateSession("test")); - tvInputService.broadcastReceiver.onReceive( - RuntimeEnvironment.application, - new Intent(TvInputManager.ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED)); - assertThat(tvInputService.getParentalControlsChangedCount()).isEqualTo(1); - } - - @Test - public void testReceiver_actionBlockedChanged() { - tvInputService.getSessionManager().addSession(tvInputService.onCreateSession("test")); - tvInputService.broadcastReceiver.onReceive( - RuntimeEnvironment.application, - new Intent(TvInputManager.ACTION_BLOCKED_RATINGS_CHANGED)); - assertThat(tvInputService.getParentalControlsChangedCount()).isEqualTo(1); - } - - @Test - public void testReceiver_invalidAction() { - tvInputService.getSessionManager().addSession(tvInputService.onCreateSession("test")); - tvInputService.broadcastReceiver.onReceive( - RuntimeEnvironment.application, new Intent("test")); - assertThat(tvInputService.getParentalControlsChangedCount()).isEqualTo(0); - } -} diff --git a/common/tests/robotests/src/com/android/tv/common/support/tis/SimpleSessionManagerTest.java b/common/tests/robotests/src/com/android/tv/common/support/tis/SimpleSessionManagerTest.java deleted file mode 100644 index 3972559f..00000000 --- a/common/tests/robotests/src/com/android/tv/common/support/tis/SimpleSessionManagerTest.java +++ /dev/null @@ -1,124 +0,0 @@ -package com.android.tv.common.support.tis; - -import static com.google.common.truth.Truth.assertThat; - -import android.media.tv.TvContentRating; -import android.net.Uri; -import android.os.Build; -import android.support.annotation.FloatRange; -import android.support.annotation.Nullable; -import android.view.Surface; - -import com.android.tv.common.support.tis.TifSession.TifSessionCallbacks; -import com.android.tv.common.support.tis.TifSession.TifSessionFactory; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -/** Tests for {@link SimpleSessionManager}. */ -@RunWith(RobolectricTestRunner.class) -@Config(minSdk = Build.VERSION_CODES.LOLLIPOP, maxSdk = Build.VERSION_CODES.P) -public class SimpleSessionManagerTest { - - private SimpleSessionManager sessionManager; - - @Before - public void setup() { - sessionManager = new SimpleSessionManager(1); - } - - @Test - public void canCreateSession_none() { - assertThat(sessionManager.canCreateNewSession()).isTrue(); - } - - @Test - public void canCreateSession_one() { - sessionManager.addSession(createTestSession()); - assertThat(sessionManager.canCreateNewSession()).isFalse(); - } - - @Test - public void addSession() { - assertThat(sessionManager.getSessionCount()).isEqualTo(0); - sessionManager.addSession(createTestSession()); - assertThat(sessionManager.getSessionCount()).isEqualTo(1); - } - - @Test - public void onRelease() { - WrappedSession testSession = createTestSession(); - sessionManager.addSession(testSession); - assertThat(sessionManager.getSessionCount()).isEqualTo(1); - testSession.onRelease(); - assertThat(sessionManager.getSessionCount()).isEqualTo(0); - } - - @Test - public void onRelease_withUnRegisteredSession() { - WrappedSession testSession = createTestSession(); - sessionManager.addSession(createTestSession()); - assertThat(sessionManager.getSessionCount()).isEqualTo(1); - testSession.onRelease(); - assertThat(sessionManager.getSessionCount()).isEqualTo(1); - } - - @Test - public void getSessions() { - WrappedSession testSession = createTestSession(); - sessionManager.addSession(testSession); - assertThat(sessionManager.getSessions()).containsExactly(testSession); - } - - private WrappedSession createTestSession() { - return new WrappedSession( - RuntimeEnvironment.application, - sessionManager, - new TestTifSessionFactory(), - "testInputId"); - } - - private static final class TestTifSessionFactory implements TifSessionFactory { - - @Override - public TifSession create(TifSessionCallbacks callbacks, String inputId) { - return new TestTifSession(callbacks); - } - } - - private static final class TestTifSession extends TifSession { - - private TestTifSession(TifSessionCallbacks callbacks) { - super(callbacks); - } - - @Override - public void onRelease() {} - - @Override - public boolean onSetSurface(@Nullable Surface surface) { - return false; - } - - @Override - public void onSurfaceChanged(int format, int width, int height) {} - - @Override - public void onSetStreamVolume(@FloatRange(from = 0.0, to = 1.0) float volume) {} - - @Override - public boolean onTune(Uri channelUri) { - return false; - } - - @Override - public void onSetCaptionEnabled(boolean enabled) {} - - @Override - public void onUnblockContent(TvContentRating unblockedRating) {} - } -} diff --git a/common/tests/robotests/src/com/android/tv/common/support/tis/TisSessionTest.java b/common/tests/robotests/src/com/android/tv/common/support/tis/TisSessionTest.java deleted file mode 100644 index e2f849ee..00000000 --- a/common/tests/robotests/src/com/android/tv/common/support/tis/TisSessionTest.java +++ /dev/null @@ -1,209 +0,0 @@ -package com.android.tv.common.support.tis; - -import static com.google.common.truth.Truth.assertThat; - -import android.media.tv.TvContentRating; -import android.media.tv.TvInputManager; -import android.media.tv.TvTrackInfo; -import android.net.Uri; -import android.os.Build; -import android.support.annotation.FloatRange; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.util.Pair; -import android.view.Surface; -import android.view.View; - -import com.android.tv.common.support.tis.TifSession.TifSessionCallbacks; - -import com.google.common.collect.ImmutableList; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import java.util.List; - -/** Tests for {@link TifSession}. */ -@RunWith(RobolectricTestRunner.class) -@Config(minSdk = Build.VERSION_CODES.LOLLIPOP, maxSdk = Build.VERSION_CODES.P) -public class TisSessionTest { - - private TestSession testSession; - private TestCallback testCallback; - - @Before - public void setup() { - testCallback = new TestCallback(); - testSession = new TestSession(testCallback); - } - - @Test - public void notifyChannelReturned() { - Uri uri = Uri.parse("http://example.com"); - testSession.notifyChannelRetuned(uri); - assertThat(testCallback.channelUri).isEqualTo(uri); - } - - @Test - public void notifyTracksChanged() { - List<TvTrackInfo> tracks = - ImmutableList.of(new TvTrackInfo.Builder(TvTrackInfo.TYPE_VIDEO, "test").build()); - testSession.notifyTracksChanged(tracks); - assertThat(testCallback.tracks).isEqualTo(tracks); - } - - @Test - public void notifyTrackSelected() { - testSession.notifyTrackSelected(TvTrackInfo.TYPE_AUDIO, "audio_test"); - assertThat(testCallback.trackSelected) - .isEqualTo(Pair.create(TvTrackInfo.TYPE_AUDIO, "audio_test")); - } - - @Test - public void notifyVideoAvailable() { - testSession.notifyVideoAvailable(); - assertThat(testCallback.videoAvailable).isTrue(); - } - - @Test - public void notifyVideoUnavailable() { - testSession.notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN); - assertThat(testCallback.notifyVideoUnavailableReason) - .isEqualTo(TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN); - } - - @Test - public void notifyContentAllowed() { - testSession.notifyContentAllowed(); - assertThat(testCallback.contentAllowed).isTrue(); - } - - @Test - public void notifyContentBlocked() { - TvContentRating rating = TvContentRating.createRating("1", "2", "3"); - testSession.notifyContentBlocked(rating); - assertThat(testCallback.blockedContentRating).isEqualTo(rating); - } - - @Test - public void notifyTimeShiftStatusChanged() { - testSession.notifyTimeShiftStatusChanged(TvInputManager.TIME_SHIFT_STATUS_AVAILABLE); - assertThat(testCallback.timeShiftStatus) - .isEqualTo(TvInputManager.TIME_SHIFT_STATUS_AVAILABLE); - } - - @Test - public void testSetOverlayViewEnabled() { - testSession.helpTestSetOverlayViewEnabled(true); - assertThat(testCallback.overlayViewEnabled).isTrue(); - - testSession.helpTestSetOverlayViewEnabled(false); - assertThat(testCallback.overlayViewEnabled).isFalse(); - } - - @Test - public void testOnCreateOverlayView() { - View actualView = testSession.onCreateOverlayView(); - assertThat(actualView).isNull(); // Default implementation returns a null. - } - - @Test - public void testOnOverlayViewSizeChanged() { - testSession.onOverlayViewSizeChanged(5 /* width */, 7 /* height */); - // Just verifing that the call completes. - } - - private static final class TestCallback implements TifSessionCallbacks { - - private Uri channelUri; - private List<TvTrackInfo> tracks; - private Pair<Integer, String> trackSelected; - private boolean videoAvailable; - private int notifyVideoUnavailableReason; - private boolean contentAllowed; - private TvContentRating blockedContentRating; - private int timeShiftStatus; - private boolean overlayViewEnabled; - - @Override - public void notifyChannelRetuned(Uri channelUri) { - this.channelUri = channelUri; - } - - @Override - public void notifyTracksChanged(List<TvTrackInfo> tracks) { - this.tracks = tracks; - } - - @Override - public void notifyTrackSelected(int type, String trackId) { - this.trackSelected = Pair.create(type, trackId); - } - - @Override - public void notifyVideoAvailable() { - this.videoAvailable = true; - } - - @Override - public void notifyVideoUnavailable(int reason) { - this.notifyVideoUnavailableReason = reason; - } - - @Override - public void notifyContentAllowed() { - this.contentAllowed = true; - } - - @Override - public void notifyContentBlocked(@NonNull TvContentRating rating) { - this.blockedContentRating = rating; - } - - @Override - public void notifyTimeShiftStatusChanged(int status) { - this.timeShiftStatus = status; - } - - @Override - public void setOverlayViewEnabled(boolean enabled) { - this.overlayViewEnabled = enabled; - } - } - - private static final class TestSession extends TifSession { - - private TestSession(TifSessionCallbacks callbacks) { - super(callbacks); - } - - @Override - public boolean onSetSurface(@Nullable Surface surface) { - return false; - } - - @Override - public void onSurfaceChanged(int format, int width, int height) {} - - @Override - public void onSetStreamVolume(@FloatRange(from = 0.0, to = 1.0) float volume) {} - - @Override - public boolean onTune(Uri channelUri) { - return false; - } - - @Override - public void onSetCaptionEnabled(boolean enabled) {} - - @Override - public void onUnblockContent(TvContentRating unblockedRating) {} - - public void helpTestSetOverlayViewEnabled(boolean enabled) { - super.setOverlayViewEnabled(enabled); - } - } -} diff --git a/common/tests/robotests/src/com/android/tv/common/support/tis/WrappedSessionTest.java b/common/tests/robotests/src/com/android/tv/common/support/tis/WrappedSessionTest.java deleted file mode 100644 index f5b6146f..00000000 --- a/common/tests/robotests/src/com/android/tv/common/support/tis/WrappedSessionTest.java +++ /dev/null @@ -1,190 +0,0 @@ -package com.android.tv.common.support.tis; - -import static com.google.common.truth.Truth.assertThat; - -import android.media.PlaybackParams; -import android.media.tv.TvContentRating; -import android.net.Uri; -import android.os.Build; -import android.view.View; - -import com.android.tv.common.support.tis.TifSession.TifSessionCallbacks; -import com.android.tv.common.support.tis.TifSession.TifSessionFactory; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -/** Tests for {@link WrappedSession}. */ -@RunWith(RobolectricTestRunner.class) -@Config(minSdk = Build.VERSION_CODES.M, maxSdk = Build.VERSION_CODES.P) -public class WrappedSessionTest { - - @Mock TifSession mockDelegate; - private TifSessionFactory sessionFactory = - new TifSessionFactory() { - @Override - public TifSession create(TifSessionCallbacks callbacks, String inputId) { - return mockDelegate; - } - }; - private WrappedSession wrappedSession; - private SimpleSessionManager sessionManager = new SimpleSessionManager(1); - - @Before - public void setup() { - MockitoAnnotations.initMocks(this); - wrappedSession = - new WrappedSession( - RuntimeEnvironment.application, - sessionManager, - sessionFactory, - "testInputId"); - } - - @Test - public void onRelease() { - sessionManager.addSession(wrappedSession); - assertThat(sessionManager.getSessionCount()).isEqualTo(1); - wrappedSession.onRelease(); - assertThat(sessionManager.getSessionCount()).isEqualTo(0); - Mockito.verify(mockDelegate).onRelease(); - Mockito.verifyNoMoreInteractions(mockDelegate); - } - - @Test - public void onSetSurface() { - wrappedSession.onSetSurface(null); - Mockito.verify(mockDelegate).onSetSurface(null); - Mockito.verifyNoMoreInteractions(mockDelegate); - } - - @Test - public void onSurfaceChanged() { - wrappedSession.onSurfaceChanged(1, 2, 3); - Mockito.verify(mockDelegate).onSurfaceChanged(1, 2, 3); - Mockito.verifyNoMoreInteractions(mockDelegate); - } - - @Test - public void onSetStreamVolume() { - wrappedSession.onSetStreamVolume(.8f); - Mockito.verify(mockDelegate).onSetStreamVolume(.8f); - Mockito.verifyNoMoreInteractions(mockDelegate); - } - - @Test - public void onTune() { - Uri uri = Uri.EMPTY; - wrappedSession.onTune(uri); - Mockito.verify(mockDelegate).onTune(uri); - Mockito.verifyNoMoreInteractions(mockDelegate); - } - - @Test - public void onSetCaptionEnabled() { - wrappedSession.onSetCaptionEnabled(true); - Mockito.verify(mockDelegate).onSetCaptionEnabled(true); - Mockito.verifyNoMoreInteractions(mockDelegate); - } - - @Test - @Config(minSdk = Build.VERSION_CODES.M) - public void onTimeShiftGetCurrentPosition() { - Mockito.when(mockDelegate.onTimeShiftGetCurrentPosition()).thenReturn(7L); - assertThat(wrappedSession.onTimeShiftGetCurrentPosition()).isEqualTo(7L); - Mockito.verify(mockDelegate).onTimeShiftGetCurrentPosition(); - Mockito.verifyNoMoreInteractions(mockDelegate); - } - - @Test - @Config(minSdk = Build.VERSION_CODES.M) - public void onTimeShiftGetStartPosition() { - Mockito.when(mockDelegate.onTimeShiftGetStartPosition()).thenReturn(8L); - assertThat(wrappedSession.onTimeShiftGetStartPosition()).isEqualTo(8L); - Mockito.verify(mockDelegate).onTimeShiftGetStartPosition(); - Mockito.verifyNoMoreInteractions(mockDelegate); - } - - @Test - @Config(minSdk = Build.VERSION_CODES.M) - public void onTimeShiftPause() { - wrappedSession.onTimeShiftPause(); - Mockito.verify(mockDelegate).onTimeShiftPause(); - Mockito.verifyNoMoreInteractions(mockDelegate); - } - - @Test - @Config(minSdk = Build.VERSION_CODES.M) - public void onTimeShiftResume() { - wrappedSession.onTimeShiftResume(); - Mockito.verify(mockDelegate).onTimeShiftResume(); - Mockito.verifyNoMoreInteractions(mockDelegate); - } - - @Test - @Config(minSdk = Build.VERSION_CODES.M) - public void onTimeShiftSeekTo() { - wrappedSession.onTimeShiftSeekTo(9L); - Mockito.verify(mockDelegate).onTimeShiftSeekTo(9L); - Mockito.verifyNoMoreInteractions(mockDelegate); - } - - @Test - @Config(minSdk = Build.VERSION_CODES.M) - public void onTimeShiftSetPlaybackParams() { - PlaybackParams paras = new PlaybackParams(); - wrappedSession.onTimeShiftSetPlaybackParams(paras); - Mockito.verify(mockDelegate).onTimeShiftSetPlaybackParams(paras); - Mockito.verifyNoMoreInteractions(mockDelegate); - } - - @Test - @Config(minSdk = Build.VERSION_CODES.M) - public void onUnblockContent() { - TvContentRating rating = - TvContentRating.createRating( - "domain", "rating_system", "rating", "subrating1", "subrating2"); - wrappedSession.onUnblockContent(rating); - Mockito.verify(mockDelegate).onUnblockContent(rating); - Mockito.verifyNoMoreInteractions(mockDelegate); - } - - @Test - public void onParentalControlsChanged() { - wrappedSession.onParentalControlsChanged(); - Mockito.verify(mockDelegate).onParentalControlsChanged(); - Mockito.verifyNoMoreInteractions(mockDelegate); - } - - @Test - public void testSetOverlayViewEnabled() { - wrappedSession.setOverlayViewEnabled(true); - // Just verifying that the call completes. - } - - @Test - public void testOnCreateOverlayView() { - View v = new View(RuntimeEnvironment.application); - Mockito.when(mockDelegate.onCreateOverlayView()).thenReturn(v); - - View actualView = wrappedSession.onCreateOverlayView(); - - assertThat(actualView).isEqualTo(v); - Mockito.verify(mockDelegate).onCreateOverlayView(); - Mockito.verifyNoMoreInteractions(mockDelegate); - } - - @Test - public void testOnOverlayViewSizeChanged() { - wrappedSession.onOverlayViewSizeChanged(5 /* width */, 13 /* height */); - Mockito.verify(mockDelegate).onOverlayViewSizeChanged(5, 13); - Mockito.verifyNoMoreInteractions(mockDelegate); - } -} diff --git a/common/tests/robotests/src/com/android/tv/common/support/tvprovider/TvContractCompatXTest.java b/common/tests/robotests/src/com/android/tv/common/support/tvprovider/TvContractCompatXTest.java deleted file mode 100644 index 51cc19dd..00000000 --- a/common/tests/robotests/src/com/android/tv/common/support/tvprovider/TvContractCompatXTest.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2019 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.common.support.tvprovider; - -import static com.google.common.truth.Truth.assertThat; - -import android.net.Uri; - -import com.android.tv.testing.constants.ConfigConstants; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -/** Test for {@link TvContractCompatX}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class TvContractCompatXTest { - - @Test - public void buildChannelUri() { - assertThat(TvContractCompatX.buildChannelUri("com.example", "foo")) - .isEqualTo( - Uri.parse( - "content://android.media.tv/channel?" - + "package=com.example&internal_provider_id=foo")); - } - - @Test - public void buildProgramsUriForChannel() { - assertThat(TvContractCompatX.buildProgramsUriForChannel("com.example", "foo")) - .isEqualTo( - Uri.parse( - "content://android.media.tv/program?" - + "package=com.example&internal_provider_id=foo")); - } - - @Test - public void buildProgramsUriForChannel_period() { - assertThat(TvContractCompatX.buildProgramsUriForChannel("com.example", "foo", 1234L, 5467L)) - .isEqualTo( - Uri.parse( - "content://android.media.tv/program?" - + "package=com.example&internal_provider_id=foo" - + "&start_time=1234&end_time=5467")); - } - - @Test - public void buildProgramsUri_period() { - assertThat(TvContractCompatX.buildProgramsUri(1234L, 5467L)) - .isEqualTo( - Uri.parse( - "content://android.media.tv/program?" - + "start_time=1234&end_time=5467")); - } -} diff --git a/common/tests/robotests/src/com/android/tv/common/util/CommonUtilsTest.java b/common/tests/robotests/src/com/android/tv/common/util/CommonUtilsTest.java deleted file mode 100644 index 3930ff69..00000000 --- a/common/tests/robotests/src/com/android/tv/common/util/CommonUtilsTest.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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.common.util; - -import static com.google.common.truth.Truth.assertThat; - -import com.android.tv.testing.constants.ConfigConstants; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -import java.io.File; -import java.io.IOException; - -/** Tests for {@link CommonUtils}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class CommonUtilsTest { - - @Test - public void deleteDirOrFile_file() throws IOException { - File file = new File(RuntimeEnvironment.application.getExternalFilesDir(null), "file"); - assertThat(file.createNewFile()).isTrue(); - assertThat(CommonUtils.deleteDirOrFile(file)).isTrue(); - assertThat(file.exists()).isFalse(); - } - - @Test - public void deleteDirOrFile_Dir() throws IOException { - File dir = new File(RuntimeEnvironment.application.getExternalFilesDir(null), "dir"); - assertThat(dir.mkdirs()).isTrue(); - assertThat(new File(dir, "file").createNewFile()).isTrue(); - assertThat(CommonUtils.deleteDirOrFile(dir)).isTrue(); - assertThat(dir.exists()).isFalse(); - } - - @Test - public void deleteDirOrFile_unreadableDir() throws IOException { - File dir = new File(RuntimeEnvironment.application.getExternalFilesDir(null), "dir"); - assertThat(dir.mkdirs()).isTrue(); - assertThat(new File(dir, "file").createNewFile()).isTrue(); - dir.setReadable(false); - // Since dir is unreadable dir.listFiles() returns null and file is not deleted thus - // dir is not actually deleted. - assertThat(CommonUtils.deleteDirOrFile(dir)).isFalse(); - assertThat(dir.exists()).isTrue(); - } - - @Test - public void deleteDirOrFile_unreadableSubDir() throws IOException { - File dir = new File(RuntimeEnvironment.application.getExternalFilesDir(null), "dir"); - File subDir = new File(dir, "sub"); - assertThat(subDir.mkdirs()).isTrue(); - File file = new File(subDir, "file"); - assertThat(file.createNewFile()).isTrue(); - subDir.setReadable(false); - // Since subDir is unreadable subDir.listFiles() returns null and file is not deleted thus - // dir is not actually deleted. - assertThat(CommonUtils.deleteDirOrFile(dir)).isFalse(); - assertThat(dir.exists()).isTrue(); - } -} diff --git a/common/tests/robotests/src/com/android/tv/common/util/ContentUriUtilsTest.java b/common/tests/robotests/src/com/android/tv/common/util/ContentUriUtilsTest.java deleted file mode 100644 index 58286724..00000000 --- a/common/tests/robotests/src/com/android/tv/common/util/ContentUriUtilsTest.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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.common.util; - -import static com.google.common.truth.Truth.assertThat; - -import android.net.Uri; - -import com.android.tv.testing.constants.ConfigConstants; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -/** Tests for {@link ContentUriUtils}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class ContentUriUtilsTest { - - @Test - public void safeParseId_empty() { - assertThat(ContentUriUtils.safeParseId(Uri.EMPTY)).isEqualTo(-1); - } - - @Test - public void safeParseId_bad() { - assertThat(ContentUriUtils.safeParseId(Uri.parse("foo/bad"))).isEqualTo(-1); - } - - @Test - public void safeParseId_123() { - assertThat(ContentUriUtils.safeParseId(Uri.parse("foo/123"))).isEqualTo(123); - } -} diff --git a/gradle.properties b/gradle.properties index 9d027fe0..62082346 100644 --- a/gradle.properties +++ b/gradle.properties @@ -21,5 +21,4 @@ org.gradle.jvmargs=-Xmx6144m -XX:MaxPermSize=6144m -XX:+HeapDumpOnOutOfMemoryErr org.gradle.daemon=true org.gradle.parallel=true -android.useAndroidX=true -android.enableJetifier=true
\ No newline at end of file +org.gradle.configureondemand=true
\ No newline at end of file diff --git a/jni/DvbManager.cpp b/jni/DvbManager.cpp index 33209594..f9dff59b 100644 --- a/jni/DvbManager.cpp +++ b/jni/DvbManager.cpp @@ -42,6 +42,7 @@ DvbManager::DvbManager(JNIEnv *env, jobject) mDvrFd(-1), mPatFilterFd(-1), mDvbApiVersion(DVB_API_VERSION_UNDEFINED), + mDeliverySystemType(-1), mFeHasLock(false), mHasPendingTune(false) { jclass clazz = env->FindClass("com/android/tv/tuner/TunerHal"); @@ -49,8 +50,6 @@ DvbManager::DvbManager(JNIEnv *env, jobject) env->GetMethodID(clazz, "openDvbFrontEndFd", "()I"); mOpenDvbDemuxMethodID = env->GetMethodID(clazz, "openDvbDemuxFd", "()I"); mOpenDvbDvrMethodID = env->GetMethodID(clazz, "openDvbDvrFd", "()I"); - memset(&mDeliverySystemTypes, DELIVERY_SYSTEM_UNDEFINED, - sizeof(mDeliverySystemTypes)); } DvbManager::~DvbManager() { @@ -116,20 +115,6 @@ int DvbManager::getSignalStrength() { int DvbManager::tune(JNIEnv *env, jobject thiz, const int frequency, const char *modulationStr, int timeout_ms) { - return tuneInternal(env, thiz, DELIVERY_SYSTEM_UNDEFINED, frequency, - modulationStr, timeout_ms); -} - -int DvbManager::tune(JNIEnv *env, jobject thiz, - const int deliverySystemType, const int frequency, - const char *modulationStr, int timeout_ms) { - return tuneInternal(env, thiz, deliverySystemType, frequency, - modulationStr, timeout_ms); -} - -int DvbManager::tuneInternal(JNIEnv *env, jobject thiz, - const int deliverySystemType, const int frequency, - const char *modulationStr, int timeout_ms) { resetExceptFe(); if (openDvbFe(env, thiz) != 0) { @@ -161,36 +146,10 @@ int DvbManager::tuneInternal(JNIEnv *env, jobject thiz, struct dtv_property deliverySystemProperty = { .cmd = DTV_DELIVERY_SYSTEM }; - switch (deliverySystemType) { - case DELIVERY_SYSTEM_DVBT: - deliverySystemProperty.u.data = SYS_DVBT; - break; - case DELIVERY_SYSTEM_DVBT2: - deliverySystemProperty.u.data = SYS_DVBT2; - break; - case DELIVERY_SYSTEM_DVBS: - deliverySystemProperty.u.data = SYS_DVBS; - break; - case DELIVERY_SYSTEM_DVBS2: - deliverySystemProperty.u.data = SYS_DVBS2; - break; - case DELIVERY_SYSTEM_DVBC: - deliverySystemProperty.u.data = SYS_DVBC_ANNEX_A; - break; - case DELIVERY_SYSTEM_ATSC: - case DELIVERY_SYSTEM_UNDEFINED: - deliverySystemProperty.u.data = SYS_ATSC; - break; - default: - ALOGE("Unrecognized delivery system type"); - return -1; - } + deliverySystemProperty.u.data = SYS_ATSC; struct dtv_property frequencyProperty = { .cmd = DTV_FREQUENCY }; - struct dtv_property bandwidthProperty = { - .cmd = DTV_BANDWIDTH_HZ, .u.data = 8000000 - }; frequencyProperty.u.data = static_cast<__u32>(frequency); struct dtv_property modulationProperty = { .cmd = DTV_MODULATION }; if (strncmp(modulationStr, "QAM", 3) == 0) { @@ -204,11 +163,10 @@ int DvbManager::tuneInternal(JNIEnv *env, jobject thiz, struct dtv_property tuneProperty = { .cmd = DTV_TUNE }; struct dtv_property props[] = { - deliverySystemProperty, frequencyProperty, modulationProperty, - bandwidthProperty, tuneProperty + deliverySystemProperty, frequencyProperty, modulationProperty, tuneProperty }; struct dtv_properties dtvProperty = { - .num = sizeof(props)/sizeof(dtv_property), .props = props + .num = 4, .props = props }; if (mHasPendingTune) { @@ -257,9 +215,6 @@ int DvbManager::tuneInternal(JNIEnv *env, jobject thiz, ALOGE("Unrecognized modulation mode : %s", modulationStr); return -1; } - feParams.u.ofdm.code_rate_HP = FEC_AUTO; - feParams.u.ofdm.code_rate_LP = FEC_AUTO; - feParams.u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; break; default: ALOGE("Unsupported delivery system."); @@ -507,27 +462,22 @@ void DvbManager::setHasPendingTune(bool hasPendingTune) { } int DvbManager::getDeliverySystemType(JNIEnv *env, jobject thiz) { - getDeliverySystemTypes(env, thiz); - return mDeliverySystemTypes[0]; -} - -int* DvbManager::getDeliverySystemTypes(JNIEnv *env, jobject thiz) { - ALOGE("getDeliverySystemTypes"); - if (mDeliverySystemTypes[0] != DELIVERY_SYSTEM_UNDEFINED) { - return mDeliverySystemTypes; + if (mDeliverySystemType != -1) { + return mDeliverySystemType; } if (mFeFd == -1) { if ((mFeFd = openDvbFeFromSystemApi(env, thiz)) < 0) { ALOGD("Can't open FE file : %s", strerror(errno)); - return mDeliverySystemTypes; + return DELIVERY_SYSTEM_UNDEFINED; } } struct dtv_property testProps[1] = { - { .cmd = DTV_ENUM_DELSYS } + { .cmd = DTV_DELIVERY_SYSTEM } }; struct dtv_properties feProp = { .num = 1, .props = testProps }; + mDeliverySystemType = DELIVERY_SYSTEM_UNDEFINED; if (ioctl(mFeFd, FE_GET_PROPERTY, &feProp) == -1) { mDvbApiVersion = DVB_API_VERSION3; if (openDvbFe(env, thiz) == 0) { @@ -535,52 +485,50 @@ int* DvbManager::getDeliverySystemTypes(JNIEnv *env, jobject thiz) { if (ioctl(mFeFd, FE_GET_INFO, &info) == 0) { switch (info.type) { case FE_QPSK: - mDeliverySystemTypes[0] = DELIVERY_SYSTEM_DVBS; + mDeliverySystemType = DELIVERY_SYSTEM_DVBS; break; case FE_QAM: - mDeliverySystemTypes[0] = DELIVERY_SYSTEM_DVBC; + mDeliverySystemType = DELIVERY_SYSTEM_DVBC; break; case FE_OFDM: - mDeliverySystemTypes[0] = DELIVERY_SYSTEM_DVBT; + mDeliverySystemType = DELIVERY_SYSTEM_DVBT; break; case FE_ATSC: - mDeliverySystemTypes[0] = DELIVERY_SYSTEM_ATSC; + mDeliverySystemType = DELIVERY_SYSTEM_ATSC; break; default: - mDeliverySystemTypes[0] = DELIVERY_SYSTEM_UNDEFINED; + mDeliverySystemType = DELIVERY_SYSTEM_UNDEFINED; break; } } } } else { mDvbApiVersion = DVB_API_VERSION5; - for (unsigned int i = 0; i < feProp.props[0].u.buffer.len; i++) { - switch (feProp.props[0].u.buffer.data[i]) { - case SYS_DVBT: - mDeliverySystemTypes[i] = DELIVERY_SYSTEM_DVBT; - break; - case SYS_DVBT2: - mDeliverySystemTypes[i] = DELIVERY_SYSTEM_DVBT2; - break; - case SYS_DVBS: - mDeliverySystemTypes[i] = DELIVERY_SYSTEM_DVBS; - break; - case SYS_DVBS2: - mDeliverySystemTypes[i] = DELIVERY_SYSTEM_DVBS2; - break; - case SYS_DVBC_ANNEX_A: - case SYS_DVBC_ANNEX_B: - case SYS_DVBC_ANNEX_C: - mDeliverySystemTypes[i] = DELIVERY_SYSTEM_DVBC; - break; - case SYS_ATSC: - mDeliverySystemTypes[i] = DELIVERY_SYSTEM_ATSC; - break; - default: - mDeliverySystemTypes[i] = DELIVERY_SYSTEM_UNDEFINED; - break; - } + switch (feProp.props[0].u.data) { + case SYS_DVBT: + mDeliverySystemType = DELIVERY_SYSTEM_DVBT; + break; + case SYS_DVBT2: + mDeliverySystemType = DELIVERY_SYSTEM_DVBT2; + break; + case SYS_DVBS: + mDeliverySystemType = DELIVERY_SYSTEM_DVBS; + break; + case SYS_DVBS2: + mDeliverySystemType = DELIVERY_SYSTEM_DVBS2; + break; + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_B: + case SYS_DVBC_ANNEX_C: + mDeliverySystemType = DELIVERY_SYSTEM_DVBC; + break; + case SYS_ATSC: + mDeliverySystemType = DELIVERY_SYSTEM_ATSC; + break; + default: + mDeliverySystemType = DELIVERY_SYSTEM_UNDEFINED; + break; } } - return mDeliverySystemTypes; -} + return mDeliverySystemType; +}
\ No newline at end of file diff --git a/jni/DvbManager.h b/jni/DvbManager.h index aaa345e7..b01113e1 100644 --- a/jni/DvbManager.h +++ b/jni/DvbManager.h @@ -63,7 +63,7 @@ class DvbManager { int mDvrFd; int mPatFilterFd; int mDvbApiVersion; - int mDeliverySystemTypes[8]; + int mDeliverySystemType; bool mFeHasLock; // Flag for pending tune request. Used for canceling the current tune operation. bool volatile mHasPendingTune; @@ -78,9 +78,6 @@ public: ~DvbManager(); int tune(JNIEnv *env, jobject thiz, const int frequency, const char *modulationStr, int timeout_ms); - int tune(JNIEnv *env, jobject thiz, - const int deliverySystemType, const int frequency, - const char *modulationStr, int timeout_ms); int stopTune(); int readTsStream(JNIEnv *env, jobject thiz, uint8_t *tsBuffer, int tsBufferSize, int timeout_ms); @@ -88,13 +85,9 @@ public: void closeAllDvbPidFilter(); void setHasPendingTune(bool hasPendingTune); int getDeliverySystemType(JNIEnv *env, jobject thiz); - int *getDeliverySystemTypes(JNIEnv *env, jobject thiz); int getSignalStrength(); private: - int tuneInternal(JNIEnv *env, jobject thiz, - const int deliverySystemType, const int frequency, - const char *modulationStr, int timeout_ms); int openDvbFe(JNIEnv *env, jobject thiz); int openDvbDvr(JNIEnv *env, jobject thiz); void closePatFilter(); diff --git a/jni/tunertvinput_jni.cpp b/jni/tunertvinput_jni.cpp index 579b92e2..030f9617 100644 --- a/jni/tunertvinput_jni.cpp +++ b/jni/tunertvinput_jni.cpp @@ -49,12 +49,11 @@ JNIEXPORT void JNICALL Java_com_android_tv_tuner_TunerHal_nativeFinalize( /* * Class: com_android_tv_tuner_TunerHal * Method: nativeTune - * Signature: (JILjava/lang/String;I)Z + * Signature: (JILjava/lang/String;)Z */ -JNIEXPORT jboolean JNICALL - Java_com_android_tv_tuner_TunerHal_nativeTune__JILjava_lang_String_2I( - JNIEnv *env, jobject thiz, jlong deviceId, jint frequency, - jstring modulation, jint timeout_ms) { +JNIEXPORT jboolean JNICALL Java_com_android_tv_tuner_TunerHal_nativeTune( + JNIEnv *env, jobject thiz, jlong deviceId, jint frequency, + jstring modulation, jint timeout_ms) { std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId); DvbManager *dvbManager; if (it == sDvbManagers.end()) { @@ -70,29 +69,6 @@ JNIEXPORT jboolean JNICALL /* * Class: com_android_tv_tuner_TunerHal - * Method: nativeTune - * Signature: (JIILjava/lang/String;I)Z - */ -JNIEXPORT jboolean JNICALL - Java_com_android_tv_tuner_TunerHal_nativeTune__JIILjava_lang_String_2I( - JNIEnv *env, jobject thiz, jlong deviceId, jint deliverySystemType, - jint frequency, jstring modulation, jint timeout_ms) { - std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId); - DvbManager *dvbManager; - if (it == sDvbManagers.end()) { - dvbManager = new DvbManager(env, thiz); - sDvbManagers.insert( - std::pair<jlong, DvbManager *>(deviceId, dvbManager)); - } else { - dvbManager = it->second; - } - int res = dvbManager->tune(env, thiz, deliverySystemType, frequency, - env->GetStringUTFChars(modulation, 0), timeout_ms); - return (res == 0); -} - -/* - * Class: com_android_tv_tuner_TunerHal * Method: nativeCloseAllPidFilters * Signature: (J)V */ @@ -214,32 +190,4 @@ Java_com_android_tv_tuner_TunerHal_nativeGetDeliverySystemType(JNIEnv *env, sDvbManagers.insert(std::pair<jlong, DvbManager *>(deviceId, dvbManager)); return dvbManager->getDeliverySystemType(env, thiz); } -} - -/* - * Class: com_android_tv_tuner_TunerHal - * Method: nativeGetDeliverySystemTypes - * Signature: (J)I - */ -JNIEXPORT jintArray JNICALL -Java_com_android_tv_tuner_TunerHal_nativeGetDeliverySystemTypes(JNIEnv *env, - jobject thiz, - jlong deviceId) { - jintArray deliverySystemTypes = env->NewIntArray(8); - if (deliverySystemTypes == NULL) { - ALOGE("Out of memory!"); - return NULL; - } - std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId); - if (it != sDvbManagers.end()) { - env->SetIntArrayRegion(deliverySystemTypes, 0, 8, - it->second->getDeliverySystemTypes(env, thiz)); - } else { - DvbManager *dvbManager = new DvbManager(env, thiz); - sDvbManagers.insert( - std::pair<jlong, DvbManager *>(deviceId, dvbManager)); - env->SetIntArrayRegion(deliverySystemTypes, 0, 8, - dvbManager->getDeliverySystemTypes(env, thiz)); - } - return deliverySystemTypes; -} +}
\ No newline at end of file diff --git a/jni/tunertvinput_jni.h b/jni/tunertvinput_jni.h index 02c242ba..36e631f5 100755 --- a/jni/tunertvinput_jni.h +++ b/jni/tunertvinput_jni.h @@ -66,18 +66,8 @@ JNIEXPORT void JNICALL Java_com_android_tv_tuner_TunerHal_nativeFinalize * Method: nativeTune * Signature: (JILjava/lang/String;I)Z */ -JNIEXPORT jboolean JNICALL - Java_com_android_tv_tuner_TunerHal_nativeTune__JILjava_lang_String_2I - (JNIEnv *, jobject, jlong, jint, jstring, jint); - -/* - * Class: com_android_tv_tuner_TunerHal - * Method: nativeTune - * Signature: Signature: (JIILjava/lang/String;I)Z - */ -JNIEXPORT jboolean JNICALL - Java_com_android_tv_tuner_TunerHal_nativeTune__JIILjava_lang_String_2I - (JNIEnv *, jobject, jlong, jint, jint, jstring, jint); +JNIEXPORT jboolean JNICALL Java_com_android_tv_tuner_TunerHal_nativeTune + (JNIEnv *, jobject, jlong, jint, jstring, jint); /* * Class: com_android_tv_tuner_TunerHal @@ -116,15 +106,6 @@ Java_com_android_tv_tuner_TunerHal_nativeGetDeliverySystemType /* * Class: com_android_tv_tuner_TunerHal - * Method: nativeGetDeliverySystemTypes - * Signature: (J)I - */ -JNIEXPORT jintArray JNICALL -Java_com_android_tv_tuner_TunerHal_nativeGetDeliverySystemTypes - (JNIEnv *, jobject, jlong); - -/* - * Class: com_android_tv_tuner_TunerHal * Method: nativeGetSignalStrength * Signature: (J)I */ diff --git a/libs/Android.bp b/libs/Android.bp index 7c41f4ea..fea94875 100644 --- a/libs/Android.bp +++ b/libs/Android.bp @@ -13,15 +13,8 @@ // limitations under the License. java_import { - name: "tv-auto-common-jar", - jars: ["m2/auto-common-0.10.jar"], - host_supported: true, - sdk_version: "current", -} - -java_import { name: "tv-auto-factory-jar", - jars: ["m2/auto-factory-1.0-beta6.jar"], + jars: ["auto-factory-1.0-beta2.jar"], host_supported: true, sdk_version: "current", } @@ -29,22 +22,20 @@ java_import { java_plugin { name: "tv-auto-factory", static_libs: [ - "jsr330", - "tv-auto-common-jar", + "jsr330", "tv-auto-factory-jar", - "tv-auto-value-jar", - "tv-google-java-format-jar", "tv-guava-jre-jar", - "tv-javapoet-jar", - "tv-javax-annotations-jar", + "tv-javawriter-jar", + "tv-javax-annotations-jar", ], processor_class: "com.google.auto.factory.processor.AutoFactoryProcessor", generates_api: true, } + java_import { name: "tv-auto-value-jar", - jars: ["m2/auto-value-1.5.3.jar"], + jars: ["auto-value-1.5.2.jar"], host_supported: true, sdk_version: "current", } @@ -60,40 +51,26 @@ java_plugin { java_import { name: "tv-error-prone-annotations-jar", - jars: ["m2/error_prone_annotations-2.3.2.jar"], - sdk_version: "current", -} - -java_import { - name: "tv-google-java-format-jar", - jars: ["google-java-format-1.7-all-deps.jar"], - host_supported: true, - sdk_version: "current", -} - -java_import { - name: "tv-guava-android-jar", - jars: ["m2/guava-28.0-android.jar"], + jars: ["error_prone_annotations-2.3.1.jar"], sdk_version: "current", } java_import { name: "tv-guava-jre-jar", - jars: ["m2/guava-28.0-jre.jar"], + jars: ["guava-23.3-jre.jar"], host_supported: true, sdk_version: "current", } java_import { - name: "tv-guava-failureaccess-jar", - jars: ["m2/failureaccess-1.0.1.jar"], - host_supported: true, + name: "tv-guava-android-jar", + jars: ["guava-23.6-android.jar"], sdk_version: "current", } -java_import_host { - name: "tv-javapoet-jar", - jars: ["m2/javapoet-1.11.1.jar"], +java_import_host{ + name: "tv-javawriter-jar", + jars: ["javawriter-2.5.1.jar"], } java_import { @@ -103,6 +80,7 @@ java_import { sdk_version: "current", } + android_library_import { name: "tv-lib-exoplayer", aars: ["exoplayer-r1.5.16.aar"], @@ -111,22 +89,31 @@ android_library_import { android_library_import { name: "tv-lib-exoplayer-v2-core", - aars: ["exoplayer-core-2.10.1.aar"], + aars: ["exoplayer-core-2.9.0.aar"], sdk_version: "current", } java_import_host { + name: "tv-lib-dagger-compiler-deps", + jars: [ + "google-java-format-1.4-all-deps.jar", + "guava-23.3-jre.jar", + "javapoet-1.8.0.jar", + ], +} + +java_import_host { name: "tv-lib-dagger-compiler-import", jars: [ - "m2/dagger-compiler-2.23.jar", - "m2/dagger-producers-2.23.jar", - "m2/dagger-spi-2.23.jar", + "dagger-compiler-2.15.jar", + "dagger-producers-2.15.jar", + "dagger-spi-2.15.jar", ], } java_import { name: "tv-lib-dagger", - jars: ["m2/dagger-2.23.jar"], + jars: ["dagger-2.15.jar"], host_supported: true, sdk_version: "current", } @@ -135,30 +122,26 @@ java_plugin { name: "tv-lib-dagger-compiler", static_libs: [ "tv-lib-dagger-compiler-import", - "tv-guava-jre-jar", - "tv-javapoet-jar", + "tv-lib-dagger-compiler-deps", "jsr330", "tv-lib-dagger", ], processor_class: "dagger.internal.codegen.ComponentProcessor", generates_api: true, - // shade guava to avoid conflicts with guava embedded in Error Prone. - jarjar_rules: "m2/dagger-jarjar-rules.txt", } android_library_import { name: "tv-lib-dagger-android", - aars: ["m2/dagger-android-2.23.aar"], + aars: ["dagger-android-2.15.aar"], sdk_version: "current", } java_import_host { name: "tv-lib-dagger-android-processor-import", jars: [ - "m2/dagger-android-jarimpl-2.23.jar", - "m2/dagger-android-processor-2.23.jar", - "m2/dagger-spi-2.23.jar", - "m2/protobuf-java-3.7.0.jar", + "dagger-android-jarimpl-2.15.jar", + "dagger-android-processor-2.15.jar", + "dagger-android-support-jarimpl-2.15.jar", ], } @@ -166,22 +149,17 @@ java_plugin { name: "tv-lib-dagger-android-processor", static_libs: [ "tv-lib-dagger-android-processor-import", - "tv-guava-jre-jar", - "tv-guava-failureaccess-jar", - "tv-javapoet-jar", - "tv-google-java-format-jar", + "tv-lib-dagger-compiler-deps", "jsr330", "tv-lib-dagger", ], processor_class: "dagger.android.processor.AndroidProcessor", generates_api: true, - // shade guava to avoid conflicts with guava embedded in Error Prone. - jarjar_rules: "m2/dagger-jarjar-rules.txt", } java_import { name: "tv-lib-truth", - jars: ["truth-0.45.jar"], + jars: ["truth-0.36.jar"], host_supported: true, sdk_version: "current", } diff --git a/libs/auto-factory-1.0-beta2.jar b/libs/auto-factory-1.0-beta2.jar Binary files differnew file mode 100644 index 00000000..ceaddac7 --- /dev/null +++ b/libs/auto-factory-1.0-beta2.jar diff --git a/libs/auto-value-1.5.2.jar b/libs/auto-value-1.5.2.jar Binary files differnew file mode 100644 index 00000000..8ac05679 --- /dev/null +++ b/libs/auto-value-1.5.2.jar diff --git a/libs/dagger-2.15.jar b/libs/dagger-2.15.jar Binary files differnew file mode 100644 index 00000000..6d766885 --- /dev/null +++ b/libs/dagger-2.15.jar diff --git a/libs/dagger-android-2.15.aar b/libs/dagger-android-2.15.aar Binary files differnew file mode 100644 index 00000000..430294a2 --- /dev/null +++ b/libs/dagger-android-2.15.aar diff --git a/libs/dagger-android-jarimpl-2.15.jar b/libs/dagger-android-jarimpl-2.15.jar Binary files differnew file mode 100644 index 00000000..7f7cd459 --- /dev/null +++ b/libs/dagger-android-jarimpl-2.15.jar diff --git a/libs/dagger-android-processor-2.15.jar b/libs/dagger-android-processor-2.15.jar Binary files differnew file mode 100644 index 00000000..3c7ac054 --- /dev/null +++ b/libs/dagger-android-processor-2.15.jar diff --git a/libs/dagger-android-support-2.15.aar b/libs/dagger-android-support-2.15.aar Binary files differnew file mode 100644 index 00000000..89a71a91 --- /dev/null +++ b/libs/dagger-android-support-2.15.aar diff --git a/libs/dagger-android-support-jarimpl-2.15.jar b/libs/dagger-android-support-jarimpl-2.15.jar Binary files differnew file mode 100644 index 00000000..d0ea01a7 --- /dev/null +++ b/libs/dagger-android-support-jarimpl-2.15.jar diff --git a/libs/dagger-compiler-2.15.jar b/libs/dagger-compiler-2.15.jar Binary files differnew file mode 100644 index 00000000..e73110f6 --- /dev/null +++ b/libs/dagger-compiler-2.15.jar diff --git a/libs/dagger-producers-2.15.jar b/libs/dagger-producers-2.15.jar Binary files differnew file mode 100644 index 00000000..f1dbb07a --- /dev/null +++ b/libs/dagger-producers-2.15.jar diff --git a/libs/dagger-spi-2.15.jar b/libs/dagger-spi-2.15.jar Binary files differnew file mode 100644 index 00000000..6e3156a9 --- /dev/null +++ b/libs/dagger-spi-2.15.jar diff --git a/libs/error_prone_annotations-2.3.1.jar b/libs/error_prone_annotations-2.3.1.jar Binary files differnew file mode 100644 index 00000000..8a0efa37 --- /dev/null +++ b/libs/error_prone_annotations-2.3.1.jar diff --git a/libs/exoplayer-core-2.10.1.aar b/libs/exoplayer-core-2.10.1.aar Binary files differdeleted file mode 100644 index 2342feda..00000000 --- a/libs/exoplayer-core-2.10.1.aar +++ /dev/null diff --git a/libs/exoplayer-core-2.9.0.aar b/libs/exoplayer-core-2.9.0.aar Binary files differnew file mode 100644 index 00000000..64c4f37f --- /dev/null +++ b/libs/exoplayer-core-2.9.0.aar diff --git a/libs/google-java-format-1.7-all-deps.jar b/libs/google-java-format-1.4-all-deps.jar Binary files differindex e2d40de4..b10bfbd6 100644 --- a/libs/google-java-format-1.7-all-deps.jar +++ b/libs/google-java-format-1.4-all-deps.jar diff --git a/libs/guava-23.3-jre.jar b/libs/guava-23.3-jre.jar Binary files differnew file mode 100644 index 00000000..b13e275f --- /dev/null +++ b/libs/guava-23.3-jre.jar diff --git a/libs/guava-23.5-jre.jar b/libs/guava-23.5-jre.jar Binary files differnew file mode 100644 index 00000000..7e5f13a8 --- /dev/null +++ b/libs/guava-23.5-jre.jar diff --git a/libs/guava-23.6-android.jar b/libs/guava-23.6-android.jar Binary files differnew file mode 100644 index 00000000..01180d23 --- /dev/null +++ b/libs/guava-23.6-android.jar diff --git a/libs/javapoet-1.8.0.jar b/libs/javapoet-1.8.0.jar Binary files differnew file mode 100644 index 00000000..6758b6d7 --- /dev/null +++ b/libs/javapoet-1.8.0.jar diff --git a/libs/javawriter-2.5.1.jar b/libs/javawriter-2.5.1.jar Binary files differnew file mode 100644 index 00000000..4ec579e7 --- /dev/null +++ b/libs/javawriter-2.5.1.jar diff --git a/libs/m2/animal-sniffer-annotations-1.17.jar b/libs/m2/animal-sniffer-annotations-1.17.jar Binary files differdeleted file mode 100644 index 6ec7a603..00000000 --- a/libs/m2/animal-sniffer-annotations-1.17.jar +++ /dev/null diff --git a/libs/m2/auto-common-0.10.jar b/libs/m2/auto-common-0.10.jar Binary files differdeleted file mode 100644 index 8cbfa729..00000000 --- a/libs/m2/auto-common-0.10.jar +++ /dev/null diff --git a/libs/m2/auto-factory-1.0-beta6.jar b/libs/m2/auto-factory-1.0-beta6.jar Binary files differdeleted file mode 100644 index e47130f2..00000000 --- a/libs/m2/auto-factory-1.0-beta6.jar +++ /dev/null diff --git a/libs/m2/auto-value-1.5.3.jar b/libs/m2/auto-value-1.5.3.jar Binary files differdeleted file mode 100644 index 99eeb0b3..00000000 --- a/libs/m2/auto-value-1.5.3.jar +++ /dev/null diff --git a/libs/m2/checker-qual-2.8.1.jar b/libs/m2/checker-qual-2.8.1.jar Binary files differdeleted file mode 100644 index 09269be6..00000000 --- a/libs/m2/checker-qual-2.8.1.jar +++ /dev/null diff --git a/libs/m2/dagger-2.23.jar b/libs/m2/dagger-2.23.jar Binary files differdeleted file mode 100644 index 544ee3d6..00000000 --- a/libs/m2/dagger-2.23.jar +++ /dev/null diff --git a/libs/m2/dagger-android-2.23.aar b/libs/m2/dagger-android-2.23.aar Binary files differdeleted file mode 100644 index 9578dcde..00000000 --- a/libs/m2/dagger-android-2.23.aar +++ /dev/null diff --git a/libs/m2/dagger-android-jarimpl-2.23.jar b/libs/m2/dagger-android-jarimpl-2.23.jar Binary files differdeleted file mode 100644 index 94a2bbef..00000000 --- a/libs/m2/dagger-android-jarimpl-2.23.jar +++ /dev/null diff --git a/libs/m2/dagger-android-processor-2.23.jar b/libs/m2/dagger-android-processor-2.23.jar Binary files differdeleted file mode 100644 index 500149c6..00000000 --- a/libs/m2/dagger-android-processor-2.23.jar +++ /dev/null diff --git a/libs/m2/dagger-compiler-2.23.jar b/libs/m2/dagger-compiler-2.23.jar Binary files differdeleted file mode 100644 index b7cb1624..00000000 --- a/libs/m2/dagger-compiler-2.23.jar +++ /dev/null diff --git a/libs/m2/dagger-jarjar-rules.txt b/libs/m2/dagger-jarjar-rules.txt deleted file mode 100644 index 618c2434..00000000 --- a/libs/m2/dagger-jarjar-rules.txt +++ /dev/null @@ -1,4 +0,0 @@ -# shade guava to avoid conflicts with guava embedded in Error Prone. -rule com.google.common.** com.google.dagger.common.@1 -rule com.google.auto.** com.google.dagger.auto.@1 - diff --git a/libs/m2/dagger-producers-2.23.jar b/libs/m2/dagger-producers-2.23.jar Binary files differdeleted file mode 100644 index cb1cef95..00000000 --- a/libs/m2/dagger-producers-2.23.jar +++ /dev/null diff --git a/libs/m2/dagger-spi-2.23.jar b/libs/m2/dagger-spi-2.23.jar Binary files differdeleted file mode 100644 index 6af1494d..00000000 --- a/libs/m2/dagger-spi-2.23.jar +++ /dev/null diff --git a/libs/m2/error_prone_annotations-2.3.2.jar b/libs/m2/error_prone_annotations-2.3.2.jar Binary files differdeleted file mode 100644 index bc2584db..00000000 --- a/libs/m2/error_prone_annotations-2.3.2.jar +++ /dev/null diff --git a/libs/m2/failureaccess-1.0.1.jar b/libs/m2/failureaccess-1.0.1.jar Binary files differdeleted file mode 100644 index 9b56dc75..00000000 --- a/libs/m2/failureaccess-1.0.1.jar +++ /dev/null diff --git a/libs/m2/guava-28.0-android.jar b/libs/m2/guava-28.0-android.jar Binary files differdeleted file mode 100644 index 516fc5fa..00000000 --- a/libs/m2/guava-28.0-android.jar +++ /dev/null diff --git a/libs/m2/guava-28.0-jre.jar b/libs/m2/guava-28.0-jre.jar Binary files differdeleted file mode 100644 index f254aae7..00000000 --- a/libs/m2/guava-28.0-jre.jar +++ /dev/null diff --git a/libs/m2/j2objc-annotations-1.3.jar b/libs/m2/j2objc-annotations-1.3.jar Binary files differdeleted file mode 100644 index a429c721..00000000 --- a/libs/m2/j2objc-annotations-1.3.jar +++ /dev/null diff --git a/libs/m2/javac-shaded-9-dev-r4023-3.jar b/libs/m2/javac-shaded-9-dev-r4023-3.jar Binary files differdeleted file mode 100644 index d7b3fd8c..00000000 --- a/libs/m2/javac-shaded-9-dev-r4023-3.jar +++ /dev/null diff --git a/libs/m2/javapoet-1.11.1.jar b/libs/m2/javapoet-1.11.1.jar Binary files differdeleted file mode 100644 index 27a18e8b..00000000 --- a/libs/m2/javapoet-1.11.1.jar +++ /dev/null diff --git a/libs/m2/jsr305-3.0.2.jar b/libs/m2/jsr305-3.0.2.jar Binary files differdeleted file mode 100644 index 59222d9c..00000000 --- a/libs/m2/jsr305-3.0.2.jar +++ /dev/null diff --git a/libs/m2/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar b/libs/m2/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar Binary files differdeleted file mode 100644 index 45832c05..00000000 --- a/libs/m2/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar +++ /dev/null diff --git a/libs/m2/pom-jre.xml b/libs/m2/pom-jre.xml deleted file mode 100644 index 2d834c33..00000000 --- a/libs/m2/pom-jre.xml +++ /dev/null @@ -1,47 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2019 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 - --> - -<!-- JRE version of libs, in particular guava --> -<project> - <modelVersion>4.0.0</modelVersion> - <groupId>com.android.tv</groupId> - <artifactId>jre-libs</artifactId> - <version>1</version> - - <repositories> - <repository> - <id>google</id> - <name>Google Maven Repository</name> - <url>https://maven.google.com</url> - <layout>default</layout> - <snapshots> - <enabled>false</enabled> - </snapshots> - </repository> - </repositories> - - <dependencies> - - - <dependency> - <groupId>com.google.guava</groupId> - <artifactId>guava</artifactId> - <version>28.0-jre</version> - </dependency> - - </dependencies> -</project>
\ No newline at end of file diff --git a/libs/m2/pom.xml b/libs/m2/pom.xml deleted file mode 100644 index 5a232d56..00000000 --- a/libs/m2/pom.xml +++ /dev/null @@ -1,98 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2019 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 - --> -<project> - <modelVersion>4.0.0</modelVersion> - <groupId>com.android.tv</groupId> - <artifactId>libs</artifactId> - <version>1</version> - - <repositories> - <repository> - <id>google</id> - <name>Google Maven Repository</name> - <url>https://maven.google.com</url> - <layout>default</layout> - <snapshots> - <enabled>false</enabled> - </snapshots> - </repository> - </repositories> - - <dependencies> - <dependency> - <groupId>com.google.auto</groupId> - <artifactId>auto-common</artifactId> - <version>0.10</version> - </dependency> - <dependency> - <groupId>com.google.auto.factory</groupId> - <artifactId>auto-factory</artifactId> - <version>1.0-beta6</version> - </dependency> - <dependency> - <groupId>com.google.dagger</groupId> - <artifactId>dagger</artifactId> - <version>2.23</version> - </dependency> - <dependency> - <groupId>com.google.dagger</groupId> - <artifactId>dagger-android</artifactId> - <type>aar</type> - <version>2.23</version> - </dependency> - <dependency> - <groupId>com.google.dagger</groupId> - <artifactId>dagger-android-jarimpl</artifactId> - <version>2.23</version> - </dependency> - <dependency> - <groupId>com.google.dagger</groupId> - <artifactId>dagger-android-processor</artifactId> - <version>2.23</version> - </dependency> - <dependency> - <groupId>com.google.dagger</groupId> - <artifactId>dagger-compiler</artifactId> - <version>2.23</version> - </dependency> - <dependency> - <groupId>com.google.dagger</groupId> - <artifactId>dagger-producers</artifactId> - <version>2.23</version> - </dependency> - <dependency> - <groupId>com.google.dagger</groupId> - <artifactId>dagger-spi</artifactId> - <version>2.23</version> - </dependency> - - - <dependency> - <groupId>com.google.guava</groupId> - <artifactId>guava</artifactId> - <version>28.0-android</version> - </dependency> - - <!-- The host version of guava is listed in pom-jre.xml --> - - <dependency> - <groupId>com.squareup</groupId> - <artifactId>javapoet</artifactId> - <version>1.11.1</version> - </dependency> - </dependencies> -</project>
\ No newline at end of file diff --git a/libs/m2/protobuf-java-3.7.0.jar b/libs/m2/protobuf-java-3.7.0.jar Binary files differdeleted file mode 100644 index eebaefeb..00000000 --- a/libs/m2/protobuf-java-3.7.0.jar +++ /dev/null diff --git a/libs/m2/update.sh b/libs/m2/update.sh deleted file mode 100755 index ee455c7b..00000000 --- a/libs/m2/update.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2019 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. - - -git rm *.jar *.aar - -EXCLUDES=google-java-format,javax.inject,support-annotations,jsr250-api,checker-compat-qual - -mvn \ - -DoutputDirectory=${pwd} \ - dependency:copy-dependencies \ - -DincludeScope=runtime \ - -DexcludeArtifactIds=${EXCLUDES} - -mvn \ - -DoutputDirectory=${pwd} \ - -f pom-jre.xml \ - dependency:copy-dependencies \ - -DincludeScope=runtime \ - -DexcludeArtifactIds=${EXCLUDES} - -git add *.jar *.aar - - diff --git a/libs/truth-0.36.jar b/libs/truth-0.36.jar Binary files differnew file mode 100644 index 00000000..8174e4a9 --- /dev/null +++ b/libs/truth-0.36.jar diff --git a/libs/truth-0.45.jar b/libs/truth-0.45.jar Binary files differdeleted file mode 100644 index 76e4da8a..00000000 --- a/libs/truth-0.45.jar +++ /dev/null diff --git a/partner_support/AndroidManifest.xml b/partner_support/AndroidManifest.xml index 8f807084..45a693fc 100644 --- a/partner_support/AndroidManifest.xml +++ b/partner_support/AndroidManifest.xml @@ -17,6 +17,6 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.google.android.tv.partner.support" android:versionCode="1"> - <uses-sdk android:targetSdkVersion="28" android:minSdkVersion="23"/> + <uses-sdk android:targetSdkVersion="27" android:minSdkVersion="23"/> <application /> </manifest> diff --git a/partner_support/g3doc/CloudEpgForPartners.md b/partner_support/g3doc/CloudEpgForPartners.md new file mode 100644 index 00000000..bec6b504 --- /dev/null +++ b/partner_support/g3doc/CloudEpgForPartners.md @@ -0,0 +1,112 @@ +# 3rd party instructions for using Cloud EPG feature of Live Channels + +Partners can ask Live Channels to retrieve EPG data for their TV Input Service +using live channels + +## Prerequisites + +* Updated agreement with Google +* Oreo or patched Nougat + +## Nougat + +To use cloud epg with Nougat you will need the following changes. + +### Patch TVProvider + +To run in Nougat you must cherry pick [change +455319](https://android-review.googlesource.com/c/platform/packages/providers/TvProvider/+/455319) +to TV Provider. + +### Customisation + +Indicate TvProvider is patched by including the following in their TV +customization resource + +``` +<bool name="tvprovider_allows_system_inserts_to_program_table">true</bool> +``` + +See https://source.android.com/devices/tv/customize-tv-app + +## **Input Setup** + +During the input setup activity, the TIS will query the content provider for +lineups in a given postal code. The TIS then inserts a row to the inputs table +with input_id and lineup_id + +On completion of the activity the TIS sets the extra data in the result to + +* `com.android.tv.extra.USE_CLOUD_EPG = true` +* `TvInputInfo.EXTRA_INPUT_ID` with their input_id + +This is used to tell Live Channels to immediately start the EPG fetch for that +input. + +### Sample Input Setup code. + +A complete sample is at +../third_party/samples/src/com/example/partnersupportsampletvinput + +#### query lineup + +```java + private AsyncTask<Void, Void, List<Lineup>> createFetchLineupsTask() { + return new AsyncTask<Void, Void, List<Lineup>>() { + @Override + protected List<Lineup> doInBackground(Void... params) { + ContentResolver cr = getActivity().getContentResolver(); + + List<Lineup> results = new ArrayList<>(); + Cursor cursor = + cr.query( + Uri.parse( + "content://com.android.tv.data.epg/lineups/postal_code/" + + ZIP), + null, + null, + null, + null); + + while (cursor.moveToNext()) { + String id = cursor.getString(0); + String name = cursor.getString(1); + String channels = cursor.getString(2); + results.add(new Lineup(id, name, channels)); + } + + return results; + } + + @Override + protected void onPostExecute(List<Lineup> lineups) { + showLineups(lineups); + } + }; + } +``` + +#### Insert cloud_epg_input + +```java +ContentValues values = new ContentValues(); +values.put(EpgContract.EpgInputs.COLUMN_INPUT_ID, SampleTvInputService.INPUT_ID); +values.put(EpgContract.EpgInputs.COLUMN_LINEUP_ID, lineup.getId()); +ContentResolver contentResolver = getActivity().getContentResolver(); +EpgInput epgInput = EpgInputs.queryEpgInput(contentResolver, SampleTvInputService.INPUT_ID); +if (epgInput == null) { + contentResolver.insert(EpgContract.EpgInputs.CONTENT_URI, values); +} else { + values.put(EpgContract.EpgInputs.COLUMN_ID, epgInput.getId()); + EpgInputs.update(contentResolver, EpgInput.createEpgChannel(values)); +} +``` + +#### Return use_cloud_epg + +```java +Intent data = new Intent(); +data.putExtra(TvInputInfo.EXTRA_INPUT_ID, inputId); +data.putExtra(com.android.tv.extra.USE_CLOUD_EPG, true); +setResult(Activity.RESULT_OK, data); +``` diff --git a/partner_support/g3doc/SeriesIdColumnForPartners.md b/partner_support/g3doc/SeriesIdColumnForPartners.md new file mode 100644 index 00000000..cd44db03 --- /dev/null +++ b/partner_support/g3doc/SeriesIdColumnForPartners.md @@ -0,0 +1,30 @@ +# 3rd party instructions for using series recording feature of Live Channels + +## Prerequisites + +* Updated agreement with Google +* Oreo or patched Nougat + +## Nougat + +To enable series recording with Nougat you will need the following changes. + +### Patch TVProvider + +To run in Nougat you must backport the following changes + +* [Filter out non-existing customized columns in + DB](https://partner-android.googlesource.com/platform/packages/providers/TvProvider/+/142162af889b2c124bb012eea608c6a65eed54bb) +* [Add TvProvider methods to get and add + columns](https://partner-android.googlesource.com/platform/packages/providers/TvProvider/+/cda6788ae903513a555fd3e07a5a1c14218c40a2) + +### Customisation + +Indicate TvProvider is patched by including the following in their TV +customization resource + +``` +<bool name="tvprovider_allows_column_creation">true</bool> +``` + +See https://source.android.com/devices/tv/customize-tv-app diff --git a/partner_support/g3doc/TurnOffEmbeddedTuner.md b/partner_support/g3doc/TurnOffEmbeddedTuner.md new file mode 100644 index 00000000..0ba7cff2 --- /dev/null +++ b/partner_support/g3doc/TurnOffEmbeddedTuner.md @@ -0,0 +1,15 @@ +# 3rd party instructions turning off the embedded tuner in Live Channels + +Partners that have a built in tuner should provide a TV Input like +SampleDvbTuner. When partners provide their own tuner they MUST turn of the +embedded tuner in Live Channels. + +### Customisation + +Indicate Live Channels should not use it's embedded tuner implementation. + +``` +<bool name="turn_off_embedded_tuner">true</bool> +``` + +See https://source.android.com/devices/tv/customize-tv-app diff --git a/partner_support/sample_customization/AndroidManifest.xml b/partner_support/sample_customization/AndroidManifest.xml index 5e4c2c7c..804691a6 100644 --- a/partner_support/sample_customization/AndroidManifest.xml +++ b/partner_support/sample_customization/AndroidManifest.xml @@ -24,7 +24,7 @@ <uses-feature android:name="android.software.leanback" android:required="true" /> <uses-feature android:name="android.hardware.touchscreen" android:required="false" /> - <uses-sdk android:targetSdkVersion="28" android:minSdkVersion="23"/> + <uses-sdk android:targetSdkVersion="27" android:minSdkVersion="23"/> <application android:label="Partner Customization" android:theme="@android:style/Theme.Holo.Light.NoActionBar" diff --git a/partner_support/samples/Android.bp b/partner_support/samples/Android.bp deleted file mode 100644 index 9c1d2db8..00000000 --- a/partner_support/samples/Android.bp +++ /dev/null @@ -1,25 +0,0 @@ -android_app { - name: "PartnerSupportSampleTvInput", - - // Include all java files. - srcs: ["src/**/*.java"], - - static_libs: [ - "androidx.leanback_leanback", - "androidx.tvprovider_tvprovider", - "live-channels-partner-support", - ], - - optimize: { - enabled: false, - }, - // Overlay view related functionality requires system APIs. - sdk_version: "system_current", - min_sdk_version: "23", // M - - // Required for com.android.tv.permission.RECEIVE_INPUT_EVENT - privileged: true, - - resource_dirs: ["res"], - -} diff --git a/partner_support/samples/Android.mk b/partner_support/samples/Android.mk new file mode 100644 index 00000000..2e771a5b --- /dev/null +++ b/partner_support/samples/Android.mk @@ -0,0 +1,33 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +# Include all java files. +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_PACKAGE_NAME := PartnerSupportSampleTvInput +LOCAL_MODULE_TAGS := optional + +LOCAL_STATIC_JAVA_LIBRARIES := \ + android-support-annotations \ + live-channels-partner-support + +LOCAL_STATIC_ANDROID_LIBRARIES := \ + android-support-compat \ + android-support-core-ui \ + android-support-v7-recyclerview \ + android-support-v17-leanback \ + androidx.tvprovider_tvprovider + +LOCAL_USE_AAPT2 := true + +LOCAL_PROGUARD_ENABLED := disabled +# Overlay view related functionality requires system APIs. +LOCAL_SDK_VERSION := system_current +LOCAL_MIN_SDK_VERSION := 23 # M + +# Required for com.android.tv.permission.RECEIVE_INPUT_EVENT +LOCAL_PRIVILEGED_MODULE := true + +LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res + +include $(BUILD_PACKAGE) diff --git a/partner_support/samples/AndroidManifest.xml b/partner_support/samples/AndroidManifest.xml index 65b2a3ba..d91c603a 100644 --- a/partner_support/samples/AndroidManifest.xml +++ b/partner_support/samples/AndroidManifest.xml @@ -29,7 +29,7 @@ <uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA" /> <uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" /> <uses-permission android:name="com.android.tv.permission.RECEIVE_INPUT_EVENT" /> - <uses-sdk android:targetSdkVersion="28" android:minSdkVersion="23"/> + <uses-sdk android:targetSdkVersion="27" android:minSdkVersion="23"/> <!--TODO(b/68949299): remove tool hint when we have smaller dependency targets--> <application android:label="@string/partner_support_sample_tv_input" tools:replace="android:label,icon,theme,appComponentFactory" diff --git a/partner_support/samples/src/com/example/partnersupportsampletvinput/ChannelScanFragment.java b/partner_support/samples/src/com/example/partnersupportsampletvinput/ChannelScanFragment.java index d449bb5f..ec7589cb 100644 --- a/partner_support/samples/src/com/example/partnersupportsampletvinput/ChannelScanFragment.java +++ b/partner_support/samples/src/com/example/partnersupportsampletvinput/ChannelScanFragment.java @@ -23,10 +23,10 @@ import android.os.AsyncTask; import android.os.Bundle; import android.os.SystemClock; import android.support.annotation.NonNull; -import androidx.leanback.app.GuidedStepFragment; -import androidx.leanback.widget.GuidanceStylist; -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; +import android.support.v17.leanback.app.GuidedStepFragment; +import android.support.v17.leanback.widget.GuidanceStylist; +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.leanback.widget.GuidedAction; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/partner_support/samples/src/com/example/partnersupportsampletvinput/LineupSelectionFragment.java b/partner_support/samples/src/com/example/partnersupportsampletvinput/LineupSelectionFragment.java index 7486a981..8c3ca77a 100644 --- a/partner_support/samples/src/com/example/partnersupportsampletvinput/LineupSelectionFragment.java +++ b/partner_support/samples/src/com/example/partnersupportsampletvinput/LineupSelectionFragment.java @@ -24,24 +24,21 @@ import android.os.AsyncTask; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.v17.leanback.app.GuidedStepFragment; +import android.support.v17.leanback.widget.GuidanceStylist; +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.leanback.widget.GuidedAction; import android.text.TextUtils; import android.util.Log; import android.util.Pair; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; - -import androidx.leanback.app.GuidedStepFragment; -import androidx.leanback.widget.GuidanceStylist; -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; - import com.google.android.tv.partner.support.EpgContract; import com.google.android.tv.partner.support.EpgInput; import com.google.android.tv.partner.support.EpgInputs; import com.google.android.tv.partner.support.Lineup; import com.google.android.tv.partner.support.Lineups; - import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -179,7 +176,7 @@ public class LineupSelectionFragment extends GuidedStepFragment { List<Lineup> lineups, List<String> localChannels) { List<Pair<Lineup, Integer>> result = new ArrayList<>(); for (Lineup lineup : lineups) { - result.add(Pair.create(lineup, getMatchCount(lineup.getChannels(), localChannels))); + result.add(new Pair<>(lineup, getMatchCount(lineup.getChannels(), localChannels))); } // sort in decreasing order Collections.sort( diff --git a/partner_support/samples/src/com/example/partnersupportsampletvinput/LocationFragment.java b/partner_support/samples/src/com/example/partnersupportsampletvinput/LocationFragment.java index 532ff9bd..9492e7e5 100644 --- a/partner_support/samples/src/com/example/partnersupportsampletvinput/LocationFragment.java +++ b/partner_support/samples/src/com/example/partnersupportsampletvinput/LocationFragment.java @@ -19,10 +19,10 @@ package com.example.partnersupportsampletvinput; import android.app.FragmentManager; import android.os.Bundle; import android.support.annotation.NonNull; -import androidx.leanback.app.GuidedStepFragment; -import androidx.leanback.widget.GuidanceStylist; -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; +import android.support.v17.leanback.app.GuidedStepFragment; +import android.support.v17.leanback.widget.GuidanceStylist; +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.leanback.widget.GuidedAction; import java.util.List; /** Location Fragment for users to enter postal code */ diff --git a/partner_support/samples/src/com/example/partnersupportsampletvinput/ResultFragment.java b/partner_support/samples/src/com/example/partnersupportsampletvinput/ResultFragment.java index 0c893182..a1c17acd 100644 --- a/partner_support/samples/src/com/example/partnersupportsampletvinput/ResultFragment.java +++ b/partner_support/samples/src/com/example/partnersupportsampletvinput/ResultFragment.java @@ -21,10 +21,10 @@ import android.content.Intent; import android.media.tv.TvInputInfo; import android.os.Bundle; import android.support.annotation.NonNull; -import androidx.leanback.app.GuidedStepFragment; -import androidx.leanback.widget.GuidanceStylist; -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; +import android.support.v17.leanback.app.GuidedStepFragment; +import android.support.v17.leanback.widget.GuidanceStylist; +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.leanback.widget.GuidedAction; import com.google.android.tv.partner.support.EpgContract; import java.util.List; diff --git a/partner_support/samples/src/com/example/partnersupportsampletvinput/SampleTvInputSetupActivity.java b/partner_support/samples/src/com/example/partnersupportsampletvinput/SampleTvInputSetupActivity.java index e11ebdfc..a0a75881 100644 --- a/partner_support/samples/src/com/example/partnersupportsampletvinput/SampleTvInputSetupActivity.java +++ b/partner_support/samples/src/com/example/partnersupportsampletvinput/SampleTvInputSetupActivity.java @@ -18,7 +18,7 @@ package com.example.partnersupportsampletvinput; import android.app.Activity; import android.os.Bundle; -import androidx.leanback.app.GuidedStepFragment; +import android.support.v17.leanback.app.GuidedStepFragment; /** The setup activity for partner support sample TV input. */ public class SampleTvInputSetupActivity extends Activity { diff --git a/partner_support/samples/src/com/example/partnersupportsampletvinput/WelcomeFragment.java b/partner_support/samples/src/com/example/partnersupportsampletvinput/WelcomeFragment.java index 96632d36..286f34f2 100644 --- a/partner_support/samples/src/com/example/partnersupportsampletvinput/WelcomeFragment.java +++ b/partner_support/samples/src/com/example/partnersupportsampletvinput/WelcomeFragment.java @@ -19,10 +19,10 @@ package com.example.partnersupportsampletvinput; import android.app.FragmentManager; import android.os.Bundle; import android.support.annotation.NonNull; -import androidx.leanback.app.GuidedStepFragment; -import androidx.leanback.widget.GuidanceStylist; -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; +import android.support.v17.leanback.app.GuidedStepFragment; +import android.support.v17.leanback.widget.GuidanceStylist; +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.leanback.widget.GuidedAction; import java.util.List; /** Welcome Fragment shows welcome information for users */ diff --git a/partner_support/src/com/google/android/tv/partner/support/EpgInput.java b/partner_support/src/com/google/android/tv/partner/support/EpgInput.java index c591c9fe..20b3542a 100644 --- a/partner_support/src/com/google/android/tv/partner/support/EpgInput.java +++ b/partner_support/src/com/google/android/tv/partner/support/EpgInput.java @@ -20,7 +20,7 @@ import android.content.ContentValues; import com.google.auto.value.AutoValue; /** - * Value class representing a TV Input that uses TV app EPG. + * Value class representing a TV Input that uses Live TV EPG. * * @see {@link EpgContract.EpgInputs} */ diff --git a/partner_support/src/com/google/android/tv/partner/support/TunerSetupUtils.java b/partner_support/src/com/google/android/tv/partner/support/TunerSetupUtils.java index d50db7d8..e25d5836 100644 --- a/partner_support/src/com/google/android/tv/partner/support/TunerSetupUtils.java +++ b/partner_support/src/com/google/android/tv/partner/support/TunerSetupUtils.java @@ -20,7 +20,6 @@ import android.support.annotation.VisibleForTesting; import android.text.TextUtils; import android.util.Log; import android.util.Pair; - import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -40,7 +39,7 @@ public class TunerSetupUtils { List<List<String>> parsedLocalChannels = parseChannelNumbers(localChannels); for (Lineup lineup : lineups) { result.add( - Pair.create(lineup, getMatchCount(lineup.getChannels(), parsedLocalChannels))); + new Pair<>(lineup, getMatchCount(lineup.getChannels(), parsedLocalChannels))); } // sort in decreasing order Collections.sort( diff --git a/partner_support/tests/robotests/javatests/com/google/android/tv/partner/support/BaseCustomizationTest.java b/partner_support/tests/robotests/javatests/com/google/android/tv/partner/support/BaseCustomizationTest.java index 03d68e4e..e2170589 100644 --- a/partner_support/tests/robotests/javatests/com/google/android/tv/partner/support/BaseCustomizationTest.java +++ b/partner_support/tests/robotests/javatests/com/google/android/tv/partner/support/BaseCustomizationTest.java @@ -17,17 +17,16 @@ package com.google.android.tv.partner.support; import static com.google.common.truth.Truth.assertThat; - import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; - import com.android.tv.testing.TestSingletonApp; import com.android.tv.testing.constants.ConfigConstants; - +import java.util.ArrayList; +import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -35,9 +34,6 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -import java.util.ArrayList; -import java.util.List; - /** Tests for {@link BaseCustomization}. */ // TODO: move to partner-support diff --git a/partner_support/tests/robotests/javatests/com/google/android/tv/partner/support/TunerSetupUtilsTest.java b/partner_support/tests/robotests/javatests/com/google/android/tv/partner/support/TunerSetupUtilsTest.java index 8d089e55..d9b48cfd 100644 --- a/partner_support/tests/robotests/javatests/com/google/android/tv/partner/support/TunerSetupUtilsTest.java +++ b/partner_support/tests/robotests/javatests/com/google/android/tv/partner/support/TunerSetupUtilsTest.java @@ -19,18 +19,16 @@ package com.google.android.tv.partner.support; import static com.google.common.truth.Truth.assertThat; import com.android.tv.testing.constants.ConfigConstants; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - +import com.google.thirdparty.robolectric.GoogleRobolectricTestRunner; import java.util.Arrays; import java.util.Collections; import java.util.List; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; /** Tests for {@link TunerSetupUtils} */ -@RunWith(RobolectricTestRunner.class) +@RunWith(GoogleRobolectricTestRunner.class) @Config(sdk = ConfigConstants.SDK) public class TunerSetupUtilsTest { diff --git a/res/layout/details_overview.xml b/res/layout/details_overview.xml index 541f3fb1..dbcf2055 100644 --- a/res/layout/details_overview.xml +++ b/res/layout/details_overview.xml @@ -55,7 +55,7 @@ android:orientation="vertical" > <!-- layout_marginStart and layout_marginEnd are overridden --> - <androidx.leanback.widget.NonOverlappingFrameLayout + <android.support.v17.leanback.widget.NonOverlappingFrameLayout android:id="@+id/details_overview_description" android:layout_width="match_parent" android:layout_height="0dp" @@ -69,7 +69,7 @@ <!-- horizontalSpacing is defined as @dimen/lb_details_overview_action_items_spacing in newer versions of Leanback Library than LC uses. --> - <androidx.leanback.widget.HorizontalGridView + <android.support.v17.leanback.widget.HorizontalGridView android:id="@+id/details_overview_actions" android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/res/layout/dvr_details_description.xml b/res/layout/dvr_details_description.xml index e37d8b0a..ee749526 100644 --- a/res/layout/dvr_details_description.xml +++ b/res/layout/dvr_details_description.xml @@ -21,7 +21,7 @@ android:layout_height="wrap_content"> <!-- Top margins are set programatically --> - <androidx.leanback.widget.ResizingTextView + <android.support.v17.leanback.widget.ResizingTextView android:id="@+id/dvr_details_description_title" android:layout_width="wrap_content" android:layout_height="wrap_content" diff --git a/res/layout/item_list.xml b/res/layout/item_list.xml index 233aa416..c06b29a0 100644 --- a/res/layout/item_list.xml +++ b/res/layout/item_list.xml @@ -33,7 +33,7 @@ and compensate the same space with padding. The accurate layout height is set in MenuRowView.onBind(). --> - <androidx.leanback.widget.HorizontalGridView + <android.support.v17.leanback.widget.HorizontalGridView android:id="@+id/list_view" style="@style/menu_row_contents_view" android:clipChildren="false" diff --git a/res/layout/option_fragment.xml b/res/layout/option_fragment.xml index 50bf991d..4a4cbbdf 100644 --- a/res/layout/option_fragment.xml +++ b/res/layout/option_fragment.xml @@ -34,7 +34,7 @@ android:textColor="@color/option_item_text_color" android:singleLine="true" /> - <androidx.leanback.widget.VerticalGridView + <android.support.v17.leanback.widget.VerticalGridView android:id="@+id/side_panel_list" android:layout_width="match_parent" android:layout_height="match_parent" diff --git a/res/layout/pin_dialog.xml b/res/layout/pin_dialog.xml index 84807f27..d40d70ec 100644 --- a/res/layout/pin_dialog.xml +++ b/res/layout/pin_dialog.xml @@ -55,8 +55,8 @@ android:fontFamily="@string/font" android:singleLine="false" /> - <com.android.tv.dialog.picker.TvPinPicker - android:id="@+id/tv_pin_picker" + <com.android.tv.dialog.picker.PinPicker + android:id="@+id/pin_picker" android:importantForAccessibility="yes" android:layout_width="match_parent" android:layout_height="154dp" diff --git a/res/layout/priority_settings_action_item.xml b/res/layout/priority_settings_action_item.xml index fc882d97..0f517319 100644 --- a/res/layout/priority_settings_action_item.xml +++ b/res/layout/priority_settings_action_item.xml @@ -15,13 +15,13 @@ limitations under the License. --> -<androidx.leanback.widget.GuidedActionItemContainer +<android.support.v17.leanback.widget.GuidedActionItemContainer xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" style="?attr/guidedActionItemContainerStyle" android:foreground="@null" android:outlineProvider="background"> - <androidx.leanback.widget.CheckableImageView + <android.support.v17.leanback.widget.CheckableImageView android:id="@+id/guidedactions_item_checkmark" style="?attr/guidedActionItemCheckmarkStyle" tools:ignore="ContentDescription" /> @@ -30,16 +30,16 @@ style="?attr/guidedActionItemIconStyle" tools:ignore="ContentDescription" /> - <androidx.leanback.widget.NonOverlappingLinearLayout + <android.support.v17.leanback.widget.NonOverlappingLinearLayout android:id="@+id/guidedactions_item_content" style="?attr/guidedActionItemContentStyle" > - <androidx.leanback.widget.GuidedActionEditText + <android.support.v17.leanback.widget.GuidedActionEditText android:id="@+id/guidedactions_item_title" style="?attr/guidedActionItemTitleStyle" /> - <androidx.leanback.widget.GuidedActionEditText + <android.support.v17.leanback.widget.GuidedActionEditText android:id="@+id/guidedactions_item_description" style="?attr/guidedActionItemDescriptionStyle" /> - </androidx.leanback.widget.NonOverlappingLinearLayout> + </android.support.v17.leanback.widget.NonOverlappingLinearLayout> <ImageView android:id="@+id/guidedactions_item_chevron" @@ -53,4 +53,4 @@ android:adjustViewBounds="true" android:src="@drawable/ic_draggable_white" tools:ignore="ContentDescription" /> -</androidx.leanback.widget.GuidedActionItemContainer>
\ No newline at end of file +</android.support.v17.leanback.widget.GuidedActionItemContainer>
\ No newline at end of file diff --git a/res/layout/program_guide_side_panel.xml b/res/layout/program_guide_side_panel.xml index 9c04feb2..466b7fa8 100644 --- a/res/layout/program_guide_side_panel.xml +++ b/res/layout/program_guide_side_panel.xml @@ -32,7 +32,7 @@ android:elevation="@dimen/program_guide_side_panel_elevation" android:background="@color/program_guide_side_panel_background"> - <androidx.leanback.widget.SearchOrbView + <android.support.v17.leanback.widget.SearchOrbView android:id="@+id/program_guide_side_panel_search_orb" android:layout_width="wrap_content" android:layout_height="wrap_content" @@ -41,7 +41,7 @@ android:nextFocusDown="@+id/program_guide_side_panel_grid_view" android:visibility="gone" /> - <androidx.leanback.widget.VerticalGridView + <android.support.v17.leanback.widget.VerticalGridView android:id="@id/program_guide_side_panel_grid_view" android:layout_width="@dimen/program_guide_side_panel_item_width" android:layout_height="match_parent" diff --git a/res/values/arrays-custom.xml b/res/values/arrays-custom.xml deleted file mode 100644 index 252d6f4f..00000000 --- a/res/values/arrays-custom.xml +++ /dev/null @@ -1,45 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2019 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. - --> - -<!-- These are resources that are expected to be different for OEM apps --> - -<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - - <!-- Keep the title and description arrays in sync --> - - <!-- Titles in the onboarding page. [CHAR LIMIT=100]--> - <string-array name="welcome_page_titles"> - <item><xliff:g id="app_name">Live TV</xliff:g> </item> - <item>A simple way to discover content</item> - <item>Download apps, get more channels</item> - <item>Customize your channel line-up</item> - </string-array> - - - <!-- Descriptions in the onboarding page. [CHAR LIMIT=NONE] --> - <string-array name="welcome_page_descriptions"> - <item>Watch content from your apps like watching channels on TV.</item> - <item>Browse content from your apps with a familiar guide and friendly interface, -\njust like channels on TV.</item> - <item>Add more channels by installing apps that offer live channels. -\nFind compatible apps in Google Play Store by using the link within the TV menu.</item> - <!-- Refer to @string/settings_channel_source_item_setup for "Channel sources" menu - and @string/options_item_settings for "Settings" menu. --> - <item>Set up your newly installed channel sources to customize your channel list. -\nChoose the Channel sources within the Settings menu to get started.</item> - </string-array> -</resources> diff --git a/res/values/arrays.xml b/res/values/arrays.xml index 9ef028ae..0604dd2b 100644 --- a/res/values/arrays.xml +++ b/res/values/arrays.xml @@ -150,4 +150,24 @@ <item>Tech/Science</item> </string-array> + <!-- Titles in the onboarding page. --> + <string-array name="welcome_page_titles"> + <item><xliff:g id="app_name">Live TV</xliff:g> </item> + <item>A simple way to discover content</item> + <item>Download apps, get more channels</item> + <item>Customize your channel line-up</item> + </string-array> + + <!-- Descriptions in the onboarding page. --> + <string-array name="welcome_page_descriptions"> + <item>Watch content from your apps like watching channels on TV.</item> + <item>Browse content from your apps with a familiar guide and friendly interface, +\njust like channels on TV.</item> + <item>Add more channels by installing apps that offer live channels. +\nFind compatible apps in the online store by using the link within the TV menu.</item> + <!-- Refer to @string/settings_channel_source_item_setup for "Channel sources" menu + and @string/options_item_settings for "Settings" menu. --> + <item>Set up your newly installed channel sources to customize your channel list. +\nChoose the Channel sources within the Settings menu to get started.</item> + </string-array> </resources> diff --git a/res/values/rating_system_strings.xml b/res/values/rating_system_strings.xml index 9922cb1c..45c48d87 100644 --- a/res/values/rating_system_strings.xml +++ b/res/values/rating_system_strings.xml @@ -16,10 +16,9 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- Age based TV content rating strings used in DVB, ISDB and DTMB. - For more info, please see STD-B10 in http://www.dibeg.org/techp/aribstd/aribstd.html (ISDB), - Table 81 of DVB SI (EN 300 468 V1.14.1) in https://www.dvb.org/standards (DVB) - and http://www.gb688.cn/bzgk/gb/newGbInfo?hcno=59E83CA701AEB4248E115BC043688FEC (DTMB).--> + <!-- Age based TV content rating strings used in DVB and ISDB. + For more info, please see STD-B10 in http://www.dibeg.org/techp/aribstd/aribstd.html (ISDB) + and Table 81 of DVB SI (EN 300 468 V1.14.1) in https://www.dvb.org/standards (DVB).--> <string name="description_age_4">Recommended for ages 4 and over.</string> <string name="description_age_5">Recommended for ages 5 and over.</string> <string name="description_age_6">Recommended for ages 6 and over.</string> @@ -110,7 +109,6 @@ <!-- A TV content rating of DVB for adult [CHAR LIMIT=NONE] --> <string name="description_es_dvb_x">Recommended for adults.</string> - <!-- TV content rating system strings for KR TV. These strings are from http://www.law.go.kr/admRulLsInfoP.do?admRulSeq=2000000118507 but they are translated from Korean to English. --> @@ -161,19 +159,4 @@ <string name="description_us_mv_pg13">Parents strongly cautioned. Some material may be inappropriate for pre-teenagers.</string> <string name="description_us_mv_r">Restricted, Contains some adult material. Parents are urged to learn more about the film before taking their young children with them.</string> <string name="description_us_mv_nc17">No one 17 and under admitted. Clearly adult. Children are not admitted.</string> - - <!-- TV content rating system strings for NZ TV. These strings are from - https://bsa.govt.nz/images/03_BSA_FREE-TO-AIR-TV_CLASSIFICATIONS_DRAFT.pdf --> - <string name="description_nz_fta_tv_g" translatable="false">Programmes which exclude material likely to be unsuitable for children. Programmes may not necessarily be designed for child viewers but should not contain material likely to alarm or distress them.</string> - <string name="description_nz_fta_tv_pgr" translatable="false">Programmes containing material more suited for mature audiences but not necessarily unsuitable for child viewers when subject to the guidance of a parent or an adult.</string> - <string name="description_nz_fta_tv_ao" translatable="false">Programmes containing adult themes and directed primarily at mature audiences.</string> - - <!-- TV content rating system strings for TH TV. These strings are from - https://broadcast.nbtc.go.th/home/ --> - <string name="description_th_tv_4" translatable="false">Suitable for audiences 3 to 5 years of age.</string> - <string name="description_th_tv_6" translatable="false">Suitable for audiences 6 to 12 years of age.</string> - <string name="description_th_tv_10" translatable="false">Suitable for all audiences.</string> - <string name="description_th_tv_13" translatable="false">Parental guidance suggested for viewers age below 13.</string> - <string name="description_th_tv_18" translatable="false">Parental guidance suggested for viewers age below 18.</string> - <string name="description_th_tv_19" translatable="false">Not suitable for children and teenagers.</string> </resources> diff --git a/res/values/strings-custom.xml b/res/values/strings-custom.xml index 5ecb8592..22f73318 100644 --- a/res/values/strings-custom.xml +++ b/res/values/strings-custom.xml @@ -14,18 +14,9 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> - - -<!-- These are resources that are expected to be different for OEM apps --> - -<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +<resources> <!-- Name of application [CHAR LIMIT=NONE] --> <string name="app_name" translatable="false">Live TV</string> - <!-- Description for channel sources screen in onboarding. [CHAR LIMIT=NONE] --> - <string name="setup_sources_description2" - meaning="Live TV version of setup_sources_description2" - ><xliff:g id="app_name">Live TV</xliff:g> combines the experience of traditional TV channels with streaming channels provided by apps. -\n\nGet started by setting up the channel sources already installed. Or browse Google Play Store for more apps that offer live channels.</string> -</resources> +</resources>
\ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index 06694a9d..36824759 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -28,16 +28,16 @@ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> - <string name="permlab_receiveInputEvent" translatable="false">receive input events from <xliff:g id="app_name">Live TV</xliff:g> app</string> + <string name="permlab_receiveInputEvent" translatable="false">receive input events from <xliff:g id="app_name">Live TV</xliff:g> app</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> - <string name="permdesc_receiveInputEvent" translatable="false">Allows the app to receive input events from <xliff:g id="app_name">Live TV</xliff:g> app</string> + <string name="permdesc_receiveInputEvent" translatable="false">Allows the app to receive input events from <xliff:g id="app_name">Live TV</xliff:g> app</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> - <string name="permlab_customizeTvApp" translatable="false">customize <xliff:g id="app_name">Live TV</xliff:g> app</string> + <string name="permlab_customizeTvApp" translatable="false">customize <xliff:g id="app_name">Live TV</xliff:g> app</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> - <string name="permdesc_customizeTvApp" translatable="false">Allows the app to customize <xliff:g id="app_name">Live TV</xliff:g> app</string> + <string name="permdesc_customizeTvApp" translatable="false">Allows the app to customize <xliff:g id="app_name">Live TV</xliff:g> app</string> <!-- Program information, mainly used for channel banner and program guide. --> <eat-comment /> @@ -388,13 +388,13 @@ <!-- Description on the locked screen with the rating when the rating of the current content is restricted by parental control. [CHAR LIMIT=NONE] --> <string name="tvview_content_locked_format">This program is rated <xliff:g id="rating" example="TV_MA">%1$s</xliff:g>.\nTo watch this program, press Right and enter your PIN.</string> <!-- Description on the locked screen when current channel is locked by parental control. [CHAR LIMIT=NONE] --> - <string name="tvview_channel_locked_no_permission">To watch this channel, use the default TV app.</string> + <string name="tvview_channel_locked_no_permission">To watch this channel, use the default Live TV app.</string> <!-- Description on the locked screen when the rating of the current content is restricted by parental control. [CHAR LIMIT=NONE] --> - <string name="tvview_content_locked_no_permission">To watch this program, use the default TV app.</string> + <string name="tvview_content_locked_no_permission">To watch this program, use the default Live TV app.</string> <!-- Description on the locked screen when the current content is restricted by parental control. [CHAR LIMIT=NONE] --> - <string name="tvview_content_locked_unrated_no_permission">This program is unrated.\nTo watch this program, use the default TV app.</string> + <string name="tvview_content_locked_unrated_no_permission">This program is unrated.\nTo watch this program, use the default Live TV app.</string> <!-- Description on the locked screen with the rating when the rating of the current content is restricted by parental control. [CHAR LIMIT=NONE] --> - <string name="tvview_content_locked_format_no_permission">This program is rated <xliff:g id="rating" example="TV_MA">%1$s</xliff:g>.\nTo watch this program, use the default TV app.</string> + <string name="tvview_content_locked_format_no_permission">This program is rated <xliff:g id="rating" example="TV_MA">%1$s</xliff:g>.\nTo watch this program, use the default Live TV app.</string> <!-- Description on the locked screen when the rating of the current content is restricted by parental control. [CHAR LIMIT=NONE] --> <string name="shrunken_tvview_content_locked">Program is blocked</string> @@ -479,7 +479,7 @@ the source video through to the display and don't provide ability to tune to a specific channel unless the user directly controls the external source device (e.g. game console, DVD player, settop box, etc) that is connected to the TV. [CHAR LIMIT=NONE] --> - <string name="msg_not_passthrough_input">Tuner type not suitable. Please launch <xliff:g id="app_name">Live TV</xliff:g> app for tuner type TV input.</string> + <string name="msg_not_passthrough_input">Tuner type not suitable. Please launch <xliff:g id="app_name">Live TV</xliff:g> app for tuner type TV input.</string> <!-- Error message when tune is failed. [CHAR LIMIT=NONE] --> <string name="msg_tune_failed">Tune failed</string> <!-- Error message when the user attempts an action (select TIS setup-activity, app-link, @@ -496,7 +496,7 @@ (commands for external device) [CHAR LIMIT=NONE] --> <string name="msg_back_key_guide">BACK key is for connected device. Press HOME button to exit.</string> <!-- Error message when a user denied to grant READ_TV_LISTING permission. [CHAR LIMIT=NONE] --> - <string name="msg_read_tv_listing_permission_denied"><xliff:g id="app_name">Live TV</xliff:g> needs permission to read the TV listings.</string> + <string name="msg_read_tv_listing_permission_denied"><xliff:g id="app_name">Live TV</xliff:g> needs permission to read the TV listings.</string> <!-- Strings for debug or not to be shown to users --> <eat-comment /> @@ -518,17 +518,17 @@ <!-- Title of Recently watched dialog. It is used for debug purpose. --> <string name="recently_watched" translatable="false">Recently watched</string> - <!-- Title of DVR history dialog. [CHAR LIMIT=50] --> + <!-- Title of DVR history dialog. --> <string name="dvr_history_dialog_title" translatable="false">DVR history</string> - <!-- Display name of DVR recording service's notification channel. [CHAR LIMIT=50] --> - <string name="dvr_notification_channel_name" ><xliff:g id="app_name">Live TV</xliff:g> DVR</string> - <!-- Content title of DVR recording service's notification. [CHAR LIMIT=50] --> - <string name="dvr_notification_content_title" ><xliff:g id="app_name">Live TV</xliff:g> DVR</string> - <!-- Content text of DVR recording service's notification during recording. [CHAR LIMIT=NONE] --> - <string name="dvr_notification_content_text_recording" ><xliff:g id="app_name">Live TV</xliff:g> are recording.</string> - <!-- Content text of DVR recording service's notification during updating schedules. [CHAR LIMIT=NONE] --> - <string name="dvr_notification_content_text_loading" ><xliff:g id="app_name">Live TV</xliff:g> are updating recording schedules.</string> + <!-- Display name of DVR recording service's notification channel. --> + <string name="dvr_notification_channel_name" translatable="false"><xliff:g id="app_name">Live TV</xliff:g> DVR</string> + <!-- Content title of DVR recording service's notification. --> + <string name="dvr_notification_content_title" translatable="false"><xliff:g id="app_name">Live TV</xliff:g> DVR</string> + <!-- Content text of DVR recording service's notification during recording. --> + <string name="dvr_notification_content_text_recording" translatable="false"><xliff:g id="app_name">Live TV</xliff:g> are recording.</string> + <!-- Content text of DVR recording service's notification during updating schedules. --> + <string name="dvr_notification_content_text_loading" translatable="false"><xliff:g id="app_name">Live TV</xliff:g> are updating recording schedules.</string> <!-- Default content title of tuner installing notifications. --> <string name="tuner_install_notification_content_title" translatable="false">Install <xliff:g id="tuner_package" example="Tuner package">%s</xliff:g></string> @@ -546,6 +546,9 @@ <eat-comment /> <!-- Text for the channel sources screen in onboarding. --> <string name="setup_sources_text">Set up your sources</string> + <!-- Description for channel sources screen in onboarding. --> + <string name="setup_sources_description">Live channels combines the experience of traditional TV channels with streaming channels provided by apps. +\n\nGet started by setting up the channel sources already installed. Or browse the online store for more apps that offer live channels.</string> <!-- Menu item label to start DVR manager UI. --> <string name="channels_item_dvr">Recordings & schedules</string> @@ -690,8 +693,8 @@ <item quantity="one">%1$d of %2$d episode is deleted</item> <item quantity="other">%1$d of %2$d episodes are deleted</item> </plurals> - <!-- Title of screen with settings for the recording of a TV Program or Series. [CHAR LIMIT=50] --> - <string name="dvr_series_settings_title">Recording settings</string> + <!-- Title of DVR series settings --> + <string name="dvr_series_settings_title" translatable="false">Recording settings</string> <!-- Item label to change priority of TV series for DVR --> <string name="dvr_series_settings_priority">Priority</string> <!-- Item description when the current series has the height proirty among scheduled @@ -719,13 +722,10 @@ <!-- DVR epg strings --> <eat-comment /> - <!-- Button text that deletes scheduled future recordings of a TV Program or Series. [CHAR LIMIT=50] --> - <string name="dvr_action_delete_schedule">Delete schedule</string> - <!-- Button text that records the selected program. [CHAR LIMIT=50] --> - <string name="dvr_action_record_program">Record program</string> - <!-- Button text that invokes android internal storage settings activity. - [CHAR LIMIT=50] --> - <string name="dvr_action_error_storage_settings">Open storage settings</string> + <string name="dvr_action_delete_schedule" translatable="false">Delete schedule</string> + <string name="dvr_action_record_program" translatable="false">Record program</string> + <!-- The action to forget DVR storage which is missing currently. invoke android internal storage settings activity. --> + <string name="dvr_action_error_storage_settings" translatable="false">Open storage settings</string> <!-- The action to stop recording. [CHAR LIMIT=10] --> <string name="dvr_action_stop">Stop</string> <!-- The action to open the activity which shows all the schedules.[CHAR LIMIT=32] --> @@ -767,10 +767,8 @@ <!-- Dvr label in epg to indicate the recording of the program has been failed. [CHAR LIMIT=30] --> <string name="dvr_epg_program_recording_failed">Recording failed</string> <string name="dvr_epg_program_icon_text" translatable="false">DVR</string> - <!-- Title of a dialog box displayed when a previously scheduled recording requires an action.[CHAR LIMIT=50] --> - <string name="dvr_epg_channel_watch_conflict_dialog_title">Upcoming schedules</string> - <!-- Description in a dialog box displayed when a previously scheduled recording requires an action. [CHAR LIMIT=NONE] --> - <string name="dvr_epg_channel_watch_conflict_dialog_description">The program will not be recorded if you keep watching this channel. Cancel the recording, or the current channel will be blocked when the recording starts.</string> + <string name="dvr_epg_channel_watch_conflict_dialog_title" translatable="false">Upcoming schedules</string> + <string name="dvr_epg_channel_watch_conflict_dialog_description" translatable="false">The programs will not be recorded if you keep watching this channel. Cancel the recordings, or current channel will be blocked when the recording starts.</string> <!-- A popup message which informs that Live TV is reading program information. --> <string name="dvr_series_progress_message_reading_programs">Reading programs</string> <!-- Dialog action which let user view the recent recordings. --> @@ -800,10 +798,10 @@ <string name="dvr_error_no_free_space_description">This program will not be recorded because there is not enough storage. Try deleting some existing recordings.</string> <!-- Dialog title which will be shown when the current DVR storage is not accessible. --> <string name="dvr_error_missing_storage_title">Missing storage</string> - <!-- Dialog description which will be shown when the current DVR storage is not accessible. [CHAR LIMIT=NONE] --> - <string name="dvr_error_missing_storage_description">Some of the storage used for recording is missing. Please connect the external drive you used before to re-enable recording. Alternately, you can forget the storage in the storage settings, if it\'s no longer available.</string> - <!-- A toast message displad to the user when the recording being requested to play is not found in storage. [CHAR LIMIT=NONE] --> - <string name="dvr_toast_recording_deleted">Recording not found.</string> + <!-- Dialog description which will be shown when the current DVR storage is not accessible. --> + <string name="dvr_error_missing_storage_description" translatable="false">Some of the storage used for recording is missing. Please connect the external drive you used before to re-enable recording. Alternately, you can forget the storage in the storage settings, if it\'s no longer available.</string> + <!-- The recording being requested to play is not existent in storage. It may be deleted. --> + <string name="dvr_toast_recording_deleted" translatable="false">The recording seems to be deleted.</string> <!-- DVR half sized dialogs --> <eat-comment /> @@ -910,8 +908,7 @@ <!-- DVR channel banner strings --> <eat-comment /> - <!-- Text desplayed on screen to show that the current program is being recorded until the time listed. [CHAR LIMIT=30] --> - <string name="dvr_recording_till_format">Recording till <xliff:g id="recordingEndTime" example="9:00pm">%1$s</xliff:g></string> + <string name="dvr_recording_till_format" translatable="false">Recording till <xliff:g id="recordingEndTime" example="9:00pm">%1$s</xliff:g></string> <!-- DVR schedule list strings --> <eat-comment/> diff --git a/res/xml/tv_content_rating_systems.xml b/res/xml/tv_content_rating_systems.xml index 361393f5..aad9d610 100644 --- a/res/xml/tv_content_rating_systems.xml +++ b/res/xml/tv_content_rating_systems.xml @@ -286,170 +286,6 @@ </rating-order> </rating-system-definition> - <!-- TV content rating system for DTMB. See http://www.gb688.cn/bzgk/gb/newGbInfo?hcno=59E83CA701AEB4248E115BC043688FEC --> - <rating-system-definition android:name="DTMB" - android:country="CN"> - <rating-definition android:name="DTMB_4" - android:title="4" - android:description="@string/description_age_4" - android:contentAgeHint="4" /> - <rating-definition android:name="DTMB_5" - android:title="5" - android:description="@string/description_age_5" - android:contentAgeHint="5" /> - <rating-definition android:name="DTMB_6" - android:title="6" - android:description="@string/description_age_6" - android:contentAgeHint="6" /> - <rating-definition android:name="DTMB_7" - android:title="7" - android:description="@string/description_age_7" - android:contentAgeHint="7" /> - <rating-definition android:name="DTMB_8" - android:title="8" - android:description="@string/description_age_8" - android:contentAgeHint="8" /> - <rating-definition android:name="DTMB_9" - android:title="9" - android:description="@string/description_age_9" - android:contentAgeHint="9" /> - <rating-definition android:name="DTMB_10" - android:title="10" - android:description="@string/description_age_10" - android:contentAgeHint="10" /> - <rating-definition android:name="DTMB_11" - android:title="11" - android:description="@string/description_age_11" - android:contentAgeHint="11" /> - <rating-definition android:name="DTMB_12" - android:title="12" - android:description="@string/description_age_12" - android:contentAgeHint="12" /> - <rating-definition android:name="DTMB_13" - android:title="13" - android:description="@string/description_age_13" - android:contentAgeHint="13" /> - <rating-definition android:name="DTMB_14" - android:title="14" - android:description="@string/description_age_14" - android:contentAgeHint="14" /> - <rating-definition android:name="DTMB_15" - android:title="15" - android:description="@string/description_age_15" - android:contentAgeHint="15" /> - <rating-definition android:name="DTMB_16" - android:title="16" - android:description="@string/description_age_16" - android:contentAgeHint="16" /> - <rating-definition android:name="DTMB_17" - android:title="17" - android:description="@string/description_age_17" - android:contentAgeHint="17" /> - <rating-definition android:name="DTMB_18" - android:title="18" - android:description="@string/description_age_18" - android:contentAgeHint="18" /> - <rating-order> - <rating android:name="DTMB_4" /> - <rating android:name="DTMB_5" /> - <rating android:name="DTMB_6" /> - <rating android:name="DTMB_7" /> - <rating android:name="DTMB_8" /> - <rating android:name="DTMB_9" /> - <rating android:name="DTMB_10" /> - <rating android:name="DTMB_11" /> - <rating android:name="DTMB_12" /> - <rating android:name="DTMB_13" /> - <rating android:name="DTMB_14" /> - <rating android:name="DTMB_15" /> - <rating android:name="DTMB_16" /> - <rating android:name="DTMB_17" /> - <rating android:name="DTMB_18" /> - </rating-order> - </rating-system-definition> - - <!-- TV content rating system for DTMB. See http://www.gb688.cn/bzgk/gb/newGbInfo?hcno=59E83CA701AEB4248E115BC043688FEC --> - <rating-system-definition android:name="DTMB" - android:country="CN"> - <rating-definition android:name="DTMB_4" - android:title="4" - android:description="@string/description_age_4" - android:contentAgeHint="4" /> - <rating-definition android:name="DTMB_5" - android:title="5" - android:description="@string/description_age_5" - android:contentAgeHint="5" /> - <rating-definition android:name="DTMB_6" - android:title="6" - android:description="@string/description_age_6" - android:contentAgeHint="6" /> - <rating-definition android:name="DTMB_7" - android:title="7" - android:description="@string/description_age_7" - android:contentAgeHint="7" /> - <rating-definition android:name="DTMB_8" - android:title="8" - android:description="@string/description_age_8" - android:contentAgeHint="8" /> - <rating-definition android:name="DTMB_9" - android:title="9" - android:description="@string/description_age_9" - android:contentAgeHint="9" /> - <rating-definition android:name="DTMB_10" - android:title="10" - android:description="@string/description_age_10" - android:contentAgeHint="10" /> - <rating-definition android:name="DTMB_11" - android:title="11" - android:description="@string/description_age_11" - android:contentAgeHint="11" /> - <rating-definition android:name="DTMB_12" - android:title="12" - android:description="@string/description_age_12" - android:contentAgeHint="12" /> - <rating-definition android:name="DTMB_13" - android:title="13" - android:description="@string/description_age_13" - android:contentAgeHint="13" /> - <rating-definition android:name="DTMB_14" - android:title="14" - android:description="@string/description_age_14" - android:contentAgeHint="14" /> - <rating-definition android:name="DTMB_15" - android:title="15" - android:description="@string/description_age_15" - android:contentAgeHint="15" /> - <rating-definition android:name="DTMB_16" - android:title="16" - android:description="@string/description_age_16" - android:contentAgeHint="16" /> - <rating-definition android:name="DTMB_17" - android:title="17" - android:description="@string/description_age_17" - android:contentAgeHint="17" /> - <rating-definition android:name="DTMB_18" - android:title="18" - android:description="@string/description_age_18" - android:contentAgeHint="18" /> - <rating-order> - <rating android:name="DTMB_4" /> - <rating android:name="DTMB_5" /> - <rating android:name="DTMB_6" /> - <rating android:name="DTMB_7" /> - <rating android:name="DTMB_8" /> - <rating android:name="DTMB_9" /> - <rating android:name="DTMB_10" /> - <rating android:name="DTMB_11" /> - <rating android:name="DTMB_12" /> - <rating android:name="DTMB_13" /> - <rating android:name="DTMB_14" /> - <rating android:name="DTMB_15" /> - <rating android:name="DTMB_16" /> - <rating android:name="DTMB_17" /> - <rating android:name="DTMB_18" /> - </rating-order> - </rating-system-definition> - <!-- TV content rating system for DVB. See Table 81 of DVB SI (EN 300 468 V1.14.1) in https://www.dvb.org/standards --> <rating-system-definition android:name="DVB" android:country="AM, BG, CH, DE, DK, FI, GR, HU, ID, IE, IL, IS, MY, NL, NZ, PL, PT, RO, RU, RS, SI, TH, TR, TW, UA"> @@ -840,28 +676,6 @@ </rating-order> </rating-system-definition> - <!-- TV content rating system for NZ. See http://www.freeviewnz.tv/ --> - <rating-system-definition android:name="NZ_TV" - android:country="NZ"> - <rating-definition android:name="NZ_TV_G" - android:title="G" - android:description="@string/description_nz_fta_tv_g" - android:contentAgeHint="0" /> - <rating-definition android:name="NZ_TV_PGR" - android:title="PGR" - android:description="@string/description_nz_fta_tv_pgr" - android:contentAgeHint="0" /> - <rating-definition android:name="NZ_TV_AO" - android:title="AO" - android:description="@string/description_nz_fta_tv_ao" - android:contentAgeHint="0" /> - <rating-order> - <rating android:name="NZ_TV_G" /> - <rating android:name="NZ_TV_PGR" /> - <rating android:name="NZ_TV_AO" /> - </rating-order> - </rating-system-definition> - <!-- TV content rating system for SG. See http://www.mda.gov.sg/RegulationsAndLicensing/ContentStandardsAndClassification/FilmsAndVideos/Pages/default.aspx --> <rating-system-definition android:name="SG_TV" android:country="SG"> @@ -899,43 +713,6 @@ </rating-order> </rating-system-definition> - <!-- TV content rating system for TH. See https://broadcast.nbtc.go.th/home/ --> - <rating-system-definition android:name="TH_TV" - android:country="TH"> - <rating-definition android:name="TH_TV_4" - android:title="4" - android:description="@string/description_th_tv_4" - android:contentAgeHint="4" /> - <rating-definition android:name="TH_TV_6" - android:title="6" - android:description="@string/description_th_tv_6" - android:contentAgeHint="6" /> - <rating-definition android:name="TH_TV_10" - android:title="10" - android:description="@string/description_th_tv_10" - android:contentAgeHint="10" /> - <rating-definition android:name="TH_TV_13" - android:title="13" - android:description="@string/description_th_tv_13" - android:contentAgeHint="13" /> - <rating-definition android:name="TH_TV_18" - android:title="18" - android:description="@string/description_th_tv_18" - android:contentAgeHint="18" /> - <rating-definition android:name="TH_TV_19" - android:title="19" - android:description="@string/description_th_tv_19" - android:contentAgeHint="19" /> - <rating-order> - <rating android:name="TH_TV_4" /> - <rating android:name="TH_TV_6" /> - <rating android:name="TH_TV_10" /> - <rating android:name="TH_TV_13" /> - <rating android:name="TH_TV_18" /> - <rating android:name="TH_TV_19" /> - </rating-order> - </rating-system-definition> - <!-- TV content rating system for US. See http://www.tvguidelines.org/ratings.htm --> <rating-system-definition android:name="US_TV" android:country="US"> diff --git a/settings.gradle b/settings.gradle index 5916cb4a..6d5cb547 100644 --- a/settings.gradle +++ b/settings.gradle @@ -23,5 +23,3 @@ include ':common' include ':tuner' include ':SampleDvbTuner' project(":SampleDvbTuner").projectDir = file("tuner/SampleDvbTuner") -include ':SampleNetworkTuner' -project(":SampleNetworkTuner").projectDir = file("tuner/SampleNetworkTuner") diff --git a/src/com/android/tv/LauncherActivity.java b/src/com/android/tv/LauncherActivity.java index ccc5600a..679d612d 100644 --- a/src/com/android/tv/LauncherActivity.java +++ b/src/com/android/tv/LauncherActivity.java @@ -27,10 +27,10 @@ import android.util.Log; * An activity to launch a new activity. * * <p>In the case when {@link MainActivity} starts a new activity using {@link - * Activity#startActivity} or {@link Activity#startActivityForResult}, TV app is terminated if the - * new activity crashes. That's because the {@link android.app.ActivityManager} terminates the - * activity which is just below the crashed activity in the activity stack. To avoid this, we need - * to locate an additional activity between these activities in the activity stack. + * Activity#startActivity} or {@link Activity#startActivityForResult}, Live TV app is + * terminated if the new activity crashes. That's because the {@link android.app.ActivityManager} + * terminates the activity which is just below the crashed activity in the activity stack. To avoid + * this, we need to locate an additional activity between these activities in the activity stack. */ public class LauncherActivity extends Activity { private static final String TAG = "LauncherActivity"; diff --git a/src/com/android/tv/MainActivity.java b/src/com/android/tv/MainActivity.java index 7a591500..b4cf71db 100644 --- a/src/com/android/tv/MainActivity.java +++ b/src/com/android/tv/MainActivity.java @@ -16,8 +16,6 @@ package com.android.tv; -import static com.android.tv.common.feature.SystemAppFeature.SYSTEM_APP_FEATURE; - import android.app.Activity; import android.app.PendingIntent; import android.app.SearchManager; @@ -46,7 +44,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.PowerManager; -import android.provider.BaseColumns; import android.provider.Settings; import android.support.annotation.IntDef; import android.support.annotation.NonNull; @@ -68,7 +65,6 @@ import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.widget.FrameLayout; import android.widget.Toast; - import com.android.tv.MainActivity.MySingletons; import com.android.tv.analytics.SendChannelStatusRunnable; import com.android.tv.analytics.SendConfigInfoRunnable; @@ -82,7 +78,6 @@ import com.android.tv.common.SoftPreconditions; import com.android.tv.common.TvContentRatingCache; import com.android.tv.common.WeakHandler; import com.android.tv.common.compat.TvInputInfoCompat; -import com.android.tv.common.dev.DeveloperPreferences; import com.android.tv.common.feature.CommonFeatures; import com.android.tv.common.memory.MemoryManageable; import com.android.tv.common.singletons.HasSingletons; @@ -96,13 +91,11 @@ import com.android.tv.common.util.SystemProperties; import com.android.tv.data.ChannelDataManager; import com.android.tv.data.ChannelImpl; import com.android.tv.data.OnCurrentProgramUpdatedListener; +import com.android.tv.data.Program; import com.android.tv.data.ProgramDataManager; -import com.android.tv.data.ProgramImpl; import com.android.tv.data.StreamInfo; import com.android.tv.data.WatchedHistoryManager; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; -import com.android.tv.data.epg.EpgFetcher; import com.android.tv.dialog.HalfSizedDialogFragment; import com.android.tv.dialog.PinDialogFragment; import com.android.tv.dialog.PinDialogFragment.OnPinCheckedListener; @@ -113,12 +106,11 @@ import com.android.tv.dvr.recorder.ConflictChecker; import com.android.tv.dvr.ui.DvrStopRecordingFragment; import com.android.tv.dvr.ui.DvrUiHelper; import com.android.tv.features.TvFeatures; -import com.android.tv.guide.ProgramItemView; import com.android.tv.menu.Menu; import com.android.tv.onboarding.OnboardingActivity; import com.android.tv.parental.ContentRatingsManager; import com.android.tv.parental.ParentalControlSettings; -import com.android.tv.perf.StartupMeasureFactory; +import com.android.tv.perf.PerformanceMonitorManagerFactory; import com.android.tv.receiver.AudioCapabilitiesReceiver; import com.android.tv.recommendation.ChannelPreviewUpdater; import com.android.tv.recommendation.NotificationService; @@ -134,7 +126,6 @@ import com.android.tv.ui.TunableTvView; import com.android.tv.ui.TunableTvView.BlockScreenType; import com.android.tv.ui.TunableTvView.OnTuneListener; import com.android.tv.ui.TvOverlayManager; -import com.android.tv.ui.TvOverlayManagerFactory; import com.android.tv.ui.TvViewUiManager; import com.android.tv.ui.sidepanel.ClosedCaptionFragment; import com.android.tv.ui.sidepanel.CustomizeChannelListFragment; @@ -144,7 +135,6 @@ import com.android.tv.ui.sidepanel.MultiAudioFragment; import com.android.tv.ui.sidepanel.SettingsFragment; import com.android.tv.ui.sidepanel.SideFragment; import com.android.tv.ui.sidepanel.parentalcontrols.ParentalControlsFragment; -import com.android.tv.ui.sidepanel.parentalcontrols.RatingsFragment; import com.android.tv.util.AsyncDbTask; import com.android.tv.util.AsyncDbTask.DbExecutor; import com.android.tv.util.CaptionSettings; @@ -160,17 +150,9 @@ import com.android.tv.util.account.AccountHelper; import com.android.tv.util.images.ImageCache; import com.google.common.base.Optional; - import dagger.android.AndroidInjection; -import dagger.android.AndroidInjector; import dagger.android.ContributesAndroidInjector; -import dagger.android.DispatchingAndroidInjector; -import dagger.android.HasAndroidInjector; - import com.android.tv.common.flags.BackendKnobsFlags; -import com.android.tv.common.flags.LegacyFlags; -import com.android.tv.common.flags.StartupFlags; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayDeque; @@ -181,17 +163,15 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; - import javax.inject.Inject; import javax.inject.Provider; -/** The main activity for the TV app. */ +/** The main activity for the Live TV app. */ public class MainActivity extends Activity implements OnActionClickListener, OnPinCheckedListener, ChannelChanger, - HasSingletons<MySingletons>, - HasAndroidInjector { + HasSingletons<MySingletons> { private static final String TAG = "MainActivity"; private static final boolean DEBUG = false; private AudioCapabilitiesReceiver mAudioCapabilitiesReceiver; @@ -278,11 +258,10 @@ public class MainActivity extends Activity private static final long START_UP_TIMER_RESET_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(3); { - StartupMeasureFactory.create().onActivityInit(); + PerformanceMonitorManagerFactory.create().getStartupMeasure().onActivityInit(); } private final MySingletonsImpl mMySingletons = new MySingletonsImpl(); - @Inject DispatchingAndroidInjector<Object> mAndroidInjector; @Inject @DbExecutor Executor mDbExecutor; private AccessibilityManager mAccessibilityManager; @@ -299,12 +278,8 @@ public class MainActivity extends Activity private DvrManager mDvrManager; private ConflictChecker mDvrConflictChecker; @Inject BackendKnobsFlags mBackendKnobs; - @Inject LegacyFlags mLegacyFlags; - @Inject StartupFlags mStartupFlags; @Inject SetupUtils mSetupUtils; @Inject Optional<BuiltInTunerManager> mOptionalBuiltInTunerManager; - @Inject AccountHelper mAccountHelper; - @Inject EpgFetcher mEpgFetcher; @VisibleForTesting protected TunableTvView mTvView; private View mContentView; @@ -339,7 +314,6 @@ public class MainActivity extends Activity private boolean mIsFilmModeSet; private float mDefaultRefreshRate; - @Inject TvOverlayManagerFactory mOverlayFactory; private TvOverlayManager mOverlayManager; // mIsCurrentChannelUnblockedByUser and mWasChannelUnblockedBeforeShrunkenByUser are used for @@ -503,6 +477,7 @@ public class MainActivity extends Activity AndroidInjection.inject(this); mAccessibilityManager = (AccessibilityManager) getSystemService(Context.ACCESSIBILITY_SERVICE); + TvSingletons tvSingletons = TvSingletons.getSingletons(this); DurationTimer startUpDebugTimer = Debug.getTimer(Debug.TAG_START_UP_TIMER); if (!startUpDebugTimer.isStarted() || startUpDebugTimer.getDuration() > START_UP_TIMER_RESET_THRESHOLD_MS) { @@ -521,7 +496,6 @@ public class MainActivity extends Activity finishAndRemoveTask(); return; } - mAccountHelper.init(); TvSingletons tvApplication = (TvSingletons) getApplication(); // In API 23, TvContract.isChannelUriForPassthroughInput is hidden. @@ -540,8 +514,8 @@ public class MainActivity extends Activity return; } setContentView(R.layout.activity_tv); - mTvView = findViewById(R.id.main_tunable_tv_view); - mTvView.initialize(mProgramDataManager, mTvInputManagerHelper, mLegacyFlags); + mTvView = (TunableTvView) findViewById(R.id.main_tunable_tv_view); + mTvView.initialize(mProgramDataManager, mTvInputManagerHelper); mTvView.setOnUnhandledInputEventListener( new OnUnhandledInputEventListener() { @Override @@ -571,13 +545,12 @@ public class MainActivity extends Activity String inputId = Utils.getLastWatchedTunerInputId(this); if (!isPassthroughInput && inputId != null - && !mStartupFlags.warmupInputidBlacklist().getElementList().contains(inputId) && channelId != Channel.INVALID_ID) { mTvView.warmUpInput(inputId, TvContract.buildChannelUri(channelId)); } tvApplication.getMainActivityWrapper().onMainActivityCreated(this); - if (BuildConfig.ENG && DeveloperPreferences.ALLOW_STRICT_MODE.get(this)) { + if (BuildConfig.ENG && SystemProperties.ALLOW_STRICT_MODE.getValue()) { Toast.makeText(this, "Using Strict Mode for eng builds", Toast.LENGTH_SHORT).show(); } mTracker = tvApplication.getTracker(); @@ -639,10 +612,13 @@ public class MainActivity extends Activity } mTvViewUiManager = new TvViewUiManager( - this, mTvView, findViewById(android.R.id.content), mTvOptionsManager); + this, + mTvView, + (FrameLayout) findViewById(android.R.id.content), + mTvOptionsManager); mContentView = findViewById(android.R.id.content); - ViewGroup sceneContainer = findViewById(R.id.scene_container); + ViewGroup sceneContainer = (ViewGroup) findViewById(R.id.scene_container); ChannelBannerView channelBannerView = (ChannelBannerView) getLayoutInflater().inflate(R.layout.channel_banner, sceneContainer, false); @@ -695,7 +671,7 @@ public class MainActivity extends Activity }); mSearchFragment = new ProgramGuideSearchFragment(); mOverlayManager = - mOverlayFactory.create( + new TvOverlayManager( this, mChannelTuner, mTvView, @@ -733,6 +709,8 @@ public class MainActivity extends Activity SendChannelStatusRunnable.startChannelStatusRecurringRunner( this, mTracker, mChannelDataManager); + // To avoid not updating Rating systems when changing language. + mTvInputManagerHelper.getContentRatingsManager().update(); if (CommonFeatures.DVR.isEnabled(this) && TvFeatures.SHOW_UPCOMING_CONFLICT_DIALOG.isEnabled(this)) { mDvrConflictChecker = new ConflictChecker(this); @@ -764,7 +742,7 @@ public class MainActivity extends Activity mChannelDataManager.reload(); mProgramDataManager.reload(); - // Restart TV app. + // Restart live channels. Intent intent = getIntent(); finish(); startActivity(intent); @@ -852,7 +830,7 @@ public class MainActivity extends Activity .getTunerInputController() .executeNetworkTunerDiscoveryAsyncTask(this); } - mEpgFetcher.fetchImmediatelyIfNeeded(); + TvSingletons.getSingletons(this).getEpgFetcher().fetchImmediatelyIfNeeded(); } @Override @@ -1149,8 +1127,8 @@ public class MainActivity extends Activity Toast.makeText(this, R.string.msg_no_setup_activity, Toast.LENGTH_SHORT).show(); return; } - // Even though other app can handle the intent, the setup launched by TV app - // should go through TV app SetupPassthroughActivity. + // Even though other app can handle the intent, the setup launched by Live channels + // should go through Live channels SetupPassthroughActivity. intent.setComponent(new ComponentName(this, SetupPassthroughActivity.class)); try { // Now we know that the user intends to set up this input. Grant permission for writing @@ -1420,9 +1398,7 @@ public class MainActivity extends Activity @Override public boolean dispatchKeyEvent(KeyEvent event) { - if (DeveloperPreferences.LOG_KEYEVENT.get(this)) { - Log.d(TAG, "dispatchKeyEvent(" + event + ")"); - } + if (SystemProperties.LOG_KEYEVENT.getValue()) Log.d(TAG, "dispatchKeyEvent(" + event + ")"); // If an activity is closed on a back key down event, back key down events with none zero // repeat count or a back key up event can be happened without the first back key down // event which should be ignored in this activity. @@ -1527,7 +1503,7 @@ public class MainActivity extends Activity new AsyncQueryProgramTask( mDbExecutor, programUriFromIntent, - ProgramImpl.PROJECTION, + Program.PROJECTION, null, null, null, @@ -1558,7 +1534,7 @@ public class MainActivity extends Activity String inputId = mInitChannelUri.getQueryParameter("input"); long channelId = Utils.getLastWatchedChannelIdForInput(this, inputId); if (channelId == Channel.INVALID_ID) { - String[] projection = {BaseColumns._ID}; + String[] projection = {Channels._ID}; long time = System.currentTimeMillis(); try (Cursor cursor = getContentResolver().query(uri, projection, null, null, null)) { @@ -1606,7 +1582,7 @@ public class MainActivity extends Activity protected Program onQuery(Cursor c) { Program program = null; if (c != null && c.moveToNext()) { - program = ProgramImpl.fromCursor(c); + program = Program.fromCursor(c); } return program; } @@ -1622,7 +1598,7 @@ public class MainActivity extends Activity Intent intent = new Intent(MainActivity.this, DetailsActivity.class); intent.putExtra(DetailsActivity.CHANNEL_ID, mChannelIdFromIntent); intent.putExtra(DetailsActivity.DETAILS_VIEW_TYPE, DetailsActivity.PROGRAM_VIEW); - intent.putExtra(DetailsActivity.PROGRAM, program.toParcelable()); + intent.putExtra(DetailsActivity.PROGRAM, program); intent.putExtra(DetailsActivity.INPUT_ID, channel.getInputId()); startActivity(intent); } @@ -2101,7 +2077,7 @@ public class MainActivity extends Activity @Override public boolean onKeyDown(int keyCode, KeyEvent event) { - if (DeveloperPreferences.LOG_KEYEVENT.get(this)) { + if (SystemProperties.LOG_KEYEVENT.getValue()) { Log.d(TAG, "onKeyDown(" + keyCode + ", " + event + ")"); } switch (mOverlayManager.onKeyDown(keyCode, event)) { @@ -2191,7 +2167,7 @@ public class MainActivity extends Activity * W debug: toggle screen size * V KEYCODE_MEDIA_RECORD debug: record the current channel for 30 sec */ - if (DeveloperPreferences.LOG_KEYEVENT.get(this)) { + if (SystemProperties.LOG_KEYEVENT.getValue()) { Log.d(TAG, "onKeyUp(" + keyCode + ", " + event + ")"); } // If we are in the middle of channel change, finish it before showing overlays. @@ -2289,7 +2265,7 @@ public class MainActivity extends Activity // Channel change is already done in the head of this method. return true; case KeyEvent.KEYCODE_S: - if (!DeveloperPreferences.USE_DEBUG_KEYS.get(this)) { + if (!SystemProperties.USE_DEBUG_KEYS.getValue()) { break; } // fall through. @@ -2297,7 +2273,7 @@ public class MainActivity extends Activity mOverlayManager.getSideFragmentManager().show(new ClosedCaptionFragment()); return true; case KeyEvent.KEYCODE_A: - if (!DeveloperPreferences.USE_DEBUG_KEYS.get(this)) { + if (!SystemProperties.USE_DEBUG_KEYS.getValue()) { break; } // fall through. @@ -2363,7 +2339,7 @@ public class MainActivity extends Activity // in case that TV isn't showing properly (e.g. no browsable channel) return true; } - if (DeveloperPreferences.USE_DEBUG_KEYS.get(this) || BuildConfig.ENG) { + if (SystemProperties.USE_DEBUG_KEYS.getValue() || BuildConfig.ENG) { switch (keyCode) { case KeyEvent.KEYCODE_W: mDebugNonFullSizeScreen = !mDebugNonFullSizeScreen; @@ -2419,7 +2395,7 @@ public class MainActivity extends Activity @Override public boolean onKeyLongPress(int keyCode, KeyEvent event) { - if (DeveloperPreferences.LOG_KEYEVENT.get(this)) Log.d(TAG, "onKeyLongPress(" + event); + if (SystemProperties.LOG_KEYEVENT.getValue()) Log.d(TAG, "onKeyLongPress(" + event); if (USE_BACK_KEY_LONG_PRESS) { // Treat the BACK key long press as the normal press since we changed the behavior in // onBackPressed(). @@ -2489,7 +2465,7 @@ public class MainActivity extends Activity } private boolean dispatchKeyEventToSession(final KeyEvent event) { - if (DeveloperPreferences.LOG_KEYEVENT.get(this)) { + if (SystemProperties.LOG_KEYEVENT.getValue()) { Log.d(TAG, "dispatchKeyEventToSession(" + event + ")"); } boolean handled = false; @@ -2742,10 +2718,7 @@ public class MainActivity extends Activity return; } - // Only try to set the channels browseable if we are a system app. - if (SYSTEM_APP_FEATURE.isEnabled(getApplicationContext())) { - Utils.enableAllChannels(this); - } + Utils.enableAllChannels(this); } // Lazy initialization @@ -2805,11 +2778,6 @@ public class MainActivity extends Activity } } - @Override - public AndroidInjector<Object> androidInjector() { - return mAndroidInjector; - } - private static class MainActivityHandler extends WeakHandler<MainActivity> { MainActivityHandler(MainActivity mainActivity) { super(mainActivity); @@ -2855,8 +2823,11 @@ public class MainActivity extends Activity Debug.getTimer(Debug.TAG_START_UP_TIMER).log("MainActivity.MyOnTuneListener.onTune"); mChannel = channel; mWasUnderShrunkenTvView = wasUnderShrunkenTvView; - // Fetch complete projection of tuned channel. - mProgramDataManager.onChannelTuned(channel.getId()); + + if (mBackendKnobs.enablePartialProgramFetch()) { + // Fetch complete projection of tuned channel. + mProgramDataManager.prefetchChannel(channel.getId()); + } } @Override @@ -3011,14 +2982,5 @@ public class MainActivity extends Activity public abstract static class Module { @ContributesAndroidInjector abstract MainActivity contributesMainActivityActivityInjector(); - - @ContributesAndroidInjector - abstract DeveloperOptionFragment contributesDeveloperOptionFragment(); - - @ContributesAndroidInjector - abstract RatingsFragment contributesRatingsFragment(); - - @ContributesAndroidInjector - abstract ProgramItemView contributesProgramItemView(); } } diff --git a/src/com/android/tv/MediaSessionWrapper.java b/src/com/android/tv/MediaSessionWrapper.java index df886391..a647a06f 100644 --- a/src/com/android/tv/MediaSessionWrapper.java +++ b/src/com/android/tv/MediaSessionWrapper.java @@ -34,9 +34,8 @@ import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; import android.text.TextUtils; import android.util.Log; - +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.util.Utils; import com.android.tv.util.images.ImageLoader; diff --git a/src/com/android/tv/SetupPassthroughActivity.java b/src/com/android/tv/SetupPassthroughActivity.java index 25049f1d..5185b122 100644 --- a/src/com/android/tv/SetupPassthroughActivity.java +++ b/src/com/android/tv/SetupPassthroughActivity.java @@ -18,7 +18,7 @@ package com.android.tv; import android.app.Activity; import android.content.ActivityNotFoundException; -import android.content.ComponentName; +import android.content.Context; import android.content.Intent; import android.media.tv.TvInputInfo; import android.os.Bundle; @@ -26,8 +26,6 @@ import android.os.Handler; import android.os.Looper; import android.support.annotation.MainThread; import android.util.Log; - -import com.android.tv.common.CommonConstants; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.actions.InputSetupActionUtils; import com.android.tv.data.ChannelDataManager; @@ -38,16 +36,9 @@ import com.android.tv.features.TvFeatures; import com.android.tv.util.SetupUtils; import com.android.tv.util.TvInputManagerHelper; import com.android.tv.util.Utils; - import com.google.android.tv.partner.support.EpgContract; - -import dagger.android.AndroidInjection; -import dagger.android.ContributesAndroidInjector; - import java.util.concurrent.TimeUnit; -import javax.inject.Inject; - /** * An activity to launch a TV input setup activity. * @@ -64,20 +55,18 @@ public class SetupPassthroughActivity extends Activity { private TvInputInfo mTvInputInfo; private Intent mActivityAfterCompletion; private boolean mEpgFetcherDuringScan; - @Inject EpgInputWhiteList mEpgInputWhiteList; - @Inject TvInputManagerHelper mInputManager; - @Inject SetupUtils mSetupUtils; - @Inject ChannelDataManager mChannelDataManager; - @Inject EpgFetcher mEpgFetcher; + private EpgInputWhiteList mEpgInputWhiteList; @Override public void onCreate(Bundle savedInstanceState) { if (DEBUG) Log.d(TAG, "onCreate"); - AndroidInjection.inject(this); super.onCreate(savedInstanceState); + TvSingletons tvSingletons = TvSingletons.getSingletons(this); + TvInputManagerHelper inputManager = tvSingletons.getTvInputManagerHelper(); Intent intent = getIntent(); String inputId = intent.getStringExtra(InputSetupActionUtils.EXTRA_INPUT_ID); - mTvInputInfo = mInputManager.getTvInputInfo(inputId); + mTvInputInfo = inputManager.getTvInputInfo(inputId); + mEpgInputWhiteList = new EpgInputWhiteList(tvSingletons.getCloudEpgFlags()); mActivityAfterCompletion = InputSetupActionUtils.getExtraActivityAfter(intent); boolean needToFetchEpg = mTvInputInfo != null && Utils.isInternalTvInput(this, mTvInputInfo.getId()); @@ -117,17 +106,6 @@ public class SetupPassthroughActivity extends Activity { InputSetupActionUtils.removeSetupIntent(extras); setupIntent.putExtras(extras); try { - ComponentName callingActivity = getCallingActivity(); - if (callingActivity != null - && !callingActivity.getPackageName().equals(CommonConstants.BASE_PACKAGE)) { - Log.w( - TAG, - "Calling activity " - + callingActivity.getPackageName() - + " is not trusted. Not forwarding intent."); - finish(); - return; - } startActivityForResult(setupIntent, REQUEST_START_SETUP_ACTIVITY); } catch (ActivityNotFoundException e) { Log.e(TAG, "Can't find activity: " + setupIntent.getComponent()); @@ -136,10 +114,10 @@ public class SetupPassthroughActivity extends Activity { } if (needToFetchEpg) { if (sScanTimeoutMonitor == null) { - sScanTimeoutMonitor = new ScanTimeoutMonitor(mEpgFetcher, mChannelDataManager); + sScanTimeoutMonitor = new ScanTimeoutMonitor(this); } sScanTimeoutMonitor.startMonitoring(); - mEpgFetcher.onChannelScanStarted(); + TvSingletons.getSingletons(this).getEpgFetcher().onChannelScanStarted(); } } } @@ -155,25 +133,15 @@ public class SetupPassthroughActivity extends Activity { boolean setupComplete = requestCode == REQUEST_START_SETUP_ACTIVITY && resultCode == Activity.RESULT_OK; // Tells EpgFetcher that channel source setup is finished. - + EpgFetcher epgFetcher = TvSingletons.getSingletons(this).getEpgFetcher(); if (mEpgFetcherDuringScan) { - mEpgFetcher.onChannelScanFinished(); + epgFetcher.onChannelScanFinished(); } if (!setupComplete) { setResult(resultCode, data); finish(); return; } - if (TvFeatures.CLOUD_EPG_FOR_3RD_PARTY.isEnabled(this) - && data != null - && data.getBooleanExtra(EpgContract.EXTRA_USE_CLOUD_EPG, false)) { - if (DEBUG) Log.d(TAG, "extra " + data.getExtras()); - String inputId = data.getStringExtra(TvInputInfo.EXTRA_INPUT_ID); - if (mEpgInputWhiteList.isInputWhiteListed(inputId)) { - mEpgFetcher.fetchImmediately(); - } - } - if (mTvInputInfo == null) { Log.w( TAG, @@ -184,19 +152,21 @@ public class SetupPassthroughActivity extends Activity { finish(); return; } - mSetupUtils.onTvInputSetupFinished( - mTvInputInfo.getId(), - () -> { - if (mActivityAfterCompletion != null) { - try { - startActivity(mActivityAfterCompletion); - } catch (ActivityNotFoundException e) { - Log.w(TAG, "Activity launch failed", e); - } - } - setResult(resultCode, data); - finish(); - }); + TvSingletons.getSingletons(this) + .getSetupUtils() + .onTvInputSetupFinished( + mTvInputInfo.getId(), + () -> { + if (mActivityAfterCompletion != null) { + try { + startActivity(mActivityAfterCompletion); + } catch (ActivityNotFoundException e) { + Log.w(TAG, "Activity launch failed", e); + } + } + setResult(resultCode, data); + finish(); + }); } /** @@ -209,7 +179,7 @@ public class SetupPassthroughActivity extends Activity { // Set timeout long enough. The message in Sony TV says the scanning takes about 30 minutes. private static final long SCAN_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(30); - private final EpgFetcher mEpgFetcher; + private final Context mContext; private final ChannelDataManager mChannelDataManager; private final Handler mHandler = new Handler(Looper.getMainLooper()); private final Runnable mScanTimeoutRunnable = @@ -237,9 +207,9 @@ public class SetupPassthroughActivity extends Activity { }; private boolean mStarted; - private ScanTimeoutMonitor(EpgFetcher epgFetcher, ChannelDataManager mChannelDataManager) { - mEpgFetcher = epgFetcher; - this.mChannelDataManager = mChannelDataManager; + private ScanTimeoutMonitor(Context context) { + mContext = context.getApplicationContext(); + mChannelDataManager = TvSingletons.getSingletons(context).getChannelDataManager(); } private void startMonitoring() { @@ -267,14 +237,7 @@ public class SetupPassthroughActivity extends Activity { private void onScanTimedOut() { stopMonitoring(); - mEpgFetcher.onChannelScanFinished(); + TvSingletons.getSingletons(mContext).getEpgFetcher().onChannelScanFinished(); } } - - /** Exports {@link MainActivity} for Dagger codegen to create the appropriate injector. */ - @dagger.Module - public abstract static class Module { - @ContributesAndroidInjector - abstract SetupPassthroughActivity contributesSetupPassthroughActivity(); - } } diff --git a/src/com/android/tv/TimeShiftManager.java b/src/com/android/tv/TimeShiftManager.java index f08b5e85..779e8df6 100644 --- a/src/com/android/tv/TimeShiftManager.java +++ b/src/com/android/tv/TimeShiftManager.java @@ -26,21 +26,18 @@ import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; import android.util.Log; import android.util.Range; - import com.android.tv.analytics.Tracker; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.WeakHandler; import com.android.tv.data.OnCurrentProgramUpdatedListener; +import com.android.tv.data.Program; import com.android.tv.data.ProgramDataManager; -import com.android.tv.data.ProgramImpl; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.ui.TunableTvView; import com.android.tv.ui.api.TunableTvViewPlayingApi.TimeShiftListener; import com.android.tv.util.AsyncDbTask; import com.android.tv.util.TimeShiftUtils; import com.android.tv.util.Utils; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -53,7 +50,7 @@ import java.util.Queue; import java.util.concurrent.TimeUnit; /** - * A class which manages the time shift feature in TV app. It consists of two parts. {@link + * A class which manages the time shift feature in Live TV. It consists of two parts. {@link * PlayController} controls the playback such as play/pause, rewind and fast-forward using {@link * TunableTvView} which communicates with TvInputService through {@link * android.media.tv.TvInputService.Session}. {@link ProgramManager} loads programs of the current @@ -147,8 +144,8 @@ public class TimeShiftManager { DISABLE_ACTION_THRESHOLD + 3 * REQUEST_CURRENT_POSITION_INTERVAL; /** * The current position sent from TIS can not be exactly the same as the current system time due - * to the elapsed time to pass the message from TIS to TV app. So the boundary threshold is - * necessary. The same goes for the recording start time. It's the same {@link + * to the elapsed time to pass the message from TIS to Live TV. So the boundary threshold + * is necessary. The same goes for the recording start time. It's the same {@link * #REQUEST_CURRENT_POSITION_INTERVAL}. */ private static final long RECORDING_BOUNDARY_THRESHOLD = REQUEST_CURRENT_POSITION_INTERVAL; @@ -622,8 +619,8 @@ public class TimeShiftManager { < mAvailablityChangedTimeMs - ALLOWED_START_TIME_OFFSET) { Log.e( TAG, - "The start time is too earlier than the time of" - + " availability: {startTime: " + "The start time is too earlier than the time of availability: {" + + "startTime: " + recordStartTimeMs + ", availability: " + mAvailablityChangedTimeMs); @@ -635,9 +632,9 @@ public class TimeShiftManager { // clock,, use system's current time instead. Log.e( TAG, - "The start time should not be earlier than the current" - + " time, reset the start time to the system's current" - + " time: {startTime: " + "The start time should not be earlier than the current time, " + + "reset the start time to the system's current time: {" + + "startTime: " + recordStartTimeMs + ", current time: " + System.currentTimeMillis()); @@ -1106,7 +1103,7 @@ public class TimeShiftManager { long end = Utils.ceilTime(startTimeMs, MAX_DUMMY_PROGRAM_DURATION); while (end < endTimeMs) { programs.add( - new ProgramImpl.Builder() + new Program.Builder() .setStartTimeUtcMillis(start) .setEndTimeUtcMillis(end) .build()); @@ -1114,7 +1111,7 @@ public class TimeShiftManager { end += MAX_DUMMY_PROGRAM_DURATION; } programs.add( - new ProgramImpl.Builder() + new Program.Builder() .setStartTimeUtcMillis(start) .setEndTimeUtcMillis(endTimeMs) .build()); diff --git a/src/com/android/tv/TvApplication.java b/src/com/android/tv/TvApplication.java index bc8226cf..5f25a24b 100644 --- a/src/com/android/tv/TvApplication.java +++ b/src/com/android/tv/TvApplication.java @@ -35,19 +35,20 @@ import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; import android.widget.Toast; - import com.android.tv.common.BaseApplication; import com.android.tv.common.feature.CommonFeatures; import com.android.tv.common.recording.RecordingStorageStatusManager; import com.android.tv.common.ui.setup.animation.SetupAnimationHelper; +import com.android.tv.common.util.Clock; import com.android.tv.common.util.Debug; import com.android.tv.common.util.SharedPreferencesUtils; 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.data.epg.EpgFetcherImpl; import com.android.tv.dvr.DvrDataManager; +import com.android.tv.dvr.DvrDataManagerImpl; import com.android.tv.dvr.DvrManager; import com.android.tv.dvr.DvrScheduleManager; import com.android.tv.dvr.DvrStorageStatusManager; @@ -55,9 +56,8 @@ import com.android.tv.dvr.DvrWatchedPositionManager; import com.android.tv.dvr.recorder.RecordingScheduler; import com.android.tv.dvr.ui.browse.DvrBrowseActivity; import com.android.tv.features.TvFeatures; -import com.android.tv.perf.PerformanceMonitor; -import com.android.tv.perf.StartupMeasure; -import com.android.tv.perf.StartupMeasureFactory; +import com.android.tv.perf.PerformanceMonitorManager; +import com.android.tv.perf.PerformanceMonitorManagerFactory; import com.android.tv.recommendation.ChannelPreviewUpdater; import com.android.tv.recommendation.RecordedProgramPreviewUpdater; import com.android.tv.tunerinputcontroller.BuiltInTunerManager; @@ -66,30 +66,27 @@ import com.android.tv.util.AsyncDbTask.DbExecutor; import com.android.tv.util.SetupUtils; import com.android.tv.util.TvInputManagerHelper; import com.android.tv.util.Utils; - import com.google.common.base.Optional; - import dagger.Lazy; - -import com.android.tv.common.flags.CloudEpgFlags; -import com.android.tv.common.flags.LegacyFlags; - import java.util.List; import java.util.concurrent.Executor; - import javax.inject.Inject; /** - * TV application. + * Live TV application. * * <p>This includes all the Google specific hooks. */ public abstract class TvApplication extends BaseApplication implements TvSingletons, Starter { - protected static final StartupMeasure STARTUP_MEASURE = StartupMeasureFactory.create(); + protected static final PerformanceMonitorManager PERFORMANCE_MONITOR_MANAGER = + PerformanceMonitorManagerFactory.create(); private static final String TAG = "TvApplication"; private static final boolean DEBUG = false; + /** Namespace for LiveChannels configs. LiveChannels configs are kept in piper. */ + public static final String CONFIGNS_P4 = "configns:p4"; + /** * Broadcast Action: The user has updated LC to a new version that supports tuner input. {@link * TunerInputController} will receive this intent to check the existence of tuner input when the @@ -105,12 +102,12 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet private final MainActivityWrapper mMainActivityWrapper = new MainActivityWrapper(); private SelectInputActivity mSelectInputActivity; - @Inject Lazy<ChannelDataManager> mChannelDataManager; + private ChannelDataManager mChannelDataManager; private volatile ProgramDataManager mProgramDataManager; private PreviewDataManager mPreviewDataManager; private DvrManager mDvrManager; private DvrScheduleManager mDvrScheduleManager; - @Inject Lazy<DvrDataManager> mDvrDataManager; + private DvrDataManager mDvrDataManager; private DvrWatchedPositionManager mDvrWatchedPositionManager; private RecordingScheduler mRecordingScheduler; private RecordingStorageStatusManager mDvrStorageStatusManager; @@ -120,16 +117,11 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet private Boolean mRunningInMainProcess; @Inject Lazy<TvInputManagerHelper> mLazyTvInputManagerHelper; private boolean mStarted; - @Inject EpgFetcher mEpgFetcher; + private EpgFetcher mEpgFetcher; @Inject Optional<BuiltInTunerManager> mOptionalBuiltInTunerManager; @Inject SetupUtils mSetupUtils; @Inject @DbExecutor Executor mDbExecutor; - @Inject Lazy<EpgReader> mEpgReader; - @Inject BuildType mBuildType; - @Inject CloudEpgFlags mCloudEpgFlags; - @Inject LegacyFlags mLegacyFlags; - @Inject PerformanceMonitor mPerformanceMonitor; @Override public void onCreate() { @@ -140,8 +132,6 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet throw new IllegalStateException(msg); } super.onCreate(); - mPerformanceMonitor.startMemoryMonitor(); - mPerformanceMonitor.startCrashMonitor(); SharedPreferencesUtils.initialize( this, () -> { @@ -156,15 +146,16 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet Log.w(TAG, "Unable to find package '" + getPackageName() + "'.", e); mVersionName = ""; } - Log.i(TAG, "Starting TV app " + getVersionName()); + Log.i(TAG, "Starting Live TV " + getVersionName()); // In SetupFragment, transitions are set in the constructor. Because the fragment can be // created in Activity.onCreate() by the framework, SetupAnimationHelper should be // initialized here before Activity.onCreate() is called. + mEpgFetcher = EpgFetcherImpl.create(this); SetupAnimationHelper.initialize(this); getTvInputManagerHelper(); - Log.i(TAG, "Started TV app " + mVersionName); + Log.i(TAG, "Started Live TV " + mVersionName); Debug.getTimer(Debug.TAG_START_UP_TIMER).log("finish TvApplication.onCreate"); } @@ -219,10 +210,8 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet mEpgFetcher.startRoutineService(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { ChannelPreviewUpdater.getInstance(this).startRoutineService(); - if (CommonFeatures.DVR.isEnabled(this)) { - RecordedProgramPreviewUpdater.getInstance(this) - .updatePreviewDataForRecordedPrograms(); - } + RecordedProgramPreviewUpdater.getInstance(this) + .updatePreviewDataForRecordedPrograms(); } } Debug.getTimer(Debug.TAG_START_UP_TIMER).log("finish TvApplication.start"); @@ -248,6 +237,11 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet } @Override + public EpgFetcher getEpgFetcher() { + return mEpgFetcher; + } + + @Override public synchronized SetupUtils getSetupUtils() { return mSetupUtils; } @@ -292,7 +286,16 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet /** Returns {@link ChannelDataManager}. */ @Override public ChannelDataManager getChannelDataManager() { - return mChannelDataManager.get(); + if (mChannelDataManager == null) { + mChannelDataManager = new ChannelDataManager(this, getTvInputManagerHelper()); + mChannelDataManager.start(); + } + return mChannelDataManager; + } + + @Override + public boolean isChannelDataManagerLoadFinished() { + return mChannelDataManager != null && mChannelDataManager.isDbLoadFinished(); } /** Returns {@link ProgramDataManager}. */ @@ -311,6 +314,11 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet return mProgramDataManager; } + @Override + public boolean isProgramDataManagerCurrentProgramsLoadFinished() { + return mProgramDataManager != null && mProgramDataManager.isCurrentProgramsLoadFinished(); + } + /** Returns {@link PreviewDataManager}. */ @TargetApi(Build.VERSION_CODES.O) @Override @@ -326,7 +334,12 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet @TargetApi(Build.VERSION_CODES.N) @Override public DvrDataManager getDvrDataManager() { - return mDvrDataManager.get(); + if (mDvrDataManager == null) { + DvrDataManagerImpl dvrDataManager = new DvrDataManagerImpl(this, Clock.SYSTEM); + mDvrDataManager = dvrDataManager; + dvrDataManager.start(); + } + return mDvrDataManager; } @Override @@ -338,11 +351,6 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet return mDvrStorageStatusManager; } - @Override - public PerformanceMonitor getPerformanceMonitor() { - return mPerformanceMonitor; - } - /** Returns the main activity information. */ @Override public MainActivityWrapper getMainActivityWrapper() { @@ -442,7 +450,7 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet } /** - * Returns the version name of the TV app. + * Returns the version name of the live channels. * * @see PackageInfo#versionName */ @@ -481,37 +489,6 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet Optional<String> optionalEmbeddedTunerInputId = mOptionalBuiltInTunerManager.transform( BuiltInTunerManager::getEmbeddedTunerInputId); - // If there is only play movies trailer input, we don't handle input count change. - final String playMoviesInputIdPrefix = "com.google.android.videos/"; - int tunerInputCount = 0; - boolean hasPlayMoviesInput = false; - for (TvInputInfo input : inputs) { - if (calledByTunerServiceChanged - && !tunerServiceEnabled - && optionalEmbeddedTunerInputId.isPresent() - && optionalEmbeddedTunerInputId.get().equals(input.getId())) { - continue; - } - if (input.getType() == TvInputInfo.TYPE_TUNER) { - if (DEBUG) Log.d(TAG, "Tuner input: " + input.getId()); - ++tunerInputCount; - if (input.getId().startsWith(playMoviesInputIdPrefix)) { - hasPlayMoviesInput = true; - } - } - } - if (DEBUG) { - Log.d( - TAG, - "Input count: " - + tunerInputCount - + " hasPlayMoviesChannel: " - + hasPlayMoviesInput); - } - if (tunerInputCount == 1 && hasPlayMoviesInput) { - if (DEBUG) Log.d(TAG, "There is only play movies input"); - skipTunerInputCheck = true; - } // Enable the TvActivity only if there is at least one tuner type input. if (!skipTunerInputCheck) { for (TvInputInfo input : inputs) { @@ -538,24 +515,13 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet if (packageManager.getComponentEnabledSetting(name) != newState) { packageManager.setComponentEnabledSetting( name, newState, dontKillApp ? PackageManager.DONT_KILL_APP : 0); - Log.i(TAG, (enable ? "Un-hide" : "Hide") + " TV app."); + Log.i(TAG, (enable ? "Un-hide" : "Hide") + " Live TV."); } mSetupUtils.onInputListUpdated(inputManager); } @Override - @DbExecutor public Executor getDbExecutor() { return mDbExecutor; } - - @Override - public Lazy<EpgReader> providesEpgReader() { - return mEpgReader; - } - - @Override - public BuildType getBuildType() { - return mBuildType; - } } diff --git a/src/com/android/tv/TvSingletons.java b/src/com/android/tv/TvSingletons.java index 9e4f4620..20edf3d4 100644 --- a/src/com/android/tv/TvSingletons.java +++ b/src/com/android/tv/TvSingletons.java @@ -17,15 +17,16 @@ package com.android.tv; import android.content.Context; - import com.android.tv.analytics.Analytics; import com.android.tv.analytics.Tracker; import com.android.tv.common.BaseApplication; import com.android.tv.common.BaseSingletons; +import com.android.tv.common.experiments.ExperimentLoader; import com.android.tv.common.flags.has.HasUiFlags; 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; @@ -36,27 +37,14 @@ import com.android.tv.perf.PerformanceMonitor; import com.android.tv.tunerinputcontroller.HasBuiltInTunerManager; import com.android.tv.util.SetupUtils; import com.android.tv.util.TvInputManagerHelper; - -import dagger.Lazy; - +import com.android.tv.util.account.AccountHelper; import com.android.tv.common.flags.BackendKnobsFlags; - import java.util.concurrent.Executor; +import javax.inject.Provider; /** Interface with getters for application scoped singletons. */ public interface TvSingletons extends BaseSingletons, HasBuiltInTunerManager, HasUiFlags { - /* - * Do not add any new methods here. - * - * To move a getter to Injection. - * 1. Make a type injectable @Singleton. - * 2. Mark the getter here as deprecated. - * 3. Lazily inject the object in TvApplication. - * 4. Move easy usages of getters to injection instead. - * 5. Delete the method when all usages are migrated. - */ - /** * Returns the @{@link TvSingletons} using the application context. * @@ -74,14 +62,24 @@ public interface TvSingletons extends BaseSingletons, HasBuiltInTunerManager, Ha @Deprecated ChannelDataManager getChannelDataManager(); + /** + * Checks if the {@link ChannelDataManager} instance has been created and all the channels has + * been loaded. + */ + boolean isChannelDataManagerLoadFinished(); + /** @deprecated use injection instead. */ @Deprecated ProgramDataManager getProgramDataManager(); + /** + * Checks if the {@link ProgramDataManager} instance has been created and the current programs + * for all the channels has been loaded. + */ + boolean isProgramDataManagerCurrentProgramsLoadFinished(); + PreviewDataManager getPreviewDataManager(); - /** @deprecated use injection instead. */ - @Deprecated DvrDataManager getDvrDataManager(); DvrScheduleManager getDvrScheduleManager(); @@ -90,8 +88,6 @@ public interface TvSingletons extends BaseSingletons, HasBuiltInTunerManager, Ha RecordingScheduler getRecordingScheduler(); - /** @deprecated use injection instead. */ - @Deprecated DvrWatchedPositionManager getDvrWatchedPositionManager(); InputSessionManager getInputSessionManager(); @@ -100,22 +96,26 @@ public interface TvSingletons extends BaseSingletons, HasBuiltInTunerManager, Ha MainActivityWrapper getMainActivityWrapper(); + AccountHelper getAccountHelper(); + boolean isRunningInMainProcess(); - /** @deprecated use injection instead. */ - @Deprecated PerformanceMonitor getPerformanceMonitor(); /** @deprecated use injection instead. */ @Deprecated TvInputManagerHelper getTvInputManagerHelper(); - Lazy<EpgReader> providesEpgReader(); + Provider<EpgReader> providesEpgReader(); + + EpgFetcher getEpgFetcher(); /** @deprecated use injection instead. */ @Deprecated SetupUtils getSetupUtils(); + ExperimentLoader getExperimentLoader(); + /** @deprecated use injection instead. */ @Deprecated Executor getDbExecutor(); diff --git a/src/com/android/tv/app/LiveTvApplication.java b/src/com/android/tv/app/LiveTvApplication.java index 80906537..38e85e48 100644 --- a/src/com/android/tv/app/LiveTvApplication.java +++ b/src/com/android/tv/app/LiveTvApplication.java @@ -22,34 +22,50 @@ import com.android.tv.analytics.Analytics; import com.android.tv.analytics.StubAnalytics; import com.android.tv.analytics.Tracker; import com.android.tv.common.dagger.ApplicationModule; +import com.android.tv.common.experiments.ExperimentLoader; import com.android.tv.common.flags.impl.DefaultBackendKnobsFlags; import com.android.tv.common.flags.impl.DefaultCloudEpgFlags; +import com.android.tv.common.flags.impl.DefaultConcurrentDvrPlaybackFlags; import com.android.tv.common.flags.impl.DefaultUiFlags; import com.android.tv.common.singletons.HasSingletons; +import com.android.tv.data.epg.EpgReader; +import com.android.tv.data.epg.StubEpgReader; import com.android.tv.modules.TvSingletonsModule; import com.android.tv.perf.PerformanceMonitor; +import com.android.tv.perf.PerformanceMonitorManagerFactory; import com.android.tv.tunerinputcontroller.BuiltInTunerManager; - +import com.android.tv.util.account.AccountHelper; +import com.android.tv.util.account.AccountHelperImpl; import com.google.common.base.Optional; - import dagger.android.AndroidInjector; - -import javax.inject.Inject; +import javax.inject.Provider; /** The top level application for Live TV. */ public class LiveTvApplication extends TvApplication implements HasSingletons<TvSingletons> { static { - STARTUP_MEASURE.onAppClassLoaded(); + PERFORMANCE_MONITOR_MANAGER.getStartupMeasure().onAppClassLoaded(); } + private final Provider<EpgReader> mEpgReaderProvider = + new Provider<EpgReader>() { + + @Override + public EpgReader get() { + return new StubEpgReader(LiveTvApplication.this); + } + }; + private final DefaultBackendKnobsFlags mBackendKnobsFlags = new DefaultBackendKnobsFlags(); private final DefaultCloudEpgFlags mCloudEpgFlags = new DefaultCloudEpgFlags(); private final DefaultUiFlags mUiFlags = new DefaultUiFlags(); - + private final DefaultConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags = + new DefaultConcurrentDvrPlaybackFlags(); + private AccountHelper mAccountHelper; private Analytics mAnalytics; private Tracker mTracker; - @Inject PerformanceMonitor mPerformanceMonitor; + private ExperimentLoader mExperimentLoader; + private PerformanceMonitor mPerformanceMonitor; @Override protected AndroidInjector<LiveTvApplication> applicationInjector() { @@ -62,15 +78,38 @@ public class LiveTvApplication extends TvApplication implements HasSingletons<Tv @Override public void onCreate() { super.onCreate(); - STARTUP_MEASURE.onAppCreate(this); + PERFORMANCE_MONITOR_MANAGER.getStartupMeasure().onAppCreate(this); } + /** Returns the {@link AccountHelperImpl}. */ @Override - public PerformanceMonitor getPerformanceMonitor() { + public AccountHelper getAccountHelper() { + if (mAccountHelper == null) { + mAccountHelper = new AccountHelperImpl(getApplicationContext()); + } + return mAccountHelper; + } + + @Override + public synchronized PerformanceMonitor getPerformanceMonitor() { + if (mPerformanceMonitor == null) { + mPerformanceMonitor = PerformanceMonitorManagerFactory.create().initialize(this); + } return mPerformanceMonitor; } @Override + public Provider<EpgReader> providesEpgReader() { + return mEpgReaderProvider; + } + + @Override + public ExperimentLoader getExperimentLoader() { + mExperimentLoader = new ExperimentLoader(); + return mExperimentLoader; + } + + @Override public DefaultBackendKnobsFlags getBackendKnobs() { return mBackendKnobsFlags; } @@ -109,6 +148,16 @@ public class LiveTvApplication extends TvApplication implements HasSingletons<Tv } @Override + public BuildType getBuildType() { + return BuildType.AOSP; + } + + @Override + public DefaultConcurrentDvrPlaybackFlags getConcurrentDvrPlaybackFlags() { + return mConcurrentDvrPlaybackFlags; + } + + @Override public TvSingletons singletons() { return this; } diff --git a/src/com/android/tv/app/LiveTvApplicationComponent.java b/src/com/android/tv/app/LiveTvApplicationComponent.java index 71ce1a8a..3d3f0492 100644 --- a/src/com/android/tv/app/LiveTvApplicationComponent.java +++ b/src/com/android/tv/app/LiveTvApplicationComponent.java @@ -15,7 +15,6 @@ */ package com.android.tv.app; -import com.android.tv.search.LocalSearchProvider; import dagger.Component; import dagger.android.AndroidInjectionModule; import dagger.android.AndroidInjector; @@ -23,10 +22,5 @@ import javax.inject.Singleton; /** Dagger component for {@link LiveTvApplication}. */ @Singleton -@Component( - modules = { - AndroidInjectionModule.class, - LiveTvModule.class, - LocalSearchProvider.Module.class - }) +@Component(modules = {AndroidInjectionModule.class, LiveTvModule.class}) public interface LiveTvApplicationComponent extends AndroidInjector<LiveTvApplication> {} diff --git a/src/com/android/tv/app/LiveTvModule.java b/src/com/android/tv/app/LiveTvModule.java index db631bc0..a28749bd 100644 --- a/src/com/android/tv/app/LiveTvModule.java +++ b/src/com/android/tv/app/LiveTvModule.java @@ -16,49 +16,18 @@ package com.android.tv.app; import com.android.tv.common.flags.impl.DefaultFlagsModule; -import com.android.tv.data.epg.EpgReader; -import com.android.tv.data.epg.StubEpgReader; import com.android.tv.modules.TvApplicationModule; -import com.android.tv.perf.PerformanceMonitor; -import com.android.tv.perf.stub.StubPerformanceMonitor; import com.android.tv.tunerinputcontroller.BuiltInTunerManager; -import com.android.tv.ui.sidepanel.DeveloperOptionFragment; -import com.android.tv.util.account.AccountHelper; -import com.android.tv.util.account.AccountHelperImpl; import com.google.common.base.Optional; import dagger.Module; import dagger.Provides; -import javax.inject.Singleton; /** Dagger module for {@link LiveTvApplication}. */ @Module(includes = {DefaultFlagsModule.class, TvApplicationModule.class}) class LiveTvModule { @Provides - static AccountHelper providesAccountHelper(AccountHelperImpl impl) { - return impl; - } - - @Provides - static Optional<DeveloperOptionFragment.AdditionalDeveloperItemsFactory> - providesAdditionalDeveloperItemsFactory() { - return Optional.absent(); - } - - @Provides Optional<BuiltInTunerManager> providesBuiltInTunerManager() { return Optional.absent(); } - - @Provides - @Singleton - PerformanceMonitor providesPerformanceMonitor() { - return new StubPerformanceMonitor(); - } - - @Provides - @Singleton - static EpgReader providesEpgReader(StubEpgReader impl) { - return impl; - } } diff --git a/src/com/android/tv/data/BaseProgram.java b/src/com/android/tv/data/BaseProgram.java new file mode 100644 index 00000000..9650fd18 --- /dev/null +++ b/src/com/android/tv/data/BaseProgram.java @@ -0,0 +1,208 @@ +/* + * 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.data; + +import android.content.Context; +import android.media.tv.TvContentRating; +import android.support.annotation.Nullable; +import android.text.TextUtils; +import com.android.tv.R; +import com.google.common.collect.ImmutableList; +import java.util.Comparator; +import java.util.Objects; + +/** + * Base class for {@link com.android.tv.data.Program} and {@link + * com.android.tv.dvr.data.RecordedProgram}. + */ +public abstract class BaseProgram { + /** + * Comparator used to compare {@link BaseProgram} according to its season and episodes number. + * If a program's season or episode number is null, it will be consider "smaller" than programs + * with season or episode numbers. + */ + public static final Comparator<BaseProgram> EPISODE_COMPARATOR = new EpisodeComparator(false); + + /** + * Comparator used to compare {@link BaseProgram} according to its season and episodes number + * with season numbers in a reversed order. If a program's season or episode number is null, it + * will be consider "smaller" than programs with season or episode numbers. + */ + public static final Comparator<BaseProgram> SEASON_REVERSED_EPISODE_COMPARATOR = + new EpisodeComparator(true); + + public static final String COLUMN_SERIES_ID = "series_id"; + + public static final String COLUMN_STATE = "state"; + + private static class EpisodeComparator implements Comparator<BaseProgram> { + private final boolean mReversedSeason; + + EpisodeComparator(boolean reversedSeason) { + mReversedSeason = reversedSeason; + } + + @Override + public int compare(BaseProgram lhs, BaseProgram rhs) { + if (lhs == rhs) { + return 0; + } + int seasonNumberCompare = numberCompare(lhs.getSeasonNumber(), rhs.getSeasonNumber()); + if (seasonNumberCompare != 0) { + return mReversedSeason ? -seasonNumberCompare : seasonNumberCompare; + } else { + return numberCompare(lhs.getEpisodeNumber(), rhs.getEpisodeNumber()); + } + } + } + + /** Compares two strings represent season numbers or episode numbers of programs. */ + public static int numberCompare(String s1, String s2) { + if (Objects.equals(s1, s2)) { + return 0; + } else if (s1 == null) { + return -1; + } else if (s2 == null) { + return 1; + } else if (s1.equals(s2)) { + return 0; + } + try { + return Integer.compare(Integer.parseInt(s1), Integer.parseInt(s2)); + } catch (NumberFormatException e) { + return s1.compareTo(s2); + } + } + + /** Returns ID of the program. */ + public abstract long getId(); + + /** Returns the title of the program. */ + public abstract String getTitle(); + + /** Returns the episode title. */ + public abstract String getEpisodeTitle(); + + /** Returns the displayed title of the program episode. */ + @Nullable + public String getEpisodeDisplayTitle(Context context) { + String episodeNumber = getEpisodeNumber(); + String episodeTitle = getEpisodeTitle(); + if (!TextUtils.isEmpty(episodeNumber)) { + episodeTitle = episodeTitle == null ? "" : episodeTitle; + String seasonNumber = getSeasonNumber(); + if (TextUtils.isEmpty(seasonNumber) || TextUtils.equals(seasonNumber, "0")) { + // Do not show "S0: ". + return context.getResources() + .getString( + R.string.display_episode_title_format_no_season_number, + episodeNumber, + episodeTitle); + } else { + return context.getResources() + .getString( + R.string.display_episode_title_format, + seasonNumber, + episodeNumber, + episodeTitle); + } + } + return episodeTitle; + } + + /** + * Returns the content description of the program episode, suitable for being spoken by an + * accessibility service. + */ + public String getEpisodeContentDescription(Context context) { + String episodeNumber = getEpisodeNumber(); + String episodeTitle = getEpisodeTitle(); + if (!TextUtils.isEmpty(episodeNumber)) { + episodeTitle = episodeTitle == null ? "" : episodeTitle; + String seasonNumber = getSeasonNumber(); + if (TextUtils.isEmpty(seasonNumber) || TextUtils.equals(seasonNumber, "0")) { + // Do not list season if it is empty or 0 + return context.getResources() + .getString( + R.string.content_description_episode_format_no_season_number, + episodeNumber, + episodeTitle); + } else { + return context.getResources() + .getString( + R.string.content_description_episode_format, + seasonNumber, + episodeNumber, + episodeTitle); + } + } + return episodeTitle; + } + + /** Returns the description of the program. */ + public abstract String getDescription(); + + /** Returns the long description of the program. */ + public abstract String getLongDescription(); + + /** Returns the start time of the program in Milliseconds. */ + public abstract long getStartTimeUtcMillis(); + + /** Returns the end time of the program in Milliseconds. */ + public abstract long getEndTimeUtcMillis(); + + /** Returns the duration of the program in Milliseconds. */ + public abstract long getDurationMillis(); + + /** Returns the series ID. */ + @Nullable + public abstract String getSeriesId(); + + /** Returns the season number. */ + public abstract String getSeasonNumber(); + + /** Returns the episode number. */ + public abstract String getEpisodeNumber(); + + /** Returns URI of the program's poster. */ + public abstract String getPosterArtUri(); + + /** Returns URI of the program's thumbnail. */ + public abstract String getThumbnailUri(); + + /** Returns the array of the ID's of the canonical genres. */ + public abstract int[] getCanonicalGenreIds(); + + /** Returns the array of content ratings. */ + public abstract ImmutableList<TvContentRating> getContentRatings(); + + /** Returns channel's ID of the program. */ + public abstract long getChannelId(); + + /** Returns if the program is valid. */ + public abstract boolean isValid(); + + /** Checks whether the program is episodic or not. */ + public boolean isEpisodic() { + return getSeriesId() != null; + } + + /** Generates the series ID for the other inputs than the tuner TV input. */ + public static String generateSeriesId(String packageName, String title) { + return packageName + "/" + title; + } +} diff --git a/src/com/android/tv/data/BaseProgramImpl.java b/src/com/android/tv/data/BaseProgramImpl.java deleted file mode 100644 index 9c8d0256..00000000 --- a/src/com/android/tv/data/BaseProgramImpl.java +++ /dev/null @@ -1,86 +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.data; - -import android.content.Context; -import android.support.annotation.Nullable; -import android.text.TextUtils; - -import com.android.tv.R; -import com.android.tv.data.api.BaseProgram; - -/** Base class for {@link ProgramImpl} and {@link com.android.tv.dvr.data.RecordedProgram}. */ -public abstract class BaseProgramImpl implements BaseProgram { - - @Override - @Nullable - public String getEpisodeDisplayTitle(Context context) { - String episodeNumber = getEpisodeNumber(); - String episodeTitle = getEpisodeTitle(); - if (!TextUtils.isEmpty(episodeNumber)) { - episodeTitle = episodeTitle == null ? "" : episodeTitle; - String seasonNumber = getSeasonNumber(); - if (TextUtils.isEmpty(seasonNumber) || TextUtils.equals(seasonNumber, "0")) { - // Do not show "S0: ". - return context.getResources() - .getString( - R.string.display_episode_title_format_no_season_number, - episodeNumber, - episodeTitle); - } else { - return context.getResources() - .getString( - R.string.display_episode_title_format, - seasonNumber, - episodeNumber, - episodeTitle); - } - } - return episodeTitle; - } - - @Override - public String getEpisodeContentDescription(Context context) { - String episodeNumber = getEpisodeNumber(); - String episodeTitle = getEpisodeTitle(); - if (!TextUtils.isEmpty(episodeNumber)) { - episodeTitle = episodeTitle == null ? "" : episodeTitle; - String seasonNumber = getSeasonNumber(); - if (TextUtils.isEmpty(seasonNumber) || TextUtils.equals(seasonNumber, "0")) { - // Do not list season if it is empty or 0 - return context.getResources() - .getString( - R.string.content_description_episode_format_no_season_number, - episodeNumber, - episodeTitle); - } else { - return context.getResources() - .getString( - R.string.content_description_episode_format, - seasonNumber, - episodeNumber, - episodeTitle); - } - } - return episodeTitle; - } - - @Override - public boolean isEpisodic() { - return !TextUtils.isEmpty(getSeriesId()); - } -} diff --git a/src/com/android/tv/data/ChannelDataManager.java b/src/com/android/tv/data/ChannelDataManager.java index 67c32309..a5c786cf 100644 --- a/src/com/android/tv/data/ChannelDataManager.java +++ b/src/com/android/tv/data/ChannelDataManager.java @@ -37,18 +37,15 @@ import android.support.annotation.VisibleForTesting; import android.util.ArraySet; import android.util.Log; import android.util.MutableInt; +import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.WeakHandler; -import com.android.tv.common.dagger.annotations.ApplicationContext; import com.android.tv.common.util.PermissionUtils; import com.android.tv.common.util.SharedPreferencesUtils; import com.android.tv.data.api.Channel; import com.android.tv.util.AsyncDbTask; -import com.android.tv.util.AsyncDbTask.DbExecutor; import com.android.tv.util.TvInputManagerHelper; import com.android.tv.util.Utils; -import com.google.auto.factory.AutoFactory; -import com.google.auto.factory.Provided; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.Collections; @@ -59,7 +56,6 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.Executor; -import javax.inject.Singleton; /** * The class to manage channel data. Basic features: reading channel list and each channel's current @@ -68,8 +64,6 @@ import javax.inject.Singleton; * methods are called in only the main thread. */ @AnyThread -@AutoFactory -@Singleton public class ChannelDataManager { private static final String TAG = "ChannelDataManager"; private static final boolean DEBUG = false; @@ -149,11 +143,21 @@ public class ChannelDataManager { }; @MainThread - public ChannelDataManager( - @Provided @ApplicationContext Context context, - @Provided TvInputManagerHelper inputManager, - @Provided @DbExecutor Executor executor, - @Provided ContentResolver contentResolver) { + public ChannelDataManager(Context context, TvInputManagerHelper inputManager) { + this( + context, + inputManager, + TvSingletons.getSingletons(context).getDbExecutor(), + context.getContentResolver()); + } + + @MainThread + @VisibleForTesting + ChannelDataManager( + Context context, + TvInputManagerHelper inputManager, + Executor executor, + ContentResolver contentResolver) { mContext = context; mInputManager = inputManager; mDbExecutor = executor; @@ -725,7 +729,7 @@ public class ChannelDataManager { /** * Updates a column {@code columnName} of DB table {@code uri} with the value {@code * columnValue}. The selective rows in the ID list {@code ids} will be updated. The DB - * operations will run on @{@link DbExecutor}. + * operations will run on {@link TvSingletons#getDbExecutor()}. */ private void updateOneColumnValue( final String columnName, final int columnValue, final List<Long> ids) { diff --git a/src/com/android/tv/data/InternalDataUtils.java b/src/com/android/tv/data/InternalDataUtils.java index b17ed092..4c30d395 100644 --- a/src/com/android/tv/data/InternalDataUtils.java +++ b/src/com/android/tv/data/InternalDataUtils.java @@ -19,11 +19,8 @@ package com.android.tv.data; import android.support.annotation.Nullable; import android.text.TextUtils; import android.util.Log; - -import com.android.tv.data.api.Program; -import com.android.tv.data.api.Program.CriticScore; +import com.android.tv.data.Program.CriticScore; import com.android.tv.dvr.data.RecordedProgram; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -52,7 +49,7 @@ public final class InternalDataUtils { * @param bytes the bytes to be deserialized * @param builder the builder for the Program class */ - public static void deserializeInternalProviderData(byte[] bytes, ProgramImpl.Builder builder) { + public static void deserializeInternalProviderData(byte[] bytes, Program.Builder builder) { if (bytes == null || bytes.length == 0) { return; } diff --git a/src/com/android/tv/data/OnCurrentProgramUpdatedListener.java b/src/com/android/tv/data/OnCurrentProgramUpdatedListener.java index 2332cda4..edb33556 100644 --- a/src/com/android/tv/data/OnCurrentProgramUpdatedListener.java +++ b/src/com/android/tv/data/OnCurrentProgramUpdatedListener.java @@ -16,8 +16,6 @@ package com.android.tv.data; -import com.android.tv.data.api.Program; - public interface OnCurrentProgramUpdatedListener { /** Called when the current program is updated. */ void onCurrentProgramUpdated(long channelId, Program program); diff --git a/src/com/android/tv/data/PreviewDataManager.java b/src/com/android/tv/data/PreviewDataManager.java index dbe6028c..8616aeec 100644 --- a/src/com/android/tv/data/PreviewDataManager.java +++ b/src/com/android/tv/data/PreviewDataManager.java @@ -32,14 +32,10 @@ import android.support.annotation.IntDef; import android.support.annotation.MainThread; import android.util.Log; import android.util.Pair; - import androidx.tvprovider.media.tv.ChannelLogoUtils; import androidx.tvprovider.media.tv.PreviewProgram; - import com.android.tv.R; import com.android.tv.common.util.PermissionUtils; -import com.android.tv.util.images.ImageLoader; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.HashMap; @@ -222,7 +218,7 @@ public class PreviewDataManager { Uri previewChannelsUri = PreviewDataUtils.addQueryParamToUri( TvContract.Channels.CONTENT_URI, - Pair.create(PARAM_PREVIEW, String.valueOf(true))); + new Pair<>(PARAM_PREVIEW, String.valueOf(true))); String packageName = mContext.getPackageName(); if (PermissionUtils.hasAccessAllEpg(mContext)) { try (Cursor cursor = @@ -432,14 +428,10 @@ public class PreviewDataManager { continue; } try { - int aspectRatio = - ImageLoader.getAspectRatioFromPosterArtUri( - mContext, program.getPosterArtUri().toString()); Uri programUri = mContentResolver.insert( TvContract.PreviewPrograms.CONTENT_URI, - PreviewDataUtils.createPreviewProgramFromContent( - program, aspectRatio) + PreviewDataUtils.createPreviewProgramFromContent(program) .toContentValues()); if (programUri != null) { long previewProgramId = ContentUris.parseId(programUri); @@ -600,14 +592,13 @@ public class PreviewDataManager { /** Creates a preview program. */ public static PreviewProgram createPreviewProgramFromContent( - PreviewProgramContent program, int aspectRatio) { + PreviewProgramContent program) { PreviewProgram.Builder builder = new PreviewProgram.Builder(); builder.setChannelId(program.getPreviewChannelId()) .setType(program.getType()) .setLive(program.getLive()) .setTitle(program.getTitle()) .setDescription(program.getDescription()) - .setPosterArtAspectRatio(aspectRatio) .setPosterArtUri(program.getPosterArtUri()) .setIntentUri(program.getIntentUri()) .setPreviewVideoUri(program.getPreviewVideoUri()) diff --git a/src/com/android/tv/data/PreviewProgramContent.java b/src/com/android/tv/data/PreviewProgramContent.java index 4ee57104..8d4b88cf 100644 --- a/src/com/android/tv/data/PreviewProgramContent.java +++ b/src/com/android/tv/data/PreviewProgramContent.java @@ -21,14 +21,10 @@ import android.net.Uri; import android.support.annotation.VisibleForTesting; import android.text.TextUtils; import android.util.Pair; - import androidx.tvprovider.media.tv.TvContractCompat; - import com.android.tv.TvSingletons; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dvr.data.RecordedProgram; - import java.util.Objects; /** A class to store the content of preview programs. */ @@ -45,7 +41,7 @@ public class PreviewProgramContent { private Uri mIntentUri; private Uri mPreviewVideoUri; - /** Create preview program content from {@link ProgramImpl} */ + /** Create preview program content from {@link Program} */ public static PreviewProgramContent createFromProgram( Context context, long previewChannelId, Program program) { Channel channel = @@ -83,7 +79,7 @@ public class PreviewProgramContent { .setIntentUri(channel.getUri()) .setPreviewVideoUri( PreviewDataManager.PreviewDataUtils.addQueryParamToUri( - channel.getUri(), Pair.create(PARAM_INPUT, channel.getInputId()))) + channel.getUri(), new Pair<>(PARAM_INPUT, channel.getInputId()))) .build(); } @@ -103,7 +99,7 @@ public class PreviewProgramContent { .setPreviewVideoUri( PreviewDataManager.PreviewDataUtils.addQueryParamToUri( recordedProgramUri, - Pair.create(PARAM_INPUT, recordedProgram.getInputId()))) + new Pair<>(PARAM_INPUT, recordedProgram.getInputId()))) .build(); } diff --git a/src/com/android/tv/data/ProgramImpl.java b/src/com/android/tv/data/Program.java index 5097e2d4..b688927a 100644 --- a/src/com/android/tv/data/ProgramImpl.java +++ b/src/com/android/tv/data/Program.java @@ -32,26 +32,24 @@ import android.support.annotation.UiThread; import android.support.annotation.VisibleForTesting; import android.support.annotation.WorkerThread; import android.text.TextUtils; - +import android.util.Log; +import com.android.tv.common.BuildConfig; import com.android.tv.common.TvContentRatingCache; import com.android.tv.common.util.CollectionUtils; import com.android.tv.common.util.CommonUtils; -import com.android.tv.data.api.BaseProgram; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.util.TvProviderUtils; import com.android.tv.util.Utils; import com.android.tv.util.images.ImageLoader; - import com.google.common.collect.ImmutableList; - +import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; /** A convenience class to create and insert program information entries into the database. */ -public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Program { +public final class Program extends BaseProgram implements Comparable<Program>, Parcelable { private static final boolean DEBUG = false; private static final boolean DEBUG_DUMP_DESCRIPTION = false; private static final String TAG = "Program"; @@ -181,8 +179,8 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr return builder.build(); } - public static ProgramImpl fromParcel(Parcel in) { - ProgramImpl program = new ProgramImpl(); + public static Program fromParcel(Parcel in) { + Program program = new Program(); program.mId = in.readLong(); program.mPackageName = in.readString(); program.mChannelId = in.readLong(); @@ -221,7 +219,7 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr new Parcelable.Creator<Program>() { @Override public Program createFromParcel(Parcel in) { - return ProgramImpl.fromParcel(in); + return Program.fromParcel(in); } @Override @@ -253,21 +251,19 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr private ImmutableList<TvContentRating> mContentRatings; private boolean mRecordingProhibited; - private ProgramImpl() { + private Program() { // Do nothing. } - @Override public long getId() { return mId; } - @Override + /** Returns the package name of this program. */ public String getPackageName() { return mPackageName; } - @Override public long getChannelId() { return mChannelId; } @@ -278,6 +274,11 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr return mChannelId >= 0; } + /** Returns {@code true} if the program is valid and {@code false} otherwise. */ + public static boolean isProgramValid(Program program) { + return program != null && program.isValid(); + } + @Override public String getTitle() { return mTitle; @@ -301,11 +302,6 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr } @Override - public String getSeasonTitle() { - return mSeasonTitle; - } - - @Override public String getEpisodeNumber() { return mEpisodeNumber; } @@ -320,7 +316,6 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr return mEndTimeUtcMillis; } - @Override public String getDurationString(Context context) { // TODO(b/71717446): expire the calculated string if (mDurationString == null) { @@ -346,17 +341,15 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr return mLongDescription; } - @Override public int getVideoWidth() { return mVideoWidth; } - @Override public int getVideoHeight() { return mVideoHeight; } - @Override + /** Returns the list of Critic Scores for this program */ @Nullable public List<CriticScore> getCriticScores() { return mCriticScores; @@ -378,12 +371,12 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr return mThumbnailUri; } - @Override + /** Returns {@code true} if the recording of this program is prohibited. */ public boolean isRecordingProhibited() { return mRecordingProhibited; } - @Override + /** Returns array of canonical genres for this program. This is expected to be called rarely. */ @Nullable public String[] getCanonicalGenres() { if (mCanonicalGenreIds == null) { @@ -402,7 +395,7 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr return mCanonicalGenreIds; } - @Override + /** Returns if this program has the genre. */ public boolean hasGenre(int genreId) { if (genreId == GenreItems.ID_ALL_CHANNELS) { return true; @@ -443,11 +436,11 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr @Override public boolean equals(Object other) { - if (!(other instanceof ProgramImpl)) { + if (!(other instanceof Program)) { return false; } // Compare all the properties because program ID can be invalid for the dummy programs. - ProgramImpl program = (ProgramImpl) other; + Program program = (Program) other; return Objects.equals(mPackageName, program.mPackageName) && mChannelId == program.mChannelId && mStartTimeUtcMillis == program.mStartTimeUtcMillis @@ -471,7 +464,7 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr @Override public int compareTo(@NonNull Program other) { - return Long.compare(mStartTimeUtcMillis, other.getStartTimeUtcMillis()); + return Long.compare(mStartTimeUtcMillis, other.mStartTimeUtcMillis); } @Override @@ -523,7 +516,7 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr } /** - * Translates a {@link ProgramImpl} to {@link ContentValues} that are ready to be written into + * Translates a {@link Program} to {@link ContentValues} that are ready to be written into * Database. */ @SuppressLint("InlinedApi") @@ -602,37 +595,37 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr return; } - mId = other.getId(); - mPackageName = other.getPackageName(); - mChannelId = other.getChannelId(); - mTitle = other.getTitle(); - mSeriesId = other.getSeriesId(); - mEpisodeTitle = other.getEpisodeTitle(); - mSeasonNumber = other.getSeasonNumber(); - mSeasonTitle = other.getSeasonTitle(); - mEpisodeNumber = other.getEpisodeNumber(); - mStartTimeUtcMillis = other.getStartTimeUtcMillis(); - mEndTimeUtcMillis = other.getEndTimeUtcMillis(); + mId = other.mId; + mPackageName = other.mPackageName; + mChannelId = other.mChannelId; + mTitle = other.mTitle; + mSeriesId = other.mSeriesId; + mEpisodeTitle = other.mEpisodeTitle; + mSeasonNumber = other.mSeasonNumber; + mSeasonTitle = other.mSeasonTitle; + mEpisodeNumber = other.mEpisodeNumber; + mStartTimeUtcMillis = other.mStartTimeUtcMillis; + mEndTimeUtcMillis = other.mEndTimeUtcMillis; mDurationString = null; // Recreate Duration when needed. - mDescription = other.getDescription(); - mLongDescription = other.getLongDescription(); - mVideoWidth = other.getVideoWidth(); - mVideoHeight = other.getVideoHeight(); - mCriticScores = other.getCriticScores(); - mPosterArtUri = other.getPosterArtUri(); - mThumbnailUri = other.getThumbnailUri(); - mCanonicalGenreIds = other.getCanonicalGenreIds(); - mContentRatings = other.getContentRatings(); - mRecordingProhibited = other.isRecordingProhibited(); + mDescription = other.mDescription; + mLongDescription = other.mLongDescription; + mVideoWidth = other.mVideoWidth; + mVideoHeight = other.mVideoHeight; + mCriticScores = other.mCriticScores; + mPosterArtUri = other.mPosterArtUri; + mThumbnailUri = other.mThumbnailUri; + mCanonicalGenreIds = other.mCanonicalGenreIds; + mContentRatings = other.mContentRatings; + mRecordingProhibited = other.mRecordingProhibited; } /** A Builder for the Program class */ public static final class Builder { - private final ProgramImpl mProgram; + private final Program mProgram; /** Creates a Builder for this Program class */ public Builder() { - mProgram = new ProgramImpl(); + mProgram = new Program(); // Fill initial data. mProgram.mPackageName = null; mProgram.mChannelId = Channel.INVALID_ID; @@ -657,7 +650,7 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr */ @VisibleForTesting public Builder(Program other) { - mProgram = new ProgramImpl(); + mProgram = new Program(); mProgram.copyFrom(other); } @@ -913,7 +906,7 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr * * @return the Program object constructed */ - public ProgramImpl build() { + public Program build() { // Generate the series ID for the episodic program of other TV input. if (TextUtils.isEmpty(mProgram.mTitle)) { // If title is null, series cannot be generated for this program. @@ -923,13 +916,17 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr // If series ID is not set, generate it for the episodic program of other TV input. setSeriesId(BaseProgram.generateSeriesId(mProgram.mPackageName, mProgram.mTitle)); } - ProgramImpl program = new ProgramImpl(); + Program program = new Program(); program.copyFrom(mProgram); return program; } } - @Override + /** + * Prefetches the program poster art. + * + * <p> + */ public void prefetchPosterArt(Context context, int posterArtWidth, int posterArtHeight) { if (mPosterArtUri == null) { return; @@ -937,13 +934,20 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr ImageLoader.prefetchBitmap(context, mPosterArtUri, posterArtWidth, posterArtHeight); } - @Override + /** + * Loads the program poster art and returns it via {@code callback}. + * + * <p>Note that it may directly call {@code callback} if the program poster art already is + * loaded. + * + * @return {@code true} if the load is complete and the callback is executed. + */ @UiThread public boolean loadPosterArt( Context context, int posterArtWidth, int posterArtHeight, - ImageLoader.ImageLoaderCallback<?> callback) { + ImageLoader.ImageLoaderCallback callback) { if (mPosterArtUri == null) { return false; } @@ -951,9 +955,24 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr context, mPosterArtUri, posterArtWidth, posterArtHeight, callback); } - @Override - public Parcelable toParcelable() { - return this; + public static boolean isDuplicate(Program p1, Program p2) { + if (p1 == null || p2 == null) { + return false; + } + boolean isDuplicate = + p1.getChannelId() == p2.getChannelId() + && p1.getStartTimeUtcMillis() == p2.getStartTimeUtcMillis() + && p1.getEndTimeUtcMillis() == p2.getEndTimeUtcMillis(); + if (DEBUG && BuildConfig.ENG && isDuplicate) { + Log.w( + TAG, + "Duplicate programs detected! - \"" + + p1.getTitle() + + "\" and \"" + + p2.getTitle() + + "\""); + } + return isDuplicate; } @Override @@ -990,4 +1009,54 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr } out.writeByte((byte) (mRecordingProhibited ? 1 : 0)); } + + /** Holds one type of critic score and its source. */ + public static final class CriticScore implements Serializable, Parcelable { + /** The source of the rating. */ + public final String source; + /** The score. */ + public final String score; + /** The url of the logo image */ + public final String logoUrl; + + public static final Parcelable.Creator<CriticScore> CREATOR = + new Parcelable.Creator<CriticScore>() { + @Override + public CriticScore createFromParcel(Parcel in) { + String source = in.readString(); + String score = in.readString(); + String logoUri = in.readString(); + return new CriticScore(source, score, logoUri); + } + + @Override + public CriticScore[] newArray(int size) { + return new CriticScore[size]; + } + }; + + /** + * Constructor for this class. + * + * @param source the source of the rating + * @param score the score + */ + public CriticScore(String source, String score, String logoUrl) { + this.source = source; + this.score = score; + this.logoUrl = logoUrl; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int i) { + out.writeString(source); + out.writeString(score); + out.writeString(logoUrl); + } + } } diff --git a/src/com/android/tv/data/ProgramDataManager.java b/src/com/android/tv/data/ProgramDataManager.java index a866c78e..2f20c89a 100644 --- a/src/com/android/tv/data/ProgramDataManager.java +++ b/src/com/android/tv/data/ProgramDataManager.java @@ -33,24 +33,19 @@ import android.util.ArraySet; import android.util.Log; import android.util.LongSparseArray; import android.util.LruCache; - import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.memory.MemoryManageable; import com.android.tv.common.util.Clock; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.perf.EventNames; import com.android.tv.perf.PerformanceMonitor; import com.android.tv.perf.TimerEvent; import com.android.tv.util.AsyncDbTask; import com.android.tv.util.MultiLongSparseArray; -import com.android.tv.util.TvInputManagerHelper; import com.android.tv.util.TvProviderUtils; import com.android.tv.util.Utils; - import com.android.tv.common.flags.BackendKnobsFlags; - import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -80,11 +75,6 @@ public class ProgramDataManager implements MemoryManageable { private static final long CURRENT_PROGRAM_UPDATE_WAIT_MS = TimeUnit.SECONDS.toMillis(5); @VisibleForTesting static final long PROGRAM_GUIDE_SNAP_TIME_MS = TimeUnit.MINUTES.toMillis(30); - // Default fetch hours - private static final long FETCH_HOURS_MS = TimeUnit.HOURS.toMillis(24); - // Load data earlier for smooth scrolling. - private static final long BUFFER_HOURS_MS = TimeUnit.HOURS.toMillis(6); - // TODO: Use TvContract constants, once they become public. private static final String PARAM_START_TIME = "start_time"; private static final String PARAM_END_TIME = "end_time"; @@ -96,20 +86,10 @@ public class ProgramDataManager implements MemoryManageable { + Programs.COLUMN_CHANNEL_ID + ", " + Programs.COLUMN_END_TIME_UTC_MILLIS; - private static final String SORT_BY_CHANNEL_ID = - Programs.COLUMN_CHANNEL_ID - + ", " - + Programs.COLUMN_START_TIME_UTC_MILLIS - + " DESC, " - + Programs.COLUMN_END_TIME_UTC_MILLIS - + " ASC, " - + Programs._ID - + " DESC"; private static final int MSG_UPDATE_CURRENT_PROGRAMS = 1000; private static final int MSG_UPDATE_ONE_CURRENT_PROGRAM = 1001; private static final int MSG_UPDATE_PREFETCH_PROGRAM = 1002; - private static final int MSG_UPDATE_CONTENT_RATINGS = 1003; private final Context mContext; private final Clock mClock; @@ -118,7 +98,6 @@ public class ProgramDataManager implements MemoryManageable { private final BackendKnobsFlags mBackendKnobsFlags; private final PerformanceMonitor mPerformanceMonitor; private final ChannelDataManager mChannelDataManager; - private final TvInputManagerHelper mTvInputManagerHelper; private boolean mStarted; // Updated only on the main thread. private volatile boolean mCurrentProgramsLoadFinished; @@ -146,11 +125,6 @@ public class ProgramDataManager implements MemoryManageable { private boolean mPauseProgramUpdate = false; private final LruCache<Long, Program> mZeroLengthProgramCache = new LruCache<>(10); - // Current tuned channel. - private long mTunedChannelId; - // Hours of data to be fetched, it is updated during horizontal scroll. - // Note that it should never exceed programGuideMaxHours. - private long mMaxFetchHoursMs = FETCH_HOURS_MS; @MainThread public ProgramDataManager(Context context) { @@ -162,8 +136,7 @@ public class ProgramDataManager implements MemoryManageable { Looper.myLooper(), TvSingletons.getSingletons(context).getBackendKnobs(), TvSingletons.getSingletons(context).getPerformanceMonitor(), - TvSingletons.getSingletons(context).getChannelDataManager(), - TvSingletons.getSingletons(context).getTvInputManagerHelper()); + TvSingletons.getSingletons(context).getChannelDataManager()); } @VisibleForTesting @@ -175,8 +148,7 @@ public class ProgramDataManager implements MemoryManageable { Looper looper, BackendKnobsFlags backendKnobsFlags, PerformanceMonitor performanceMonitor, - ChannelDataManager channelDataManager, - TvInputManagerHelper tvInputManagerHelper) { + ChannelDataManager channelDataManager) { mContext = context; mDbExecutor = executor; mClock = time; @@ -185,7 +157,6 @@ public class ProgramDataManager implements MemoryManageable { mBackendKnobsFlags = backendKnobsFlags; mPerformanceMonitor = performanceMonitor; mChannelDataManager = channelDataManager; - mTvInputManagerHelper = tvInputManagerHelper; mProgramObserver = new ContentObserver(mHandler) { @Override @@ -234,7 +205,6 @@ public class ProgramDataManager implements MemoryManageable { // Should be called directly instead of posting MSG_UPDATE_CURRENT_PROGRAMS message // to the handler. If not, another DB task can be executed before loading current programs. handleUpdateCurrentPrograms(); - mHandler.sendEmptyMessage(MSG_UPDATE_CONTENT_RATINGS); if (mPrefetchEnabled) { mHandler.sendEmptyMessage(MSG_UPDATE_PREFETCH_PROGRAM); } @@ -289,67 +259,15 @@ public class ProgramDataManager implements MemoryManageable { } } - /** - * Prefetch program data if needed. - * - * @param channelId ID of the channel to prefetch - * @param selectedProgramIndex index of selected program. - */ - public void prefetchChannel(long channelId, int selectedProgramIndex) { - long startTimeMs = - Utils.floorTime( - mClock.currentTimeMillis() - PROGRAM_GUIDE_SNAP_TIME_MS, - PROGRAM_GUIDE_SNAP_TIME_MS); - long programGuideMaxHoursMs = - TimeUnit.HOURS.toMillis(mBackendKnobsFlags.programGuideMaxHours()); - long endTimeMs = 0; - if (mMaxFetchHoursMs < programGuideMaxHoursMs - && isHorizontalLoadNeeded(startTimeMs, channelId, selectedProgramIndex)) { - // Horizontal scrolling needs to load data of further days. - mMaxFetchHoursMs = Math.min(programGuideMaxHoursMs, mMaxFetchHoursMs + FETCH_HOURS_MS); - mCompleteInfoChannelIds.clear(); - } - // Load max hours complete data for first channel. - if (mCompleteInfoChannelIds.isEmpty()) { - endTimeMs = startTimeMs + programGuideMaxHoursMs; - } else if (!mCompleteInfoChannelIds.contains(channelId)) { - endTimeMs = startTimeMs + mMaxFetchHoursMs; - } - if (endTimeMs > 0) { - mCompleteInfoChannelIds.add(channelId); - new SingleChannelPrefetchTask(channelId, startTimeMs, endTimeMs).executeOnDbThread(); - } - } - public void prefetchChannel(long channelId) { - prefetchChannel(channelId, 0); - } - - /** - * Check if enough data is present for horizontal scroll, otherwise prefetch programs. - * - * <p>If end time of current program is past {@code BUFFER_HOURS_MS} less than the fetched time - * we need to prefetch proceeding programs. - * - * @param startTimeMs Fetch start time, it is used to get fetch end time. - * @param channelId - * @param selectedProgramIndex - * @return {@code true} If data load is needed, else {@code false}. - */ - private boolean isHorizontalLoadNeeded( - long startTimeMs, long channelId, int selectedProgramIndex) { - if (mChannelIdProgramCache.containsKey(channelId)) { - ArrayList<Program> programs = mChannelIdProgramCache.get(channelId); - long marginEndTime = startTimeMs + mMaxFetchHoursMs - BUFFER_HOURS_MS; - return programs.size() > selectedProgramIndex && - programs.get(selectedProgramIndex).getEndTimeUtcMillis() > marginEndTime; + if (mCompleteInfoChannelIds.add(channelId)) { + long startTimeMs = + Utils.floorTime( + mClock.currentTimeMillis() - PROGRAM_GUIDE_SNAP_TIME_MS, + PROGRAM_GUIDE_SNAP_TIME_MS); + long endTimeMs = startTimeMs + TimeUnit.HOURS.toMillis(getFetchDuration()); + new SingleChannelPrefetchTask(channelId, startTimeMs, endTimeMs).executeOnDbThread(); } - return false; - } - - public void onChannelTuned(long channelId) { - mTunedChannelId = channelId; - prefetchChannel(channelId); } /** A Callback interface to receive notification on program data retrieval from DB. */ @@ -362,10 +280,12 @@ public class ProgramDataManager implements MemoryManageable { void onProgramUpdated(); /** - * Called when we update program data during scrolling. Data is loaded from DB on request - * basis. It loads data based on horizontal scrolling as well. + * Called when we update complete program data of specific channel during scrolling. Data is + * loaded from DB on request basis. + * + * @param channelId */ - void onChannelUpdated(); + void onSingleChannelUpdated(long channelId); } /** Adds the {@link Callback}. */ @@ -392,7 +312,7 @@ public class ProgramDataManager implements MemoryManageable { } else { mPrefetchEnabled = false; cancelPrefetchTask(); - clearChannelInfoMap(); + mChannelIdProgramCache.clear(); mHandler.removeMessages(MSG_UPDATE_PREFETCH_PROGRAM); } } @@ -619,7 +539,10 @@ public class ProgramDataManager implements MemoryManageable { } programMap.clear(); - String[] projection = ProgramImpl.PARTIAL_PROJECTION; + String[] projection = + mBackendKnobsFlags.enablePartialProgramFetch() + ? Program.PARTIAL_PROJECTION + : Program.PROJECTION; if (TvProviderUtils.checkSeriesIdColumn(mContext, Programs.CONTENT_URI)) { if (Utils.isProgramsUri(uri)) { projection = @@ -639,7 +562,10 @@ public class ProgramDataManager implements MemoryManageable { } return null; } - Program program = ProgramImpl.fromCursorPartialProjection(c); + Program program = + mBackendKnobsFlags.enablePartialProgramFetch() + ? Program.fromCursorPartialProjection(c) + : Program.fromCursor(c); if (Program.isDuplicate(program, lastReadProgram)) { duplicateCount++; continue; @@ -649,14 +575,15 @@ public class ProgramDataManager implements MemoryManageable { ArrayList<Program> programs = programMap.get(program.getChannelId()); if (programs == null) { programs = new ArrayList<>(); - // To skip already loaded complete data. - Program currentProgramInfo = - mChannelIdCurrentProgramMap.get(program.getChannelId()); - if (currentProgramInfo != null - && Program.isDuplicate(program, currentProgramInfo)) { - program = currentProgramInfo; + if (mBackendKnobsFlags.enablePartialProgramFetch()) { + // To skip already loaded complete data. + Program currentProgramInfo = + mChannelIdCurrentProgramMap.get(program.getChannelId()); + if (currentProgramInfo != null + && Program.isDuplicate(program, currentProgramInfo)) { + program = currentProgramInfo; + } } - programMap.put(program.getChannelId(), programs); } programs.add(program); @@ -701,12 +628,15 @@ public class ProgramDataManager implements MemoryManageable { mLastPrefetchTaskRunMs + PROGRAM_GUIDE_SNAP_TIME_MS, PROGRAM_GUIDE_SNAP_TIME_MS) - currentTime; + // Issue second pre-fetch immediately after the first partial update + if (mChannelIdProgramCache.isEmpty()) { + nextMessageDelayedTime = 0; + } mChannelIdProgramCache = programs; - // Since cache has partial data we need to reset the map of complete data. - clearChannelInfoMap(); - // Get complete projection of tuned channel. - prefetchChannel(mTunedChannelId); - + if (mBackendKnobsFlags.enablePartialProgramFetch()) { + // Since cache has partial data we need to reset the map of complete data. + mCompleteInfoChannelIds.clear(); + } notifyProgramUpdated(); if (mFromEmptyCacheTimeEvent != null) { mPerformanceMonitor.stopTimer( @@ -724,11 +654,6 @@ public class ProgramDataManager implements MemoryManageable { } } - private void clearChannelInfoMap() { - mCompleteInfoChannelIds.clear(); - mMaxFetchHoursMs = FETCH_HOURS_MS; - } - private long getFetchDuration() { if (mChannelIdProgramCache.isEmpty()) { return Math.max(1L, mBackendKnobsFlags.programGuideInitialFetchHours()); @@ -760,7 +685,7 @@ public class ProgramDataManager implements MemoryManageable { mDbExecutor, mContext, TvContract.buildProgramsUriForChannel(channelId, startTimeMs, endTimeMs), - ProgramImpl.PROJECTION, + Program.PROJECTION, null, null, SORT_BY_TIME); @@ -771,7 +696,7 @@ public class ProgramDataManager implements MemoryManageable { protected ArrayList<Program> onQuery(Cursor c) { ArrayList<Program> programMap = new ArrayList<>(); while (c.moveToNext()) { - Program program = ProgramImpl.fromCursor(c); + Program program = Program.fromCursor(c); programMap.add(program); } return programMap; @@ -780,7 +705,7 @@ public class ProgramDataManager implements MemoryManageable { @Override protected void onPostExecute(ArrayList<Program> programs) { mChannelIdProgramCache.put(mChannelId, programs); - notifyChannelUpdated(); + notifySingleChannelUpdated(mChannelId); } } @@ -790,9 +715,9 @@ public class ProgramDataManager implements MemoryManageable { } } - private void notifyChannelUpdated() { + private void notifySingleChannelUpdated(long channelId) { for (Callback callback : mCallbacks) { - callback.onChannelUpdated(); + callback.onSingleChannelUpdated(channelId); } } @@ -806,10 +731,10 @@ public class ProgramDataManager implements MemoryManageable { .appendQueryParameter(PARAM_START_TIME, String.valueOf(time)) .appendQueryParameter(PARAM_END_TIME, String.valueOf(time)) .build(), - ProgramImpl.PROJECTION, + Program.PROJECTION, null, null, - SORT_BY_CHANNEL_ID); + SORT_BY_TIME); } @Override @@ -822,21 +747,17 @@ public class ProgramDataManager implements MemoryManageable { if (isCancelled()) { return programs; } - Program program = ProgramImpl.fromCursor(c); - // Only one program is expected per channel for this query - // However, skip overlapping programs from same channel - if (Program.sameChannel(program, lastReadProgram) - && Program.isOverlapping(program, lastReadProgram)) { + Program program = Program.fromCursor(c); + if (Program.isDuplicate(program, lastReadProgram)) { duplicateCount++; continue; } else { lastReadProgram = program; } - programs.add(program); } if (duplicateCount > 0) { - Log.w(TAG, "Found " + duplicateCount + " overlapping programs"); + Log.w(TAG, "Found " + duplicateCount + " duplicate programs"); } } return programs; @@ -856,7 +777,9 @@ public class ProgramDataManager implements MemoryManageable { for (Long channelId : removedChannelIds) { if (mPrefetchEnabled) { mChannelIdProgramCache.remove(channelId); - mCompleteInfoChannelIds.remove(channelId); + if (mBackendKnobsFlags.enablePartialProgramFetch()) { + mCompleteInfoChannelIds.remove(channelId); + } } mChannelIdCurrentProgramMap.remove(channelId); notifyCurrentProgramUpdate(channelId, null); @@ -874,7 +797,7 @@ public class ProgramDataManager implements MemoryManageable { mDbExecutor, mContext, TvContract.buildProgramsUriForChannel(channelId, time, time), - ProgramImpl.PROJECTION, + Program.PROJECTION, null, null, SORT_BY_TIME); @@ -885,7 +808,7 @@ public class ProgramDataManager implements MemoryManageable { public Program onQuery(Cursor c) { Program program = null; if (c != null && c.moveToNext()) { - program = ProgramImpl.fromCursor(c); + program = Program.fromCursor(c); } return program; } @@ -946,9 +869,6 @@ public class ProgramDataManager implements MemoryManageable { } break; } - case MSG_UPDATE_CONTENT_RATINGS: - mTvInputManagerHelper.getContentRatingsManager().update(); - break; default: // Do nothing } @@ -1012,7 +932,7 @@ public class ProgramDataManager implements MemoryManageable { // Create dummy program which indicates data isn't loaded yet so DB query is required. private Program createDummyProgram(long startTimeMs, long endTimeMs) { - return new ProgramImpl.Builder() + return new Program.Builder() .setChannelId(Channel.INVALID_ID) .setStartTimeUtcMillis(startTimeMs) .setEndTimeUtcMillis(endTimeMs) diff --git a/src/com/android/tv/data/api/BaseProgram.java b/src/com/android/tv/data/api/BaseProgram.java deleted file mode 100644 index 8acaf79e..00000000 --- a/src/com/android/tv/data/api/BaseProgram.java +++ /dev/null @@ -1,141 +0,0 @@ -package com.android.tv.data.api; - -import android.content.Context; -import android.media.tv.TvContentRating; -import android.support.annotation.Nullable; -import com.google.common.collect.ImmutableList; -import java.util.Comparator; -import java.util.Objects; - -/** - * Base class for {@link com.android.tv.data.Program} and {@link - * com.android.tv.dvr.data.RecordedProgram}. - */ -public interface BaseProgram { - - /** - * Comparator used to compare {@link BaseProgram} according to its season and episodes number. - * If a program's season or episode number is null, it will be consider "smaller" than programs - * with season or episode numbers. - */ - Comparator<BaseProgram> EPISODE_COMPARATOR = new EpisodeComparator(false); - /** - * Comparator used to compare {@link BaseProgram} according to its season and episodes number - * with season numbers in a reversed order. If a program's season or episode number is null, it - * will be consider "smaller" than programs with season or episode numbers. - */ - Comparator<BaseProgram> SEASON_REVERSED_EPISODE_COMPARATOR = new EpisodeComparator(true); - - String COLUMN_SERIES_ID = "series_id"; - String COLUMN_STATE = "state"; - - /** Compares two strings represent season numbers or episode numbers of programs. */ - static int numberCompare(String s1, String s2) { - if (Objects.equals(s1, s2)) { - return 0; - } else if (s1 == null) { - return -1; - } else if (s2 == null) { - return 1; - } else if (s1.equals(s2)) { - return 0; - } - try { - return Integer.compare(Integer.parseInt(s1), Integer.parseInt(s2)); - } catch (NumberFormatException e) { - return s1.compareTo(s2); - } - } - - /** Generates the series ID for the other inputs than the tuner TV input. */ - static String generateSeriesId(String packageName, String title) { - return packageName + "/" + title; - } - - /** Returns ID of the program. */ - long getId(); - - /** Returns the title of the program. */ - String getTitle(); - - /** Returns the episode title. */ - String getEpisodeTitle(); - - /** Returns the displayed title of the program episode. */ - @Nullable - String getEpisodeDisplayTitle(Context context); - - /** - * Returns the content description of the program episode, suitable for being spoken by an - * accessibility service. - */ - String getEpisodeContentDescription(Context context); - - /** Returns the description of the program. */ - String getDescription(); - - /** Returns the long description of the program. */ - String getLongDescription(); - - /** Returns the start time of the program in Milliseconds. */ - long getStartTimeUtcMillis(); - - /** Returns the end time of the program in Milliseconds. */ - long getEndTimeUtcMillis(); - - /** Returns the duration of the program in Milliseconds. */ - long getDurationMillis(); - - /** Returns the series ID. */ - @Nullable - String getSeriesId(); - - /** Returns the season number. */ - String getSeasonNumber(); - - /** Returns the episode number. */ - String getEpisodeNumber(); - - /** Returns URI of the program's poster. */ - String getPosterArtUri(); - - /** Returns URI of the program's thumbnail. */ - String getThumbnailUri(); - - /** Returns the array of the ID's of the canonical genres. */ - int[] getCanonicalGenreIds(); - - /** Returns the array of content ratings. */ - ImmutableList<TvContentRating> getContentRatings(); - - /** Returns channel's ID of the program. */ - long getChannelId(); - - /** Returns if the program is valid. */ - boolean isValid(); - - /** Checks whether the program is episodic or not. */ - boolean isEpisodic(); - - /** Generates the series ID for the other inputs than the tuner TV input. */ - class EpisodeComparator implements Comparator<BaseProgram> { - private final boolean mReversedSeason; - - EpisodeComparator(boolean reversedSeason) { - mReversedSeason = reversedSeason; - } - - @Override - public int compare(BaseProgram lhs, BaseProgram rhs) { - if (lhs == rhs) { - return 0; - } - int seasonNumberCompare = numberCompare(lhs.getSeasonNumber(), rhs.getSeasonNumber()); - if (seasonNumberCompare != 0) { - return mReversedSeason ? -seasonNumberCompare : seasonNumberCompare; - } else { - return numberCompare(lhs.getEpisodeNumber(), rhs.getEpisodeNumber()); - } - } - } -} diff --git a/src/com/android/tv/data/api/Program.java b/src/com/android/tv/data/api/Program.java deleted file mode 100644 index f2221f6e..00000000 --- a/src/com/android/tv/data/api/Program.java +++ /dev/null @@ -1,141 +0,0 @@ -package com.android.tv.data.api; - -import android.content.Context; -import android.os.Parcel; -import android.os.Parcelable; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; - -import com.android.tv.util.images.ImageLoader; - -import java.io.Serializable; -import java.util.List; - -/** A convenience interface to create and insert program information entries into the database. */ -public interface Program extends BaseProgram, Comparable<Program> { - - /** Returns {@code true} if the program is valid and {@code false} otherwise. */ - static boolean isProgramValid(Program program) { - return program != null && program.isValid(); - } - - static boolean isDuplicate(Program p1, Program p2) { - if (p1 == null || p2 == null) { - return false; - } - return p1.getChannelId() == p2.getChannelId() - && p1.getStartTimeUtcMillis() == p2.getStartTimeUtcMillis() - && p1.getEndTimeUtcMillis() == p2.getEndTimeUtcMillis(); - } - - /** True if the start or end times overlap. */ - static boolean isOverlapping(@Nullable Program p1, @Nullable Program p2) { - return p1 != null - && p2 != null - && p1.getStartTimeUtcMillis() < p2.getEndTimeUtcMillis() - && p1.getEndTimeUtcMillis() > p2.getStartTimeUtcMillis(); - } - - /** True if the channels IDs are the same. */ - static boolean sameChannel(@Nullable Program p1, @Nullable Program p2) { - return p1 != null && p2 != null && p1.getChannelId() == p2.getChannelId(); - } - - /** Returns the package name of this program. */ - String getPackageName(); - - /** Returns the season title */ - String getSeasonTitle(); - - /** Gets the localized duration of the program */ - String getDurationString(Context context); - - int getVideoWidth(); - - int getVideoHeight(); - - /** Returns the list of Critic Scores for this program */ - @Nullable - List<CriticScore> getCriticScores(); - - /** Returns {@code true} if the recording of this program is prohibited. */ - boolean isRecordingProhibited(); - - /** Returns array of canonical genres for this program. This is expected to be called rarely. */ - @Nullable - String[] getCanonicalGenres(); - - /** Returns if this program has the genre. */ - boolean hasGenre(int genreId); - - /** Prefetch the program poster art. */ - void prefetchPosterArt(Context context, int posterArtWidth, int posterArtHeight); - - /** - * Loads the program poster art and returns it via {@code callback}. - * - * <p>Note that it may directly call {@code callback} if the program poster art already is - * loaded. - * - * @return {@code true} if the load is complete and the callback is executed. - */ - @UiThread - boolean loadPosterArt( - Context context, - int posterArtWidth, - int posterArtHeight, - ImageLoader.ImageLoaderCallback<?> callback); - - /** Returns a {@link Parcelable} representation of this instance. */ - Parcelable toParcelable(); - - /** Holds one type of critic score and its source. */ - final class CriticScore implements Serializable, Parcelable { - /** The source of the rating. */ - public final String source; - /** The score. */ - public final String score; - /** The url of the logo image */ - public final String logoUrl; - - public static final Creator<CriticScore> CREATOR = - new Creator<CriticScore>() { - @Override - public CriticScore createFromParcel(Parcel in) { - String source = in.readString(); - String score = in.readString(); - String logoUri = in.readString(); - return new CriticScore(source, score, logoUri); - } - - @Override - public CriticScore[] newArray(int size) { - return new CriticScore[size]; - } - }; - - /** - * Constructor for this class. - * - * @param source the source of the rating - * @param score the score - */ - public CriticScore(String source, String score, String logoUrl) { - this.source = source; - this.score = score; - this.logoUrl = logoUrl; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int i) { - out.writeString(source); - out.writeString(score); - out.writeString(logoUrl); - } - } -} diff --git a/src/com/android/tv/data/epg/EpgFetchHelper.java b/src/com/android/tv/data/epg/EpgFetchHelper.java index 4e889115..3843ca99 100644 --- a/src/com/android/tv/data/epg/EpgFetchHelper.java +++ b/src/com/android/tv/data/epg/EpgFetchHelper.java @@ -28,15 +28,12 @@ import android.preference.PreferenceManager; import android.support.annotation.WorkerThread; import android.text.TextUtils; import android.util.Log; - import com.android.tv.common.CommonConstants; import com.android.tv.common.util.Clock; -import com.android.tv.data.ProgramImpl; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.features.TvFeatures; import com.android.tv.util.TvProviderUtils; - import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -109,7 +106,7 @@ class EpgFetchHelper { ops.add( ContentProviderOperation.newUpdate( TvContract.buildProgramUri(oldProgram.getId())) - .withValues(ProgramImpl.toContentValues(newProgram, context)) + .withValues(Program.toContentValues(newProgram, context)) .build()); oldProgramsIndex++; newProgramsIndex++; @@ -135,7 +132,7 @@ class EpgFetchHelper { if (addNewProgram) { ops.add( ContentProviderOperation.newInsert(Programs.CONTENT_URI) - .withValues(ProgramImpl.toContentValues(newProgram, context)) + .withValues(Program.toContentValues(newProgram, context)) .build()); } // Throttle the batch operation not to cause TransactionTooLargeException. @@ -202,7 +199,7 @@ class EpgFetchHelper { @WorkerThread private static List<Program> queryPrograms( Context context, long channelId, long startTimeMs, long endTimeMs) { - String[] projection = ProgramImpl.PROJECTION; + String[] projection = Program.PROJECTION; if (TvProviderUtils.checkSeriesIdColumn(context, Programs.CONTENT_URI)) { projection = TvProviderUtils.addExtraColumnsToProjection( @@ -222,7 +219,7 @@ class EpgFetchHelper { } ArrayList<Program> programs = new ArrayList<>(); while (c.moveToNext()) { - programs.add(ProgramImpl.fromCursor(c)); + programs.add(Program.fromCursor(c)); } return programs; } diff --git a/src/com/android/tv/data/epg/EpgFetchService.java b/src/com/android/tv/data/epg/EpgFetchService.java index cfa79cb0..aa4f3588 100644 --- a/src/com/android/tv/data/epg/EpgFetchService.java +++ b/src/com/android/tv/data/epg/EpgFetchService.java @@ -18,24 +18,22 @@ package com.android.tv.data.epg; import android.app.job.JobParameters; import android.app.job.JobService; - import com.android.tv.Starter; +import com.android.tv.TvSingletons; import com.android.tv.data.ChannelDataManager; -import dagger.android.AndroidInjection; - -import javax.inject.Inject; - /** JobService to Fetch EPG data. */ public class EpgFetchService extends JobService { - @Inject EpgFetcher mEpgFetcher; - @Inject ChannelDataManager mChannelDataManager; + private EpgFetcher mEpgFetcher; + private ChannelDataManager mChannelDataManager; @Override public void onCreate() { - AndroidInjection.inject(this); super.onCreate(); Starter.start(this); + TvSingletons tvSingletons = TvSingletons.getSingletons(getApplicationContext()); + mEpgFetcher = tvSingletons.getEpgFetcher(); + mChannelDataManager = tvSingletons.getChannelDataManager(); } @Override diff --git a/src/com/android/tv/data/epg/EpgFetcherImpl.java b/src/com/android/tv/data/epg/EpgFetcherImpl.java index 27d7f8d5..b191421f 100644 --- a/src/com/android/tv/data/epg/EpgFetcherImpl.java +++ b/src/com/android/tv/data/epg/EpgFetcherImpl.java @@ -38,12 +38,10 @@ import android.support.annotation.VisibleForTesting; import android.support.annotation.WorkerThread; import android.text.TextUtils; import android.util.Log; - import com.android.tv.TvSingletons; import com.android.tv.common.BuildConfig; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.buildtype.HasBuildType; -import com.android.tv.common.dagger.annotations.ApplicationContext; import com.android.tv.common.util.Clock; import com.android.tv.common.util.CommonUtils; import com.android.tv.common.util.LocationUtils; @@ -54,22 +52,17 @@ import com.android.tv.data.ChannelDataManager; import com.android.tv.data.ChannelImpl; import com.android.tv.data.ChannelLogoFetcher; import com.android.tv.data.Lineup; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; -import com.android.tv.data.epg.EpgReader.EpgChannel; import com.android.tv.features.TvFeatures; import com.android.tv.perf.EventNames; import com.android.tv.perf.PerformanceMonitor; import com.android.tv.perf.TimerEvent; import com.android.tv.util.Utils; - import com.google.android.tv.partner.support.EpgInput; import com.google.android.tv.partner.support.EpgInputs; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; - import com.android.tv.common.flags.BackendKnobsFlags; - import java.io.IOException; import java.util.ArrayList; import java.util.Collection; @@ -80,8 +73,6 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; -import javax.inject.Inject; - /** * The service class to fetch EPG routinely or on-demand during channel scanning * @@ -118,6 +109,7 @@ public class EpgFetcherImpl implements EpgFetcher { private static final int MSG_FINISH_FETCH_DURING_SCAN = 3; private static final int MSG_RETRY_PREPARE_FETCH_DURING_SCAN = 4; + private static final int QUERY_CHANNEL_COUNT = 50; private static final int MINIMUM_CHANNELS_TO_DECIDE_LINEUP = 3; private final Context mContext; @@ -138,9 +130,31 @@ public class EpgFetcherImpl implements EpgFetcher { private Clock mClock; - @Inject - public EpgFetcherImpl( - @ApplicationContext Context context, + public static EpgFetcher create(Context context) { + context = context.getApplicationContext(); + TvSingletons tvSingletons = TvSingletons.getSingletons(context); + ChannelDataManager channelDataManager = tvSingletons.getChannelDataManager(); + PerformanceMonitor performanceMonitor = tvSingletons.getPerformanceMonitor(); + EpgReader epgReader = tvSingletons.providesEpgReader().get(); + Clock clock = tvSingletons.getClock(); + EpgInputWhiteList epgInputWhiteList = + new EpgInputWhiteList(tvSingletons.getCloudEpgFlags()); + BackendKnobsFlags backendKnobsFlags = tvSingletons.getBackendKnobs(); + HasBuildType.BuildType buildType = tvSingletons.getBuildType(); + return new EpgFetcherImpl( + context, + epgInputWhiteList, + channelDataManager, + epgReader, + performanceMonitor, + clock, + backendKnobsFlags, + buildType); + } + + @VisibleForTesting + EpgFetcherImpl( + Context context, EpgInputWhiteList epgInputWhiteList, ChannelDataManager channelDataManager, EpgReader epgReader, @@ -455,16 +469,23 @@ public class EpgFetcherImpl implements EpgFetcher { if (epgChannels.size() == 0) { return; } - int batchSize = (int) Math.max(1, mBackendKnobsFlags.epgFetcherChannelsPerProgramFetch()); - for (Iterable<EpgChannel> batch : Iterables.partition(epgChannels, batchSize)) { - batchUpdateEpg(mEpgReader.getPrograms(ImmutableSet.copyOf(batch), durationSec)); + Set<EpgReader.EpgChannel> batch = new HashSet<>(QUERY_CHANNEL_COUNT); + for (EpgReader.EpgChannel epgChannel : epgChannels) { + batch.add(epgChannel); + if (batch.size() >= QUERY_CHANNEL_COUNT) { + batchUpdateEpg(mEpgReader.getPrograms(batch, durationSec)); + batch.clear(); + } + } + if (!batch.isEmpty()) { + batchUpdateEpg(mEpgReader.getPrograms(batch, durationSec)); } } @WorkerThread private void batchUpdateEpg(Map<EpgReader.EpgChannel, Collection<Program>> allPrograms) { for (Map.Entry<EpgReader.EpgChannel, Collection<Program>> entry : allPrograms.entrySet()) { - List<Program> programs = new ArrayList<>(entry.getValue()); + List<Program> programs = new ArrayList(entry.getValue()); if (programs == null) { continue; } @@ -583,7 +604,6 @@ public class EpgFetcherImpl implements EpgFetcher { ? ((Integer) REASON_CLOUD_EPG_FAILURE) : anyCloudEpgSuccess ? null : builtInResult; } - clearUnusedLineups(null); return builtInResult; } finally { TrafficStats.setThreadStatsTag(oldTag); diff --git a/src/com/android/tv/data/epg/EpgInputWhiteList.java b/src/com/android/tv/data/epg/EpgInputWhiteList.java index 4a5f98bb..24b4fe3d 100644 --- a/src/com/android/tv/data/epg/EpgInputWhiteList.java +++ b/src/com/android/tv/data/epg/EpgInputWhiteList.java @@ -21,14 +21,13 @@ import android.support.annotation.VisibleForTesting; import android.text.TextUtils; import android.util.Log; import com.android.tv.common.BuildConfig; +import com.android.tv.common.experiments.Experiments; import com.android.tv.common.flags.CloudEpgFlags; -import com.android.tv.common.flags.LegacyFlags; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; -import javax.inject.Inject; /** Checks if a package or a input is white listed. */ public final class EpgInputWhiteList { @@ -37,7 +36,6 @@ public final class EpgInputWhiteList { private static final String QA_DEV_INPUTS = "com.example.partnersupportsampletvinput/.SampleTvInputService," + "com.android.tv.tuner.sample.dvb/.tvinput.SampleDvbTunerTvInputService"; - private final LegacyFlags mLegacyFlags; /** Returns the package portion of a inputId */ @Nullable @@ -45,12 +43,10 @@ public final class EpgInputWhiteList { return inputId == null ? null : inputId.substring(0, inputId.indexOf("/")); } - private final CloudEpgFlags mCloudEpgFlags; + private final CloudEpgFlags cloudEpgFlags; - @Inject - public EpgInputWhiteList(CloudEpgFlags cloudEpgFlags, LegacyFlags legacyFlags) { - mCloudEpgFlags = cloudEpgFlags; - mLegacyFlags = legacyFlags; + public EpgInputWhiteList(CloudEpgFlags cloudEpgFlags) { + this.cloudEpgFlags = cloudEpgFlags; } public boolean isInputWhiteListed(String inputId) { @@ -75,8 +71,8 @@ public final class EpgInputWhiteList { } private Set<String> getWhiteListedInputs() { - Set<String> result = toInputSet(mCloudEpgFlags.thirdPartyEpgInputsCsv()); - if (BuildConfig.ENG || mLegacyFlags.enableQaFeatures()) { + Set<String> result = toInputSet(cloudEpgFlags.thirdPartyEpgInputsCsv()); + if (BuildConfig.ENG || Experiments.ENABLE_QA_FEATURES.get()) { HashSet<String> moreInputs = new HashSet<>(toInputSet(QA_DEV_INPUTS)); if (result.isEmpty()) { result = moreInputs; diff --git a/src/com/android/tv/data/epg/EpgReader.java b/src/com/android/tv/data/epg/EpgReader.java index 8c0e3f09..c9fcd979 100644 --- a/src/com/android/tv/data/epg/EpgReader.java +++ b/src/com/android/tv/data/epg/EpgReader.java @@ -19,14 +19,11 @@ package com.android.tv.data.epg; import android.support.annotation.AnyThread; import android.support.annotation.NonNull; import android.support.annotation.WorkerThread; - import com.android.tv.data.Lineup; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dvr.data.SeriesInfo; - import com.google.auto.value.AutoValue; - import java.util.Collection; import java.util.List; import java.util.Map; @@ -39,8 +36,8 @@ public interface EpgReader { /** Value class that holds a EpgChannelId and its corresponding {@link Channel} */ @AutoValue abstract class EpgChannel { - public static EpgChannel createEpgChannel( - Channel channel, String epgChannelId, boolean dbUpdateNeeded) { + public static EpgChannel createEpgChannel(Channel channel, String epgChannelId, + boolean dbUpdateNeeded) { return new AutoValue_EpgReader_EpgChannel(channel, epgChannelId, dbUpdateNeeded); } diff --git a/src/com/android/tv/data/epg/StubEpgReader.java b/src/com/android/tv/data/epg/StubEpgReader.java index 19bf786e..3b001481 100644 --- a/src/com/android/tv/data/epg/StubEpgReader.java +++ b/src/com/android/tv/data/epg/StubEpgReader.java @@ -16,25 +16,21 @@ package com.android.tv.data.epg; +import android.content.Context; import android.support.annotation.NonNull; - import com.android.tv.data.Lineup; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dvr.data.SeriesInfo; - import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; -import javax.inject.Inject; - /** A stub class to read EPG. */ public class StubEpgReader implements EpgReader { - @Inject - public StubEpgReader() {} + public StubEpgReader(@SuppressWarnings("unused") Context context) {} @Override public boolean isAvailable() { diff --git a/src/com/android/tv/dialog/PinDialogFragment.java b/src/com/android/tv/dialog/PinDialogFragment.java index c7145583..87308093 100644 --- a/src/com/android/tv/dialog/PinDialogFragment.java +++ b/src/com/android/tv/dialog/PinDialogFragment.java @@ -18,7 +18,6 @@ package com.android.tv.dialog; import android.app.ActivityManager; import android.app.Dialog; -import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; import android.media.tv.TvContentRating; @@ -34,13 +33,10 @@ import android.view.ViewGroup.LayoutParams; import android.widget.TextView; import android.widget.Toast; import com.android.tv.R; +import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; -import com.android.tv.dialog.picker.TvPinPicker; -import com.android.tv.util.TvInputManagerHelper; +import com.android.tv.dialog.picker.PinPicker; import com.android.tv.util.TvSettings; -import dagger.android.AndroidInjection; -import com.android.tv.common.flags.UiFlags; -import javax.inject.Inject; public class PinDialogFragment extends SafeDismissDialogFragment { private static final String TAG = "PinDialogFragment"; @@ -84,8 +80,7 @@ public class PinDialogFragment extends SafeDismissDialogFragment { private TextView mWrongPinView; private View mEnterPinView; private TextView mTitleView; - - private TvPinPicker mTvPinPicker; + private PinPicker mPicker; private SharedPreferences mSharedPreferences; private String mPrevPin; private String mPin; @@ -93,8 +88,6 @@ public class PinDialogFragment extends SafeDismissDialogFragment { private int mWrongPinCount; private long mDisablePinUntil; private final Handler mHandler = new Handler(); - @Inject TvInputManagerHelper mTvInputManagerHelper; - @Inject UiFlags mUiFlags; public static PinDialogFragment create(int type) { return create(type, null); @@ -110,12 +103,6 @@ public class PinDialogFragment extends SafeDismissDialogFragment { } @Override - public void onAttach(Context context) { - AndroidInjection.inject(this); - super.onAttach(context); - } - - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mRequestType = getArguments().getInt(ARGS_TYPE, PIN_DIALOG_TYPE_ENTER_PIN); @@ -167,8 +154,8 @@ public class PinDialogFragment extends SafeDismissDialogFragment { mWrongPinView = (TextView) v.findViewById(R.id.wrong_pin); mEnterPinView = v.findViewById(R.id.enter_pin); mTitleView = (TextView) mEnterPinView.findViewById(R.id.title); - mTvPinPicker = v.findViewById(R.id.tv_pin_picker); - mTvPinPicker.setOnClickListener( + mPicker = v.findViewById(R.id.pin_picker); + mPicker.setOnClickListener( view -> { String pin = getPinInput(); if (!TextUtils.isEmpty(pin)) { @@ -196,7 +183,8 @@ public class PinDialogFragment extends SafeDismissDialogFragment { mTitleView.setText( getString( R.string.pin_enter_unlock_dvr, - mTvInputManagerHelper + TvSingletons.getSingletons(getContext()) + .getTvInputManagerHelper() .getContentRatingsManager() .getDisplayNameForRating(tvContentRating))); } @@ -216,8 +204,7 @@ public class PinDialogFragment extends SafeDismissDialogFragment { if (mType != PIN_DIALOG_TYPE_NEW_PIN) { updateWrongPin(); } - - mTvPinPicker.requestFocus(); + mPicker.requestFocus(); return v; } @@ -351,11 +338,11 @@ public class PinDialogFragment extends SafeDismissDialogFragment { } private String getPinInput() { - return mTvPinPicker.getPin(); + return mPicker.getPinInput(); } private void resetPinInput() { - mTvPinPicker.resetPin(); + mPicker.resetPinInput(); } /** diff --git a/src/com/android/tv/dialog/picker/PinPicker.java b/src/com/android/tv/dialog/picker/PinPicker.java new file mode 100644 index 00000000..f501dfd1 --- /dev/null +++ b/src/com/android/tv/dialog/picker/PinPicker.java @@ -0,0 +1,131 @@ +/* + * 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.dialog.picker; + +import android.content.Context; +import android.support.annotation.Nullable; +import android.support.annotation.VisibleForTesting; +import android.support.v17.leanback.widget.picker.Picker; +import android.support.v17.leanback.widget.picker.PickerColumn; +import android.util.AttributeSet; +import android.view.KeyEvent; +import android.view.View; +import android.view.ViewGroup; +import java.util.ArrayList; +import java.util.List; + +/** 4 digit picker */ +public final class PinPicker extends Picker { + // TODO(b/116144491): use leanback pin picker. + + private final List<PickerColumn> mPickers = new ArrayList<>(); + private OnClickListener mOnClickListener; + + // the version of picker I link to does not have this constructor + public PinPicker(Context context, AttributeSet attributeSet) { + this(context, attributeSet, 0); + } + + public PinPicker(Context context, AttributeSet attributeSet, int defStyleAttr) { + super(context, attributeSet, defStyleAttr); + + for (int i = 0; i < 4; i++) { + PickerColumn pickerColumn = new PickerColumn(); + pickerColumn.setMinValue(0); + pickerColumn.setMaxValue(9); + pickerColumn.setLabelFormat("%d"); + mPickers.add(pickerColumn); + } + setSeparator(" "); + setColumns(mPickers); + setActivated(true); + setFocusable(true); + super.setOnClickListener(this::onClick); + } + + public String getPinInput() { + String result = ""; + try { + for (PickerColumn column : mPickers) { + + result += column.getCurrentValue(); + } + } catch (IllegalStateException e) { + result = ""; + } + return result; + } + + @Override + public void setOnClickListener(@Nullable OnClickListener l) { + mOnClickListener = l; + } + + private void onClick(View v) { + int selectedColumn = getSelectedColumn(); + int nextColumn = selectedColumn + 1; + // Only call the click listener if we are on the last column + // Otherwise move to the next column + if (nextColumn == getColumnsCount()) { + if (mOnClickListener != null) { + mOnClickListener.onClick(v); + } + } else { + setSelectedColumn(nextColumn); + onRequestFocusInDescendants(ViewGroup.FOCUS_FORWARD, null); + } + } + + public void resetPinInput() { + setActivated(false); + for (int i = 0; i < 4; i++) { + setColumnValue(i, 0, true); + } + setSelectedColumn(0); + setActivated(true); // This resets the focus + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + if (event.getAction() == KeyEvent.ACTION_UP) { + int keyCode = event.getKeyCode(); + int digit = digitFromKeyCode(keyCode); + if (digit != -1) { + int selectedColumn = getSelectedColumn(); + setColumnValue(selectedColumn, digit, false); + int nextColumn = selectedColumn + 1; + if (nextColumn < getColumnsCount()) { + setSelectedColumn(nextColumn); + onRequestFocusInDescendants(ViewGroup.FOCUS_FORWARD, null); + } else { + callOnClick(); + } + return true; + } + } + return super.dispatchKeyEvent(event); + } + + @VisibleForTesting + static int digitFromKeyCode(int keyCode) { + if (keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) { + return keyCode - KeyEvent.KEYCODE_0; + } else if (keyCode >= KeyEvent.KEYCODE_NUMPAD_0 && keyCode <= KeyEvent.KEYCODE_NUMPAD_9) { + return keyCode - KeyEvent.KEYCODE_NUMPAD_0; + } + return -1; + } +} diff --git a/src/com/android/tv/dialog/picker/TvPinPicker.java b/src/com/android/tv/dialog/picker/TvPinPicker.java deleted file mode 100644 index 064b7f02..00000000 --- a/src/com/android/tv/dialog/picker/TvPinPicker.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2019 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.dialog.picker; - -import static android.content.Context.ACCESSIBILITY_SERVICE; - -import android.content.Context; -import androidx.leanback.widget.picker.PinPicker; -import android.util.AttributeSet; -import android.view.accessibility.AccessibilityManager; - -/** 4 digit picker */ -public final class TvPinPicker extends PinPicker { - - private boolean mSkipPerformClick = true; - private boolean mIsAccessibilityEnabled = false; - - public TvPinPicker(Context context, AttributeSet attributeSet) { - this(context, attributeSet, 0); - } - - public TvPinPicker(Context context, AttributeSet attributeSet, int defStyleAttr) { - super(context, attributeSet, defStyleAttr); - setActivated(true); - AccessibilityManager am = - (AccessibilityManager) context.getSystemService(ACCESSIBILITY_SERVICE); - mIsAccessibilityEnabled = am.isEnabled(); - } - - @Override - public boolean performClick() { - // (b/120096347) Skip first click when talkback is enabled - if (mSkipPerformClick && mIsAccessibilityEnabled) { - mSkipPerformClick = false; - /* Force focus to next value */ - setColumnValue(getSelectedColumn(), 1, true); - return false; - } - return super.performClick(); - } -} diff --git a/src/com/android/tv/dvr/DvrDataManagerImpl.java b/src/com/android/tv/dvr/DvrDataManagerImpl.java index 3e26a231..0053650b 100644 --- a/src/com/android/tv/dvr/DvrDataManagerImpl.java +++ b/src/com/android/tv/dvr/DvrDataManagerImpl.java @@ -37,10 +37,8 @@ import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; import android.util.Range; - import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; -import com.android.tv.common.dagger.annotations.ApplicationContext; import com.android.tv.common.recording.RecordingStorageStatusManager; import com.android.tv.common.recording.RecordingStorageStatusManager.OnStorageMountChangedListener; import com.android.tv.common.util.Clock; @@ -50,7 +48,6 @@ 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.dvr.provider.DvrDatabaseHelper; import com.android.tv.dvr.provider.DvrDbFuture.AddScheduleFuture; import com.android.tv.dvr.provider.DvrDbFuture.AddSeriesRecordingFuture; import com.android.tv.dvr.provider.DvrDbFuture.DeleteScheduleFuture; @@ -63,14 +60,11 @@ import com.android.tv.dvr.provider.DvrDbSync; import com.android.tv.dvr.recorder.SeriesRecordingScheduler; import com.android.tv.util.AsyncDbTask; import com.android.tv.util.AsyncDbTask.AsyncRecordedProgramQueryTask; -import com.android.tv.util.AsyncDbTask.DbExecutor; import com.android.tv.util.TvInputManagerHelper; import com.android.tv.util.TvUriMatcher; - import com.google.common.base.Predicate; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.ListenableFuture; - import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -82,13 +76,9 @@ import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.Future; -import javax.inject.Inject; -import javax.inject.Singleton; - /** DVR Data manager to handle recordings and schedules. */ @MainThread @TargetApi(Build.VERSION_CODES.N) -@Singleton public class DvrDataManagerImpl extends BaseDvrDataManager { private static final String TAG = "DvrDataManagerImpl"; private static final boolean DEBUG = false; @@ -108,7 +98,6 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { private final HashMap<Long, SeriesRecording> mSeriesRecordingsForRemovedInput = new HashMap<>(); private final Context mContext; - private final DvrDatabaseHelper mDbHelper; private Executor mDbExecutor; private final ContentObserver mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) { @@ -198,28 +187,20 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { return moved; } - @Inject - public DvrDataManagerImpl( - @ApplicationContext Context context, - Clock clock, - TvInputManagerHelper tvInputManagerHelper, - @DbExecutor Executor dbExecutor, - DvrDatabaseHelper dbHelper) { + public DvrDataManagerImpl(Context context, Clock clock) { super(context, clock); mContext = context; TvSingletons tvSingletons = TvSingletons.getSingletons(context); - mInputManager = tvInputManagerHelper; + mInputManager = tvSingletons.getTvInputManagerHelper(); mStorageStatusManager = tvSingletons.getRecordingStorageStatusManager(); - mDbExecutor = dbExecutor; - mDbHelper = dbHelper; - start(); + mDbExecutor = tvSingletons.getDbExecutor(); } - private void start() { + public void start() { mInputManager.addCallback(mInputCallback); mStorageStatusManager.addListener(mStorageMountChangedListener); DvrQuerySeriesRecordingFuture dvrQuerySeriesRecordingTask = - new DvrQuerySeriesRecordingFuture(mDbHelper); + new DvrQuerySeriesRecordingFuture(mContext); ListenableFuture<List<SeriesRecording>> dvrQuerySeriesRecordingFuture = dvrQuerySeriesRecordingTask.executeOnDbThread( new FutureCallback<List<SeriesRecording>>() { @@ -232,8 +213,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { if (SoftPreconditions.checkState( !seriesIds.contains(r.getSeriesId()), TAG, - "Skip loading series recording with duplicate series" - + " ID: " + "Skip loading series recording with duplicate series ID: " + r)) { seriesIds.add(r.getSeriesId()); if (isInputAvailable(r.getInputId())) { @@ -257,7 +237,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { } }); mPendingDvrFuture.add(dvrQuerySeriesRecordingFuture); - DvrQueryScheduleFuture dvrQueryScheduleTask = new DvrQueryScheduleFuture(mDbHelper); + DvrQueryScheduleFuture dvrQueryScheduleTask = new DvrQueryScheduleFuture(mContext); ListenableFuture<List<ScheduledRecording>> dvrQueryScheduleFuture = dvrQueryScheduleTask.executeOnDbThread( new FutureCallback<List<ScheduledRecording>>() { @@ -661,7 +641,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { notifyScheduledRecordingAdded(schedules); } ListenableFuture addScheduleFuture = - new AddScheduleFuture(mDbHelper) + new AddScheduleFuture(mContext) .executeOnDbThread(removeFromSetOnCompletion, schedules); mNoStopFuture.add(addScheduleFuture); removeDeletedSchedules(schedules); @@ -683,7 +663,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { notifySeriesRecordingAdded(seriesRecordings); } ListenableFuture addSeriesRecordingFuture = - new AddSeriesRecordingFuture(mDbHelper) + new AddSeriesRecordingFuture(mContext) .executeOnDbThread(removeFromSetOnCompletion, seriesRecordings); mNoStopFuture.add(addSeriesRecordingFuture); } @@ -743,7 +723,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { } if (!schedulesToDelete.isEmpty()) { ListenableFuture deleteScheduleFuture = - new DeleteScheduleFuture(mDbHelper) + new DeleteScheduleFuture(mContext) .executeOnDbThread( removeFromSetOnCompletion, ScheduledRecording.toArray(schedulesToDelete)); @@ -751,7 +731,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { } if (!schedulesNotToDelete.isEmpty()) { ListenableFuture updateScheduleFuture = - new UpdateScheduleFuture(mDbHelper) + new UpdateScheduleFuture(mContext) .executeOnDbThread( removeFromSetOnCompletion, ScheduledRecording.toArray(schedulesNotToDelete)); @@ -794,7 +774,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { notifySeriesRecordingRemoved(seriesRecordings); } ListenableFuture deleteSeriesRecordingFuture = - new DeleteSeriesRecordingFuture(mDbHelper) + new DeleteSeriesRecordingFuture(mContext) .executeOnDbThread(removeFromSetOnCompletion, seriesRecordings); mNoStopFuture.add(deleteSeriesRecordingFuture); removeDeletedSchedules(seriesRecordings); @@ -849,7 +829,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { } if (updateDb) { ListenableFuture updateScheduleFuture = - new UpdateScheduleFuture(mDbHelper) + new UpdateScheduleFuture(mContext) .executeOnDbThread(removeFromSetOnCompletion, scheduleArray); mNoStopFuture.add(updateScheduleFuture); } @@ -876,7 +856,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { notifySeriesRecordingChanged(seriesRecordings); } ListenableFuture updateSeriesRecordingFuture = - new UpdateSeriesRecordingFuture(mDbHelper) + new UpdateSeriesRecordingFuture(mContext) .executeOnDbThread(removeFromSetOnCompletion, seriesRecordings); mNoStopFuture.add(updateSeriesRecordingFuture); } @@ -897,7 +877,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { } if (!schedulesToDelete.isEmpty()) { ListenableFuture deleteScheduleFuture = - new DeleteScheduleFuture(mDbHelper) + new DeleteScheduleFuture(mContext) .executeOnDbThread( removeFromSetOnCompletion, ScheduledRecording.toArray(schedulesToDelete)); @@ -922,7 +902,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { } if (!schedulesToDelete.isEmpty()) { ListenableFuture deleteScheduleFuture = - new DeleteScheduleFuture(mDbHelper) + new DeleteScheduleFuture(mContext) .executeOnDbThread( removeFromSetOnCompletion, ScheduledRecording.toArray(schedulesToDelete)); @@ -970,7 +950,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { mSeriesRecordingsForRemovedInput.remove(r.getId()); } ListenableFuture deleteSeriesRecordingFuture = - new DeleteSeriesRecordingFuture(mDbHelper) + new DeleteSeriesRecordingFuture(mContext) .executeOnDbThread( removeFromSetOnCompletion, SeriesRecording.toArray(removedSeriesRecordings)); @@ -1063,13 +1043,13 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { } } ListenableFuture deleteScheduleFuture = - new DeleteScheduleFuture(mDbHelper) + new DeleteScheduleFuture(mContext) .executeOnDbThread( removeFromSetOnCompletion, ScheduledRecording.toArray(schedulesToDelete)); mNoStopFuture.add(deleteScheduleFuture); ListenableFuture deleteSeriesRecordingFuture = - new DeleteSeriesRecordingFuture(mDbHelper) + new DeleteSeriesRecordingFuture(mContext) .executeOnDbThread( removeFromSetOnCompletion, SeriesRecording.toArray(seriesRecordingsToDelete)); @@ -1105,7 +1085,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { if (!removedSeriesRecordings.isEmpty()) { SeriesRecording[] removed = SeriesRecording.toArray(removedSeriesRecordings); ListenableFuture deleteSeriesRecordingFuture = - new DeleteSeriesRecordingFuture(mDbHelper) + new DeleteSeriesRecordingFuture(mContext) .executeOnDbThread(removeFromSetOnCompletion, removed); mNoStopFuture.add(deleteSeriesRecordingFuture); if (mDvrLoadFinished) { diff --git a/src/com/android/tv/dvr/DvrManager.java b/src/com/android/tv/dvr/DvrManager.java index 12982c6c..cc9ad37a 100644 --- a/src/com/android/tv/dvr/DvrManager.java +++ b/src/com/android/tv/dvr/DvrManager.java @@ -37,13 +37,12 @@ import android.support.annotation.VisibleForTesting; import android.support.annotation.WorkerThread; import android.util.Log; import android.util.Range; - import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.feature.CommonFeatures; import com.android.tv.common.util.CommonUtils; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dvr.DvrDataManager.OnRecordedProgramLoadFinishedListener; import com.android.tv.dvr.DvrDataManager.RecordedProgramListener; import com.android.tv.dvr.DvrScheduleManager.OnInitializeListener; @@ -52,7 +51,6 @@ import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.data.SeriesRecording; import com.android.tv.util.AsyncDbTask; import com.android.tv.util.Utils; - import java.io.File; import java.util.ArrayList; import java.util.Arrays; @@ -189,7 +187,7 @@ public class DvrManager { ? mScheduleManager.suggestNewPriority() : mScheduleManager.suggestHighestPriority( seriesRecording.getInputId(), - Range.create( + new Range( program.getStartTimeUtcMillis(), program.getEndTimeUtcMillis()), seriesRecording.getPriority())); diff --git a/src/com/android/tv/dvr/DvrScheduleManager.java b/src/com/android/tv/dvr/DvrScheduleManager.java index 3afcc422..7202dce0 100644 --- a/src/com/android/tv/dvr/DvrScheduleManager.java +++ b/src/com/android/tv/dvr/DvrScheduleManager.java @@ -25,12 +25,11 @@ import android.support.annotation.NonNull; import android.support.annotation.VisibleForTesting; import android.util.ArraySet; import android.util.Range; - import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; import com.android.tv.data.ChannelDataManager; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dvr.DvrDataManager.OnDvrScheduleLoadFinishedListener; import com.android.tv.dvr.DvrDataManager.ScheduledRecordingListener; import com.android.tv.dvr.data.ScheduledRecording; @@ -38,7 +37,6 @@ import com.android.tv.dvr.data.SeriesRecording; import com.android.tv.dvr.recorder.InputTaskScheduler; import com.android.tv.util.CompositeComparator; import com.android.tv.util.Utils; - import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -78,7 +76,7 @@ public class DvrScheduleManager { ScheduledRecording.ID_COMPARATOR); private final Context mContext; - private final DvrDataManager mDataManager; + private final DvrDataManagerImpl mDataManager; private final ChannelDataManager mChannelDataManager; private final Map<String, List<ScheduledRecording>> mInputScheduleMap = new HashMap<>(); @@ -97,7 +95,7 @@ public class DvrScheduleManager { public DvrScheduleManager(Context context) { mContext = context; TvSingletons tvSingletons = TvSingletons.getSingletons(context); - mDataManager = tvSingletons.getDvrDataManager(); + mDataManager = (DvrDataManagerImpl) tvSingletons.getDvrDataManager(); mChannelDataManager = tvSingletons.getChannelDataManager(); if (mDataManager.isDvrScheduleLoadFinished() && mChannelDataManager.isDbLoadFinished()) { buildData(); diff --git a/src/com/android/tv/dvr/DvrStorageStatusManager.java b/src/com/android/tv/dvr/DvrStorageStatusManager.java index a0ae8939..dc347a9e 100644 --- a/src/com/android/tv/dvr/DvrStorageStatusManager.java +++ b/src/com/android/tv/dvr/DvrStorageStatusManager.java @@ -114,7 +114,7 @@ public class DvrStorageStatusManager extends RecordingStorageStatusManager { return; } for (TvInputInfo info : tvInputInfoList) { - if (CommonUtils.isBundledInput(info.getId()) && dvrManager != null) { + if (CommonUtils.isBundledInput(info.getId())) { dvrManager.forgetStorage(info.getId()); } } diff --git a/src/com/android/tv/dvr/DvrWatchedPositionManager.java b/src/com/android/tv/dvr/DvrWatchedPositionManager.java index b4fea7f3..8616962f 100644 --- a/src/com/android/tv/dvr/DvrWatchedPositionManager.java +++ b/src/com/android/tv/dvr/DvrWatchedPositionManager.java @@ -20,10 +20,8 @@ import android.content.Context; import android.content.SharedPreferences; import android.media.tv.TvInputManager; import android.support.annotation.IntDef; - import com.android.tv.common.util.SharedPreferencesUtils; import com.android.tv.dvr.data.RecordedProgram; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -38,7 +36,7 @@ import java.util.concurrent.CopyOnWriteArraySet; */ public class DvrWatchedPositionManager { private SharedPreferences mWatchedPositions; - private final Map<Long, Set<WatchedPositionChangedListener>> mListeners = new HashMap<>(); + private final Map<Long, Set> mListeners = new HashMap<>(); /** * The minimum percentage of recorded program being watched that will be considered as being diff --git a/src/com/android/tv/dvr/data/RecordedProgram.java b/src/com/android/tv/dvr/data/RecordedProgram.java index 61430551..899e65ac 100644 --- a/src/com/android/tv/dvr/data/RecordedProgram.java +++ b/src/com/android/tv/dvr/data/RecordedProgram.java @@ -36,10 +36,9 @@ import com.android.tv.common.TvContentRatingCache; import com.android.tv.common.data.RecordedProgramState; import com.android.tv.common.util.CommonUtils; import com.android.tv.common.util.StringUtils; -import com.android.tv.data.BaseProgramImpl; +import com.android.tv.data.BaseProgram; import com.android.tv.data.GenreItems; import com.android.tv.data.InternalDataUtils; -import com.android.tv.data.api.BaseProgram; import com.android.tv.util.TvProviderUtils; import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; @@ -50,7 +49,7 @@ import java.util.concurrent.TimeUnit; /** Immutable instance of {@link android.media.tv.TvContract.RecordedPrograms}. */ @TargetApi(Build.VERSION_CODES.N) @AutoValue -public abstract class RecordedProgram extends BaseProgramImpl { +public abstract class RecordedProgram extends BaseProgram { public static final int ID_NOT_SET = -1; private static final String TAG = "RecordedProgram"; diff --git a/src/com/android/tv/dvr/data/ScheduledRecording.java b/src/com/android/tv/dvr/data/ScheduledRecording.java index 1237fb3e..ba6d3cf9 100644 --- a/src/com/android/tv/dvr/data/ScheduledRecording.java +++ b/src/com/android/tv/dvr/data/ScheduledRecording.java @@ -27,17 +27,15 @@ import android.support.annotation.IntDef; import android.support.annotation.Nullable; import android.text.TextUtils; import android.util.Range; - import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.util.CommonUtils; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dvr.DvrScheduleManager; import com.android.tv.dvr.provider.DvrContract.Schedules; import com.android.tv.util.CompositeComparator; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Collection; @@ -494,7 +492,7 @@ public final class ScheduledRecording implements Parcelable { } }; - /** The ID internal to TV app */ + /** The ID internal to Live TV */ private long mId; /** diff --git a/src/com/android/tv/dvr/data/SeriesRecording.java b/src/com/android/tv/dvr/data/SeriesRecording.java index cd7d9662..6cb0e836 100644 --- a/src/com/android/tv/dvr/data/SeriesRecording.java +++ b/src/com/android/tv/dvr/data/SeriesRecording.java @@ -22,14 +22,11 @@ import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.IntDef; import android.text.TextUtils; - -import com.android.tv.data.BaseProgramImpl; -import com.android.tv.data.api.BaseProgram; -import com.android.tv.data.api.Program; +import com.android.tv.data.BaseProgram; +import com.android.tv.data.Program; import com.android.tv.dvr.DvrScheduleManager; import com.android.tv.dvr.provider.DvrContract.SeriesRecordings; import com.android.tv.util.Utils; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; @@ -88,8 +85,7 @@ public class SeriesRecording implements Parcelable { (SeriesRecording lhs, SeriesRecording rhs) -> Long.compare(lhs.mId, rhs.mId); /** - * Creates a new Builder with the values set from the series information of {@link - * BaseProgramImpl}. + * Creates a new Builder with the values set from the series information of {@link BaseProgram}. */ public static Builder builder(String inputId, BaseProgram p) { return new Builder() diff --git a/src/com/android/tv/dvr/provider/DvrContract.java b/src/com/android/tv/dvr/provider/DvrContract.java index 8539ae36..a5f2e2cd 100644 --- a/src/com/android/tv/dvr/provider/DvrContract.java +++ b/src/com/android/tv/dvr/provider/DvrContract.java @@ -20,7 +20,7 @@ import android.provider.BaseColumns; /** * The contract between the DVR provider and applications. Contains definitions for the supported - * columns. It's for the internal use in TV app. + * columns. It's for the internal use in Live TV. */ public final class DvrContract { /** Column definition for Schedules table. */ @@ -69,8 +69,8 @@ public final class DvrContract { public static final String FAILED_REASON_INVALID_CHANNEL = "FAILED_REASON_INVALID_CHANNEL"; /** The recording failed because the scheduler was stopped */ - public static final String FAILED_REASON_SCHEDULER_STOPPED = - "FAILED_REASON_SCHEDULER_STOPPED"; + public static final String FAILED_REASON_SCHEDULER_STOPPED + = "FAILED_REASON_SCHEDULER_STOPPED"; /** The recording failed because some messages were not sent to the message queue */ public static final String FAILED_REASON_MESSAGE_NOT_SENT = @@ -84,7 +84,8 @@ public final class DvrContract { "FAILED_REASON_CONNECTION_FAILED"; /** - * The recording failed because a required recording resource was not able to be allocated. + * The recording failed because a required recording resource was not able to be + * allocated. */ public static final String FAILED_REASON_RESOURCE_BUSY = "FAILED_REASON_RESOURCE_BUSY"; diff --git a/src/com/android/tv/dvr/provider/DvrDatabaseHelper.java b/src/com/android/tv/dvr/provider/DvrDatabaseHelper.java index 1dcda8e0..ebf133db 100644 --- a/src/com/android/tv/dvr/provider/DvrDatabaseHelper.java +++ b/src/com/android/tv/dvr/provider/DvrDatabaseHelper.java @@ -26,18 +26,12 @@ import android.database.sqlite.SQLiteStatement; import android.provider.BaseColumns; import android.text.TextUtils; import android.util.Log; - -import com.android.tv.common.dagger.annotations.ApplicationContext; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.data.SeriesRecording; import com.android.tv.dvr.provider.DvrContract.Schedules; import com.android.tv.dvr.provider.DvrContract.SeriesRecordings; -import javax.inject.Inject; -import javax.inject.Singleton; - /** A data class for one recorded contents. */ -@Singleton public class DvrDatabaseHelper extends SQLiteOpenHelper { private static final String TAG = "DvrDatabaseHelper"; private static final boolean DEBUG = false; @@ -244,9 +238,8 @@ public class DvrDatabaseHelper extends SQLiteOpenHelper { return "DELETE FROM " + tableName + " WHERE " + BaseColumns._ID + "=?"; } - @Inject - public DvrDatabaseHelper(@ApplicationContext Context context) { - super(context, DB_NAME, null, DATABASE_VERSION); + public DvrDatabaseHelper(Context context) { + super(context.getApplicationContext(), DB_NAME, null, DATABASE_VERSION); } @Override @@ -273,12 +266,8 @@ public class DvrDatabaseHelper extends SQLiteOpenHelper { return; } if (oldVersion < 18) { - db.execSQL( - "ALTER TABLE " - + Schedules.TABLE_NAME - + " ADD COLUMN " - + Schedules.COLUMN_FAILED_REASON - + " TEXT DEFAULT null;"); + db.execSQL("ALTER TABLE " + Schedules.TABLE_NAME + " ADD COLUMN " + + Schedules.COLUMN_FAILED_REASON + " TEXT DEFAULT null;"); } } diff --git a/src/com/android/tv/dvr/provider/DvrDbFuture.java b/src/com/android/tv/dvr/provider/DvrDbFuture.java index cbc2c07d..ae8c480b 100644 --- a/src/com/android/tv/dvr/provider/DvrDbFuture.java +++ b/src/com/android/tv/dvr/provider/DvrDbFuture.java @@ -16,23 +16,21 @@ package com.android.tv.dvr.provider; +import android.content.Context; import android.database.Cursor; import android.support.annotation.Nullable; import android.util.Log; - import com.android.tv.common.concurrent.NamedThreadFactory; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.data.SeriesRecording; import com.android.tv.dvr.provider.DvrContract.Schedules; import com.android.tv.dvr.provider.DvrContract.SeriesRecordings; import com.android.tv.util.MainThreadExecutor; - import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; - import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executors; @@ -40,24 +38,29 @@ import java.util.concurrent.Executors; /** {@link DvrDbFuture} that defaults to executing on its own single threaded Executor Service. */ public abstract class DvrDbFuture<ParamsT, ResultT> { private static final NamedThreadFactory THREAD_FACTORY = - new NamedThreadFactory(DvrDbFuture.class.getSimpleName()); + new NamedThreadFactory(DvrDbFuture.class.getSimpleName()); private static final ListeningExecutorService DB_EXECUTOR = - MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor(THREAD_FACTORY)); + MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor(THREAD_FACTORY)); - final DvrDatabaseHelper mDbHelper; + private static DvrDatabaseHelper sDbHelper; private ListenableFuture<ResultT> mFuture; - private DvrDbFuture(DvrDatabaseHelper mDbHelper) { - this.mDbHelper = mDbHelper; + final Context mContext; + + private DvrDbFuture(Context context) { + mContext = context; } - /** Execute the task on the {@link #DB_EXECUTOR} thread and return Future */ + /** Execute the task on the {@link #DB_EXECUTOR} thread and return Future*/ @SafeVarargs public final ListenableFuture<ResultT> executeOnDbThread( - FutureCallback<ResultT> callback, ParamsT... params) { - mFuture = DB_EXECUTOR.submit(() -> dbHelperInBackground(params)); - Futures.addCallback(mFuture, callback, MainThreadExecutor.getInstance()); - return mFuture; + FutureCallback<ResultT> callback, ParamsT... params) { + if (sDbHelper == null) { + sDbHelper = new DvrDatabaseHelper(mContext.getApplicationContext()); + } + mFuture = DB_EXECUTOR.submit(() -> dbHelperInBackground(params)); + Futures.addCallback(mFuture, callback, MainThreadExecutor.getInstance()); + return mFuture; } /** Executes in the background after initializing DbHelper} */ @@ -69,48 +72,52 @@ public abstract class DvrDbFuture<ParamsT, ResultT> { } /** Inserts schedules. */ - public static class AddScheduleFuture extends DvrDbFuture<ScheduledRecording, Void> { - public AddScheduleFuture(DvrDatabaseHelper dbHelper) { - super(dbHelper); + public static class AddScheduleFuture + extends DvrDbFuture<ScheduledRecording, Void> { + public AddScheduleFuture(Context context) { + super(context); } @Override protected final Void dbHelperInBackground(ScheduledRecording... params) { - mDbHelper.insertSchedules(params); + sDbHelper.insertSchedules(params); return null; } } /** Update schedules. */ - public static class UpdateScheduleFuture extends DvrDbFuture<ScheduledRecording, Void> { - public UpdateScheduleFuture(DvrDatabaseHelper dbHelper) { - super(dbHelper); + public static class UpdateScheduleFuture + extends DvrDbFuture<ScheduledRecording, Void> { + public UpdateScheduleFuture(Context context) { + super(context); } @Override protected final Void dbHelperInBackground(ScheduledRecording... params) { - mDbHelper.updateSchedules(params); + sDbHelper.updateSchedules(params); return null; } } /** Delete schedules. */ - public static class DeleteScheduleFuture extends DvrDbFuture<ScheduledRecording, Void> { - public DeleteScheduleFuture(DvrDatabaseHelper dbHelper) { - super(dbHelper); + public static class DeleteScheduleFuture + extends DvrDbFuture<ScheduledRecording, Void> { + public DeleteScheduleFuture(Context context) { + super(context); } @Override protected final Void dbHelperInBackground(ScheduledRecording... params) { - mDbHelper.deleteSchedules(params); + sDbHelper.deleteSchedules(params); return null; } } /** Returns all {@link ScheduledRecording}s. */ - public static class DvrQueryScheduleFuture extends DvrDbFuture<Void, List<ScheduledRecording>> { - public DvrQueryScheduleFuture(DvrDatabaseHelper dbHelper) { - super(dbHelper); + public static class DvrQueryScheduleFuture + extends DvrDbFuture<Void, List<ScheduledRecording>> { + public DvrQueryScheduleFuture(Context context) { + super(context); } @Override @@ -120,7 +127,7 @@ public abstract class DvrDbFuture<ParamsT, ResultT> { return null; } List<ScheduledRecording> scheduledRecordings = new ArrayList<>(); - try (Cursor c = mDbHelper.query(Schedules.TABLE_NAME, ScheduledRecording.PROJECTION)) { + try (Cursor c = sDbHelper.query(Schedules.TABLE_NAME, ScheduledRecording.PROJECTION)) { while (c.moveToNext() && !isCancelled()) { scheduledRecordings.add(ScheduledRecording.fromCursor(c)); } @@ -130,40 +137,43 @@ public abstract class DvrDbFuture<ParamsT, ResultT> { } /** Inserts series recordings. */ - public static class AddSeriesRecordingFuture extends DvrDbFuture<SeriesRecording, Void> { - public AddSeriesRecordingFuture(DvrDatabaseHelper dbHelper) { - super(dbHelper); + public static class AddSeriesRecordingFuture + extends DvrDbFuture<SeriesRecording, Void> { + public AddSeriesRecordingFuture(Context context) { + super(context); } @Override protected final Void dbHelperInBackground(SeriesRecording... params) { - mDbHelper.insertSeriesRecordings(params); + sDbHelper.insertSeriesRecordings(params); return null; } } /** Update series recordings. */ - public static class UpdateSeriesRecordingFuture extends DvrDbFuture<SeriesRecording, Void> { - public UpdateSeriesRecordingFuture(DvrDatabaseHelper dbHelper) { - super(dbHelper); + public static class UpdateSeriesRecordingFuture + extends DvrDbFuture<SeriesRecording, Void> { + public UpdateSeriesRecordingFuture(Context context) { + super(context); } @Override protected final Void dbHelperInBackground(SeriesRecording... params) { - mDbHelper.updateSeriesRecordings(params); + sDbHelper.updateSeriesRecordings(params); return null; } } /** Delete series recordings. */ - public static class DeleteSeriesRecordingFuture extends DvrDbFuture<SeriesRecording, Void> { - public DeleteSeriesRecordingFuture(DvrDatabaseHelper dbHelper) { - super(dbHelper); + public static class DeleteSeriesRecordingFuture + extends DvrDbFuture<SeriesRecording, Void> { + public DeleteSeriesRecordingFuture(Context context) { + super(context); } @Override protected final Void dbHelperInBackground(SeriesRecording... params) { - mDbHelper.deleteSeriesRecordings(params); + sDbHelper.deleteSeriesRecordings(params); return null; } } @@ -173,8 +183,8 @@ public abstract class DvrDbFuture<ParamsT, ResultT> { extends DvrDbFuture<Void, List<SeriesRecording>> { private static final String TAG = "DvrQuerySeriesRecording"; - public DvrQuerySeriesRecordingFuture(DvrDatabaseHelper dbHelper) { - super(dbHelper); + public DvrQuerySeriesRecordingFuture(Context context) { + super(context); } @Override @@ -185,7 +195,7 @@ public abstract class DvrDbFuture<ParamsT, ResultT> { } List<SeriesRecording> scheduledRecordings = new ArrayList<>(); try (Cursor c = - mDbHelper.query(SeriesRecordings.TABLE_NAME, SeriesRecording.PROJECTION)) { + sDbHelper.query(SeriesRecordings.TABLE_NAME, SeriesRecording.PROJECTION)) { while (c.moveToNext() && !isCancelled()) { scheduledRecordings.add(SeriesRecording.fromCursor(c)); } diff --git a/src/com/android/tv/dvr/provider/DvrDbSync.java b/src/com/android/tv/dvr/provider/DvrDbSync.java index c2eae771..7658ca45 100644 --- a/src/com/android/tv/dvr/provider/DvrDbSync.java +++ b/src/com/android/tv/dvr/provider/DvrDbSync.java @@ -29,19 +29,17 @@ import android.os.Looper; import android.support.annotation.MainThread; import android.support.annotation.VisibleForTesting; import android.util.Log; - import com.android.tv.TvSingletons; import com.android.tv.data.ChannelDataManager; -import com.android.tv.data.api.Program; +import com.android.tv.data.Program; import com.android.tv.dvr.DvrDataManager.ScheduledRecordingListener; +import com.android.tv.dvr.DvrDataManagerImpl; import com.android.tv.dvr.DvrManager; -import com.android.tv.dvr.WritableDvrDataManager; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.data.SeriesRecording; import com.android.tv.dvr.recorder.SeriesRecordingScheduler; import com.android.tv.util.AsyncDbTask.AsyncQueryProgramTask; import com.android.tv.util.TvUriMatcher; - import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -51,7 +49,6 @@ import java.util.Objects; import java.util.Queue; import java.util.Set; import java.util.concurrent.Executor; -import java.util.concurrent.TimeUnit; /** * A class to synchronizes DVR DB with TvProvider. @@ -68,11 +65,9 @@ public class DvrDbSync { private static final String TAG = "DvrDbSync"; private static final boolean DEBUG = false; - private static final long RECORD_MARGIN_MS = TimeUnit.SECONDS.toMillis(10); - private final Context mContext; private final DvrManager mDvrManager; - private final WritableDvrDataManager mDataManager; + private final DvrDataManagerImpl mDataManager; private final ChannelDataManager mChannelDataManager; private final Executor mDbExecutor; private final Queue<Long> mProgramIdQueue = new LinkedList<>(); @@ -143,7 +138,7 @@ public class DvrDbSync { } }; - public DvrDbSync(Context context, WritableDvrDataManager dataManager) { + public DvrDbSync(Context context, DvrDataManagerImpl dataManager) { this( context, dataManager, @@ -156,7 +151,7 @@ public class DvrDbSync { @VisibleForTesting DvrDbSync( Context context, - WritableDvrDataManager dataManager, + DvrDataManagerImpl dataManager, ChannelDataManager channelDataManager, DvrManager dvrManager, SeriesRecordingScheduler seriesRecordingScheduler, @@ -330,15 +325,10 @@ public class DvrDbSync { // Old program belongs to a series but the new one doesn't. seriesRecordingsToUpdate.add(seriesRecordingForOldSchedule); } - // Change start time only when the recording is not started yet and if it is not - // within marginal time of current time. Marginal check is needed to prevent the - // update of start time if recording is just triggered or about to get triggered. - boolean marginalToCurrentTime = RECORD_MARGIN_MS > - Math.abs(System.currentTimeMillis() - schedule.getStartTimeMs()); + // Change start time only when the recording is not started yet. boolean needToChangeStartTime = schedule.getState() != ScheduledRecording.STATE_RECORDING_IN_PROGRESS - && program.getStartTimeUtcMillis() != schedule.getStartTimeMs() - && !marginalToCurrentTime; + && program.getStartTimeUtcMillis() != schedule.getStartTimeMs(); if (needToChangeStartTime) { builder.setStartTimeMs(program.getStartTimeUtcMillis()); needUpdate = true; diff --git a/src/com/android/tv/dvr/provider/EpisodicProgramLoadTask.java b/src/com/android/tv/dvr/provider/EpisodicProgramLoadTask.java index a66e5b02..02e197f1 100644 --- a/src/com/android/tv/dvr/provider/EpisodicProgramLoadTask.java +++ b/src/com/android/tv/dvr/provider/EpisodicProgramLoadTask.java @@ -25,19 +25,16 @@ import android.net.Uri; import android.os.Build; import android.support.annotation.Nullable; import android.support.annotation.WorkerThread; - import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.util.PermissionUtils; -import com.android.tv.data.ProgramImpl; -import com.android.tv.data.api.Program; +import com.android.tv.data.Program; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.data.SeasonEpisodeNumber; import com.android.tv.dvr.data.SeriesRecording; import com.android.tv.util.AsyncDbTask.AsyncProgramQueryTask; import com.android.tv.util.AsyncDbTask.CursorFilter; - import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -50,11 +47,11 @@ import java.util.Set; public abstract class EpisodicProgramLoadTask { private static final String TAG = "EpisodicProgramLoadTask"; - private static final int PROGRAM_ID_INDEX = ProgramImpl.getColumnIndex(Programs._ID); + private static final int PROGRAM_ID_INDEX = Program.getColumnIndex(Programs._ID); private static final int START_TIME_INDEX = - ProgramImpl.getColumnIndex(Programs.COLUMN_START_TIME_UTC_MILLIS); + Program.getColumnIndex(Programs.COLUMN_START_TIME_UTC_MILLIS); private static final int RECORDING_PROHIBITED_INDEX = - ProgramImpl.getColumnIndex(Programs.COLUMN_RECORDING_PROHIBITED); + Program.getColumnIndex(Programs.COLUMN_RECORDING_PROHIBITED); private static final String PARAM_START_TIME = "start_time"; private static final String PARAM_END_TIME = "end_time"; @@ -292,7 +289,7 @@ public abstract class EpisodicProgramLoadTask { && mDisallowedProgramIds.contains(c.getLong(PROGRAM_ID_INDEX))) { return false; } - Program program = ProgramImpl.fromCursor(c); + Program program = Program.fromCursor(c); for (SeriesRecording seriesRecording : mSeriesRecordings) { boolean programMatches; if (mIgnoreChannelOption) { diff --git a/src/com/android/tv/dvr/recorder/SeriesRecordingScheduler.java b/src/com/android/tv/dvr/recorder/SeriesRecordingScheduler.java index 92b4e06a..696038cf 100644 --- a/src/com/android/tv/dvr/recorder/SeriesRecordingScheduler.java +++ b/src/com/android/tv/dvr/recorder/SeriesRecordingScheduler.java @@ -27,12 +27,11 @@ import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; import android.util.LongSparseArray; - import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.util.CollectionUtils; import com.android.tv.common.util.SharedPreferencesUtils; -import com.android.tv.data.api.Program; +import com.android.tv.data.Program; import com.android.tv.data.epg.EpgReader; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.DvrDataManager.ScheduledRecordingListener; @@ -44,9 +43,6 @@ import com.android.tv.dvr.data.SeasonEpisodeNumber; import com.android.tv.dvr.data.SeriesInfo; import com.android.tv.dvr.data.SeriesRecording; import com.android.tv.dvr.provider.EpisodicProgramLoadTask; - -import dagger.Lazy; - import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -58,6 +54,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import javax.inject.Provider; /** * Creates the {@link com.android.tv.dvr.data.ScheduledRecording}s for the {@link @@ -532,9 +529,10 @@ public class SeriesRecordingScheduler { private class FetchSeriesInfoTask extends AsyncTask<Void, Void, SeriesInfo> { private final SeriesRecording mSeriesRecording; - private final Lazy<EpgReader> mEpgReaderProvider; + private final Provider<EpgReader> mEpgReaderProvider; - FetchSeriesInfoTask(SeriesRecording seriesRecording, Lazy<EpgReader> epgReaderProvider) { + FetchSeriesInfoTask( + SeriesRecording seriesRecording, Provider<EpgReader> epgReaderProvider) { mSeriesRecording = seriesRecording; mEpgReaderProvider = epgReaderProvider; } diff --git a/src/com/android/tv/dvr/ui/DvrAlreadyRecordedFragment.java b/src/com/android/tv/dvr/ui/DvrAlreadyRecordedFragment.java index 1f4faf31..5e3caa9c 100644 --- a/src/com/android/tv/dvr/ui/DvrAlreadyRecordedFragment.java +++ b/src/com/android/tv/dvr/ui/DvrAlreadyRecordedFragment.java @@ -22,16 +22,13 @@ import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; - -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; - +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.leanback.widget.GuidedAction; import com.android.tv.R; import com.android.tv.TvSingletons; -import com.android.tv.data.api.Program; +import com.android.tv.data.Program; import com.android.tv.dvr.DvrManager; import com.android.tv.dvr.data.RecordedProgram; - import java.util.List; /** diff --git a/src/com/android/tv/dvr/ui/DvrAlreadyScheduledFragment.java b/src/com/android/tv/dvr/ui/DvrAlreadyScheduledFragment.java index 56ffc884..a6bbe137 100644 --- a/src/com/android/tv/dvr/ui/DvrAlreadyScheduledFragment.java +++ b/src/com/android/tv/dvr/ui/DvrAlreadyScheduledFragment.java @@ -22,17 +22,14 @@ import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.leanback.widget.GuidedAction; import android.text.format.DateUtils; - -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; - import com.android.tv.R; import com.android.tv.TvSingletons; -import com.android.tv.data.api.Program; +import com.android.tv.data.Program; import com.android.tv.dvr.DvrManager; import com.android.tv.dvr.data.ScheduledRecording; - import java.util.List; /** diff --git a/src/com/android/tv/dvr/ui/DvrChannelRecordDurationOptionFragment.java b/src/com/android/tv/dvr/ui/DvrChannelRecordDurationOptionFragment.java index b24281ad..6be35cb2 100644 --- a/src/com/android/tv/dvr/ui/DvrChannelRecordDurationOptionFragment.java +++ b/src/com/android/tv/dvr/ui/DvrChannelRecordDurationOptionFragment.java @@ -18,9 +18,9 @@ package com.android.tv.dvr.ui; import android.graphics.drawable.Drawable; import android.os.Bundle; -import androidx.leanback.app.GuidedStepFragment; -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; +import android.support.v17.leanback.app.GuidedStepFragment; +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.leanback.widget.GuidedAction; import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; diff --git a/src/com/android/tv/dvr/ui/DvrConflictFragment.java b/src/com/android/tv/dvr/ui/DvrConflictFragment.java index 5e0a96bb..649cc89a 100644 --- a/src/com/android/tv/dvr/ui/DvrConflictFragment.java +++ b/src/com/android/tv/dvr/ui/DvrConflictFragment.java @@ -21,25 +21,22 @@ import android.media.tv.TvInputInfo; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.leanback.widget.GuidedAction; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; - -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; - import com.android.tv.MainActivity; import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.recorder.ConflictChecker; import com.android.tv.dvr.recorder.ConflictChecker.OnUpcomingConflictChangeListener; import com.android.tv.util.Utils; - import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; diff --git a/src/com/android/tv/dvr/ui/DvrGuidedActionsStylist.java b/src/com/android/tv/dvr/ui/DvrGuidedActionsStylist.java index 81fc3ed5..611962d0 100644 --- a/src/com/android/tv/dvr/ui/DvrGuidedActionsStylist.java +++ b/src/com/android/tv/dvr/ui/DvrGuidedActionsStylist.java @@ -17,8 +17,8 @@ package com.android.tv.dvr.ui; import android.content.Context; -import androidx.leanback.app.GuidedStepFragment; -import androidx.leanback.widget.GuidedActionsStylist; +import android.support.v17.leanback.app.GuidedStepFragment; +import android.support.v17.leanback.widget.GuidedActionsStylist; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; diff --git a/src/com/android/tv/dvr/ui/DvrGuidedStepFragment.java b/src/com/android/tv/dvr/ui/DvrGuidedStepFragment.java index fda4cdee..a900cc70 100644 --- a/src/com/android/tv/dvr/ui/DvrGuidedStepFragment.java +++ b/src/com/android/tv/dvr/ui/DvrGuidedStepFragment.java @@ -20,9 +20,9 @@ import android.app.Activity; import android.app.DialogFragment; import android.content.Context; import android.os.Bundle; -import androidx.leanback.widget.GuidanceStylist; -import androidx.leanback.widget.GuidedAction; -import androidx.leanback.widget.VerticalGridView; +import android.support.v17.leanback.widget.GuidanceStylist; +import android.support.v17.leanback.widget.GuidedAction; +import android.support.v17.leanback.widget.VerticalGridView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/src/com/android/tv/dvr/ui/DvrHalfSizedDialogFragment.java b/src/com/android/tv/dvr/ui/DvrHalfSizedDialogFragment.java index e8f501e9..e6b54f67 100644 --- a/src/com/android/tv/dvr/ui/DvrHalfSizedDialogFragment.java +++ b/src/com/android/tv/dvr/ui/DvrHalfSizedDialogFragment.java @@ -20,15 +20,13 @@ import android.app.Activity; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; +import android.support.v17.leanback.app.GuidedStepFragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import androidx.leanback.app.GuidedStepFragment; - import com.android.tv.MainActivity; import com.android.tv.R; -import com.android.tv.data.ProgramImpl; import com.android.tv.dialog.HalfSizedDialogFragment; import com.android.tv.dvr.ui.DvrConflictFragment.DvrChannelWatchConflictFragment; import com.android.tv.dvr.ui.DvrConflictFragment.DvrProgramConflictFragment; @@ -38,7 +36,7 @@ import com.android.tv.ui.DetailsActivity; public class DvrHalfSizedDialogFragment extends HalfSizedDialogFragment { /** Key for input ID. Type: String. */ public static final String KEY_INPUT_ID = "DvrHalfSizedDialogFragment.input_id"; - /** Key for the program. Type: {@link ProgramImpl}. */ + /** Key for the program. Type: {@link com.android.tv.data.Program}. */ public static final String KEY_PROGRAM = "DvrHalfSizedDialogFragment.program"; /** Key for the channel ID. Type: long. */ public static final String KEY_CHANNEL_ID = "DvrHalfSizedDialogFragment.channel_id"; diff --git a/src/com/android/tv/dvr/ui/DvrInsufficientSpaceErrorFragment.java b/src/com/android/tv/dvr/ui/DvrInsufficientSpaceErrorFragment.java index 01631b99..6fba4d98 100644 --- a/src/com/android/tv/dvr/ui/DvrInsufficientSpaceErrorFragment.java +++ b/src/com/android/tv/dvr/ui/DvrInsufficientSpaceErrorFragment.java @@ -20,8 +20,8 @@ import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.leanback.widget.GuidedAction; import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; diff --git a/src/com/android/tv/dvr/ui/DvrMissingStorageErrorFragment.java b/src/com/android/tv/dvr/ui/DvrMissingStorageErrorFragment.java index 3237acd7..02b2da1d 100644 --- a/src/com/android/tv/dvr/ui/DvrMissingStorageErrorFragment.java +++ b/src/com/android/tv/dvr/ui/DvrMissingStorageErrorFragment.java @@ -21,8 +21,8 @@ import android.content.ActivityNotFoundException; import android.content.Intent; import android.os.Bundle; import android.provider.Settings; -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.leanback.widget.GuidedAction; import android.util.Log; import com.android.tv.R; import com.android.tv.ui.DetailsActivity; diff --git a/src/com/android/tv/dvr/ui/DvrPrioritySettingsFragment.java b/src/com/android/tv/dvr/ui/DvrPrioritySettingsFragment.java index ae41f501..5bb97e90 100644 --- a/src/com/android/tv/dvr/ui/DvrPrioritySettingsFragment.java +++ b/src/com/android/tv/dvr/ui/DvrPrioritySettingsFragment.java @@ -22,9 +22,9 @@ import android.content.Context; import android.graphics.Typeface; import android.os.Build; import android.os.Bundle; -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; -import androidx.leanback.widget.GuidedActionsStylist; +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.leanback.widget.GuidedAction; +import android.support.v17.leanback.widget.GuidedActionsStylist; import android.view.View; import android.widget.ImageView; import android.widget.TextView; diff --git a/src/com/android/tv/dvr/ui/DvrScheduleFragment.java b/src/com/android/tv/dvr/ui/DvrScheduleFragment.java index 7131f626..72603d03 100644 --- a/src/com/android/tv/dvr/ui/DvrScheduleFragment.java +++ b/src/com/android/tv/dvr/ui/DvrScheduleFragment.java @@ -22,21 +22,18 @@ import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; +import android.support.v17.leanback.app.GuidedStepFragment; +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.leanback.widget.GuidedAction; import android.text.format.DateUtils; - -import androidx.leanback.app.GuidedStepFragment; -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; - import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; -import com.android.tv.data.ProgramImpl; +import com.android.tv.data.Program; 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.ui.DvrConflictFragment.DvrProgramConflictFragment; - import java.util.Collections; import java.util.List; @@ -55,7 +52,7 @@ public class DvrScheduleFragment extends DvrGuidedStepFragment { private static final int ACTION_RECORD_EPISODE = 1; private static final int ACTION_RECORD_SERIES = 2; - private ProgramImpl mProgram; + private Program mProgram; private boolean mAddCurrentProgramToSeries; @Override diff --git a/src/com/android/tv/dvr/ui/DvrSeriesDeletionActivity.java b/src/com/android/tv/dvr/ui/DvrSeriesDeletionActivity.java index 730237c4..a237f1d2 100644 --- a/src/com/android/tv/dvr/ui/DvrSeriesDeletionActivity.java +++ b/src/com/android/tv/dvr/ui/DvrSeriesDeletionActivity.java @@ -20,13 +20,15 @@ import android.app.Activity; import android.content.pm.PackageManager; import android.os.Bundle; import android.support.annotation.NonNull; -import androidx.leanback.app.GuidedStepFragment; +import android.support.v17.leanback.app.GuidedStepFragment; import android.util.Log; import android.widget.Toast; + import com.android.tv.R; import com.android.tv.Starter; import com.android.tv.TvSingletons; import com.android.tv.dvr.DvrManager; + import java.util.ArrayList; import java.util.List; @@ -68,7 +70,7 @@ public class DvrSeriesDeletionActivity extends Activity { && grantResults[0] == PackageManager.PERMISSION_GRANTED) { deleteSelectedIds(true); } else { - // NOTE: If TV app ever supports both embedded and separate DVR inputs + // NOTE: If Live TV ever supports both embedded and separate DVR inputs // then we should try to do the delete regardless. Log.i( TAG, @@ -91,14 +93,14 @@ public class DvrSeriesDeletionActivity extends Activity { dvrManager.removeRecordedPrograms(mIdsToDelete, deleteFiles); } Toast.makeText( - this, - getResources() - .getQuantityString( - R.plurals.dvr_msg_episodes_deleted, - mIdsToDelete.size(), - mIdsToDelete.size(), - recordingSize), - Toast.LENGTH_LONG) + this, + getResources() + .getQuantityString( + R.plurals.dvr_msg_episodes_deleted, + mIdsToDelete.size(), + mIdsToDelete.size(), + recordingSize), + Toast.LENGTH_LONG) .show(); finish(); } diff --git a/src/com/android/tv/dvr/ui/DvrSeriesDeletionFragment.java b/src/com/android/tv/dvr/ui/DvrSeriesDeletionFragment.java index 10ef226b..ff213231 100644 --- a/src/com/android/tv/dvr/ui/DvrSeriesDeletionFragment.java +++ b/src/com/android/tv/dvr/ui/DvrSeriesDeletionFragment.java @@ -19,10 +19,10 @@ package com.android.tv.dvr.ui; import android.content.Context; import android.media.tv.TvInputManager; import android.os.Bundle; -import androidx.leanback.app.GuidedStepFragment; -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; -import androidx.leanback.widget.GuidedActionsStylist; +import android.support.v17.leanback.app.GuidedStepFragment; +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.leanback.widget.GuidedAction; +import android.support.v17.leanback.widget.GuidedActionsStylist; import android.text.TextUtils; import android.view.ViewGroup.LayoutParams; import android.widget.Toast; diff --git a/src/com/android/tv/dvr/ui/DvrSeriesScheduledDialogActivity.java b/src/com/android/tv/dvr/ui/DvrSeriesScheduledDialogActivity.java index d72099ba..9acb5b5e 100644 --- a/src/com/android/tv/dvr/ui/DvrSeriesScheduledDialogActivity.java +++ b/src/com/android/tv/dvr/ui/DvrSeriesScheduledDialogActivity.java @@ -18,7 +18,7 @@ package com.android.tv.dvr.ui; import android.app.Activity; import android.os.Bundle; -import androidx.leanback.app.GuidedStepFragment; +import android.support.v17.leanback.app.GuidedStepFragment; import com.android.tv.R; public class DvrSeriesScheduledDialogActivity extends Activity { diff --git a/src/com/android/tv/dvr/ui/DvrSeriesScheduledFragment.java b/src/com/android/tv/dvr/ui/DvrSeriesScheduledFragment.java index 7d369904..c6e26850 100644 --- a/src/com/android/tv/dvr/ui/DvrSeriesScheduledFragment.java +++ b/src/com/android/tv/dvr/ui/DvrSeriesScheduledFragment.java @@ -20,26 +20,22 @@ import android.content.Context; import android.content.Intent; import android.graphics.drawable.Drawable; import android.os.Bundle; - -import androidx.leanback.widget.GuidanceStylist; -import androidx.leanback.widget.GuidedAction; - +import android.support.v17.leanback.widget.GuidanceStylist; +import android.support.v17.leanback.widget.GuidedAction; import com.android.tv.R; import com.android.tv.TvSingletons; -import com.android.tv.data.ProgramImpl; -import com.android.tv.data.api.Program; +import com.android.tv.data.Program; import com.android.tv.dvr.DvrScheduleManager; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.data.SeriesRecording; import com.android.tv.dvr.ui.list.DvrSchedulesActivity; import com.android.tv.dvr.ui.list.DvrSeriesSchedulesFragment; - import java.util.List; public class DvrSeriesScheduledFragment extends DvrGuidedStepFragment { /** * The key for program list which will be passed to {@link DvrSeriesSchedulesFragment}. Type: - * List<{@link ProgramImpl}> + * List<{@link Program}> */ public static final String SERIES_SCHEDULED_KEY_PROGRAMS = "series_scheduled_key_programs"; @@ -50,7 +46,6 @@ public class DvrSeriesScheduledFragment extends DvrGuidedStepFragment { private SeriesRecording mSeriesRecording; private boolean mShowViewScheduleOption; private List<Program> mPrograms; - private String mSeriesRecordingTitle; private int mSchedulesAddedCount = 0; private boolean mHasConflict = false; @@ -80,7 +75,6 @@ public class DvrSeriesScheduledFragment extends DvrGuidedStepFragment { getActivity().finish(); return; } - mSeriesRecordingTitle = mSeriesRecording.getTitle(); mPrograms = (List<Program>) BigArguments.getArgument(SERIES_SCHEDULED_KEY_PROGRAMS); BigArguments.reset(); mSchedulesAddedCount = @@ -168,7 +162,7 @@ public class DvrSeriesScheduledFragment extends DvrGuidedStepFragment { R.plurals.dvr_series_scheduled_no_conflict, mSchedulesAddedCount, mSchedulesAddedCount, - mSeriesRecordingTitle); + mSeriesRecording.getTitle()); } else { // mInThisSeriesConflictCount equals 0 and mOutThisSeriesConflictCount equals 0 means // mHasConflict is false. So we don't need to check that case. @@ -178,7 +172,7 @@ public class DvrSeriesScheduledFragment extends DvrGuidedStepFragment { R.plurals.dvr_series_scheduled_this_and_other_series_conflict, mSchedulesAddedCount, mSchedulesAddedCount, - mSeriesRecordingTitle, + mSeriesRecording.getTitle(), mInThisSeriesConflictCount + mOutThisSeriesConflictCount); } else if (mInThisSeriesConflictCount != 0) { return getResources() @@ -186,7 +180,7 @@ public class DvrSeriesScheduledFragment extends DvrGuidedStepFragment { R.plurals.dvr_series_recording_scheduled_only_this_series_conflict, mSchedulesAddedCount, mSchedulesAddedCount, - mSeriesRecordingTitle, + mSeriesRecording.getTitle(), mInThisSeriesConflictCount); } else { if (mOutThisSeriesConflictCount == 1) { @@ -195,14 +189,14 @@ public class DvrSeriesScheduledFragment extends DvrGuidedStepFragment { R.plurals.dvr_series_scheduled_only_other_series_one_conflict, mSchedulesAddedCount, mSchedulesAddedCount, - mSeriesRecordingTitle); + mSeriesRecording.getTitle()); } else { return getResources() .getQuantityString( R.plurals.dvr_series_scheduled_only_other_series_many_conflicts, mSchedulesAddedCount, mSchedulesAddedCount, - mSeriesRecordingTitle, + mSeriesRecording.getTitle(), mOutThisSeriesConflictCount); } } diff --git a/src/com/android/tv/dvr/ui/DvrSeriesSettingsActivity.java b/src/com/android/tv/dvr/ui/DvrSeriesSettingsActivity.java index eb3ca283..1a51cf46 100644 --- a/src/com/android/tv/dvr/ui/DvrSeriesSettingsActivity.java +++ b/src/com/android/tv/dvr/ui/DvrSeriesSettingsActivity.java @@ -19,13 +19,10 @@ package com.android.tv.dvr.ui; import android.app.Activity; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; - -import androidx.leanback.app.GuidedStepFragment; - +import android.support.v17.leanback.app.GuidedStepFragment; import com.android.tv.R; import com.android.tv.Starter; import com.android.tv.common.SoftPreconditions; -import com.android.tv.data.ProgramImpl; /** Activity to show details view in DVR. */ public class DvrSeriesSettingsActivity extends Activity { @@ -43,7 +40,7 @@ public class DvrSeriesSettingsActivity extends Activity { public static final String IS_WINDOW_TRANSLUCENT = "windows_translucent"; /** * Name of the program list. The list contains the programs which belong to the series. Type: - * List<{@link ProgramImpl}> + * List<{@link com.android.tv.data.Program}> */ public static final String PROGRAM_LIST = "program_list"; diff --git a/src/com/android/tv/dvr/ui/DvrSeriesSettingsFragment.java b/src/com/android/tv/dvr/ui/DvrSeriesSettingsFragment.java index 7fc201c5..eadb3b9e 100644 --- a/src/com/android/tv/dvr/ui/DvrSeriesSettingsFragment.java +++ b/src/com/android/tv/dvr/ui/DvrSeriesSettingsFragment.java @@ -21,19 +21,17 @@ import android.app.FragmentManager; import android.content.Context; import android.os.Build; import android.os.Bundle; +import android.support.v17.leanback.app.GuidedStepFragment; +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.leanback.widget.GuidedAction; +import android.support.v17.leanback.widget.GuidedActionsStylist; import android.util.LongSparseArray; - -import androidx.leanback.app.GuidedStepFragment; -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; -import androidx.leanback.widget.GuidedActionsStylist; - import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.data.ChannelDataManager; import com.android.tv.data.ChannelImpl; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.DvrManager; import com.android.tv.dvr.data.ScheduledRecording; @@ -41,7 +39,6 @@ import com.android.tv.dvr.data.SeasonEpisodeNumber; import com.android.tv.dvr.data.SeriesRecording; import com.android.tv.dvr.data.SeriesRecording.ChannelOption; import com.android.tv.dvr.recorder.SeriesRecordingScheduler; - import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -72,7 +69,6 @@ public class DvrSeriesSettingsFragment extends GuidedStepFragment private Program mCurrentProgram; private String mFragmentTitle; - private String mSeriesRecordingTitle; private String mProrityActionTitle; private String mProrityActionHighestText; private String mProrityActionLowestText; @@ -96,7 +92,6 @@ public class DvrSeriesSettingsFragment extends GuidedStepFragment getActivity().finish(); return; } - mSeriesRecordingTitle = mSeriesRecording.getTitle(); mShowViewScheduleOptionInDialog = getArguments() .getBoolean(DvrSeriesSettingsActivity.SHOW_VIEW_SCHEDULE_OPTION_IN_DIALOG); @@ -166,8 +161,9 @@ public class DvrSeriesSettingsFragment extends GuidedStepFragment @Override public Guidance onCreateGuidance(Bundle savedInstanceState) { + String breadcrumb = mSeriesRecording.getTitle(); String title = mFragmentTitle; - return new Guidance(title, null, mSeriesRecordingTitle, null); + return new Guidance(title, null, breadcrumb, null); } @Override diff --git a/src/com/android/tv/dvr/ui/DvrStopRecordingFragment.java b/src/com/android/tv/dvr/ui/DvrStopRecordingFragment.java index 1475a8c3..1ab4c500 100644 --- a/src/com/android/tv/dvr/ui/DvrStopRecordingFragment.java +++ b/src/com/android/tv/dvr/ui/DvrStopRecordingFragment.java @@ -23,17 +23,13 @@ import android.os.Build; import android.os.Bundle; import android.support.annotation.IntDef; import android.support.annotation.NonNull; - -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; - +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.leanback.widget.GuidedAction; import com.android.tv.R; import com.android.tv.TvSingletons; -import com.android.tv.data.ProgramImpl; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.DvrDataManager.ScheduledRecordingListener; import com.android.tv.dvr.data.ScheduledRecording; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; @@ -48,7 +44,7 @@ import java.util.List; public class DvrStopRecordingFragment extends DvrGuidedStepFragment { /** The action ID for the stop action. */ public static final int ACTION_STOP = 1; - /** Key for the program. Type: {@link ProgramImpl}. */ + /** Key for the program. Type: {@link com.android.tv.data.Program}. */ public static final String KEY_REASON = "DvrStopRecordingFragment.type"; @Retention(RetentionPolicy.SOURCE) diff --git a/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingDialogFragment.java b/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingDialogFragment.java index 4a8ce04e..15abf902 100644 --- a/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingDialogFragment.java +++ b/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingDialogFragment.java @@ -18,7 +18,7 @@ package com.android.tv.dvr.ui; import android.app.DialogFragment; import android.os.Bundle; -import androidx.leanback.app.GuidedStepFragment; +import android.support.v17.leanback.app.GuidedStepFragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingFragment.java b/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingFragment.java index 0b8f5df0..99211fdb 100644 --- a/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingFragment.java +++ b/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingFragment.java @@ -20,8 +20,8 @@ import android.app.Activity; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.support.annotation.NonNull; -import androidx.leanback.widget.GuidanceStylist; -import androidx.leanback.widget.GuidedAction; +import android.support.v17.leanback.widget.GuidanceStylist; +import android.support.v17.leanback.widget.GuidedAction; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/src/com/android/tv/dvr/ui/DvrUiHelper.java b/src/com/android/tv/dvr/ui/DvrUiHelper.java index 657abfa2..a121cf99 100644 --- a/src/com/android/tv/dvr/ui/DvrUiHelper.java +++ b/src/com/android/tv/dvr/ui/DvrUiHelper.java @@ -33,7 +33,6 @@ import android.text.Html; import android.text.Spannable; import android.text.SpannableString; import android.text.SpannableStringBuilder; -import android.text.Spanned; import android.text.TextUtils; import android.text.style.TextAppearanceSpan; import android.widget.ImageView; @@ -45,9 +44,9 @@ import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.recording.RecordingStorageStatusManager; import com.android.tv.common.util.CommonUtils; -import com.android.tv.data.api.BaseProgram; +import com.android.tv.data.BaseProgram; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dialog.HalfSizedDialogFragment; import com.android.tv.dvr.DvrManager; import com.android.tv.dvr.data.RecordedProgram; @@ -76,7 +75,6 @@ import com.android.tv.ui.DetailsActivity; import com.android.tv.util.ToastUtils; import com.android.tv.util.Utils; -import com.google.common.collect.ImmutableList; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -124,7 +122,7 @@ public class DvrUiHelper { return; } Bundle args = new Bundle(); - args.putParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM, program.toParcelable()); + args.putParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM, program); args.putBoolean( DvrScheduleFragment.KEY_ADD_CURRENT_PROGRAM_TO_SERIES, addCurrentProgramToSeries); showDialogFragment(activity, new DvrScheduleDialogFragment(), args, true, true); @@ -146,7 +144,7 @@ public class DvrUiHelper { return; } Bundle args = new Bundle(); - args.putParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM, program.toParcelable()); + args.putParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM, program); showDialogFragment(activity, new DvrProgramConflictDialogFragment(), args, false, true); } @@ -229,7 +227,7 @@ public class DvrUiHelper { return; } Bundle args = new Bundle(); - args.putParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM, program.toParcelable()); + args.putParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM, program); showDialogFragment(activity, new DvrAlreadyScheduledDialogFragment(), args, false, true); } @@ -239,18 +237,14 @@ public class DvrUiHelper { return; } Bundle args = new Bundle(); - args.putParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM, program.toParcelable()); + args.putParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM, program); showDialogFragment(activity, new DvrAlreadyRecordedDialogFragment(), args, false, true); } /** Shows program information dialog. */ public static void showWriteStoragePermissionRationaleDialog(Activity activity) { - showDialogFragment( - activity, - new DvrWriteStoragePermissionRationaleDialogFragment(), - new Bundle(), - false, - false); + showDialogFragment(activity, new DvrWriteStoragePermissionRationaleDialogFragment(), + new Bundle(), false, false); } /** @@ -465,7 +459,7 @@ public class DvrUiHelper { boolean removeEmptySeriesSchedule, boolean isWindowTranslucent, boolean showViewScheduleOptionInDialog, - @Nullable Program currentProgram) { + Program currentProgram) { SeriesRecording series = TvSingletons.getSingletons(context) .getDvrDataManager() @@ -487,15 +481,13 @@ public class DvrUiHelper { new EpisodicProgramLoadTask(context, series) { @Override protected void onPostExecute(List<Program> loadedPrograms) { - if (sProgressDialog != null) { - sProgressDialog.dismiss(); - sProgressDialog = null; - } + sProgressDialog.dismiss(); + sProgressDialog = null; startSeriesSettingsActivityInternal( context, seriesRecordingId, loadedPrograms == null - ? ImmutableList.of() + ? Collections.EMPTY_LIST : loadedPrograms, removeEmptySeriesSchedule, isWindowTranslucent, @@ -532,7 +524,7 @@ public class DvrUiHelper { boolean removeEmptySeriesSchedule, boolean isWindowTranslucent, boolean showViewScheduleOptionInDialog, - @Nullable Program currentProgram) { + Program currentProgram) { SoftPreconditions.checkState( programs != null, TAG, "Start series settings activity but programs is null"); Intent intent = new Intent(context, DvrSeriesSettingsActivity.class); @@ -545,9 +537,7 @@ public class DvrUiHelper { intent.putExtra( DvrSeriesSettingsActivity.SHOW_VIEW_SCHEDULE_OPTION_IN_DIALOG, showViewScheduleOptionInDialog); - if (currentProgram != null) { - intent.putExtra(DvrSeriesSettingsActivity.CURRENT_PROGRAM, currentProgram.toParcelable()); - } + intent.putExtra(DvrSeriesSettingsActivity.CURRENT_PROGRAM, currentProgram); context.startActivity(intent); } @@ -692,18 +682,16 @@ public class DvrUiHelper { } SpannableStringBuilder builder; if (TextUtils.isEmpty(seasonNumber) || seasonNumber.equals("0")) { - Spanned temp = + builder = TextUtils.isEmpty(episodeNumber) - ? SpannableStringBuilder.valueOf(title) - : Html.fromHtml( - context.getString( - R.string.program_title_with_episode_number_no_season, - title, - episodeNumber)); - builder = SpannableStringBuilder.valueOf(temp); + ? new SpannableStringBuilder(title) + : new SpannableStringBuilder(Html.fromHtml(context.getString( + R.string.program_title_with_episode_number_no_season, + title, + episodeNumber))); } else { builder = - SpannableStringBuilder.valueOf( + new SpannableStringBuilder( Html.fromHtml( context.getString( R.string.program_title_with_episode_number, diff --git a/src/com/android/tv/dvr/ui/DvrWriteStoragePermissionRationaleFragment.java b/src/com/android/tv/dvr/ui/DvrWriteStoragePermissionRationaleFragment.java index 25f7f38b..c93f5831 100644 --- a/src/com/android/tv/dvr/ui/DvrWriteStoragePermissionRationaleFragment.java +++ b/src/com/android/tv/dvr/ui/DvrWriteStoragePermissionRationaleFragment.java @@ -19,8 +19,8 @@ package com.android.tv.dvr.ui; import android.app.Activity; import android.content.res.Resources; import android.os.Bundle; -import androidx.leanback.widget.GuidanceStylist; -import androidx.leanback.widget.GuidedAction; +import android.support.v17.leanback.widget.GuidanceStylist; +import android.support.v17.leanback.widget.GuidedAction; import com.android.tv.R; diff --git a/src/com/android/tv/dvr/ui/SortedArrayAdapter.java b/src/com/android/tv/dvr/ui/SortedArrayAdapter.java index 7a26d5ed..1eb8080a 100644 --- a/src/com/android/tv/dvr/ui/SortedArrayAdapter.java +++ b/src/com/android/tv/dvr/ui/SortedArrayAdapter.java @@ -17,8 +17,8 @@ package com.android.tv.dvr.ui; import android.support.annotation.VisibleForTesting; -import androidx.leanback.widget.ArrayObjectAdapter; -import androidx.leanback.widget.PresenterSelector; +import android.support.v17.leanback.widget.ArrayObjectAdapter; +import android.support.v17.leanback.widget.PresenterSelector; import com.android.tv.common.SoftPreconditions; import java.util.ArrayList; import java.util.Collection; diff --git a/src/com/android/tv/dvr/ui/TrackedGuidedStepFragment.java b/src/com/android/tv/dvr/ui/TrackedGuidedStepFragment.java index c0a57c0f..0172f76f 100644 --- a/src/com/android/tv/dvr/ui/TrackedGuidedStepFragment.java +++ b/src/com/android/tv/dvr/ui/TrackedGuidedStepFragment.java @@ -17,8 +17,8 @@ package com.android.tv.dvr.ui; import android.content.Context; -import androidx.leanback.app.GuidedStepFragment; -import androidx.leanback.widget.GuidedAction; +import android.support.v17.leanback.app.GuidedStepFragment; +import android.support.v17.leanback.widget.GuidedAction; import com.android.tv.TvSingletons; import com.android.tv.analytics.Tracker; diff --git a/src/com/android/tv/dvr/ui/browse/ActionPresenterSelector.java b/src/com/android/tv/dvr/ui/browse/ActionPresenterSelector.java index a06705c6..41ace9a4 100644 --- a/src/com/android/tv/dvr/ui/browse/ActionPresenterSelector.java +++ b/src/com/android/tv/dvr/ui/browse/ActionPresenterSelector.java @@ -17,10 +17,10 @@ package com.android.tv.dvr.ui.browse; import android.graphics.drawable.Drawable; -import androidx.leanback.R; -import androidx.leanback.widget.Action; -import androidx.leanback.widget.Presenter; -import androidx.leanback.widget.PresenterSelector; +import android.support.v17.leanback.R; +import android.support.v17.leanback.widget.Action; +import android.support.v17.leanback.widget.Presenter; +import android.support.v17.leanback.widget.PresenterSelector; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; diff --git a/src/com/android/tv/dvr/ui/browse/CurrentRecordingDetailsFragment.java b/src/com/android/tv/dvr/ui/browse/CurrentRecordingDetailsFragment.java index 88ef112f..8c311d68 100644 --- a/src/com/android/tv/dvr/ui/browse/CurrentRecordingDetailsFragment.java +++ b/src/com/android/tv/dvr/ui/browse/CurrentRecordingDetailsFragment.java @@ -19,13 +19,12 @@ package com.android.tv.dvr.ui.browse; import android.content.Context; import android.content.res.Resources; import android.media.tv.TvInputManager; - -import androidx.leanback.widget.Action; -import androidx.leanback.widget.OnActionClickedListener; -import androidx.leanback.widget.SparseArrayObjectAdapter; - +import android.support.v17.leanback.widget.Action; +import android.support.v17.leanback.widget.OnActionClickedListener; +import android.support.v17.leanback.widget.SparseArrayObjectAdapter; import com.android.tv.R; import com.android.tv.TvSingletons; +import com.android.tv.common.flags.has.HasConcurrentDvrPlaybackFlags; import com.android.tv.dialog.HalfSizedDialogFragment; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.DvrManager; @@ -34,10 +33,7 @@ import com.android.tv.dvr.data.RecordedProgram; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.ui.DvrStopRecordingFragment; import com.android.tv.dvr.ui.DvrUiHelper; - -import dagger.android.AndroidInjection; - -import javax.inject.Inject; +import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags; /** {@link RecordingDetailsFragment} for current recording in DVR. */ public class CurrentRecordingDetailsFragment extends RecordingDetailsFragment { @@ -47,7 +43,8 @@ public class CurrentRecordingDetailsFragment extends RecordingDetailsFragment { private DvrDataManager mDvrDataManger; private RecordedProgram mRecordedProgram; - @Inject DvrWatchedPositionManager mDvrWatchedPositionManager; + private DvrWatchedPositionManager mDvrWatchedPositionManager; + private ConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags; private boolean mPaused; private final DvrDataManager.ScheduledRecordingListener mScheduledRecordingListener = new DvrDataManager.ScheduledRecordingListener() { @@ -79,10 +76,12 @@ public class CurrentRecordingDetailsFragment extends RecordingDetailsFragment { @Override public void onAttach(Context context) { - AndroidInjection.inject(this); super.onAttach(context); mDvrDataManger = TvSingletons.getSingletons(context).getDvrDataManager(); mDvrDataManger.addScheduledRecordingListener(mScheduledRecordingListener); + mDvrWatchedPositionManager = + TvSingletons.getSingletons(getActivity()).getDvrWatchedPositionManager(); + mConcurrentDvrPlaybackFlags = HasConcurrentDvrPlaybackFlags.fromContext(context); } @Override @@ -116,7 +115,9 @@ public class CurrentRecordingDetailsFragment extends RecordingDetailsFragment { res.getString(R.string.dvr_detail_stop_recording), null, res.getDrawable(R.drawable.lb_ic_stop))); - if (mRecordedProgram != null && mRecordedProgram.isPartial()) { + if (mConcurrentDvrPlaybackFlags.enabled() + && mRecordedProgram != null + && mRecordedProgram.isPartial()) { if (mDvrWatchedPositionManager.getWatchedStatus(mRecordedProgram) == DvrWatchedPositionManager.DVR_WATCHED_STATUS_WATCHING) { adapter.set( diff --git a/src/com/android/tv/dvr/ui/browse/DetailsContent.java b/src/com/android/tv/dvr/ui/browse/DetailsContent.java index b5e05264..e179743c 100644 --- a/src/com/android/tv/dvr/ui/browse/DetailsContent.java +++ b/src/com/android/tv/dvr/ui/browse/DetailsContent.java @@ -20,11 +20,10 @@ import android.content.Context; import android.media.tv.TvContract; import android.support.annotation.Nullable; import android.text.TextUtils; - import com.android.tv.R; import com.android.tv.TvSingletons; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dvr.data.RecordedProgram; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.data.SeriesRecording; @@ -127,10 +126,9 @@ public class DetailsContent { } private static String getErrorMessage(Context context, ScheduledRecording recording) { - int reason = - recording.getFailedReason() == null - ? ScheduledRecording.FAILED_REASON_OTHER - : recording.getFailedReason(); + int reason = recording.getFailedReason() == null + ? ScheduledRecording.FAILED_REASON_OTHER + : recording.getFailedReason(); switch (reason) { case ScheduledRecording.FAILED_REASON_PROGRAM_ENDED_BEFORE_RECORDING_STARTED: return context.getString(R.string.dvr_recording_failed_not_started); @@ -138,7 +136,8 @@ public class DetailsContent { return context.getString(R.string.dvr_recording_failed_resource_busy); case ScheduledRecording.FAILED_REASON_INPUT_UNAVAILABLE: return context.getString( - R.string.dvr_recording_failed_input_unavailable, recording.getInputId()); + R.string.dvr_recording_failed_input_unavailable, + recording.getInputId()); case ScheduledRecording.FAILED_REASON_INPUT_DVR_UNSUPPORTED: return context.getString(R.string.dvr_recording_failed_input_dvr_unsupported); case ScheduledRecording.FAILED_REASON_INSUFFICIENT_SPACE: diff --git a/src/com/android/tv/dvr/ui/browse/DetailsContentPresenter.java b/src/com/android/tv/dvr/ui/browse/DetailsContentPresenter.java index fafc70cf..6b5fd1fd 100644 --- a/src/com/android/tv/dvr/ui/browse/DetailsContentPresenter.java +++ b/src/com/android/tv/dvr/ui/browse/DetailsContentPresenter.java @@ -24,7 +24,7 @@ import android.app.Activity; import android.content.Context; import android.graphics.Paint; import android.graphics.Paint.FontMetricsInt; -import androidx.leanback.widget.Presenter; +import android.support.v17.leanback.widget.Presenter; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; @@ -40,10 +40,10 @@ import com.android.tv.util.Utils; /** * An {@link Presenter} for rendering a detailed description of an DVR item. Typically this * Presenter will be used in a {@link - * androidx.leanback.widget.DetailsOverviewRowPresenter}. Most codes of this class is - * originated from {@link androidx.leanback.widget.AbstractDetailsDescriptionPresenter}. + * android.support.v17.leanback.widget.DetailsOverviewRowPresenter}. Most codes of this class is + * originated from {@link android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter}. * The latter class are re-used to provide a customized version of {@link - * androidx.leanback.widget.DetailsOverviewRow}. + * android.support.v17.leanback.widget.DetailsOverviewRow}. */ public class DetailsContentPresenter extends Presenter { /** The ViewHolder for the {@link DetailsContentPresenter}. */ diff --git a/src/com/android/tv/dvr/ui/browse/DetailsViewBackgroundHelper.java b/src/com/android/tv/dvr/ui/browse/DetailsViewBackgroundHelper.java index 8a4c7854..4e41daee 100644 --- a/src/com/android/tv/dvr/ui/browse/DetailsViewBackgroundHelper.java +++ b/src/com/android/tv/dvr/ui/browse/DetailsViewBackgroundHelper.java @@ -21,7 +21,7 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Handler; -import androidx.leanback.app.BackgroundManager; +import android.support.v17.leanback.app.BackgroundManager; /** The Background Helper. */ public class DetailsViewBackgroundHelper { diff --git a/src/com/android/tv/dvr/ui/browse/DvrBrowseActivity.java b/src/com/android/tv/dvr/ui/browse/DvrBrowseActivity.java index 7262b4a0..5743ea5c 100644 --- a/src/com/android/tv/dvr/ui/browse/DvrBrowseActivity.java +++ b/src/com/android/tv/dvr/ui/browse/DvrBrowseActivity.java @@ -22,13 +22,13 @@ import android.media.tv.TvInputManager; import android.os.Bundle; import com.android.tv.R; import com.android.tv.Starter; -import com.android.tv.perf.StartupMeasureFactory; +import com.android.tv.perf.PerformanceMonitorManagerFactory; /** {@link android.app.Activity} for DVR UI. */ public class DvrBrowseActivity extends Activity { { - StartupMeasureFactory.create().onActivityInit(); + PerformanceMonitorManagerFactory.create().getStartupMeasure().onActivityInit(); } private DvrBrowseFragment mFragment; diff --git a/src/com/android/tv/dvr/ui/browse/DvrBrowseFragment.java b/src/com/android/tv/dvr/ui/browse/DvrBrowseFragment.java index 786942e0..17ba1939 100644 --- a/src/com/android/tv/dvr/ui/browse/DvrBrowseFragment.java +++ b/src/com/android/tv/dvr/ui/browse/DvrBrowseFragment.java @@ -21,14 +21,13 @@ import android.content.Context; import android.os.Build; import android.os.Bundle; import android.os.Handler; -import android.text.TextUtils; -import androidx.leanback.app.BrowseFragment; -import androidx.leanback.widget.ArrayObjectAdapter; -import androidx.leanback.widget.ClassPresenterSelector; -import androidx.leanback.widget.HeaderItem; -import androidx.leanback.widget.ListRow; -import androidx.leanback.widget.Presenter; -import androidx.leanback.widget.TitleViewAdapter; +import android.support.v17.leanback.app.BrowseFragment; +import android.support.v17.leanback.widget.ArrayObjectAdapter; +import android.support.v17.leanback.widget.ClassPresenterSelector; +import android.support.v17.leanback.widget.HeaderItem; +import android.support.v17.leanback.widget.ListRow; +import android.support.v17.leanback.widget.Presenter; +import android.support.v17.leanback.widget.TitleViewAdapter; import android.util.Log; import android.view.View; import android.view.ViewTreeObserver.OnGlobalFocusChangeListener; @@ -476,7 +475,7 @@ public class DvrBrowseFragment extends BrowseFragment mRecentAdapter.add(recordedProgram); String seriesId = recordedProgram.getSeriesId(); SeriesRecording seriesRecording = null; - if (!TextUtils.isEmpty(seriesId)) { + if (seriesId != null) { seriesRecording = mDvrDataManager.getSeriesRecording(seriesId); RecordedProgram latestProgram = mSeriesId2LatestProgram.get(seriesId); if (latestProgram == null @@ -500,7 +499,7 @@ public class DvrBrowseFragment extends BrowseFragment private void handleRecordedProgramRemoved(RecordedProgram recordedProgram) { mRecentAdapter.remove(recordedProgram); String seriesId = recordedProgram.getSeriesId(); - if (!TextUtils.isEmpty(seriesId)) { + if (seriesId != null) { SeriesRecording seriesRecording = mDvrDataManager.getSeriesRecording(seriesId); RecordedProgram latestProgram = mSeriesId2LatestProgram.get(recordedProgram.getSeriesId()); @@ -521,7 +520,7 @@ public class DvrBrowseFragment extends BrowseFragment mRecentAdapter.change(recordedProgram); String seriesId = recordedProgram.getSeriesId(); SeriesRecording seriesRecording = null; - if (!TextUtils.isEmpty(seriesId)) { + if (seriesId != null) { seriesRecording = mDvrDataManager.getSeriesRecording(seriesId); RecordedProgram latestProgram = mSeriesId2LatestProgram.get(seriesId); if (latestProgram == null @@ -664,7 +663,7 @@ public class DvrBrowseFragment extends BrowseFragment } } if (getSelectedPosition() >= mRowsAdapter.size()) { - setSelectedPosition(mRowsAdapter.size() - 1); + setSelectedPosition(mRecentAdapter.size() - 1); } } diff --git a/src/com/android/tv/dvr/ui/browse/DvrDetailsFragment.java b/src/com/android/tv/dvr/ui/browse/DvrDetailsFragment.java index a38180a5..f90981f0 100644 --- a/src/com/android/tv/dvr/ui/browse/DvrDetailsFragment.java +++ b/src/com/android/tv/dvr/ui/browse/DvrDetailsFragment.java @@ -25,15 +25,15 @@ import android.media.tv.TvContentRating; import android.net.Uri; import android.os.Bundle; import android.support.annotation.Nullable; -import androidx.leanback.app.DetailsFragment; -import androidx.leanback.widget.ArrayObjectAdapter; -import androidx.leanback.widget.ClassPresenterSelector; -import androidx.leanback.widget.DetailsOverviewRow; -import androidx.leanback.widget.DetailsOverviewRowPresenter; -import androidx.leanback.widget.OnActionClickedListener; -import androidx.leanback.widget.PresenterSelector; -import androidx.leanback.widget.SparseArrayObjectAdapter; -import androidx.leanback.widget.VerticalGridView; +import android.support.v17.leanback.app.DetailsFragment; +import android.support.v17.leanback.widget.ArrayObjectAdapter; +import android.support.v17.leanback.widget.ClassPresenterSelector; +import android.support.v17.leanback.widget.DetailsOverviewRow; +import android.support.v17.leanback.widget.DetailsOverviewRowPresenter; +import android.support.v17.leanback.widget.OnActionClickedListener; +import android.support.v17.leanback.widget.PresenterSelector; +import android.support.v17.leanback.widget.SparseArrayObjectAdapter; +import android.support.v17.leanback.widget.VerticalGridView; import android.text.TextUtils; import android.widget.Toast; import com.android.tv.R; diff --git a/src/com/android/tv/dvr/ui/browse/DvrItemPresenter.java b/src/com/android/tv/dvr/ui/browse/DvrItemPresenter.java index ebdee32f..4298d86a 100644 --- a/src/com/android/tv/dvr/ui/browse/DvrItemPresenter.java +++ b/src/com/android/tv/dvr/ui/browse/DvrItemPresenter.java @@ -19,7 +19,7 @@ package com.android.tv.dvr.ui.browse; import android.app.Activity; import android.content.Context; import android.support.annotation.CallSuper; -import androidx.leanback.widget.Presenter; +import android.support.v17.leanback.widget.Presenter; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; diff --git a/src/com/android/tv/dvr/ui/browse/DvrListRowPresenter.java b/src/com/android/tv/dvr/ui/browse/DvrListRowPresenter.java index 625f8f76..a2d1cb28 100644 --- a/src/com/android/tv/dvr/ui/browse/DvrListRowPresenter.java +++ b/src/com/android/tv/dvr/ui/browse/DvrListRowPresenter.java @@ -17,7 +17,7 @@ package com.android.tv.dvr.ui.browse; import android.content.Context; -import androidx.leanback.widget.ListRowPresenter; +import android.support.v17.leanback.widget.ListRowPresenter; import android.view.ViewGroup; import com.android.tv.R; diff --git a/src/com/android/tv/dvr/ui/browse/RecordedProgramDetailsFragment.java b/src/com/android/tv/dvr/ui/browse/RecordedProgramDetailsFragment.java index 5f58af8e..bf963547 100644 --- a/src/com/android/tv/dvr/ui/browse/RecordedProgramDetailsFragment.java +++ b/src/com/android/tv/dvr/ui/browse/RecordedProgramDetailsFragment.java @@ -19,9 +19,9 @@ package com.android.tv.dvr.ui.browse; import android.content.res.Resources; import android.media.tv.TvInputManager; import android.os.Bundle; -import androidx.leanback.widget.Action; -import androidx.leanback.widget.OnActionClickedListener; -import androidx.leanback.widget.SparseArrayObjectAdapter; +import android.support.v17.leanback.widget.Action; +import android.support.v17.leanback.widget.OnActionClickedListener; +import android.support.v17.leanback.widget.SparseArrayObjectAdapter; import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.common.util.PermissionUtils; @@ -32,7 +32,7 @@ import com.android.tv.dvr.data.RecordedProgram; import com.android.tv.dvr.ui.DvrUiHelper; import com.android.tv.ui.DetailsActivity; -/** {@link androidx.leanback.app.DetailsFragment} for recorded program in DVR. */ +/** {@link android.support.v17.leanback.app.DetailsFragment} for recorded program in DVR. */ public class RecordedProgramDetailsFragment extends DvrDetailsFragment implements DvrDataManager.RecordedProgramListener { private static final int ACTION_RESUME_PLAYING = 1; diff --git a/src/com/android/tv/dvr/ui/browse/RecordingCardView.java b/src/com/android/tv/dvr/ui/browse/RecordingCardView.java index ac7c5745..c83ceaf0 100644 --- a/src/com/android/tv/dvr/ui/browse/RecordingCardView.java +++ b/src/com/android/tv/dvr/ui/browse/RecordingCardView.java @@ -23,16 +23,14 @@ import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.support.annotation.Nullable; -import android.text.Layout; +import android.support.v17.leanback.widget.BaseCardView; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; -import android.view.ViewTreeObserver; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; -import androidx.leanback.widget.BaseCardView; import com.android.tv.R; import com.android.tv.dvr.data.RecordedProgram; import com.android.tv.ui.ViewUtils; @@ -44,7 +42,7 @@ import com.android.tv.util.images.ImageLoader; */ public class RecordingCardView extends BaseCardView { // This value should be the same with - // androidx.leanback.widget.FocusHighlightHelper.BrowseItemFocusHighlight.DURATION_MS + // android.support.v17.leanback.widget.FocusHighlightHelper.BrowseItemFocusHighlight.DURATION_MS private static final int ANIMATION_DURATION = 150; private final ImageView mImageView; private final int mImageWidth; @@ -64,7 +62,6 @@ public class RecordingCardView extends BaseCardView { private final boolean mExpandTitleWhenFocused; private boolean mExpanded; private String mDetailBackgroundImageUri; - private Layout mTitleViewLayout; public RecordingCardView(Context context) { this(context, false); @@ -123,14 +120,6 @@ public class RecordingCardView extends BaseCardView { * value)); } }); - getViewTreeObserver().addOnGlobalLayoutListener( - new ViewTreeObserver.OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - getViewTreeObserver().removeOnGlobalLayoutListener(this); - mTitleViewLayout = mFoldedTitleView.getLayout(); - } - }); mExpandTitleWhenFocused = expandTitleWhenFocused; } @@ -165,8 +154,7 @@ public class RecordingCardView extends BaseCardView { * @param withAnimation {@code true} to expand/fold with animation. */ public void expandTitle(boolean expand, boolean withAnimation) { - if (expand != mExpanded && mTitleViewLayout != null - && mTitleViewLayout.getEllipsisCount(0) > 0) { + if (expand != mExpanded && mFoldedTitleView.getLayout().getEllipsisCount(0) > 0) { if (withAnimation) { if (expand) { mExpandTitleAnimator.start(); diff --git a/src/com/android/tv/dvr/ui/browse/RecordingDetailsFragment.java b/src/com/android/tv/dvr/ui/browse/RecordingDetailsFragment.java index e85f983f..243681c6 100644 --- a/src/com/android/tv/dvr/ui/browse/RecordingDetailsFragment.java +++ b/src/com/android/tv/dvr/ui/browse/RecordingDetailsFragment.java @@ -17,7 +17,7 @@ package com.android.tv.dvr.ui.browse; import android.os.Bundle; -import androidx.leanback.app.DetailsFragment; +import android.support.v17.leanback.app.DetailsFragment; import com.android.tv.TvSingletons; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.ui.DetailsActivity; diff --git a/src/com/android/tv/dvr/ui/browse/ScheduledRecordingDetailsFragment.java b/src/com/android/tv/dvr/ui/browse/ScheduledRecordingDetailsFragment.java index 7ef8e59f..f08bb12b 100644 --- a/src/com/android/tv/dvr/ui/browse/ScheduledRecordingDetailsFragment.java +++ b/src/com/android/tv/dvr/ui/browse/ScheduledRecordingDetailsFragment.java @@ -18,9 +18,9 @@ package com.android.tv.dvr.ui.browse; import android.content.res.Resources; import android.os.Bundle; -import androidx.leanback.widget.Action; -import androidx.leanback.widget.OnActionClickedListener; -import androidx.leanback.widget.SparseArrayObjectAdapter; +import android.support.v17.leanback.widget.Action; +import android.support.v17.leanback.widget.OnActionClickedListener; +import android.support.v17.leanback.widget.SparseArrayObjectAdapter; import com.android.tv.R; import com.android.tv.TvSingletons; diff --git a/src/com/android/tv/dvr/ui/browse/SeriesRecordingDetailsFragment.java b/src/com/android/tv/dvr/ui/browse/SeriesRecordingDetailsFragment.java index 1c020091..9104ef10 100644 --- a/src/com/android/tv/dvr/ui/browse/SeriesRecordingDetailsFragment.java +++ b/src/com/android/tv/dvr/ui/browse/SeriesRecordingDetailsFragment.java @@ -21,21 +21,21 @@ import android.graphics.drawable.Drawable; import android.media.tv.TvInputManager; import android.os.Bundle; import android.support.annotation.Nullable; +import android.support.v17.leanback.app.DetailsFragment; +import android.support.v17.leanback.widget.Action; +import android.support.v17.leanback.widget.ArrayObjectAdapter; +import android.support.v17.leanback.widget.ClassPresenterSelector; +import android.support.v17.leanback.widget.DetailsOverviewRow; +import android.support.v17.leanback.widget.DetailsOverviewRowPresenter; +import android.support.v17.leanback.widget.HeaderItem; +import android.support.v17.leanback.widget.ListRow; +import android.support.v17.leanback.widget.OnActionClickedListener; +import android.support.v17.leanback.widget.PresenterSelector; +import android.support.v17.leanback.widget.SparseArrayObjectAdapter; import android.text.TextUtils; -import androidx.leanback.app.DetailsFragment; -import androidx.leanback.widget.Action; -import androidx.leanback.widget.ArrayObjectAdapter; -import androidx.leanback.widget.ClassPresenterSelector; -import androidx.leanback.widget.DetailsOverviewRow; -import androidx.leanback.widget.DetailsOverviewRowPresenter; -import androidx.leanback.widget.HeaderItem; -import androidx.leanback.widget.ListRow; -import androidx.leanback.widget.OnActionClickedListener; -import androidx.leanback.widget.PresenterSelector; -import androidx.leanback.widget.SparseArrayObjectAdapter; import com.android.tv.R; import com.android.tv.TvSingletons; -import com.android.tv.data.api.BaseProgram; +import com.android.tv.data.BaseProgram; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.DvrWatchedPositionManager; import com.android.tv.dvr.data.RecordedProgram; diff --git a/src/com/android/tv/dvr/ui/list/BaseDvrSchedulesFragment.java b/src/com/android/tv/dvr/ui/list/BaseDvrSchedulesFragment.java index 293e1d94..77a63508 100644 --- a/src/com/android/tv/dvr/ui/list/BaseDvrSchedulesFragment.java +++ b/src/com/android/tv/dvr/ui/list/BaseDvrSchedulesFragment.java @@ -17,8 +17,8 @@ package com.android.tv.dvr.ui.list; import android.os.Bundle; -import androidx.leanback.app.DetailsFragment; -import androidx.leanback.widget.ClassPresenterSelector; +import android.support.v17.leanback.app.DetailsFragment; +import android.support.v17.leanback.widget.ClassPresenterSelector; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/src/com/android/tv/dvr/ui/list/DvrHistoryFragment.java b/src/com/android/tv/dvr/ui/list/DvrHistoryFragment.java index 1d93c8cb..0ca05fac 100644 --- a/src/com/android/tv/dvr/ui/list/DvrHistoryFragment.java +++ b/src/com/android/tv/dvr/ui/list/DvrHistoryFragment.java @@ -17,24 +17,23 @@ package com.android.tv.dvr.ui.list; import android.os.Bundle; +import android.support.v17.leanback.app.DetailsFragment; +import android.support.v17.leanback.widget.ClassPresenterSelector; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; -import androidx.leanback.app.DetailsFragment; -import androidx.leanback.widget.ClassPresenterSelector; import com.android.tv.R; import com.android.tv.TvSingletons; 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.ui.list.SchedulesHeaderRowPresenter.DateHeaderRowPresenter; -import com.android.tv.common.flags.UiFlags; /** A fragment to show the DVR history. */ public class DvrHistoryFragment extends DetailsFragment implements DvrDataManager.ScheduledRecordingListener, - DvrDataManager.RecordedProgramListener { + DvrDataManager.RecordedProgramListener { private DvrHistoryRowAdapter mRowsAdapter; private TextView mEmptyInfoScreenView; @@ -49,17 +48,11 @@ public class DvrHistoryFragment extends DetailsFragment presenterSelector.addClassPresenter( ScheduleRow.class, new ScheduleRowPresenter(getContext())); TvSingletons singletons = TvSingletons.getSingletons(getContext()); - UiFlags uiFlags = singletons.getUiFlags(); - mDvrDataManager = singletons.getDvrDataManager(); - mRowsAdapter = - new DvrHistoryRowAdapter( - getContext(), - presenterSelector, - singletons.getClock(), - mDvrDataManager, - uiFlags); + mRowsAdapter = new DvrHistoryRowAdapter( + getContext(), presenterSelector, singletons.getClock()); setAdapter(mRowsAdapter); mRowsAdapter.start(); + mDvrDataManager = singletons.getDvrDataManager(); mDvrDataManager.addScheduledRecordingListener(this); mDvrDataManager.addRecordedProgramListener(this); mEmptyInfoScreenView = (TextView) getActivity().findViewById(R.id.empty_info_screen); @@ -142,6 +135,7 @@ public class DvrHistoryFragment extends DetailsFragment hideEmptyMessage(); } } + } @Override diff --git a/src/com/android/tv/dvr/ui/list/DvrHistoryRowAdapter.java b/src/com/android/tv/dvr/ui/list/DvrHistoryRowAdapter.java index a10367fb..156d1a7e 100644 --- a/src/com/android/tv/dvr/ui/list/DvrHistoryRowAdapter.java +++ b/src/com/android/tv/dvr/ui/list/DvrHistoryRowAdapter.java @@ -20,19 +20,20 @@ import android.annotation.TargetApi; import android.content.Context; import android.os.Build.VERSION_CODES; import android.support.annotation.Nullable; +import android.support.v17.leanback.widget.ArrayObjectAdapter; +import android.support.v17.leanback.widget.ClassPresenterSelector; import android.text.format.DateUtils; import android.util.Log; -import androidx.leanback.widget.ArrayObjectAdapter; -import androidx.leanback.widget.ClassPresenterSelector; import com.android.tv.R; +import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.util.Clock; 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.recorder.ScheduledProgramReaper; import com.android.tv.dvr.ui.list.SchedulesHeaderRow.DateHeaderRow; import com.android.tv.util.Utils; -import com.android.tv.common.flags.UiFlags; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -47,8 +48,8 @@ class DvrHistoryRowAdapter extends ArrayObjectAdapter { private static final boolean DEBUG = false; private static final long ONE_DAY_MS = TimeUnit.DAYS.toMillis(1); + private static final int MAX_HISTORY_DAYS = ScheduledProgramReaper.DAYS; - private final long mMaxHistoryDays; private final Context mContext; private final Clock mClock; private final DvrDataManager mDvrDataManager; @@ -56,16 +57,11 @@ class DvrHistoryRowAdapter extends ArrayObjectAdapter { private final Map<Long, ScheduledRecording> mRecordedProgramScheduleMap = new HashMap<>(); public DvrHistoryRowAdapter( - Context context, - ClassPresenterSelector classPresenterSelector, - Clock clock, - DvrDataManager dvrDataManager, - UiFlags uiFlags) { + Context context, ClassPresenterSelector classPresenterSelector, Clock clock) { super(classPresenterSelector); mContext = context; mClock = clock; - mDvrDataManager = dvrDataManager; - mMaxHistoryDays = uiFlags.maxHistoryDays(); + mDvrDataManager = TvSingletons.getSingletons(mContext).getDvrDataManager(); mTitles.add(mContext.getString(R.string.dvr_date_today)); mTitles.add(mContext.getString(R.string.dvr_date_yesterday)); } @@ -82,9 +78,9 @@ class DvrHistoryRowAdapter extends ArrayObjectAdapter { List<RecordedProgram> recordedProgramList = mDvrDataManager.getRecordedPrograms(); recordingList.addAll( - recordedProgramsToScheduledRecordings(recordedProgramList, mMaxHistoryDays)); - recordingList.sort( - ScheduledRecording.START_TIME_THEN_PRIORITY_THEN_ID_COMPARATOR.reversed()); + recordedProgramsToScheduledRecordings(recordedProgramList, MAX_HISTORY_DAYS)); + recordingList + .sort(ScheduledRecording.START_TIME_THEN_PRIORITY_THEN_ID_COMPARATOR.reversed()); long deadLine = Utils.getFirstMillisecondOfDay(mClock.currentTimeMillis()); for (int i = 0; i < recordingList.size(); ) { ArrayList<ScheduledRecording> section = new ArrayList<>(); @@ -132,7 +128,7 @@ class DvrHistoryRowAdapter extends ArrayObjectAdapter { } private List<ScheduledRecording> recordedProgramsToScheduledRecordings( - List<RecordedProgram> programs, long maxDays) { + List<RecordedProgram> programs, int maxDays) { List<ScheduledRecording> result = new ArrayList<>(); for (RecordedProgram recordedProgram : programs) { ScheduledRecording scheduledRecording = @@ -146,12 +142,12 @@ class DvrHistoryRowAdapter extends ArrayObjectAdapter { @Nullable private ScheduledRecording recordedProgramsToScheduledRecordings( - RecordedProgram program, long maxDays) { + RecordedProgram program, int maxDays) { long firstMillisecondToday = Utils.getFirstMillisecondOfDay(mClock.currentTimeMillis()); - if (maxDays != 0 - && maxDays - < Utils.computeDateDifference( - program.getStartTimeUtcMillis(), firstMillisecondToday)) { + if (maxDays + < Utils.computeDateDifference( + program.getStartTimeUtcMillis(), + firstMillisecondToday)) { return null; } ScheduledRecording scheduledRecording = ScheduledRecording.builder(program).build(); @@ -179,7 +175,7 @@ class DvrHistoryRowAdapter extends ArrayObjectAdapter { return; } ScheduledRecording schedule = - recordedProgramsToScheduledRecordings(program, mMaxHistoryDays); + recordedProgramsToScheduledRecordings(program, MAX_HISTORY_DAYS); if (schedule == null) { return; } @@ -252,10 +248,8 @@ class DvrHistoryRowAdapter extends ArrayObjectAdapter { for (; index < size(); index++) { if (get(index) instanceof ScheduleRow) { ScheduleRow scheduleRow = (ScheduleRow) get(index); - if (ScheduledRecording.START_TIME_THEN_PRIORITY_THEN_ID_COMPARATOR - .reversed() - .compare(scheduleRow.getSchedule(), recording) - > 0) { + if (ScheduledRecording.START_TIME_THEN_PRIORITY_THEN_ID_COMPARATOR.reversed() + .compare(scheduleRow.getSchedule(), recording) > 0) { break; } pre = index; diff --git a/src/com/android/tv/dvr/ui/list/DvrSchedulesActivity.java b/src/com/android/tv/dvr/ui/list/DvrSchedulesActivity.java index d0884f99..82b85630 100644 --- a/src/com/android/tv/dvr/ui/list/DvrSchedulesActivity.java +++ b/src/com/android/tv/dvr/ui/list/DvrSchedulesActivity.java @@ -20,15 +20,13 @@ import android.app.Activity; import android.app.ProgressDialog; import android.os.Bundle; import android.support.annotation.IntDef; - import com.android.tv.R; import com.android.tv.Starter; -import com.android.tv.data.api.Program; +import com.android.tv.data.Program; import com.android.tv.dvr.data.SeriesRecording; import com.android.tv.dvr.provider.EpisodicProgramLoadTask; import com.android.tv.dvr.recorder.SeriesRecordingScheduler; import com.android.tv.dvr.ui.BigArguments; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Collections; diff --git a/src/com/android/tv/dvr/ui/list/DvrSchedulesFragment.java b/src/com/android/tv/dvr/ui/list/DvrSchedulesFragment.java index 43a3579a..d97b61f4 100644 --- a/src/com/android/tv/dvr/ui/list/DvrSchedulesFragment.java +++ b/src/com/android/tv/dvr/ui/list/DvrSchedulesFragment.java @@ -17,7 +17,7 @@ package com.android.tv.dvr.ui.list; import android.os.Bundle; -import androidx.leanback.widget.ClassPresenterSelector; +import android.support.v17.leanback.widget.ClassPresenterSelector; import com.android.tv.R; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.ui.list.SchedulesHeaderRowPresenter.DateHeaderRowPresenter; diff --git a/src/com/android/tv/dvr/ui/list/DvrSeriesSchedulesFragment.java b/src/com/android/tv/dvr/ui/list/DvrSeriesSchedulesFragment.java index 50bc04c7..d376e358 100644 --- a/src/com/android/tv/dvr/ui/list/DvrSeriesSchedulesFragment.java +++ b/src/com/android/tv/dvr/ui/list/DvrSeriesSchedulesFragment.java @@ -25,24 +25,20 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; +import android.support.v17.leanback.widget.ClassPresenterSelector; import android.transition.Fade; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; - -import androidx.leanback.widget.ClassPresenterSelector; - import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.data.ChannelDataManager; -import com.android.tv.data.ProgramImpl; -import com.android.tv.data.api.Program; +import com.android.tv.data.Program; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.DvrDataManager.SeriesRecordingListener; import com.android.tv.dvr.data.SeriesRecording; import com.android.tv.dvr.provider.EpisodicProgramLoadTask; import com.android.tv.dvr.ui.BigArguments; - import java.util.Collections; import java.util.List; @@ -57,7 +53,7 @@ public class DvrSeriesSchedulesFragment extends BaseDvrSchedulesFragment { "series_schedules_key_series_recording"; /** * The key for programs which belong to the series recording whose scheduled recording list will - * be displayed. Type: List<{@link ProgramImpl}> + * be displayed. Type: List<{@link Program}> */ public static final String SERIES_SCHEDULES_KEY_SERIES_PROGRAMS = "series_schedules_key_series_programs"; diff --git a/src/com/android/tv/dvr/ui/list/EpisodicProgramRow.java b/src/com/android/tv/dvr/ui/list/EpisodicProgramRow.java index ccb497fb..d5808412 100644 --- a/src/com/android/tv/dvr/ui/list/EpisodicProgramRow.java +++ b/src/com/android/tv/dvr/ui/list/EpisodicProgramRow.java @@ -17,8 +17,7 @@ package com.android.tv.dvr.ui.list; import android.content.Context; - -import com.android.tv.data.api.Program; +import com.android.tv.data.Program; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.data.ScheduledRecording.Builder; import com.android.tv.dvr.ui.DvrUiHelper; diff --git a/src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java b/src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java index de259f5a..ef4a4337 100644 --- a/src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java +++ b/src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java @@ -22,8 +22,8 @@ import android.os.Build.VERSION_CODES; import android.os.Handler; import android.os.Looper; import android.os.Message; -import androidx.leanback.widget.ArrayObjectAdapter; -import androidx.leanback.widget.ClassPresenterSelector; +import android.support.v17.leanback.widget.ArrayObjectAdapter; +import android.support.v17.leanback.widget.ClassPresenterSelector; import android.text.format.DateUtils; import android.util.ArraySet; import android.util.Log; diff --git a/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java b/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java index ff296f49..11680a0d 100644 --- a/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java +++ b/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java @@ -24,7 +24,7 @@ import android.content.Context; import android.content.res.Resources; import android.os.Build; import android.support.annotation.IntDef; -import androidx.leanback.widget.RowPresenter; +import android.support.v17.leanback.widget.RowPresenter; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; diff --git a/src/com/android/tv/dvr/ui/list/SchedulesHeaderRow.java b/src/com/android/tv/dvr/ui/list/SchedulesHeaderRow.java index 5c687cde..bbddc07f 100644 --- a/src/com/android/tv/dvr/ui/list/SchedulesHeaderRow.java +++ b/src/com/android/tv/dvr/ui/list/SchedulesHeaderRow.java @@ -16,9 +16,8 @@ package com.android.tv.dvr.ui.list; -import com.android.tv.data.api.Program; +import com.android.tv.data.Program; import com.android.tv.dvr.data.SeriesRecording; - import java.util.List; /** A base class for the rows for schedules' header. */ diff --git a/src/com/android/tv/dvr/ui/list/SchedulesHeaderRowPresenter.java b/src/com/android/tv/dvr/ui/list/SchedulesHeaderRowPresenter.java index 2550eebc..28a44bf3 100644 --- a/src/com/android/tv/dvr/ui/list/SchedulesHeaderRowPresenter.java +++ b/src/com/android/tv/dvr/ui/list/SchedulesHeaderRowPresenter.java @@ -19,7 +19,7 @@ package com.android.tv.dvr.ui.list; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.drawable.Drawable; -import androidx.leanback.widget.RowPresenter; +import android.support.v17.leanback.widget.RowPresenter; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; diff --git a/src/com/android/tv/dvr/ui/list/SeriesScheduleRowAdapter.java b/src/com/android/tv/dvr/ui/list/SeriesScheduleRowAdapter.java index 2c377549..9a9c94ea 100644 --- a/src/com/android/tv/dvr/ui/list/SeriesScheduleRowAdapter.java +++ b/src/com/android/tv/dvr/ui/list/SeriesScheduleRowAdapter.java @@ -20,22 +20,19 @@ import android.annotation.TargetApi; import android.content.Context; import android.media.tv.TvInputInfo; import android.os.Build; +import android.support.v17.leanback.widget.ClassPresenterSelector; import android.util.ArrayMap; import android.util.Log; - -import androidx.leanback.widget.ClassPresenterSelector; - import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; -import com.android.tv.data.api.Program; +import com.android.tv.data.Program; import com.android.tv.dvr.DvrDataManager; 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.ui.list.SchedulesHeaderRow.SeriesRecordingHeaderRow; import com.android.tv.util.Utils; - import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; diff --git a/src/com/android/tv/dvr/ui/playback/DvrPlaybackActivity.java b/src/com/android/tv/dvr/ui/playback/DvrPlaybackActivity.java index 4aa1200e..f24ad2c0 100644 --- a/src/com/android/tv/dvr/ui/playback/DvrPlaybackActivity.java +++ b/src/com/android/tv/dvr/ui/playback/DvrPlaybackActivity.java @@ -16,6 +16,7 @@ package com.android.tv.dvr.ui.playback; +import android.app.Activity; import android.content.ContentUris; import android.content.Intent; import android.content.res.Configuration; @@ -27,12 +28,9 @@ import com.android.tv.Starter; import com.android.tv.dialog.PinDialogFragment.OnPinCheckedListener; import com.android.tv.dvr.data.RecordedProgram; import com.android.tv.util.Utils; -import dagger.android.AndroidInjection; -import dagger.android.ContributesAndroidInjector; -import dagger.android.DaggerActivity; /** Activity to play a {@link RecordedProgram}. */ -public class DvrPlaybackActivity extends DaggerActivity implements OnPinCheckedListener { +public class DvrPlaybackActivity extends Activity implements OnPinCheckedListener { private static final String TAG = "DvrPlaybackActivity"; private static final boolean DEBUG = false; @@ -41,7 +39,6 @@ public class DvrPlaybackActivity extends DaggerActivity implements OnPinCheckedL @Override public void onCreate(Bundle savedInstanceState) { - AndroidInjection.inject(this); Starter.start(this); if (DEBUG) Log.d(TAG, "onCreate"); super.onCreate(savedInstanceState); @@ -95,16 +92,4 @@ public class DvrPlaybackActivity extends DaggerActivity implements OnPinCheckedL void setOnPinCheckListener(OnPinCheckedListener listener) { mOnPinCheckedListener = listener; } - - /** - * Exports {@link DvrPlaybackActivity} for Dagger codegen to create the appropriate injector. - */ - @dagger.Module - public abstract static class Module { - @ContributesAndroidInjector - abstract DvrPlaybackActivity contributesDvrPlaybackActivity(); - - @ContributesAndroidInjector - abstract DvrPlaybackOverlayFragment contributesDvrPlaybackOverlayFragment(); - } } diff --git a/src/com/android/tv/dvr/ui/playback/DvrPlaybackControlHelper.java b/src/com/android/tv/dvr/ui/playback/DvrPlaybackControlHelper.java index 35c5d4e4..791d26bb 100644 --- a/src/com/android/tv/dvr/ui/playback/DvrPlaybackControlHelper.java +++ b/src/com/android/tv/dvr/ui/playback/DvrPlaybackControlHelper.java @@ -26,15 +26,15 @@ import android.media.session.PlaybackState; import android.media.tv.TvTrackInfo; import android.os.Bundle; import android.support.annotation.Nullable; -import androidx.leanback.media.PlaybackControlGlue; -import androidx.leanback.widget.AbstractDetailsDescriptionPresenter; -import androidx.leanback.widget.Action; -import androidx.leanback.widget.ArrayObjectAdapter; -import androidx.leanback.widget.PlaybackControlsRow; -import androidx.leanback.widget.PlaybackControlsRow.ClosedCaptioningAction; -import androidx.leanback.widget.PlaybackControlsRow.MultiAction; -import androidx.leanback.widget.PlaybackControlsRowPresenter; -import androidx.leanback.widget.RowPresenter; +import android.support.v17.leanback.media.PlaybackControlGlue; +import android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter; +import android.support.v17.leanback.widget.Action; +import android.support.v17.leanback.widget.ArrayObjectAdapter; +import android.support.v17.leanback.widget.PlaybackControlsRow; +import android.support.v17.leanback.widget.PlaybackControlsRow.ClosedCaptioningAction; +import android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction; +import android.support.v17.leanback.widget.PlaybackControlsRowPresenter; +import android.support.v17.leanback.widget.RowPresenter; import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; diff --git a/src/com/android/tv/dvr/ui/playback/DvrPlaybackOverlayFragment.java b/src/com/android/tv/dvr/ui/playback/DvrPlaybackOverlayFragment.java index 0c96cac8..1059e852 100644 --- a/src/com/android/tv/dvr/ui/playback/DvrPlaybackOverlayFragment.java +++ b/src/com/android/tv/dvr/ui/playback/DvrPlaybackOverlayFragment.java @@ -26,25 +26,24 @@ import android.media.tv.TvContentRating; import android.media.tv.TvInputManager; import android.media.tv.TvTrackInfo; import android.os.Bundle; +import android.support.v17.leanback.app.PlaybackFragment; +import android.support.v17.leanback.app.PlaybackFragmentGlueHost; +import android.support.v17.leanback.widget.ArrayObjectAdapter; +import android.support.v17.leanback.widget.BaseOnItemViewClickedListener; +import android.support.v17.leanback.widget.ClassPresenterSelector; +import android.support.v17.leanback.widget.HeaderItem; +import android.support.v17.leanback.widget.ListRow; +import android.support.v17.leanback.widget.Presenter; +import android.support.v17.leanback.widget.RowPresenter; +import android.support.v17.leanback.widget.SinglePresenterSelector; import android.util.Log; import android.view.Display; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; -import androidx.leanback.app.PlaybackFragment; -import androidx.leanback.app.PlaybackFragmentGlueHost; -import androidx.leanback.widget.ArrayObjectAdapter; -import androidx.leanback.widget.BaseOnItemViewClickedListener; -import androidx.leanback.widget.ClassPresenterSelector; -import androidx.leanback.widget.HeaderItem; -import androidx.leanback.widget.ListRow; -import androidx.leanback.widget.Presenter; -import androidx.leanback.widget.RowPresenter; -import androidx.leanback.widget.SinglePresenterSelector; import com.android.tv.R; -import com.android.tv.audio.AudioManagerHelper; -import com.android.tv.common.buildtype.HasBuildType.BuildType; -import com.android.tv.data.api.BaseProgram; +import com.android.tv.TvSingletons; +import com.android.tv.data.BaseProgram; import com.android.tv.dialog.PinDialogFragment; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.data.RecordedProgram; @@ -56,11 +55,8 @@ import com.android.tv.ui.AppLayerTvView; import com.android.tv.util.TvSettings; import com.android.tv.util.TvTrackInfoUtils; import com.android.tv.util.Utils; -import dagger.android.AndroidInjection; -import com.android.tv.common.flags.LegacyFlags; import java.util.ArrayList; import java.util.List; -import javax.inject.Inject; public class DvrPlaybackOverlayFragment extends PlaybackFragment { // TODO: Handles audio focus. Deals with block and ratings. @@ -79,7 +75,7 @@ public class DvrPlaybackOverlayFragment extends PlaybackFragment { private ArrayObjectAdapter mRowsAdapter; private SortedArrayAdapter<BaseProgram> mRelatedRecordingsRowAdapter; private DvrPlaybackCardPresenter mRelatedRecordingCardPresenter; - private AudioManagerHelper mAudioManagerHelper; + private DvrDataManager mDvrDataManager; private AppLayerTvView mTvView; private View mBlockScreenView; private ListRow mRelatedRecordingsRow; @@ -101,24 +97,9 @@ public class DvrPlaybackOverlayFragment extends PlaybackFragment { } }; - @Inject DvrDataManager mDvrDataManager; - @Inject LegacyFlags mLegacyFlags; - @Inject BuildType buildType; - - @Override - public void onAttach(Context context) { - if (DEBUG) { - Log.d(TAG, "onAttach"); - } - AndroidInjection.inject(this); - super.onAttach(context); - } - @Override public void onCreate(Bundle savedInstanceState) { - if (DEBUG) { - Log.d(TAG, "onCreate"); - } + if (DEBUG) Log.d(TAG, "onCreate"); super.onCreate(savedInstanceState); mVerticalPaddingBase = getActivity() @@ -134,6 +115,7 @@ public class DvrPlaybackOverlayFragment extends PlaybackFragment { .getResources() .getDimensionPixelOffset( R.dimen.dvr_playback_overlay_padding_top_no_secondary_row); + mDvrDataManager = TvSingletons.getSingletons(getActivity()).getDvrDataManager(); if (!mDvrDataManager.isRecordedProgramLoadFinished()) { mDvrDataManager.addRecordedProgramLoadFinishedListener( new DvrDataManager.OnRecordedProgramLoadFinishedListener() { @@ -171,8 +153,6 @@ public class DvrPlaybackOverlayFragment extends PlaybackFragment { public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mTvView = getActivity().findViewById(R.id.dvr_tv_view); - mTvView.setUseSecureSurface( - buildType != BuildType.ENG && !mLegacyFlags.enableDeveloperFeatures()); mBlockScreenView = getActivity().findViewById(R.id.block_screen); mDvrPlayer = new DvrPlayer(mTvView, getActivity()); mMediaSessionHelper = @@ -260,16 +240,13 @@ public class DvrPlaybackOverlayFragment extends PlaybackFragment { setFadingEnabled(false); long programId = ((RecordedProgram) itemViewHolder.view.getTag()).getId(); - if (DEBUG) { - Log.d(TAG, "Play Related Recording:" + programId); - } + if (DEBUG) Log.d(TAG, "Play Related Recording:" + programId); Intent intent = new Intent(getContext(), DvrPlaybackActivity.class); intent.putExtra(Utils.EXTRA_KEY_RECORDED_PROGRAM_ID, programId); getContext().startActivity(intent); } } }); - mAudioManagerHelper = new AudioManagerHelper(getActivity(), mDvrPlayer.getView()); if (mProgram != null) { setUpRows(); preparePlayback(getActivity().getIntent()); @@ -278,9 +255,7 @@ public class DvrPlaybackOverlayFragment extends PlaybackFragment { @Override public void onPause() { - if (DEBUG) { - Log.d(TAG, "onPause"); - } + if (DEBUG) Log.d(TAG, "onPause"); super.onPause(); if (mMediaSessionHelper.getPlaybackState() == PlaybackState.STATE_FAST_FORWARDING || mMediaSessionHelper.getPlaybackState() == PlaybackState.STATE_REWINDING) { @@ -295,12 +270,9 @@ public class DvrPlaybackOverlayFragment extends PlaybackFragment { @Override public void onDestroy() { - if (DEBUG) { - Log.d(TAG, "onDestroy"); - } + if (DEBUG) Log.d(TAG, "onDestroy"); mPlaybackControlHelper.unregisterCallback(); mMediaSessionHelper.release(); - mAudioManagerHelper.abandonAudioFocus(); mRelatedRecordingCardPresenter.unbindAllViewHolders(); mDvrPlayer.release(); super.onDestroy(); @@ -444,7 +416,6 @@ public class DvrPlaybackOverlayFragment extends PlaybackFragment { private void preparePlayback(Intent intent) { mMediaSessionHelper.setupPlayback(mProgram, getSeekTimeFromIntent(intent)); mPlaybackControlHelper.updateSecondaryRow(false, false); - mAudioManagerHelper.requestAudioFocus(); getActivity().getMediaController().getTransportControls().prepare(); updateRelatedRecordingsRow(); } diff --git a/src/com/android/tv/dvr/ui/playback/DvrPlaybackSideFragment.java b/src/com/android/tv/dvr/ui/playback/DvrPlaybackSideFragment.java index 95858e3c..b4481df8 100644 --- a/src/com/android/tv/dvr/ui/playback/DvrPlaybackSideFragment.java +++ b/src/com/android/tv/dvr/ui/playback/DvrPlaybackSideFragment.java @@ -19,8 +19,8 @@ package com.android.tv.dvr.ui.playback; import android.media.tv.TvTrackInfo; import android.os.Bundle; import android.support.annotation.NonNull; -import androidx.leanback.app.GuidedStepFragment; -import androidx.leanback.widget.GuidedAction; +import android.support.v17.leanback.app.GuidedStepFragment; +import android.support.v17.leanback.widget.GuidedAction; import android.text.TextUtils; import android.transition.Transition; import android.view.LayoutInflater; diff --git a/src/com/android/tv/dvr/ui/playback/DvrPlayer.java b/src/com/android/tv/dvr/ui/playback/DvrPlayer.java index 6cfa2e20..d14646b8 100644 --- a/src/com/android/tv/dvr/ui/playback/DvrPlayer.java +++ b/src/com/android/tv/dvr/ui/playback/DvrPlayer.java @@ -326,11 +326,6 @@ public class DvrPlayer { return mProgram; } - /** Returns the DVR tv view. */ - public DvrTvView getView() { - return mTvView; - } - /** Returns the currrent playback posistion in msecs. */ public long getPlaybackPosition() { return mTimeShiftCurrentPositionMs; @@ -521,17 +516,13 @@ public class DvrPlayer { for (TvTrackInfo trackInfo : trackInfos) { if (trackInfo.getId().equals(trackId)) { float videoAspectRatio; - float videoPixelAspectRatio = - trackInfo.getVideoPixelAspectRatio(); int videoWidth = trackInfo.getVideoWidth(); int videoHeight = trackInfo.getVideoHeight(); if (videoWidth > 0 && videoHeight > 0) { videoAspectRatio = - (float) trackInfo.getVideoWidth() + trackInfo.getVideoPixelAspectRatio() + * trackInfo.getVideoWidth() / trackInfo.getVideoHeight(); - videoAspectRatio *= - videoPixelAspectRatio > 0 ? - videoPixelAspectRatio : 1; } else { // Aspect ratio is unknown. Pass the message to // listeners. diff --git a/src/com/android/tv/features/TvFeatures.java b/src/com/android/tv/features/TvFeatures.java index a18d9c89..208d53f6 100644 --- a/src/com/android/tv/features/TvFeatures.java +++ b/src/com/android/tv/features/TvFeatures.java @@ -27,11 +27,14 @@ import static com.android.tv.common.feature.FeatureUtils.or; import android.content.Context; import android.content.pm.PackageManager; import android.os.Build; - +import android.support.annotation.VisibleForTesting; +import com.android.tv.common.experiments.Experiments; import com.android.tv.common.feature.CommonFeatures; +import com.android.tv.common.feature.ExperimentFeature; import com.android.tv.common.feature.Feature; import com.android.tv.common.feature.FeatureUtils; import com.android.tv.common.feature.FlagFeature; +import com.android.tv.common.feature.PropertyFeature; import com.android.tv.common.feature.Sdk; import com.android.tv.common.feature.TestableFeature; import com.android.tv.common.flags.has.HasUiFlags; @@ -39,7 +42,7 @@ import com.android.tv.common.singletons.HasSingletons; import com.android.tv.common.util.PermissionUtils; /** - * List of {@link Feature} for the TV app. + * List of {@link Feature} for the Live TV App. * * <p>Remove the {@code Feature} once it is launched. */ @@ -48,6 +51,16 @@ public final class TvFeatures extends CommonFeatures { /** When enabled store network affiliation information to TV provider */ public static final Feature STORE_NETWORK_AFFILIATION = ENG_ONLY_FEATURE; + /** When enabled use system setting for turning on analytics. */ + public static final Feature ANALYTICS_OPT_IN = + ExperimentFeature.from(Experiments.ENABLE_ANALYTICS_VIA_CHECKBOX); + /** + * Analytics that include sensitive information such as channel or program identifiers. + * + * <p>See <a href="http://b/22062676">b/22062676</a> + */ + public static final Feature ANALYTICS_V2 = and(ON, ANALYTICS_OPT_IN); + private static final Feature TV_PROVIDER_ALLOWS_INSERT_TO_PROGRAM_TABLE = or(Sdk.AT_LEAST_O, PartnerFeatures.TVPROVIDER_ALLOWS_SYSTEM_INSERTS_TO_PROGRAM_TABLE); @@ -74,7 +87,7 @@ public final class TvFeatures extends CommonFeatures { or( FlagFeature.from( context -> HasSingletons.get(HasUiFlags.class, context), - input -> input.getUiFlags().unhideLauncher()), + input -> input.getUiFlags().uhideLauncher()), // If LC app runs as non-system app, we unhide the app. not(PermissionUtils::hasAccessAllEpg)); @@ -101,5 +114,8 @@ public final class TvFeatures extends CommonFeatures { /** Use input blacklist to disable partner's tuner input. */ public static final Feature USE_PARTNER_INPUT_BLACKLIST = ON; + @VisibleForTesting + public static final Feature TEST_FEATURE = PropertyFeature.create("test_feature", false); + private TvFeatures() {} } diff --git a/src/com/android/tv/guide/GenreListAdapter.java b/src/com/android/tv/guide/GenreListAdapter.java index 995b053c..b4baf421 100644 --- a/src/com/android/tv/guide/GenreListAdapter.java +++ b/src/com/android/tv/guide/GenreListAdapter.java @@ -18,7 +18,7 @@ package com.android.tv.guide; import android.content.Context; import android.support.annotation.MainThread; -import androidx.recyclerview.widget.RecyclerView; +import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.LayoutInflater; import android.view.View; diff --git a/src/com/android/tv/guide/ProgramGrid.java b/src/com/android/tv/guide/ProgramGrid.java index 96e161cd..caafb045 100644 --- a/src/com/android/tv/guide/ProgramGrid.java +++ b/src/com/android/tv/guide/ProgramGrid.java @@ -19,7 +19,7 @@ package com.android.tv.guide; import android.content.Context; import android.content.res.Resources; import android.graphics.Rect; -import androidx.leanback.widget.VerticalGridView; +import android.support.v17.leanback.widget.VerticalGridView; import android.util.AttributeSet; import android.util.Log; import android.util.Range; @@ -256,19 +256,8 @@ public class ProgramGrid extends VerticalGridView { scrollToPosition(getAdapter().getItemCount() - 1); return null; } else if (getSelectedPosition() == getAdapter().getItemCount() - 1) { - int itemCount = getLayoutManager().getItemCount(); - int childCount = getChildCount(); - // b/129466363 For an item which overalps with previous layout GridLayoutManager - // will scroll to first child of current layout, instead of going to previous one. - // smoothscrollToPosition will invalidate all layouts and scroll to position 0. - // This condition checks for an item which overlaps with the first layout - if (itemCount > 2 * (childCount + 1) || itemCount <= childCount) { - scrollToPosition(0); - return null; - } else { - smoothScrollToPosition(0); - return getChildAt(0); - } + scrollToPosition(0); + return null; } return focused; } diff --git a/src/com/android/tv/guide/ProgramGuide.java b/src/com/android/tv/guide/ProgramGuide.java index 8ae61e8a..bc1b11b6 100644 --- a/src/com/android/tv/guide/ProgramGuide.java +++ b/src/com/android/tv/guide/ProgramGuide.java @@ -32,7 +32,10 @@ import android.os.SystemClock; import android.preference.PreferenceManager; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import androidx.recyclerview.widget.RecyclerView; +import android.support.v17.leanback.widget.OnChildSelectedListener; +import android.support.v17.leanback.widget.SearchOrbView; +import android.support.v17.leanback.widget.VerticalGridView; +import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.View; import android.view.View.MeasureSpec; @@ -41,11 +44,6 @@ import android.view.ViewGroup.LayoutParams; import android.view.ViewTreeObserver; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener; - -import androidx.leanback.widget.OnChildSelectedListener; -import androidx.leanback.widget.SearchOrbView; -import androidx.leanback.widget.VerticalGridView; - import com.android.tv.ChannelTuner; import com.android.tv.MainActivity; import com.android.tv.R; @@ -67,9 +65,7 @@ import com.android.tv.ui.ViewUtils; import com.android.tv.ui.hideable.AutoHideScheduler; import com.android.tv.util.TvInputManagerHelper; import com.android.tv.util.Utils; - -import com.android.tv.common.flags.UiFlags; - +import com.android.tv.common.flags.BackendKnobsFlags; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; @@ -116,7 +112,6 @@ public class ProgramGuide private final int mAnimationDuration; private final int mDetailPadding; private final SearchOrbView mSearchOrb; - private final UiFlags mUiFlags; private int mCurrentTimeIndicatorWidth; private final View mContainer; @@ -190,14 +185,15 @@ public class ProgramGuide mActivity = activity; TvSingletons singletons = TvSingletons.getSingletons(mActivity); mPerformanceMonitor = singletons.getPerformanceMonitor(); - mUiFlags = singletons.getUiFlags(); + BackendKnobsFlags backendKnobsFlags = singletons.getBackendKnobs(); mProgramManager = new ProgramManager( tvInputManagerHelper, channelDataManager, programDataManager, dvrDataManager, - dvrScheduleManager); + dvrScheduleManager, + backendKnobsFlags); mChannelTuner = channelTuner; mTracker = tracker; mPreShowRunnable = preShowRunnable; @@ -265,7 +261,7 @@ public class ProgramGuide } }); mSidePanelGridView.setOnChildSelectedListener( - new androidx.leanback.widget.OnChildSelectedListener() { + new android.support.v17.leanback.widget.OnChildSelectedListener() { @Override public void onChildSelected(ViewGroup viewGroup, View view, int i, long l) { mSearchOrb.animate().alpha(i == 0 ? 1.0f : 0.0f); @@ -286,8 +282,7 @@ public class ProgramGuide res.getInteger(R.integer.max_recycled_view_pool_epg_header_row_item)); mTimelineRow.setAdapter(mTimeListAdapter); - ProgramTableAdapter programTableAdapter = - new ProgramTableAdapter(mActivity, this, mUiFlags); + ProgramTableAdapter programTableAdapter = new ProgramTableAdapter(mActivity, this); programTableAdapter.registerAdapterDataObserver( new RecyclerView.AdapterDataObserver() { @Override diff --git a/src/com/android/tv/guide/ProgramItemView.java b/src/com/android/tv/guide/ProgramItemView.java index 5ec293f7..a46beab7 100644 --- a/src/com/android/tv/guide/ProgramItemView.java +++ b/src/com/android/tv/guide/ProgramItemView.java @@ -23,7 +23,6 @@ import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; import android.graphics.drawable.StateListDrawable; -import android.os.Build; import android.os.Handler; import android.text.SpannableStringBuilder; import android.text.Spanned; @@ -35,7 +34,6 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import android.widget.Toast; - import com.android.tv.MainActivity; import com.android.tv.R; import com.android.tv.TvSingletons; @@ -43,22 +41,17 @@ import com.android.tv.analytics.Tracker; import com.android.tv.common.feature.CommonFeatures; import com.android.tv.common.util.Clock; import com.android.tv.data.ChannelDataManager; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dvr.DvrManager; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.ui.DvrUiHelper; import com.android.tv.guide.ProgramManager.TableEntry; import com.android.tv.util.ToastUtils; import com.android.tv.util.Utils; - -import dagger.android.HasAndroidInjector; - import java.lang.reflect.InvocationTargetException; import java.util.concurrent.TimeUnit; -import javax.inject.Inject; - public class ProgramItemView extends TextView { private static final String TAG = "ProgramItemView"; @@ -80,8 +73,8 @@ public class ProgramItemView extends TextView { private static TextAppearanceSpan sGrayedOutEpisodeTitleStyle; private final DvrManager mDvrManager; - @Inject Clock mClock; - @Inject ChannelDataManager mChannelDataManager; + private final Clock mClock; + private final ChannelDataManager mChannelDataManager; private ProgramGuide mProgramGuide; private TableEntry mTableEntry; private int mMaxWidthForRipple; @@ -209,11 +202,12 @@ public class ProgramItemView extends TextView { public ProgramItemView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - ((HasAndroidInjector) context).androidInjector().inject(this); setOnClickListener(ON_CLICKED); setOnFocusChangeListener(ON_FOCUS_CHANGED); TvSingletons singletons = TvSingletons.getSingletons(getContext()); mDvrManager = singletons.getDvrManager(); + mChannelDataManager = singletons.getChannelDataManager(); + mClock = singletons.getClock(); } private void initIfNeeded() { @@ -536,9 +530,6 @@ public class ProgramItemView extends TextView { } private static int getStateCount(StateListDrawable stateListDrawable) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - return stateListDrawable.getStateCount(); - } try { Object stateCount = StateListDrawable.class @@ -555,9 +546,6 @@ public class ProgramItemView extends TextView { } private static Drawable getStateDrawable(StateListDrawable stateListDrawable, int index) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - return stateListDrawable.getStateDrawable(index); - } try { Object drawable = StateListDrawable.class diff --git a/src/com/android/tv/guide/ProgramListAdapter.java b/src/com/android/tv/guide/ProgramListAdapter.java index 68ae43ee..397bacfb 100644 --- a/src/com/android/tv/guide/ProgramListAdapter.java +++ b/src/com/android/tv/guide/ProgramListAdapter.java @@ -17,7 +17,7 @@ package com.android.tv.guide; import android.content.res.Resources; -import androidx.recyclerview.widget.RecyclerView; +import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.LayoutInflater; import android.view.View; diff --git a/src/com/android/tv/guide/ProgramManager.java b/src/com/android/tv/guide/ProgramManager.java index 516a4d9c..3a5a4a02 100644 --- a/src/com/android/tv/guide/ProgramManager.java +++ b/src/com/android/tv/guide/ProgramManager.java @@ -21,20 +21,18 @@ import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; import android.util.ArraySet; import android.util.Log; - import com.android.tv.data.ChannelDataManager; import com.android.tv.data.GenreItems; +import com.android.tv.data.Program; import com.android.tv.data.ProgramDataManager; -import com.android.tv.data.ProgramImpl; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.DvrScheduleManager; import com.android.tv.dvr.DvrScheduleManager.OnConflictStateChangeListener; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.util.TvInputManagerHelper; import com.android.tv.util.Utils; - +import com.android.tv.common.flags.BackendKnobsFlags; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -62,6 +60,7 @@ public class ProgramManager { private final ProgramDataManager mProgramDataManager; private final DvrDataManager mDvrDataManager; // Only set if DVR is enabled private final DvrScheduleManager mDvrScheduleManager; + private final BackendKnobsFlags mBackendKnobsFlags; private long mStartUtcMillis; private long mEndUtcMillis; @@ -125,8 +124,16 @@ public class ProgramManager { } @Override - public void onChannelUpdated() { - updateTableEntriesWithoutNotification(false); + public void onSingleChannelUpdated(long channelId) { + boolean parentalControlsEnabled = + mTvInputManagerHelper + .getParentalControlSettings() + .isParentalControlsEnabled(); + // Inline the updating of the mChannelIdEntriesMap here so we can only call + // getParentalControlSettings once. + List<TableEntry> entries = + createProgramEntries(channelId, parentalControlsEnabled); + mChannelIdEntriesMap.put(channelId, entries); notifyTableEntriesUpdated(); } }; @@ -208,12 +215,14 @@ public class ProgramManager { ChannelDataManager channelDataManager, ProgramDataManager programDataManager, @Nullable DvrDataManager dvrDataManager, - @Nullable DvrScheduleManager dvrScheduleManager) { + @Nullable DvrScheduleManager dvrScheduleManager, + BackendKnobsFlags backendKnobsFlags) { mTvInputManagerHelper = tvInputManagerHelper; mChannelDataManager = channelDataManager; mProgramDataManager = programDataManager; mDvrDataManager = dvrDataManager; mDvrScheduleManager = dvrScheduleManager; + mBackendKnobsFlags = backendKnobsFlags; } void programGuideVisibilityChanged(boolean visible) { @@ -242,6 +251,7 @@ public class ProgramManager { mDvrScheduleManager.removeOnConflictStateChangeListener( mOnConflictStateChangeListener); } + mChannelIdEntriesMap.clear(); } } @@ -416,12 +426,14 @@ public class ProgramManager { } /** - * Returns an entry as {@link ProgramImpl} for a given {@code channelId} and {@code index} of - * entries within the currently managed time range. Returned {@link ProgramImpl} can be a dummy - * one (e.g., whose channelId is INVALID_ID), when it corresponds to a gap between programs. + * Returns an entry as {@link Program} for a given {@code channelId} and {@code index} of + * entries within the currently managed time range. Returned {@link Program} can be a dummy one + * (e.g., whose channelId is INVALID_ID), when it corresponds to a gap between programs. */ TableEntry getTableEntry(long channelId, int index) { - mProgramDataManager.prefetchChannel(channelId, index); + if (mBackendKnobsFlags.enablePartialProgramFetch()) { + mProgramDataManager.prefetchChannel(channelId); + } return mChannelIdEntriesMap.get(channelId).get(index); } @@ -695,7 +707,7 @@ public class ProgramManager { /** * Entry for program guide table. An "entry" can be either an actual program or a gap between * programs. This is needed for {@link ProgramListAdapter} because {@link - * androidx.leanback.widget.HorizontalGridView} ignores margins between items. + * android.support.v17.leanback.widget.HorizontalGridView} ignores margins between items. */ static class TableEntry { /** Channel ID which this entry is included. */ @@ -725,7 +737,7 @@ public class ProgramManager { private TableEntry( long channelId, - ProgramImpl program, + Program program, long entryStartUtcMillis, long entryEndUtcMillis, boolean isBlocked) { @@ -747,7 +759,7 @@ public class ProgramManager { mIsBlocked = isBlocked; } - /** A stable id useful for {@link androidx.recyclerview.widget.RecyclerView.Adapter}. */ + /** A stable id useful for {@link android.support.v7.widget.RecyclerView.Adapter}. */ long getId() { // using a negative entryEndUtcMillis keeps it from conflicting with program Id return program != null ? program.getId() : -entryEndUtcMillis; diff --git a/src/com/android/tv/guide/ProgramRow.java b/src/com/android/tv/guide/ProgramRow.java index 6f8f31c1..3317c15f 100644 --- a/src/com/android/tv/guide/ProgramRow.java +++ b/src/com/android/tv/guide/ProgramRow.java @@ -18,7 +18,7 @@ package com.android.tv.guide; import android.content.Context; import android.graphics.Rect; -import androidx.recyclerview.widget.LinearLayoutManager; +import android.support.v7.widget.LinearLayoutManager; import android.util.AttributeSet; import android.util.Log; import android.util.Range; diff --git a/src/com/android/tv/guide/ProgramRowAccessibilityDelegate.java b/src/com/android/tv/guide/ProgramRowAccessibilityDelegate.java index a6a4624b..5e498be4 100644 --- a/src/com/android/tv/guide/ProgramRowAccessibilityDelegate.java +++ b/src/com/android/tv/guide/ProgramRowAccessibilityDelegate.java @@ -17,8 +17,8 @@ package com.android.tv.guide; import android.os.Bundle; -import androidx.recyclerview.widget.RecyclerView; -import androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.RecyclerViewAccessibilityDelegate; import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; diff --git a/src/com/android/tv/guide/ProgramTableAdapter.java b/src/com/android/tv/guide/ProgramTableAdapter.java index aed8b900..7576bf50 100644 --- a/src/com/android/tv/guide/ProgramTableAdapter.java +++ b/src/com/android/tv/guide/ProgramTableAdapter.java @@ -28,8 +28,8 @@ import android.media.tv.TvInputInfo; import android.os.Handler; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import androidx.recyclerview.widget.RecyclerView; -import androidx.recyclerview.widget.RecyclerView.RecycledViewPool; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.RecyclerView.RecycledViewPool; import android.text.Html; import android.text.Spannable; import android.text.SpannableString; @@ -47,14 +47,13 @@ import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeL import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; - import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.common.feature.CommonFeatures; import com.android.tv.common.util.CommonUtils; +import com.android.tv.data.Program; +import com.android.tv.data.Program.CriticScore; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; -import com.android.tv.data.api.Program.CriticScore; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.DvrManager; import com.android.tv.dvr.data.ScheduledRecording; @@ -68,8 +67,6 @@ import com.android.tv.util.images.ImageLoader; import com.android.tv.util.images.ImageLoader.ImageLoaderCallback; import com.android.tv.util.images.ImageLoader.LoadTvInputLogoTask; -import com.android.tv.common.flags.UiFlags; - import java.util.ArrayList; import java.util.List; @@ -112,11 +109,10 @@ class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapter.Progr private final String mRecordingInProgressText; private final int mDvrPaddingStartWithTrack; private final int mDvrPaddingStartWithOutTrack; - private final UiFlags mUiFlags; private RecyclerView mRecyclerView; - ProgramTableAdapter(Context context, ProgramGuide programGuide, UiFlags uiFlags) { + ProgramTableAdapter(Context context, ProgramGuide programGuide) { mContext = context; mAccessibilityManager = (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE); @@ -130,7 +126,6 @@ class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapter.Progr } mProgramGuide = programGuide; mProgramManager = programGuide.getProgramManager(); - mUiFlags = uiFlags; Resources res = context.getResources(); mChannelLogoWidth = @@ -661,35 +656,6 @@ class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapter.Progr mDvrIndicator.setVisibility(View.GONE); } - if (mUiFlags.enableCriticRatings()) { - // display critic scores if any exist - List<CriticScore> criticScores = program.getCriticScores(); - if (criticScores != null) { - // inflate more critic score views if required - if (criticScores.size() > mCriticScoreViews.size()) { - LayoutInflater inflater = LayoutInflater.from(mContext); - LinearLayout layout = - (LinearLayout) - inflater.inflate( - R.layout.program_guide_critic_score_layout, - null); - mCriticScoreViews.add(layout); - } - // fill critic score views and add to layout - for (int i = 0; i < criticScores.size(); i++) { - View criticScoreView = mCriticScoreViews.get(i); - ViewParent previousParentView = criticScoreView.getParent(); - if (previousParentView != null - && previousParentView instanceof ViewGroup) { - ((ViewGroup) previousParentView).removeView(criticScoreView); - } - updateCriticScoreView( - this, program.getId(), criticScores.get(i), criticScoreView); - mCriticScoresLayout.addView(mCriticScoreViews.get(i)); - } - } - } - if (blockedRating == null) { mBlockView.setVisibility(View.GONE); updateTextView(mDescriptionView, program.getDescription()); diff --git a/src/com/android/tv/guide/TimeListAdapter.java b/src/com/android/tv/guide/TimeListAdapter.java index 62fec69a..9c10c952 100644 --- a/src/com/android/tv/guide/TimeListAdapter.java +++ b/src/com/android/tv/guide/TimeListAdapter.java @@ -17,7 +17,7 @@ package com.android.tv.guide; import android.content.res.Resources; -import androidx.recyclerview.widget.RecyclerView; +import android.support.v7.widget.RecyclerView; import android.text.format.DateFormat; import android.view.LayoutInflater; import android.view.View; diff --git a/src/com/android/tv/guide/TimelineGridView.java b/src/com/android/tv/guide/TimelineGridView.java index 2d257878..c4922b75 100644 --- a/src/com/android/tv/guide/TimelineGridView.java +++ b/src/com/android/tv/guide/TimelineGridView.java @@ -17,8 +17,8 @@ package com.android.tv.guide; import android.content.Context; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; import android.view.View; diff --git a/src/com/android/tv/menu/ActionCardView.java b/src/com/android/tv/menu/ActionCardView.java index 0e789c67..3ecd5f5c 100644 --- a/src/com/android/tv/menu/ActionCardView.java +++ b/src/com/android/tv/menu/ActionCardView.java @@ -19,7 +19,6 @@ package com.android.tv.menu; import android.content.Context; import android.util.AttributeSet; import android.util.Log; -import android.view.accessibility.AccessibilityNodeInfo; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; @@ -94,13 +93,6 @@ public class ActionCardView extends RelativeLayout implements ItemListRowView.Ca } } - /** Request focus and accessibility focus on card view. */ - @Override - public boolean requestFocusWithAccessibility() { - return requestFocus() && - performAccessibilityAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); - } - @Override public void onRecycled() {} } diff --git a/src/com/android/tv/menu/AppLinkCardView.java b/src/com/android/tv/menu/AppLinkCardView.java index 49d32fed..fd93c314 100644 --- a/src/com/android/tv/menu/AppLinkCardView.java +++ b/src/com/android/tv/menu/AppLinkCardView.java @@ -26,13 +26,13 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.support.annotation.Nullable; +import android.support.v7.graphics.Palette; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.widget.ImageView; import android.widget.TextView; -import androidx.palette.graphics.Palette; import com.android.tv.MainActivity; import com.android.tv.R; import com.android.tv.data.api.Channel; diff --git a/src/com/android/tv/menu/BaseCardView.java b/src/com/android/tv/menu/BaseCardView.java index ed78cb73..3a94ebbf 100644 --- a/src/com/android/tv/menu/BaseCardView.java +++ b/src/com/android/tv/menu/BaseCardView.java @@ -27,7 +27,6 @@ import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.view.ViewOutlineProvider; -import android.view.accessibility.AccessibilityNodeInfo; import android.widget.LinearLayout; import android.widget.TextView; import com.android.tv.R; @@ -136,13 +135,6 @@ public abstract class BaseCardView<T> extends LinearLayout implements ItemListRo } } - /** Request focus and accessibility focus on card view. */ - @Override - public boolean requestFocusWithAccessibility() { - return requestFocus() && - performAccessibilityAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); - } - /** Sets text of this card view. */ public void setText(int resId) { if (mTextResId != resId) { diff --git a/src/com/android/tv/menu/ChannelCardView.java b/src/com/android/tv/menu/ChannelCardView.java index 7fe5e491..76056ee4 100644 --- a/src/com/android/tv/menu/ChannelCardView.java +++ b/src/com/android/tv/menu/ChannelCardView.java @@ -26,14 +26,12 @@ import android.view.View; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; - import com.android.tv.MainActivity; import com.android.tv.R; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.parental.ParentalControlSettings; import com.android.tv.util.images.ImageLoader; - import java.util.Objects; /** A view to render channel card. */ diff --git a/src/com/android/tv/menu/ChannelsPosterPrefetcher.java b/src/com/android/tv/menu/ChannelsPosterPrefetcher.java index 3a502304..9cecb9c0 100644 --- a/src/com/android/tv/menu/ChannelsPosterPrefetcher.java +++ b/src/com/android/tv/menu/ChannelsPosterPrefetcher.java @@ -23,15 +23,13 @@ import android.os.Message; import android.support.annotation.MainThread; import android.support.annotation.NonNull; import android.util.Log; - import com.android.tv.R; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.WeakHandler; import com.android.tv.data.ChannelImpl; +import com.android.tv.data.Program; import com.android.tv.data.ProgramDataManager; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; - import java.util.List; /** A poster image prefetcher to show the program poster art in the Channels row faster. */ diff --git a/src/com/android/tv/menu/ChannelsRow.java b/src/com/android/tv/menu/ChannelsRow.java index dbfc7820..7d03bf2b 100644 --- a/src/com/android/tv/menu/ChannelsRow.java +++ b/src/com/android/tv/menu/ChannelsRow.java @@ -73,7 +73,6 @@ public class ChannelsRow extends ItemListRow { mTvRecommendation = null; } mChannelsPosterPrefetcher.cancel(); - mChannelsAdapter.release(); } /** Handle the update event of the recent channel. */ diff --git a/src/com/android/tv/menu/ChannelsRowAdapter.java b/src/com/android/tv/menu/ChannelsRowAdapter.java index e6b61037..4a9e4765 100644 --- a/src/com/android/tv/menu/ChannelsRowAdapter.java +++ b/src/com/android/tv/menu/ChannelsRowAdapter.java @@ -47,7 +47,6 @@ public class ChannelsRowAdapter extends ItemListRowView.ItemListAdapter<Channels private final int mMaxCount; private final int mMinCount; private final ChannelChanger mChannelChanger; - private final AccessibilityManager mAccessibilityManager; private boolean mShowChannelUpDown; @@ -67,9 +66,10 @@ public class ChannelsRowAdapter extends ItemListRowView.ItemListAdapter<Channels mMaxCount = maxCount; setHasStableIds(true); mChannelChanger = (ChannelChanger) (context); - mAccessibilityManager = context.getSystemService(AccessibilityManager.class); - mShowChannelUpDown = mAccessibilityManager.isEnabled(); - mAccessibilityManager.addAccessibilityStateChangeListener(this); + AccessibilityManager accessibilityManager = + context.getSystemService(AccessibilityManager.class); + mShowChannelUpDown = accessibilityManager.isEnabled(); + accessibilityManager.addAccessibilityStateChangeListener(this); } @Override @@ -316,10 +316,4 @@ public class ChannelsRowAdapter extends ItemListRowView.ItemListAdapter<Channels mShowChannelUpDown = enabled; update(); } - - @Override - public void release() { - mAccessibilityManager.removeAccessibilityStateChangeListener(this); - super.release(); - } } diff --git a/src/com/android/tv/menu/ItemListRowView.java b/src/com/android/tv/menu/ItemListRowView.java index cc6d23c3..7042324d 100644 --- a/src/com/android/tv/menu/ItemListRowView.java +++ b/src/com/android/tv/menu/ItemListRowView.java @@ -17,9 +17,9 @@ package com.android.tv.menu; import android.content.Context; -import androidx.leanback.widget.HorizontalGridView; -import androidx.leanback.widget.OnChildSelectedListener; -import androidx.recyclerview.widget.RecyclerView; +import android.support.v17.leanback.widget.HorizontalGridView; +import android.support.v17.leanback.widget.OnChildSelectedListener; +import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; @@ -44,8 +44,6 @@ public class ItemListRowView extends MenuRowView implements OnChildSelectedListe void onSelected(); void onDeselected(); - - boolean requestFocusWithAccessibility(); } private HorizontalGridView mListView; @@ -116,13 +114,6 @@ public class ItemListRowView extends MenuRowView implements OnChildSelectedListe } } - @Override - protected void requestChildFocus() { - if (mSelectedCard != null) { - mSelectedCard.requestFocusWithAccessibility(); - } - } - public abstract static class ItemListAdapter<T> extends RecyclerView.Adapter<ItemListAdapter.MyViewHolder> { private final MainActivity mMainActivity; diff --git a/src/com/android/tv/menu/Menu.java b/src/com/android/tv/menu/Menu.java index 0687441e..6bdbf87b 100644 --- a/src/com/android/tv/menu/Menu.java +++ b/src/com/android/tv/menu/Menu.java @@ -23,7 +23,7 @@ import android.content.Context; import android.content.res.Resources; import android.support.annotation.IntDef; import android.support.annotation.VisibleForTesting; -import androidx.leanback.widget.HorizontalGridView; +import android.support.v17.leanback.widget.HorizontalGridView; import android.util.Log; import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener; import com.android.tv.ChannelTuner; diff --git a/src/com/android/tv/menu/MenuLayoutManager.java b/src/com/android/tv/menu/MenuLayoutManager.java index 8f95db77..a600f704 100644 --- a/src/com/android/tv/menu/MenuLayoutManager.java +++ b/src/com/android/tv/menu/MenuLayoutManager.java @@ -25,15 +25,15 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Rect; import android.support.annotation.UiThread; -import androidx.recyclerview.widget.RecyclerView; +import android.support.v4.view.animation.FastOutLinearInInterpolator; +import android.support.v4.view.animation.FastOutSlowInInterpolator; +import android.support.v4.view.animation.LinearOutSlowInInterpolator; +import android.support.v7.widget.RecyclerView; import android.util.Log; import android.util.Property; import android.view.View; import android.view.ViewGroup.MarginLayoutParams; import android.widget.TextView; -import androidx.interpolator.view.animation.FastOutLinearInInterpolator; -import androidx.interpolator.view.animation.FastOutSlowInInterpolator; -import androidx.interpolator.view.animation.LinearOutSlowInInterpolator; import com.android.tv.R; import com.android.tv.common.SoftPreconditions; import com.android.tv.util.Utils; diff --git a/src/com/android/tv/menu/MenuRow.java b/src/com/android/tv/menu/MenuRow.java index 0945a0c5..8dc12bad 100644 --- a/src/com/android/tv/menu/MenuRow.java +++ b/src/com/android/tv/menu/MenuRow.java @@ -31,8 +31,6 @@ public abstract class MenuRow { private MenuRowView mMenuRowView; - private boolean mIsReselected = false; - // TODO: Check if the heightResId is really necessary. public MenuRow(Context context, Menu menu, int titleResId, int heightResId) { this(context, menu, context.getString(titleResId), heightResId); @@ -102,19 +100,4 @@ public abstract class MenuRow { public boolean hideTitleWhenSelected() { return false; } - - /** - * Sets if menu row is reselected. - * - * @param isReselected {@code true} if row is reselected; - * else {@code false}. - */ - public void setIsReselected(boolean isReselected) { - mIsReselected = isReselected; - } - - /** Returns true if row is reselected. */ - public boolean isReselected() { - return mIsReselected; - } } diff --git a/src/com/android/tv/menu/MenuRowFactory.java b/src/com/android/tv/menu/MenuRowFactory.java index a3837a10..048d725d 100644 --- a/src/com/android/tv/menu/MenuRowFactory.java +++ b/src/com/android/tv/menu/MenuRowFactory.java @@ -24,7 +24,6 @@ import com.android.tv.R; import com.android.tv.common.customization.CustomAction; import com.android.tv.common.customization.CustomizationManager; import com.android.tv.ui.TunableTvView; -import com.android.tv.common.flags.LegacyFlags; import java.util.List; /** A factory class to create menu rows. */ @@ -32,15 +31,12 @@ public class MenuRowFactory { private final MainActivity mMainActivity; private final TunableTvView mTvView; private final CustomizationManager mCustomizationManager; - private final LegacyFlags mLegacyFlags; /** A constructor. */ - public MenuRowFactory( - MainActivity mainActivity, TunableTvView tvView, LegacyFlags mLegacyFlags) { + public MenuRowFactory(MainActivity mainActivity, TunableTvView tvView) { mMainActivity = mainActivity; mTvView = tvView; mCustomizationManager = new CustomizationManager(mainActivity); - this.mLegacyFlags = mLegacyFlags; mCustomizationManager.initialize(); } @@ -64,8 +60,7 @@ public class MenuRowFactory { return new TvOptionsRow( mMainActivity, menu, - mCustomizationManager.getCustomActions(CustomizationManager.ID_OPTIONS_ROW), - mLegacyFlags); + mCustomizationManager.getCustomActions(CustomizationManager.ID_OPTIONS_ROW)); } return null; } @@ -75,17 +70,13 @@ public class MenuRowFactory { /** The ID of the row. */ public static final String ID = TvOptionsRow.class.getName(); - private TvOptionsRow( - Context context, - Menu menu, - List<CustomAction> customActions, - LegacyFlags legacyFlags) { + private TvOptionsRow(Context context, Menu menu, List<CustomAction> customActions) { super( context, menu, R.string.menu_title_options, R.dimen.action_card_height, - new TvOptionsRowAdapter(context, customActions, legacyFlags)); + new TvOptionsRowAdapter(context, customActions)); } } diff --git a/src/com/android/tv/menu/MenuRowView.java b/src/com/android/tv/menu/MenuRowView.java index e09a4ef0..a064f352 100644 --- a/src/com/android/tv/menu/MenuRowView.java +++ b/src/com/android/tv/menu/MenuRowView.java @@ -25,7 +25,6 @@ import android.util.Log; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; -import android.view.accessibility.AccessibilityEvent; import android.widget.LinearLayout; import android.widget.TextView; import com.android.tv.R; @@ -90,18 +89,6 @@ public abstract class MenuRowView extends LinearLayout { float textSizeDeselected = res.getDimensionPixelSize(R.dimen.menu_row_title_text_size_deselected); mTitleViewScaleSelected = textSizeSelected / textSizeDeselected; - this.setAccessibilityDelegate( - new AccessibilityDelegate() { - @Override - public void sendAccessibilityEvent(View host, int eventType) { - super.sendAccessibilityEvent(host, eventType); - if (eventType == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED && - !mRow.isReselected()) { - requestChildFocus(); - } - } - } - ); } @Override @@ -190,9 +177,6 @@ public abstract class MenuRowView extends LinearLayout { mLastFocusView = v; } - /** Subclasses should implement this to request focus on child. */ - protected abstract void requestChildFocus(); - /** * Called when the focus of a child view is changed. The inherited class should override this * method instead of calling {@link diff --git a/src/com/android/tv/menu/MenuView.java b/src/com/android/tv/menu/MenuView.java index add4a774..f5fec000 100644 --- a/src/com/android/tv/menu/MenuView.java +++ b/src/com/android/tv/menu/MenuView.java @@ -250,40 +250,39 @@ public class MenuView extends FrameLayout implements IMenuView { // The bounds of the views move and overlap with each other during the animation. In this // situation, the framework can't perform the correct focus navigation. So the menu view // should search by itself. - if (direction == View.FOCUS_UP || direction == View.FOCUS_DOWN) { - return getUpDownFocus(focused, direction); - } - return super.focusSearch(focused, direction); - } - - private View getUpDownFocus(View focused, int direction) { - View newView = super.focusSearch(focused, direction); - MenuRowView oldfocusedParent = getParentMenuRowView(focused); - MenuRowView newFocusedParent = getParentMenuRowView(newView); - int selectedPosition = mLayoutManager.getSelectedPosition(); - int start, delta; if (direction == View.FOCUS_UP) { - start = selectedPosition - 1; - delta = -1; - } else { - start = selectedPosition + 1; - delta = 1; - } - if (newFocusedParent != oldfocusedParent) { - // The focus leaves from the current menu row view. - int count = mMenuRowViews.size(); - int i = start; - while (i < count && i >= 0) { - MenuRowView view = mMenuRowViews.get(i); - if (view.getVisibility() == View.VISIBLE) { - mMenuRows.get(i).setIsReselected(false); - return view; + View newView = super.focusSearch(focused, direction); + MenuRowView oldfocusedParent = getParentMenuRowView(focused); + MenuRowView newFocusedParent = getParentMenuRowView(newView); + int selectedPosition = mLayoutManager.getSelectedPosition(); + if (newFocusedParent != oldfocusedParent) { + // The focus leaves from the current menu row view. + for (int i = selectedPosition - 1; i >= 0; --i) { + MenuRowView view = mMenuRowViews.get(i); + if (view.getVisibility() == View.VISIBLE) { + return view; + } + } + } + return newView; + } else if (direction == View.FOCUS_DOWN) { + View newView = super.focusSearch(focused, direction); + MenuRowView oldfocusedParent = getParentMenuRowView(focused); + MenuRowView newFocusedParent = getParentMenuRowView(newView); + int selectedPosition = mLayoutManager.getSelectedPosition(); + if (newFocusedParent != oldfocusedParent) { + // The focus leaves from the current menu row view. + int count = mMenuRowViews.size(); + for (int i = selectedPosition + 1; i < count; ++i) { + MenuRowView view = mMenuRowViews.get(i); + if (view.getVisibility() == View.VISIBLE) { + return view; + } } - i += delta; } + return newView; } - mMenuRows.get(selectedPosition).setIsReselected(true); - return newView; + return super.focusSearch(focused, direction); } private MenuRowView getParentMenuRowView(View view) { diff --git a/src/com/android/tv/menu/PlayControlsButton.java b/src/com/android/tv/menu/PlayControlsButton.java index 1b85d632..ac3292a3 100644 --- a/src/com/android/tv/menu/PlayControlsButton.java +++ b/src/com/android/tv/menu/PlayControlsButton.java @@ -22,7 +22,6 @@ import android.content.Context; import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; -import android.view.accessibility.AccessibilityNodeInfo; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; @@ -147,11 +146,4 @@ public class PlayControlsButton extends FrameLayout { mIcon.setAlpha(enabled ? ALPHA_ENABLED : ALPHA_DISABLED); mLabel.setEnabled(enabled); } - - /** Request focus and accessibility focus to the button */ - public boolean requestFocusWithAccessibility() { - return mButton.requestFocus() && - mButton.performAccessibilityAction( - AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); - } } diff --git a/src/com/android/tv/menu/PlayControlsRowView.java b/src/com/android/tv/menu/PlayControlsRowView.java index 5dde3be0..0ce74ae1 100644 --- a/src/com/android/tv/menu/PlayControlsRowView.java +++ b/src/com/android/tv/menu/PlayControlsRowView.java @@ -24,7 +24,6 @@ import android.util.AttributeSet; import android.view.View; import android.widget.TextView; import android.widget.Toast; - import com.android.tv.MainActivity; import com.android.tv.R; import com.android.tv.TimeShiftManager; @@ -32,8 +31,8 @@ import com.android.tv.TimeShiftManager.TimeShiftActionId; import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.feature.CommonFeatures; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dialog.HalfSizedDialogFragment; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.DvrDataManager.OnDvrScheduleLoadFinishedListener; @@ -488,11 +487,6 @@ public class PlayControlsRowView extends MenuRowView { } } - @Override - protected void requestChildFocus() { - mPlayPauseButton.requestFocusWithAccessibility(); - } - /** Updates the view contents. It is called from the PlayControlsRow. */ public void update() { updateAll(false); diff --git a/src/com/android/tv/menu/TvOptionsRowAdapter.java b/src/com/android/tv/menu/TvOptionsRowAdapter.java index 418560a8..fe52b25e 100644 --- a/src/com/android/tv/menu/TvOptionsRowAdapter.java +++ b/src/com/android/tv/menu/TvOptionsRowAdapter.java @@ -19,8 +19,8 @@ package com.android.tv.menu; import android.content.Context; import android.media.tv.TvTrackInfo; import com.android.tv.TvOptionsManager; -import com.android.tv.common.BuildConfig; import com.android.tv.common.customization.CustomAction; +import com.android.tv.common.util.CommonUtils; import com.android.tv.data.DisplayMode; import com.android.tv.features.TvFeatures; import com.android.tv.ui.TvViewUiManager; @@ -28,7 +28,6 @@ import com.android.tv.ui.sidepanel.ClosedCaptionFragment; import com.android.tv.ui.sidepanel.DeveloperOptionFragment; import com.android.tv.ui.sidepanel.DisplayModeFragment; import com.android.tv.ui.sidepanel.MultiAudioFragment; -import com.android.tv.common.flags.LegacyFlags; import java.util.ArrayList; import java.util.List; @@ -36,12 +35,8 @@ import java.util.List; * An adapter of options. */ public class TvOptionsRowAdapter extends CustomizableOptionsRowAdapter { - private final LegacyFlags mLegacyFlags; - - public TvOptionsRowAdapter( - Context context, List<CustomAction> customActions, LegacyFlags mLegacyFlags) { + public TvOptionsRowAdapter(Context context, List<CustomAction> customActions) { super(context, customActions); - this.mLegacyFlags = mLegacyFlags; } @Override @@ -54,7 +49,7 @@ public class TvOptionsRowAdapter extends CustomizableOptionsRowAdapter { } actionList.add(MenuAction.SELECT_AUDIO_LANGUAGE_ACTION); actionList.add(MenuAction.MORE_CHANNELS_ACTION); - if (BuildConfig.ENG || mLegacyFlags.enableDeveloperFeatures()) { + if (CommonUtils.isDeveloper()) { actionList.add(MenuAction.DEV_ACTION); } actionList.add(MenuAction.SETTINGS_ACTION); diff --git a/src/com/android/tv/modules/TvApplicationModule.java b/src/com/android/tv/modules/TvApplicationModule.java index 99753d1e..45383ae1 100644 --- a/src/com/android/tv/modules/TvApplicationModule.java +++ b/src/com/android/tv/modules/TvApplicationModule.java @@ -16,101 +16,43 @@ package com.android.tv.modules; import android.content.Context; - import com.android.tv.MainActivity; -import com.android.tv.SetupPassthroughActivity; import com.android.tv.TvApplication; -import com.android.tv.common.buildtype.BuildTypeModule; import com.android.tv.common.concurrent.NamedThreadFactory; import com.android.tv.common.dagger.ApplicationModule; import com.android.tv.common.dagger.annotations.ApplicationContext; -import com.android.tv.data.ChannelDataManager; -import com.android.tv.data.ChannelDataManagerFactory; -import com.android.tv.data.epg.EpgFetchService; -import com.android.tv.data.epg.EpgFetcher; -import com.android.tv.data.epg.EpgFetcherImpl; -import com.android.tv.dialog.PinDialogFragment; -import com.android.tv.dvr.DvrDataManager; -import com.android.tv.dvr.DvrDataManagerImpl; -import com.android.tv.dvr.WritableDvrDataManager; -import com.android.tv.dvr.ui.playback.DvrPlaybackActivity; import com.android.tv.onboarding.OnboardingActivity; -import com.android.tv.onboarding.SetupSourcesFragment; -import com.android.tv.setup.SystemSetupActivity; -import com.android.tv.ui.DetailsActivity; import com.android.tv.util.AsyncDbTask; import com.android.tv.util.TvInputManagerHelper; - -import dagger.Binds; import dagger.Module; import dagger.Provides; -import dagger.android.ContributesAndroidInjector; - -import com.android.tv.common.flags.LegacyFlags; - import java.util.concurrent.Executor; import java.util.concurrent.Executors; - import javax.inject.Singleton; /** Dagger module for {@link TvApplication}. */ @Module( includes = { ApplicationModule.class, - BuildTypeModule.class, - DetailsActivity.Module.class, - DvrPlaybackActivity.Module.class, - MainActivity.Module.class, - OnboardingActivity.Module.class, - SetupPassthroughActivity.Module.class, - SetupSourcesFragment.ContentFragment.Module.class, - SystemSetupActivity.Module.class, TvSingletonsModule.class, + MainActivity.Module.class, + OnboardingActivity.Module.class }) -public abstract class TvApplicationModule { +public class TvApplicationModule { private static final NamedThreadFactory THREAD_FACTORY = new NamedThreadFactory("tv-app-db"); @Provides @AsyncDbTask.DbExecutor @Singleton - static Executor providesDbExecutor() { + Executor providesDbExecutor() { return Executors.newSingleThreadExecutor(THREAD_FACTORY); } @Provides @Singleton - static TvInputManagerHelper providesTvInputManagerHelper( - @ApplicationContext Context context, LegacyFlags legacyFlags) { - TvInputManagerHelper tvInputManagerHelper = new TvInputManagerHelper(context, legacyFlags); + TvInputManagerHelper providesTvInputManagerHelper(@ApplicationContext Context context) { + TvInputManagerHelper tvInputManagerHelper = new TvInputManagerHelper(context); tvInputManagerHelper.start(); - // Since this is injected as a Lazy in the application start is delayed. return tvInputManagerHelper; } - - @Provides - @Singleton - static ChannelDataManager providesChannelDataManager(ChannelDataManagerFactory factory) { - ChannelDataManager channelDataManager = factory.create(); - channelDataManager.start(); - // Since this is injected as a Lazy in the application start is delayed. - return channelDataManager; - } - - @Binds - @Singleton - abstract DvrDataManager providesDvrDataManager(DvrDataManagerImpl impl); - - @Binds - @Singleton - abstract WritableDvrDataManager providesWritableDvrDataManager(DvrDataManagerImpl impl); - - @Binds - @Singleton - abstract EpgFetcher epgFetcher(EpgFetcherImpl impl); - - @ContributesAndroidInjector - abstract PinDialogFragment contributesPinDialogFragment(); - - @ContributesAndroidInjector - abstract EpgFetchService contributesEpgFetchService(); } diff --git a/src/com/android/tv/modules/TvSingletonsModule.java b/src/com/android/tv/modules/TvSingletonsModule.java index f8d10fde..f998c08b 100644 --- a/src/com/android/tv/modules/TvSingletonsModule.java +++ b/src/com/android/tv/modules/TvSingletonsModule.java @@ -16,9 +16,8 @@ package com.android.tv.modules; import com.android.tv.TvSingletons; +import com.android.tv.data.ChannelDataManager; import com.android.tv.data.ProgramDataManager; -import com.android.tv.dvr.DvrWatchedPositionManager; - import dagger.Module; import dagger.Provides; @@ -37,8 +36,8 @@ public class TvSingletonsModule { } @Provides - DvrWatchedPositionManager providesDvrWatchedPositionManager() { - return mTvSingletons.getDvrWatchedPositionManager(); + ChannelDataManager providesChannelDataManager() { + return mTvSingletons.getChannelDataManager(); } @Provides diff --git a/src/com/android/tv/onboarding/OnboardingActivity.java b/src/com/android/tv/onboarding/OnboardingActivity.java index 1739e5a0..776ae664 100644 --- a/src/com/android/tv/onboarding/OnboardingActivity.java +++ b/src/com/android/tv/onboarding/OnboardingActivity.java @@ -88,7 +88,7 @@ public class OnboardingActivity extends SetupActivity { TvSingletons singletons = TvSingletons.getSingletons(this); mInputManager = singletons.getTvInputManagerHelper(); if (PermissionUtils.hasAccessAllEpg(this) || PermissionUtils.hasReadTvListings(this)) { - // Make the channels of the new inputs which have been setup outside TV app + // Make the channels of the new inputs which have been setup outside Live TV // browsable. if (mChannelDataManager.isDbLoadFinished()) { mSetupUtils.markNewChannelsBrowsable(); @@ -187,7 +187,7 @@ public class OnboardingActivity extends SetupActivity { } // Even though other app can handle the intent, the setup launched by // Live - // channels should go through TV app SetupPassthroughActivity. + // channels should go through Live channels SetupPassthroughActivity. intent.setComponent( new ComponentName(this, SetupPassthroughActivity.class)); try { diff --git a/src/com/android/tv/onboarding/SetupSourcesFragment.java b/src/com/android/tv/onboarding/SetupSourcesFragment.java index b54d1bc9..3566c9c3 100644 --- a/src/com/android/tv/onboarding/SetupSourcesFragment.java +++ b/src/com/android/tv/onboarding/SetupSourcesFragment.java @@ -16,44 +16,33 @@ package com.android.tv.onboarding; -import android.app.Activity; +import android.content.Context; import android.graphics.Typeface; import android.media.tv.TvInputInfo; import android.media.tv.TvInputManager.TvInputCallback; import android.os.Bundle; import android.support.annotation.NonNull; +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.leanback.widget.GuidedAction; +import android.support.v17.leanback.widget.GuidedActionsStylist; +import android.support.v17.leanback.widget.VerticalGridView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; - -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; -import androidx.leanback.widget.GuidedActionsStylist; -import androidx.leanback.widget.VerticalGridView; - import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.common.ui.setup.SetupGuidedStepFragment; import com.android.tv.common.ui.setup.SetupMultiPaneFragment; import com.android.tv.data.ChannelDataManager; import com.android.tv.data.TvInputNewComparator; -import com.android.tv.tunerinputcontroller.BuiltInTunerManager; import com.android.tv.ui.GuidedActionsStylistWithDivider; import com.android.tv.util.SetupUtils; import com.android.tv.util.TvInputManagerHelper; - -import com.google.common.base.Optional; - -import dagger.android.AndroidInjection; -import dagger.android.ContributesAndroidInjector; - import java.util.ArrayList; import java.util.Collections; import java.util.List; -import javax.inject.Inject; - /** A fragment for channel source info/setup. */ public class SetupSourcesFragment extends SetupMultiPaneFragment { /** The action category for the actions which is fired from this fragment. */ @@ -117,10 +106,9 @@ public class SetupSourcesFragment extends SetupMultiPaneFragment { private static final int PENDING_ACTION_INPUT_CHANGED = 1; private static final int PENDING_ACTION_CHANNEL_CHANGED = 2; - @Inject TvInputManagerHelper mInputManager; - @Inject ChannelDataManager mChannelDataManager; - @Inject SetupUtils mSetupUtils; - @Inject Optional<BuiltInTunerManager> mBuiltInTunerManagerOptional; + private TvInputManagerHelper mInputManager; + private ChannelDataManager mChannelDataManager; + private SetupUtils mSetupUtils; private List<TvInputInfo> mInputs; private int mKnownInputStartIndex; private int mDoneInputStartIndex; @@ -199,38 +187,37 @@ public class SetupSourcesFragment extends SetupMultiPaneFragment { @Override public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mParentFragment = (SetupSourcesFragment) getParentFragment(); - } - - @Override - public void onAttach(Activity activity) { - AndroidInjection.inject(this); - super.onAttach(activity); + Context context = getActivity(); + TvSingletons singletons = TvSingletons.getSingletons(context); + mInputManager = singletons.getTvInputManagerHelper(); + mChannelDataManager = singletons.getChannelDataManager(); + mSetupUtils = singletons.getSetupUtils(); buildInputs(); mInputManager.addCallback(mInputCallback); mChannelDataManager.addListener(mChannelDataManagerListener); + super.onCreate(savedInstanceState); mParentFragment = (SetupSourcesFragment) getParentFragment(); - if (mBuiltInTunerManagerOptional.isPresent()) { - mBuiltInTunerManagerOptional + if (singletons.getBuiltInTunerManager().isPresent()) { + singletons + .getBuiltInTunerManager() .get() .getTunerInputController() - .executeNetworkTunerDiscoveryAsyncTask(activity); + .executeNetworkTunerDiscoveryAsyncTask(getContext()); } } @Override - public void onDetach() { + public void onDestroy() { + super.onDestroy(); mChannelDataManager.removeListener(mChannelDataManagerListener); mInputManager.removeCallback(mInputCallback); - super.onDetach(); } @NonNull @Override public Guidance onCreateGuidance(Bundle savedInstanceState) { String title = getString(R.string.setup_sources_text); - String description = getString(R.string.setup_sources_description2); + String description = getString(R.string.setup_sources_description); return new Guidance(title, description, null, null); } @@ -417,13 +404,5 @@ public class SetupSourcesFragment extends SetupMultiPaneFragment { setAccessibilityDelegate(vh, action); } } - /** - * Exports {@link ContentFragment} for Dagger codegen to create the appropriate injector. - */ - @dagger.Module - public abstract static class Module { - @ContributesAndroidInjector - abstract ContentFragment contributesContentFragment(); - } } } diff --git a/src/com/android/tv/onboarding/WelcomeFragment.java b/src/com/android/tv/onboarding/WelcomeFragment.java index 667da058..8c119a8a 100644 --- a/src/com/android/tv/onboarding/WelcomeFragment.java +++ b/src/com/android/tv/onboarding/WelcomeFragment.java @@ -25,7 +25,7 @@ import android.animation.AnimatorSet; import android.content.Context; import android.os.Bundle; import android.support.annotation.Nullable; -import androidx.leanback.app.OnboardingFragment; +import android.support.v17.leanback.app.OnboardingFragment; import android.text.Editable; import android.text.TextWatcher; import android.view.Gravity; @@ -621,9 +621,9 @@ public class WelcomeFragment extends OnboardingFragment { LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = super.onCreateView(inflater, container, savedInstanceState); setLogoResourceId(R.drawable.splash_logo); - mTitleView = view.findViewById(androidx.leanback.R.id.title); - mPagingIndicator = view.findViewById(androidx.leanback.R.id.page_indicator); - mStartButton = view.findViewById(androidx.leanback.R.id.button_start); + mTitleView = view.findViewById(android.support.v17.leanback.R.id.title); + mPagingIndicator = view.findViewById(android.support.v17.leanback.R.id.page_indicator); + mStartButton = view.findViewById(android.support.v17.leanback.R.id.button_start); mStartButton.setAccessibilityDelegate( new AccessibilityDelegate() { diff --git a/src/com/android/tv/parental/ContentRatingsManager.java b/src/com/android/tv/parental/ContentRatingsManager.java index 174039ba..32a1325b 100644 --- a/src/com/android/tv/parental/ContentRatingsManager.java +++ b/src/com/android/tv/parental/ContentRatingsManager.java @@ -22,7 +22,6 @@ import android.media.tv.TvContentRatingSystemInfo; import android.support.annotation.Nullable; import android.text.TextUtils; import com.android.tv.R; -import com.android.tv.common.util.PermissionUtils; import com.android.tv.parental.ContentRatingSystem.Rating; import com.android.tv.parental.ContentRatingSystem.SubRating; import com.android.tv.util.TvInputManagerHelper; @@ -43,14 +42,13 @@ public class ContentRatingsManager { public void update() { mContentRatingSystems.clear(); - if (PermissionUtils.hasReadContetnRatingSystem(mContext)) { - ContentRatingsParser parser = new ContentRatingsParser(mContext); - List<TvContentRatingSystemInfo> infos = mTvInputManager.getTvContentRatingSystemList(); - for (TvContentRatingSystemInfo info : infos) { - List<ContentRatingSystem> list = parser.parse(info); - if (list != null) { - mContentRatingSystems.addAll(list); - } + ContentRatingsParser parser = new ContentRatingsParser(mContext); + + List<TvContentRatingSystemInfo> infos = mTvInputManager.getTvContentRatingSystemList(); + for (TvContentRatingSystemInfo info : infos) { + List<ContentRatingSystem> list = parser.parse(info); + if (list != null) { + mContentRatingSystems.addAll(list); } } } diff --git a/src/com/android/tv/parental/ParentalControlSettings.java b/src/com/android/tv/parental/ParentalControlSettings.java index 9990ae35..b41b160e 100644 --- a/src/com/android/tv/parental/ParentalControlSettings.java +++ b/src/com/android/tv/parental/ParentalControlSettings.java @@ -19,12 +19,12 @@ package com.android.tv.parental; import android.content.Context; import android.media.tv.TvContentRating; import android.media.tv.TvInputManager; +import com.android.tv.common.experiments.Experiments; import com.android.tv.parental.ContentRatingSystem.Rating; import com.android.tv.parental.ContentRatingSystem.SubRating; import com.android.tv.util.TvSettings; import com.android.tv.util.TvSettings.ContentRatingLevel; import com.google.common.collect.ImmutableList; -import com.android.tv.common.flags.LegacyFlags; import java.util.HashSet; import java.util.Set; @@ -40,16 +40,14 @@ public class ParentalControlSettings { private final Context mContext; private final TvInputManager mTvInputManager; - private final LegacyFlags mLegacyFlags; // mRatings is expected to be synchronized with mTvInputManager.getBlockedRatings(). private Set<TvContentRating> mRatings; private Set<TvContentRating> mCustomRatings; - public ParentalControlSettings(Context context, LegacyFlags legacyFlags) { + public ParentalControlSettings(Context context) { mContext = context; mTvInputManager = (TvInputManager) mContext.getSystemService(Context.TV_INPUT_SERVICE); - mLegacyFlags = legacyFlags; } public boolean isParentalControlsEnabled() { @@ -132,7 +130,7 @@ public class ParentalControlSettings { } else { mRatings = ContentRatingLevelPolicy.getRatingsForLevel(this, manager, level); if (level != TvSettings.CONTENT_RATING_LEVEL_NONE - && mLegacyFlags.enableUnratedContentSettings()) { + && Boolean.TRUE.equals(Experiments.ENABLE_UNRATED_CONTENT_SETTINGS.get())) { // UNRATED contents should be blocked unless the rating level is none or custom mRatings.add(TvContentRating.UNRATED); } diff --git a/src/com/android/tv/perf/PerformanceMonitor.java b/src/com/android/tv/perf/PerformanceMonitor.java index 30197c74..b1ae759d 100644 --- a/src/com/android/tv/perf/PerformanceMonitor.java +++ b/src/com/android/tv/perf/PerformanceMonitor.java @@ -96,14 +96,4 @@ public interface PerformanceMonitor { * @return true if the activity is available to start */ boolean startPerformanceMonitorEventDebugActivity(Context context); - - /** - * Initialize crash monitoring for an app by wrapping the default {@link - * Thread.UncaughtExceptionHandler} with a handler that can report crashes to the performance - * montitor and then delegate the handling of the UncaughtException to the original default - * {@link Thread.UncaughtExceptionHandler}. - * - * <p>Note: This will override the current {@link Thread.UncaughtExceptionHandler}. - */ - void startCrashMonitor(); } diff --git a/src/com/android/tv/perf/PerformanceMonitorManager.java b/src/com/android/tv/perf/PerformanceMonitorManager.java new file mode 100644 index 00000000..db6667d1 --- /dev/null +++ b/src/com/android/tv/perf/PerformanceMonitorManager.java @@ -0,0 +1,38 @@ +/* + * 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.perf; + +import android.app.Application; + +/** Manages the initialization of Performance Monitoring. */ +public interface PerformanceMonitorManager { + + /** + * Initializes the {@link com.android.tv.perf.PerformanceMonitor}. + * + * <p>This should only be called once. + */ + PerformanceMonitor initialize(Application app); + + /** + * Returns a lightweight object to help measure both cold and warm startup latency. + * + * <p>This method is idempotent and lightweight. It can be called multiple times and does not + * need to be cached. + */ + StartupMeasure getStartupMeasure(); +} diff --git a/common/src/com/android/tv/common/buildtype/BuildTypeFactory.java b/src/com/android/tv/perf/PerformanceMonitorManagerFactory.java index 706a6034..fe3ea14b 100644 --- a/common/src/com/android/tv/common/buildtype/BuildTypeFactory.java +++ b/src/com/android/tv/perf/PerformanceMonitorManagerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * 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. @@ -13,29 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.tv.common.buildtype; - -import com.google.common.base.Supplier; +package com.android.tv.perf; +import com.android.tv.perf.stub.StubPerformanceMonitorManager; import javax.inject.Inject; - -/** Factory for {@link HasBuildType.BuildType}. - * - * <p>Hardcoded to {@link HasBuildType.BuildType#AOSP}. - */ -public class BuildTypeFactory implements Supplier<HasBuildType> { - private static final HasBuildType INSTANCE = new AospBuildTypeProvider(); +public final class PerformanceMonitorManagerFactory { + private static final PerformanceMonitorManagerFactory INSTANCE = + new PerformanceMonitorManagerFactory(); @Inject - public BuildTypeFactory() {} + public PerformanceMonitorManagerFactory() {} - public static HasBuildType create() { - return INSTANCE; + public static PerformanceMonitorManager create() { + return INSTANCE.get(); } - @Override - public HasBuildType get() { - return INSTANCE; + public PerformanceMonitorManager get() { + return new StubPerformanceMonitorManager(); } -}
\ No newline at end of file +} diff --git a/src/com/android/tv/perf/StartupMeasure.java b/src/com/android/tv/perf/StartupMeasure.java index c7fa50fe..5cf183ca 100644 --- a/src/com/android/tv/perf/StartupMeasure.java +++ b/src/com/android/tv/perf/StartupMeasure.java @@ -19,16 +19,8 @@ import android.app.Activity; import android.app.Application; /** - * Measures App startup. - * - * <p>This interface is lightweight to help measure both cold and warm startup latency. - * Implementations must not throw any Exception. - * - * <p>Because this class needs to be used in static initialization blocks, it can not be injected - * via dagger. - * - * <p>Creating implementations of this interface must be idempotent and lightweight. It does not - * need to be cached. + * Measures App startup. This interface is lightweight to help measure both cold and warm startup + * latency. Implementations must not throw any Exception. */ public interface StartupMeasure { diff --git a/src/com/android/tv/perf/StartupMeasureFactory.java b/src/com/android/tv/perf/StartupMeasureFactory.java deleted file mode 100644 index a99c88af..00000000 --- a/src/com/android/tv/perf/StartupMeasureFactory.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2019 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.perf; - - -import com.android.tv.perf.stub.StubStartupMeasure; - -import com.google.common.base.Supplier; -import java.lang.Override; -import javax.inject.Inject; - -/** Factory for {@link StartupMeasure}. - * - * <p>Hardcoded to {@link StubStartupMeasure}. - */ -public final class StartupMeasureFactory implements Supplier<StartupMeasure> { - private static final StartupMeasureFactory INSTANCE = new StartupMeasureFactory(); - - @Inject - public StartupMeasureFactory() {} - - public static StartupMeasure create() { - return INSTANCE.get(); - } - - @Override - public StartupMeasure get() { - return new StubStartupMeasure(); - } -} diff --git a/src/com/android/tv/perf/stub/StubPerformanceMonitor.java b/src/com/android/tv/perf/stub/StubPerformanceMonitor.java index ac3dc250..80c2f6c5 100644 --- a/src/com/android/tv/perf/stub/StubPerformanceMonitor.java +++ b/src/com/android/tv/perf/stub/StubPerformanceMonitor.java @@ -56,6 +56,7 @@ public final class StubPerformanceMonitor implements PerformanceMonitor { return false; } - @Override - public void startCrashMonitor() {} + public static TimerEvent startBootstrapTimer() { + return new TimerEvent() {}; + } } diff --git a/common/src/com/android/tv/common/flags/impl/DefaultSetupFlags.java b/src/com/android/tv/perf/stub/StubPerformanceMonitorManager.java index 3abe6627..0c268155 100644 --- a/common/src/com/android/tv/common/flags/impl/DefaultSetupFlags.java +++ b/src/com/android/tv/perf/stub/StubPerformanceMonitorManager.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * 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. @@ -13,26 +13,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.tv.common.flags.impl; -import com.android.tv.common.flags.proto.TypedFeatures.StringListParam; +package com.android.tv.perf.stub; -import com.android.tv.common.flags.SetupFlags; +import android.app.Application; +import com.android.tv.perf.PerformanceMonitor; +import com.android.tv.perf.PerformanceMonitorManager; +import com.android.tv.perf.StartupMeasure; -/** Default {@link SetupFlags} */ -public class DefaultSetupFlags implements SetupFlags { - @Override - public boolean compiled() { - return true; - } +/** Manages a stub implementation of Performance Monitoring. */ +public class StubPerformanceMonitorManager implements PerformanceMonitorManager { @Override - public StringListParam setupPassThroughPackageWhitelist() { - return StringListParam.getDefaultInstance(); + public PerformanceMonitor initialize(Application app) { + return new StubPerformanceMonitor(); } @Override - public boolean useWhitelistForSetupPassThrough() { - return false; + public StartupMeasure getStartupMeasure() { + return new StubStartupMeasure(); } } diff --git a/src/com/android/tv/receiver/AudioCapabilitiesReceiver.java b/src/com/android/tv/receiver/AudioCapabilitiesReceiver.java index 5fa7606d..3fb66245 100644 --- a/src/com/android/tv/receiver/AudioCapabilitiesReceiver.java +++ b/src/com/android/tv/receiver/AudioCapabilitiesReceiver.java @@ -42,7 +42,7 @@ public final class AudioCapabilitiesReceiver { // AC3 capabilities stat is sent to Google Analytics just once in order to avoid // duplicated stat reports since it doesn't change over time in most cases. // Increase this revision when we should force the stat to be sent again. - // TODO: Consider using custom metrics. + // TODO: Consier using custom metrics. private static final int REPORT_REVISION = 1; private final Context mContext; diff --git a/src/com/android/tv/receiver/PackageIntentsReceiver.java b/src/com/android/tv/receiver/PackageIntentsReceiver.java index 7ff67b50..5bc6d724 100644 --- a/src/com/android/tv/receiver/PackageIntentsReceiver.java +++ b/src/com/android/tv/receiver/PackageIntentsReceiver.java @@ -23,7 +23,9 @@ import android.net.Uri; import android.util.Log; import com.android.tv.Starter; import com.android.tv.TvSingletons; +import com.android.tv.features.TvFeatures; import com.android.tv.util.Partner; +import com.google.android.tv.partner.support.EpgContract; /** A class for handling the broadcast intents from PackageManager. */ public class PackageIntentsReceiver extends BroadcastReceiver { diff --git a/src/com/android/tv/recommendation/ChannelPreviewUpdater.java b/src/com/android/tv/recommendation/ChannelPreviewUpdater.java index 61ebb2d0..2590a337 100644 --- a/src/com/android/tv/recommendation/ChannelPreviewUpdater.java +++ b/src/com/android/tv/recommendation/ChannelPreviewUpdater.java @@ -27,18 +27,15 @@ import android.os.Build; import android.support.annotation.RequiresApi; import android.text.TextUtils; import android.util.Log; - import androidx.tvprovider.media.tv.TvContractCompat; - import com.android.tv.Starter; import com.android.tv.TvSingletons; import com.android.tv.data.PreviewDataManager; import com.android.tv.data.PreviewProgramContent; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.parental.ParentalControlSettings; import com.android.tv.util.Utils; - import java.util.ArrayList; import java.util.HashSet; import java.util.List; diff --git a/src/com/android/tv/recommendation/ChannelRecord.java b/src/com/android/tv/recommendation/ChannelRecord.java index f047aac6..c7a7cb37 100644 --- a/src/com/android/tv/recommendation/ChannelRecord.java +++ b/src/com/android/tv/recommendation/ChannelRecord.java @@ -19,12 +19,10 @@ package com.android.tv.recommendation; import android.content.Context; import android.support.annotation.GuardedBy; import android.support.annotation.VisibleForTesting; - import com.android.tv.TvSingletons; +import com.android.tv.data.Program; import com.android.tv.data.ProgramDataManager; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; - import java.util.ArrayDeque; import java.util.Deque; diff --git a/src/com/android/tv/recommendation/NotificationService.java b/src/com/android/tv/recommendation/NotificationService.java index 1652bd77..f40a0862 100644 --- a/src/com/android/tv/recommendation/NotificationService.java +++ b/src/com/android/tv/recommendation/NotificationService.java @@ -40,21 +40,19 @@ import android.text.TextUtils; import android.util.Log; import android.util.SparseLongArray; import android.view.View; - import com.android.tv.MainActivityWrapper.OnCurrentChannelChangeListener; import com.android.tv.R; import com.android.tv.Starter; import com.android.tv.TvSingletons; import com.android.tv.common.CommonConstants; import com.android.tv.common.WeakHandler; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.util.TvInputManagerHelper; import com.android.tv.util.Utils; import com.android.tv.util.images.BitmapUtils; import com.android.tv.util.images.BitmapUtils.ScaledBitmapInfo; import com.android.tv.util.images.ImageLoader; - import java.util.ArrayList; import java.util.List; diff --git a/src/com/android/tv/recommendation/RecommendationDataManager.java b/src/com/android/tv/recommendation/RecommendationDataManager.java index e254ba58..fc20031c 100644 --- a/src/com/android/tv/recommendation/RecommendationDataManager.java +++ b/src/com/android/tv/recommendation/RecommendationDataManager.java @@ -34,17 +34,14 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.WorkerThread; import android.util.Log; - import com.android.tv.TvSingletons; import com.android.tv.common.WeakHandler; import com.android.tv.common.util.PermissionUtils; import com.android.tv.data.ChannelDataManager; -import com.android.tv.data.ProgramImpl; +import com.android.tv.data.Program; import com.android.tv.data.WatchedHistoryManager; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.util.TvUriMatcher; - import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -235,9 +232,6 @@ public class RecommendationDataManager implements WatchedHistoryManager.Listener @MainThread private void stop() { - if (mWatchedHistoryManager != null) { - mWatchedHistoryManager.setListener(null); - } for (int what = MSG_FIRST; what <= MSG_LAST; ++what) { mHandler.removeMessages(what); } @@ -365,7 +359,7 @@ public class RecommendationDataManager implements WatchedHistoryManager.Listener WatchedHistoryManager.WatchedRecord watchedRecord) { long endTime = watchedRecord.watchedStartTime + watchedRecord.duration; Program program = - new ProgramImpl.Builder() + new Program.Builder() .setChannelId(watchedRecord.channelId) .setTitle("") .setStartTimeUtcMillis(watchedRecord.watchedStartTime) @@ -417,7 +411,7 @@ public class RecommendationDataManager implements WatchedHistoryManager.Listener } Program program = - new ProgramImpl.Builder() + new Program.Builder() .setChannelId(cursor.getLong(mIndexWatchChannelId)) .setTitle(cursor.getString(mIndexProgramTitle)) .setStartTimeUtcMillis(cursor.getLong(mIndexProgramStartTime)) diff --git a/src/com/android/tv/recommendation/Recommender.java b/src/com/android/tv/recommendation/Recommender.java index a8535a49..f350799f 100644 --- a/src/com/android/tv/recommendation/Recommender.java +++ b/src/com/android/tv/recommendation/Recommender.java @@ -20,9 +20,7 @@ import android.content.Context; import android.support.annotation.VisibleForTesting; import android.util.Log; import android.util.Pair; - import com.android.tv.data.api.Channel; - import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -129,7 +127,7 @@ public class Recommender implements RecommendationDataManager.Listener { } } if (!mIncludeRecommendedOnly || maxScore != Evaluator.NOT_RECOMMENDED) { - records.add(Pair.create(cr.getChannel(), maxScore)); + records.add(new Pair<>(cr.getChannel(), maxScore)); } } if (size > records.size()) { diff --git a/src/com/android/tv/recommendation/RoutineWatchEvaluator.java b/src/com/android/tv/recommendation/RoutineWatchEvaluator.java index b3952c01..9240682a 100644 --- a/src/com/android/tv/recommendation/RoutineWatchEvaluator.java +++ b/src/com/android/tv/recommendation/RoutineWatchEvaluator.java @@ -19,9 +19,7 @@ package com.android.tv.recommendation; import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; import android.text.TextUtils; - -import com.android.tv.data.api.Program; - +import com.android.tv.data.Program; import java.text.BreakIterator; import java.util.ArrayList; import java.util.Calendar; diff --git a/src/com/android/tv/recommendation/WatchedProgram.java b/src/com/android/tv/recommendation/WatchedProgram.java index 0da9c620..239de1f2 100644 --- a/src/com/android/tv/recommendation/WatchedProgram.java +++ b/src/com/android/tv/recommendation/WatchedProgram.java @@ -16,7 +16,7 @@ package com.android.tv.recommendation; -import com.android.tv.data.api.Program; +import com.android.tv.data.Program; public final class WatchedProgram { private final Program mProgram; diff --git a/src/com/android/tv/search/DataManagerSearch.java b/src/com/android/tv/search/DataManagerSearch.java index 1a0ada3a..a649c0ac 100644 --- a/src/com/android/tv/search/DataManagerSearch.java +++ b/src/com/android/tv/search/DataManagerSearch.java @@ -26,18 +26,15 @@ import android.os.SystemClock; import android.support.annotation.MainThread; import android.text.TextUtils; import android.util.Log; - import com.android.tv.TvSingletons; import com.android.tv.data.ChannelDataManager; +import com.android.tv.data.Program; import com.android.tv.data.ProgramDataManager; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.search.LocalSearchProvider.SearchResult; import com.android.tv.util.MainThreadExecutor; import com.android.tv.util.Utils; - import com.google.common.collect.ImmutableList; - import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; diff --git a/src/com/android/tv/search/LocalSearchProvider.java b/src/com/android/tv/search/LocalSearchProvider.java index 86999560..5652c986 100644 --- a/src/com/android/tv/search/LocalSearchProvider.java +++ b/src/com/android/tv/search/LocalSearchProvider.java @@ -17,6 +17,7 @@ package com.android.tv.search; import android.app.SearchManager; +import android.content.ContentProvider; import android.content.ContentValues; import android.database.Cursor; import android.database.MatrixCursor; @@ -27,30 +28,21 @@ import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; import android.text.TextUtils; import android.util.Log; - +import com.android.tv.TvSingletons; import com.android.tv.common.CommonConstants; import com.android.tv.common.SoftPreconditions; -import com.android.tv.common.dagger.init.SafePreDaggerInitializer; import com.android.tv.common.util.CommonUtils; import com.android.tv.common.util.PermissionUtils; import com.android.tv.perf.EventNames; import com.android.tv.perf.PerformanceMonitor; import com.android.tv.perf.TimerEvent; import com.android.tv.util.TvUriMatcher; - import com.google.auto.value.AutoValue; - -import dagger.android.ContributesAndroidInjector; -import dagger.android.DaggerContentProvider; - import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import javax.inject.Inject; - -/** Content provider for local search */ -public class LocalSearchProvider extends DaggerContentProvider { +public class LocalSearchProvider extends ContentProvider { private static final String TAG = "LocalSearchProvider"; private static final boolean DEBUG = false; @@ -87,18 +79,14 @@ public class LocalSearchProvider extends DaggerContentProvider { private static final String NO_LIVE_CONTENTS = "0"; private static final String LIVE_CONTENTS = "1"; - @Inject PerformanceMonitor mPerformanceMonitor; + private PerformanceMonitor mPerformanceMonitor; /** Used only for testing */ private SearchInterface mSearchInterface; @Override public boolean onCreate() { - SafePreDaggerInitializer.init(getContext()); - if (!super.onCreate()) { - Log.e(TAG, "LocalSearchProvider.onCreate() failed."); - return false; - } + mPerformanceMonitor = TvSingletons.getSingletons(getContext()).getPerformanceMonitor(); return true; } @@ -233,13 +221,6 @@ public class LocalSearchProvider extends DaggerContentProvider { throw new UnsupportedOperationException(); } - /** Module for {@link LocalSearchProvider} */ - @dagger.Module - public abstract static class Module { - @ContributesAndroidInjector - abstract LocalSearchProvider contributesLocalSearchProviderInjector(); - } - /** A placeholder to a search result. */ @AutoValue public abstract static class SearchResult { @@ -254,8 +235,6 @@ public class LocalSearchProvider extends DaggerContentProvider { .setProgressPercentage(0); } - public abstract Builder toBuilder(); - @AutoValue.Builder abstract static class Builder { abstract Builder setChannelId(long value); diff --git a/src/com/android/tv/search/ProgramGuideSearchFragment.java b/src/com/android/tv/search/ProgramGuideSearchFragment.java index fa2e4516..6c94bd33 100644 --- a/src/com/android/tv/search/ProgramGuideSearchFragment.java +++ b/src/com/android/tv/search/ProgramGuideSearchFragment.java @@ -21,18 +21,18 @@ import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.os.AsyncTask; import android.os.Bundle; -import androidx.leanback.app.SearchFragment; -import androidx.leanback.widget.ArrayObjectAdapter; -import androidx.leanback.widget.HeaderItem; -import androidx.leanback.widget.ImageCardView; -import androidx.leanback.widget.ListRow; -import androidx.leanback.widget.ListRowPresenter; -import androidx.leanback.widget.ObjectAdapter; -import androidx.leanback.widget.OnItemViewClickedListener; -import androidx.leanback.widget.Presenter; -import androidx.leanback.widget.Row; -import androidx.leanback.widget.RowPresenter; -import androidx.leanback.widget.SearchBar; +import android.support.v17.leanback.app.SearchFragment; +import android.support.v17.leanback.widget.ArrayObjectAdapter; +import android.support.v17.leanback.widget.HeaderItem; +import android.support.v17.leanback.widget.ImageCardView; +import android.support.v17.leanback.widget.ListRow; +import android.support.v17.leanback.widget.ListRowPresenter; +import android.support.v17.leanback.widget.ObjectAdapter; +import android.support.v17.leanback.widget.OnItemViewClickedListener; +import android.support.v17.leanback.widget.Presenter; +import android.support.v17.leanback.widget.Row; +import android.support.v17.leanback.widget.RowPresenter; +import android.support.v17.leanback.widget.SearchBar; import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; diff --git a/src/com/android/tv/search/TvProviderSearch.java b/src/com/android/tv/search/TvProviderSearch.java index c46938a9..8a1f51f9 100644 --- a/src/com/android/tv/search/TvProviderSearch.java +++ b/src/com/android/tv/search/TvProviderSearch.java @@ -308,7 +308,7 @@ public class TvProviderSearch implements SearchInterface { if (c != null && c.moveToNext() && !isRatingBlocked(c.getString(2))) { String channelName = result.getTitle(); String channelNumber = result.getChannelNumber(); - SearchResult.Builder builder = result.toBuilder(); + SearchResult.Builder builder = SearchResult.builder(); long startUtcMillis = c.getLong(5); long endUtcMillis = c.getLong(6); builder.setTitle(c.getString(0)); diff --git a/src/com/android/tv/setup/SystemSetupActivity.java b/src/com/android/tv/setup/SystemSetupActivity.java index 999b157a..b2160b3a 100644 --- a/src/com/android/tv/setup/SystemSetupActivity.java +++ b/src/com/android/tv/setup/SystemSetupActivity.java @@ -24,9 +24,9 @@ import android.content.Intent; import android.media.tv.TvInputInfo; import android.os.Bundle; import android.widget.Toast; - import com.android.tv.R; import com.android.tv.SetupPassthroughActivity; +import com.android.tv.TvSingletons; import com.android.tv.common.CommonConstants; import com.android.tv.common.ui.setup.SetupActivity; import com.android.tv.common.ui.setup.SetupMultiPaneFragment; @@ -36,11 +36,6 @@ import com.android.tv.util.OnboardingUtils; import com.android.tv.util.SetupUtils; import com.android.tv.util.TvInputManagerHelper; -import dagger.android.AndroidInjection; -import dagger.android.ContributesAndroidInjector; - -import javax.inject.Inject; - /** A activity to start input sources setup fragment for initial setup flow. */ public class SystemSetupActivity extends SetupActivity { private static final String SYSTEM_SETUP = @@ -48,17 +43,18 @@ public class SystemSetupActivity extends SetupActivity { private static final int SHOW_RIPPLE_DURATION_MS = 266; private static final int REQUEST_CODE_START_SETUP_ACTIVITY = 1; - @Inject TvInputManagerHelper mInputManager; + private TvInputManagerHelper mInputManager; @Override protected void onCreate(Bundle savedInstanceState) { - AndroidInjection.inject(this); super.onCreate(savedInstanceState); Intent intent = getIntent(); if (!SYSTEM_SETUP.equals(intent.getAction())) { finish(); return; } + TvSingletons singletons = TvSingletons.getSingletons(this); + mInputManager = singletons.getTvInputManagerHelper(); } @Override @@ -96,7 +92,7 @@ public class SystemSetupActivity extends SetupActivity { } // Even though other app can handle the intent, the setup launched by // Live - // channels should go through TV app SetupPassthroughActivity. + // channels should go through Live channels SetupPassthroughActivity. intent.setComponent( new ComponentName(this, SetupPassthroughActivity.class)); try { @@ -128,13 +124,4 @@ public class SystemSetupActivity extends SetupActivity { } return false; } - - /** - * Exports {@link SystemSetupActivity} for Dagger codegen to create the appropriate injector. - */ - @dagger.Module - public abstract static class Module { - @ContributesAndroidInjector - abstract SystemSetupActivity contributeSystemSetupActivity(); - } } diff --git a/src/com/android/tv/ui/AppLayerTvView.java b/src/com/android/tv/ui/AppLayerTvView.java index 4c54fb3c..e2b64a1e 100644 --- a/src/com/android/tv/ui/AppLayerTvView.java +++ b/src/com/android/tv/ui/AppLayerTvView.java @@ -21,6 +21,7 @@ import android.util.AttributeSet; import android.view.SurfaceView; import android.view.View; import com.android.tv.common.compat.TvViewCompat; +import com.android.tv.common.util.CommonUtils; import com.android.tv.common.util.Debug; /** @@ -28,14 +29,9 @@ import com.android.tv.common.util.Debug; * * <p>Once an app starts using additional window like SubPanel and it gets window focus, the {@link * android.media.tv.TvView#setMain()} does not work because its implementation assumes that the app - * uses only application layer. - * - * <p>TODO: remove this class once the TvView.setMain() is revisited. + * uses only application layer. TODO: remove this class once the TvView.setMain() is revisited. */ public class AppLayerTvView extends TvViewCompat { - - boolean mUseSecureSurface = true; - public AppLayerTvView(Context context) { super(context); } @@ -48,11 +44,6 @@ public class AppLayerTvView extends TvViewCompat { super(context, attrs, defStyleAttr); } - /** Set the security of children {@link SurfaceView}s to {@code secure} */ - public void setUseSecureSurface(boolean secure) { - mUseSecureSurface = secure; - } - @Override public boolean hasWindowFocus() { return true; @@ -62,7 +53,7 @@ public class AppLayerTvView extends TvViewCompat { public void onViewAdded(View child) { if (child instanceof SurfaceView) { // Note: See b/29118070 for detail. - ((SurfaceView) child).setSecure(mUseSecureSurface); + ((SurfaceView) child).setSecure(!CommonUtils.isDeveloper()); } super.onViewAdded(child); } diff --git a/src/com/android/tv/ui/ChannelBannerView.java b/src/com/android/tv/ui/ChannelBannerView.java index f0781214..00ac7e32 100644 --- a/src/com/android/tv/ui/ChannelBannerView.java +++ b/src/com/android/tv/ui/ChannelBannerView.java @@ -46,15 +46,13 @@ import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.TextView; - import com.android.tv.R; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.feature.CommonFeatures; import com.android.tv.common.singletons.HasSingletons; -import com.android.tv.data.ProgramImpl; +import com.android.tv.data.Program; import com.android.tv.data.StreamInfo; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dvr.DvrManager; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.parental.ContentRatingsManager; @@ -66,9 +64,7 @@ import com.android.tv.util.images.ImageCache; import com.android.tv.util.images.ImageLoader; import com.android.tv.util.images.ImageLoader.ImageLoaderCallback; import com.android.tv.util.images.ImageLoader.LoadTvInputLogoTask; - import com.google.common.collect.ImmutableList; - import javax.inject.Provider; /** A view to render channel banner. */ @@ -122,7 +118,6 @@ public class ChannelBannerView extends FrameLayout private final TvInputManagerHelper mTvInputManagerHelper; // TvOverlayManager is always created after ChannelBannerView private final Provider<TvOverlayManager> mTvOverlayManager; - private final AccessibilityManager mAccessibilityManager; private View mChannelView; @@ -270,12 +265,12 @@ public class ChannelBannerView extends FrameLayout mContentRatingsManager = mTvInputManagerHelper.getContentRatingsManager(); mNoProgram = - new ProgramImpl.Builder() + new Program.Builder() .setTitle(context.getString(R.string.channel_banner_no_title)) .setDescription(EMPTY_STRING) .build(); mLockedChannelProgram = - new ProgramImpl.Builder() + new Program.Builder() .setTitle(context.getString(R.string.channel_banner_locked_channel_title)) .setDescription(EMPTY_STRING) .build(); @@ -283,7 +278,8 @@ public class ChannelBannerView extends FrameLayout sClosedCaptionMark = context.getString(R.string.closed_caption); } mAutoHideScheduler = new AutoHideScheduler(context, this::hide); - mAccessibilityManager = context.getSystemService(AccessibilityManager.class); + context.getSystemService(AccessibilityManager.class) + .addAccessibilityStateChangeListener(mAutoHideScheduler); } @Override @@ -323,18 +319,6 @@ public class ChannelBannerView extends FrameLayout } @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - mAccessibilityManager.addAccessibilityStateChangeListener(mAutoHideScheduler); - } - - @Override - protected void onDetachedFromWindow() { - mAccessibilityManager.removeAccessibilityStateChangeListener(mAutoHideScheduler); - super.onDetachedFromWindow(); - } - - @Override public void onEnterAction(boolean fromEmptyScene) { resetAnimationEffects(); if (fromEmptyScene) { @@ -564,7 +548,7 @@ public class ChannelBannerView extends FrameLayout return new ImageLoaderCallback<ChannelBannerView>(channelBannerView) { @Override public void onBitmapLoaded(ChannelBannerView view, @Nullable Bitmap logo) { - if (!channel.equals(view.mCurrentChannel)) { + if (channel.equals(view.mCurrentChannel)) { // The logo is obsolete. return; } @@ -751,23 +735,15 @@ public class ChannelBannerView extends FrameLayout } else { ImmutableList<TvContentRating> ratings = (program == null) ? null : program.getContentRatings(); - int ratingsViewIndex = 0; - if (ratings != null) { - for (int i = 0; i < ratings.size(); i++) { - if (ratingsViewIndex < DISPLAYED_CONTENT_RATINGS_COUNT - && !TextUtils.isEmpty( - mContentRatingsManager.getDisplayNameForRating( - ratings.get(i)))) { - mContentRatingsTextViews[ratingsViewIndex].setText( - mContentRatingsManager.getDisplayNameForRating(ratings.get(i))); - mContentRatingsTextViews[ratingsViewIndex].setVisibility(View.VISIBLE); - ratingsViewIndex++; - } + for (int i = 0; i < DISPLAYED_CONTENT_RATINGS_COUNT; i++) { + if (ratings == null || ratings.size() <= i) { + mContentRatingsTextViews[i].setVisibility(View.GONE); + } else { + mContentRatingsTextViews[i].setText( + mContentRatingsManager.getDisplayNameForRating(ratings.get(i))); + mContentRatingsTextViews[i].setVisibility(View.VISIBLE); } } - while (ratingsViewIndex < DISPLAYED_CONTENT_RATINGS_COUNT) { - mContentRatingsTextViews[ratingsViewIndex++].setVisibility(View.GONE); - } } } diff --git a/src/com/android/tv/ui/DetailsActivity.java b/src/com/android/tv/ui/DetailsActivity.java index 92c13f57..80c0f64b 100644 --- a/src/com/android/tv/ui/DetailsActivity.java +++ b/src/com/android/tv/ui/DetailsActivity.java @@ -16,11 +16,12 @@ package com.android.tv.ui; +import android.app.Activity; import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Parcelable; import android.support.annotation.NonNull; -import androidx.leanback.app.DetailsFragment; +import android.support.v17.leanback.app.DetailsFragment; import android.transition.Transition; import android.transition.Transition.TransitionListener; import android.util.Log; @@ -34,12 +35,9 @@ import com.android.tv.dvr.ui.browse.CurrentRecordingDetailsFragment; import com.android.tv.dvr.ui.browse.RecordedProgramDetailsFragment; import com.android.tv.dvr.ui.browse.ScheduledRecordingDetailsFragment; import com.android.tv.dvr.ui.browse.SeriesRecordingDetailsFragment; -import dagger.android.ContributesAndroidInjector; -import dagger.android.DaggerActivity; /** Activity to show details view. */ -public class DetailsActivity extends DaggerActivity - implements PinDialogFragment.OnPinCheckedListener { +public class DetailsActivity extends Activity implements PinDialogFragment.OnPinCheckedListener { private static final String TAG = "DetailsActivity"; private static final long INVALID_RECORD_ID = -1; @@ -208,15 +206,4 @@ public class DetailsActivity extends DaggerActivity } finish(); } - - /** Exports {@link DaggerActivity} for Dagger codegen to create the appropriate injector. */ - @dagger.Module - public abstract static class Module { - @ContributesAndroidInjector - abstract DetailsActivity contributesDetailsActivityInjector(); - - @ContributesAndroidInjector - abstract CurrentRecordingDetailsFragment - contributesCurrentRecordingDetailsFragmentInjector(); - } } diff --git a/src/com/android/tv/ui/GuidedActionsStylistWithDivider.java b/src/com/android/tv/ui/GuidedActionsStylistWithDivider.java index 3aba5d1d..9685b04b 100644 --- a/src/com/android/tv/ui/GuidedActionsStylistWithDivider.java +++ b/src/com/android/tv/ui/GuidedActionsStylistWithDivider.java @@ -17,9 +17,9 @@ package com.android.tv.ui; import android.content.Context; -import androidx.leanback.app.GuidedStepFragment; -import androidx.leanback.widget.GuidedAction; -import androidx.leanback.widget.GuidedActionsStylist; +import android.support.v17.leanback.app.GuidedStepFragment; +import android.support.v17.leanback.widget.GuidedAction; +import android.support.v17.leanback.widget.GuidedActionsStylist; import com.android.tv.R; /** Extended stylist class used for {@link GuidedStepFragment} with divider support. */ diff --git a/src/com/android/tv/ui/OnRepeatedKeyInterceptListener.java b/src/com/android/tv/ui/OnRepeatedKeyInterceptListener.java index 703dc242..9b916afe 100644 --- a/src/com/android/tv/ui/OnRepeatedKeyInterceptListener.java +++ b/src/com/android/tv/ui/OnRepeatedKeyInterceptListener.java @@ -17,7 +17,7 @@ package com.android.tv.ui; import android.os.Message; import android.support.annotation.NonNull; -import androidx.leanback.widget.VerticalGridView; +import android.support.v17.leanback.widget.VerticalGridView; import android.util.Log; import android.view.KeyEvent; import android.view.View; diff --git a/src/com/android/tv/ui/ProgramDetailsFragment.java b/src/com/android/tv/ui/ProgramDetailsFragment.java index bfcebd7d..88a7b2ca 100644 --- a/src/com/android/tv/ui/ProgramDetailsFragment.java +++ b/src/com/android/tv/ui/ProgramDetailsFragment.java @@ -23,23 +23,21 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.support.annotation.Nullable; +import android.support.v17.leanback.app.DetailsFragment; +import android.support.v17.leanback.widget.Action; +import android.support.v17.leanback.widget.ArrayObjectAdapter; +import android.support.v17.leanback.widget.ClassPresenterSelector; +import android.support.v17.leanback.widget.DetailsOverviewRow; +import android.support.v17.leanback.widget.DetailsOverviewRowPresenter; +import android.support.v17.leanback.widget.OnActionClickedListener; +import android.support.v17.leanback.widget.PresenterSelector; +import android.support.v17.leanback.widget.SparseArrayObjectAdapter; +import android.support.v17.leanback.widget.VerticalGridView; import android.text.TextUtils; - -import androidx.leanback.app.DetailsFragment; -import androidx.leanback.widget.Action; -import androidx.leanback.widget.ArrayObjectAdapter; -import androidx.leanback.widget.ClassPresenterSelector; -import androidx.leanback.widget.DetailsOverviewRow; -import androidx.leanback.widget.DetailsOverviewRowPresenter; -import androidx.leanback.widget.OnActionClickedListener; -import androidx.leanback.widget.PresenterSelector; -import androidx.leanback.widget.SparseArrayObjectAdapter; -import androidx.leanback.widget.VerticalGridView; - import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.common.feature.CommonFeatures; -import com.android.tv.data.ProgramImpl; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.DvrManager; @@ -66,7 +64,7 @@ public class ProgramDetailsFragment extends DetailsFragment protected DetailsViewBackgroundHelper mBackgroundHelper; private ArrayObjectAdapter mRowsAdapter; private DetailsOverviewRow mDetailsOverview; - private ProgramImpl mProgram; + private Program mProgram; private String mInputId; private ScheduledRecording mScheduledRecording; private DvrManager mDvrManager; @@ -139,7 +137,7 @@ public class ProgramDetailsFragment extends DetailsFragment * the detail activity and fragment will be ended. */ private boolean onLoadDetails(Bundle args) { - ProgramImpl program = args.getParcelable(DetailsActivity.PROGRAM); + Program program = args.getParcelable(DetailsActivity.PROGRAM); long channelId = args.getLong(DetailsActivity.CHANNEL_ID); String inputId = args.getString(DetailsActivity.INPUT_ID); if (program != null && channelId != Channel.INVALID_ID && !TextUtils.isEmpty(inputId)) { diff --git a/src/com/android/tv/ui/SelectInputView.java b/src/com/android/tv/ui/SelectInputView.java index a0cfad32..f4949f08 100644 --- a/src/com/android/tv/ui/SelectInputView.java +++ b/src/com/android/tv/ui/SelectInputView.java @@ -22,8 +22,8 @@ import android.media.tv.TvInputInfo; import android.media.tv.TvInputManager; import android.media.tv.TvInputManager.TvInputCallback; import android.support.annotation.NonNull; -import androidx.leanback.widget.VerticalGridView; -import androidx.recyclerview.widget.RecyclerView; +import android.support.v17.leanback.widget.VerticalGridView; +import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; diff --git a/src/com/android/tv/ui/TunableTvView.java b/src/com/android/tv/ui/TunableTvView.java index a736e79d..5ac6bd83 100644 --- a/src/com/android/tv/ui/TunableTvView.java +++ b/src/com/android/tv/ui/TunableTvView.java @@ -54,13 +54,11 @@ import android.view.View; import android.view.accessibility.AccessibilityManager; import android.widget.FrameLayout; import android.widget.ImageView; - import com.android.tv.InputSessionManager; import com.android.tv.InputSessionManager.TvViewSession; import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.analytics.Tracker; -import com.android.tv.common.BuildConfig; import com.android.tv.common.CommonConstants; import com.android.tv.common.compat.TvInputConstantCompat; import com.android.tv.common.compat.TvViewCompat.TvInputCallbackCompat; @@ -69,11 +67,11 @@ import com.android.tv.common.util.CommonUtils; import com.android.tv.common.util.Debug; import com.android.tv.common.util.DurationTimer; import com.android.tv.common.util.PermissionUtils; +import com.android.tv.data.Program; import com.android.tv.data.ProgramDataManager; import com.android.tv.data.StreamInfo; import com.android.tv.data.WatchedHistoryManager; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.features.TvFeatures; import com.android.tv.parental.ContentRatingsManager; import com.android.tv.parental.ParentalControlSettings; @@ -83,9 +81,6 @@ import com.android.tv.util.NetworkUtils; import com.android.tv.util.TvInputManagerHelper; import com.android.tv.util.Utils; import com.android.tv.util.images.ImageLoader; - -import com.android.tv.common.flags.LegacyFlags; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; @@ -290,12 +285,12 @@ public class TunableTvView extends FrameLayout implements StreamInfo, TunableTvV if (mVideoWidth <= 0 || mVideoHeight <= 0) { mVideoDisplayAspectRatio = 0.0f; } else { - float videoPixelAspectRatio = + float VideoPixelAspectRatio = track.getVideoPixelAspectRatio(); - mVideoDisplayAspectRatio = (float) mVideoWidth - / mVideoHeight; - mVideoDisplayAspectRatio *= videoPixelAspectRatio > 0 ? - videoPixelAspectRatio : 1; + mVideoDisplayAspectRatio = + VideoPixelAspectRatio + * mVideoWidth + / mVideoHeight; } } else if (type == TvTrackInfo.TYPE_AUDIO) { mAudioChannelCount = track.getAudioChannelCount(); @@ -322,7 +317,7 @@ public class TunableTvView extends FrameLayout implements StreamInfo, TunableTvV if (DEBUG) Log.d(TAG, "onVideoAvailable: {inputId=" + inputId + "}"); Debug.getTimer(Debug.TAG_START_UP_TIMER) .log( - "Start up of TV app ends," + "Start up of Live TV ends," + " TunableTvView.onVideoAvailable resets timer"); Debug.getTimer(Debug.TAG_START_UP_TIMER).reset(); Debug.removeTimer(Debug.TAG_START_UP_TIMER); @@ -478,12 +473,8 @@ public class TunableTvView extends FrameLayout implements StreamInfo, TunableTvV } public void initialize( - ProgramDataManager programDataManager, - TvInputManagerHelper tvInputManagerHelper, - LegacyFlags mLegacyFlags) { + ProgramDataManager programDataManager, TvInputManagerHelper tvInputManagerHelper) { mTvView = findViewById(R.id.tv_view); - mTvView.setUseSecureSurface(!BuildConfig.ENG && !mLegacyFlags.enableDeveloperFeatures()); - mProgramDataManager = programDataManager; mInputManagerHelper = tvInputManagerHelper; mContentRatingsManager = tvInputManagerHelper.getContentRatingsManager(); @@ -562,9 +553,7 @@ public class TunableTvView extends FrameLayout implements StreamInfo, TunableTvV } public void setMain() { - if (PermissionUtils.hasChangeHdmiCecActiveSource(getContext())) { - mTvView.setMain(); - } + mTvView.setMain(); } public void setWatchedHistoryManager(WatchedHistoryManager watchedHistoryManager) { @@ -664,22 +653,17 @@ public class TunableTvView extends FrameLayout implements StreamInfo, TunableTvV // To reduce the IPCs, unregister the callback here and register it when necessary. mTvView.setTimeShiftPositionCallback(null); setTimeShiftAvailable(false); + if (needSurfaceSizeUpdate && mFixedSurfaceWidth > 0 && mFixedSurfaceHeight > 0) { + // When the input is changed, TvView recreates its SurfaceView internally. + // So we need to call SurfaceHolder.setFixedSize for the new SurfaceView. + getSurfaceView().getHolder().setFixedSize(mFixedSurfaceWidth, mFixedSurfaceHeight); + } mVideoUnavailableReason = TvInputManager.VIDEO_UNAVAILABLE_REASON_TUNING; if (mTvViewSession != null) { mTvViewSession.tune(channel, params, listener); } else { mTvView.tune(mInputInfo.getId(), mCurrentChannel.getUri(), params); } - if (needSurfaceSizeUpdate && mFixedSurfaceWidth > 0 && mFixedSurfaceHeight > 0) { - // When the input is changed, TvView recreates its SurfaceView internally. - // So we need to call SurfaceHolder.setFixedSize for the new SurfaceView. - SurfaceView surfaceView = getSurfaceView(); - if (surfaceView != null) { - surfaceView.getHolder().setFixedSize(mFixedSurfaceWidth, mFixedSurfaceHeight); - } else { - Log.w(TAG, "Failed to set fixed size for surface view: Null surface view"); - } - } updateBlockScreenAndMuting(); if (mOnTuneListener != null) { mOnTuneListener.onStreamInfoChanged(this, true); diff --git a/src/com/android/tv/ui/TvOverlayManager.java b/src/com/android/tv/ui/TvOverlayManager.java index 0ab7c685..b2854a1f 100644 --- a/src/com/android/tv/ui/TvOverlayManager.java +++ b/src/com/android/tv/ui/TvOverlayManager.java @@ -33,7 +33,6 @@ import android.view.Gravity; import android.view.KeyEvent; import android.view.ViewGroup; import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener; - import com.android.tv.ChannelTuner; import com.android.tv.MainActivity; import com.android.tv.MainActivity.KeyHandlerResultType; @@ -48,7 +47,6 @@ import com.android.tv.common.ui.setup.OnActionClickListener; import com.android.tv.common.ui.setup.SetupFragment; import com.android.tv.common.ui.setup.SetupMultiPaneFragment; import com.android.tv.data.ChannelDataManager; -import com.android.tv.data.ProgramDataManager; import com.android.tv.dialog.DvrHistoryDialogFragment; import com.android.tv.dialog.FullscreenDialogFragment; import com.android.tv.dialog.HalfSizedDialogFragment; @@ -70,12 +68,6 @@ import com.android.tv.ui.TvTransitionManager.SceneType; import com.android.tv.ui.sidepanel.SideFragmentManager; import com.android.tv.ui.sidepanel.parentalcontrols.RatingsFragment; import com.android.tv.util.TvInputManagerHelper; - -import com.google.auto.factory.AutoFactory; -import com.google.auto.factory.Provided; - -import com.android.tv.common.flags.LegacyFlags; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -87,7 +79,6 @@ import java.util.Set; /** A class responsible for the life cycle and event handling of the pop-ups over TV view. */ @UiThread -@AutoFactory public class TvOverlayManager implements AccessibilityStateChangeListener { private static final String TAG = "TvOverlayManager"; private static final boolean DEBUG = false; @@ -225,7 +216,6 @@ public class TvOverlayManager implements AccessibilityStateChangeListener { private final List<Runnable> mPendingActions = new ArrayList<>(); private final Queue<PendingDialogAction> mPendingDialogActionQueue = new LinkedList<>(); - private final LegacyFlags mLegacyFlags; private OnBackStackChangedListener mOnBackStackChangedListener; @@ -239,17 +229,12 @@ public class TvOverlayManager implements AccessibilityStateChangeListener { InputBannerView inputBannerView, SelectInputView selectInputView, ViewGroup sceneContainer, - ProgramGuideSearchFragment searchFragment, - @Provided LegacyFlags legacyFlags, - @Provided ChannelDataManager channelDataManager, - @Provided TvInputManagerHelper tvInputManager, - @Provided ProgramDataManager programDataManager) { + ProgramGuideSearchFragment searchFragment) { mMainActivity = mainActivity; mChannelTuner = channelTuner; TvSingletons singletons = TvSingletons.getSingletons(mainActivity); - mLegacyFlags = legacyFlags; - mChannelDataManager = channelDataManager; - mInputManager = tvInputManager; + mChannelDataManager = singletons.getChannelDataManager(); + mInputManager = singletons.getTvInputManagerHelper(); mTvView = tvView; mChannelBannerView = channelBannerView; mKeypadChannelSwitchView = keypadChannelSwitchView; @@ -286,7 +271,7 @@ public class TvOverlayManager implements AccessibilityStateChangeListener { tvView, optionsManager, menuView, - new MenuRowFactory(mainActivity, tvView, this.mLegacyFlags), + new MenuRowFactory(mainActivity, tvView), new Menu.OnMenuVisibilityChangeListener() { @Override public void onMenuVisibilityChange(boolean visible) { @@ -319,9 +304,9 @@ public class TvOverlayManager implements AccessibilityStateChangeListener { new ProgramGuide( mainActivity, channelTuner, - mInputManager, + singletons.getTvInputManagerHelper(), mChannelDataManager, - programDataManager, + singletons.getProgramDataManager(), dvrDataManager, singletons.getDvrScheduleManager(), singletons.getTracker(), diff --git a/src/com/android/tv/ui/ViewUtils.java b/src/com/android/tv/ui/ViewUtils.java index 431b3113..f64a70b2 100644 --- a/src/com/android/tv/ui/ViewUtils.java +++ b/src/com/android/tv/ui/ViewUtils.java @@ -18,11 +18,9 @@ package com.android.tv.ui; import android.animation.Animator; import android.animation.ValueAnimator; -import android.os.Build; import android.util.Log; import android.view.View; import android.view.ViewGroup.LayoutParams; - import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -35,9 +33,6 @@ public class ViewUtils { } public static void setTransitionAlpha(View v, float alpha) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - v.setTransitionAlpha(alpha); - } Method method; try { method = View.class.getDeclaredMethod("setTransitionAlpha", Float.TYPE); diff --git a/src/com/android/tv/ui/sidepanel/ChannelCheckItem.java b/src/com/android/tv/ui/sidepanel/ChannelCheckItem.java index de3ae751..2726839c 100644 --- a/src/com/android/tv/ui/sidepanel/ChannelCheckItem.java +++ b/src/com/android/tv/ui/sidepanel/ChannelCheckItem.java @@ -19,14 +19,13 @@ package com.android.tv.ui.sidepanel; import android.text.TextUtils; import android.view.View; import android.widget.TextView; - import com.android.tv.R; import com.android.tv.data.ChannelDataManager; import com.android.tv.data.ChannelDataManager.ChannelListener; import com.android.tv.data.OnCurrentProgramUpdatedListener; +import com.android.tv.data.Program; import com.android.tv.data.ProgramDataManager; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; public abstract class ChannelCheckItem extends CompoundButtonItem { private final ChannelDataManager mChannelDataManager; diff --git a/src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java b/src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java index b62a57ee..62130b64 100644 --- a/src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java +++ b/src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java @@ -20,7 +20,7 @@ import android.content.Context; import android.content.SharedPreferences; import android.media.tv.TvContract.Channels; import android.os.Bundle; -import androidx.leanback.widget.VerticalGridView; +import android.support.v17.leanback.widget.VerticalGridView; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; diff --git a/src/com/android/tv/ui/sidepanel/DeveloperOptionFragment.java b/src/com/android/tv/ui/sidepanel/DeveloperOptionFragment.java index e43568c9..36ee5a2d 100644 --- a/src/com/android/tv/ui/sidepanel/DeveloperOptionFragment.java +++ b/src/com/android/tv/ui/sidepanel/DeveloperOptionFragment.java @@ -16,38 +16,29 @@ package com.android.tv.ui.sidepanel; +import android.accounts.Account; import android.app.Activity; - -import com.android.tv.MainActivity; +import android.support.annotation.NonNull; +import android.util.Log; +import android.widget.Toast; import com.android.tv.R; -import com.android.tv.common.BuildConfig; +import com.android.tv.TvSingletons; import com.android.tv.common.CommonPreferences; import com.android.tv.common.feature.CommonFeatures; -import com.android.tv.perf.PerformanceMonitor; +import com.android.tv.common.util.CommonUtils; + -import com.google.common.base.Optional; -import com.google.common.collect.ImmutableList; -import dagger.android.AndroidInjection; -import com.android.tv.common.flags.LegacyFlags; -import javax.inject.Inject; +import java.util.ArrayList; +import java.util.List; /** Options for developers only */ public class DeveloperOptionFragment extends SideFragment { + private static final String TAG = "DeveloperOptionFragment"; private static final String TRACKER_LABEL = "debug options"; - @Inject Optional<AdditionalDeveloperItemsFactory> mAdditionalDeveloperItemsFactory; - @Inject PerformanceMonitor mPerformanceMonitor; - @Inject LegacyFlags mLegacyFlags; - - @Override - public void onAttach(Activity activity) { - AndroidInjection.inject(this); - super.onAttach(activity); - } - @Override protected String getTitle() { return getString(R.string.menu_developer_options); @@ -59,15 +50,8 @@ public class DeveloperOptionFragment extends SideFragment { } @Override - protected ImmutableList<Item> getItemList() { - ImmutableList.Builder<Item> items = ImmutableList.builder(); - if (mAdditionalDeveloperItemsFactory.isPresent()) { - items.addAll( - mAdditionalDeveloperItemsFactory - .get() - .getAdditionalDevItems(getMainActivity())); - items.add(new DividerItem()); - } + protected List<Item> getItemList() { + List<Item> items = new ArrayList<>(); if (CommonFeatures.DVR.isEnabled(getContext())) { items.add( new ActionItem(getString(R.string.dev_item_dvr_history)) { @@ -77,7 +61,7 @@ public class DeveloperOptionFragment extends SideFragment { } }); } - if (BuildConfig.ENG || mLegacyFlags.enableDeveloperFeatures()) { + if (CommonUtils.isDeveloper()) { items.add( new ActionItem(getString(R.string.dev_item_watch_history)) { @Override @@ -103,21 +87,17 @@ public class DeveloperOptionFragment extends SideFragment { CommonPreferences.setStoreTsStream(getContext(), isChecked()); } }); - if (BuildConfig.ENG || mLegacyFlags.enableDeveloperFeatures()) { + if (CommonUtils.isDeveloper()) { items.add( new ActionItem(getString(R.string.dev_item_show_performance_monitor_log)) { @Override protected void onSelected() { - mPerformanceMonitor.startPerformanceMonitorEventDebugActivity( - getContext()); + TvSingletons.getSingletons(getContext()) + .getPerformanceMonitor() + .startPerformanceMonitorEventDebugActivity(getContext()); } }); } - return items.build(); - } - - /** Factory to create additional items. */ - public interface AdditionalDeveloperItemsFactory { - ImmutableList<Item> getAdditionalDevItems(MainActivity mainActivity); + return items; } } diff --git a/src/com/android/tv/ui/sidepanel/SettingsFragment.java b/src/com/android/tv/ui/sidepanel/SettingsFragment.java index 1c03b6a9..aa71fb75 100644 --- a/src/com/android/tv/ui/sidepanel/SettingsFragment.java +++ b/src/com/android/tv/ui/sidepanel/SettingsFragment.java @@ -35,7 +35,7 @@ import com.android.tv.util.Utils; import java.util.ArrayList; import java.util.List; -/** Shows TV app settings. */ +/** Shows Live TV settings. */ public class SettingsFragment extends SideFragment { private static final String TRACKER_LABEL = "settings"; diff --git a/src/com/android/tv/ui/sidepanel/SideFragment.java b/src/com/android/tv/ui/sidepanel/SideFragment.java index 703b1e43..590f1300 100644 --- a/src/com/android/tv/ui/sidepanel/SideFragment.java +++ b/src/com/android/tv/ui/sidepanel/SideFragment.java @@ -20,27 +20,24 @@ import android.app.Fragment; import android.content.Context; import android.graphics.drawable.RippleDrawable; import android.os.Bundle; -import androidx.recyclerview.widget.RecyclerView; +import android.support.v17.leanback.widget.VerticalGridView; +import android.support.v7.widget.RecyclerView; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.TextView; - -import androidx.leanback.widget.VerticalGridView; - import com.android.tv.MainActivity; import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.analytics.HasTrackerLabel; import com.android.tv.analytics.Tracker; -import com.android.tv.common.dev.DeveloperPreferences; import com.android.tv.common.util.DurationTimer; +import com.android.tv.common.util.SystemProperties; import com.android.tv.data.ChannelDataManager; import com.android.tv.data.ProgramDataManager; import com.android.tv.util.ViewCache; - import java.util.List; public abstract class SideFragment<T extends Item> extends Fragment implements HasTrackerLabel { @@ -59,7 +56,7 @@ public abstract class SideFragment<T extends Item> extends Fragment implements H new RecyclerView.RecycledViewPool(); private VerticalGridView mListView; - private ItemAdapter<T> mAdapter; + private ItemAdapter mAdapter; private SideFragmentListener mListener; private ChannelDataManager mChannelDataManager; private ProgramDataManager mProgramDataManager; @@ -68,7 +65,6 @@ public abstract class SideFragment<T extends Item> extends Fragment implements H private final int mHideKey; private final int mDebugHideKey; - private Context mContext; public SideFragment() { this(KeyEvent.KEYCODE_UNKNOWN, KeyEvent.KEYCODE_UNKNOWN); @@ -77,7 +73,7 @@ public abstract class SideFragment<T extends Item> extends Fragment implements H /** * @param hideKey the KeyCode used to hide the fragment * @param debugHideKey the KeyCode used to hide the fragment if {@link - * DeveloperPreferences#USE_DEBUG_KEYS}. + * SystemProperties#USE_DEBUG_KEYS}. */ public SideFragment(int hideKey, int debugHideKey) { mHideKey = hideKey; @@ -87,7 +83,6 @@ public abstract class SideFragment<T extends Item> extends Fragment implements H @Override public void onAttach(Context context) { super.onAttach(context); - mContext = context; mChannelDataManager = getMainActivity().getChannelDataManager(); mProgramDataManager = getMainActivity().getProgramDataManager(); mTracker = TvSingletons.getSingletons(context).getTracker(); @@ -134,8 +129,7 @@ public abstract class SideFragment<T extends Item> extends Fragment implements H } public final boolean isHideKeyForThisPanel(int keyCode) { - boolean debugKeysEnabled = - DeveloperPreferences.USE_DEBUG_KEYS.getDefaultIfContextNull(mContext); + boolean debugKeysEnabled = SystemProperties.USE_DEBUG_KEYS.getValue(); return mHideKey != KeyEvent.KEYCODE_UNKNOWN && (mHideKey == keyCode || (debugKeysEnabled && mDebugHideKey == keyCode)); } diff --git a/src/com/android/tv/ui/sidepanel/parentalcontrols/ChannelsBlockedFragment.java b/src/com/android/tv/ui/sidepanel/parentalcontrols/ChannelsBlockedFragment.java index 620b7017..b14bf78d 100644 --- a/src/com/android/tv/ui/sidepanel/parentalcontrols/ChannelsBlockedFragment.java +++ b/src/com/android/tv/ui/sidepanel/parentalcontrols/ChannelsBlockedFragment.java @@ -23,7 +23,7 @@ import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; import android.os.Bundle; import android.os.Handler; -import androidx.leanback.widget.VerticalGridView; +import android.support.v17.leanback.widget.VerticalGridView; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; diff --git a/src/com/android/tv/ui/sidepanel/parentalcontrols/RatingsFragment.java b/src/com/android/tv/ui/sidepanel/parentalcontrols/RatingsFragment.java index 60f8425f..d1ae4423 100644 --- a/src/com/android/tv/ui/sidepanel/parentalcontrols/RatingsFragment.java +++ b/src/com/android/tv/ui/sidepanel/parentalcontrols/RatingsFragment.java @@ -16,7 +16,6 @@ package com.android.tv.ui.sidepanel.parentalcontrols; -import android.app.Activity; import android.graphics.drawable.Drawable; import android.media.tv.TvContentRating; import android.os.Bundle; @@ -25,9 +24,9 @@ import android.util.SparseIntArray; import android.view.View; import android.widget.CompoundButton; import android.widget.ImageView; - import com.android.tv.MainActivity; import com.android.tv.R; +import com.android.tv.common.experiments.Experiments; import com.android.tv.dialog.WebDialogFragment; import com.android.tv.license.LicenseUtils; import com.android.tv.parental.ContentRatingSystem; @@ -40,28 +39,18 @@ import com.android.tv.ui.sidepanel.RadioButtonItem; import com.android.tv.ui.sidepanel.SideFragment; import com.android.tv.util.TvSettings; import com.android.tv.util.TvSettings.ContentRatingLevel; - import com.google.common.collect.ImmutableList; - -import dagger.android.AndroidInjection; - -import com.android.tv.common.flags.LegacyFlags; - import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; -import javax.inject.Inject; - public class RatingsFragment extends SideFragment { private static final SparseIntArray sLevelResourceIdMap; private static final SparseIntArray sDescriptionResourceIdMap; private static final String TRACKER_LABEL = "Ratings"; private int mItemsSize; - @Inject LegacyFlags mLegacyFlags; - static { sLevelResourceIdMap = new SparseIntArray(5); sLevelResourceIdMap.put(TvSettings.CONTENT_RATING_LEVEL_NONE, R.string.option_rating_none); @@ -112,7 +101,8 @@ public class RatingsFragment extends SideFragment { protected List<Item> getItemList() { List<Item> items = new ArrayList<>(); - if (mBlockUnratedItem != null && mLegacyFlags.enableUnratedContentSettings()) { + if (mBlockUnratedItem != null + && Boolean.TRUE.equals(Experiments.ENABLE_UNRATED_CONTENT_SETTINGS.get())) { items.add(mBlockUnratedItem); items.add(new DividerItem()); } @@ -168,13 +158,7 @@ public class RatingsFragment extends SideFragment { super.onCreate(savedInstanceState); mParentalControlSettings = getMainActivity().getParentalControlSettings(); mParentalControlSettings.loadRatings(); - } - - @Override - public void onAttach(Activity activity) { - AndroidInjection.inject(this); - super.onAttach(activity); - if (mLegacyFlags.enableUnratedContentSettings()) { + if (Boolean.TRUE.equals(Experiments.ENABLE_UNRATED_CONTENT_SETTINGS.get())) { mBlockUnratedItem = new CheckBoxItem( getResources().getString(R.string.option_block_unrated_programs)) { @@ -195,8 +179,6 @@ public class RatingsFragment extends SideFragment { } } }; - } else { - mBlockUnratedItem = null; } } @@ -253,7 +235,8 @@ public class RatingsFragment extends SideFragment { super.onSelected(); mParentalControlSettings.setContentRatingLevel( getMainActivity().getContentRatingsManager(), mRatingLevel); - if (mBlockUnratedItem != null && mLegacyFlags.enableUnratedContentSettings()) { + if (mBlockUnratedItem != null + && Boolean.TRUE.equals(Experiments.ENABLE_UNRATED_CONTENT_SETTINGS.get())) { // set checked if UNRATED is blocked, and set unchecked otherwise. mBlockUnratedItem.setChecked( mParentalControlSettings.isRatingBlocked( diff --git a/src/com/android/tv/util/AsyncDbTask.java b/src/com/android/tv/util/AsyncDbTask.java index 2e9a1ea8..b3523952 100644 --- a/src/com/android/tv/util/AsyncDbTask.java +++ b/src/com/android/tv/util/AsyncDbTask.java @@ -28,23 +28,18 @@ import android.support.annotation.Nullable; import android.support.annotation.WorkerThread; import android.util.Log; import android.util.Range; - import com.android.tv.TvSingletons; import com.android.tv.common.BuildConfig; import com.android.tv.common.SoftPreconditions; import com.android.tv.data.ChannelImpl; -import com.android.tv.data.ProgramImpl; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dvr.data.RecordedProgram; - import com.google.common.base.Predicate; - import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executor; - import javax.inject.Qualifier; /** @@ -128,7 +123,7 @@ public abstract class AsyncDbTask<Params, Progress, Result> return null; } if (Utils.isProgramsUri(mUri) - && TvProviderUtils.checkSeriesIdColumn(context, Programs.CONTENT_URI)) { + && TvProviderUtils.checkSeriesIdColumn(context, Programs.CONTENT_URI)) { mProjection = TvProviderUtils.addExtraColumnsToProjection( mProjection, TvProviderUtils.EXTRA_PROGRAM_COLUMN_SERIES_ID); @@ -328,19 +323,10 @@ public abstract class AsyncDbTask<Params, Progress, Result> } } - /** - * Gets an {@link List} of {@link ProgramImpl}s from {@link TvContract.Programs#CONTENT_URI}. - */ + /** Gets an {@link List} of {@link Program}s from {@link TvContract.Programs#CONTENT_URI}. */ public abstract static class AsyncProgramQueryTask extends AsyncQueryListTask<Program> { public AsyncProgramQueryTask(Executor executor, Context context) { - super( - executor, - context, - Programs.CONTENT_URI, - ProgramImpl.PROJECTION, - null, - null, - null); + super(executor, context, Programs.CONTENT_URI, Program.PROJECTION, null, null, null); } public AsyncProgramQueryTask( @@ -355,7 +341,7 @@ public abstract class AsyncDbTask<Params, Progress, Result> executor, context, uri, - ProgramImpl.PROJECTION, + Program.PROJECTION, selection, selectionArgs, sortOrder, @@ -364,7 +350,7 @@ public abstract class AsyncDbTask<Params, Progress, Result> @Override protected final Program fromCursor(Cursor c) { - return ProgramImpl.fromCursor(c); + return Program.fromCursor(c); } } @@ -390,7 +376,7 @@ public abstract class AsyncDbTask<Params, Progress, Result> } /** - * Gets an {@link List} of {@link ProgramImpl}s for a given channel and period {@link + * Gets an {@link List} of {@link Program}s for a given channel and period {@link * TvContract#buildProgramsUriForChannel(long, long, long)}. If the {@code period} is {@code * null}, then all the programs is queried. */ @@ -424,7 +410,7 @@ public abstract class AsyncDbTask<Params, Progress, Result> } } - /** Gets a single {@link ProgramImpl} from {@link TvContract.Programs#CONTENT_URI}. */ + /** Gets a single {@link Program} from {@link TvContract.Programs#CONTENT_URI}. */ public static class AsyncQueryProgramTask extends AsyncQueryItemTask<Program> { public AsyncQueryProgramTask(Executor executor, Context context, long programId) { @@ -432,7 +418,7 @@ public abstract class AsyncDbTask<Params, Progress, Result> executor, context, TvContract.buildProgramUri(programId), - ProgramImpl.PROJECTION, + Program.PROJECTION, null, null, null); @@ -440,7 +426,7 @@ public abstract class AsyncDbTask<Params, Progress, Result> @Override protected Program fromCursor(Cursor c) { - return ProgramImpl.fromCursor(c); + return Program.fromCursor(c); } } diff --git a/src/com/android/tv/util/OnboardingUtils.java b/src/com/android/tv/util/OnboardingUtils.java index 4fae2f00..3b72e091 100644 --- a/src/com/android/tv/util/OnboardingUtils.java +++ b/src/com/android/tv/util/OnboardingUtils.java @@ -27,9 +27,7 @@ public final class OnboardingUtils { private static final String PREF_KEY_ONBOARDING_VERSION_CODE = "pref_onbaording_versionCode"; private static final int ONBOARDING_VERSION = 1; - // Replace as needed - private static final String MERCHANT_COLLECTION_URL_STRING = - "https://play.google.com/store/apps/collection/promotion_3001bf9_ATV_livechannels"; + private static final String MERCHANT_COLLECTION_URL_STRING = getMerchantCollectionUrl(); /** Intent to show merchant collection in online store. */ public static final Intent ONLINE_STORE_INTENT = @@ -71,5 +69,10 @@ public final class OnboardingUtils { .apply(); } + /** Returns merchant collection URL. */ + private static String getMerchantCollectionUrl() { + return "TODO: add a merchant collection url"; + } + private OnboardingUtils() {} } diff --git a/src/com/android/tv/util/SetupUtils.java b/src/com/android/tv/util/SetupUtils.java index 52b3e3e8..a9b67fa8 100644 --- a/src/com/android/tv/util/SetupUtils.java +++ b/src/com/android/tv/util/SetupUtils.java @@ -307,7 +307,8 @@ public class SetupUtils { } /** - * Called when TV app is launched. Once it is called, {@link #isFirstTune} will return false. + * Called when Live channels app is launched. Once it is called, {@link #isFirstTune} will + * return false. */ public void onTuned() { if (!mIsFirstTune) { diff --git a/common/src/com/android/tv/common/util/sql/SqlParams.java b/src/com/android/tv/util/SqlParams.java index 87fcabdb..fa557ba2 100644 --- a/common/src/com/android/tv/common/util/sql/SqlParams.java +++ b/src/com/android/tv/util/SqlParams.java @@ -14,7 +14,7 @@ * limitations under the License */ -package com.android.tv.common.util.sql; +package com.android.tv.util; import android.database.DatabaseUtils; import android.support.annotation.Nullable; diff --git a/src/com/android/tv/util/TvInputManagerHelper.java b/src/com/android/tv/util/TvInputManagerHelper.java index 23c9b494..cb7d9854 100644 --- a/src/com/android/tv/util/TvInputManagerHelper.java +++ b/src/com/android/tv/util/TvInputManagerHelper.java @@ -46,8 +46,6 @@ import com.android.tv.parental.ContentRatingsManager; import com.android.tv.parental.ParentalControlSettings; import com.android.tv.util.images.ImageCache; import com.android.tv.util.images.ImageLoader; -import com.google.common.collect.Ordering; -import com.android.tv.common.flags.LegacyFlags; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -129,7 +127,6 @@ public class TvInputManagerHelper { private static final String PERMISSION_ACCESS_ALL_EPG_DATA = "com.android.providers.tv.permission.ACCESS_ALL_EPG_DATA"; private static final String[] mPhysicalTunerBlackList = { - "com.google.android.videos", // Play Movies }; private static final String META_LABEL_SORT_KEY = "input_sort_key"; @@ -161,10 +158,6 @@ public class TvInputManagerHelper { } private static final String[] PARTNER_TUNER_INPUT_PREFIX_BLACKLIST = { - /* Begin_AOSP_Comment_Out - // Disabled partner's tuner input prefix list. - "com.mediatek.tvinput/.dtv" - End_AOSP_Comment_Out */ }; private static final String[] TESTABLE_INPUTS = { @@ -299,8 +292,8 @@ public class TvInputManagerHelper { private boolean mAllow3rdPartyInputs; @Inject - public TvInputManagerHelper(@ApplicationContext Context context, LegacyFlags legacyFlags) { - this(context, createTvInputManagerWrapper(context), legacyFlags); + public TvInputManagerHelper(@ApplicationContext Context context) { + this(context, createTvInputManagerWrapper(context)); } @Nullable @@ -312,14 +305,12 @@ public class TvInputManagerHelper { @VisibleForTesting protected TvInputManagerHelper( - Context context, - @Nullable TvInputManagerInterface tvInputManager, - LegacyFlags legacyFlags) { + Context context, @Nullable TvInputManagerInterface tvInputManager) { mContext = context.getApplicationContext(); mPackageManager = context.getPackageManager(); mTvInputManager = tvInputManager; mContentRatingsManager = new ContentRatingsManager(context, tvInputManager); - mParentalControlSettings = new ParentalControlSettings(context, legacyFlags); + mParentalControlSettings = new ParentalControlSettings(context); mTvInputInfoComparator = new InputComparatorInternal(this); mContentObserver = new ContentObserver(mHandler) { @@ -357,6 +348,7 @@ public class TvInputManagerHelper { updateAllow3rdPartyInputs(); mTvInputManager.registerCallback(mInternalCallback, mHandler); initInputMaps(); + mContentRatingsManager.update(); } public void stop() { @@ -454,12 +446,10 @@ public class TvInputManagerHelper { } /** Loads label of {@code info}. */ - @Nullable public String loadLabel(TvInputInfo info) { String label = mTvInputLabels.get(info.getId()); if (label == null) { - CharSequence labelSequence = info.loadLabel(mContext); - label = labelSequence == null ? null : labelSequence.toString(); + label = info.loadLabel(mContext).toString(); mTvInputLabels.put(info.getId(), label); } return label; @@ -713,8 +703,6 @@ public class TvInputManagerHelper { @VisibleForTesting static class InputComparatorInternal implements Comparator<TvInputInfo> { private final TvInputManagerHelper mInputManager; - private static final Ordering<Comparable> NULL_FIRST_STRING_ORDERING = - Ordering.natural().nullsFirst(); public InputComparatorInternal(TvInputManagerHelper inputManager) { mInputManager = inputManager; @@ -725,8 +713,7 @@ public class TvInputManagerHelper { if (mInputManager.isPartnerInput(lhs) != mInputManager.isPartnerInput(rhs)) { return mInputManager.isPartnerInput(lhs) ? -1 : 1; } - return NULL_FIRST_STRING_ORDERING.compare( - mInputManager.loadLabel(lhs), mInputManager.loadLabel(rhs)); + return mInputManager.loadLabel(lhs).compareTo(mInputManager.loadLabel(rhs)); } } @@ -808,7 +795,7 @@ public class TvInputManagerHelper { if (TextUtils.isEmpty(label)) { label = mTvInputManagerHelper.loadLabel(input); } - return label == null ? "" : label; + return label; } private int getPriority(TvInputInfo info) { diff --git a/src/com/android/tv/util/TvProviderUtils.java b/src/com/android/tv/util/TvProviderUtils.java index d931dcd5..6b5aaecc 100644 --- a/src/com/android/tv/util/TvProviderUtils.java +++ b/src/com/android/tv/util/TvProviderUtils.java @@ -27,7 +27,7 @@ import android.support.annotation.StringDef; import android.support.annotation.VisibleForTesting; import android.support.annotation.WorkerThread; import android.util.Log; -import com.android.tv.data.api.BaseProgram; +import com.android.tv.data.BaseProgram; import com.android.tv.features.PartnerFeatures; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -67,9 +67,6 @@ public final class TvProviderUtils { @WorkerThread public static synchronized boolean checkSeriesIdColumn(Context context, Uri uri) { boolean canCreateColumn = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O); - canCreateColumn = - (canCreateColumn - || PartnerFeatures.TVPROVIDER_ALLOWS_COLUMN_CREATION.isEnabled(context)); if (!canCreateColumn) { return false; } @@ -115,9 +112,6 @@ public final class TvProviderUtils { @WorkerThread public static synchronized boolean checkStateColumn(Context context, Uri uri) { boolean canCreateColumn = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O); - canCreateColumn = - (canCreateColumn - || PartnerFeatures.TVPROVIDER_ALLOWS_COLUMN_CREATION.isEnabled(context)); if (!canCreateColumn) { return false; } @@ -150,8 +144,8 @@ public final class TvProviderUtils { return TRUE.equals(sRecordedProgramHasStateColumn); } - public static String[] addExtraColumnsToProjection( - String[] projection, @TvProviderExtraColumn String column) { + public static String[] addExtraColumnsToProjection(String[] projection, + @TvProviderExtraColumn String column) { List<String> projectionList = new ArrayList<>(Arrays.asList(projection)); if (!projectionList.contains(column)) { projectionList.add(column); diff --git a/src/com/android/tv/util/TvTrackInfoUtils.java b/src/com/android/tv/util/TvTrackInfoUtils.java index ae30df11..4ec96c62 100644 --- a/src/com/android/tv/util/TvTrackInfoUtils.java +++ b/src/com/android/tv/util/TvTrackInfoUtils.java @@ -17,16 +17,9 @@ package com.android.tv.util; import android.content.Context; import android.media.tv.TvTrackInfo; -import android.os.Build; -import android.os.LocaleList; import android.text.TextUtils; import android.util.Log; - import com.android.tv.R; - -import com.google.common.collect.Iterables; - -import java.util.ArrayList; import java.util.Comparator; import java.util.HashSet; import java.util.List; @@ -45,19 +38,17 @@ public class TvTrackInfoUtils { private static final int AUDIO_CHANNEL_SURROUND_8 = 8; /** - * Compares how closely two {@link android.media.tv.TvTrackInfo}s match {@code languages}, - * {@code channelCount} and {@code id} in that precedence. A listed sorted with this comparator - * has the worst matches first. + * Compares how closely two {@link android.media.tv.TvTrackInfo}s match {@code language}, {@code + * channelCount} and {@code id} in that precedence. * * @param id The track id to match. - * @param languages The prioritized list of languages. Languages earlier in the list are a - * better match. + * @param language The language to match. * @param channelCount The channel count to match. * @return -1 if lhs is a worse match, 0 if lhs and rhs match equally and 1 if lhs is a better * match. */ public static Comparator<TvTrackInfo> createComparator( - final String id, final List<String> languages, final int channelCount) { + final String id, final String language, final int channelCount) { return (TvTrackInfo lhs, TvTrackInfo rhs) -> { if (Objects.equals(lhs, rhs)) { return 0; @@ -68,35 +59,26 @@ public class TvTrackInfoUtils { if (rhs == null) { return 1; } - // Find the first language that matches the lhs and rhs tracks. The earlier match is - // better. If there is no match set the index to the size of the language list since - // its the worst match. - int lhsLangIndex = - Iterables.indexOf(languages, s -> Utils.isEqualLanguage(lhs.getLanguage(), s)); - if (lhsLangIndex == -1) { - lhsLangIndex = languages.size(); - } - int rhsLangIndex = - Iterables.indexOf(languages, s -> Utils.isEqualLanguage(rhs.getLanguage(), s)); - if (rhsLangIndex == -1) { - rhsLangIndex = languages.size(); - } - if (lhsLangIndex != rhsLangIndex) { - // Return the track with lower index as best - return Integer.compare(rhsLangIndex, lhsLangIndex); - } - boolean lhsCountMatch = - lhs.getType() != TvTrackInfo.TYPE_AUDIO - || lhs.getAudioChannelCount() == channelCount; - boolean rhsCountMatch = - rhs.getType() != TvTrackInfo.TYPE_AUDIO - || rhs.getAudioChannelCount() == channelCount; - if (lhsCountMatch && rhsCountMatch) { - return Boolean.compare(lhs.getId().equals(id), rhs.getId().equals(id)); - } else if (lhsCountMatch || rhsCountMatch) { - return Boolean.compare(lhsCountMatch, rhsCountMatch); + // Assumes {@code null} language matches to any language since it means user hasn't + // selected any track before or selected a track without language information. + boolean lhsLangMatch = + language == null || Utils.isEqualLanguage(lhs.getLanguage(), language); + boolean rhsLangMatch = + language == null || Utils.isEqualLanguage(rhs.getLanguage(), language); + if (lhsLangMatch && rhsLangMatch) { + boolean lhsCountMatch = + lhs.getType() != TvTrackInfo.TYPE_AUDIO + || lhs.getAudioChannelCount() == channelCount; + boolean rhsCountMatch = + rhs.getType() != TvTrackInfo.TYPE_AUDIO + || rhs.getAudioChannelCount() == channelCount; + if (lhsCountMatch && rhsCountMatch) { + return Boolean.compare(lhs.getId().equals(id), rhs.getId().equals(id)); + } else { + return Boolean.compare(lhsCountMatch, rhsCountMatch); + } } else { - return Integer.compare(lhs.getAudioChannelCount(), rhs.getAudioChannelCount()); + return Boolean.compare(lhsLangMatch, rhsLangMatch); } }; } @@ -115,20 +97,7 @@ public class TvTrackInfoUtils { if (tracks == null) { return null; } - List<String> languages = new ArrayList<>(); - if (language == null) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - LocaleList locales = LocaleList.getDefault(); - for (int i = 0; i < locales.size(); i++) { - languages.add(locales.get(i).getLanguage()); - } - } else { - languages.add(Locale.getDefault().getLanguage()); - } - } else { - languages.add(language); - } - Comparator<TvTrackInfo> comparator = createComparator(id, languages, channelCount); + Comparator<TvTrackInfo> comparator = createComparator(id, language, channelCount); TvTrackInfo best = null; for (TvTrackInfo track : tracks) { if (comparator.compare(track, best) > 0) { @@ -159,7 +128,11 @@ public class TvTrackInfoUtils { if (!TextUtils.isEmpty(track.getLanguage())) { language = new Locale(track.getLanguage()).getDisplayName(); } else { - Log.d(TAG, "No language information found for the audio track: " + toString(track)); + Log.d( + TAG, + "No language information found for the audio track: " + + toString(track) + ); } StringBuilder metadata = new StringBuilder(); @@ -234,31 +207,31 @@ public class TvTrackInfoUtils { public static String toString(TvTrackInfo info) { int trackType = info.getType(); return "TvTrackInfo{" - + "type=" - + trackTypeToString(trackType) - + ", id=" - + info.getId() - + ", language=" - + info.getLanguage() - + ", description=" - + info.getDescription() - + (trackType == TvTrackInfo.TYPE_AUDIO - ? (", audioChannelCount=" - + info.getAudioChannelCount() - + ", audioSampleRate=" - + info.getAudioSampleRate()) - : "") - + (trackType == TvTrackInfo.TYPE_VIDEO - ? (", videoWidth=" - + info.getVideoWidth() - + ", videoHeight=" - + info.getVideoHeight() - + ", videoFrameRate=" - + info.getVideoFrameRate() - + ", videoPixelAspectRatio=" - + info.getVideoPixelAspectRatio()) - : "") - + "}"; + + "type=" + + trackTypeToString(trackType) + + ", id=" + + info.getId() + + ", language=" + + info.getLanguage() + + ", description=" + + info.getDescription() + + (trackType == TvTrackInfo.TYPE_AUDIO + ? + (", audioChannelCount=" + + info.getAudioChannelCount() + + ", audioSampleRate=" + + info.getAudioSampleRate()) : "") + + (trackType == TvTrackInfo.TYPE_VIDEO + ? + (", videoWidth=" + + info.getVideoWidth() + + ", videoHeight=" + + info.getVideoHeight() + + ", videoFrameRate=" + + info.getVideoFrameRate() + + ", videoPixelAspectRatio=" + + info.getVideoPixelAspectRatio()) : "") + + "}"; } private TvTrackInfoUtils() {} diff --git a/src/com/android/tv/util/Utils.java b/src/com/android/tv/util/Utils.java index c1f9e935..51173739 100644 --- a/src/com/android/tv/util/Utils.java +++ b/src/com/android/tv/util/Utils.java @@ -39,19 +39,17 @@ import android.text.TextUtils; import android.text.format.DateUtils; import android.util.Log; import android.view.View; - import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.common.BaseSingletons; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.util.Clock; import com.android.tv.data.GenreItems; -import com.android.tv.data.ProgramImpl; +import com.android.tv.data.Program; import com.android.tv.data.StreamInfo; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; - import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collection; @@ -326,7 +324,7 @@ public class Utils { TvContract.buildChannelUri(channelId), timeMs, timeMs); ContentResolver resolver = context.getContentResolver(); - String[] projection = ProgramImpl.PROJECTION; + String[] projection = Program.PROJECTION; if (TvProviderUtils.checkSeriesIdColumn(context, TvContract.Programs.CONTENT_URI)) { if (Utils.isProgramsUri(uri)) { projection = @@ -336,7 +334,7 @@ public class Utils { } try (Cursor cursor = resolver.query(uri, projection, null, null, null)) { if (cursor != null && cursor.moveToNext()) { - return ProgramImpl.fromCursor(cursor); + return Program.fromCursor(cursor); } } return null; @@ -605,7 +603,6 @@ public class Utils { } /** Returns the label for a given input. Returns the custom label, if any. */ - @Nullable public static String loadLabel(Context context, TvInputInfo input) { if (input == null) { return null; @@ -615,7 +612,7 @@ public class Utils { CharSequence customLabel = inputManager.loadCustomLabel(input); String label = (customLabel == null) ? null : customLabel.toString(); if (TextUtils.isEmpty(label)) { - label = inputManager.loadLabel(input); + label = inputManager.loadLabel(input).toString(); } return label; } @@ -717,6 +714,33 @@ public class Utils { return context.createConfigurationContext(config).getText(resourceId); } + /** Checks where there is any internal TV input. */ + public static boolean hasInternalTvInputs(Context context, boolean tunerInputOnly) { + for (TvInputInfo input : + TvSingletons.getSingletons(context) + .getTvInputManagerHelper() + .getTvInputInfos(true, tunerInputOnly)) { + if (isInternalTvInput(context, input.getId())) { + return true; + } + } + return false; + } + + /** Returns the internal TV inputs. */ + public static List<TvInputInfo> getInternalTvInputs(Context context, boolean tunerInputOnly) { + List<TvInputInfo> inputs = new ArrayList<>(); + for (TvInputInfo input : + TvSingletons.getSingletons(context) + .getTvInputManagerHelper() + .getTvInputInfos(true, tunerInputOnly)) { + if (isInternalTvInput(context, input.getId())) { + inputs.add(input); + } + } + return inputs; + } + /** Checks whether the input is internal or not. */ public static boolean isInternalTvInput(Context context, String inputId) { ComponentName unflattenInputId = ComponentName.unflattenFromString(inputId); diff --git a/src/com/android/tv/util/account/AccountHelper.java b/src/com/android/tv/util/account/AccountHelper.java index d54c2f56..e98b42ec 100644 --- a/src/com/android/tv/util/account/AccountHelper.java +++ b/src/com/android/tv/util/account/AccountHelper.java @@ -35,11 +35,4 @@ public interface AccountHelper { /** Returns all eligible accounts . */ @Nullable Account getFirstEligibleAccount(); - - /** - * Initialize the account helper. - * - * <p>This method is a no op if called more than once. - */ - void init(); } diff --git a/src/com/android/tv/util/account/AccountHelperImpl.java b/src/com/android/tv/util/account/AccountHelperImpl.java index e97cc3f2..58fbd27e 100644 --- a/src/com/android/tv/util/account/AccountHelperImpl.java +++ b/src/com/android/tv/util/account/AccountHelperImpl.java @@ -21,12 +21,8 @@ import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; import android.support.annotation.Nullable; -import com.android.tv.common.dagger.annotations.ApplicationContext; -import javax.inject.Inject; -import javax.inject.Singleton; /** Helper methods for getting and selecting a user account. */ -@Singleton public class AccountHelperImpl implements com.android.tv.util.account.AccountHelper { private static final String SELECTED_ACCOUNT = "android.tv.livechannels.selected_account"; @@ -35,8 +31,7 @@ public class AccountHelperImpl implements com.android.tv.util.account.AccountHel @Nullable private Account mSelectedAccount; - @Inject - public AccountHelperImpl(@ApplicationContext Context context) { + public AccountHelperImpl(Context context) { mContext = context.getApplicationContext(); mDefaultPreferences = PreferenceManager.getDefaultSharedPreferences(mContext); } @@ -103,9 +98,4 @@ public class AccountHelperImpl implements com.android.tv.util.account.AccountHel PreferenceManager.getDefaultSharedPreferences(mContext); defaultPreferences.edit().putString(SELECTED_ACCOUNT, account.name).commit(); } - - @Override - public void init() { - // do nothing. - } } diff --git a/src/com/android/tv/util/images/ImageLoader.java b/src/com/android/tv/util/images/ImageLoader.java index e026f26a..d2ad0eb1 100644 --- a/src/com/android/tv/util/images/ImageLoader.java +++ b/src/com/android/tv/util/images/ImageLoader.java @@ -29,13 +29,9 @@ import android.support.annotation.UiThread; import android.support.annotation.WorkerThread; import android.util.ArraySet; import android.util.Log; - -import androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms; - import com.android.tv.R; import com.android.tv.common.concurrent.NamedThreadFactory; import com.android.tv.util.images.BitmapUtils.ScaledBitmapInfo; - import java.lang.ref.WeakReference; import java.util.HashMap; import java.util.Map; @@ -168,8 +164,8 @@ public final class ImageLoader { * @return {@code true} if the load is complete and the callback is executed. */ @UiThread - public static <T> boolean loadBitmap( - Context context, String uriString, ImageLoaderCallback<T> callback) { + public static boolean loadBitmap( + Context context, String uriString, ImageLoaderCallback callback) { return loadBitmap(context, uriString, Integer.MAX_VALUE, Integer.MAX_VALUE, callback); } @@ -182,12 +178,12 @@ public final class ImageLoader { * @return {@code true} if the load is complete and the callback is executed. */ @UiThread - public static <T> boolean loadBitmap( + public static boolean loadBitmap( Context context, String uriString, int maxWidth, int maxHeight, - ImageLoaderCallback<T> callback) { + ImageLoaderCallback callback) { if (DEBUG) { Log.d(TAG, "loadBitmap() " + uriString); } @@ -195,12 +191,12 @@ public final class ImageLoader { context, uriString, maxWidth, maxHeight, callback, IMAGE_THREAD_POOL_EXECUTOR); } - private static <T> boolean doLoadBitmap( + private static boolean doLoadBitmap( Context context, String uriString, int maxWidth, int maxHeight, - ImageLoaderCallback<T> callback, + ImageLoaderCallback callback, Executor executor) { // Check the cache before creating a Task. The cache will be checked again in doLoadBitmap // but checking a cache is much cheaper than creating an new task. @@ -226,8 +222,7 @@ public final class ImageLoader { * @return {@code true} if the load is complete and the callback is executed. */ @UiThread - public static <T> boolean loadBitmap( - ImageLoaderCallback<T> callback, LoadBitmapTask<T> loadBitmapTask) { + public static boolean loadBitmap(ImageLoaderCallback callback, LoadBitmapTask loadBitmapTask) { if (DEBUG) { Log.d(TAG, "loadBitmap() " + loadBitmapTask); } @@ -236,8 +231,8 @@ public final class ImageLoader { /** @return {@code true} if the load is complete and the callback is executed. */ @UiThread - private static <T> boolean doLoadBitmap( - ImageLoaderCallback<T> callback, Executor executor, LoadBitmapTask<T> loadBitmapTask) { + private static boolean doLoadBitmap( + ImageLoaderCallback callback, Executor executor, LoadBitmapTask loadBitmapTask) { ScaledBitmapInfo bitmapInfo = loadBitmapTask.getFromCache(); boolean needToReload = loadBitmapTask.isReloadNeeded(); if (bitmapInfo != null && !needToReload) { @@ -272,11 +267,11 @@ public final class ImageLoader { * * <p>Implement {@link #doGetBitmapInBackground} to do the actual loading. */ - public abstract static class LoadBitmapTask<T> extends AsyncTask<Void, Void, ScaledBitmapInfo> { + public abstract static class LoadBitmapTask extends AsyncTask<Void, Void, ScaledBitmapInfo> { protected final Context mAppContext; protected final int mMaxWidth; protected final int mMaxHeight; - private final Set<ImageLoaderCallback<T>> mCallbacks = new ArraySet<>(); + private final Set<ImageLoaderCallback> mCallbacks = new ArraySet<>(); private final ImageCache mImageCache; private final String mKey; @@ -358,7 +353,7 @@ public final class ImageLoader { public final void onPostExecute(ScaledBitmapInfo scaledBitmapInfo) { if (DEBUG) Log.d(ImageLoader.TAG, "Bitmap is loaded " + mKey); - for (ImageLoader.ImageLoaderCallback<T> callback : mCallbacks) { + for (ImageLoader.ImageLoaderCallback callback : mCallbacks) { callback.onBitmapLoaded(scaledBitmapInfo == null ? null : scaledBitmapInfo.bitmap); } ImageLoader.sPendingListMap.remove(mKey); @@ -381,7 +376,7 @@ public final class ImageLoader { } } - private static final class LoadBitmapFromUriTask<T> extends LoadBitmapTask<T> { + private static final class LoadBitmapFromUriTask extends LoadBitmapTask { private LoadBitmapFromUriTask( Context context, ImageCache imageCache, @@ -400,7 +395,7 @@ public final class ImageLoader { } /** Loads and caches the logo for a given {@link TvInputInfo} */ - public static final class LoadTvInputLogoTask<T> extends LoadBitmapTask<T> { + public static final class LoadTvInputLogoTask extends LoadBitmapTask { private final TvInputInfo mInfo; public LoadTvInputLogoTask(Context context, ImageCache cache, TvInputInfo info) { @@ -419,10 +414,9 @@ public final class ImageLoader { @Override public ScaledBitmapInfo doGetBitmapInBackground() { Drawable drawable = mInfo.loadIcon(mAppContext); - Bitmap bm = - drawable instanceof BitmapDrawable - ? ((BitmapDrawable) drawable).getBitmap() - : BitmapUtils.drawableToBitmap(drawable); + Bitmap bm = drawable instanceof BitmapDrawable + ? ((BitmapDrawable) drawable).getBitmap() + : BitmapUtils.drawableToBitmap(drawable); return bm == null ? null : BitmapUtils.createScaledBitmapInfo(getKey(), bm, mMaxWidth, mMaxHeight); @@ -434,46 +428,6 @@ public final class ImageLoader { } } - /** - * Calculates Aspect Ratio of Poster Art from Uri. - * - * <p><b>Note</b> the function will check the cache before loading the bitmap - * - * @return the Aspect Ratio of the Poster Art. - */ - public static int getAspectRatioFromPosterArtUri(Context context, String uriString) { - // Check the cache before loading the bitmap. - ImageCache imageCache = ImageCache.getInstance(); - ScaledBitmapInfo bitmapInfo = imageCache.get(uriString); - int bitmapWidth; - int bitmapHeight; - float bitmapAspectRatio; - int aspectRatio; - if (bitmapInfo == null) { - bitmapInfo = - BitmapUtils.decodeSampledBitmapFromUriString( - context, uriString, Integer.MAX_VALUE, Integer.MAX_VALUE); - } - bitmapWidth = bitmapInfo.bitmap.getWidth(); - bitmapHeight = bitmapInfo.bitmap.getHeight(); - bitmapAspectRatio = (float) bitmapWidth / bitmapHeight; - /* Assign nearest aspect ratio from the defined values in Preview Programs */ - if (bitmapAspectRatio > 0 && bitmapAspectRatio <= 0.6803) { - aspectRatio = PreviewPrograms.ASPECT_RATIO_2_3; - } else if (bitmapAspectRatio > 0.6803 && bitmapAspectRatio <= 0.8469) { - aspectRatio = PreviewPrograms.ASPECT_RATIO_MOVIE_POSTER; - } else if (bitmapAspectRatio > 0.8469 && bitmapAspectRatio <= 1.1667) { - aspectRatio = PreviewPrograms.ASPECT_RATIO_1_1; - } else if (bitmapAspectRatio > 1.1667 && bitmapAspectRatio <= 1.4167) { - aspectRatio = PreviewPrograms.ASPECT_RATIO_4_3; - } else if (bitmapAspectRatio > 1.4167 && bitmapAspectRatio <= 1.6389) { - aspectRatio = PreviewPrograms.ASPECT_RATIO_3_2; - } else { - aspectRatio = PreviewPrograms.ASPECT_RATIO_16_9; - } - return aspectRatio; - } - private static synchronized Handler getMainHandler() { if (sMainHandler == null) { sMainHandler = new Handler(Looper.getMainLooper()); diff --git a/tests/common/Android.bp b/tests/common/Android.bp deleted file mode 100644 index 1abaaf76..00000000 --- a/tests/common/Android.bp +++ /dev/null @@ -1,50 +0,0 @@ -// -// Copyright (C) 2019 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. -// - -android_library { - name: "tv-test-common", - - // Include all test java files. - srcs: [ - "src/**/*.java", - "src/**/I*.aidl", - ], - - static_libs: [ - "android-support-annotations", - "androidx.test.runner", - "androidx.test.rules", - "tv-guava-android-jar", - "mockito-robolectric-prebuilt", - "tv-lib-truth", - "ub-uiautomator", - "Robolectric_all-target", - ], - - // Link tv-common as shared library to avoid the problem of initialization of the constants - libs: [ - "tv-common", - "LiveTv", - ], - - sdk_version: "system_current", - - resource_dirs: ["res"], - aidl: { - local_include_dirs: ["src"], - }, - -} diff --git a/tests/common/Android.mk b/tests/common/Android.mk index e434e124..7a111d0c 100644 --- a/tests/common/Android.mk +++ b/tests/common/Android.mk @@ -1,23 +1,29 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_MODULE := tv-test-common-robo - +# Include all test java files. LOCAL_SRC_FILES := \ - $(call all-java-files-under, src/com/android/tv/testing/robo) \ - $(call all-java-files-under, src/com/android/tv/testing/shadows) - -LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res + $(call all-java-files-under, src) \ + $(call all-Iaidl-files-under, src) LOCAL_STATIC_JAVA_LIBRARIES := \ - robolectric_android-all-stub \ - Robolectric_all-target \ - mockito-robolectric-prebuilt \ - tv-test-common \ + android-support-annotations \ + androidx.test.runner \ + androidx.test.rules \ + tv-guava-android-jar \ + mockito-target \ + tv-lib-truth \ + ub-uiautomator \ -LOCAL_INSTRUMENTATION_FOR := LiveTv +# Link tv-common as shared library to avoid the problem of initialization of the constants +LOCAL_JAVA_LIBRARIES := tv-common +LOCAL_INSTRUMENTATION_FOR := LiveTv +LOCAL_MODULE := tv-test-common LOCAL_MODULE_TAGS := optional LOCAL_SDK_VERSION := system_current +LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res +LOCAL_AIDL_INCLUDES += $(LOCAL_PATH)/src + include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/tests/common/AndroidManifest.xml b/tests/common/AndroidManifest.xml index ec9614da..3a769a8d 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="28" android:minSdkVersion="23"/> + <uses-sdk android:targetSdkVersion="27" android:minSdkVersion="23"/> <application /> </manifest> diff --git a/tests/common/src/com/android/tv/testing/ChannelNumberSubject.java b/tests/common/src/com/android/tv/testing/ChannelNumberSubject.java index 1592897c..ba4662ee 100644 --- a/tests/common/src/com/android/tv/testing/ChannelNumberSubject.java +++ b/tests/common/src/com/android/tv/testing/ChannelNumberSubject.java @@ -16,8 +16,6 @@ package com.android.tv.testing; -import static com.google.common.truth.Fact.simpleFact; - import android.support.annotation.Nullable; import com.android.tv.data.ChannelNumber; import com.google.common.truth.ComparableSubject; @@ -26,7 +24,8 @@ import com.google.common.truth.Subject; import com.google.common.truth.Truth; /** Propositions for {@link ChannelNumber} subjects. */ -public final class ChannelNumberSubject extends ComparableSubject { +public final class ChannelNumberSubject + extends ComparableSubject<ChannelNumberSubject, ChannelNumber> { private static final Subject.Factory<ChannelNumberSubject, ChannelNumber> FACTORY = ChannelNumberSubject::new; @@ -38,30 +37,30 @@ public final class ChannelNumberSubject extends ComparableSubject { return Truth.assertAbout(channelNumbers()).that(actual); } - private final ChannelNumber actual; - - public ChannelNumberSubject(FailureMetadata failureMetadata, @Nullable ChannelNumber subject) { - super(failureMetadata, subject); - this.actual = subject; + public ChannelNumberSubject(FailureMetadata failureMetadata, @Nullable ChannelNumber subject) { + super(failureMetadata, subject); } public void displaysAs(int major) { - if (!actual.majorNumber.equals(Integer.toString(major)) || actual.hasDelimiter) { - failWithActual("expected to display as", major); + if (!getSubject().majorNumber.equals(Integer.toString(major)) + || getSubject().hasDelimiter) { + fail("displaysAs", major); } } public void displaysAs(int major, int minor) { - if (!actual.majorNumber.equals(Integer.toString(major)) - || !actual.minorNumber.equals(Integer.toString(minor)) - || !actual.hasDelimiter) { - failWithActual("expected to display as", major + "-" + minor); + if (!getSubject().majorNumber.equals(Integer.toString(major)) + || !getSubject().minorNumber.equals(Integer.toString(minor)) + || !getSubject().hasDelimiter) { + fail("displaysAs", major + "-" + minor); } } public void isEmpty() { - if (!actual.majorNumber.isEmpty() || !actual.minorNumber.isEmpty() || actual.hasDelimiter) { - failWithActual(simpleFact("expected to be empty")); + if (!getSubject().majorNumber.isEmpty() + || !getSubject().minorNumber.isEmpty() + || getSubject().hasDelimiter) { + fail("isEmpty"); } } } diff --git a/tests/common/src/com/android/tv/testing/ComparatorTester.java b/tests/common/src/com/android/tv/testing/ComparatorTester.java index 01c3964d..6ebd8b4e 100644 --- a/tests/common/src/com/android/tv/testing/ComparatorTester.java +++ b/tests/common/src/com/android/tv/testing/ComparatorTester.java @@ -16,198 +16,128 @@ package com.android.tv.testing; -import static com.google.common.truth.Truth.assertWithMessage; -import static com.google.common.truth.Truth.assert_; - -import android.support.annotation.Nullable; - -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; -import com.google.common.primitives.Ints; +import static junit.framework.Assert.assertEquals; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.Comparator; import java.util.List; /** - * Tests that a given {@link Comparator} (or the implementation of {@link Comparable}) is correct. - * To use, repeatedly call {@link #addEqualityGroup(Object...)} with sets of objects that should be - * equal. The calls to {@link #addEqualityGroup(Object...)} must be made in sorted order. Then call - * {@link #testCompare()} to test the comparison. For example: - * - * <pre>{@code - * new ComparatorTester() - * .addEqualityGroup(1) - * .addEqualityGroup(2) - * .addEqualityGroup(3) - * .testCompare(); - * }</pre> + * Tester for {@link Comparator} relationships between groups of T. * - * <p>By default, a {@code Comparator} is not tested for compatibility with {@link - * Object#equals(Object)}. If that is desired, use the {link #requireConsistencyWithEquals()} to - * explicitly activate the check. For example: + * <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 - * new ComparatorTester(Comparator.naturalOrder()) - * .requireConsistencyWithEquals() - * .addEqualityGroup(1) - * .addEqualityGroup(2) - * .addEqualityGroup(3) - * .testCompare(); + * ComparatorTester + * .withoutEqualsTest(String.CASE_INSENSITIVE_ORDER) + * .addComparableGroup("Hello", "HELLO") + * .addComparableGroup("World", "wORLD") + * .addComparableGroup("ZEBRA") + * .test(); * }</pre> * - * <p>If for some reason you need to suppress the compatibility check when testing a {@code - * Comparable}, use the {link #permitInconsistencyWithEquals()} to explicitly deactivate the check. - * For example: - * - * <pre>{@code - * new ComparatorTester() - * .permitInconsistencyWithEquals() - * .addEqualityGroup(1) - * .addEqualityGroup(2) - * .addEqualityGroup(3) - * .testCompare(); - * }</pre> + * @param <T> the type of objects to compare. */ -public class ComparatorTester { - @SuppressWarnings({"unchecked", "rawtypes"}) - @Nullable - private final Comparator comparator; +public class ComparatorTester<T> { - /** The items that we are checking, stored as a sorted set of equivalence classes. */ - private final List<List<Object>> equalityGroups; + private final List<List<T>> listOfGroups = new ArrayList<>(); - /** Whether to enforce a.equals(b) == (a.compareTo(b) == 0) */ - private boolean testForEqualsCompatibility; + private final Comparator<T> comparator; - /** - * Creates a new instance that tests the order of objects using the natural order (as defined by - * {@link Comparable}). - */ - public ComparatorTester() { - this(null); + public static <T> ComparatorTester<T> withoutEqualsTest(Comparator<T> comparator) { + return new ComparatorTester<>(comparator); } - /** - * Creates a new instance that tests the order of objects using the given comparator. Or, if the - * comparator is {@code null}, the natural ordering (as defined by {@link Comparable}) - */ - public ComparatorTester(@Nullable Comparator<?> comparator) { - this.equalityGroups = Lists.newArrayList(); + private ComparatorTester(Comparator<T> comparator) { this.comparator = comparator; - this.testForEqualsCompatibility = (this.comparator == null); - } - - /** - * Activates enforcement of {@code a.equals(b) == (a.compareTo(b) == 0)}. This is off by default - * when testing {@link Comparator}s, but can be turned on if required. - */ - public ComparatorTester requireConsistencyWithEquals() { - testForEqualsCompatibility = true; - return this; } - /** - * Deactivates enforcement of {@code a.equals(b) == (a.compareTo(b) == 0)}. This is on by - * default when testing {@link Comparable}s, but can be turned off if required. - */ - public ComparatorTester permitInconsistencyWithEquals() { - testForEqualsCompatibility = false; + @SafeVarargs + public final ComparatorTester<T> addComparableGroup(T... items) { + listOfGroups.add(Arrays.asList(items)); return this; } - /** - * Adds a set of objects to the test which should all compare as equal. All of the elements in - * {@code objects} must be greater than any element of {@code objects} in a previous call to - * {@link #addEqualityGroup(Object...)}. - * - * @return {@code this} (to allow chaining of calls) - */ - public ComparatorTester addEqualityGroup(Object... objects) { - Preconditions.checkNotNull(objects); - Preconditions.checkArgument(objects.length > 0, "Array must not be empty"); - equalityGroups.add(ImmutableList.copyOf(objects)); - return this; - } - - @SuppressWarnings({"unchecked"}) - private int compare(Object a, Object b) { - int compareValue; - if (comparator == null) { - compareValue = ((Comparable<Object>) a).compareTo(b); - } else { - compareValue = comparator.compare(a, b); - } - return compareValue; - } - - public final void testCompare() { - doTestEquivalanceGroupOrdering(); - if (testForEqualsCompatibility) { - doTestEqualsCompatibility(); + public void test() { + for (int i = 0; i < listOfGroups.size(); i++) { + List<T> currentGroup = listOfGroups.get(i); + for (int j = 0; j < i; j++) { + List<T> lhs = listOfGroups.get(j); + assertOrder(i, j, lhs, currentGroup); + } + assertZero(currentGroup); + for (int j = i + 1; j < listOfGroups.size(); j++) { + List<T> rhs = listOfGroups.get(j); + assertOrder(i, j, currentGroup, rhs); + } } + // TODO: also test equals } - private final void doTestEquivalanceGroupOrdering() { - for (int referenceIndex = 0; referenceIndex < equalityGroups.size(); referenceIndex++) { - for (Object reference : equalityGroups.get(referenceIndex)) { - testNullCompare(reference); - testClassCast(reference); - for (int otherIndex = 0; otherIndex < equalityGroups.size(); otherIndex++) { - for (Object other : equalityGroups.get(otherIndex)) { - assertWithMessage("compare(%s, %s)", reference, other) - .that(Integer.signum(compare(reference, other))) - .isEqualTo( - Integer.signum(Ints.compare(referenceIndex, otherIndex))); - } - } - } - } + private void assertOrder(int less, int more, List<T> lessGroup, List<T> moreGroup) { + assertLess(less, more, lessGroup, moreGroup); + assertMore(more, less, moreGroup, lessGroup); } - private final void doTestEqualsCompatibility() { - for (List<Object> referenceGroup : equalityGroups) { - for (Object reference : referenceGroup) { - for (List<Object> otherGroup : equalityGroups) { - for (Object other : otherGroup) { - assertWithMessage( - "Testing equals() for compatibility with" - + " compare()/compareTo(), add a call to" - + " doNotRequireEqualsCompatibility() if this is not" - + " required") - .withMessage("%s.equals(%s)", reference, other) - .that(reference.equals(other)) - .isEqualTo(compare(reference, other) == 0); - } - } + 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); } } } - private void testNullCompare(Object obj) { - // Comparator does not require any specific behavior for null. - if (comparator == null) { - try { - compare(obj, null); - assert_().fail("Expected NullPointerException in %s.compare(null)", obj); - } catch (NullPointerException expected) { - // TODO(cpovirk): Consider accepting JavaScriptException under GWT + 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); } } } - @SuppressWarnings("unchecked") - private void testClassCast(Object obj) { - if (comparator == null) { - try { - compare(obj, ICanNotBeCompared.INSTANCE); - assert_().fail("Expected ClassCastException in %s.compareTo(otherObject)", obj); - } catch (ClassCastException expected) { + private void assertZero(Collection<T> group) { + // Test everything against everything in both directions, including against itself. + for (T leftItem : group) { + for (T rightItem : group) { + assertEquals( + leftItem + " compareTo " + rightItem, + 0, + comparator.compare(leftItem, rightItem)); } } } - - private static final class ICanNotBeCompared { - static final ComparatorTester.ICanNotBeCompared INSTANCE = new ICanNotBeCompared(); - } } diff --git a/tests/common/src/com/android/tv/testing/EpgTestData.java b/tests/common/src/com/android/tv/testing/EpgTestData.java index d22bd283..362f336a 100644 --- a/tests/common/src/com/android/tv/testing/EpgTestData.java +++ b/tests/common/src/com/android/tv/testing/EpgTestData.java @@ -18,17 +18,13 @@ package com.android.tv.testing; import com.android.tv.data.ChannelImpl; import com.android.tv.data.Lineup; -import com.android.tv.data.ProgramImpl; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; -import com.android.tv.testing.fakes.FakeClock; - 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. */ @@ -79,14 +75,14 @@ public abstract class EpgTestData { // Start and end time may be negative meaning they happen before "now". public static final Program PROGRAM_1 = - new ProgramImpl.Builder() + new Program.Builder() .setTitle("Program 1") .setStartTimeUtcMillis(0) .setEndTimeUtcMillis(TimeUnit.MINUTES.toMillis(30)) .build(); public static final Program PROGRAM_2 = - new ProgramImpl.Builder() + new Program.Builder() .setTitle("Program 2") .setStartTimeUtcMillis(TimeUnit.MINUTES.toMillis(30)) .setEndTimeUtcMillis(TimeUnit.MINUTES.toMillis(60)) @@ -195,7 +191,7 @@ public abstract class EpgTestData { new Function<Program, Program>() { @Override public Program apply(Program p) { - return new ProgramImpl.Builder(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/fakes/FakeClock.java b/tests/common/src/com/android/tv/testing/FakeClock.java index adef3cd3..f5941939 100644 --- a/tests/common/src/com/android/tv/testing/fakes/FakeClock.java +++ b/tests/common/src/com/android/tv/testing/FakeClock.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.tv.testing.fakes; +package com.android.tv.testing; import com.android.tv.common.util.Clock; import java.util.concurrent.TimeUnit; diff --git a/tests/common/src/com/android/tv/testing/FakeEpgReader.java b/tests/common/src/com/android/tv/testing/FakeEpgReader.java index 24afe8eb..fb35c652 100644 --- a/tests/common/src/com/android/tv/testing/FakeEpgReader.java +++ b/tests/common/src/com/android/tv/testing/FakeEpgReader.java @@ -19,17 +19,13 @@ 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.ProgramImpl; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.data.epg.EpgReader; import com.android.tv.dvr.data.SeriesInfo; -import com.android.tv.testing.fakes.FakeClock; - import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.collect.ImmutableList; @@ -37,7 +33,6 @@ 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; @@ -149,7 +144,7 @@ public final class FakeEpgReader implements EpgReader { @Nullable @Override public Program apply(@Nullable Program program) { - return new ProgramImpl.Builder(program) + return new Program.Builder(program) .setChannelId(channel.getChannel().getId()) .setPackageName(channel.getChannel().getPackageName()) .build(); diff --git a/tests/common/src/com/android/tv/testing/FakeTvInputManagerHelper.java b/tests/common/src/com/android/tv/testing/FakeTvInputManagerHelper.java index be083856..85bdcf04 100644 --- a/tests/common/src/com/android/tv/testing/FakeTvInputManagerHelper.java +++ b/tests/common/src/com/android/tv/testing/FakeTvInputManagerHelper.java @@ -17,14 +17,13 @@ package com.android.tv.testing; import android.content.Context; -import com.android.tv.common.flags.impl.DefaultLegacyFlags; import com.android.tv.util.TvInputManagerHelper; /** Fake TvInputManagerHelper. */ public class FakeTvInputManagerHelper extends TvInputManagerHelper { public FakeTvInputManagerHelper(Context context) { - super(context, new FakeTvInputManager(), DefaultLegacyFlags.DEFAULT); + super(context, new FakeTvInputManager()); } public FakeTvInputManager getFakeTvInputManager() { diff --git a/tests/common/src/com/android/tv/testing/fakes/FakeTvProvider.java b/tests/common/src/com/android/tv/testing/FakeTvProvider.java index 36e97bcc..20903c60 100644 --- a/tests/common/src/com/android/tv/testing/fakes/FakeTvProvider.java +++ b/tests/common/src/com/android/tv/testing/FakeTvProvider.java @@ -14,7 +14,7 @@ * limitations under the License */ -package com.android.tv.testing.fakes; +package com.android.tv.testing; import android.annotation.SuppressLint; import android.content.ContentProvider; @@ -54,7 +54,7 @@ import androidx.tvprovider.media.tv.TvContractCompat.Programs; import androidx.tvprovider.media.tv.TvContractCompat.Programs.Genres; import androidx.tvprovider.media.tv.TvContractCompat.RecordedPrograms; import androidx.tvprovider.media.tv.TvContractCompat.WatchNextPrograms; -import com.android.tv.common.util.sql.SqlParams; +import com.android.tv.util.SqlParams; import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; import java.io.IOException; diff --git a/tests/common/src/com/android/tv/testing/TestSingletonApp.java b/tests/common/src/com/android/tv/testing/TestSingletonApp.java index e233d95d..f1a98ff5 100644 --- a/tests/common/src/com/android/tv/testing/TestSingletonApp.java +++ b/tests/common/src/com/android/tv/testing/TestSingletonApp.java @@ -19,23 +19,25 @@ package com.android.tv.testing; import android.app.Application; 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.experiments.ExperimentLoader; import com.android.tv.common.flags.impl.DefaultBackendKnobsFlags; import com.android.tv.common.flags.impl.DefaultCloudEpgFlags; +import com.android.tv.common.flags.impl.DefaultConcurrentDvrPlaybackFlags; +import com.android.tv.common.flags.impl.DefaultTunerFlags; import com.android.tv.common.flags.impl.DefaultUiFlags; -import com.android.tv.common.flags.impl.SettableFlagsModule; import com.android.tv.common.recording.RecordingStorageStatusManager; import com.android.tv.common.singletons.HasSingletons; 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; @@ -45,38 +47,47 @@ import com.android.tv.dvr.recorder.RecordingScheduler; import com.android.tv.perf.PerformanceMonitor; import com.android.tv.perf.stub.StubPerformanceMonitor; import com.android.tv.testing.dvr.DvrDataManagerInMemoryImpl; -import com.android.tv.testing.fakes.FakeClock; import com.android.tv.testing.testdata.TestData; import com.android.tv.tuner.singletons.TunerSingletons; +import com.android.tv.tuner.source.TsDataSourceManager; +import com.android.tv.tuner.source.TunerTsStreamerManager; +import com.android.tv.tuner.tvinput.factory.TunerSessionFactory; +import com.android.tv.tuner.tvinput.factory.TunerSessionFactoryImpl; import com.android.tv.tunerinputcontroller.BuiltInTunerManager; -import com.android.tv.util.AsyncDbTask.DbExecutor; import com.android.tv.util.SetupUtils; import com.android.tv.util.TvInputManagerHelper; - +import com.android.tv.util.account.AccountHelper; import com.google.common.base.Optional; - -import dagger.Lazy; - import java.util.concurrent.Executor; +import javax.inject.Provider; -/** Test application for TV app. */ +/** Test application for Live TV. */ public class TestSingletonApp extends Application implements TvSingletons, TunerSingletons, HasSingletons<TvSingletons> { public final FakeClock fakeClock = FakeClock.createWithCurrentTime(); public final FakeEpgReader epgReader = new FakeEpgReader(fakeClock); public final FakeEpgFetcher epgFetcher = new FakeEpgFetcher(); - public final SettableFlagsModule flagsModule = new SettableFlagsModule(); public FakeTvInputManagerHelper tvInputManagerHelper; public SetupUtils setupUtils; public DvrManager dvrManager; public DvrDataManager mDvrDataManager; - @DbExecutor public Executor dbExecutor = AsyncTask.SERIAL_EXECUTOR; - private final Lazy<EpgReader> mEpgReaderProvider = () -> epgReader; + private final Provider<EpgReader> mEpgReaderProvider = SingletonProvider.create(epgReader); private final Optional<BuiltInTunerManager> mBuiltInTunerManagerOptional = Optional.absent(); - - private final PerformanceMonitor mPerformanceMonitor = new StubPerformanceMonitor(); + private final DefaultBackendKnobsFlags mBackendKnobs = new DefaultBackendKnobsFlags(); + private final DefaultCloudEpgFlags mCloudEpgFlags = new DefaultCloudEpgFlags(); + private final DefaultUiFlags mUiFlags = new DefaultUiFlags(); + private final DefaultConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags = + new DefaultConcurrentDvrPlaybackFlags(); + private final TsDataSourceManager.Factory mTsDataSourceManagerFactory = + new TsDataSourceManager.Factory(() -> new TunerTsStreamerManager(null)); + private final TunerSessionFactoryImpl mTunerSessionFactory = + new TunerSessionFactoryImpl( + new DefaultTunerFlags(), + mConcurrentDvrPlaybackFlags, + mTsDataSourceManagerFactory); + private PerformanceMonitor mPerformanceMonitor; private ChannelDataManager mChannelDataManager; @Override @@ -85,9 +96,7 @@ public class TestSingletonApp extends Application tvInputManagerHelper = new FakeTvInputManagerHelper(this); setupUtils = new SetupUtils(this, mBuiltInTunerManagerOptional); tvInputManagerHelper.start(); - mChannelDataManager = - new ChannelDataManager( - this, tvInputManagerHelper, dbExecutor, getContentResolver()); + mChannelDataManager = new ChannelDataManager(this, tvInputManagerHelper); mChannelDataManager.start(); mDvrDataManager = new DvrDataManagerInMemoryImpl(this, fakeClock); // HACK reset the singleton for tests @@ -115,11 +124,21 @@ public class TestSingletonApp extends Application } @Override + public boolean isChannelDataManagerLoadFinished() { + return false; + } + + @Override public ProgramDataManager getProgramDataManager() { return null; } @Override + public boolean isProgramDataManagerCurrentProgramsLoadFinished() { + return false; + } + + @Override public PreviewDataManager getPreviewDataManager() { return null; } @@ -165,11 +184,16 @@ public class TestSingletonApp extends Application } @Override - public Lazy<EpgReader> providesEpgReader() { + public Provider<EpgReader> providesEpgReader() { return mEpgReaderProvider; } @Override + public EpgFetcher getEpgFetcher() { + return epgFetcher; + } + + @Override public SetupUtils getSetupUtils() { return setupUtils; } @@ -180,11 +204,21 @@ public class TestSingletonApp extends Application } @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; } @@ -201,6 +235,9 @@ public class TestSingletonApp extends Application @Override public PerformanceMonitor getPerformanceMonitor() { + if (mPerformanceMonitor == null) { + mPerformanceMonitor = new StubPerformanceMonitor(); + } return mPerformanceMonitor; } @@ -211,22 +248,22 @@ public class TestSingletonApp extends Application @Override public Executor getDbExecutor() { - return dbExecutor; + return AsyncTask.SERIAL_EXECUTOR; } @Override public DefaultBackendKnobsFlags getBackendKnobs() { - return flagsModule.backendKnobsFlags; + return mBackendKnobs; } @Override public DefaultCloudEpgFlags getCloudEpgFlags() { - return flagsModule.cloudEpgFlags; + return mCloudEpgFlags; } @Override public DefaultUiFlags getUiFlags() { - return flagsModule.uiFlags; + return mUiFlags; } @Override @@ -235,6 +272,15 @@ public class TestSingletonApp extends Application } @Override + public DefaultConcurrentDvrPlaybackFlags getConcurrentDvrPlaybackFlags() { + return mConcurrentDvrPlaybackFlags; + } + + public TunerSessionFactory getTunerSessionFactory() { + return mTunerSessionFactory; + } + + @Override public TvSingletons singletons() { return this; } diff --git a/tests/common/src/com/android/tv/testing/constants/ConfigConstants.java b/tests/common/src/com/android/tv/testing/constants/ConfigConstants.java index 944d5395..890c51e0 100644 --- a/tests/common/src/com/android/tv/testing/constants/ConfigConstants.java +++ b/tests/common/src/com/android/tv/testing/constants/ConfigConstants.java @@ -23,8 +23,6 @@ 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; - public static final int MIN_SDK = Build.VERSION_CODES.M; - public static final int MAX_SDK = Build.VERSION_CODES.P; private ConfigConstants() {} } diff --git a/tests/common/src/com/android/tv/testing/robo/ContentProviders.java b/tests/common/src/com/android/tv/testing/robo/ContentProviders.java deleted file mode 100644 index aaaa11df..00000000 --- a/tests/common/src/com/android/tv/testing/robo/ContentProviders.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 deleted file mode 100644 index ad91f3d9..00000000 --- a/tests/common/src/com/android/tv/testing/robo/RobotTestAppHelper.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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.TestSingletonApp; -import com.android.tv.testing.fakes.FakeTvProvider; -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 deleted file mode 100644 index 5a2c41e6..00000000 --- a/tests/common/src/com/android/tv/testing/shadows/ShadowMediaSession.java +++ /dev/null @@ -1,89 +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.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/uihelper/LiveChannelsUiDeviceHelper.java b/tests/common/src/com/android/tv/testing/uihelper/LiveChannelsUiDeviceHelper.java index 30fbf371..4b7c1f89 100644 --- a/tests/common/src/com/android/tv/testing/uihelper/LiveChannelsUiDeviceHelper.java +++ b/tests/common/src/com/android/tv/testing/uihelper/LiveChannelsUiDeviceHelper.java @@ -30,7 +30,7 @@ import com.android.tv.common.CommonConstants; import com.android.tv.testing.utils.Utils; import junit.framework.Assert; -/** Helper for testing the 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; @@ -56,7 +56,7 @@ public class LiveChannelsUiDeviceHelper extends BaseUiDeviceHelper { waitForCondition(mUiDevice, Until.hasObject(Constants.TV_VIEW)); Assert.assertTrue( - Constants.TV_APP_PACKAGE + " did not start", + Constants.TV_APP_PACKAGE + " did not start", mUiDevice.wait( Until.hasObject(By.pkg(Constants.TV_APP_PACKAGE).depth(0)), APPLICATION_START_TIMEOUT_MSEC)); diff --git a/tests/func/AndroidManifest.xml b/tests/func/AndroidManifest.xml index e60773fc..3d7d775f 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="28" android:minSdkVersion="23" /> + <uses-sdk android:targetSdkVersion="27" android:minSdkVersion="23" /> <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" 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 e24c72fa..efc7ecf4 100644 --- a/tests/func/src/com/android/tv/tests/ui/PlayControlsRowViewTest.java +++ b/tests/func/src/com/android/tv/tests/ui/PlayControlsRowViewTest.java @@ -135,7 +135,7 @@ public class PlayControlsRowViewTest { 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 TV app. + // Press HOME twice to visit the home screen and return to Live TV. controller.pressHome(); // Wait until home screen is shown. controller.waitForIdle(); diff --git a/tests/input/AndroidManifest.xml b/tests/input/AndroidManifest.xml index 564323ad..fa52946e 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="28" android:minSdkVersion="23"/> + <uses-sdk android:targetSdkVersion="27" 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/src/com/android/tv/testinput/TestTvInputService.java b/tests/input/src/com/android/tv/testinput/TestTvInputService.java index d19f4558..840587c9 100644 --- a/tests/input/src/com/android/tv/testinput/TestTvInputService.java +++ b/tests/input/src/com/android/tv/testinput/TestTvInputService.java @@ -53,7 +53,7 @@ public class TestTvInputService extends TvInputService { private static final int REFRESH_DELAY_MS = 1000 / 5; private static final boolean DEBUG = false; - // Consider the command delivering time from TV app. + // Consider the command delivering time from Live TV. private static final long MAX_COMMAND_DELAY = TimeUnit.SECONDS.toMillis(3); private final TestInputControl mBackend = TestInputControl.getInstance(); diff --git a/tests/jank/AndroidManifest.xml b/tests/jank/AndroidManifest.xml index 15388514..7c0997ac 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="28" android:minSdkVersion="23" /> + <uses-sdk android:targetSdkVersion="27" android:minSdkVersion="23" /> <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" 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 57e5f100..4ad0f643 100644 --- a/tests/jank/src/com/android/tv/tests/jank/Utils.java +++ b/tests/jank/src/com/android/tv/tests/jank/Utils.java @@ -19,7 +19,7 @@ import android.support.test.uiautomator.UiDevice; import com.android.tv.testing.uihelper.UiDeviceUtils; public final class Utils { - /** TV app process name */ + /** Live TV process name */ public static final String LIVE_CHANNELS_PROCESS_NAME = "com.android.tv"; private Utils() {} diff --git a/tests/robotests/Android.mk b/tests/robotests/Android.mk deleted file mode 100644 index d5c51b57..00000000 --- a/tests/robotests/Android.mk +++ /dev/null @@ -1,76 +0,0 @@ -############################################################# -# Tv Robolectric test target. # -############################################################# -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_MODULE := TvRoboTests -LOCAL_MODULE_CLASS := JAVA_LIBRARIES - -BASE_DIR = src/com/android/tv -EXCLUDE_FILES := \ - $(BASE_DIR)/TvActivityTest.java \ - $(BASE_DIR)/data/epg/EpgFetcherImplTest.java \ - $(BASE_DIR)/guide/ProgramItemViewTest.java \ - -LOCAL_SRC_FILES := $(call all-java-files-under, src) -LOCAL_SRC_FILES := $(filter-out $(EXCLUDE_FILES),$(LOCAL_SRC_FILES)) - -LOCAL_JAVA_LIBRARIES := \ - Robolectric_all-target \ - mockito-robolectric-prebuilt \ - robolectric_android-all-stub \ - -LOCAL_STATIC_JAVA_LIBRARIES := \ - tv-lib-dagger - -LOCAL_STATIC_ANDROID_LIBRARIES := \ - androidx.test.core \ - tv-lib-dagger-android \ - tv-test-common \ - tv-test-common-robo \ - -LOCAL_ANNOTATION_PROCESSORS := \ - tv-lib-dagger-android-processor \ - tv-lib-dagger-compiler \ - -LOCAL_ANNOTATION_PROCESSOR_CLASSES := \ - dagger.internal.codegen.ComponentProcessor,dagger.android.processor.AndroidProcessor - -LOCAL_INSTRUMENTATION_FOR := LiveTv - -LOCAL_MODULE_TAGS := optional - -include $(BUILD_STATIC_JAVA_LIBRARY) - -############################################################# -# Tv runner target to run the previous target. # -############################################################# -include $(CLEAR_VARS) -LOCAL_MODULE := RunTvRoboTests - -BASE_DIR = com/android/tv -EXCLUDE_FILES := \ - $(BASE_DIR)/MainActivityRoboTest.java \ - $(BASE_DIR)/TvActivityTest.java \ - $(BASE_DIR)/data/epg/EpgFetcherImplTest.java \ - $(BASE_DIR)/guide/ProgramItemViewTest.java \ - $(BASE_DIR)/guide/ProgramTableAdapterTest.java \ - -LOCAL_ROBOTEST_FILES := $(call find-files-in-subdirs,$(LOCAL_PATH)/src,*Test.java,.) -LOCAL_ROBOTEST_FILES := $(filter-out $(EXCLUDE_FILES),$(LOCAL_ROBOTEST_FILES)) - -LOCAL_JAVA_LIBRARIES := \ - Robolectric_all-target \ - TvRoboTests \ - mockito-robolectric-prebuilt \ - robolectric_android-all-stub \ - tv-lib-truth \ - tv-test-common \ - tv-test-common-robo \ - -LOCAL_TEST_PACKAGE := LiveTv - -LOCAL_ROBOTEST_TIMEOUT := 36000 - -include external/robolectric-shadows/run_robotests.mk diff --git a/tests/robotests/README.md b/tests/robotests/README.md deleted file mode 100644 index 8e4bcb5a..00000000 --- a/tests/robotests/README.md +++ /dev/null @@ -1,5 +0,0 @@ -Unit test suite for Live Channels using Robolectric. - -``` -$ m -j96 RunTvRoboTests -```
\ No newline at end of file diff --git a/tests/robotests/src/com/android/tv/MainActivityRoboTest.java b/tests/robotests/src/com/android/tv/MainActivityRoboTest.java deleted file mode 100644 index be7ae06b..00000000 --- a/tests/robotests/src/com/android/tv/MainActivityRoboTest.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * 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; - -import static com.google.common.truth.Truth.assertThat; - -import android.media.tv.TvTrackInfo; -import android.os.Bundle; -import android.view.LayoutInflater; - -import com.android.tv.common.flags.impl.DefaultLegacyFlags; -import com.android.tv.data.ProgramDataManager; -import com.android.tv.data.StreamInfo; -import com.android.tv.testing.TestSingletonApp; -import com.android.tv.testing.constants.ConfigConstants; -import com.android.tv.ui.TunableTvView; -import com.android.tv.util.TvInputManagerHelper; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; -import org.robolectric.shadow.api.Shadow; - -import java.util.Arrays; - -/** Tests for {@link TunableTvView} */ -@RunWith(RobolectricTestRunner.class) -@Config( - sdk = ConfigConstants.SDK, - application = TestSingletonApp.class, - shadows = {ShadowTvView.class}) -public class MainActivityRoboTest { - private ShadowTvView mShadowTvView; - private FakeMainActivity mMainActivity; - - @Before - public void setUp() { - mMainActivity = Robolectric.buildActivity(FakeMainActivity.class).create().get(); - mShadowTvView = Shadow.extract(mMainActivity.getTvView().getTvView()); - mShadowTvView.listener = mMainActivity.getListener(); - } - - @Test - public void testSelectAudioTrack_autoSelect() { - mShadowTvView.mAudioTrackCountChanged = false; - setTracks( - TvTrackInfo.TYPE_AUDIO, - buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "EN audio 1", "EN"), - buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "FR audio 1", "FR")); - mMainActivity.selectAudioTrack("FR audio 1"); - assertThat(mMainActivity.getSelectedTrack(TvTrackInfo.TYPE_AUDIO)).isEqualTo("FR audio 1"); - - setTracks( - TvTrackInfo.TYPE_AUDIO, - buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "EN audio 2", "EN"), - buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "FR audio 2", "FR"), - buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "FR audio 3", "FR")); - mMainActivity.applyMultiAudio(null); - // FR audio 2 is selected according the previously selected track. - assertThat(mMainActivity.getSelectedTrack(TvTrackInfo.TYPE_AUDIO)).isEqualTo("FR audio 2"); - } - - @Test - public void testSelectAudioTrack_audioTrackCountChanged() { - mShadowTvView.mAudioTrackCountChanged = true; - setTracks( - TvTrackInfo.TYPE_AUDIO, - buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "EN audio 1", "EN"), - buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "FR audio 1", "FR")); - mMainActivity.selectAudioTrack("FR audio 1"); - assertThat(mMainActivity.getSelectedTrack(TvTrackInfo.TYPE_AUDIO)).isEqualTo("FR audio 1"); - - setTracks( - TvTrackInfo.TYPE_AUDIO, - buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "EN audio 2", "EN"), - buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "FR audio 2", "FR"), - buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "FR audio 3", "FR")); - mMainActivity.selectAudioTrack("FR audio 3"); - // FR audio 3 is selected even if the track info has been changed - assertThat(mMainActivity.getSelectedTrack(TvTrackInfo.TYPE_AUDIO)).isEqualTo("FR audio 3"); - } - - @Test - public void testSelectAudioTrack_audioTrackCountNotChanged() { - mShadowTvView.mAudioTrackCountChanged = false; - setTracks( - TvTrackInfo.TYPE_AUDIO, - buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "EN audio 1", "EN"), - buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "FR audio 1", "FR")); - mMainActivity.selectAudioTrack("FR audio 1"); - assertThat(mMainActivity.getSelectedTrack(TvTrackInfo.TYPE_AUDIO)).isEqualTo("FR audio 1"); - - setTracks( - TvTrackInfo.TYPE_AUDIO, - buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "EN audio 2", "EN"), - buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "FR audio 2", "FR"), - buildTrackForTesting(TvTrackInfo.TYPE_AUDIO, "FR audio 3", "FR")); - mMainActivity.selectAudioTrack("FR audio 3"); - assertThat(mMainActivity.getSelectedTrack(TvTrackInfo.TYPE_AUDIO)).isEqualTo("FR audio 3"); - } - - private void setTracks(int type, TvTrackInfo... tracks) { - mShadowTvView.mTracks.put(type, Arrays.asList(tracks)); - mShadowTvView.mSelectedTracks.put(type, null); - } - - private TvTrackInfo buildTrackForTesting(int type, String id, String language) { - return new TvTrackInfo.Builder(type, id) - .setLanguage(language) - .setAudioChannelCount(0) - .build(); - } - - /** A {@link MainActivity} class for tests */ - public static class FakeMainActivity extends MainActivity { - private MyOnTuneListener mListener; - - @Override - protected void onCreate(Bundle savedInstanceState) { - // Override onCreate() to omit unnecessary member variables - mTvView = - (TunableTvView) - LayoutInflater.from(RuntimeEnvironment.application) - .inflate(R.layout.activity_tv, null) - .findViewById(R.id.main_tunable_tv_view); - DefaultLegacyFlags legacyFlags = DefaultLegacyFlags.DEFAULT; - mTvView.initialize( - new ProgramDataManager(RuntimeEnvironment.application), - new TvInputManagerHelper(RuntimeEnvironment.application, legacyFlags), - legacyFlags); - mTvView.start(); - mListener = - new MyOnTuneListener() { - @Override - public void onStreamInfoChanged( - StreamInfo info, boolean allowAutoSelectionOfTrack) { - applyMultiAudio( - allowAutoSelectionOfTrack - ? null - : getSelectedTrack(TvTrackInfo.TYPE_AUDIO)); - } - }; - mTvView.setOnTuneListener(mListener); - } - - public TunableTvView getTvView() { - return mTvView; - } - - public MyOnTuneListener getListener() { - return mListener; - } - } -} diff --git a/tests/robotests/src/com/android/tv/MediaSessionWrapperTest.java b/tests/robotests/src/com/android/tv/MediaSessionWrapperTest.java deleted file mode 100644 index 5be62acb..00000000 --- a/tests/robotests/src/com/android/tv/MediaSessionWrapperTest.java +++ /dev/null @@ -1,165 +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; - -import static com.google.common.truth.Truth.assertThat; - -import android.app.PendingIntent; -import android.content.Intent; -import android.media.MediaMetadata; -import android.media.session.PlaybackState; - -import com.android.tv.testing.EpgTestData; -import com.android.tv.testing.TvRobolectricTestRunner; -import com.android.tv.testing.TestSingletonApp; -import com.android.tv.testing.constants.ConfigConstants; -import com.android.tv.testing.shadows.ShadowMediaSession; - -import com.google.common.collect.Maps; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; -import org.robolectric.shadow.api.Shadow; - -import java.util.Map; - -/** Tests fpr {@link MediaSessionWrapper}. */ -@RunWith(TvRobolectricTestRunner.class) -@Config( - sdk = ConfigConstants.SDK, - application = TestSingletonApp.class, - shadows = {ShadowMediaSession.class}) -public class MediaSessionWrapperTest { - - private static final int TEST_REQUEST_CODE = 1337; - - private ShadowMediaSession mediaSession; - private MediaSessionWrapper mediaSessionWrapper; - private PendingIntent pendingIntent; - - @Before - public void setUp() { - pendingIntent = - PendingIntent.getActivity( - RuntimeEnvironment.application, TEST_REQUEST_CODE, new Intent(), 0); - mediaSessionWrapper = - new MediaSessionWrapper(RuntimeEnvironment.application, pendingIntent) { - @Override - void initMediaController() { - // Not use MediaController for tests here because: - // 1. it's not allow to shadow MediaController - // 2. The Context TestSingletonApp is not an instance of Activity so - // Activity.setMediaController cannot be called. - // onPlaybackStateChanged() is called in #setPlaybackState instead. - } - - @Override - void unregisterMediaControllerCallback() {} - }; - mediaSession = Shadow.extract(mediaSessionWrapper.getMediaSession()); - } - - @Test - public void setSessionActivity() { - assertThat(mediaSession.mSessionActivity).isEqualTo(this.pendingIntent); - } - - @Test - public void setPlaybackState_true() { - setPlaybackState(true); - assertThat(mediaSession.mActive).isTrue(); - assertThat(mediaSession.mPlaybackState.getState()).isEqualTo(PlaybackState.STATE_PLAYING); - } - - @Test - public void setPlaybackState_false() { - setPlaybackState(false); - assertThat(mediaSession.mActive).isFalse(); - assertThat(mediaSession.mPlaybackState).isNull(); - } - - @Test - public void setPlaybackState_trueThenFalse() { - setPlaybackState(true); - setPlaybackState(false); - assertThat(mediaSession.mActive).isFalse(); - assertThat(mediaSession.mPlaybackState.getState()).isEqualTo(PlaybackState.STATE_STOPPED); - } - - @Test - public void update_channel10() { - - mediaSessionWrapper.update(false, EpgTestData.toTvChannel(EpgTestData.CHANNEL_10), null); - assertThat(asMap(mediaSession.mMediaMetadata)) - .containsExactly(MediaMetadata.METADATA_KEY_TITLE, "Channel TEN"); - } - - @Test - public void update_blockedChannel10() { - mediaSessionWrapper.update(true, EpgTestData.toTvChannel(EpgTestData.CHANNEL_10), null); - assertThat(asMap(mediaSession.mMediaMetadata)) - .containsExactly( - MediaMetadata.METADATA_KEY_TITLE, - "Channel blocked", - MediaMetadata.METADATA_KEY_ART, - null); - } - - @Test - public void update_channel10Program2() { - mediaSessionWrapper.update( - false, EpgTestData.toTvChannel(EpgTestData.CHANNEL_10), EpgTestData.PROGRAM_2); - assertThat(asMap(mediaSession.mMediaMetadata)) - .containsExactly(MediaMetadata.METADATA_KEY_TITLE, "Program 2"); - } - - @Test - public void update_blockedChannel10Program2() { - mediaSessionWrapper.update( - true, EpgTestData.toTvChannel(EpgTestData.CHANNEL_10), EpgTestData.PROGRAM_2); - assertThat(asMap(mediaSession.mMediaMetadata)) - .containsExactly( - MediaMetadata.METADATA_KEY_TITLE, - "Channel blocked", - MediaMetadata.METADATA_KEY_ART, - null); - // TODO(b/70559407): test async loading of images. - } - - @Test - public void release() { - mediaSessionWrapper.release(); - assertThat(mediaSession.mReleased).isTrue(); - } - - private Map<String, Object> asMap(MediaMetadata mediaMetadata) { - return Maps.asMap(mediaMetadata.keySet(), key -> mediaMetadata.getString(key)); - } - - private void setPlaybackState(boolean isPlaying) { - mediaSessionWrapper.setPlaybackState(isPlaying); - mediaSessionWrapper - .getMediaControllerCallback() - .onPlaybackStateChanged( - isPlaying - ? MediaSessionWrapper.MEDIA_SESSION_STATE_PLAYING - : MediaSessionWrapper.MEDIA_SESSION_STATE_STOPPED); - } -} diff --git a/tests/robotests/src/com/android/tv/SetupPassthroughActivityTest.java b/tests/robotests/src/com/android/tv/SetupPassthroughActivityTest.java deleted file mode 100644 index 76037b49..00000000 --- a/tests/robotests/src/com/android/tv/SetupPassthroughActivityTest.java +++ /dev/null @@ -1,447 +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; - -import static com.google.common.truth.Truth.assertThat; - -import static org.robolectric.Shadows.shadowOf; - -import android.app.Activity; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.ServiceInfo; -import android.media.tv.TvInputInfo; -import android.os.Build.VERSION; -import android.os.Build.VERSION_CODES; -import android.support.annotation.Nullable; - -import androidx.test.core.app.ApplicationProvider; - -import com.android.tv.common.CommonConstants; -import com.android.tv.common.dagger.ApplicationModule; -import com.android.tv.common.flags.impl.DefaultLegacyFlags; -import com.android.tv.common.flags.impl.SettableFlagsModule; -import com.android.tv.common.util.CommonUtils; -import com.android.tv.data.ChannelDataManager; -import com.android.tv.data.epg.EpgFetcher; -import com.android.tv.features.TvFeatures; -import com.android.tv.modules.TvSingletonsModule; -import com.android.tv.testing.FakeTvInputManager; -import com.android.tv.testing.FakeTvInputManagerHelper; -import com.android.tv.testing.TestSingletonApp; -import com.android.tv.testing.constants.ConfigConstants; -import com.android.tv.tunerinputcontroller.BuiltInTunerManager; -import com.android.tv.util.AsyncDbTask.DbExecutor; -import com.android.tv.util.SetupUtils; -import com.android.tv.util.TvInputManagerHelper; - -import com.google.android.tv.partner.support.EpgContract; -import com.google.common.base.Optional; -import com.android.tv.common.flags.proto.TypedFeatures.StringListParam; - -import dagger.Component; -import dagger.Module; -import dagger.Provides; -import dagger.android.AndroidInjectionModule; -import dagger.android.AndroidInjector; -import dagger.android.DispatchingAndroidInjector; -import dagger.android.HasAndroidInjector; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentMatchers; -import org.mockito.Mockito; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.android.controller.ActivityController; -import org.robolectric.android.util.concurrent.RoboExecutorService; -import org.robolectric.annotation.Config; -import org.robolectric.shadows.ShadowActivity; - -import java.util.concurrent.Executor; - -import javax.inject.Inject; -import javax.inject.Singleton; - -/** Tests for {@link SetupPassthroughActivity}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK, application = SetupPassthroughActivityTest.MyTestApp.class) -public class SetupPassthroughActivityTest { - - private static final int REQUEST_START_SETUP_ACTIVITY = 200; - - private MyTestApp testSingletonApp; - - private TvInputInfo testInput; - - @Before - public void setup() { - testInput = createMockInput("com.example/.Input"); - testSingletonApp = (MyTestApp) ApplicationProvider.getApplicationContext(); - testSingletonApp.flagsModule.legacyFlags = - DefaultLegacyFlags.builder().enableQaFeatures(true).build(); - testSingletonApp.tvInputManagerHelper.getFakeTvInputManager(); - } - - @After - public void after() { - TvFeatures.CLOUD_EPG_FOR_3RD_PARTY.resetForTests(); - } - - @Test - public void create_emptyIntent() { - SetupPassthroughActivity activity = - Robolectric.buildActivity(SetupPassthroughActivity.class, new Intent()) - .create() - .get(); - ShadowActivity.IntentForResult shadowIntent = - shadowOf(activity).getNextStartedActivityForResult(); - // Since there is no inputs, the next activity should not be started. - assertThat(shadowIntent).isNull(); - assertThat(activity.isFinishing()).isTrue(); - } - - @Test - public void create_noInputs() { - SetupPassthroughActivity activity = createSetupActivityFor("com.example/.Input"); - ShadowActivity.IntentForResult shadowIntent = - shadowOf(activity).getNextStartedActivityForResult(); - // Since there is no inputs, the next activity should not be started. - assertThat(shadowIntent).isNull(); - assertThat(activity.isFinishing()).isTrue(); - } - - @Test - public void create_inputNotFound() { - testSingletonApp.tvInputManagerHelper = new FakeTvInputManagerHelper(testSingletonApp); - testSingletonApp.tvInputManagerHelper.start(); - testSingletonApp.tvInputManagerHelper.getFakeTvInputManager().add(testInput, -1); - SetupPassthroughActivity activity = createSetupActivityFor("com.example/.Other"); - ShadowActivity.IntentForResult shadowIntent = - shadowOf(activity).getNextStartedActivityForResult(); - // Since the input is not found, the next activity should not be started. - assertThat(shadowIntent).isNull(); - assertThat(activity.isFinishing()).isTrue(); - } - - @Test - public void create_validInput() { - testSingletonApp.tvInputManagerHelper.start(); - testSingletonApp.tvInputManagerHelper.getFakeTvInputManager().add(testInput, -1); - SetupPassthroughActivity activity = createSetupActivityFor(testInput.getId()); - - ShadowActivity.IntentForResult shadowIntent = - shadowOf(activity).getNextStartedActivityForResult(); - assertThat(shadowIntent).isNotNull(); - assertThat(shadowIntent.options).isNull(); - assertThat(shadowIntent.intent.getExtras()).isNotNull(); - assertThat(shadowIntent.requestCode).isEqualTo(REQUEST_START_SETUP_ACTIVITY); - assertThat(activity.isFinishing()).isFalse(); - } - - @Test - public void create_trustedCallingPackage() { - testSingletonApp.tvInputManagerHelper.start(); - testSingletonApp.tvInputManagerHelper.getFakeTvInputManager().add(testInput, -1); - - ActivityController<SetupPassthroughActivity> activityController = - Robolectric.buildActivity( - SetupPassthroughActivity.class, - CommonUtils.createSetupIntent(new Intent(), testInput.getId())); - SetupPassthroughActivity activity = activityController.get(); - ShadowActivity shadowActivity = shadowOf(activity); - shadowActivity.setCallingActivity( - new ComponentName(CommonConstants.BASE_PACKAGE, "com.example.MyClass")); - activityController.create(); - - ShadowActivity.IntentForResult shadowIntent = - shadowActivity.getNextStartedActivityForResult(); - assertThat(shadowIntent).isNotNull(); - assertThat(shadowIntent.options).isNull(); - assertThat(shadowIntent.intent.getExtras()).isNotNull(); - assertThat(shadowIntent.requestCode).isEqualTo(REQUEST_START_SETUP_ACTIVITY); - assertThat(activity.isFinishing()).isFalse(); - } - - @Test - public void create_nonTrustedCallingPackage() { - testSingletonApp.tvInputManagerHelper.start(); - testSingletonApp.tvInputManagerHelper.getFakeTvInputManager().add(testInput, -1); - - ActivityController<SetupPassthroughActivity> activityController = - Robolectric.buildActivity( - SetupPassthroughActivity.class, - CommonUtils.createSetupIntent(new Intent(), testInput.getId())); - SetupPassthroughActivity activity = activityController.get(); - ShadowActivity shadowActivity = shadowOf(activity); - shadowActivity.setCallingActivity( - new ComponentName("com.notTrusted", "com.notTrusted.MyClass")); - activityController.create(); - - ShadowActivity.IntentForResult shadowIntent = - shadowActivity.getNextStartedActivityForResult(); - // Since the calling activity is not trusted, the next activity should not be started. - assertThat(shadowIntent).isNull(); - assertThat(activity.isFinishing()).isTrue(); - } - - @Test - public void onActivityResult_canceled() { - testSingletonApp.tvInputManagerHelper.getFakeTvInputManager().add(testInput, -1); - SetupPassthroughActivity activity = createSetupActivityFor(testInput.getId()); - - activity.onActivityResult(0, Activity.RESULT_CANCELED, null); - assertThat(activity.isFinishing()).isTrue(); - assertThat(shadowOf(activity).getResultCode()).isEqualTo(Activity.RESULT_CANCELED); - } - - @Test - public void onActivityResult_ok() { - TestSetupUtils setupUtils = new TestSetupUtils(RuntimeEnvironment.application); - testSingletonApp.setupUtils = setupUtils; - testSingletonApp.tvInputManagerHelper.getFakeTvInputManager().add(testInput, -1); - SetupPassthroughActivity activity = createSetupActivityFor(testInput.getId()); - activity.onActivityResult(REQUEST_START_SETUP_ACTIVITY, Activity.RESULT_OK, null); - - assertThat(testSingletonApp.epgFetcher.fetchStarted).isFalse(); - assertThat(setupUtils.finishedId).isEqualTo("com.example/.Input"); - assertThat(activity.isFinishing()).isFalse(); - - setupUtils.finishedRunnable.run(); - assertThat(activity.isFinishing()).isTrue(); - assertThat(shadowOf(activity).getResultCode()).isEqualTo(Activity.RESULT_OK); - } - - @Test - public void onActivityResult_3rdPartyEpg_ok() { - TvFeatures.CLOUD_EPG_FOR_3RD_PARTY.enableForTest(); - TestSetupUtils setupUtils = new TestSetupUtils(RuntimeEnvironment.application); - testSingletonApp.setupUtils = setupUtils; - testSingletonApp.tvInputManagerHelper.getFakeTvInputManager().add(testInput, -1); - testSingletonApp.getCloudEpgFlags().setThirdPartyEpgInputCsv(testInput.getId()); - SetupPassthroughActivity activity = createSetupActivityFor(testInput.getId()); - Intent data = new Intent(); - data.putExtra(EpgContract.EXTRA_USE_CLOUD_EPG, true); - data.putExtra(TvInputInfo.EXTRA_INPUT_ID, testInput.getId()); - activity.onActivityResult(REQUEST_START_SETUP_ACTIVITY, Activity.RESULT_OK, data); - - assertThat(testSingletonApp.epgFetcher.fetchStarted).isTrue(); - assertThat(setupUtils.finishedId).isEqualTo("com.example/.Input"); - assertThat(activity.isFinishing()).isFalse(); - - setupUtils.finishedRunnable.run(); - assertThat(activity.isFinishing()).isTrue(); - assertThat(shadowOf(activity).getResultCode()).isEqualTo(Activity.RESULT_OK); - } - - @Test - public void onActivityResult_3rdPartyEpg_notWhiteListed() { - TvFeatures.CLOUD_EPG_FOR_3RD_PARTY.enableForTest(); - TestSetupUtils setupUtils = new TestSetupUtils(RuntimeEnvironment.application); - testSingletonApp.setupUtils = setupUtils; - testSingletonApp.tvInputManagerHelper.getFakeTvInputManager().add(testInput, -1); - SetupPassthroughActivity activity = createSetupActivityFor(testInput.getId()); - Intent data = new Intent(); - data.putExtra(EpgContract.EXTRA_USE_CLOUD_EPG, true); - data.putExtra(TvInputInfo.EXTRA_INPUT_ID, testInput.getId()); - activity.onActivityResult(REQUEST_START_SETUP_ACTIVITY, Activity.RESULT_OK, data); - - assertThat(testSingletonApp.epgFetcher.fetchStarted).isFalse(); - assertThat(setupUtils.finishedId).isEqualTo("com.example/.Input"); - assertThat(activity.isFinishing()).isFalse(); - - setupUtils.finishedRunnable.run(); - assertThat(activity.isFinishing()).isTrue(); - assertThat(shadowOf(activity).getResultCode()).isEqualTo(Activity.RESULT_OK); - } - - @Test - public void onActivityResult_3rdPartyEpg_disabled() { - TvFeatures.CLOUD_EPG_FOR_3RD_PARTY.disableForTests(); - TestSetupUtils setupUtils = new TestSetupUtils(RuntimeEnvironment.application); - testSingletonApp.setupUtils = setupUtils; - testSingletonApp.tvInputManagerHelper.getFakeTvInputManager().add(testInput, -1); - testSingletonApp.getCloudEpgFlags().setThirdPartyEpgInputCsv(testInput.getId()); - testSingletonApp.dbExecutor = new RoboExecutorService(); - SetupPassthroughActivity activity = createSetupActivityFor(testInput.getId()); - Intent data = new Intent(); - data.putExtra(EpgContract.EXTRA_USE_CLOUD_EPG, true); - data.putExtra(TvInputInfo.EXTRA_INPUT_ID, testInput.getId()); - activity.onActivityResult(REQUEST_START_SETUP_ACTIVITY, Activity.RESULT_OK, data); - - assertThat(testSingletonApp.epgFetcher.fetchStarted).isFalse(); - assertThat(setupUtils.finishedId).isEqualTo("com.example/.Input"); - assertThat(activity.isFinishing()).isFalse(); - - setupUtils.finishedRunnable.run(); - assertThat(activity.isFinishing()).isTrue(); - assertThat(shadowOf(activity).getResultCode()).isEqualTo(Activity.RESULT_OK); - } - - @Test - public void onActivityResult_ok_tvInputInfo_null() { - TestSetupUtils setupUtils = new TestSetupUtils(RuntimeEnvironment.application); - testSingletonApp.setupUtils = setupUtils; - FakeTvInputManager tvInputManager = - testSingletonApp.tvInputManagerHelper.getFakeTvInputManager(); - SetupPassthroughActivity activity = createSetupActivityFor(testInput.getId()); - activity.onActivityResult(REQUEST_START_SETUP_ACTIVITY, Activity.RESULT_OK, null); - - assertThat(tvInputManager.getTvInputInfo(testInput.getId())).isEqualTo(null); - assertThat(testSingletonApp.epgFetcher.fetchStarted).isFalse(); - assertThat(activity.isFinishing()).isTrue(); - - assertThat(shadowOf(activity).getResultCode()).isEqualTo(Activity.RESULT_OK); - } - - private SetupPassthroughActivity createSetupActivityFor(String inputId) { - return Robolectric.buildActivity( - SetupPassthroughActivity.class, - CommonUtils.createSetupIntent(new Intent(), inputId)) - .create() - .get(); - } - - private TvInputInfo createMockInput(String inputId) { - TvInputInfo tvInputInfo = Mockito.mock(TvInputInfo.class); - ServiceInfo serviceInfo = new ServiceInfo(); - ApplicationInfo applicationInfo = new ApplicationInfo(); - Mockito.when(tvInputInfo.getId()).thenReturn(inputId); - serviceInfo.packageName = inputId.substring(0, inputId.indexOf('/')); - serviceInfo.applicationInfo = applicationInfo; - applicationInfo.flags = 0; - Mockito.when(tvInputInfo.getServiceInfo()).thenReturn(serviceInfo); - Mockito.when(tvInputInfo.loadLabel(ArgumentMatchers.any())).thenReturn("testLabel"); - if (VERSION.SDK_INT >= VERSION_CODES.N) { - Mockito.when(tvInputInfo.loadCustomLabel(ArgumentMatchers.any())) - .thenReturn("testCustomLabel"); - } - return tvInputInfo; - } - - /** - * Test SetupUtils. - * - * <p>SetupUtils has lots of DB and threading interactions, that make it hard to test. This - * bypasses all of that. - */ - private static class TestSetupUtils extends SetupUtils { - public String finishedId; - public Runnable finishedRunnable; - - private TestSetupUtils(Context context) { - super(context, Optional.absent()); - } - - @Override - public void onTvInputSetupFinished(String inputId, @Nullable Runnable postRunnable) { - finishedId = inputId; - finishedRunnable = postRunnable; - } - } - - /** Test app for {@link SetupPassthroughActivityTest} */ - public static class MyTestApp extends TestSingletonApp implements HasAndroidInjector { - - @Inject DispatchingAndroidInjector<Object> dispatchingAndroidInjector; - - @Override - public void onCreate() { - - super.onCreate(); - // Inject afterwards so we can use objects created in super. - // Note TestSingletonApp does not do injection so it is safe - applicationInjector().inject(this); - } - - @Override - public AndroidInjector<Object> androidInjector() { - return dispatchingAndroidInjector; - } - - protected AndroidInjector<MyTestApp> applicationInjector() { - - return DaggerSetupPassthroughActivityTest_TestComponent.builder() - .applicationModule(new ApplicationModule(this)) - .tvSingletonsModule(new TvSingletonsModule(this)) - .testModule(new TestModule(this)) - .settableFlagsModule(flagsModule) - .build(); - } - } - - /** Dagger component for {@link SetupPassthroughActivityTest}. */ - @Singleton - @Component( - modules = { - AndroidInjectionModule.class, - TestModule.class, - }) - interface TestComponent extends AndroidInjector<MyTestApp> {} - - @Module( - includes = { - SetupPassthroughActivity.Module.class, - ApplicationModule.class, - TvSingletonsModule.class, - SettableFlagsModule.class, - }) - /** Module for {@link MyTestApp} */ - static class TestModule { - private final MyTestApp myTestApp; - - TestModule(MyTestApp test) { - myTestApp = test; - } - - @Provides - Optional<BuiltInTunerManager> providesBuiltInTunerManager() { - return Optional.absent(); - } - - @Provides - TvInputManagerHelper providesTvInputManagerHelper() { - return myTestApp.tvInputManagerHelper; - } - - @Provides - SetupUtils providesTestSetupUtils() { - return myTestApp.setupUtils; - } - - @Provides - @DbExecutor - Executor providesDbExecutor() { - return myTestApp.dbExecutor; - } - - @Provides - ChannelDataManager providesChannelDataManager() { - return myTestApp.getChannelDataManager(); - } - - @Provides - EpgFetcher providesEpgFetcher() { - return myTestApp.epgFetcher; - } - } -} diff --git a/tests/robotests/src/com/android/tv/ShadowTvView.java b/tests/robotests/src/com/android/tv/ShadowTvView.java deleted file mode 100644 index 8aad9f00..00000000 --- a/tests/robotests/src/com/android/tv/ShadowTvView.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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; - -import android.content.Context; -import android.media.tv.TvTrackInfo; -import android.media.tv.TvView; -import android.util.AttributeSet; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; -import org.robolectric.shadows.ShadowView; - -// TODO(b/78304522): move this class to robolectric -/** Shadow class of {@link TvView}. */ -@Implements(TvView.class) -public class ShadowTvView extends ShadowView { - public Map<Integer, String> mSelectedTracks = new HashMap<>(); - public Map<Integer, List<TvTrackInfo>> mTracks = new HashMap<>(); - public MainActivity.MyOnTuneListener listener; - public TvView.TvInputCallback mCallback; - public boolean mAudioTrackCountChanged; - - @Implementation - public void __constructor__(Context context) { - } - - @Implementation - public void __constructor__(Context context, AttributeSet attrs) { - } - - @Override - public void __constructor__(Context context, AttributeSet attrs, int defStyleAttr) { - } - - @Implementation - public List<TvTrackInfo> getTracks(int type) { - return mTracks.get(type); - } - - @Implementation - public void selectTrack(int type, String trackId) { - mSelectedTracks.put(type, trackId); - int infoIndex = findTrackIndex(type, trackId); - // for some drivers, audio track count is set to 0 until the corresponding track is - // selected. Here we replace the track with another one whose audio track count is non-zero - // to test this case. - if (mAudioTrackCountChanged) { - replaceTrack(type, infoIndex); - } - mCallback.onTrackSelected("fakeInputId", type, trackId); - } - - @Implementation - public String getSelectedTrack(int type) { - return mSelectedTracks.get(type); - } - - @Implementation - public void setCallback(TvView.TvInputCallback callback) { - mCallback = callback; - } - - private int findTrackIndex(int type, String trackId) { - List<TvTrackInfo> tracks = mTracks.get(type); - if (tracks == null) { - return -1; - } - for (int i = 0; i < tracks.size(); i++) { - TvTrackInfo info = tracks.get(i); - if (info.getId().equals(trackId)) { - return i; - } - } - return -1; - } - - private void replaceTrack(int type, int trackIndex) { - if (trackIndex >= 0) { - TvTrackInfo info = mTracks.get(type).get(trackIndex); - info = new TvTrackInfo - .Builder(info.getType(), info.getId()) - .setLanguage(info.getLanguage()) - .setAudioChannelCount(info.getAudioChannelCount() + 2) - .build(); - mTracks.get(type).set(trackIndex, info); - } - } -} diff --git a/tests/robotests/src/com/android/tv/TvActivityTest.java b/tests/robotests/src/com/android/tv/TvActivityTest.java deleted file mode 100644 index c153de8a..00000000 --- a/tests/robotests/src/com/android/tv/TvActivityTest.java +++ /dev/null @@ -1,48 +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; - -import android.content.Intent; - -import com.android.tv.testing.constants.ConfigConstants; -import com.android.tv.util.Utils; - -import com.google.android.libraries.testing.truth.IntentSubject; -import com.google.common.truth.Truth; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; -import org.robolectric.shadows.ShadowApplication; - -/** Test for {@link TvActivity}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class TvActivityTest { - - @Test - public void testLifeCycle() { - TvActivity activity = Robolectric.setupActivity(TvActivity.class); - Truth.assertThat(activity.isFinishing()).isTrue(); - - Intent nextStartedActivity = ShadowApplication.getInstance().getNextStartedActivity(); - IntentSubject.assertThat(nextStartedActivity).hasComponentClass(MainActivity.class); - IntentSubject.assertThat(nextStartedActivity).hasExtra(Utils.EXTRA_KEY_FROM_LAUNCHER, true); - } -} diff --git a/tests/robotests/src/com/android/tv/audio/AudioManagerHelperTest.java b/tests/robotests/src/com/android/tv/audio/AudioManagerHelperTest.java deleted file mode 100644 index e71b5620..00000000 --- a/tests/robotests/src/com/android/tv/audio/AudioManagerHelperTest.java +++ /dev/null @@ -1,262 +0,0 @@ -/* - * 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.audio; - -import static com.google.common.truth.Truth.assertThat; - -import android.app.Activity; -import android.media.AudioManager; -import android.os.Build; - -import com.android.tv.testing.constants.ConfigConstants; -import com.android.tv.ui.api.TunableTvViewPlayingApi; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.Shadows; -import org.robolectric.annotation.Config; - -/** Tests for {@link AudioManagerHelper}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class AudioManagerHelperTest { - - private AudioManagerHelper mAudioManagerHelper; - private TestTvView mTvView; - private AudioManager mAudioManager; - - @Before - public void setup() { - Activity testActivity = Robolectric.buildActivity(Activity.class).get(); - mTvView = new TestTvView(); - mAudioManager = RuntimeEnvironment.application.getSystemService(AudioManager.class); - - mAudioManagerHelper = new AudioManagerHelper(testActivity, mTvView); - } - - @Test - public void onAudioFocusChange_none_noTimeShift() { - mTvView.mTimeShiftAvailable = false; - - mAudioManagerHelper.onAudioFocusChange(AudioManager.AUDIOFOCUS_NONE); - - assertThat(mTvView.mPaused).isNull(); - assertThat(mTvView.mVolume).isZero(); - } - - @Test - public void onAudioFocusChange_none_TimeShift() { - mTvView.mTimeShiftAvailable = true; - - mAudioManagerHelper.onAudioFocusChange(AudioManager.AUDIOFOCUS_NONE); - - assertThat(mTvView.mPaused).isTrue(); - assertThat(mTvView.mVolume).isNull(); - } - - @Test - public void onAudioFocusChange_gain_noTimeShift() { - mTvView.mTimeShiftAvailable = false; - - mAudioManagerHelper.onAudioFocusChange(AudioManager.AUDIOFOCUS_GAIN); - - assertThat(mTvView.mPaused).isNull(); - assertThat(mTvView.mVolume).isEqualTo(1.0f); - } - - @Test - public void onAudioFocusChange_gain_timeShift() { - mTvView.mTimeShiftAvailable = true; - - mAudioManagerHelper.onAudioFocusChange(AudioManager.AUDIOFOCUS_GAIN); - - assertThat(mTvView.mPaused).isFalse(); - assertThat(mTvView.mVolume).isNull(); - } - - @Test - public void onAudioFocusChange_loss_noTimeShift() { - mTvView.mTimeShiftAvailable = false; - - mAudioManagerHelper.onAudioFocusChange(AudioManager.AUDIOFOCUS_LOSS); - - assertThat(mTvView.mPaused).isNull(); - assertThat(mTvView.mVolume).isEqualTo(0.0f); - } - - @Test - public void onAudioFocusChange_loss_timeShift() { - mTvView.mTimeShiftAvailable = true; - - mAudioManagerHelper.onAudioFocusChange(AudioManager.AUDIOFOCUS_LOSS); - - assertThat(mTvView.mPaused).isTrue(); - assertThat(mTvView.mVolume).isNull(); - } - - @Test - public void onAudioFocusChange_lossTransient_noTimeShift() { - mTvView.mTimeShiftAvailable = false; - - mAudioManagerHelper.onAudioFocusChange(AudioManager.AUDIOFOCUS_LOSS_TRANSIENT); - - assertThat(mTvView.mPaused).isNull(); - assertThat(mTvView.mVolume).isEqualTo(0.0f); - } - - @Test - public void onAudioFocusChange_lossTransient_timeShift() { - mTvView.mTimeShiftAvailable = true; - - mAudioManagerHelper.onAudioFocusChange(AudioManager.AUDIOFOCUS_LOSS_TRANSIENT); - - assertThat(mTvView.mPaused).isTrue(); - assertThat(mTvView.mVolume).isNull(); - } - - @Test - public void onAudioFocusChange_lossTransientCanDuck_noTimeShift() { - mTvView.mTimeShiftAvailable = false; - - mAudioManagerHelper.onAudioFocusChange(AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK); - - assertThat(mTvView.mPaused).isNull(); - assertThat(mTvView.mVolume).isEqualTo(0.3f); - } - - @Test - public void onAudioFocusChange_lossTransientCanDuck_timeShift() { - mTvView.mTimeShiftAvailable = true; - - mAudioManagerHelper.onAudioFocusChange(AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK); - - assertThat(mTvView.mPaused).isTrue(); - assertThat(mTvView.mVolume).isNull(); - } - - @Test - @Config(sdk = {ConfigConstants.SDK, Build.VERSION_CODES.O}) - public void requestAudioFocus_granted() { - Shadows.shadowOf(mAudioManager) - .setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_GRANTED); - mAudioManagerHelper.requestAudioFocus(); - - assertThat(mTvView.mPaused).isNull(); - assertThat(mTvView.mVolume).isEqualTo(1.0f); - } - - @Test - @Config(sdk = {ConfigConstants.SDK, Build.VERSION_CODES.O}) - public void requestAudioFocus_failed() { - Shadows.shadowOf(mAudioManager) - .setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_FAILED); - - mAudioManagerHelper.requestAudioFocus(); - - assertThat(mTvView.mPaused).isNull(); - assertThat(mTvView.mVolume).isZero(); - } - - @Test - @Config(sdk = {ConfigConstants.SDK, Build.VERSION_CODES.O}) - public void requestAudioFocus_delayed() { - Shadows.shadowOf(mAudioManager) - .setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_DELAYED); - - mAudioManagerHelper.requestAudioFocus(); - - assertThat(mTvView.mPaused).isNull(); - assertThat(mTvView.mVolume).isZero(); - } - - @Test - public void setVolumeByAudioFocusStatus_started() { - mAudioManagerHelper.setVolumeByAudioFocusStatus(); - - assertThat(mTvView.mPaused).isNull(); - assertThat(mTvView.mVolume).isZero(); - } - - @Test - public void setVolumeByAudioFocusStatus_notStarted() { - mTvView.mStarted = false; - mAudioManagerHelper.setVolumeByAudioFocusStatus(); - - assertThat(mTvView.mPaused).isNull(); - assertThat(mTvView.mVolume).isNull(); - } - - private static class TestTvView implements TunableTvViewPlayingApi { - private boolean mStarted = true; - private boolean mTimeShiftAvailable = false; - private Float mVolume = null; - private Boolean mPaused = null; - - @Override - public boolean isPlaying() { - return mStarted; - } - - @Override - public void setStreamVolume(float volume) { - mVolume = volume; - } - - @Override - public void setTimeShiftListener(TimeShiftListener listener) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isTimeShiftAvailable() { - return mTimeShiftAvailable; - } - - @Override - public void timeShiftPlay() { - mPaused = false; - } - - @Override - public void timeShiftPause() { - mPaused = true; - } - - @Override - public void timeShiftRewind(int speed) { - throw new UnsupportedOperationException(); - } - - @Override - public void timeShiftFastForward(int speed) { - throw new UnsupportedOperationException(); - } - - @Override - public void timeShiftSeekTo(long timeMs) { - throw new UnsupportedOperationException(); - } - - @Override - public long timeShiftGetCurrentPositionMs() { - throw new UnsupportedOperationException(); - } - } -} diff --git a/tests/robotests/src/com/android/tv/data/ChannelNumberTest.java b/tests/robotests/src/com/android/tv/data/ChannelNumberTest.java deleted file mode 100644 index de051cf5..00000000 --- a/tests/robotests/src/com/android/tv/data/ChannelNumberTest.java +++ /dev/null @@ -1,176 +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.data; - -import static com.android.tv.data.ChannelNumber.parseChannelNumber; -import static com.android.tv.testing.ChannelNumberSubject.assertThat; - -import static com.google.common.truth.Truth.assertThat; - -import com.android.tv.testing.ComparableTester; -import com.android.tv.testing.constants.ConfigConstants; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -/** Tests for {@link ChannelNumber}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class ChannelNumberTest { - - @Test - public void newChannelNumber() { - assertThat(new ChannelNumber()).isEmpty(); - } - - @Test - public void parseChannelNumber_empty() { - assertThat(parseChannelNumber("")).isNull(); - } - - @Test - public void parseChannelNumber_dash() { - assertThat(parseChannelNumber("-")).isNull(); - } - - @Test - public void parseChannelNumber_abcd12() { - assertThat(parseChannelNumber("abcd12")).isNull(); - } - - @Test - public void parseChannelNumber_12abcd() { - assertThat(parseChannelNumber("12abcd")).isNull(); - } - - @Test - public void parseChannelNumber_dash12() { - assertThat(parseChannelNumber("-12")).isNull(); - } - - @Test - public void parseChannelNumber_1() { - assertThat(parseChannelNumber("1")).displaysAs(1); - } - - @Test - public void parseChannelNumber_1234dash4321() { - assertThat(parseChannelNumber("1234-4321")).displaysAs(1234, 4321); - } - - @Test - public void parseChannelNumber_3dash4() { - assertThat(parseChannelNumber("3-4")).displaysAs(3, 4); - } - - @Test - public void parseChannelNumber_5dash6() { - assertThat(parseChannelNumber("5-6")).displaysAs(5, 6); - } - - @Test - public void compareTo() { - 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 - public void compare_null_null() { - assertThat(ChannelNumber.compare(null, null)).isEqualTo(0); - } - - @Test - public void compare_1_1() { - assertThat(ChannelNumber.compare("1", "1")).isEqualTo(0); - ; - } - - @Test - public void compare_null_1() { - assertThat(ChannelNumber.compare(null, "1")).isLessThan(0); - } - - @Test - public void compare_abcd_1() { - assertThat(ChannelNumber.compare("abcd", "1")).isLessThan(0); - } - - @Test - public void compare_dash1_1() { - assertThat(ChannelNumber.compare(".4", "1")).isLessThan(0); - } - - @Test - public void compare_1_null() { - assertThat(ChannelNumber.compare("1", null)).isGreaterThan(0); - } - - @Test - public void equivalent_null_to_null() { - assertThat(ChannelNumber.equivalent(null, null)).isTrue(); - } - - @Test - public void equivalent_1_to_1() { - assertThat(ChannelNumber.equivalent("1", "1")).isTrue(); - } - - @Test - public void equivalent_1d2_to_1() { - assertThat(ChannelNumber.equivalent("1-2", "1")).isTrue(); - } - - @Test - public void equivalent_1_to_1d2() { - assertThat(ChannelNumber.equivalent("1", "1-2")).isTrue(); - } - - @Test - public void equivalent_1_to_2_isFalse() { - assertThat(ChannelNumber.equivalent("1", "2")).isFalse(); - } - - @Test - public void equivalent_1d1_to_1d1() { - assertThat(ChannelNumber.equivalent("1-1", "1-1")).isTrue(); - } - - @Test - public void equivalent_1d1_to_1d2_isFalse() { - assertThat(ChannelNumber.equivalent("1-1", "1-2")).isFalse(); - } - - @Test - public void equivalent_1_to_null_isFalse() { - assertThat(ChannelNumber.equivalent("1", null)).isFalse(); - } - - @Test - public void equivalent_null_to_1_isFalse() { - assertThat(ChannelNumber.equivalent(null, "1")).isFalse(); - } -} diff --git a/tests/robotests/src/com/android/tv/data/GenreItemTest.java b/tests/robotests/src/com/android/tv/data/GenreItemTest.java deleted file mode 100644 index b19dc0d1..00000000 --- a/tests/robotests/src/com/android/tv/data/GenreItemTest.java +++ /dev/null @@ -1,95 +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.google.common.truth.Truth.assertThat; - -import android.media.tv.TvContract.Programs.Genres; -import android.os.Build; - -import com.android.tv.testing.TvRobolectricTestRunner; -import com.android.tv.testing.constants.ConfigConstants; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -/** Tests for {@link GenreItems}. */ -@RunWith(TvRobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class GenreItemTest { - private static final String INVALID_GENRE = "INVALID GENRE"; - - @Test - public void testGetLabels() { - // Checks if no exception is thrown. - GenreItems.getLabels(RuntimeEnvironment.application); - } - - @Test - public void testGetCanonicalGenre() { - int count = GenreItems.getGenreCount(); - assertThat(GenreItems.getCanonicalGenre(GenreItems.ID_ALL_CHANNELS)).isNull(); - for (int i = 1; i < count; ++i) { - assertThat(GenreItems.getCanonicalGenre(i)).isNotNull(); - } - } - - @Test - public void testGetId_base() { - int count = GenreItems.getGenreCount(); - assertThat(GenreItems.getId(null)).isEqualTo(GenreItems.ID_ALL_CHANNELS); - assertThat(GenreItems.getId(INVALID_GENRE)).isEqualTo(GenreItems.ID_ALL_CHANNELS); - 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) { - assertThat(GenreItems.getId(Genres.ARTS)).isEqualTo(GenreItems.ID_ALL_CHANNELS); - assertThat(GenreItems.getId(Genres.ENTERTAINMENT)) - .isEqualTo(GenreItems.ID_ALL_CHANNELS); - assertThat(GenreItems.getId(Genres.LIFE_STYLE)).isEqualTo(GenreItems.ID_ALL_CHANNELS); - assertThat(GenreItems.getId(Genres.MUSIC)).isEqualTo(GenreItems.ID_ALL_CHANNELS); - assertThat(GenreItems.getId(Genres.PREMIER)).isEqualTo(GenreItems.ID_ALL_CHANNELS); - assertThat(GenreItems.getId(Genres.TECH_SCIENCE)).isEqualTo(GenreItems.ID_ALL_CHANNELS); - } 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) { - assertThat(value >= lower && value <= upper).isTrue(); - } -} diff --git a/tests/robotests/src/com/android/tv/data/PreviewDataManagerTest.java b/tests/robotests/src/com/android/tv/data/PreviewDataManagerTest.java deleted file mode 100644 index b341abf4..00000000 --- a/tests/robotests/src/com/android/tv/data/PreviewDataManagerTest.java +++ /dev/null @@ -1,214 +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.data; - -import static com.google.common.truth.Truth.assertThat; - -import android.content.ContentProvider; -import android.content.ContentValues; -import android.content.pm.ProviderInfo; -import android.database.Cursor; -import android.database.SQLException; -import android.net.Uri; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.util.Log; -import android.util.Pair; - -import androidx.tvprovider.media.tv.PreviewProgram; -import androidx.tvprovider.media.tv.TvContractCompat; - -import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; -import com.android.tv.dvr.data.RecordedProgram; -import com.android.tv.testing.TvRobolectricTestRunner; -import com.android.tv.testing.constants.ConfigConstants; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; -import org.robolectric.shadows.ShadowContentResolver; -import org.robolectric.shadows.ShadowLog; - -import java.util.List; - -/** Tests for {@link PreviewDataManager}. */ -@RunWith(TvRobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class PreviewDataManagerTest { - private static final long FAKE_PREVIEW_CHANNEL_ID = 2002; - private static final long FAKE_PROGRAM_ID = 1001; - private static final String FAKE_PROGRAM_TITLE = "test program"; - private static final String FAKE_PROGRAM_POSTER_URI = "http://fake.uri/poster.jpg"; - private static final long FAKE_CHANNEL_ID = 1002; - private static final String FAKE_CHANNEL_DISPLAY_NAME = "test channel"; - private static final String FAKE_INPUT_ID = "test input"; - - private static class QueryExceptionProvider extends ContentProvider { - @Override - public boolean onCreate() { - return false; - } - - @Nullable - @Override - public Cursor query( - @NonNull Uri uri, - @Nullable String[] projection, - @Nullable String selection, - @Nullable String[] selectionArgs, - @Nullable String sortOrder) { - throw new SQLException("Testing " + uri); - } - - @Nullable - @Override - public String getType(@NonNull Uri uri) { - return null; - } - - @Nullable - @Override - public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) { - return null; - } - - @Override - public int delete( - @NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) { - return 0; - } - - @Override - public int update( - @NonNull Uri uri, - @Nullable ContentValues values, - @Nullable String selection, - @Nullable String[] selectionArgs) { - return 0; - } - } - - @Test - public void start() { - PreviewDataManager previewDataManager = - new PreviewDataManager(RuntimeEnvironment.application); - assertThat(previewDataManager.isLoadFinished()).isFalse(); - previewDataManager.start(); - assertThat(previewDataManager.isLoadFinished()).isTrue(); - } - - @Test - public void queryPreviewData_sqlexception() { - ProviderInfo info = new ProviderInfo(); - info.authority = TvContractCompat.AUTHORITY; - QueryExceptionProvider provider = - Robolectric.buildContentProvider(QueryExceptionProvider.class).create(info).get(); - ShadowContentResolver.registerProviderInternal(TvContractCompat.AUTHORITY, provider); - - PreviewDataManager previewDataManager = - new PreviewDataManager(RuntimeEnvironment.application); - assertThat(previewDataManager.isLoadFinished()).isFalse(); - previewDataManager.start(); - List<ShadowLog.LogItem> logs = ShadowLog.getLogsForTag("PreviewDataManager"); - // The only warning should be the test one - // NOTE: I am not using hamcrest matchers because of weird class loading issues - // TODO: use truth - for (ShadowLog.LogItem log : logs) { - if (log.type == Log.WARN) { - assertThat(log.msg).isEqualTo("Unable to get preview data"); - assertThat(log.throwable).isInstanceOf(SQLException.class); - assertThat(log.throwable) - .hasMessageThat() - .isEqualTo("Testing content://android.media.tv/channel?preview=true"); - } - } - } - - @Test - public void createPreviewProgram_fromProgram() { - Program program = - new ProgramImpl.Builder() - .setId(FAKE_PROGRAM_ID) - .setTitle(FAKE_PROGRAM_TITLE) - .setPosterArtUri(FAKE_PROGRAM_POSTER_URI) - .build(); - Channel channel = - new ChannelImpl.Builder() - .setId(FAKE_CHANNEL_ID) - .setDisplayName(FAKE_CHANNEL_DISPLAY_NAME) - .setInputId(FAKE_INPUT_ID) - .build(); - - PreviewProgram previewProgram = - PreviewDataManager.PreviewDataUtils.createPreviewProgramFromContent( - PreviewProgramContent.createFromProgram( - FAKE_PREVIEW_CHANNEL_ID, program, channel), - 0); - - assertThat(previewProgram.getChannelId()).isEqualTo(FAKE_PREVIEW_CHANNEL_ID); - assertThat(previewProgram.getType()) - .isEqualTo(TvContractCompat.PreviewPrograms.TYPE_CHANNEL); - assertThat(previewProgram.isLive()).isTrue(); - assertThat(previewProgram.getTitle()).isEqualTo(FAKE_PROGRAM_TITLE); - assertThat(previewProgram.getDescription()).isEqualTo(FAKE_CHANNEL_DISPLAY_NAME); - assertThat(previewProgram.getPosterArtUri().toString()).isEqualTo(FAKE_PROGRAM_POSTER_URI); - assertThat(previewProgram.getIntentUri()).isEqualTo(channel.getUri()); - assertThat(previewProgram.getPreviewVideoUri()) - .isEqualTo( - PreviewDataManager.PreviewDataUtils.addQueryParamToUri( - channel.getUri(), - Pair.create(PreviewProgramContent.PARAM_INPUT, FAKE_INPUT_ID))); - assertThat(previewProgram.getInternalProviderId()) - .isEqualTo(Long.toString(FAKE_PROGRAM_ID)); - assertThat(previewProgram.getContentId()).isEqualTo(channel.getUri().toString()); - } - - @Test - public void createPreviewProgram_fromRecordedProgram() { - RecordedProgram program = - RecordedProgram.builder() - .setId(FAKE_PROGRAM_ID) - .setTitle(FAKE_PROGRAM_TITLE) - .setPosterArtUri(FAKE_PROGRAM_POSTER_URI) - .setInputId(FAKE_INPUT_ID) - .build(); - Uri recordedProgramUri = TvContractCompat.buildRecordedProgramUri(FAKE_PROGRAM_ID); - - PreviewProgram previewProgram = - PreviewDataManager.PreviewDataUtils.createPreviewProgramFromContent( - PreviewProgramContent.createFromRecordedProgram( - FAKE_PREVIEW_CHANNEL_ID, program, null), - 0); - - assertThat(previewProgram.getChannelId()).isEqualTo(FAKE_PREVIEW_CHANNEL_ID); - assertThat(previewProgram.getType()).isEqualTo(TvContractCompat.PreviewPrograms.TYPE_CLIP); - assertThat(previewProgram.isLive()).isFalse(); - assertThat(previewProgram.getTitle()).isEqualTo(FAKE_PROGRAM_TITLE); - assertThat(previewProgram.getDescription()).isEmpty(); - assertThat(previewProgram.getPosterArtUri().toString()).isEqualTo(FAKE_PROGRAM_POSTER_URI); - assertThat(previewProgram.getIntentUri()).isEqualTo(recordedProgramUri); - assertThat(previewProgram.getPreviewVideoUri()) - .isEqualTo( - PreviewDataManager.PreviewDataUtils.addQueryParamToUri( - recordedProgramUri, - Pair.create(PreviewProgramContent.PARAM_INPUT, FAKE_INPUT_ID))); - assertThat(previewProgram.getContentId()).isEqualTo(recordedProgramUri.toString()); - } -} diff --git a/tests/robotests/src/com/android/tv/data/ProgramDataManagerTest.java b/tests/robotests/src/com/android/tv/data/ProgramDataManagerTest.java deleted file mode 100644 index 2176aa98..00000000 --- a/tests/robotests/src/com/android/tv/data/ProgramDataManagerTest.java +++ /dev/null @@ -1,316 +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.os.Looper.getMainLooper; - -import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth.assertWithMessage; - -import static org.robolectric.Shadows.shadowOf; - -import android.content.ContentResolver; -import android.media.tv.TvContract; - -import com.android.tv.common.flags.impl.DefaultBackendKnobsFlags; -import com.android.tv.data.api.Program; -import com.android.tv.perf.stub.StubPerformanceMonitor; -import com.android.tv.testing.FakeTvInputManagerHelper; -import com.android.tv.testing.TestSingletonApp; -import com.android.tv.testing.constants.ConfigConstants; -import com.android.tv.testing.constants.Constants; -import com.android.tv.testing.data.ProgramInfo; -import com.android.tv.testing.data.ProgramUtils; -import com.android.tv.testing.fakes.FakeClock; -import com.android.tv.testing.fakes.FakeTvProvider; -import com.android.tv.testing.robo.ContentProviders; -import com.android.tv.testing.testdata.TestData; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.android.util.concurrent.RoboExecutorService; -import org.robolectric.annotation.Config; - -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -/** Test for {@link ProgramDataManager} */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK, application = TestSingletonApp.class) -public class 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; - - private ProgramDataManager mProgramDataManager; - private FakeClock mClock; - private TestProgramDataManagerCallback mCallback; - - @Before - public void setUp() { - mClock = FakeClock.createWithCurrentTime(); - mCallback = new TestProgramDataManagerCallback(); - ContentProviders.register(FakeTvProvider.class, TvContract.AUTHORITY); - TestData.DEFAULT_10_CHANNELS.init( - RuntimeEnvironment.application, mClock, TimeUnit.DAYS.toMillis(1)); - FakeTvInputManagerHelper tvInputManagerHelper = - new FakeTvInputManagerHelper(RuntimeEnvironment.application); - RoboExecutorService executor = new RoboExecutorService(); - ContentResolver contentResolver = RuntimeEnvironment.application.getContentResolver(); - ChannelDataManager channelDataManager = - new ChannelDataManager( - RuntimeEnvironment.application, - tvInputManagerHelper, - executor, - contentResolver); - mProgramDataManager = - new ProgramDataManager( - RuntimeEnvironment.application, - executor, - RuntimeEnvironment.application.getContentResolver(), - mClock, - getMainLooper(), - new DefaultBackendKnobsFlags(), - new StubPerformanceMonitor(), - channelDataManager, - tvInputManagerHelper); - - mProgramDataManager.setPrefetchEnabled(true); - mProgramDataManager.addCallback(mCallback); - } - - @After - public void tearDown() { - mProgramDataManager.stop(); - } - - private void startAndWaitForComplete() throws InterruptedException { - mProgramDataManager.start(); - shadowOf(getMainLooper()).idle(); - assertThat(mCallback.channelUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS)) - .isTrue(); - } - - /** 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(RuntimeEnvironment.application, index); - assertThat(startTimeMs).isAtMost(mClock.currentTimeMillis()); - assertThat(mClock.currentTimeMillis()).isLessThan(startTimeMs + programAt.durationMs); - } - } - - /** - * Test for following methods. - * - * <p>{@link ProgramDataManager#getCurrentProgram(long)}, {@link - * ProgramDataManager#getPrograms(long, long)}, {@link - * ProgramDataManager#setPrefetchTimeRange(long)}. - */ - @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)}. - assertThat(currentProgram).isNotNull(); - assertWithMessage("currentProgramStartTime") - .that(currentProgram.getStartTimeUtcMillis()) - .isLessThan(mClock.currentTimeMillis()); - assertWithMessage("currentProgramEndTime") - .that(currentProgram.getEndTimeUtcMillis()) - .isGreaterThan(mClock.currentTimeMillis()); - - // 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(RuntimeEnvironment.application, 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); - assertThat(programs.get(0).getStartTimeUtcMillis()).isEqualTo(startTimeMs); - - // Test {@link ProgramDataManager#setPrefetchTimeRange(long)}. - programs = - mProgramDataManager.getPrograms( - channelId, prefetchTimeRangeStartMs - TimeUnit.HOURS.toMillis(1)); - for (Program program : programs) { - assertThat(program.getEndTimeUtcMillis()).isAtLeast(prefetchTimeRangeStartMs); - } - } - } - - /** - * Test for following methods. - * - * <p>{@link ProgramDataManager#addOnCurrentProgramUpdatedListener}, {@link - * ProgramDataManager#removeOnCurrentProgramUpdatedListener}. - */ - @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(RuntimeEnvironment.application, 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}. - TestProgramDataManagerOnCurrentProgramUpdatedListener listener = - new TestProgramDataManagerOnCurrentProgramUpdatedListener(); - mClock.setCurrentTimeMillis(mClock.currentTimeMillis() + WAIT_TIME_OUT_MS); - mProgramDataManager.addOnCurrentProgramUpdatedListener(testChannelId, listener); - shadowOf(getMainLooper()).runToEndOfTasks(); - assertThat( - listener.currentProgramUpdatedLatch.await( - WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS)) - .isTrue(); - assertThat(listener.updatedChannelId).isEqualTo(testChannelId); - Program currentProgram = mProgramDataManager.getCurrentProgram(testChannelId); - assertProgramEquals(nextProgramStartTimeMs, nextProgramInfo, currentProgram); - assertThat(currentProgram).isEqualTo(listener.updatedProgram); - } - - /** 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); - mCallback.reset(); - List<Program> programList = - mProgramDataManager.getPrograms(testChannelId, mClock.currentTimeMillis()); - assertThat(programList).isNotNull(); - long lastProgramEndTime = programList.get(programList.size() - 1).getEndTimeUtcMillis(); - // Make change in content provider - ProgramUtils.populatePrograms( - RuntimeEnvironment.application, - TvContract.buildChannelUri(testChannelId), - ProgramInfo.create(), - mClock, - TimeUnit.DAYS.toMillis(2)); - shadowOf(getMainLooper()).runToEndOfTasks(); - assertThat(mCallback.programUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS)) - .isTrue(); - programList = mProgramDataManager.getPrograms(testChannelId, mClock.currentTimeMillis()); - assertThat(lastProgramEndTime) - .isLessThan(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); - mCallback.reset(); - mProgramDataManager.setPauseProgramUpdate(true); - ProgramUtils.populatePrograms( - RuntimeEnvironment.application, - TvContract.buildChannelUri(testChannelId), - ProgramInfo.create(), - mClock, - TimeUnit.DAYS.toMillis(2)); - shadowOf(getMainLooper()).runToEndOfTasks(); - assertThat(mCallback.programUpdatedLatch.await(FAILURE_TIME_OUT_MS, TimeUnit.MILLISECONDS)) - .isFalse(); - } - - public static void assertProgramEquals( - long expectedStartTime, ProgramInfo expectedInfo, Program actualProgram) { - assertWithMessage("title").that(actualProgram.getTitle()).isEqualTo(expectedInfo.title); - assertWithMessage("episode") - .that(actualProgram.getEpisodeTitle()) - .isEqualTo(expectedInfo.episode); - assertWithMessage("description") - .that(actualProgram.getDescription()) - .isEqualTo(expectedInfo.description); - assertWithMessage("startTime") - .that(actualProgram.getStartTimeUtcMillis()) - .isEqualTo(expectedStartTime); - assertWithMessage("endTime") - .that(actualProgram.getEndTimeUtcMillis()) - .isEqualTo(expectedStartTime + expectedInfo.durationMs); - } - - private static class TestProgramDataManagerCallback implements ProgramDataManager.Callback { - public CountDownLatch programUpdatedLatch = new CountDownLatch(1); - public CountDownLatch channelUpdatedLatch = new CountDownLatch(1); - - @Override - public void onProgramUpdated() { - programUpdatedLatch.countDown(); - } - - @Override - public void onChannelUpdated() { - channelUpdatedLatch.countDown(); - } - - public void reset() { - programUpdatedLatch = new CountDownLatch(1); - channelUpdatedLatch = new CountDownLatch(1); - } - } - - private static 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/robotests/src/com/android/tv/data/ProgramTest.java b/tests/robotests/src/com/android/tv/data/ProgramTest.java deleted file mode 100644 index 407cca97..00000000 --- a/tests/robotests/src/com/android/tv/data/ProgramTest.java +++ /dev/null @@ -1,276 +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 com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth.assertWithMessage; - -import android.media.tv.TvContentRating; -import android.media.tv.TvContract.Programs.Genres; -import android.os.Parcel; - -import com.android.tv.data.api.Program; -import com.android.tv.data.api.Program.CriticScore; -import com.android.tv.testing.TvRobolectricTestRunner; -import com.android.tv.testing.constants.ConfigConstants; - -import com.google.common.collect.ImmutableList; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** Tests for {@link ProgramImpl}. */ -@RunWith(TvRobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -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 ProgramImpl.Builder().build(); - assertWithMessage("isValid").that(program.isValid()).isFalse(); - } - - @Test - public void testNoGenres() { - Program program = new ProgramImpl.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 ProgramImpl.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 ProgramImpl.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 ProgramImpl.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")); - ImmutableList<TvContentRating> ratings = - ImmutableList.of( - TvContentRating.unflattenFromString("1/2/3"), - TvContentRating.unflattenFromString("4/5/6")); - ProgramImpl p = - new ProgramImpl.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); - ProgramImpl r2 = ProgramImpl.fromParcel(p2); - assertThat(r2).isEqualTo(p); - } finally { - p1.recycle(); - p2.recycle(); - } - } - - @Test - public void testParcelableWithCriticScore() { - ProgramImpl program = - new ProgramImpl.Builder() - .setTitle("MyTitle") - .addCriticScore( - new CriticScore( - "default source", "5/10", "http://testurl/testimage.jpg")) - .build(); - Parcel parcel = Parcel.obtain(); - program.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - Program programFromParcel = ProgramImpl.CREATOR.createFromParcel(parcel); - - assertThat(programFromParcel.getCriticScores()).isNotNull(); - assertThat(programFromParcel.getCriticScores().get(0).source).isEqualTo("default source"); - assertThat(programFromParcel.getCriticScores().get(0).score).isEqualTo("5/10"); - assertThat(programFromParcel.getCriticScores().get(0).logoUrl) - .isEqualTo("http://testurl/testimage.jpg"); - } - - @Test - public void getEpisodeContentDescription_blank() { - Program program = new ProgramImpl.Builder().build(); - assertThat(program.getEpisodeContentDescription(RuntimeEnvironment.application)).isNull(); - } - - @Test - public void getEpisodeContentDescription_seasonEpisodeAndTitle() { - Program program = - new ProgramImpl.Builder() - .setSeasonNumber("1") - .setEpisodeNumber("2") - .setEpisodeTitle("The second one") - .build(); - assertThat(program.getEpisodeContentDescription(RuntimeEnvironment.application)) - .isEqualTo("Season 1 Episode 2 The second one"); - } - - @Test - public void getEpisodeContentDescription_EpisodeAndTitle() { - Program program = - new ProgramImpl.Builder() - .setEpisodeNumber("2") - .setEpisodeTitle("The second one") - .build(); - assertThat(program.getEpisodeContentDescription(RuntimeEnvironment.application)) - .isEqualTo("Episode 2 The second one"); - } - - @Test - public void getEpisodeContentDescription_seasonEpisode() { - Program program = - new ProgramImpl.Builder().setSeasonNumber("1").setEpisodeNumber("2").build(); - assertThat(program.getEpisodeContentDescription(RuntimeEnvironment.application)) - .isEqualTo("Season 1 Episode 2 "); - } - - @Test - public void getEpisodeContentDescription_EpisodeTitle() { - Program program = new ProgramImpl.Builder().setEpisodeTitle("The second one").build(); - assertThat(program.getEpisodeContentDescription(RuntimeEnvironment.application)) - .isEqualTo("The second one"); - } - - @Test - public void getEpisodeDisplayTitle_blank() { - Program program = new ProgramImpl.Builder().build(); - assertThat(program.getEpisodeDisplayTitle(RuntimeEnvironment.application)).isNull(); - } - - @Test - public void getEpisodeDisplayTitle_seasonEpisodeAndTitle() { - Program program = - new ProgramImpl.Builder() - .setSeasonNumber("1") - .setEpisodeNumber("2") - .setEpisodeTitle("The second one") - .build(); - assertThat(program.getEpisodeDisplayTitle(RuntimeEnvironment.application)) - .isEqualTo("S1: Ep. 2 The second one"); - } - - @Test - public void getEpisodeDisplayTitle_EpisodeTitle() { - Program program = - new ProgramImpl.Builder() - .setEpisodeNumber("2") - .setEpisodeTitle("The second one") - .build(); - assertThat(program.getEpisodeDisplayTitle(RuntimeEnvironment.application)) - .isEqualTo("Ep. 2 The second one"); - } - - @Test - public void getEpisodeDisplayTitle_seasonEpisode() { - Program program = - new ProgramImpl.Builder().setSeasonNumber("1").setEpisodeNumber("2").build(); - assertThat(program.getEpisodeDisplayTitle(RuntimeEnvironment.application)) - .isEqualTo("S1: Ep. 2 "); - } - - @Test - public void getEpisodeDisplayTitle_episode() { - Program program = new ProgramImpl.Builder().setEpisodeTitle("The second one").build(); - assertThat(program.getEpisodeDisplayTitle(RuntimeEnvironment.application)) - .isEqualTo("The second one"); - } - - private static void assertNullCanonicalGenres(Program program) { - String[] actual = program.getCanonicalGenres(); - assertWithMessage("Expected null canonical genres but was " + Arrays.toString(actual)) - .that(actual) - .isNull(); - } - - private static void assertCanonicalGenres(Program program, String... expected) { - assertWithMessage("canonical genres") - .that(Arrays.asList(program.getCanonicalGenres())) - .isEqualTo(Arrays.asList(expected)); - } - - private static void assertHasGenre(Program program, int genreId, boolean expected) { - assertWithMessage("hasGenre(" + genreId + ")") - .that(program.hasGenre(genreId)) - .isEqualTo(expected); - } -} diff --git a/tests/robotests/src/com/android/tv/data/TvInputNewComparatorTest.java b/tests/robotests/src/com/android/tv/data/TvInputNewComparatorTest.java deleted file mode 100644 index 201fa03d..00000000 --- a/tests/robotests/src/com/android/tv/data/TvInputNewComparatorTest.java +++ /dev/null @@ -1,102 +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 android.content.pm.ResolveInfo; -import android.media.tv.TvInputInfo; -import android.util.Pair; - -import com.android.tv.testing.ComparatorTester; -import com.android.tv.testing.constants.ConfigConstants; -import com.android.tv.testing.utils.TestUtils; -import com.android.tv.util.SetupUtils; -import com.android.tv.util.TvInputManagerHelper; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentMatchers; -import org.mockito.Mockito; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import java.util.Comparator; -import java.util.LinkedHashMap; - -/** Test for {@link TvInputNewComparator} */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class TvInputNewComparatorTest { - @Test - public void testComparator() throws Exception { - LinkedHashMap<String, Pair<Boolean, Boolean>> inputIdToNewInput = new LinkedHashMap<>(); - inputIdToNewInput.put("2_new_input", Pair.create(true, false)); - inputIdToNewInput.put("4_new_input", Pair.create(true, false)); - inputIdToNewInput.put("4_old_input", Pair.create(false, false)); - inputIdToNewInput.put("0_old_input", Pair.create(false, true)); - inputIdToNewInput.put("1_old_input", Pair.create(false, true)); - inputIdToNewInput.put("3_old_input", Pair.create(false, true)); - - SetupUtils setupUtils = Mockito.mock(SetupUtils.class); - Mockito.when(setupUtils.isNewInput(ArgumentMatchers.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(ArgumentMatchers.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()); - } - }); - TvInputNewComparator comparator = new TvInputNewComparator(setupUtils, inputManager); - ComparatorTester comparatorTester = - new ComparatorTester(comparator).permitInconsistencyWithEquals(); - 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); - comparatorTester.addEqualityGroup(info1, info2, info3); - } - comparatorTester.testCompare(); - } -} diff --git a/tests/robotests/src/com/android/tv/data/WatchedHistoryManagerTest.java b/tests/robotests/src/com/android/tv/data/WatchedHistoryManagerTest.java deleted file mode 100644 index 761827a9..00000000 --- a/tests/robotests/src/com/android/tv/data/WatchedHistoryManagerTest.java +++ /dev/null @@ -1,144 +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.google.common.truth.Truth.assertThat; - -import androidx.test.filters.SmallTest; - -import com.android.tv.data.WatchedHistoryManager.WatchedRecord; -import com.android.tv.testing.constants.ConfigConstants; - -import com.google.common.util.concurrent.MoreExecutors; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -import java.util.concurrent.TimeUnit; - -/** Test for {@link WatchedHistoryManagerTest}. */ -@SmallTest -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class WatchedHistoryManagerTest { - // Wait time for expected success. - private static final int MAX_HISTORY_SIZE = 100; - - private WatchedHistoryManager mWatchedHistoryManager; - private TestWatchedHistoryManagerListener mListener; - - @Before - public void setUp() { - mWatchedHistoryManager = - new WatchedHistoryManager( - RuntimeEnvironment.application, - MAX_HISTORY_SIZE, - MoreExecutors.directExecutor()); - mListener = new TestWatchedHistoryManagerListener(); - mWatchedHistoryManager.setListener(mListener); - } - - private void startAndWaitForComplete() { - mWatchedHistoryManager.start(); - assertThat(mListener.mLoadFinished).isTrue(); - } - - @Test - public void testIsLoaded() { - startAndWaitForComplete(); - assertThat(mWatchedHistoryManager.isLoaded()).isTrue(); - } - - @Test - public void testLogChannelViewStop() { - startAndWaitForComplete(); - long fakeId = 100000000; - long time = System.currentTimeMillis(); - long duration = TimeUnit.MINUTES.toMillis(10); - ChannelImpl channel = new ChannelImpl.Builder().setId(fakeId).build(); - mWatchedHistoryManager.logChannelViewStop(channel, time, duration); - - WatchedRecord record = mWatchedHistoryManager.getRecord(0); - WatchedRecord recordFromSharedPreferences = - mWatchedHistoryManager.getRecordFromSharedPreferences(0); - assertThat(fakeId).isEqualTo(record.channelId); - assertThat(time - duration).isEqualTo(record.watchedStartTime); - assertThat(duration).isEqualTo(record.duration); - assertThat(recordFromSharedPreferences).isEqualTo(record); - } - - @Test - public void testCircularHistoryQueue() { - startAndWaitForComplete(); - final long startChannelId = 100000000; - long time = System.currentTimeMillis(); - long duration = TimeUnit.MINUTES.toMillis(10); - - int size = MAX_HISTORY_SIZE * 2; - for (int i = 0; i < size; ++i) { - 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); - 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. - assertThat(mWatchedHistoryManager.getRecordFromSharedPreferences(MAX_HISTORY_SIZE)) - .isEqualTo(mWatchedHistoryManager.getRecordFromSharedPreferences(0)); - } - - @Test - public void testWatchedRecordEquals() { - 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 - public void testEncodeDecodeWatchedRecord() { - long fakeId = 100000000; - long time = System.currentTimeMillis(); - long duration = TimeUnit.MINUTES.toMillis(10); - WatchedRecord record = new WatchedRecord(fakeId, time, duration); - WatchedRecord sameRecord = - mWatchedHistoryManager.decode(mWatchedHistoryManager.encode(record)); - assertThat(sameRecord).isEqualTo(record); - } - - private static final class TestWatchedHistoryManagerListener - implements WatchedHistoryManager.Listener { - boolean mLoadFinished; - - @Override - public void onLoadFinished() { - mLoadFinished = true; - } - - @Override - public void onNewRecordAdded(WatchedRecord watchedRecord) {} - } -} diff --git a/tests/robotests/src/com/android/tv/data/api/ProgramTest.java b/tests/robotests/src/com/android/tv/data/api/ProgramTest.java deleted file mode 100644 index 3b9f062a..00000000 --- a/tests/robotests/src/com/android/tv/data/api/ProgramTest.java +++ /dev/null @@ -1,119 +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.api; - -import static com.google.common.truth.Truth.assertThat; - -import com.android.tv.data.ProgramImpl; -import com.android.tv.testing.constants.ConfigConstants; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -/** Tests for {@link Program}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class ProgramTest { - - private static ProgramImpl createProgramWithStartEndTimes( - long startTimeUtcMillis, long endTimeUtcMillis) { - return new ProgramImpl.Builder() - .setStartTimeUtcMillis(startTimeUtcMillis) - .setEndTimeUtcMillis(endTimeUtcMillis) - .build(); - } - - private static ProgramImpl createProgramWithChannelId(long channelId) { - return new ProgramImpl.Builder().setChannelId(channelId).build(); - } - - private final Program start10end20 = createProgramWithStartEndTimes(10, 20); - private final Program channel1 = createProgramWithChannelId(1); - - @Test - public void sameChannel_nullAlwaysFalse() { - assertThat(Program.sameChannel(null, null)).isFalse(); - assertThat(Program.sameChannel(channel1, null)).isFalse(); - assertThat(Program.sameChannel(null, channel1)).isFalse(); - } - - @Test - public void sameChannel_true() { - assertThat(Program.sameChannel(channel1, channel1)).isTrue(); - assertThat(Program.sameChannel(channel1, createProgramWithChannelId(1))).isTrue(); - } - - @Test - public void sameChannel_false() { - assertThat(Program.sameChannel(channel1, createProgramWithChannelId(2))).isFalse(); - } - - @Test - public void isOverLapping_nullAlwaysFalse() { - assertThat(Program.isOverlapping(null, null)).isFalse(); - assertThat(Program.isOverlapping(start10end20, null)).isFalse(); - assertThat(Program.isOverlapping(null, start10end20)).isFalse(); - } - - @Test - public void isOverLapping_same() { - assertThat(Program.isOverlapping(start10end20, start10end20)).isTrue(); - } - - @Test - public void isOverLapping_endBefore() { - assertThat(Program.isOverlapping(start10end20, createProgramWithStartEndTimes(1, 9))) - .isFalse(); - } - - @Test - public void isOverLapping_endAtStart() { - assertThat(Program.isOverlapping(start10end20, createProgramWithStartEndTimes(1, 10))) - .isFalse(); - } - - @Test - public void isOverLapping_endDuring() { - assertThat(Program.isOverlapping(start10end20, createProgramWithStartEndTimes(1, 11))) - .isTrue(); - } - - @Test - public void isOverLapping_startAfter() { - assertThat(Program.isOverlapping(start10end20, createProgramWithStartEndTimes(21, 30))) - .isFalse(); - } - - @Test - public void isOverLapping_beginAtEnd() { - assertThat(Program.isOverlapping(start10end20, createProgramWithStartEndTimes(20, 30))) - .isFalse(); - } - - @Test - public void isOverLapping_beginBeforeEnd() { - assertThat(Program.isOverlapping(start10end20, createProgramWithStartEndTimes(19, 30))) - .isTrue(); - } - - @Test - public void isOverLapping_inside() { - assertThat(Program.isOverlapping(start10end20, createProgramWithStartEndTimes(11, 19))) - .isTrue(); - } -} diff --git a/tests/robotests/src/com/android/tv/data/epg/EpgFetcherImplTest.java b/tests/robotests/src/com/android/tv/data/epg/EpgFetcherImplTest.java deleted file mode 100644 index 91472d0d..00000000 --- a/tests/robotests/src/com/android/tv/data/epg/EpgFetcherImplTest.java +++ /dev/null @@ -1,313 +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.data.epg; - -/** Tests for {@link EpgFetcher}. */ -import static com.google.common.truth.Truth.assertThat; - -import android.content.ContentResolver; -import android.content.ContentValues; -import android.database.sqlite.SQLiteDatabase; -import android.media.tv.TvContract; - -import androidx.tvprovider.media.tv.Channel; - -import com.android.tv.common.CommonPreferences; -import com.android.tv.common.buildtype.HasBuildType.BuildType; -import com.android.tv.common.flags.impl.DefaultBackendKnobsFlags; -import com.android.tv.common.flags.impl.SettableFlagsModule; -import com.android.tv.common.util.PostalCodeUtils; -import com.android.tv.data.ChannelDataManager; -import com.android.tv.features.TvFeatures; -import com.android.tv.perf.PerformanceMonitor; -import com.android.tv.perf.stub.StubPerformanceMonitor; -import com.android.tv.testing.DbTestingUtils; -import com.android.tv.testing.EpgTestData; -import com.android.tv.testing.FakeEpgReader; -import com.android.tv.testing.FakeTvInputManagerHelper; -import com.android.tv.testing.TestSingletonApp; -import com.android.tv.testing.constants.ConfigConstants; -import com.android.tv.testing.fakes.FakeClock; -import com.android.tv.testing.fakes.FakeTvProvider; -import com.android.tv.testing.robo.ContentProviders; - -import com.google.android.tv.livechannels.epg.provider.EpgContentProvider; -import com.google.android.tv.partner.support.EpgContract; -import com.google.common.collect.ImmutableList; -import com.android.tv.common.flags.proto.TypedFeatures.StringListParam; - -import dagger.Component; -import dagger.Module; -import dagger.android.AndroidInjectionModule; -import dagger.android.AndroidInjector; -import dagger.android.DispatchingAndroidInjector; -import dagger.android.HasAndroidInjector; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.Shadows; -import org.robolectric.android.util.concurrent.RoboExecutorService; -import org.robolectric.annotation.Config; - -import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; - -import javax.inject.Inject; - -/** Tests for {@link EpgFetcherImpl}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK, application = EpgFetcherImplTest.TestApp.class) -public class EpgFetcherImplTest { - - /** TestApp for {@link EpgFetcherImplTest} */ - public static class TestApp extends TestSingletonApp implements HasAndroidInjector { - @Inject DispatchingAndroidInjector<Object> dispatchingAndroidInjector; - - @Override - public void onCreate() { - super.onCreate(); - DaggerEpgFetcherImplTest_TestAppComponent.builder() - .settableFlagsModule(flagsModule) - .build() - .inject(this); - } - - @Override - public AndroidInjector<Object> androidInjector() { - return dispatchingAndroidInjector; - } - } - - /** Component for {@link EpgFetcherImplTest} */ - @Component( - modules = { - AndroidInjectionModule.class, - TestModule.class, - EpgContentProvider.Module.class - }) - interface TestAppComponent extends AndroidInjector<TestApp> {} - - /** Module for {@link EpgFetcherImplTest} */ - @Module(includes = {SettableFlagsModule.class}) - public static class TestModule {} - - private static final String[] PROGRAM_COLUMNS = { - TvContract.Programs.COLUMN_CHANNEL_ID, - TvContract.Programs.COLUMN_TITLE, - TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS, - TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS - }; - - private static final String[] CHANNEL_COLUMNS = { - TvContract.Channels.COLUMN_DISPLAY_NAME, - TvContract.Channels.COLUMN_DISPLAY_NUMBER, - TvContract.Channels.COLUMN_NETWORK_AFFILIATION - }; - - private FakeClock mFakeClock; - private EpgFetcherImpl mEpgFetcher; - private ChannelDataManager mChannelDataManager; - private FakeEpgReader mEpgReader; - private PerformanceMonitor mPerformanceMonitor = new StubPerformanceMonitor(); - private ContentResolver mContentResolver; - private FakeTvProvider mTvProvider; - private EpgContentProvider mEpgProvider; - private EpgContentProvider.EpgDatabaseHelper mDatabaseHelper; - private TestApp mTestApp; - - @Before - public void setup() { - - TvFeatures.CLOUD_EPG_FOR_3RD_PARTY.enableForTest(); - mTestApp = (TestApp) RuntimeEnvironment.application; - Shadows.shadowOf(RuntimeEnvironment.application) - .grantPermissions("com.android.providers.tv.permission.ACCESS_ALL_EPG_DATA"); - mDatabaseHelper = new EpgContentProvider.EpgDatabaseHelper(RuntimeEnvironment.application); - CommonPreferences.initialize(RuntimeEnvironment.application); - PostalCodeUtils.setLastPostalCode(RuntimeEnvironment.application, "90210"); - EpgFetchHelper.setLastLineupId(RuntimeEnvironment.application, "test90210"); - mTvProvider = ContentProviders.register(FakeTvProvider.class, TvContract.AUTHORITY); - mEpgProvider = ContentProviders.register(EpgContentProvider.class, EpgContract.AUTHORITY); - mEpgProvider.setCallingPackage_("com.google.android.tv"); - mFakeClock = FakeClock.createWithCurrentTime(); - FakeTvInputManagerHelper fakeTvInputManagerHelper = - new FakeTvInputManagerHelper(RuntimeEnvironment.application); - mContentResolver = RuntimeEnvironment.application.getContentResolver(); - mChannelDataManager = - new ChannelDataManager( - RuntimeEnvironment.application, - fakeTvInputManagerHelper, - new RoboExecutorService(), - mContentResolver); - fakeTvInputManagerHelper.start(); - mChannelDataManager.start(); - mEpgReader = new FakeEpgReader(mFakeClock); - mEpgFetcher = - new EpgFetcherImpl( - RuntimeEnvironment.application, - new EpgInputWhiteList( - mTestApp.flagsModule.cloudEpgFlags, - mTestApp.flagsModule.legacyFlags), - mChannelDataManager, - mEpgReader, - mPerformanceMonitor, - mFakeClock, - new DefaultBackendKnobsFlags(), - BuildType.NO_JNI_TEST); - EpgTestData.DATA_90210.loadData(mFakeClock, mEpgReader); // This also sets fake clock - EpgFetchHelper.setLastEpgUpdatedTimestamp( - RuntimeEnvironment.application, - mFakeClock.currentTimeMillis() - TimeUnit.DAYS.toMillis(1)); - } - - @After - public void after() { - mChannelDataManager.stop(); - TvFeatures.CLOUD_EPG_FOR_3RD_PARTY.resetForTests(); - } - - @Test - public void fetchImmediately_nochannels() throws ExecutionException, InterruptedException { - EpgFetcherImpl.FetchAsyncTask fetcherTask = mEpgFetcher.createFetchTask(null, null); - fetcherTask.execute(); - - assertThat(fetcherTask.get()).isEqualTo(EpgFetcherImpl.REASON_NO_BUILT_IN_CHANNELS); - List<List<String>> rows = - DbTestingUtils.toList( - mContentResolver.query( - TvContract.Programs.CONTENT_URI, - PROGRAM_COLUMNS, - null, - null, - null)); - assertThat(rows).isEmpty(); - } - - @Test - public void fetchImmediately_testChannel() throws ExecutionException, InterruptedException { - // The channels must be in the app package. - // For this test the package is com.android.tv.data.epg - insertTestChannels( - "com.android.tv.data.epg/.tuner.TunerTvInputService", EpgTestData.CHANNEL_10); - EpgFetcherImpl.FetchAsyncTask fetcherTask = mEpgFetcher.createFetchTask(null, null); - fetcherTask.execute(); - - assertThat(fetcherTask.get()).isNull(); - List<List<String>> rows = - DbTestingUtils.toList( - mContentResolver.query( - TvContract.Programs.CONTENT_URI, - PROGRAM_COLUMNS, - null, - null, - null)); - assertThat(rows) - .containsExactly( - ImmutableList.of("1", "Program 1", "1496358000000", "1496359800000")); - } - - @Test - public void fetchImmediately_epgChannel() throws ExecutionException, InterruptedException { - mTestApp.flagsModule.cloudEpgFlags.setThirdPartyEpgInputCsv("com.example/.Input"); - insertTestChannels("com.example/.Input", EpgTestData.CHANNEL_10, EpgTestData.CHANNEL_11); - createTestEpgInput(); - EpgFetcherImpl.FetchAsyncTask fetcherTask = mEpgFetcher.createFetchTask(null, null); - fetcherTask.execute(); - - assertThat(fetcherTask.get()).isNull(); - List<List<String>> rows = - DbTestingUtils.toList( - mContentResolver.query( - TvContract.Programs.CONTENT_URI, - PROGRAM_COLUMNS, - null, - null, - null)); - assertThat(rows) - .containsExactly( - ImmutableList.of("1", "Program 1", "1496358000000", "1496359800000"), - ImmutableList.of("2", "Program 2", "1496359800000", "1496361600000")); - } - - @Test - public void testUpdateNetworkAffiliation() throws ExecutionException, InterruptedException { - if (!TvFeatures.STORE_NETWORK_AFFILIATION.isEnabled(RuntimeEnvironment.application)) { - return; - } - // set network affiliation to null so that it can be updated later - Channel channel = - new Channel.Builder(EpgTestData.CHANNEL_10).setNetworkAffiliation(null).build(); - // The channels must be in the app package. - // For this test the package is com.android.tv.data.epg - insertTestChannels("com.android.tv.data.epg/.tuner.TunerTvInputService", channel); - - List<List<String>> rows = - DbTestingUtils.toList( - mContentResolver.query( - TvContract.Channels.CONTENT_URI, - CHANNEL_COLUMNS, - null, - null, - null)); - assertThat(rows).containsExactly(ImmutableList.of("Channel TEN", "10", "null")); - EpgFetcherImpl.FetchAsyncTask fetcherTask = mEpgFetcher.createFetchTask(null, null); - fetcherTask.execute(); - - assertThat(fetcherTask.get()).isNull(); - rows = - DbTestingUtils.toList( - mContentResolver.query( - TvContract.Channels.CONTENT_URI, - CHANNEL_COLUMNS, - null, - null, - null)); - // network affiliation should be updated - assertThat(rows) - .containsExactly( - ImmutableList.of("Channel TEN", "10", "Channel 10 Network Affiliation")); - } - - protected void insertTestChannels(String inputId, Channel... channels) { - - for (Channel channel : channels) { - ContentValues values = - new Channel.Builder(channel).setInputId(inputId).build().toContentValues(); - String packageName = inputId.substring(0, inputId.indexOf('/')); - mTvProvider.setCallingPackage(packageName); - mContentResolver.insert(TvContract.Channels.CONTENT_URI, values); - mTvProvider.setCallingPackage("com.android.tv"); - } - } - - private void createTestEpgInput() { - // Use the database helper so we can set the package name. - SQLiteDatabase db = mDatabaseHelper.getWritableDatabase(); - ContentValues values = new ContentValues(); - values.put(EpgContract.EpgInputs.COLUMN_ID, "1"); - values.put(EpgContract.EpgInputs.COLUMN_PACKAGE_NAME, "com.example"); - values.put(EpgContract.EpgInputs.COLUMN_INPUT_ID, "com.example/.Input"); - values.put(EpgContract.EpgInputs.COLUMN_LINEUP_ID, "lineup1"); - long rowId = db.insert("epg_input", null, values); - assertThat(rowId).isEqualTo(1); - } -} diff --git a/tests/robotests/src/com/android/tv/data/epg/EpgInputWhiteListTest.java b/tests/robotests/src/com/android/tv/data/epg/EpgInputWhiteListTest.java deleted file mode 100644 index d989b51f..00000000 --- a/tests/robotests/src/com/android/tv/data/epg/EpgInputWhiteListTest.java +++ /dev/null @@ -1,129 +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.data.epg; - -import static com.google.common.truth.Truth.assertThat; - -import com.android.tv.common.flags.impl.DefaultCloudEpgFlags; -import com.android.tv.common.flags.impl.DefaultLegacyFlags; -import com.android.tv.features.TvFeatures; -import com.android.tv.testing.constants.ConfigConstants; -import com.android.tv.common.flags.proto.TypedFeatures.StringListParam; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -/** Tests for {@link EpgInputWhiteList}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class EpgInputWhiteListTest { - - private EpgInputWhiteList mWhiteList; - private DefaultCloudEpgFlags mCloudEpgFlags; - private DefaultLegacyFlags mLegacyFlags; - - @Before - public void setup() { - TvFeatures.CLOUD_EPG_FOR_3RD_PARTY.enableForTest(); - mCloudEpgFlags = new DefaultCloudEpgFlags(); - mLegacyFlags = DefaultLegacyFlags.DEFAULT; - mWhiteList = new EpgInputWhiteList(mCloudEpgFlags, mLegacyFlags); - } - - @After - public void after() { - TvFeatures.CLOUD_EPG_FOR_3RD_PARTY.resetForTests(); - } - - @Test - public void isInputWhiteListed_noRemoteConfig() { - assertThat(mWhiteList.isInputWhiteListed("com.example/.Foo")).isFalse(); - } - - @Test - public void isInputWhiteListed_noMatch() { - mCloudEpgFlags.setThirdPartyEpgInputCsv("com.example/.Bar"); - assertThat(mWhiteList.isInputWhiteListed("com.example/.Foo")).isFalse(); - } - - @Test - public void isInputWhiteListed_match() { - mCloudEpgFlags.setThirdPartyEpgInputCsv("com.example/.Foo"); - assertThat(mWhiteList.isInputWhiteListed("com.example/.Foo")).isTrue(); - } - - @Test - public void isInputWhiteListed_matchWithTwo() { - mCloudEpgFlags.setThirdPartyEpgInputCsv("com.example/.Foo,com.example/.Bar"); - assertThat(mWhiteList.isInputWhiteListed("com.example/.Foo")).isTrue(); - } - - @Test - public void toInputSet_withNewLine() { - assertThat(EpgInputWhiteList.toInputSet("com.example/.Foo,\ncom.example/.Bar\n")) - .containsExactly("com.example/.Foo", "com.example/.Bar"); - } - - @Test - public void toInputSet_withWhiteSpace() { - assertThat(EpgInputWhiteList.toInputSet("com.example/.Foo , com.example/.Bar ")) - .containsExactly("com.example/.Foo", "com.example/.Bar"); - } - - @Test - public void isPackageWhiteListed_noRemoteConfig() { - assertThat(mWhiteList.isPackageWhiteListed("com.example")).isFalse(); - } - - @Test - public void isPackageWhiteListed_noMatch() { - mCloudEpgFlags.setThirdPartyEpgInputCsv("com.example/.Bar"); - assertThat(mWhiteList.isPackageWhiteListed("com.other")).isFalse(); - } - - @Test - public void isPackageWhiteListed_match() { - mCloudEpgFlags.setThirdPartyEpgInputCsv("com.example/.Foo"); - assertThat(mWhiteList.isPackageWhiteListed("com.example")).isTrue(); - } - - @Test - public void isPackageWhiteListed_matchWithTwo() { - mCloudEpgFlags.setThirdPartyEpgInputCsv("com.example/.Foo,com.example/.Bar"); - assertThat(mWhiteList.isPackageWhiteListed("com.example")).isTrue(); - } - - @Test - public void isPackageWhiteListed_matchBadInput() { - mCloudEpgFlags.setThirdPartyEpgInputCsv("com.example.Foo"); - assertThat(mWhiteList.isPackageWhiteListed("com.example")).isFalse(); - } - - @Test - public void isPackageWhiteListed_tunerInput() { - EpgInputWhiteList whiteList = - new EpgInputWhiteList(new DefaultCloudEpgFlags(), DefaultLegacyFlags.DEFAULT); - assertThat( - whiteList.isInputWhiteListed( - "com.google.android.tv/.tuner.tvinput.TunerTvInputService")) - .isTrue(); - } -} diff --git a/tests/robotests/src/com/android/tv/dvr/BaseDvrDataManagerTest.java b/tests/robotests/src/com/android/tv/dvr/BaseDvrDataManagerTest.java deleted file mode 100644 index 8c3baadb..00000000 --- a/tests/robotests/src/com/android/tv/dvr/BaseDvrDataManagerTest.java +++ /dev/null @@ -1,96 +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 android.os.Build; -import android.support.annotation.NonNull; - -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.TestSingletonApp; -import com.android.tv.testing.dvr.DvrDataManagerInMemoryImpl; -import com.android.tv.testing.dvr.RecordingTestUtils; -import com.android.tv.testing.fakes.FakeClock; - -import com.google.common.truth.Truth; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -import java.util.List; -import java.util.concurrent.TimeUnit; - -/** Tests for {@link BaseDvrDataManager} using {@link DvrDataManagerInMemoryImpl}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = Build.VERSION_CODES.N, application = TestSingletonApp.class) -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(RuntimeEnvironment.application, mFakeClock); - } - - @After - public void tearDown() { - mDvrFeature.resetForTests(); - } - - @Test - public void testGetNonStartedScheduledRecordings() { - ScheduledRecording recording = - mDvrDataManager.addScheduledRecordingInternal( - createNewScheduledRecordingStartingNow()); - List<ScheduledRecording> result = mDvrDataManager.getNonStartedScheduledRecordings(); - Truth.assertThat(result).containsExactly(recording); - } - - @Test - public void testGetNonStartedScheduledRecordings_past() { - mDvrDataManager.addScheduledRecordingInternal(createNewScheduledRecordingStartingNow()); - mFakeClock.increment(TimeUnit.MINUTES, 6); - List<ScheduledRecording> result = mDvrDataManager.getNonStartedScheduledRecordings(); - Truth.assertThat(result).isEmpty(); - } - - @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/robotests/src/com/android/tv/dvr/DvrDataManagerImplTest.java b/tests/robotests/src/com/android/tv/dvr/DvrDataManagerImplTest.java deleted file mode 100644 index 528e0233..00000000 --- a/tests/robotests/src/com/android/tv/dvr/DvrDataManagerImplTest.java +++ /dev/null @@ -1,85 +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.google.common.truth.Truth.assertWithMessage; - -import android.os.Build; - -import com.android.tv.dvr.data.ScheduledRecording; -import com.android.tv.testing.TestSingletonApp; -import com.android.tv.testing.dvr.RecordingTestUtils; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import java.util.ArrayList; -import java.util.List; - -/** Tests for {@link DvrDataManagerImpl} */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = Build.VERSION_CODES.N, application = TestSingletonApp.class) -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) { - assertWithMessage("getNextScheduledStartTimeAfter()") - .that(DvrDataManagerImpl.getNextStartTimeAfter(scheduledRecordings, startTime)) - .isEqualTo(expected); - } -} diff --git a/tests/robotests/src/com/android/tv/dvr/DvrScheduleManagerTest.java b/tests/robotests/src/com/android/tv/dvr/DvrScheduleManagerTest.java deleted file mode 100644 index bd4113e4..00000000 --- a/tests/robotests/src/com/android/tv/dvr/DvrScheduleManagerTest.java +++ /dev/null @@ -1,883 +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 com.google.common.truth.Truth.assertThat; - -import static org.junit.Assert.fail; - -import android.os.Build; -import android.util.Range; - -import com.android.tv.dvr.DvrScheduleManager.ConflictInfo; -import com.android.tv.dvr.data.ScheduledRecording; -import com.android.tv.testing.TestSingletonApp; -import com.android.tv.testing.dvr.RecordingTestUtils; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -/** Tests for {@link DvrScheduleManager} */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = Build.VERSION_CODES.N, application = TestSingletonApp.class) -public class DvrScheduleManagerTest { - private static final String INPUT_ID = "input_id"; - - @Test - public void testGetConflictingSchedules_emptySchedule() { - List<ScheduledRecording> schedules = new ArrayList<>(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 1)).isEmpty(); - } - - @Test - public void testGetConflictingSchedules_noConflict() { - long priority = 0; - long channelId = 0; - List<ScheduledRecording> schedules = new ArrayList<>(); - - schedules.add( - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 200L)); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 1)).isEmpty(); - - schedules.add( - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 100L)); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 2)).isEmpty(); - - schedules.add( - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 100L, 200L)); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 2)).isEmpty(); - - schedules.add( - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 100L)); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 3)).isEmpty(); - - schedules.add( - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 100L, 200L)); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 3)).isEmpty(); - } - - @Test - public void testGetConflictingSchedules_noTuner() { - long priority = 0; - long channelId = 0; - List<ScheduledRecording> schedules = new ArrayList<>(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 0)).isEmpty(); - - schedules.add( - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 200L)); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 0)).isEqualTo(schedules); - schedules.add( - 0, - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 100L)); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 0)).isEqualTo(schedules); - } - - @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); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 1)).isEmpty(); - - ScheduledRecording r2 = - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 100L); - schedules.add(r2); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 1)) - .containsExactly(r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 2)).isEmpty(); - - ScheduledRecording r3 = - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 100L, 200L); - schedules.add(r3); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 1)) - .containsExactly(r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 2)).isEmpty(); - - ScheduledRecording r4 = - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 100L); - schedules.add(r4); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 1)) - .containsExactly(r2, r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 2)) - .containsExactly(r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 3)).isEmpty(); - - ScheduledRecording r5 = - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 100L, 200L); - schedules.add(r5); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 1)) - .containsExactly(r3, r2, r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 2)) - .containsExactly(r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 3)).isEmpty(); - - ScheduledRecording r6 = - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 10L, 90L); - schedules.add(r6); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 1)) - .containsExactly(r4, r3, r2, r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 2)) - .containsExactly(r2, r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 3)) - .containsExactly(r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 4)).isEmpty(); - - ScheduledRecording r7 = - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 110L, 190L); - schedules.add(r7); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 1)) - .containsExactly(r5, r4, r3, r2, r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 2)) - .containsExactly(r3, r2, r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 3)) - .containsExactly(r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 4)).isEmpty(); - - ScheduledRecording r8 = - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 50L, 150L); - schedules.add(r8); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 1)) - .containsExactly(r7, r6, r5, r4, r3, r2, r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 2)) - .containsExactly(r5, r4, r3, r2, r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 3)) - .containsExactly(r3, r2, r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 4)) - .containsExactly(r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 5)).isEmpty(); - } - - @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); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 1)).isEmpty(); - - ScheduledRecording r2 = - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 100L); - schedules.add(r2); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 1)) - .containsExactly(r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 2)).isEmpty(); - - ScheduledRecording r3 = - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 100L, 200L); - schedules.add(r3); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 1)) - .containsExactly(r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 2)).isEmpty(); - } - - @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); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 1)).isEmpty(); - - ScheduledRecording r2 = - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 100L); - schedules.add(0, r2); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 1)) - .containsExactly(r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 2)).isEmpty(); - - ScheduledRecording r3 = - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 100L, 200L); - schedules.add(0, r3); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 1)) - .containsExactly(r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 2)).isEmpty(); - - ScheduledRecording r4 = - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 0L, 100L); - schedules.add(0, r4); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 1)) - .containsExactly(r2, r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 2)) - .containsExactly(r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 3)).isEmpty(); - - ScheduledRecording r5 = - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 100L, 200L); - schedules.add(0, r5); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 1)) - .containsExactly(r3, r2, r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 2)) - .containsExactly(r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 3)).isEmpty(); - - ScheduledRecording r6 = - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 10L, 90L); - schedules.add(0, r6); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 1)) - .containsExactly(r4, r3, r2, r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 2)) - .containsExactly(r2, r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 3)) - .containsExactly(r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 4)).isEmpty(); - - ScheduledRecording r7 = - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 110L, 190L); - schedules.add(0, r7); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 1)) - .containsExactly(r5, r4, r3, r2, r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 2)) - .containsExactly(r3, r2, r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 3)) - .containsExactly(r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 4)).isEmpty(); - - ScheduledRecording r8 = - RecordingTestUtils.createTestRecordingWithPriorityAndPeriod( - ++channelId, ++priority, 50L, 150L); - schedules.add(0, r8); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 1)) - .containsExactly(r7, r6, r5, r4, r3, r2, r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 2)) - .containsExactly(r5, r4, r3, r2, r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 3)) - .containsExactly(r3, r2, r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 4)) - .containsExactly(r1) - .inOrder(); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 5)).isEmpty(); - } - - @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); - assertThat( - DvrScheduleManager.getConflictingSchedules( - schedules, 1, Collections.singletonList(new Range<>(10L, 20L)))) - .containsExactly(r1) - .inOrder(); - assertThat( - DvrScheduleManager.getConflictingSchedules( - schedules, 1, Collections.singletonList(new Range<>(110L, 120L)))) - .containsExactly(r1) - .inOrder(); - } - - @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); - assertThat( - DvrScheduleManager.getConflictingSchedules( - schedules, 1, Collections.singletonList(new Range<>(10L, 20L)))) - .containsExactly(r1) - .inOrder(); - assertThat( - DvrScheduleManager.getConflictingSchedules( - schedules, 1, Collections.singletonList(new Range<>(110L, 120L)))) - .containsExactly(r1) - .inOrder(); - } - - @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); - assertThat( - DvrScheduleManager.getConflictingSchedules( - schedules, 1, Collections.singletonList(new Range<>(10L, 20L)))) - .containsExactly(r1) - .inOrder(); - assertThat( - DvrScheduleManager.getConflictingSchedules( - schedules, 1, Collections.singletonList(new Range<>(110L, 120L)))) - .containsExactly(r2) - .inOrder(); - assertThat( - DvrScheduleManager.getConflictingSchedules( - schedules, 1, Collections.singletonList(new Range<>(50L, 150L)))) - .containsExactly(r2, r1) - .inOrder(); - List<Range<Long>> ranges = new ArrayList<>(); - ranges.add(new Range<>(10L, 20L)); - ranges.add(new Range<>(110L, 120L)); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 1, ranges)) - .containsExactly(r2, r1) - .inOrder(); - } - - @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); - assertThat( - DvrScheduleManager.getConflictingSchedules( - Collections.singletonList( - ScheduledRecording.builder(INPUT_ID, ++channelId, 10L, 20L) - .setPriority(++priority) - .build()), - schedules, - 1)) - .containsExactly(r2, r1) - .inOrder(); - assertThat( - DvrScheduleManager.getConflictingSchedules( - Collections.singletonList( - ScheduledRecording.builder( - INPUT_ID, ++channelId, 110L, 120L) - .setPriority(++priority) - .build()), - schedules, - 1)) - .containsExactly(r1) - .inOrder(); - } - - @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); - assertThat( - DvrScheduleManager.getConflictingSchedules( - Collections.singletonList( - ScheduledRecording.builder(INPUT_ID, ++channelId, 10L, 20L) - .setPriority(++priority) - .build()), - schedules, - 1)) - .containsExactly(r1) - .inOrder(); - assertThat( - DvrScheduleManager.getConflictingSchedules( - Collections.singletonList( - ScheduledRecording.builder( - INPUT_ID, ++channelId, 110L, 120L) - .setPriority(++priority) - .build()), - schedules, - 1)) - .containsExactly(r2, r1) - .inOrder(); - } - - @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. - assertThat( - DvrScheduleManager.getConflictingSchedules( - Collections.singletonList( - ScheduledRecording.builder( - INPUT_ID, ++channelId, 200L, 300L) - .setPriority(0) - .build()), - schedules, - 1)) - .containsExactly(r1) - .inOrder(); - } - - @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)); - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 3)).isEmpty(); - } - - @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. - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 1)) - .containsExactly(r2) - .inOrder(); - } - - @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. - assertThat(DvrScheduleManager.getConflictingSchedules(schedules, 1)) - .containsExactly(r2, r1) - .inOrder(); - } - - @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)); - assertThat( - DvrScheduleManager.getConflictingSchedulesForTune( - INPUT_ID, channelId, 0L, priority + 1, schedules, 1)) - .isEmpty(); - } - - @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)); - assertThat( - DvrScheduleManager.getConflictingSchedulesForTune( - INPUT_ID, channelId + 1, 0L, priority + 1, schedules, 1)) - .containsExactly(schedules.get(0)) - .inOrder(); - } - - @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); - assertThat( - DvrScheduleManager.getConflictingSchedulesForWatching( - INPUT_ID, channelToWatch, 0L, ++priority, schedules, 3)) - .isEmpty(); - assertThat( - DvrScheduleManager.getConflictingSchedulesForWatching( - INPUT_ID, channelToWatch, 0L, ++priority, schedules, 2)) - .containsExactly(r1) - .inOrder(); - } - - @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); - assertThat( - DvrScheduleManager.getConflictingSchedulesForWatching( - INPUT_ID, channelToWatch, 0L, ++priority, schedules, 2)) - .isEmpty(); - assertThat( - DvrScheduleManager.getConflictingSchedulesForWatching( - INPUT_ID, channelToWatch, 0L, ++priority, schedules, 1)) - .containsExactly(r2) - .inOrder(); - } - - @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); - assertThat( - DvrScheduleManager.getConflictingSchedulesForWatching( - INPUT_ID, channelToWatch, 0L, ++priority, schedules, 2)) - .isEmpty(); - assertThat( - DvrScheduleManager.getConflictingSchedulesForWatching( - INPUT_ID, channelToWatch, 0L, ++priority, schedules, 1)) - .containsExactly(r1) - .inOrder(); - } - - @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); - assertThat( - DvrScheduleManager.getConflictingSchedulesForWatching( - INPUT_ID, channelToWatch, 0L, ++priority, schedules, 3)) - .containsExactly(r2) - .inOrder(); - assertThat( - DvrScheduleManager.getConflictingSchedulesForWatching( - INPUT_ID, channelToWatch, 0L, ++priority, schedules, 2)) - .containsExactly(r2) - .inOrder(); - assertThat( - DvrScheduleManager.getConflictingSchedulesForWatching( - INPUT_ID, channelToWatch, 0L, ++priority, schedules, 1)) - .containsExactly(r2, r1) - .inOrder(); - } - - @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); - assertThat( - DvrScheduleManager.getConflictingSchedulesForWatching( - INPUT_ID, channelToWatch, 0L, ++priority, schedules, 3)) - .containsExactly(r1) - .inOrder(); - assertThat( - DvrScheduleManager.getConflictingSchedulesForWatching( - INPUT_ID, channelToWatch, 0L, ++priority, schedules, 2)) - .containsExactly(r1) - .inOrder(); - assertThat( - DvrScheduleManager.getConflictingSchedulesForWatching( - INPUT_ID, channelToWatch, 0L, ++priority, schedules, 1)) - .containsExactly(r3, r1) - .inOrder(); - } - - @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"); - } -} diff --git a/tests/robotests/src/com/android/tv/dvr/ScheduledRecordingTest.java b/tests/robotests/src/com/android/tv/dvr/ScheduledRecordingTest.java deleted file mode 100644 index 4c845c49..00000000 --- a/tests/robotests/src/com/android/tv/dvr/ScheduledRecordingTest.java +++ /dev/null @@ -1,126 +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 com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth.assertWithMessage; - -import android.os.Build; -import android.util.Range; - -import com.android.tv.data.ChannelImpl; -import com.android.tv.data.ProgramImpl; -import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; -import com.android.tv.dvr.data.ScheduledRecording; -import com.android.tv.testing.TestSingletonApp; -import com.android.tv.testing.dvr.RecordingTestUtils; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -/** Tests for {@link ScheduledRecordingTest} */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = Build.VERSION_CODES.N, application = TestSingletonApp.class) -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 ChannelImpl.Builder().build(); - Program p = new ProgramImpl.Builder().build(); - ScheduledRecording actual = - ScheduledRecording.builder(INPUT_ID, p).setChannelId(c.getId()).build(); - assertWithMessage("type").that(actual.getType()).isEqualTo(ScheduledRecording.TYPE_PROGRAM); - } - - @Test - public void testBuildTime() { - ScheduledRecording actual = - createTestRecordingWithIdAndPeriod(1, INPUT_ID, CHANNEL_ID, 10L, 20L); - assertWithMessage("type").that(actual.getType()).isEqualTo(ScheduledRecording.TYPE_TIMED); - } - - @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 - assertThat(sortByPriority(c, b, a)).containsExactly(a, b, c).inOrder(); - - // make A preferred over B - a = ScheduledRecording.buildFrom(a).setPriority(b.getPriority() + 2).build(); - assertThat(sortByPriority(a, b, c)).containsExactly(b, c, a).inOrder(); - } - - 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) { - assertWithMessage("isOverlapping(Range(" + lower + "," + upper + "), recording " + r) - .that(r.isOverLapping(new Range<>(lower, upper))) - .isEqualTo(expected); - } -} diff --git a/tests/robotests/src/com/android/tv/dvr/data/SeriesRecordingTest.java b/tests/robotests/src/com/android/tv/dvr/data/SeriesRecordingTest.java deleted file mode 100644 index a0b79cef..00000000 --- a/tests/robotests/src/com/android/tv/dvr/data/SeriesRecordingTest.java +++ /dev/null @@ -1,147 +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 com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth.assertWithMessage; - -import android.os.Parcel; - -import com.android.tv.data.ProgramImpl; -import com.android.tv.data.api.Program; -import com.android.tv.testing.constants.ConfigConstants; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -/** Tests for {@link SeriesRecording}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -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 ProgramImpl mBaseProgram = - new ProgramImpl.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); - assertThat(r2).isEqualTo(r1); - } finally { - p1.recycle(); - p2.recycle(); - } - } - - @Test - public void testDoesProgramMatch_simpleMatch() { - assertDoesProgramMatch(mBaseProgram, mBaseSeriesRecording, true); - } - - @Test - public void testDoesProgramMatch_differentSeriesId() { - Program program = - new ProgramImpl.Builder(mBaseProgram).setSeriesId(OTHER_SERIES_ID).build(); - assertDoesProgramMatch(program, mBaseSeriesRecording, false); - } - - @Test - public void testDoesProgramMatch_differentChannel() { - Program program = - new ProgramImpl.Builder(mBaseProgram).setChannelId(OTHER_CHANNEL_ID).build(); - assertDoesProgramMatch(program, mBaseSeriesRecording, false); - } - - @Test - public void testDoesProgramMatch_startFromSeason2() { - ProgramImpl program = mBaseProgram; - assertDoesProgramMatch(program, mSeriesRecordingSeason2, true); - program = new ProgramImpl.Builder(program).setSeasonNumber("1").build(); - assertDoesProgramMatch(program, mSeriesRecordingSeason2, false); - program = new ProgramImpl.Builder(program).setSeasonNumber("2").build(); - assertDoesProgramMatch(program, mSeriesRecordingSeason2, true); - program = new ProgramImpl.Builder(program).setSeasonNumber("3").build(); - assertDoesProgramMatch(program, mSeriesRecordingSeason2, true); - } - - @Test - public void testDoesProgramMatch_startFromSeason2episode5() { - ProgramImpl program = mBaseProgram; - assertDoesProgramMatch(program, mSeriesRecordingSeason2Episode5, true); - program = new ProgramImpl.Builder(program).setSeasonNumber("2").build(); - assertDoesProgramMatch(program, mSeriesRecordingSeason2Episode5, true); - program = new ProgramImpl.Builder(program).setEpisodeNumber("4").build(); - assertDoesProgramMatch(program, mSeriesRecordingSeason2Episode5, false); - program = new ProgramImpl.Builder(program).setEpisodeNumber("5").build(); - assertDoesProgramMatch(program, mSeriesRecordingSeason2Episode5, true); - program = new ProgramImpl.Builder(program).setEpisodeNumber("6").build(); - assertDoesProgramMatch(program, mSeriesRecordingSeason2Episode5, true); - program = - new ProgramImpl.Builder(program).setSeasonNumber("3").setEpisodeNumber("1").build(); - assertDoesProgramMatch(program, mSeriesRecordingSeason2Episode5, true); - } - - private void assertDoesProgramMatch( - Program p, SeriesRecording seriesRecording, boolean expected) { - assertWithMessage(seriesRecording + " doesProgramMatch " + p) - .that(seriesRecording.matchProgram(p)) - .isEqualTo(expected); - } -} diff --git a/tests/robotests/src/com/android/tv/dvr/provider/DvrDbSyncTest.java b/tests/robotests/src/com/android/tv/dvr/provider/DvrDbSyncTest.java deleted file mode 100644 index 5f8db0ad..00000000 --- a/tests/robotests/src/com/android/tv/dvr/provider/DvrDbSyncTest.java +++ /dev/null @@ -1,178 +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.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -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 com.android.tv.data.ChannelDataManager; -import com.android.tv.data.ProgramImpl; -import com.android.tv.data.api.Program; -import com.android.tv.dvr.DvrManager; -import com.android.tv.dvr.WritableDvrDataManager; -import com.android.tv.dvr.data.ScheduledRecording; -import com.android.tv.dvr.data.SeriesRecording; -import com.android.tv.dvr.recorder.SeriesRecordingScheduler; -import com.android.tv.testing.TestSingletonApp; -import com.android.tv.testing.constants.ConfigConstants; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.android.util.concurrent.RoboExecutorService; -import org.robolectric.annotation.Config; - -/** Tests for {@link com.android.tv.dvr.DvrScheduleManager} */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK, application = TestSingletonApp.class) -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 ProgramImpl baseProgram; - private ProgramImpl baseSeriesProgram; - private ScheduledRecording baseSchedule; - private ScheduledRecording baseSeriesSchedule; - - private DvrDbSync mDbSync; - @Mock private DvrManager mDvrManager; - @Mock private WritableDvrDataManager mDataManager; - @Mock private ChannelDataManager mChannelDataManager; - @Mock private SeriesRecordingScheduler mSeriesRecordingScheduler; - - @Before - public void setUp() { - // TODO(b/69843199): make these static finals - baseProgram = - new ProgramImpl.Builder() - .setId(BASE_PROGRAM_ID) - .setStartTimeUtcMillis(BASE_START_TIME_MS) - .setEndTimeUtcMillis(BASE_END_TIME_MS) - .build(); - baseSeriesProgram = - new ProgramImpl.Builder() - .setId(BASE_PROGRAM_ID) - .setStartTimeUtcMillis(BASE_START_TIME_MS) - .setEndTimeUtcMillis(BASE_END_TIME_MS) - .setSeasonNumber(BASE_SEASON_NUMBER) - .setEpisodeNumber(BASE_EPISODE_NUMBER) - .build(); - baseSchedule = ScheduledRecording.builder(INPUT_ID, baseProgram).build(); - baseSeriesSchedule = ScheduledRecording.builder(INPUT_ID, baseSeriesProgram).build(); - - MockitoAnnotations.initMocks(this); - when(mChannelDataManager.isDbLoadFinished()).thenReturn(true); - when(mDvrManager.addSeriesRecording(any(), any(), anyInt())) - .thenReturn(SeriesRecording.builder(INPUT_ID, baseProgram).build()); - mDbSync = - new DvrDbSync( - RuntimeEnvironment.application.getApplicationContext(), - mDataManager, - mChannelDataManager, - mDvrManager, - mSeriesRecordingScheduler, - new RoboExecutorService()); - } - - @Test - public void testHandleUpdateProgram_null() { - addSchedule(BASE_PROGRAM_ID, baseSchedule); - mDbSync.handleUpdateProgram(null, BASE_PROGRAM_ID); - verify(mDataManager).removeScheduledRecording(baseSchedule); - } - - @Test - public void testHandleUpdateProgram_changeTimeNotStarted() { - addSchedule(BASE_PROGRAM_ID, baseSchedule); - long startTimeMs = BASE_START_TIME_MS + 1; - long endTimeMs = BASE_END_TIME_MS + 1; - Program program = - new ProgramImpl.Builder(baseProgram) - .setStartTimeUtcMillis(startTimeMs) - .setEndTimeUtcMillis(endTimeMs) - .build(); - mDbSync.handleUpdateProgram(program, BASE_PROGRAM_ID); - assertUpdateScheduleCalled(program); - } - - @Test - public void testHandleUpdateProgram_changeTimeInProgressNotCalled() { - addSchedule( - BASE_PROGRAM_ID, - ScheduledRecording.buildFrom(baseSchedule) - .setState(ScheduledRecording.STATE_RECORDING_IN_PROGRESS) - .build()); - long startTimeMs = BASE_START_TIME_MS + 1; - Program program = - new ProgramImpl.Builder(baseProgram).setStartTimeUtcMillis(startTimeMs).build(); - mDbSync.handleUpdateProgram(program, BASE_PROGRAM_ID); - verify(mDataManager, never()).updateScheduledRecording(any()); - } - - @Test - public void testHandleUpdateProgram_changeSeason() { - addSchedule(BASE_PROGRAM_ID, baseSeriesSchedule); - String seasonNumber = BASE_SEASON_NUMBER + "1"; - String episodeNumber = BASE_EPISODE_NUMBER + "1"; - Program program = - new ProgramImpl.Builder(baseSeriesProgram) - .setSeasonNumber(seasonNumber) - .setEpisodeNumber(episodeNumber) - .build(); - mDbSync.handleUpdateProgram(program, BASE_PROGRAM_ID); - assertUpdateScheduleCalled(program); - } - - @Test - public void testHandleUpdateProgram_finished() { - addSchedule( - BASE_PROGRAM_ID, - ScheduledRecording.buildFrom(baseSeriesSchedule) - .setState(ScheduledRecording.STATE_RECORDING_FINISHED) - .build()); - String seasonNumber = BASE_SEASON_NUMBER + "1"; - String episodeNumber = BASE_EPISODE_NUMBER + "1"; - Program program = - new ProgramImpl.Builder(baseSeriesProgram) - .setSeasonNumber(seasonNumber) - .setEpisodeNumber(episodeNumber) - .build(); - mDbSync.handleUpdateProgram(program, BASE_PROGRAM_ID); - verify(mDataManager, never()).updateScheduledRecording(any()); - } - - 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/robotests/src/com/android/tv/dvr/provider/EpisodicProgramLoadTaskTest.java b/tests/robotests/src/com/android/tv/dvr/provider/EpisodicProgramLoadTaskTest.java deleted file mode 100644 index 3597342d..00000000 --- a/tests/robotests/src/com/android/tv/dvr/provider/EpisodicProgramLoadTaskTest.java +++ /dev/null @@ -1,92 +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 com.google.common.truth.Truth.assertThat; - -import android.os.Build.VERSION_CODES; - -import com.android.tv.dvr.data.SeasonEpisodeNumber; -import com.android.tv.testing.TestSingletonApp; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import java.util.ArrayList; -import java.util.List; - -/** Tests for {@link EpisodicProgramLoadTask} */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = VERSION_CODES.N, application = TestSingletonApp.class) -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); - assertThat(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); - assertThat(seasonEpisodeNumbers) - .doesNotContain( - new SeasonEpisodeNumber( - SERIES_RECORDING_ID2, SEASON_NUMBER1, EPISODE_NUMBER1)); - assertThat(seasonEpisodeNumbers) - .doesNotContain( - new SeasonEpisodeNumber( - SERIES_RECORDING_ID1, SEASON_NUMBER2, EPISODE_NUMBER1)); - assertThat(seasonEpisodeNumbers) - .doesNotContain( - 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); - assertThat(seasonEpisodeNumbers) - .doesNotContain( - new SeasonEpisodeNumber(SERIES_RECORDING_ID1, null, EPISODE_NUMBER1)); - assertThat(seasonEpisodeNumbers) - .doesNotContain( - new SeasonEpisodeNumber(SERIES_RECORDING_ID1, SEASON_NUMBER1, null)); - assertThat(seasonEpisodeNumbers) - .doesNotContain(new SeasonEpisodeNumber(SERIES_RECORDING_ID1, null, null)); - } -} diff --git a/tests/robotests/src/com/android/tv/dvr/recorder/InputTaskSchedulerTest.java b/tests/robotests/src/com/android/tv/dvr/recorder/InputTaskSchedulerTest.java deleted file mode 100644 index 40069f62..00000000 --- a/tests/robotests/src/com/android/tv/dvr/recorder/InputTaskSchedulerTest.java +++ /dev/null @@ -1,259 +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 org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.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 com.android.tv.InputSessionManager; -import com.android.tv.common.util.Clock; -import com.android.tv.data.ChannelDataManager; -import com.android.tv.data.api.Channel; -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.TestSingletonApp; -import com.android.tv.testing.dvr.RecordingTestUtils; -import com.android.tv.testing.fakes.FakeClock; -import com.android.tv.testing.utils.TestUtils; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; - -/** Tests for {@link InputTaskScheduler}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = Build.VERSION_CODES.N, application = TestSingletonApp.class) -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( - RuntimeEnvironment.application, - 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), - eq( - ScheduledRecording - .FAILED_REASON_PROGRAM_ENDED_BEFORE_RECORDING_STARTED)); - } - - @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/robotests/src/com/android/tv/dvr/recorder/RecordingTaskTest.java b/tests/robotests/src/com/android/tv/dvr/recorder/RecordingTaskTest.java deleted file mode 100644 index 55ee270c..00000000 --- a/tests/robotests/src/com/android/tv/dvr/recorder/RecordingTaskTest.java +++ /dev/null @@ -1,164 +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 org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.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 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.ChannelImpl; -import com.android.tv.data.api.Channel; -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.TestSingletonApp; -import com.android.tv.testing.dvr.DvrDataManagerInMemoryImpl; -import com.android.tv.testing.dvr.RecordingTestUtils; -import com.android.tv.testing.fakes.FakeClock; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -import java.util.concurrent.TimeUnit; - -/** Tests for {@link RecordingTask}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = Build.VERSION_CODES.N, application = TestSingletonApp.class) -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(RuntimeEnvironment.application, 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(any(), 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 ChannelImpl.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.sendEmptyMessageDelayed(anyInt(), 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( - RuntimeEnvironment.application, - 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; - } -} diff --git a/tests/robotests/src/com/android/tv/dvr/recorder/ScheduledProgramReaperTest.java b/tests/robotests/src/com/android/tv/dvr/recorder/ScheduledProgramReaperTest.java deleted file mode 100644 index 945c031f..00000000 --- a/tests/robotests/src/com/android/tv/dvr/recorder/ScheduledProgramReaperTest.java +++ /dev/null @@ -1,136 +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 com.google.common.truth.Truth.assertThat; - -import static org.junit.Assert.assertTrue; - -import android.os.Build; - -import com.android.tv.common.feature.CommonFeatures; -import com.android.tv.common.feature.TestableFeature; -import com.android.tv.common.util.CommonUtils; -import com.android.tv.dvr.DvrManager; -import com.android.tv.dvr.data.ScheduledRecording; -import com.android.tv.testing.TestSingletonApp; -import com.android.tv.testing.dvr.DvrDataManagerInMemoryImpl; -import com.android.tv.testing.dvr.RecordingTestUtils; -import com.android.tv.testing.fakes.FakeClock; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -import java.util.concurrent.TimeUnit; - -/** Tests for {@link ScheduledProgramReaper}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = Build.VERSION_CODES.N, application = TestSingletonApp.class) -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(RuntimeEnvironment.application, 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(); - assertThat(mDvrDataManager.getAllScheduledRecordings()).containsExactly(recording); - mReaper.run(); - assertThat(mDvrDataManager.getAllScheduledRecordings()).containsExactly(recording); - } - - @Test - public void testRun_oneRecordingsStarted() { - ScheduledRecording recording = addNewScheduledRecordingForTomorrow(); - assertThat(mDvrDataManager.getAllScheduledRecordings()).containsExactly(recording); - mFakeClock.increment(TimeUnit.DAYS); - mReaper.run(); - assertThat(mDvrDataManager.getAllScheduledRecordings()).containsExactly(recording); - } - - @Test - public void testRun_oneRecordingsFinished() { - ScheduledRecording recording = addNewScheduledRecordingForTomorrow(); - assertThat(mDvrDataManager.getAllScheduledRecordings()).containsExactly(recording); - mFakeClock.increment(TimeUnit.DAYS); - mFakeClock.increment(TimeUnit.MINUTES, 2); - mReaper.run(); - assertThat(mDvrDataManager.getAllScheduledRecordings()).containsExactly(recording); - } - - @Test - public void testRun_oneRecordingsExpired() { - ScheduledRecording recording = addNewScheduledRecordingForTomorrow(); - assertThat(mDvrDataManager.getAllScheduledRecordings()).containsExactly(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 " - + CommonUtils.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/robotests/src/com/android/tv/dvr/recorder/SchedulerTest.java b/tests/robotests/src/com/android/tv/dvr/recorder/SchedulerTest.java deleted file mode 100644 index d2bd2ff1..00000000 --- a/tests/robotests/src/com/android/tv/dvr/recorder/SchedulerTest.java +++ /dev/null @@ -1,136 +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 org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.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 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.DvrManager; -import com.android.tv.dvr.data.ScheduledRecording; -import com.android.tv.testing.TestSingletonApp; -import com.android.tv.testing.dvr.DvrDataManagerInMemoryImpl; -import com.android.tv.testing.dvr.RecordingTestUtils; -import com.android.tv.testing.fakes.FakeClock; -import com.android.tv.util.TvInputManagerHelper; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -import java.util.concurrent.TimeUnit; - -/** Tests for {@link RecordingScheduler}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = Build.VERSION_CODES.N, application = TestSingletonApp.class) -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(RuntimeEnvironment.application, mFakeClock); - Mockito.when(mChannelDataManager.isDbLoadFinished()).thenReturn(true); - mScheduler = - new RecordingScheduler( - Looper.myLooper(), - mDvrManager, - mSessionManager, - mDataManager, - mChannelDataManager, - mInputManager, - RuntimeEnvironment.application, - 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)); - } -} diff --git a/tests/robotests/src/com/android/tv/dvr/recorder/SeriesRecordingSchedulerTest.java b/tests/robotests/src/com/android/tv/dvr/recorder/SeriesRecordingSchedulerTest.java deleted file mode 100644 index dc4f4db4..00000000 --- a/tests/robotests/src/com/android/tv/dvr/recorder/SeriesRecordingSchedulerTest.java +++ /dev/null @@ -1,154 +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 com.google.common.truth.Truth.assertThat; - -import android.os.Build; -import android.util.LongSparseArray; - -import com.android.tv.common.feature.CommonFeatures; -import com.android.tv.common.feature.TestableFeature; -import com.android.tv.data.ProgramImpl; -import com.android.tv.data.api.Program; -import com.android.tv.dvr.data.SeriesRecording; -import com.android.tv.testing.TestSingletonApp; -import com.android.tv.testing.dvr.DvrDataManagerInMemoryImpl; -import com.android.tv.testing.fakes.FakeClock; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** Tests for {@link SeriesRecordingScheduler} */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = Build.VERSION_CODES.N, application = TestSingletonApp.class) -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 ProgramImpl mBaseProgram = - new ProgramImpl.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(RuntimeEnvironment.application, 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 ProgramImpl.Builder(mBaseProgram) - .setSeasonNumber(SEASON_NUMBER1) - .setEpisodeNumber(EPISODE_NUMBER1) - .build(); - programs.add(program1); - Program program2 = - new ProgramImpl.Builder(mBaseProgram) - .setSeasonNumber(SEASON_NUMBER2) - .setEpisodeNumber(EPISODE_NUMBER2) - .build(); - programs.add(program2); - LongSparseArray<List<Program>> result = - SeriesRecordingScheduler.pickOneProgramPerEpisode( - mDataManager, Collections.singletonList(seriesRecording), programs); - assertThat(result.get(SERIES_RECORDING_ID1)).containsExactly(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<>(); - ProgramImpl program1 = - new ProgramImpl.Builder(mBaseProgram) - .setSeasonNumber(SEASON_NUMBER1) - .setEpisodeNumber(EPISODE_NUMBER1) - .setStartTimeUtcMillis(0) - .build(); - programs.add(program1); - Program program2 = new ProgramImpl.Builder(program1).setStartTimeUtcMillis(1).build(); - programs.add(program2); - Program program3 = - new ProgramImpl.Builder(mBaseProgram) - .setSeasonNumber(SEASON_NUMBER2) - .setEpisodeNumber(EPISODE_NUMBER2) - .build(); - programs.add(program3); - Program program4 = new ProgramImpl.Builder(program1).setStartTimeUtcMillis(1).build(); - programs.add(program4); - LongSparseArray<List<Program>> result = - SeriesRecordingScheduler.pickOneProgramPerEpisode( - mDataManager, Collections.singletonList(seriesRecording), programs); - assertThat(result.get(SERIES_RECORDING_ID1)).containsExactly(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 ProgramImpl.Builder(mBaseProgram).setStartTimeUtcMillis(0).build(); - programs.add(program1); - Program program2 = new ProgramImpl.Builder(mBaseProgram).setStartTimeUtcMillis(1).build(); - programs.add(program2); - LongSparseArray<List<Program>> result = - SeriesRecordingScheduler.pickOneProgramPerEpisode( - mDataManager, Collections.singletonList(seriesRecording), programs); - assertThat(result.get(SERIES_RECORDING_ID1)).containsExactly(program1, program2); - } -} diff --git a/tests/robotests/src/com/android/tv/dvr/ui/SortedArrayAdapterTest.java b/tests/robotests/src/com/android/tv/dvr/ui/SortedArrayAdapterTest.java deleted file mode 100644 index aa90d413..00000000 --- a/tests/robotests/src/com/android/tv/dvr/ui/SortedArrayAdapterTest.java +++ /dev/null @@ -1,255 +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 static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth.assertWithMessage; - -import androidx.leanback.widget.ClassPresenterSelector; -import androidx.leanback.widget.ObjectAdapter; - -import com.android.tv.testing.constants.ConfigConstants; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import java.util.Arrays; -import java.util.Comparator; -import java.util.Objects; - -/** Tests for {@link SortedArrayAdapter}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class SortedArrayAdapterTest { - 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(); - assertThat(mAdapter.size()).isEqualTo(1); - assertThat(mAdapter.get(0)).isEqualTo(P2); - } - - @Test - public void testExtraItem() { - mAdapter = new TestSortedArrayAdapter(Integer.MAX_VALUE, EXTRA); - mAdapter.setInitialItems(Arrays.asList(P1, P2)); - assertNotEmpty(); - assertThat(mAdapter.size()).isEqualTo(3); - assertThat(mAdapter.get(0)).isEqualTo(P2); - assertThat(mAdapter.get(2)).isEqualTo(EXTRA); - mAdapter.remove(P2); - mAdapter.remove(P1); - assertThat(mAdapter.size()).isEqualTo(1); - assertThat(mAdapter.get(0)).isEqualTo(EXTRA); - } - - @Test - public void testExtraItemWithMaxCount() { - mAdapter = new TestSortedArrayAdapter(1, EXTRA); - mAdapter.setInitialItems(Arrays.asList(P1, P2)); - assertNotEmpty(); - assertThat(mAdapter.size()).isEqualTo(2); - assertThat(mAdapter.get(0)).isEqualTo(P2); - assertThat(mAdapter.get(1)).isEqualTo(EXTRA); - mAdapter.remove(P2); - assertThat(mAdapter.size()).isEqualTo(1); - assertThat(mAdapter.get(0)).isEqualTo(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() { - assertWithMessage("empty").that(mAdapter.isEmpty()).isTrue(); - } - - private void assertNotEmpty() { - assertWithMessage("empty").that(mAdapter.isEmpty()).isFalse(); - } - - private static void assertContentsInOrder(ObjectAdapter adapter, Object... contents) { - int ex = contents.length; - assertWithMessage("size").that(adapter.size()).isEqualTo(ex); - for (int i = 0; i < ex; i++) { - assertWithMessage("element " + 1).that(adapter.get(i)).isEqualTo(contents[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; - } - } -} diff --git a/tests/robotests/src/com/android/tv/dvr/ui/browse/DvrBrowseFragmentTest.java b/tests/robotests/src/com/android/tv/dvr/ui/browse/DvrBrowseFragmentTest.java deleted file mode 100644 index 25a4256f..00000000 --- a/tests/robotests/src/com/android/tv/dvr/ui/browse/DvrBrowseFragmentTest.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.dvr.ui.browse; - -import com.android.tv.dvr.data.RecordedProgram; -import com.android.tv.dvr.data.ScheduledRecording; -import com.android.tv.testing.ComparatorTester; -import com.android.tv.testing.constants.ConfigConstants; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -/** Test for {@link DvrBrowseFragment}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class DvrBrowseFragmentTest { - - @Test - public void testRecentRowComparator_scheduledRecordings_latestFirst() { - ComparatorTester comparatorTester = - new ComparatorTester(DvrBrowseFragment.RECENT_ROW_COMPARATOR) - .permitInconsistencyWithEquals(); - // priority (highest to lowest): start time, class, ID - comparatorTester.addEqualityGroup(buildRecordedProgramForTest(2, 120, 150)); - comparatorTester.addEqualityGroup(buildRecordedProgramForTest(1, 120, 150)); - comparatorTester.addEqualityGroup(buildScheduledRecordingForTest(1, 120, 150)); - comparatorTester.addEqualityGroup(buildScheduledRecordingForTest(2, 120, 150)); - comparatorTester.addEqualityGroup(buildRecordedProgramForTest(4, 100, 200)); - comparatorTester.addEqualityGroup(buildRecordedProgramForTest(3, 100, 200)); - comparatorTester.addEqualityGroup(buildScheduledRecordingForTest(3, 100, 200)); - comparatorTester.addEqualityGroup(buildScheduledRecordingForTest(4, 100, 200)); - comparatorTester.addEqualityGroup(new Object(), Long.valueOf("777"), "string"); - comparatorTester.testCompare(); - } - - private ScheduledRecording buildScheduledRecordingForTest(long id, long start, long end) { - return ScheduledRecording.builder("test", 1, start, end).setId(id).build(); - } - - private RecordedProgram buildRecordedProgramForTest(long id, long start, long end) { - return RecordedProgram.builder() - .setId(id) - .setInputId("test") - .setStartTimeUtcMillis(start) - .setEndTimeUtcMillis(end) - .build(); - } -} diff --git a/tests/robotests/src/com/android/tv/dvr/ui/list/DvrHistoryRowAdapterTest.java b/tests/robotests/src/com/android/tv/dvr/ui/list/DvrHistoryRowAdapterTest.java deleted file mode 100644 index 5d247e37..00000000 --- a/tests/robotests/src/com/android/tv/dvr/ui/list/DvrHistoryRowAdapterTest.java +++ /dev/null @@ -1,278 +0,0 @@ -/* - * 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.dvr.ui.list; - -import static com.google.common.truth.Truth.assertThat; - -import androidx.leanback.widget.ClassPresenterSelector; - -import com.android.tv.common.flags.impl.DefaultUiFlags; -import com.android.tv.common.util.Clock; -import com.android.tv.dvr.data.RecordedProgram; -import com.android.tv.dvr.data.ScheduledRecording; -import com.android.tv.testing.TvRobolectricTestRunner; -import com.android.tv.testing.TestSingletonApp; -import com.android.tv.testing.constants.ConfigConstants; -import com.android.tv.testing.dvr.DvrDataManagerInMemoryImpl; -import com.android.tv.testing.fakes.FakeClock; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -import java.util.ArrayList; -import java.util.List; - -/** Test for {@link DvrHistoryRowAdapter}. */ -@RunWith(TvRobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK, application = TestSingletonApp.class) -public class DvrHistoryRowAdapterTest { - - private static final ScheduledRecording SCHEDULE_1 = - buildScheduledRecordingForTest( - 2, - 1518249600000L, // 2/10/2018 0:00 PST - 1518250600000L, - ScheduledRecording.STATE_RECORDING_FAILED); - private static final ScheduledRecording SCHEDULE_1_COPY = - buildScheduledRecordingForTest( - 3, - 1518249600000L, // 2/10/2018 0:00 PST - 1518250600000L, - ScheduledRecording.STATE_RECORDING_FAILED); - private static final ScheduledRecording SCHEDULE_2 = - buildScheduledRecordingForTest( - 4, - 1518595200000L, // 2/14/2018 0:00 PST - 1518596200000L, - ScheduledRecording.STATE_RECORDING_FAILED); - private static final ScheduledRecording SCHEDULE_2_COPY = - buildScheduledRecordingForTest( - 5, - 1518595200000L, // 2/14/2018 0:00 PST - 1518596200000L, - ScheduledRecording.STATE_RECORDING_FAILED); - - private static RecordedProgram sRecordedProgram; - private static final long FAKE_CURRENT_TIME = 1518764400000L; // 2/15/2018 23:00 PST - - private DvrHistoryRowAdapter mDvrHistoryRowAdapter; - private DvrDataManagerInMemoryImpl mDvrDataManager; - - @Before - public void setUp() { - sRecordedProgram = - buildRecordedProgramForTest( - 6, - 1518249600000L, // 2/10/2018 0:00 PST - 1518250600000L); - - TestSingletonApp app = (TestSingletonApp) RuntimeEnvironment.application; - Clock clock = FakeClock.createWithTime(FAKE_CURRENT_TIME); - - mDvrDataManager = new DvrDataManagerInMemoryImpl(app, clock); - app.mDvrDataManager = mDvrDataManager; - // keep the original IDs instead of creating a new one. - mDvrDataManager.addScheduledRecording( - true, SCHEDULE_1, SCHEDULE_1_COPY, SCHEDULE_2, SCHEDULE_2_COPY); - - ClassPresenterSelector presenterSelector = new ClassPresenterSelector(); - mDvrHistoryRowAdapter = - new DvrHistoryRowAdapter( - RuntimeEnvironment.application, - presenterSelector, - clock, - mDvrDataManager, - new DefaultUiFlags()); - } - - @Test - public void testStart() { - mDvrHistoryRowAdapter.start(); - assertInitialState(); - } - - @Test - public void testOnScheduledRecordingAdded_existingHeader() { - mDvrHistoryRowAdapter.start(); - ScheduledRecording toAdd = - buildScheduledRecordingForTest( - 6, - 1518249600000L, // 2/10/2018 - 1518250600000L, - ScheduledRecording.STATE_RECORDING_FAILED); - mDvrHistoryRowAdapter.onScheduledRecordingAdded(toAdd); - - // a schedule row is added - assertThat(mDvrHistoryRowAdapter.size()).isEqualTo(7); - assertThat(getHeaderItemCounts()).containsExactly(2, 3).inOrder(); - assertThat(getScheduleSize()).isEqualTo(5); - } - - @Test - public void testOnScheduledRecordingAdded_newHeader_addOldest() { - mDvrHistoryRowAdapter.start(); - ScheduledRecording toAdd = - buildScheduledRecordingForTest( - 6, - 1518159600000L, // 2/8/2018 PST - 1518160600000L, - ScheduledRecording.STATE_RECORDING_FAILED); - mDvrHistoryRowAdapter.onScheduledRecordingAdded(toAdd); - - // a header row and a schedule row are added - assertThat(mDvrHistoryRowAdapter.size()).isEqualTo(8); - assertThat(getHeaderItemCounts()).containsExactly(2, 2, 1).inOrder(); - assertThat(getScheduleSize()).isEqualTo(5); - } - - @Test - public void testOnScheduledRecordingAdded_newHeader_addBetween() { - mDvrHistoryRowAdapter.start(); - ScheduledRecording toAdd = - buildScheduledRecordingForTest( - 6, - 1518336000000L, // 2/11/2018 PST - 1518337000000L, - ScheduledRecording.STATE_RECORDING_FAILED); - mDvrHistoryRowAdapter.onScheduledRecordingAdded(toAdd); - - // a header row and a schedule row are added - assertThat(mDvrHistoryRowAdapter.size()).isEqualTo(8); - assertThat(getHeaderItemCounts()).containsExactly(2, 1, 2).inOrder(); - assertThat(getScheduleSize()).isEqualTo(5); - } - - @Test - public void testOnScheduledRecordingAdded_newHeader_addNewest() { - mDvrHistoryRowAdapter.start(); - ScheduledRecording toAdd = - buildScheduledRecordingForTest( - 6, - 1518681600000L, // 2/15/2018 PST - 1518682600000L, - ScheduledRecording.STATE_RECORDING_FAILED); - mDvrHistoryRowAdapter.onScheduledRecordingAdded(toAdd); - - // a header row and a schedule row are added - assertThat(mDvrHistoryRowAdapter.size()).isEqualTo(8); - assertThat(getHeaderItemCounts()).containsExactly(1, 2, 2).inOrder(); - assertThat(getScheduleSize()).isEqualTo(5); - } - - @Test - public void testOnScheduledRecordingAdded_addRecordedProgram() { - mDvrHistoryRowAdapter.start(); - mDvrHistoryRowAdapter.onScheduledRecordingAdded(sRecordedProgram); - - // a header row and a schedule row are added - assertThat(mDvrHistoryRowAdapter.size()).isEqualTo(7); - assertThat(getHeaderItemCounts()).containsExactly(2, 3).inOrder(); - assertThat(getScheduleSize()).isEqualTo(5); - } - - @Test - public void testOnScheduledRecordingRemoved_keepHeader() { - mDvrHistoryRowAdapter.start(); - mDvrHistoryRowAdapter.onScheduledRecordingRemoved(SCHEDULE_1); - - // a schedule row is removed - assertThat(mDvrHistoryRowAdapter.size()).isEqualTo(5); - assertThat(getHeaderItemCounts()).containsExactly(2, 1).inOrder(); - assertThat(getScheduleSize()).isEqualTo(3); - } - - @Test - public void testOnScheduledRecordingRemoved_removeHeader() { - mDvrHistoryRowAdapter.start(); - mDvrHistoryRowAdapter.onScheduledRecordingRemoved(SCHEDULE_1); - mDvrHistoryRowAdapter.onScheduledRecordingRemoved(SCHEDULE_1_COPY); - - // a header row and a schedule row are removed - assertThat(mDvrHistoryRowAdapter.size()).isEqualTo(3); - assertThat(getHeaderItemCounts()).containsExactly(2).inOrder(); - assertThat(getScheduleSize()).isEqualTo(2); - } - - @Test - public void testOnScheduledRecordingRemoved_removeRecordedProgram() { - mDvrDataManager.addRecordedProgramInternal(sRecordedProgram, true); - mDvrHistoryRowAdapter.start(); - assertThat(mDvrHistoryRowAdapter.size()).isEqualTo(7); - assertThat(getHeaderItemCounts()).containsExactly(2, 3).inOrder(); - assertThat(getScheduleSize()).isEqualTo(5); - - mDvrHistoryRowAdapter.onScheduledRecordingRemoved(sRecordedProgram); - - // a schedule row is removed - assertThat(mDvrHistoryRowAdapter.size()).isEqualTo(6); - assertThat(getHeaderItemCounts()).containsExactly(2, 2); - assertThat(getScheduleSize()).isEqualTo(4); - } - - private static ScheduledRecording buildScheduledRecordingForTest( - long id, long startTime, long endTime, int state) { - ScheduledRecording.Builder builder = - ScheduledRecording.builder("fakeInput", 1, startTime, endTime) - .setId(id) - .setState(state); - return builder.build(); - } - - private static RecordedProgram buildRecordedProgramForTest( - long id, long startTime, long endTime) { - RecordedProgram.Builder builder = - RecordedProgram.builder() - .setId(id) - .setInputId("fakeInput") - .setStartTimeUtcMillis(startTime) - .setEndTimeUtcMillis(endTime); - return builder.build(); - } - - private int getScheduleSize() { - int size = 0; - for (int i = 0; i < mDvrHistoryRowAdapter.size(); i++) { - Object item = mDvrHistoryRowAdapter.get(i); - if (item instanceof ScheduleRow && ((ScheduleRow) item).getSchedule() != null) { - size++; - } - } - return size; - } - - private List<Integer> getHeaderItemCounts() { - List<Integer> result = new ArrayList<>(); - for (int i = 0; i < mDvrHistoryRowAdapter.size(); i++) { - Object item = mDvrHistoryRowAdapter.get(i); - if (item instanceof SchedulesHeaderRow) { - int count = ((SchedulesHeaderRow) item).getItemCount(); - assertThat(count).isAtLeast(1); - result.add(count); - } - } - return result; - } - - private void assertInitialState() { - assertThat(mDvrHistoryRowAdapter.size()).isEqualTo(6); - assertThat(getHeaderItemCounts()).containsExactly(2, 2).inOrder(); - assertThat(getScheduleSize()).isEqualTo(4); - } -} diff --git a/tests/robotests/src/com/android/tv/dvr/ui/playback/DvrPlayerTest.java b/tests/robotests/src/com/android/tv/dvr/ui/playback/DvrPlayerTest.java deleted file mode 100644 index ad0ddf35..00000000 --- a/tests/robotests/src/com/android/tv/dvr/ui/playback/DvrPlayerTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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.dvr.ui.playback; - -import static com.google.common.truth.Truth.assertThat; - -import android.media.tv.TvTrackInfo; - -import com.android.tv.ShadowTvView; -import com.android.tv.testing.TestSingletonApp; -import com.android.tv.testing.constants.ConfigConstants; -import com.android.tv.ui.AppLayerTvView; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; -import org.robolectric.shadow.api.Shadow; - -import java.util.ArrayList; -import java.util.Collections; - -/** Test for {@link DvrPlayer}. */ -@RunWith(RobolectricTestRunner.class) -@Config( - sdk = ConfigConstants.SDK, - application = TestSingletonApp.class, - shadows = {ShadowTvView.class}) -public class DvrPlayerTest { - private ShadowTvView mShadowTvView; - private DvrPlayer mDvrPlayer; - - @Before - public void setUp() { - AppLayerTvView tvView = new AppLayerTvView(RuntimeEnvironment.application); - mShadowTvView = Shadow.extract(tvView); - mDvrPlayer = new DvrPlayer(tvView, RuntimeEnvironment.application); - } - - @Test - public void testGetAudioTracks_null() { - mShadowTvView.mTracks.put(TvTrackInfo.TYPE_AUDIO, null); - assertThat(mDvrPlayer.getAudioTracks()).isNotNull(); - assertThat(mDvrPlayer.getAudioTracks()).isEmpty(); - } - - @Test - public void testGetAudioTracks_empty() { - mShadowTvView.mTracks.put(TvTrackInfo.TYPE_AUDIO, new ArrayList<>()); - assertThat(mDvrPlayer.getAudioTracks()).isNotNull(); - assertThat(mDvrPlayer.getAudioTracks()).isEmpty(); - } - - @Test - public void testGetAudioTracks_nonEmpty() { - TvTrackInfo info = new TvTrackInfo.Builder(TvTrackInfo.TYPE_AUDIO, "fake id").build(); - mShadowTvView.mTracks.put(TvTrackInfo.TYPE_AUDIO, Collections.singletonList(info)); - assertThat(mDvrPlayer.getAudioTracks()).containsExactly(info); - } -} diff --git a/tests/robotests/src/com/android/tv/guide/ProgramItemViewTest.java b/tests/robotests/src/com/android/tv/guide/ProgramItemViewTest.java deleted file mode 100644 index e7850c1b..00000000 --- a/tests/robotests/src/com/android/tv/guide/ProgramItemViewTest.java +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright (C) 2019 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.guide; - -import static com.google.android.libraries.testing.truth.TextViewSubject.assertThat; - -import android.support.annotation.NonNull; -import android.view.LayoutInflater; - -import com.android.tv.R; -import com.android.tv.common.util.Clock; -import com.android.tv.data.ChannelDataManager; -import com.android.tv.data.ProgramImpl; -import com.android.tv.dvr.DvrManager; -import com.android.tv.dvr.data.ScheduledRecording; -import com.android.tv.guide.ProgramItemViewTest.TestApp; -import com.android.tv.guide.ProgramItemViewTest.TestModule.Contributes; -import com.android.tv.guide.ProgramManager.TableEntry; -import com.android.tv.testing.TestSingletonApp; -import com.android.tv.testing.constants.ConfigConstants; -import com.android.tv.testing.robo.RobotTestAppHelper; -import com.android.tv.testing.testdata.TestData; - -import dagger.Component; -import dagger.Module; -import dagger.Provides; -import dagger.android.AndroidInjectionModule; -import dagger.android.AndroidInjector; -import dagger.android.ContributesAndroidInjector; -import dagger.android.DispatchingAndroidInjector; -import dagger.android.HasAndroidInjector; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -import java.time.Duration; -import java.util.concurrent.TimeUnit; - -import javax.inject.Inject; - -/** Tests for {@link ProgramItemView}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK, application = TestApp.class) -public class ProgramItemViewTest { - - /** TestApp for {@link ProgramItemViewTest} */ - public static class TestApp extends TestSingletonApp implements HasAndroidInjector { - @Inject DispatchingAndroidInjector<Object> dispatchingAndroidInjector; - - @Override - public void onCreate() { - super.onCreate(); - DaggerProgramItemViewTest_TestAppComponent.builder() - .testModule(new TestModule(this)) - .build() - .inject(this); - } - - @Override - public AndroidInjector<Object> androidInjector() { - return dispatchingAndroidInjector; - } - } - - /** Component for {@link ProgramItemViewTest} */ - @Component( - modules = { - AndroidInjectionModule.class, - TestModule.class, - }) - interface TestAppComponent extends AndroidInjector<TestApp> {} - - /** Module for {@link ProgramItemViewTest} */ - @Module(includes = {Contributes.class}) - public static class TestModule { - - @Module() - public abstract static class Contributes { - @ContributesAndroidInjector - abstract ProgramItemView contributesProgramItemView(); - } - - private final TestApp myTestApp; - - TestModule(TestApp test) { - myTestApp = test; - } - - @Provides - ChannelDataManager providesChannelDataManager() { - return myTestApp.getChannelDataManager(); - } - - @Provides - Clock provideClock() { - return myTestApp.getClock(); - } - } - - // Thursday, June 1, 2017 1:00:00 PM GMT-07:00 - private final long testStartTimeMs = 1496347200000L; - - // Thursday, June 1, 2017 8:00:00 PM GMT-07:00 - private final long eightPM = 1496372400000L; - private final ProgramImpl baseProgram = - new ProgramImpl.Builder() - .setChannelId(1) - .setStartTimeUtcMillis(eightPM) - .setEndTimeUtcMillis(eightPM + Duration.ofHours(1).toMillis()) - .build(); - - private ProgramItemView mPprogramItemView; - - @Mock DvrManager dvrManager; - - @Before - public void setup() { - MockitoAnnotations.initMocks(this); - TestSingletonApp app = (TestSingletonApp) RuntimeEnvironment.application; - app.dvrManager = dvrManager; - app.fakeClock.setBootTimeMillis(testStartTimeMs + TimeUnit.HOURS.toMillis(-12)); - app.fakeClock.setCurrentTimeMillis(testStartTimeMs); - RobotTestAppHelper.loadTestData(app, TestData.DEFAULT_10_CHANNELS); - mPprogramItemView = - (ProgramItemView) - LayoutInflater.from(RuntimeEnvironment.application) - .inflate(R.layout.program_guide_table_item, null); - GuideUtils.setWidthPerHour(100); - } - - @Test - public void initialState() { - assertThat(mPprogramItemView).hasEmptyText(); - } - - @Test - public void setValue_noProgram() { - TableEntry tableEntry = create30MinuteTableEntryFor(null, null, false); - mPprogramItemView.setValues(null, tableEntry, 0, 0, 0, "a gap"); - assertThat(mPprogramItemView).hasText("a gap"); - assertThat(mPprogramItemView).hasContentDescription("1 a gap 8:00 – 9:00 PM"); - } - - @Test - public void setValue_programNoTitle() { - ProgramImpl program = new ProgramImpl.Builder(baseProgram).build(); - TableEntry tableEntry = create30MinuteTableEntryFor(program, null, false); - mPprogramItemView.setValues(null, tableEntry, 0, 0, 0, "a gap"); - assertThat(mPprogramItemView).hasText("No information"); - assertThat(mPprogramItemView).hasContentDescription("1 No information 8:00 – 9:00 PM"); - } - - @Test - public void setValue_programTitle() { - ProgramImpl program = - new ProgramImpl.Builder(baseProgram).setTitle("A good program").build(); - TableEntry tableEntry = create30MinuteTableEntryFor(program, null, false); - mPprogramItemView.setValues(null, tableEntry, 0, 0, 0, "a gap"); - assertThat(mPprogramItemView).hasText("A good program"); - assertThat(mPprogramItemView).hasContentDescription("1 A good program 8:00 – 9:00 PM"); - } - - @Test - public void setValue_programDescriptionBlocked() { - ProgramImpl program = - new ProgramImpl.Builder(baseProgram) - .setTitle("A good program") - .setDescription("Naughty") - .build(); - TableEntry tableEntry = create30MinuteTableEntryFor(program, null, true); - mPprogramItemView.setValues(null, tableEntry, 0, 0, 0, "a gap"); - assertThat(mPprogramItemView).hasText("A good program"); - assertThat(mPprogramItemView) - .hasContentDescription("1 A good program 8:00 – 9:00 PM This program is blocked"); - } - - @Test - public void setValue_programEpisode() { - ProgramImpl program = - new ProgramImpl.Builder(baseProgram) - .setTitle("A good program") - .setEpisodeTitle("The one with an episode") - .build(); - TableEntry tableEntry = create30MinuteTableEntryFor(program, null, false); - mPprogramItemView.setValues(null, tableEntry, 0, 0, 0, "a gap"); - assertThat(mPprogramItemView).hasText("A good program\n\u200DThe one with an episode"); - assertThat(mPprogramItemView) - .hasContentDescription("1 A good program 8:00 – 9:00 PM The one with an episode"); - } - - @Test - public void setValue_programEpisodeAndDescrition() { - ProgramImpl program = - new ProgramImpl.Builder(baseProgram) - .setTitle("A good program") - .setEpisodeTitle("The one with an episode") - .setDescription("Jack and Jill go up a hill") - .build(); - TableEntry tableEntry = create30MinuteTableEntryFor(program, null, false); - mPprogramItemView.setValues(null, tableEntry, 0, 0, 0, "a gap"); - assertThat(mPprogramItemView).hasText("A good program\n\u200DThe one with an episode"); - assertThat(mPprogramItemView) - .hasContentDescription( - "1 A good program 8:00 – 9:00 PM The one with an episode" - + " Jack and Jill go up a hill"); - } - - @Test - public void setValue_scheduledConflict() { - ProgramImpl program = - new ProgramImpl.Builder(baseProgram).setTitle("A good program").build(); - ScheduledRecording scheduledRecording = - ScheduledRecording.builder("input1", program).build(); - TableEntry tableEntry = create30MinuteTableEntryFor(program, scheduledRecording, false); - Mockito.when(dvrManager.isConflicting(scheduledRecording)).thenReturn(true); - - mPprogramItemView.setValues(null, tableEntry, 0, 0, 0, "a gap"); - assertThat(mPprogramItemView).hasText("A good program"); - assertThat(mPprogramItemView) - .hasContentDescription("1 A good program 8:00 – 9:00 PM Recording conflict"); - } - - @Test - public void setValue_scheduled() { - ProgramImpl program = - new ProgramImpl.Builder(baseProgram).setTitle("A good program").build(); - ScheduledRecording scheduledRecording = - ScheduledRecording.builder("input1", program) - .setState(ScheduledRecording.STATE_RECORDING_NOT_STARTED) - .build(); - TableEntry tableEntry = create30MinuteTableEntryFor(program, scheduledRecording, false); - Mockito.when(dvrManager.isConflicting(scheduledRecording)).thenReturn(false); - - mPprogramItemView.setValues(null, tableEntry, 0, 0, 0, "a gap"); - assertThat(mPprogramItemView).hasText("A good program"); - assertThat(mPprogramItemView) - .hasContentDescription("1 A good program 8:00 – 9:00 PM Recording scheduled"); - } - - @Test - public void setValue_recordingInProgress() { - ProgramImpl program = - new ProgramImpl.Builder(baseProgram).setTitle("A good program").build(); - ScheduledRecording scheduledRecording = - ScheduledRecording.builder("input1", program) - .setState(ScheduledRecording.STATE_RECORDING_IN_PROGRESS) - .build(); - TableEntry tableEntry = create30MinuteTableEntryFor(program, scheduledRecording, false); - Mockito.when(dvrManager.isConflicting(scheduledRecording)).thenReturn(false); - - mPprogramItemView.setValues(null, tableEntry, 0, 0, 0, "a gap"); - assertThat(mPprogramItemView).hasText("A good program"); - assertThat(mPprogramItemView) - .hasContentDescription("1 A good program 8:00 – 9:00 PM Recording"); - } - - @NonNull - private TableEntry create30MinuteTableEntryFor( - ProgramImpl program, ScheduledRecording scheduledRecording, boolean isBlocked) { - return ProgramManager.createTableEntryForTest( - 1, - program, - scheduledRecording, - eightPM, - eightPM + Duration.ofHours(1).toMillis(), - isBlocked); - } -} diff --git a/tests/robotests/src/com/android/tv/guide/ProgramTableAdapterTest.java b/tests/robotests/src/com/android/tv/guide/ProgramTableAdapterTest.java deleted file mode 100644 index 52072748..00000000 --- a/tests/robotests/src/com/android/tv/guide/ProgramTableAdapterTest.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2019 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.guide; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.anyLong; - -import com.android.tv.common.flags.impl.DefaultUiFlags; -import com.android.tv.data.ChannelDataManager; -import com.android.tv.data.ChannelImpl; -import com.android.tv.data.GenreItems; -import com.android.tv.data.ProgramDataManager; -import com.android.tv.data.ProgramImpl; -import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; -import com.android.tv.testing.TestSingletonApp; -import com.android.tv.testing.constants.ConfigConstants; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; - -/** Tests for {@link ProgramTableAdapter}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK, application = TestSingletonApp.class) -public class ProgramTableAdapterTest { - - @Mock private ProgramGuide mProgramGuide; - @Mock private ChannelDataManager mChannelDataManager; - @Mock private ProgramDataManager mProgramDataManager; - private ProgramManager mProgramManager; - - // Thursday, June 1, 2017 1:00:00 PM GMT-07:00 - private final long mTestStartTimeMs = 1496347200000L; - // Thursday, June 1, 2017 8:00:00 PM GMT-07:00 - private final long mEightPM = 1496372400000L; - private DefaultUiFlags mUiFlags; - - @Before - public void setup() { - MockitoAnnotations.initMocks(this); - TestSingletonApp app = (TestSingletonApp) RuntimeEnvironment.application; - app.fakeClock.setBootTimeMillis(mTestStartTimeMs + TimeUnit.HOURS.toMillis(-12)); - app.fakeClock.setCurrentTimeMillis(mTestStartTimeMs); - mUiFlags = new DefaultUiFlags(); - mProgramManager = - new ProgramManager( - app.getTvInputManagerHelper(), - mChannelDataManager, - mProgramDataManager, - null, - null); - } - - @Test - public void testOnTableEntryChanged() { - Mockito.when(mProgramGuide.getProgramManager()).thenReturn(mProgramManager); - Mockito.when(mProgramDataManager.getCurrentProgram(anyLong())) - .thenAnswer( - invocation -> { - long id = (long) invocation.getArguments()[0]; - return buildProgramForTesting( - id, id, (int) id % GenreItems.getGenreCount()); - }); - ProgramTableAdapter programTableAdapter = - new ProgramTableAdapter(RuntimeEnvironment.application, mProgramGuide, mUiFlags); - mProgramManager.setChannels(buildChannelForTesting(1, 2, 3)); - assertThat(mProgramManager.getChannelCount()).isEqualTo(3); - - // set genre ID to 1. Then channel 1 is in the filtered list but channel 2 is not. - mProgramManager.resetChannelListWithGenre(1); - assertThat(mProgramManager.getChannelCount()).isEqualTo(1); - assertThat(mProgramManager.getChannelIndex(2)).isEqualTo(-1); - - // should be no exception when onTableEntryChanged() is called - programTableAdapter.onTableEntryChanged( - ProgramManager.createTableEntryForTest( - 2, - mProgramDataManager.getCurrentProgram(2), - null, - mTestStartTimeMs, - mEightPM, - false)); - } - - private List<Channel> buildChannelForTesting(long... ids) { - List<Channel> channels = new ArrayList<>(); - for (long id : ids) { - channels.add(new ChannelImpl.Builder().setId(id).build()); - } - return channels; - } - - private Program buildProgramForTesting(long id, long channelId, int genreId) { - return new ProgramImpl.Builder() - .setId(id) - .setChannelId(channelId) - .setCanonicalGenres(GenreItems.getCanonicalGenre(genreId)) - .build(); - } -} diff --git a/tests/robotests/src/com/android/tv/search/FakeSearchInterface.java b/tests/robotests/src/com/android/tv/search/FakeSearchInterface.java deleted file mode 100644 index 568bddde..00000000 --- a/tests/robotests/src/com/android/tv/search/FakeSearchInterface.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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.search; - -import android.content.Intent; -import android.media.tv.TvContract; -import android.media.tv.TvContract.Programs; - -import com.android.tv.data.api.Program; -import com.android.tv.search.LocalSearchProvider.SearchResult; - -import java.util.ArrayList; -import java.util.List; - -/** Fake {@link SearchInterface} for testing. */ -public class FakeSearchInterface implements SearchInterface { - public final List<Program> mPrograms = new ArrayList<>(); - - @Override - public List<SearchResult> search(String query, int limit, int action) { - - List<SearchResult> results = new ArrayList<>(); - for (Program program : mPrograms) { - if (program.getTitle().contains(query) || program.getDescription().contains(query)) { - results.add(fromProgram(program)); - } - } - return results; - } - - public static SearchResult fromProgram(Program program) { - SearchResult.Builder result = SearchResult.builder(); - result.setTitle(program.getTitle()); - result.setDescription( - program.getStartTimeUtcMillis() + " - " + program.getEndTimeUtcMillis()); - result.setImageUri(program.getPosterArtUri()); - result.setIntentAction(Intent.ACTION_VIEW); - result.setIntentData(TvContract.buildChannelUri(program.getChannelId()).toString()); - result.setIntentExtraData(TvContract.buildProgramUri(program.getId()).toString()); - result.setContentType(Programs.CONTENT_ITEM_TYPE); - result.setIsLive(true); - result.setVideoWidth(program.getVideoWidth()); - result.setVideoHeight(program.getVideoHeight()); - result.setDuration(program.getDurationMillis()); - result.setChannelId(program.getChannelId()); - return result.build(); - } -} diff --git a/tests/robotests/src/com/android/tv/search/LocalSearchProviderTest.java b/tests/robotests/src/com/android/tv/search/LocalSearchProviderTest.java deleted file mode 100644 index 76151264..00000000 --- a/tests/robotests/src/com/android/tv/search/LocalSearchProviderTest.java +++ /dev/null @@ -1,257 +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 com.google.common.truth.Truth.assertThat; - -import static junit.framework.Assert.fail; - -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.verify; - -import android.app.SearchManager; -import android.content.ContentResolver; -import android.content.ContentUris; -import android.database.Cursor; -import android.net.Uri; - -import com.android.tv.common.flags.impl.SettableFlagsModule; -import com.android.tv.data.ProgramImpl; -import com.android.tv.data.api.Program; -import com.android.tv.perf.PerformanceMonitor; -import com.android.tv.perf.stub.StubPerformanceMonitor; -import com.android.tv.search.LocalSearchProvider.SearchResult; -import com.android.tv.search.LocalSearchProviderTest.TestAppComponent.TestAppModule; -import com.android.tv.testing.TestSingletonApp; -import com.android.tv.testing.constants.ConfigConstants; -import com.android.tv.testing.robo.ContentProviders; - -import dagger.Component; -import dagger.Module; -import dagger.Provides; -import dagger.android.AndroidInjectionModule; -import dagger.android.AndroidInjector; -import dagger.android.DispatchingAndroidInjector; -import dagger.android.HasAndroidInjector; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -import java.util.ArrayList; -import java.util.List; - -import javax.inject.Inject; -import javax.inject.Singleton; - -/** Unit test for {@link LocalSearchProvider}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK, application = LocalSearchProviderTest.TestApp.class) -public class LocalSearchProviderTest { - - /** Test app for {@link LocalSearchProviderTest} */ - public static class TestApp extends TestSingletonApp implements HasAndroidInjector { - @Inject DispatchingAndroidInjector<Object> mDispatchingAndroidProvider; - - @Override - public void onCreate() { - super.onCreate(); - DaggerLocalSearchProviderTest_TestAppComponent.builder() - .settableFlagsModule(flagsModule) - .build() - .inject(this); - } - - @Override - public AndroidInjector<Object> androidInjector() { - return mDispatchingAndroidProvider; - } - } - - @Component( - modules = { - AndroidInjectionModule.class, - SettableFlagsModule.class, - LocalSearchProvider.Module.class, - TestAppModule.class - }) - @Singleton - interface TestAppComponent extends AndroidInjector<TestApp> { - @Module - abstract static class TestAppModule { - @Provides - @Singleton - static PerformanceMonitor providePerformanceMonitor() { - return new StubPerformanceMonitor(); - } - } - } - - private final Program mProgram1 = - new ProgramImpl.Builder() - .setTitle("Dummy program") - .setDescription("Dummy program season 2") - .setPosterArtUri("FakeUri") - .setStartTimeUtcMillis(1516674000000L) - .setEndTimeUtcMillis(1516677000000L) - .setChannelId(7) - .setVideoWidth(1080) - .setVideoHeight(960) - .build(); - - private final String mAuthority = "com.android.tv.search"; - private final String mKeyword = "mKeyword"; - private final Uri mBaseSearchUri = - Uri.parse( - "content://" - + mAuthority - + "/" - + SearchManager.SUGGEST_URI_PATH_QUERY - + "/" - + mKeyword); - - private final Uri mWrongSearchUri = - Uri.parse("content://" + mAuthority + "/wrong_path/" + mKeyword); - - private LocalSearchProvider mProvider; - private ContentResolver mContentResolver; - - @Mock private SearchInterface mMockSearchInterface; - private final FakeSearchInterface mFakeSearchInterface = new FakeSearchInterface(); - - @Before - public void setup() { - MockitoAnnotations.initMocks(this); - mProvider = ContentProviders.register(LocalSearchProvider.class, mAuthority); - mContentResolver = RuntimeEnvironment.application.getContentResolver(); - } - - @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 = mContentResolver.query(mWrongSearchUri, 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) { - mProvider.setSearchInterface(mMockSearchInterface); - Uri uri = mBaseSearchUri; - 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 = mContentResolver.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(mKeyword, expectedLimit, expectedAction); - reset(mMockSearchInterface); - } - - @Test - public void testGetType() { - assertThat(mProvider.getType(mBaseSearchUri)).isEqualTo(SearchManager.SUGGEST_MIME_TYPE); - } - - @Test - public void query_empty() { - mProvider.setSearchInterface(mFakeSearchInterface); - Cursor cursor = mContentResolver.query(mBaseSearchUri, null, null, null, null); - assertThat(cursor.moveToNext()).isFalse(); - } - - @Test - public void query_program1() { - mProvider.setSearchInterface(mFakeSearchInterface); - mFakeSearchInterface.mPrograms.add(mProgram1); - Uri uri = - Uri.parse( - "content://" - + mAuthority - + "/" - + SearchManager.SUGGEST_URI_PATH_QUERY - + "/" - + "Dummy"); - Cursor cursor = mContentResolver.query(uri, null, null, null, null); - assertThat(fromCursor(cursor)).containsExactly(FakeSearchInterface.fromProgram(mProgram1)); - } - - private List<SearchResult> fromCursor(Cursor cursor) { - List<SearchResult> results = new ArrayList<>(); - while (cursor.moveToNext()) { - SearchResult.Builder result = SearchResult.builder(); - int i = 0; - result.setTitle(cursor.getString(i++)); - result.setDescription(cursor.getString(i++)); - result.setImageUri(cursor.getString(i++)); - result.setIntentAction(cursor.getString(i++)); - String intentData = cursor.getString(i++); - result.setIntentData(intentData); - result.setIntentExtraData(cursor.getString(i++)); - result.setContentType(cursor.getString(i++)); - result.setIsLive(cursor.getString(i++).equals("1")); - result.setVideoWidth(Integer.valueOf(cursor.getString(i++))); - result.setVideoHeight(Integer.valueOf(cursor.getString(i++))); - result.setDuration(Long.valueOf(cursor.getString(i++))); - result.setProgressPercentage(Integer.valueOf(cursor.getString(i))); - result.setChannelId(ContentUris.parseId(Uri.parse(intentData))); - results.add(result.build()); - } - return results; - } -} diff --git a/tests/robotests/src/com/android/tv/testing/TvRobolectricTestRunner.java b/tests/robotests/src/com/android/tv/testing/TvRobolectricTestRunner.java deleted file mode 100644 index 445fab26..00000000 --- a/tests/robotests/src/com/android/tv/testing/TvRobolectricTestRunner.java +++ /dev/null @@ -1,84 +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.testing; - -import org.junit.runners.model.InitializationError; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; -import org.robolectric.manifest.AndroidManifest; -import org.robolectric.res.Fs; -import org.robolectric.res.ResourcePath; - -import java.util.List; - -/** - * Custom test runner TV. This is needed because the default behavior for robolectric is just to - * grab the resource directory in the target package. We want to override this to add several - * spanning different projects. - * - * <p><b>Note</b> copied from - * http://cs/android/packages/apps/Settings/tests/robotests/src/com/android/settings/testutils/SettingsRobolectricTestRunner.java - */ -public class TvRobolectricTestRunner extends RobolectricTestRunner { - - /** We don't actually want to change this behavior, so we just call super. */ - public TvRobolectricTestRunner(Class<?> testClass) throws InitializationError { - super(testClass); - } - - /** - * We are going to create our own custom manifest so that we can add multiple resource paths to - * it. This lets us access resources in both Settings and SettingsLib in our tests. - */ - @Override - protected AndroidManifest getAppManifest(Config config) { - final String packageName = "com.android.tv"; - - // By adding any resources from libraries we need the AndroidManifest, we can access - // them from within the parallel universe's resource loader. - return new AndroidManifest( - Fs.fileFromPath(config.manifest()), - Fs.fileFromPath(config.resourceDir()), - Fs.fileFromPath(config.assetDir()), - packageName) { - @Override - public List<ResourcePath> getIncludedResourcePaths() { - List<ResourcePath> paths = super.getIncludedResourcePaths(); - TvRobolectricTestRunner.getIncludedResourcePaths(paths); - return paths; - } - }; - } - - public static void getIncludedResourcePaths(List<ResourcePath> paths) { - paths.add( - new ResourcePath( - null, - Fs.fileFromPath("./packages/apps/TV/res"), - null)); - paths.add( - new ResourcePath( - null, - Fs.fileFromPath("./packages/apps/TV/common/res"), - null)); - paths.add( - new ResourcePath( - null, - Fs.fileFromPath("./packages/apps/TV/material_res"), - null)); - } -} diff --git a/tests/robotests/src/com/android/tv/ui/ChannelBannerViewTest.java b/tests/robotests/src/com/android/tv/ui/ChannelBannerViewTest.java deleted file mode 100644 index 80a50f6f..00000000 --- a/tests/robotests/src/com/android/tv/ui/ChannelBannerViewTest.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * 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.ui; - -import static com.google.common.truth.Truth.assertThat; - -import static org.robolectric.Shadows.shadowOf; - -import android.app.Activity; -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ImageView; - -import com.android.tv.R; -import com.android.tv.common.flags.impl.DefaultLegacyFlags; -import com.android.tv.common.singletons.HasSingletons; -import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; -import com.android.tv.dvr.DvrManager; -import com.android.tv.testing.TvRobolectricTestRunner; -import com.android.tv.testing.constants.ConfigConstants; -import com.android.tv.ui.ChannelBannerView.MySingletons; -import com.android.tv.util.TvInputManagerHelper; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import javax.inject.Provider; - -/** Tests for {@link ChannelBannerView}. */ -@RunWith(TvRobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class ChannelBannerViewTest { - - private TestActivity testActivity; - private ChannelBannerView mChannelBannerView; - private ImageView mChannelSignalStrengthView; - - @Before - public void setUp() { - testActivity = Robolectric.buildActivity(TestActivity.class).create().get(); - mChannelBannerView = - (ChannelBannerView) - LayoutInflater.from(testActivity).inflate(R.layout.channel_banner, null); - mChannelSignalStrengthView = mChannelBannerView.findViewById(R.id.channel_signal_strength); - } - - @Test - public void updateChannelSignalStrengthView_valueIsNotValid() { - mChannelBannerView.updateChannelSignalStrengthView(-1); - assertThat(mChannelSignalStrengthView.getVisibility()).isEqualTo(View.GONE); - mChannelBannerView.updateChannelSignalStrengthView(101); - assertThat(mChannelSignalStrengthView.getVisibility()).isEqualTo(View.GONE); - } - - @Test - public void updateChannelSignalStrengthView_20() { - mChannelBannerView.updateChannelSignalStrengthView(20); - assertThat(mChannelSignalStrengthView.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(shadowOf(mChannelSignalStrengthView.getDrawable()).getCreatedFromResId()) - .isEqualTo(R.drawable.quantum_ic_signal_cellular_0_bar_white_24); - } - - @Test - public void updateChannelSignalStrengthView_40() { - mChannelBannerView.updateChannelSignalStrengthView(40); - assertThat(mChannelSignalStrengthView.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(shadowOf(mChannelSignalStrengthView.getDrawable()).getCreatedFromResId()) - .isEqualTo(R.drawable.quantum_ic_signal_cellular_1_bar_white_24); - } - - @Test - public void updateChannelSignalStrengthView_60() { - mChannelBannerView.updateChannelSignalStrengthView(60); - assertThat(mChannelSignalStrengthView.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(shadowOf(mChannelSignalStrengthView.getDrawable()).getCreatedFromResId()) - .isEqualTo(R.drawable.quantum_ic_signal_cellular_2_bar_white_24); - } - - @Test - public void updateChannelSignalStrengthView_80() { - mChannelBannerView.updateChannelSignalStrengthView(80); - assertThat(mChannelSignalStrengthView.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(shadowOf(mChannelSignalStrengthView.getDrawable()).getCreatedFromResId()) - .isEqualTo(R.drawable.quantum_ic_signal_cellular_3_bar_white_24); - } - - @Test - public void updateChannelSignalStrengthView_100() { - mChannelBannerView.updateChannelSignalStrengthView(100); - assertThat(mChannelSignalStrengthView.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(shadowOf(mChannelSignalStrengthView.getDrawable()).getCreatedFromResId()) - .isEqualTo(R.drawable.quantum_ic_signal_cellular_4_bar_white_24); - } - - /** An activity for {@link ChannelBannerViewTest}. */ - public static class TestActivity extends Activity implements HasSingletons<MySingletons> { - - MySingletonsImpl mSingletons = new MySingletonsImpl(); - Context mContext = this; - - @Override - public ChannelBannerView.MySingletons singletons() { - return mSingletons; - } - - /** MySingletons implementation needed for this class. */ - public class MySingletonsImpl implements ChannelBannerView.MySingletons { - - @Override - public Provider<Channel> getCurrentChannelProvider() { - return null; - } - - @Override - public Provider<Program> getCurrentProgramProvider() { - return null; - } - - @Override - public Provider<TvOverlayManager> getOverlayManagerProvider() { - return null; - } - - @Override - public TvInputManagerHelper getTvInputManagerHelperSingleton() { - return new TvInputManagerHelper(mContext, DefaultLegacyFlags.DEFAULT); - } - - @Override - public Provider<Long> getCurrentPlayingPositionProvider() { - return null; - } - - @Override - public DvrManager getDvrManagerSingleton() { - return null; - } - } - } -} diff --git a/tests/robotests/src/com/android/tv/ui/hideable/AutoHideSchedulerTest.java b/tests/robotests/src/com/android/tv/ui/hideable/AutoHideSchedulerTest.java deleted file mode 100644 index a0a21070..00000000 --- a/tests/robotests/src/com/android/tv/ui/hideable/AutoHideSchedulerTest.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * 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.ui.hideable; - -import static com.google.common.truth.Truth.assertThat; - -import com.android.tv.testing.constants.ConfigConstants; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; -import org.robolectric.shadows.ShadowLooper; - -import java.util.concurrent.TimeUnit; - -/** Test for {@link AutoHideScheduler}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class AutoHideSchedulerTest { - - private TestRunnable mTestRunnable = new TestRunnable(); - private AutoHideScheduler mAutoHideScheduler; - private ShadowLooper mShadowLooper; - - @Before - public void setUp() throws Exception { - mShadowLooper = ShadowLooper.getShadowMainLooper(); - mAutoHideScheduler = new AutoHideScheduler(RuntimeEnvironment.application, mTestRunnable); - } - - @Test - public void initialState() { - assertThat(mAutoHideScheduler.isScheduled()).isFalse(); - } - - @Test - public void cancel() { - mAutoHideScheduler.cancel(); - assertThat(mAutoHideScheduler.isScheduled()).isFalse(); - } - - @Test - public void schedule() { - mAutoHideScheduler.schedule(10); - assertThat(mAutoHideScheduler.isScheduled()).isTrue(); - assertThat(mTestRunnable.runCount).isEqualTo(0); - } - - @Test - public void setA11yEnabledThenSchedule() { - mAutoHideScheduler.onAccessibilityStateChanged(true); - mAutoHideScheduler.schedule(10); - assertThat(mAutoHideScheduler.isScheduled()).isFalse(); - assertThat(mTestRunnable.runCount).isEqualTo(0); - } - - @Test - public void scheduleThenCancel() { - mAutoHideScheduler.schedule(10); - assertThat(mAutoHideScheduler.isScheduled()).isTrue(); - mAutoHideScheduler.cancel(); - assertThat(mAutoHideScheduler.isScheduled()).isFalse(); - assertThat(mTestRunnable.runCount).isEqualTo(0); - } - - @Test - public void scheduleThenLoop() { - mAutoHideScheduler.schedule(10); - assertThat(mAutoHideScheduler.isScheduled()).isTrue(); - assertThat(mTestRunnable.runCount).isEqualTo(0); - mShadowLooper.idle(9, TimeUnit.MILLISECONDS); - assertThat(mAutoHideScheduler.isScheduled()).isTrue(); - assertThat(mTestRunnable.runCount).isEqualTo(0); - mShadowLooper.idle(1, TimeUnit.MILLISECONDS); - assertThat(mAutoHideScheduler.isScheduled()).isFalse(); - assertThat(mTestRunnable.runCount).isEqualTo(1); - } - - @Test - public void scheduleSetA11yEnabledThenLoop() { - mAutoHideScheduler.schedule(10); - assertThat(mAutoHideScheduler.isScheduled()).isTrue(); - assertThat(mTestRunnable.runCount).isEqualTo(0); - mShadowLooper.idle(9, TimeUnit.MILLISECONDS); - assertThat(mAutoHideScheduler.isScheduled()).isTrue(); - assertThat(mTestRunnable.runCount).isEqualTo(0); - mAutoHideScheduler.onAccessibilityStateChanged(true); - mShadowLooper.idle(1, TimeUnit.MILLISECONDS); - assertThat(mAutoHideScheduler.isScheduled()).isFalse(); - assertThat(mTestRunnable.runCount).isEqualTo(0); - } - - private static class TestRunnable implements Runnable { - int runCount = 0; - - @Override - public void run() { - runCount++; - } - } -} diff --git a/tests/robotests/src/com/android/tv/util/MultiLongSparseArrayTest.java b/tests/robotests/src/com/android/tv/util/MultiLongSparseArrayTest.java deleted file mode 100644 index 931ff0be..00000000 --- a/tests/robotests/src/com/android/tv/util/MultiLongSparseArrayTest.java +++ /dev/null @@ -1,105 +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 com.google.common.truth.Truth.assertThat; - -import com.android.tv.testing.constants.ConfigConstants; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -/** Tests for {@link MultiLongSparseArray}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class MultiLongSparseArrayTest { - @Test - public void testEmpty() { - MultiLongSparseArray<String> sparseArray = new MultiLongSparseArray<>(); - assertThat(sparseArray.get(0)).isEmpty(); - } - - @Test - public void testOneElement() { - MultiLongSparseArray<String> sparseArray = new MultiLongSparseArray<>(); - sparseArray.put(0, "foo"); - assertThat(sparseArray.get(0)).containsExactly("foo"); - } - - @Test - public void testTwoElements() { - MultiLongSparseArray<String> sparseArray = new MultiLongSparseArray<>(); - sparseArray.put(0, "foo"); - sparseArray.put(0, "bar"); - assertThat(sparseArray.get(0)).containsExactly("foo", "bar"); - } - - @Test - public void testClearEmptyCache() { - MultiLongSparseArray<String> sparseArray = new MultiLongSparseArray<>(); - sparseArray.clearEmptyCache(); - assertThat(sparseArray.getEmptyCacheSize()).isEqualTo(0); - sparseArray.put(0, "foo"); - sparseArray.remove(0, "foo"); - assertThat(sparseArray.getEmptyCacheSize()).isEqualTo(1); - sparseArray.clearEmptyCache(); - assertThat(sparseArray.getEmptyCacheSize()).isEqualTo(0); - } - - @Test - public void testMaxEmptyCacheSize() { - MultiLongSparseArray<String> sparseArray = new MultiLongSparseArray<>(); - sparseArray.clearEmptyCache(); - assertThat(sparseArray.getEmptyCacheSize()).isEqualTo(0); - 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"); - } - assertThat(sparseArray.getEmptyCacheSize()) - .isEqualTo(MultiLongSparseArray.DEFAULT_MAX_EMPTIES_KEPT); - sparseArray.clearEmptyCache(); - assertThat(sparseArray.getEmptyCacheSize()).isEqualTo(0); - } - - @Test - public void testReuseEmptySets() { - MultiLongSparseArray<String> sparseArray = new MultiLongSparseArray<>(); - sparseArray.clearEmptyCache(); - assertThat(sparseArray.getEmptyCacheSize()).isEqualTo(0); - // 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"); - } - assertThat(sparseArray.getEmptyCacheSize()) - .isEqualTo(MultiLongSparseArray.DEFAULT_MAX_EMPTIES_KEPT); - - // 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"); - assertThat(sparseArray.getEmptyCacheSize()) - .isEqualTo(MultiLongSparseArray.DEFAULT_MAX_EMPTIES_KEPT - i - 1); - } - } -} diff --git a/tests/robotests/src/com/android/tv/util/TvInputManagerHelperRoboTest.java b/tests/robotests/src/com/android/tv/util/TvInputManagerHelperRoboTest.java deleted file mode 100644 index 9586c1f5..00000000 --- a/tests/robotests/src/com/android/tv/util/TvInputManagerHelperRoboTest.java +++ /dev/null @@ -1,52 +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.util; - -import static com.google.common.truth.Truth.assertThat; - -import android.media.tv.TvInputInfo; -import android.media.tv.TvInputManager; - -import com.android.tv.common.flags.impl.DefaultLegacyFlags; -import com.android.tv.testing.constants.ConfigConstants; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -/** - * Tests for {@link TvInputManagerHelper}. - * - * <p>This test is named ...RoboTest because there is already a test named <code> - * TvInputManagerHelperTest</code> - */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class TvInputManagerHelperRoboTest { - - @Test - public void getInputState_null() { - TvInputInfo tvinputInfo = null; - TvInputManagerHelper tvInputManagerHelper = - new TvInputManagerHelper( - RuntimeEnvironment.application, DefaultLegacyFlags.DEFAULT); - assertThat(TvInputManager.INPUT_STATE_DISCONNECTED) - .isSameInstanceAs(tvInputManagerHelper.getInputState(tvinputInfo)); - } -} diff --git a/tests/robotests/src/com/android/tv/util/TvProviderUtilsTest.java b/tests/robotests/src/com/android/tv/util/TvProviderUtilsTest.java deleted file mode 100644 index bd0e9966..00000000 --- a/tests/robotests/src/com/android/tv/util/TvProviderUtilsTest.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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.util; - -import static com.google.common.truth.Truth.assertThat; - -import android.content.pm.ProviderInfo; -import android.media.tv.TvContract; -import android.os.Bundle; - -import com.android.tv.testing.constants.ConfigConstants; -import com.android.tv.testing.fakes.FakeTvProvider; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; -import org.robolectric.shadows.ShadowContentResolver; - -import java.util.Set; - -/** Tests for {@link TvProviderUtils}. */ -@RunWith(RobolectricTestRunner.class) -@Config( - sdk = ConfigConstants.SDK, - shadows = {ShadowContentResolver.class}) -public class TvProviderUtilsTest { - - @Before - public void setUp() { - ProviderInfo info = new ProviderInfo(); - info.authority = TvContract.AUTHORITY; - FakeTvProvider provider = - Robolectric.buildContentProvider(FakeTvProviderForTesting.class).create(info).get(); - provider.onCreate(); - ShadowContentResolver.registerProviderInternal(TvContract.AUTHORITY, provider); - } - - @Test - public void testAddExtraColumnsToProjection() { - String[] inputStrings = {"column_1", "column_2", "column_3"}; - assertThat( - TvProviderUtils.addExtraColumnsToProjection( - inputStrings, TvProviderUtils.EXTRA_PROGRAM_COLUMN_STATE)) - .asList() - .containsExactly( - "column_1", - "column_2", - "column_3", - TvProviderUtils.EXTRA_PROGRAM_COLUMN_STATE) - .inOrder(); - } - - @Test - public void testAddExtraColumnsToProjection_extraColumnExists() { - String[] inputStrings = { - "column_1", - "column_2", - TvProviderUtils.EXTRA_PROGRAM_COLUMN_SERIES_ID, - TvProviderUtils.EXTRA_PROGRAM_COLUMN_STATE, - "column_3" - }; - assertThat( - TvProviderUtils.addExtraColumnsToProjection( - inputStrings, TvProviderUtils.EXTRA_PROGRAM_COLUMN_STATE)) - .asList() - .containsExactly( - "column_1", - "column_2", - TvProviderUtils.EXTRA_PROGRAM_COLUMN_SERIES_ID, - TvProviderUtils.EXTRA_PROGRAM_COLUMN_STATE, - "column_3") - .inOrder(); - } - - @Test - public void testGetExistingColumns_noException() { - FakeTvProviderForTesting.mThrowException = false; - FakeTvProviderForTesting.mBundleResult = new Bundle(); - FakeTvProviderForTesting.mBundleResult.putStringArray( - TvContract.EXTRA_EXISTING_COLUMN_NAMES, new String[] {"column 1", "column 2"}); - Set<String> columns = - TvProviderUtils.getExistingColumns( - RuntimeEnvironment.application, TvContract.Programs.CONTENT_URI); - assertThat(columns).containsExactly("column 1", "column 2"); - } - - @Test - public void testGetExistingColumns_throwsException() { - FakeTvProviderForTesting.mThrowException = true; - FakeTvProviderForTesting.mBundleResult = new Bundle(); - // should be no exception here - Set<String> columns = - TvProviderUtils.getExistingColumns( - RuntimeEnvironment.application, TvContract.Programs.CONTENT_URI); - assertThat(columns).isEmpty(); - } - - private static class FakeTvProviderForTesting extends FakeTvProvider { - private static Bundle mBundleResult; - private static boolean mThrowException; - - @Override - public Bundle call(String method, String arg, Bundle extras) { - if (mThrowException) { - throw new IllegalStateException(); - } - return mBundleResult; - } - } -} diff --git a/tests/robotests/src/com/android/tv/util/TvTrackInfoUtilsTest.java b/tests/robotests/src/com/android/tv/util/TvTrackInfoUtilsTest.java deleted file mode 100644 index c59cb16e..00000000 --- a/tests/robotests/src/com/android/tv/util/TvTrackInfoUtilsTest.java +++ /dev/null @@ -1,385 +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 com.android.tv.util.TvTrackInfoUtils.getBestTrackInfo; - -import static com.google.common.truth.Truth.assertWithMessage; - -import static org.junit.Assert.assertEquals; - -import android.media.tv.TvTrackInfo; -import android.os.Build.VERSION_CODES; -import android.os.LocaleList; - -import com.android.tv.testing.ComparatorTester; -import com.android.tv.testing.TvRobolectricTestRunner; -import com.android.tv.testing.constants.ConfigConstants; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Locale; - -/** Tests for {@link com.android.tv.util.TvTrackInfoUtils}. */ -@RunWith(TvRobolectricTestRunner.class) -@Config(minSdk = ConfigConstants.MIN_SDK, maxSdk = ConfigConstants.MAX_SDK) -public class TvTrackInfoUtilsTest { - - /** Tests for {@link TvTrackInfoUtils#getBestTrackInfo}. */ - private static final String UN_MATCHED_ID = "no matching ID"; - - private final TvTrackInfo info1En1 = createTvTrackInfo("track_1", "en", 1); - - private final TvTrackInfo info2En5 = createTvTrackInfo("track_2", "en", 5); - - private final TvTrackInfo info3Fr8 = createTvTrackInfo("track_3", "fr", 8); - - private final TvTrackInfo info4Null2 = createTvTrackInfo("track_4", null, 2); - - private final TvTrackInfo info5Null6 = createTvTrackInfo("track_5", null, 6); - - private TvTrackInfo createTvTrackInfo(String trackId, String language, int audioChannelCount) { - return new TvTrackInfo.Builder(TvTrackInfo.TYPE_AUDIO, trackId) - .setLanguage(language) - .setAudioChannelCount(audioChannelCount) - .build(); - } - - private final List<TvTrackInfo> allTracks = - Arrays.asList(info1En1, info2En5, info3Fr8, info4Null2, info5Null6); - private final List<TvTrackInfo> nullLanguageTracks = Arrays.asList(info4Null2, info5Null6); - - @Test - public void testGetBestTrackInfo_empty() { - TvTrackInfo result = getBestTrackInfo(Collections.emptyList(), UN_MATCHED_ID, "en", 1); - assertWithMessage("best track ").that(result).isEqualTo(null); - } - - @Test - public void testGetBestTrackInfo_exactMatch() { - TvTrackInfo result = getBestTrackInfo(allTracks, "track_1", "en", 1); - assertWithMessage("best track ").that(result).isEqualTo(info1En1); - } - - @Test - public void testGetBestTrackInfo_langAndChannelCountMatch() { - TvTrackInfo result = getBestTrackInfo(allTracks, UN_MATCHED_ID, "en", 5); - assertWithMessage("best track ").that(result).isEqualTo(info2En5); - } - - @Test - public void testGetBestTrackInfo_languageOnlyMatch() { - TvTrackInfo result = getBestTrackInfo(allTracks, UN_MATCHED_ID, "fr", 1); - assertWithMessage("best track ").that(result).isEqualTo(info3Fr8); - } - - @Test - @Config(minSdk = ConfigConstants.MIN_SDK, maxSdk = VERSION_CODES.M) - public void testGetBestTrackInfo_channelCountOnlyMatchWithNullLanguage_23() { - Locale localPreference = Locale.forLanguageTag("es"); - Locale.setDefault(localPreference); - TvTrackInfo result = getBestTrackInfo(allTracks, UN_MATCHED_ID, null, 8); - assertWithMessage("best track ").that(result).isEqualTo(info3Fr8); - } - - @Test - @Config(minSdk = VERSION_CODES.N, maxSdk = ConfigConstants.MAX_SDK) - public void testGetBestTrackInfo_channelCountOnlyMatchWithNullLanguage() { - // Setting LoacaleList to a language which is not in the test set. - LocaleList localPreferenceList = LocaleList.forLanguageTags("es"); - LocaleList.setDefault(localPreferenceList); - TvTrackInfo result = getBestTrackInfo(allTracks, UN_MATCHED_ID, null, 8); - assertWithMessage("best track ").that(result).isEqualTo(info3Fr8); - } - - @Test - public void testGetBestTrackInfo_noMatches() { - TvTrackInfo result = getBestTrackInfo(allTracks, UN_MATCHED_ID, "kr", 1); - assertWithMessage("best track ").that(result).isEqualTo(info1En1); - } - - @Test - @Config(minSdk = ConfigConstants.MIN_SDK, maxSdk = VERSION_CODES.M) - public void testGetBestTrackInfo_noMatchesWithNullLanguage_23() { - Locale localPreference = Locale.forLanguageTag("es"); - Locale.setDefault(localPreference); - TvTrackInfo result = getBestTrackInfo(allTracks, UN_MATCHED_ID, null, 0); - assertWithMessage("best track ").that(result).isEqualTo(info3Fr8); - } - - @Test - @Config(minSdk = VERSION_CODES.N, maxSdk = ConfigConstants.MAX_SDK) - public void testGetBestTrackInfo_noMatchesWithNullLanguage() { - // Setting LoacaleList to a language which is not in the test set. - LocaleList localPreferenceList = LocaleList.forLanguageTags("es"); - LocaleList.setDefault(localPreferenceList); - TvTrackInfo result = getBestTrackInfo(allTracks, UN_MATCHED_ID, null, 0); - assertWithMessage("best track ").that(result).isEqualTo(info3Fr8); - } - - @Test - public void testGetBestTrackInfo_channelCountAndIdMatch() { - TvTrackInfo result = getBestTrackInfo(nullLanguageTracks, "track_5", null, 6); - assertWithMessage("best track ").that(result).isEqualTo(info5Null6); - } - - @Test - public void testComparator() { - List<String> languages = Arrays.asList("en", "spa", "hi"); - Comparator<TvTrackInfo> comparator = - TvTrackInfoUtils.createComparator("track_1", languages, 1); - new ComparatorTester(comparator) - .permitInconsistencyWithEquals() - // lang not match - .addEqualityGroup( - createTvTrackInfo("track_1", "kr", 2), - createTvTrackInfo("track_1", "ja", 2), - createTvTrackInfo("track_1", "ch", 2)) - // lang not match, better count - .addEqualityGroup( - createTvTrackInfo("track_1", "kr", 3), - createTvTrackInfo("track_1", "ch", 3)) - // lang not match, count match - .addEqualityGroup( - createTvTrackInfo("track_1", "ch", 1), - createTvTrackInfo("track_1", "ja", 1)) - // lang match in order of increasing priority - .addEqualityGroup(createTvTrackInfo("track_1", "hi", 3)) - .addEqualityGroup(createTvTrackInfo("track_2", "hi", 7)) - .addEqualityGroup(createTvTrackInfo("track_1", "hi", 1)) - .addEqualityGroup(createTvTrackInfo("track_1", "spa", 5)) - .addEqualityGroup(createTvTrackInfo("track_2", "spa", 1)) - .addEqualityGroup(createTvTrackInfo("track_1", "spa", 1)) - .addEqualityGroup(createTvTrackInfo("track_2", "en", 3)) - .addEqualityGroup( - createTvTrackInfo("track_1", "en", 5), - createTvTrackInfo("track_2", "en", 5)) - // best lang match and count match - .addEqualityGroup( - createTvTrackInfo("track_2", "en", 1), - createTvTrackInfo("track_3", "en", 1)) - // all match - .addEqualityGroup( - createTvTrackInfo("track_1", "en", 1), - createTvTrackInfo("track_1", "en", 1)) - .testCompare(); - } - - /** Tests for {@link TvTrackInfoUtils#needToShowSampleRate}. */ - private final TvTrackInfo info6En1 = createTvTrackInfo("track_6", "en", 1); - - private final TvTrackInfo info7En0 = createTvTrackInfo("track_7", "en", 0); - - private final TvTrackInfo info8En0 = createTvTrackInfo("track_8", "en", 0); - - private List<TvTrackInfo> trackList; - - @Test - public void needToShowSampleRate_false() { - trackList = Arrays.asList(info1En1, info2En5); - assertEquals( - false, - TvTrackInfoUtils.needToShowSampleRate(RuntimeEnvironment.application, trackList)); - } - - @Test - public void needToShowSampleRate_sameLanguageAndChannelCount() { - trackList = Arrays.asList(info1En1, info6En1); - assertEquals( - true, - TvTrackInfoUtils.needToShowSampleRate(RuntimeEnvironment.application, trackList)); - } - - @Test - public void needToShowSampleRate_sameLanguageNoChannelCount() { - trackList = Arrays.asList(info7En0, info8En0); - assertEquals( - true, - TvTrackInfoUtils.needToShowSampleRate(RuntimeEnvironment.application, trackList)); - } - - /** Tests for {@link TvTrackInfoUtils#getMultiAudioString}. */ - private static final String TRACK_ID = "test_track_id"; - - private static final int AUDIO_SAMPLE_RATE = 48000; - - @Test - public void testAudioTrackLanguage() { - assertEquals( - "Korean", - TvTrackInfoUtils.getMultiAudioString( - RuntimeEnvironment.application, createAudioTrackInfo("kor"), false)); - assertEquals( - "English", - TvTrackInfoUtils.getMultiAudioString( - RuntimeEnvironment.application, createAudioTrackInfo("eng"), false)); - assertEquals( - "Unknown language", - TvTrackInfoUtils.getMultiAudioString( - RuntimeEnvironment.application, createAudioTrackInfo(null), false)); - assertEquals( - "Unknown language", - TvTrackInfoUtils.getMultiAudioString( - RuntimeEnvironment.application, createAudioTrackInfo(""), false)); - assertEquals( - "abc", - TvTrackInfoUtils.getMultiAudioString( - RuntimeEnvironment.application, createAudioTrackInfo("abc"), false)); - } - - @Test - public void testAudioTrackCount() { - assertEquals( - "English", - TvTrackInfoUtils.getMultiAudioString( - RuntimeEnvironment.application, createAudioTrackInfo("eng", -1), false)); - assertEquals( - "English", - TvTrackInfoUtils.getMultiAudioString( - RuntimeEnvironment.application, createAudioTrackInfo("eng", 0), false)); - assertEquals( - "English (mono)", - TvTrackInfoUtils.getMultiAudioString( - RuntimeEnvironment.application, createAudioTrackInfo("eng", 1), false)); - assertEquals( - "English (stereo)", - TvTrackInfoUtils.getMultiAudioString( - RuntimeEnvironment.application, createAudioTrackInfo("eng", 2), false)); - assertEquals( - "English (3 channels)", - TvTrackInfoUtils.getMultiAudioString( - RuntimeEnvironment.application, createAudioTrackInfo("eng", 3), false)); - assertEquals( - "English (4 channels)", - TvTrackInfoUtils.getMultiAudioString( - RuntimeEnvironment.application, createAudioTrackInfo("eng", 4), false)); - assertEquals( - "English (5 channels)", - TvTrackInfoUtils.getMultiAudioString( - RuntimeEnvironment.application, createAudioTrackInfo("eng", 5), false)); - assertEquals( - "English (5.1 surround)", - TvTrackInfoUtils.getMultiAudioString( - RuntimeEnvironment.application, createAudioTrackInfo("eng", 6), false)); - assertEquals( - "English (7 channels)", - TvTrackInfoUtils.getMultiAudioString( - RuntimeEnvironment.application, createAudioTrackInfo("eng", 7), false)); - assertEquals( - "English (7.1 surround)", - TvTrackInfoUtils.getMultiAudioString( - RuntimeEnvironment.application, createAudioTrackInfo("eng", 8), false)); - } - - @Test - public void testShowSampleRate() { - assertEquals( - "Korean (48kHz)", - TvTrackInfoUtils.getMultiAudioString( - RuntimeEnvironment.application, createAudioTrackInfo("kor", 0), true)); - assertEquals( - "Korean (7.1 surround, 48kHz)", - TvTrackInfoUtils.getMultiAudioString( - RuntimeEnvironment.application, 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(); - } - - /** Tests for {@link TvTrackInfoUtils#toString */ - @Test - public void toString_audioWithDetails() { - assertEquals( - "TvTrackInfo{type=Audio, id=track_1, language=en, " - + "description=test, audioChannelCount=1, audioSampleRate=5}", - TvTrackInfoUtils.toString( - new TvTrackInfo.Builder(TvTrackInfo.TYPE_AUDIO, "track_1") - .setLanguage("en") - .setAudioChannelCount(1) - .setDescription("test") - .setAudioSampleRate(5) - .build())); - } - - @Test - public void toString_audioWithDefaults() { - assertEquals( - "TvTrackInfo{type=Audio, id=track_2, language=null, " - + "description=null, audioChannelCount=0, audioSampleRate=0}", - TvTrackInfoUtils.toString( - new TvTrackInfo.Builder(TvTrackInfo.TYPE_AUDIO, "track_2").build())); - } - - @Test - public void toString_videoWithDetails() { - assertEquals( - "TvTrackInfo{type=Video, id=track_3, language=en, description=test, videoWidth=1," - + " videoHeight=1, videoFrameRate=1.0, videoPixelAspectRatio=2.0}", - TvTrackInfoUtils.toString( - new TvTrackInfo.Builder(TvTrackInfo.TYPE_VIDEO, "track_3") - .setLanguage("en") - .setDescription("test") - .setVideoWidth(1) - .setVideoHeight(1) - .setVideoFrameRate(1) - .setVideoPixelAspectRatio(2) - .build())); - } - - @Test - public void toString_videoWithDefaults() { - assertEquals( - "TvTrackInfo{type=Video, id=track_4, language=null, description=null, videoWidth=0," - + " videoHeight=0, videoFrameRate=0.0, videoPixelAspectRatio=1.0}", - TvTrackInfoUtils.toString( - new TvTrackInfo.Builder(TvTrackInfo.TYPE_VIDEO, "track_4").build())); - } - - @Test - public void toString_subtitleWithDetails() { - assertEquals( - "TvTrackInfo{type=Subtitle, id=track_5, language=en, description=test}", - TvTrackInfoUtils.toString( - new TvTrackInfo.Builder(TvTrackInfo.TYPE_SUBTITLE, "track_5") - .setLanguage("en") - .setDescription("test") - .build())); - } - - @Test - public void toString_subtitleWithDefaults() { - assertEquals( - "TvTrackInfo{type=Subtitle, id=track_6, language=null, description=null}", - TvTrackInfoUtils.toString( - new TvTrackInfo.Builder(TvTrackInfo.TYPE_SUBTITLE, "track_6").build())); - } -} diff --git a/tests/robotests/src/com/android/tv/util/UtilsTest.java b/tests/robotests/src/com/android/tv/util/UtilsTest.java deleted file mode 100644 index eb27e8a0..00000000 --- a/tests/robotests/src/com/android/tv/util/UtilsTest.java +++ /dev/null @@ -1,495 +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.assertFalse; -import static org.junit.Assert.assertTrue; - -import android.text.format.DateUtils; - -import com.android.tv.testing.constants.ConfigConstants; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -import java.util.Calendar; -import java.util.GregorianCalendar; -import java.util.Locale; -import java.util.TimeZone; - -/** - * 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. - */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class UtilsTest { - // 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( - RuntimeEnvironment.application, - DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(1, 3), - getFebOfThisYearInMillis(1, 3), - false, - DateUtils.FORMAT_12HOUR)); - assertEquals( - "03:00", - Utils.getDurationString( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - DATE_THIS_YEAR_2_1_MS, - getFebOfThisYearInMillis(1, 23), - getFebOfThisYearInMillis(2, 0), - useShortFormat, - DateUtils.FORMAT_12HOUR)); - assertEquals( - "23:00 – 00:00", - Utils.getDurationString( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - 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( - RuntimeEnvironment.application, - DATE_THIS_YEAR_2_1_MS, - DATE_THIS_YEAR_2_1_MS, - DATE_THIS_YEAR_2_1_MS, - useShortFormat, - DateUtils.FORMAT_24HOUR)); - } - } - - @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); - } - - @Test - public void testIsInternalTvInputInvalidInternalInputId() { - String inputId = "tv.comp"; - assertFalse(Utils.isInternalTvInput(RuntimeEnvironment.application, inputId)); - } -} diff --git a/tests/unit/Android.mk b/tests/unit/Android.mk index 80dbfeef..5ea7ccd8 100644 --- a/tests/unit/Android.mk +++ b/tests/unit/Android.mk @@ -9,7 +9,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_STATIC_JAVA_LIBRARIES := \ androidx.test.runner \ - mockito-robolectric-prebuilt \ + mockito-target \ tv-test-common \ LOCAL_JAVA_LIBRARIES := \ diff --git a/tests/unit/AndroidManifest.xml b/tests/unit/AndroidManifest.xml index 5ee17de2..c7d2f528 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="28" android:minSdkVersion="23" /> + <uses-sdk android:targetSdkVersion="27" android:minSdkVersion="23" /> <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" diff --git a/tests/unit/src/com/android/tv/CurrentPositionMediatorTest.java b/tests/unit/src/com/android/tv/CurrentPositionMediatorTest.java index 052123c0..4b85eaae 100644 --- a/tests/unit/src/com/android/tv/CurrentPositionMediatorTest.java +++ b/tests/unit/src/com/android/tv/CurrentPositionMediatorTest.java @@ -53,9 +53,9 @@ public class CurrentPositionMediatorTest extends BaseMainActivityTestCase { public void testOnSeekRequested() { long seekToTimeMs = System.currentTimeMillis() - REQUEST_TIMEOUT_MS * 3; mMediator.onSeekRequested(seekToTimeMs); - assertWithMessage("Seek request time") - .that(mMediator.mSeekRequestTimeMs) - .isNotSameInstanceAs(INVALID_TIME); + assertWithMessage("Seek request time") + .that(mMediator.mSeekRequestTimeMs) + .isNotSameAs(INVALID_TIME); assertWithMessage("Current position") .that(mMediator.mCurrentPositionMs) .isEqualTo(seekToTimeMs); @@ -68,15 +68,15 @@ public class CurrentPositionMediatorTest extends BaseMainActivityTestCase { long newCurrentTimeMs = seekToTimeMs + REQUEST_TIMEOUT_MS; mMediator.onSeekRequested(seekToTimeMs); mMediator.onCurrentPositionChanged(newCurrentTimeMs); - assertWithMessage("Seek request time") - .that(mMediator.mSeekRequestTimeMs) - .isNotSameInstanceAs(INVALID_TIME); - assertWithMessage("Current position") - .that(mMediator.mCurrentPositionMs) - .isNotSameInstanceAs(seekToTimeMs); - assertWithMessage("Current position") - .that(mMediator.mCurrentPositionMs) - .isNotSameInstanceAs(newCurrentTimeMs); + 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 diff --git a/tests/unit/src/com/android/tv/data/ChannelDataManagerTest.java b/tests/unit/src/com/android/tv/data/ChannelDataManagerTest.java index ecae18a2..71ccaf35 100644 --- a/tests/unit/src/com/android/tv/data/ChannelDataManagerTest.java +++ b/tests/unit/src/com/android/tv/data/ChannelDataManagerTest.java @@ -56,7 +56,7 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentMatchers; +import org.mockito.Matchers; import org.mockito.Mockito; /** @@ -92,29 +92,35 @@ public class ChannelDataManagerTest { 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(ArgumentMatchers.anyString())) - .thenReturn(true); - Context mockContext = Mockito.mock(Context.class); - Mockito.when(mockContext.getContentResolver()).thenReturn(mContentResolver); - Mockito.when(mockContext.checkSelfPermission(ArgumentMatchers.anyString())) - .thenAnswer( - invocation -> { - Object[] args = invocation.getArguments(); - return getTargetContext().checkSelfPermission(((String) args[0])); + getInstrumentation() + .runOnMainSync( + new Runnable() { + @Override + public void run() { + TvInputManagerHelper mockHelper = + Mockito.mock(TvInputManagerHelper.class); + Mockito.when(mockHelper.hasTvInputInfo(Matchers.anyString())) + .thenReturn(true); + Context mockContext = Mockito.mock(Context.class); + Mockito.when(mockContext.getContentResolver()) + .thenReturn(mContentResolver); + Mockito.when(mockContext.checkSelfPermission(Matchers.anyString())) + .thenAnswer( + invocation -> { + Object[] args = invocation.getArguments(); + return getTargetContext() + .checkSelfPermission(((String) args[0])); + }); + + mChannelDataManager = + new ChannelDataManager( + mockContext, + mockHelper, + AsyncTask.SERIAL_EXECUTOR, + mContentResolver); + mChannelDataManager.addListener(mListener); + } }); - - mChannelDataManager = - new ChannelDataManager( - mockContext, mockHelper, AsyncTask.SERIAL_EXECUTOR, mContentResolver); - mChannelDataManager.addListener(mListener); - } - }); } @After diff --git a/tests/unit/src/com/android/tv/data/ChannelImplTest.java b/tests/unit/src/com/android/tv/data/ChannelImplTest.java index df2f1a1f..86cfab66 100644 --- a/tests/unit/src/com/android/tv/data/ChannelImplTest.java +++ b/tests/unit/src/com/android/tv/data/ChannelImplTest.java @@ -25,24 +25,20 @@ import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; - import androidx.test.filters.SmallTest; import androidx.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.ArgumentMatchers; +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 ChannelImpl}. */ @SmallTest @RunWith(AndroidJUnit4.class) @@ -50,7 +46,7 @@ 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 TV app. + // 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 = @@ -119,7 +115,7 @@ public class ChannelImplTest { } }) .when(mockPackageManager) - .getActivityInfo(ArgumentMatchers.<ComponentName>any(), ArgumentMatchers.anyInt()); + .getActivityInfo(Mockito.<ComponentName>any(), Mockito.anyInt()); mMockContext = Mockito.mock(Context.class); Mockito.when(mMockContext.getApplicationContext()).thenReturn(mMockContext); @@ -257,7 +253,7 @@ public class ChannelImplTest { @Test public void testComparator() { TvInputManagerHelper manager = Mockito.mock(TvInputManagerHelper.class); - Mockito.when(manager.isPartnerInput(ArgumentMatchers.anyString())) + Mockito.when(manager.isPartnerInput(Matchers.anyString())) .thenAnswer( new Answer<Boolean>() { @Override @@ -267,18 +263,17 @@ public class ChannelImplTest { } }); Comparator<Channel> comparator = new TestChannelComparator(manager); - ComparatorTester comparatorTester = - new ComparatorTester(comparator).permitInconsistencyWithEquals(); - comparatorTester.addEqualityGroup( + ComparatorTester<Channel> comparatorTester = ComparatorTester.withoutEqualsTest(comparator); + comparatorTester.addComparableGroup( new ChannelImpl.Builder().setInputId(PARTNER_INPUT_ID).build()); - comparatorTester.addEqualityGroup(new ChannelImpl.Builder().setInputId("1").build()); - comparatorTester.addEqualityGroup( + comparatorTester.addComparableGroup(new ChannelImpl.Builder().setInputId("1").build()); + comparatorTester.addComparableGroup( new ChannelImpl.Builder().setInputId("1").setDisplayNumber("2").build()); - comparatorTester.addEqualityGroup( + comparatorTester.addComparableGroup( new ChannelImpl.Builder().setInputId("2").setDisplayNumber("1.0").build()); // display name does not affect comparator - comparatorTester.addEqualityGroup( + comparatorTester.addComparableGroup( new ChannelImpl.Builder() .setInputId("2") .setDisplayNumber("1.62") @@ -294,12 +289,12 @@ public class ChannelImplTest { .setDisplayNumber("1.62") .setDisplayName("test3") .build()); - comparatorTester.addEqualityGroup( + comparatorTester.addComparableGroup( new ChannelImpl.Builder().setInputId("2").setDisplayNumber("2.0").build()); // Numeric display number sorting - comparatorTester.addEqualityGroup( + comparatorTester.addComparableGroup( new ChannelImpl.Builder().setInputId("2").setDisplayNumber("12.2").build()); - comparatorTester.testCompare(); + comparatorTester.test(); } /** @@ -311,7 +306,7 @@ public class ChannelImplTest { @Test public void testComparatorLabel() { TvInputManagerHelper manager = Mockito.mock(TvInputManagerHelper.class); - Mockito.when(manager.isPartnerInput(ArgumentMatchers.anyString())) + Mockito.when(manager.isPartnerInput(Matchers.anyString())) .thenAnswer( new Answer<Boolean>() { @Override @@ -321,21 +316,20 @@ public class ChannelImplTest { } }); Comparator<Channel> comparator = new ChannelComparatorWithDescriptionAsLabel(manager); - ComparatorTester comparatorTester = - new ComparatorTester(comparator).permitInconsistencyWithEquals(); + ComparatorTester<Channel> comparatorTester = ComparatorTester.withoutEqualsTest(comparator); - comparatorTester.addEqualityGroup( + comparatorTester.addComparableGroup( new ChannelImpl.Builder().setInputId(PARTNER_INPUT_ID).setDescription("A").build()); // The description is used as a label for this test. - comparatorTester.addEqualityGroup( + comparatorTester.addComparableGroup( new ChannelImpl.Builder().setDescription("A").setInputId("1").build()); - comparatorTester.addEqualityGroup( + comparatorTester.addComparableGroup( new ChannelImpl.Builder().setDescription("A").setInputId("2").build()); - comparatorTester.addEqualityGroup( + comparatorTester.addComparableGroup( new ChannelImpl.Builder().setDescription("B").setInputId("1").build()); - comparatorTester.testCompare(); + comparatorTester.test(); } @Test diff --git a/tests/unit/src/com/android/tv/features/FeaturesTest.java b/tests/unit/src/com/android/tv/features/FeaturesTest.java new file mode 100644 index 00000000..e35758c3 --- /dev/null +++ b/tests/unit/src/com/android/tv/features/FeaturesTest.java @@ -0,0 +1,36 @@ +/* + * 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.features; + +import static com.google.common.truth.Truth.assertThat; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** 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. + assertThat(TvFeatures.TEST_FEATURE.isEnabled(null)).isFalse(); + } +} diff --git a/tests/unit/src/com/android/tv/menu/MenuTest.java b/tests/unit/src/com/android/tv/menu/MenuTest.java index 7058316e..e384c398 100644 --- a/tests/unit/src/com/android/tv/menu/MenuTest.java +++ b/tests/unit/src/com/android/tv/menu/MenuTest.java @@ -25,7 +25,6 @@ import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentMatchers; import org.mockito.Matchers; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; @@ -43,10 +42,8 @@ public class MenuTest { public void setUp() { mMenuView = Mockito.mock(IMenuView.class); MenuRowFactory factory = Mockito.mock(MenuRowFactory.class); - Mockito.when( - factory.createMenuRow( - ArgumentMatchers.any(Menu.class), ArgumentMatchers.any(Class.class))) - .thenReturn(null); + Mockito.when(factory.createMenuRow(Mockito.any(Menu.class), Mockito.any(Class.class))) + .thenReturn(null); mVisibilityChangeListener = Mockito.mock(OnMenuVisibilityChangeListener.class); mMenu = new Menu(getTargetContext(), mMenuView, factory, mVisibilityChangeListener); mMenu.disableAnimationForTest(); diff --git a/tests/unit/src/com/android/tv/menu/TvOptionsRowAdapterTest.java b/tests/unit/src/com/android/tv/menu/TvOptionsRowAdapterTest.java index 64a055a2..5ecbdf02 100644 --- a/tests/unit/src/com/android/tv/menu/TvOptionsRowAdapterTest.java +++ b/tests/unit/src/com/android/tv/menu/TvOptionsRowAdapterTest.java @@ -24,7 +24,6 @@ import android.os.SystemClock; import android.text.TextUtils; import androidx.test.filters.MediumTest; import androidx.test.runner.AndroidJUnit4; -import com.android.tv.common.flags.impl.DefaultLegacyFlags; import com.android.tv.testing.activities.BaseMainActivityTestCase; import com.android.tv.testing.constants.Constants; import com.android.tv.testing.testinput.ChannelState; @@ -50,9 +49,7 @@ public class TvOptionsRowAdapterTest extends BaseMainActivityTestCase { @Before public void setUp() { super.setUp(); - mTvOptionsRowAdapter = - new TvOptionsRowAdapter( - mActivity, Collections.emptyList(), DefaultLegacyFlags.DEFAULT); + mTvOptionsRowAdapter = new TvOptionsRowAdapter(mActivity, Collections.emptyList()); tuneToChannel(TvTestInputConstants.CH_1_DEFAULT_DONT_MODIFY); waitUntilAudioTracksHaveSize(1); waitUntilAudioTrackSelected(ChannelState.DEFAULT.getSelectedAudioTrackId()); @@ -76,10 +73,10 @@ public class TvOptionsRowAdapterTest extends BaseMainActivityTestCase { waitUntilAudioTrackSelected(Constants.EN_STEREO_AUDIO_TRACK.getId()); boolean result = mTvOptionsRowAdapter.updateMultiAudioAction(); - assertWithMessage("update Action had change").that(result).isTrue(); - assertWithMessage("Multi Audio enabled") - .that(MenuAction.SELECT_AUDIO_LANGUAGE_ACTION.isEnabled()) - .isTrue(); + assertWithMessage("update Action had change").that(result).isTrue(); + assertWithMessage("Multi Audio enabled") + .that(MenuAction.SELECT_AUDIO_LANGUAGE_ACTION.isEnabled()) + .isTrue(); } @Test @@ -94,10 +91,10 @@ public class TvOptionsRowAdapterTest extends BaseMainActivityTestCase { waitUntilAudioTrackSelected(Constants.GENERIC_AUDIO_TRACK.getId()); boolean result = mTvOptionsRowAdapter.updateMultiAudioAction(); - assertWithMessage("update Action had change").that(result).isTrue(); - assertWithMessage("Multi Audio enabled") - .that(MenuAction.SELECT_AUDIO_LANGUAGE_ACTION.isEnabled()) - .isFalse(); + assertWithMessage("update Action had change").that(result).isTrue(); + assertWithMessage("Multi Audio enabled") + .that(MenuAction.SELECT_AUDIO_LANGUAGE_ACTION.isEnabled()) + .isFalse(); } @Test @@ -113,10 +110,10 @@ public class TvOptionsRowAdapterTest extends BaseMainActivityTestCase { waitUntilVideoTrackSelected(data.mSelectedVideoTrackId); boolean result = mTvOptionsRowAdapter.updateMultiAudioAction(); - assertWithMessage("update Action had change").that(result).isTrue(); - assertWithMessage("Multi Audio enabled") - .that(MenuAction.SELECT_AUDIO_LANGUAGE_ACTION.isEnabled()) - .isFalse(); + 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) { diff --git a/tests/unit/src/com/android/tv/recommendation/RecommendationUtils.java b/tests/unit/src/com/android/tv/recommendation/RecommendationUtils.java index eb012f49..b929a0ae 100644 --- a/tests/unit/src/com/android/tv/recommendation/RecommendationUtils.java +++ b/tests/unit/src/com/android/tv/recommendation/RecommendationUtils.java @@ -26,7 +26,7 @@ import java.util.List; import java.util.Random; import java.util.TreeMap; import java.util.concurrent.TimeUnit; -import org.mockito.ArgumentMatchers; +import org.mockito.Matchers; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; @@ -57,16 +57,17 @@ public class RecommendationUtils { }) .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(ArgumentMatchers.anyLong()); + 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; } @@ -130,7 +131,7 @@ public class RecommendationUtils { // Time hopping with random minutes. latestWatchEndTimeMs += TimeUnit.MINUTES.toMillis(mRandom.nextInt(30) + 1); } - long watchedDurationMs = mRandom.nextInt((int) maxWatchDurationMs) + 1L; + long watchedDurationMs = mRandom.nextInt((int) maxWatchDurationMs) + 1; if (!addWatchLog(channelId, latestWatchEndTimeMs, watchedDurationMs)) { return false; } diff --git a/tests/unit/src/com/android/tv/recommendation/RoutineWatchEvaluatorTest.java b/tests/unit/src/com/android/tv/recommendation/RoutineWatchEvaluatorTest.java index 6cb0e08c..d9149050 100644 --- a/tests/unit/src/com/android/tv/recommendation/RoutineWatchEvaluatorTest.java +++ b/tests/unit/src/com/android/tv/recommendation/RoutineWatchEvaluatorTest.java @@ -17,22 +17,17 @@ package com.android.tv.recommendation; import static com.google.common.truth.Truth.assertThat; - import static org.junit.Assert.assertEquals; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; - -import com.android.tv.data.ProgramImpl; -import com.android.tv.data.api.Program; +import com.android.tv.data.Program; import com.android.tv.recommendation.RoutineWatchEvaluator.ProgramTime; - -import org.junit.Test; -import org.junit.runner.RunWith; - import java.util.Calendar; import java.util.List; import java.util.concurrent.TimeUnit; +import org.junit.Test; +import org.junit.runner.RunWith; /** Tests for {@link RoutineWatchEvaluator}. */ @SmallTest @@ -126,15 +121,15 @@ public class RoutineWatchEvaluatorTest extends EvaluatorTestCase<RoutineWatchEva @Test public void testCalculateTitleMatchScore_longerMatchIsBetter() { String base = "foo bar baz"; - assertThat( - new ScoredItem[] { - score(base, ""), - score(base, "bar"), - score(base, "foo bar"), - score(base, "foo bar baz") - }) - .asList() - .isInOrder(); + assertThat( + new ScoredItem[] { + score(base, ""), + score(base, "bar"), + score(base, "foo bar"), + score(base, "foo bar baz") + }) + .asList() + .isOrdered(); } @Test @@ -325,7 +320,7 @@ public class RoutineWatchEvaluatorTest extends EvaluatorTestCase<RoutineWatchEva private Program createDummyProgram(Calendar startTime, long programDurationMs) { long startTimeMs = startTime.getTimeInMillis(); - return new ProgramImpl.Builder() + return new Program.Builder() .setStartTimeUtcMillis(startTimeMs) .setEndTimeUtcMillis(startTimeMs + programDurationMs) .build(); diff --git a/tests/unit/src/com/android/tv/util/MockTvSingletons.java b/tests/unit/src/com/android/tv/util/MockTvSingletons.java index d9ff5e71..fd4b43cf 100644 --- a/tests/unit/src/com/android/tv/util/MockTvSingletons.java +++ b/tests/unit/src/com/android/tv/util/MockTvSingletons.java @@ -17,15 +17,16 @@ package com.android.tv.util; import android.content.Context; - 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.common.experiments.ExperimentLoader; import com.android.tv.common.flags.impl.DefaultBackendKnobsFlags; import com.android.tv.common.flags.impl.DefaultCloudEpgFlags; +import com.android.tv.common.flags.impl.DefaultConcurrentDvrPlaybackFlags; import com.android.tv.common.flags.impl.DefaultUiFlags; import com.android.tv.common.recording.RecordingStorageStatusManager; import com.android.tv.common.singletons.HasSingletons; @@ -33,6 +34,7 @@ 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; @@ -40,14 +42,11 @@ 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.testing.fakes.FakeClock; +import com.android.tv.testing.FakeClock; import com.android.tv.tunerinputcontroller.BuiltInTunerManager; - import com.google.common.base.Optional; - -import dagger.Lazy; - import java.util.concurrent.Executor; +import javax.inject.Provider; /** Mock {@link TvSingletons} class. */ public class MockTvSingletons implements TvSingletons, HasSingletons<TvSingletons> { @@ -57,6 +56,8 @@ public class MockTvSingletons implements TvSingletons, HasSingletons<TvSingleton private final DefaultBackendKnobsFlags mBackendFlags = new DefaultBackendKnobsFlags(); private final DefaultCloudEpgFlags mCloudEpgFlags = new DefaultCloudEpgFlags(); private final DefaultUiFlags mUiFlags = new DefaultUiFlags(); + private final DefaultConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags = + new DefaultConcurrentDvrPlaybackFlags(); private PerformanceMonitor mPerformanceMonitor; public MockTvSingletons(Context context) { @@ -77,11 +78,21 @@ public class MockTvSingletons implements TvSingletons, HasSingletons<TvSingleton } @Override + public boolean isChannelDataManagerLoadFinished() { + return mApp.isChannelDataManagerLoadFinished(); + } + + @Override public ProgramDataManager getProgramDataManager() { return mApp.getProgramDataManager(); } @Override + public boolean isProgramDataManagerCurrentProgramsLoadFinished() { + return mApp.isProgramDataManagerCurrentProgramsLoadFinished(); + } + + @Override public PreviewDataManager getPreviewDataManager() { return mApp.getPreviewDataManager(); } @@ -137,11 +148,16 @@ public class MockTvSingletons implements TvSingletons, HasSingletons<TvSingleton } @Override - public Lazy<EpgReader> providesEpgReader() { + public Provider<EpgReader> providesEpgReader() { return mApp.providesEpgReader(); } @Override + public EpgFetcher getEpgFetcher() { + return mApp.getEpgFetcher(); + } + + @Override public SetupUtils getSetupUtils() { return mApp.getSetupUtils(); } @@ -152,11 +168,21 @@ public class MockTvSingletons implements TvSingletons, HasSingletons<TvSingleton } @Override + public ExperimentLoader getExperimentLoader() { + return mApp.getExperimentLoader(); + } + + @Override public MainActivityWrapper getMainActivityWrapper() { return mApp.getMainActivityWrapper(); } @Override + public com.android.tv.util.account.AccountHelper getAccountHelper() { + return mApp.getAccountHelper(); + } + + @Override public boolean isRunningInMainProcess() { return mApp.isRunningInMainProcess(); } @@ -196,6 +222,11 @@ public class MockTvSingletons implements TvSingletons, HasSingletons<TvSingleton } @Override + public DefaultConcurrentDvrPlaybackFlags getConcurrentDvrPlaybackFlags() { + return mConcurrentDvrPlaybackFlags; + } + + @Override public TvSingletons singletons() { return this; } diff --git a/tests/unit/src/com/android/tv/util/TvInputManagerHelperTest.java b/tests/unit/src/com/android/tv/util/TvInputManagerHelperTest.java index ab3c5e79..7e35d76b 100644 --- a/tests/unit/src/com/android/tv/util/TvInputManagerHelperTest.java +++ b/tests/unit/src/com/android/tv/util/TvInputManagerHelperTest.java @@ -20,24 +20,19 @@ import static androidx.test.InstrumentationRegistry.getContext; import android.content.pm.ResolveInfo; import android.media.tv.TvInputInfo; - import androidx.test.filters.SmallTest; import androidx.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.ArgumentMatchers; 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} */ @SmallTest @RunWith(AndroidJUnit4.class) @@ -92,13 +87,13 @@ public class TvInputManagerHelperTest { TvInputManagerHelper manager = createMockTvInputManager(); - ComparatorTester comparatorTester = - new ComparatorTester(new TvInputManagerHelper.InputComparatorInternal(manager)) - .permitInconsistencyWithEquals(); + ComparatorTester<TvInputInfo> comparatorTester = + ComparatorTester.withoutEqualsTest( + new TvInputManagerHelper.InputComparatorInternal(manager)); for (TvInputInfo input : inputs) { - comparatorTester.addEqualityGroup(input); + comparatorTester.addComparableGroup(input); } - comparatorTester.testCompare(); + comparatorTester.test(); } @Test @@ -148,17 +143,15 @@ public class TvInputManagerHelperTest { TvInputManagerHelper manager = createMockTvInputManager(); - ComparatorTester comparatorTester = - new ComparatorTester( - new TvInputManagerHelper.HardwareInputComparator( - getContext(), manager)) - .permitInconsistencyWithEquals(); + ComparatorTester<TvInputInfo> comparatorTester = + ComparatorTester.withoutEqualsTest( + new TvInputManagerHelper.HardwareInputComparator(getContext(), manager)); comparatorTester - .addEqualityGroup(hdmi3) - .addEqualityGroup(hdmi2) - .addEqualityGroup(hdmi1) - .addEqualityGroup(hdmi4) - .testCompare(); + .addComparableGroup(hdmi3) + .addComparableGroup(hdmi2) + .addComparableGroup(hdmi1) + .addComparableGroup(hdmi4) + .test(); } @Test @@ -209,12 +202,10 @@ public class TvInputManagerHelperTest { TvInputManagerHelper manager = createMockTvInputManager(); - ComparatorTester comparatorTester = - new ComparatorTester( - new TvInputManagerHelper.HardwareInputComparator( - getContext(), manager)) - .permitInconsistencyWithEquals(); - comparatorTester.addEqualityGroup(cec1).addEqualityGroup(cec2).testCompare(); + ComparatorTester<TvInputInfo> comparatorTester = + ComparatorTester.withoutEqualsTest( + new TvInputManagerHelper.HardwareInputComparator(getContext(), manager)); + comparatorTester.addComparableGroup(cec1).addComparableGroup(cec2).test(); } private TvInputManagerHelper createMockTvInputManager() { @@ -228,7 +219,7 @@ public class TvInputManagerHelperTest { } }) .when(manager) - .isPartnerInput(ArgumentMatchers.<TvInputInfo>any()); + .isPartnerInput(Mockito.<TvInputInfo>any()); Mockito.doAnswer( new Answer<String>() { @Override @@ -238,7 +229,7 @@ public class TvInputManagerHelperTest { } }) .when(manager) - .loadLabel(ArgumentMatchers.<TvInputInfo>any()); + .loadLabel(Mockito.<TvInputInfo>any()); Mockito.doAnswer( new Answer<String>() { @Override @@ -248,7 +239,7 @@ public class TvInputManagerHelperTest { } }) .when(manager) - .loadCustomLabel(ArgumentMatchers.<TvInputInfo>any()); + .loadCustomLabel(Mockito.<TvInputInfo>any()); Mockito.doAnswer( new Answer<TvInputInfo>() { @Override @@ -260,7 +251,7 @@ public class TvInputManagerHelperTest { } }) .when(manager) - .getTvInputInfo(ArgumentMatchers.<String>any()); + .getTvInputInfo(Mockito.<String>any()); return manager; } diff --git a/tests/unit/src/com/android/tv/util/images/ImageCacheTest.java b/tests/unit/src/com/android/tv/util/images/ImageCacheTest.java index 6e968249..41722135 100644 --- a/tests/unit/src/com/android/tv/util/images/ImageCacheTest.java +++ b/tests/unit/src/com/android/tv/util/images/ImageCacheTest.java @@ -52,28 +52,28 @@ public class ImageCacheTest { public void testPutIfLarger_smaller() throws Exception { mImageCache.putIfNeeded(INFO_50); - assertWithMessage("before").that(mImageCache.get(KEY)).isSameInstanceAs(INFO_50); + assertWithMessage("before").that(mImageCache.get(KEY)).isSameAs(INFO_50); mImageCache.putIfNeeded(INFO_25); - assertWithMessage("after").that(mImageCache.get(KEY)).isSameInstanceAs(INFO_50); + assertWithMessage("after").that(mImageCache.get(KEY)).isSameAs(INFO_50); } @Test public void testPutIfLarger_larger() throws Exception { mImageCache.putIfNeeded(INFO_50); - assertWithMessage("before").that(mImageCache.get(KEY)).isSameInstanceAs(INFO_50); + assertWithMessage("before").that(mImageCache.get(KEY)).isSameAs(INFO_50); mImageCache.putIfNeeded(INFO_100); - assertWithMessage("after").that(mImageCache.get(KEY)).isSameInstanceAs(INFO_100); + assertWithMessage("after").that(mImageCache.get(KEY)).isSameAs(INFO_100); } @Test public void testPutIfLarger_alreadyMax() throws Exception { mImageCache.putIfNeeded(INFO_100); - assertWithMessage("before").that(mImageCache.get(KEY)).isSameInstanceAs(INFO_100); + assertWithMessage("before").that(mImageCache.get(KEY)).isSameAs(INFO_100); mImageCache.putIfNeeded(INFO_200); - assertWithMessage("after").that(mImageCache.get(KEY)).isSameInstanceAs(INFO_100); + assertWithMessage("after").that(mImageCache.get(KEY)).isSameAs(INFO_100); } } diff --git a/tuner/Android.bp b/tuner/Android.bp index d1df99fc..215a1e53 100644 --- a/tuner/Android.bp +++ b/tuner/Android.bp @@ -20,25 +20,25 @@ android_library { sdk_version: "system_current", resource_dirs: ["res"], libs: [ - "android-support-annotations", - "android-support-compat", - "android-support-core-ui", - "android-support-v7-palette", - "android-support-v7-recyclerview", - "androidx.leanback_leanback", - "androidx.tvprovider_tvprovider", - "jsr330", - "live-tv-tuner-proto", "tv-auto-value-jar", "tv-auto-factory-jar", - "tv-common", + "android-support-annotations", "tv-error-prone-annotations-jar", "tv-guava-android-jar", "tv-javax-annotations-jar", + "jsr330", "tv-lib-dagger", "tv-lib-exoplayer", "tv-lib-exoplayer-v2-core", + "live-tv-tuner-proto", + "android-support-compat", + "android-support-core-ui", + "android-support-v7-palette", + "android-support-v7-recyclerview", + "android-support-v17-leanback", + "androidx.tvprovider_tvprovider", "tv-lib-dagger-android", + "tv-common", ], plugins: [ "tv-auto-value", diff --git a/tuner/AndroidManifest.xml b/tuner/AndroidManifest.xml index c084f3fc..fd217717 100644 --- a/tuner/AndroidManifest.xml +++ b/tuner/AndroidManifest.xml @@ -18,7 +18,7 @@ xmlns:tools="http://schemas.android.com/tools" package="com.android.tv.tuner" android:versionCode="1"> - <uses-sdk android:targetSdkVersion="28" android:minSdkVersion="23"/> + <uses-sdk android:targetSdkVersion="27" android:minSdkVersion="23"/> <application tools:replace="android:appComponentFactory" android:appComponentFactory="android.support.v4.app.CoreComponentFactory" /> </manifest> diff --git a/tuner/SampleDvbTuner/AndroidManifest.xml b/tuner/SampleDvbTuner/AndroidManifest.xml index da23f84a..5ad927e3 100755 --- a/tuner/SampleDvbTuner/AndroidManifest.xml +++ b/tuner/SampleDvbTuner/AndroidManifest.xml @@ -19,7 +19,7 @@ <uses-sdk android:minSdkVersion="23" - android:targetSdkVersion="28" /> + android:targetSdkVersion="27" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> @@ -29,8 +29,6 @@ <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA" /> <uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" /> - <!-- Permission to modify Recorded Program --> - <uses-permission android:name="com.android.providers.tv.permission.ACCESS_ALL_EPG_DATA" /> <!-- Permissions/feature for USB tuner --> <uses-permission android:name="android.permission.DVB_DEVICE" /> diff --git a/tuner/SampleDvbTuner/build.gradle b/tuner/SampleDvbTuner/build.gradle index 28ad3e4a..657a4258 100644 --- a/tuner/SampleDvbTuner/build.gradle +++ b/tuner/SampleDvbTuner/build.gradle @@ -19,35 +19,48 @@ * Experimental gradle configuration. This file may not be up to date. */ +buildscript { + repositories { + mavenCentral() + google() + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:3.1.4' + classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.5' + } +} apply plugin: 'com.android.application' apply plugin: 'com.google.protobuf' - android { - compileSdkVersion 28 - buildToolsVersion '28.0.3' + compileSdkVersion 26 + buildToolsVersion '28.0.2' - compileOptions() { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + dexOptions { + preDexLibraries = false + additionalParameters=['--core-library'] + javaMaxHeapSize "6g" + } + android { + defaultConfig { + resConfigs "en" + } } - defaultConfig { minSdkVersion 23 - resConfigs "en" - targetSdkVersion 28 + targetSdkVersion 26 versionCode 1 versionName "1.0" } - buildTypes { debug { minifyEnabled false } - release { - minifyEnabled true - } } - + compileOptions() { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } sourceSets { main { res.srcDirs = ['res'] @@ -57,18 +70,22 @@ android { } } -dependencies { - implementation 'androidx.leanback:leanback:1.1.0-alpha02' - implementation 'androidx.palette:palette:1.0.0' - implementation 'androidx.tvprovider:tvprovider:1.0.0' - - annotationProcessor 'com.google.auto.value:auto-value:1.5.3' - implementation 'com.google.auto.value:auto-value:1.5.3' - implementation 'com.google.dagger:dagger:2.23' - implementation 'com.google.dagger:dagger-android:2.23' - annotationProcessor 'com.google.dagger:dagger-android-processor:2.23' - annotationProcessor 'com.google.dagger:dagger-compiler:2.23' +repositories { + mavenCentral() + jcenter() + google() +} - implementation project(':common') - implementation project(':tuner') +final String SUPPORT_LIBS_VERSION = '26.1.0' +dependencies { + implementation 'com.google.android.exoplayer:exoplayer-core:2.9.0' + implementation 'com.google.android.exoplayer:exoplayer:r1.5.16' + implementation "com.android.support:palette-v7:${SUPPORT_LIBS_VERSION}" + implementation "com.android.support:leanback-v17:${SUPPORT_LIBS_VERSION}" + implementation "com.android.support:support-tv-provider:${SUPPORT_LIBS_VERSION}" + /*Not building with latest one (1.6.2)*/ + annotationProcessor 'com.google.auto.value:auto-value:1.5.4' + implementation 'com.google.auto.value:auto-value:1.5.4' + implementation project(':common') + implementation project(':tuner') } diff --git a/tuner/SampleDvbTuner/robotests/javatests/com/android/tv/tuner/sample/dvb/util/SampleDvbConstantsTest.java b/tuner/SampleDvbTuner/robotests/javatests/com/android/tv/tuner/sample/dvb/util/SampleDvbConstantsTest.java deleted file mode 100644 index 52fcffd6..00000000 --- a/tuner/SampleDvbTuner/robotests/javatests/com/android/tv/tuner/sample/dvb/util/SampleDvbConstantsTest.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2019 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.tuner.sample.dvb.util; - -import static com.google.common.truth.Truth.assertThat; - -import android.content.ComponentName; - -import androidx.test.core.app.ApplicationProvider; - -import com.android.tv.testing.constants.ConfigConstants; -import com.android.tv.tuner.sample.dvb.tvinput.SampleDvbTunerTvInputService; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -/** Tests for {@link SampleDvbConstants}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class SampleDvbConstantsTest { - - @Test - public void tunerInputId() { - assertThat(ComponentName.unflattenFromString(SampleDvbConstants.TUNER_INPUT_ID)) - .isEqualTo( - new ComponentName( - ApplicationProvider.getApplicationContext(), - SampleDvbTunerTvInputService.class)); - } -} diff --git a/tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/AndroidManifest.xml b/tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/AndroidManifest.xml index 8732b0d8..dc042286 100644 --- a/tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/AndroidManifest.xml +++ b/tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/AndroidManifest.xml @@ -27,8 +27,6 @@ <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA" /> <uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" /> - <!-- Permission to modify Recorded Program --> - <uses-permission android:name="com.android.providers.tv.permission.ACCESS_ALL_EPG_DATA" /> <!-- Permissions/feature for USB tuner --> <uses-permission android:name="android.permission.DVB_DEVICE" /> @@ -38,7 +36,7 @@ <uses-feature android:name="android.software.leanback" android:required="true" /> <uses-feature android:name="android.software.live_tv" android:required="true" /> <uses-feature android:name="android.hardware.touchscreen" android:required="false"/> - <uses-sdk android:targetSdkVersion="28" android:minSdkVersion="23"/> + <uses-sdk android:targetSdkVersion="27" android:minSdkVersion="23"/> <application android:name=".app.SampleDvbTuner" android:icon="@mipmap/ic_launcher" diff --git a/tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/app/SampleDvbTuner.java b/tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/app/SampleDvbTuner.java index 5c9e8420..568e3c98 100644 --- a/tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/app/SampleDvbTuner.java +++ b/tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/app/SampleDvbTuner.java @@ -18,18 +18,16 @@ package com.android.tv.tuner.sample.dvb.app; import android.content.ComponentName; import android.media.tv.TvContract; - import com.android.tv.common.BaseApplication; -import com.android.tv.common.dagger.ApplicationModule; import com.android.tv.common.singletons.HasSingletons; import com.android.tv.tuner.modules.TunerSingletonsModule; import com.android.tv.tuner.sample.dvb.singletons.SampleDvbSingletons; import com.android.tv.tuner.sample.dvb.tvinput.SampleDvbTunerTvInputService; - +import com.android.tv.tuner.tvinput.factory.TunerSessionFactory; +import com.android.tv.tuner.tvinput.factory.TunerSessionFactoryImpl; import dagger.android.AndroidInjector; - import com.android.tv.common.flags.CloudEpgFlags; - +import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags; import javax.inject.Inject; /** The top level application for Sample DVB Tuner. */ @@ -38,6 +36,8 @@ public class SampleDvbTuner extends BaseApplication private String mEmbeddedInputId; @Inject CloudEpgFlags mCloudEpgFlags; + @Inject ConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags; + @Inject TunerSessionFactoryImpl mTunerSessionFactory; @Override public void onCreate() { @@ -47,7 +47,7 @@ public class SampleDvbTuner extends BaseApplication @Override protected AndroidInjector<SampleDvbTuner> applicationInjector() { return DaggerSampleDvbTunerComponent.builder() - .applicationModule(new ApplicationModule(this)) + .sampleDvbTunerModule(new SampleDvbTunerModule(this)) .tunerSingletonsModule(new TunerSingletonsModule(this)) .build(); } @@ -73,7 +73,16 @@ public class SampleDvbTuner extends BaseApplication } @Override + public ConcurrentDvrPlaybackFlags getConcurrentDvrPlaybackFlags() { + return mConcurrentDvrPlaybackFlags; + } + + @Override public SampleDvbSingletons singletons() { return this; } + + public TunerSessionFactory getTunerSessionFactory() { + return mTunerSessionFactory; + } } diff --git a/tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/app/SampleDvbTunerModule.java b/tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/app/SampleDvbTunerModule.java index aaaa1011..4da3ca9d 100644 --- a/tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/app/SampleDvbTunerModule.java +++ b/tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/app/SampleDvbTunerModule.java @@ -15,30 +15,38 @@ */ package com.android.tv.tuner.sample.dvb.app; -import com.android.tv.common.dagger.ApplicationModule; import com.android.tv.common.flags.impl.DefaultFlagsModule; import com.android.tv.tuner.api.TunerFactory; -import com.android.tv.tuner.dvb.DvbTunerHalFactory; +import com.android.tv.tuner.builtin.BuiltInTunerHalFactory; import com.android.tv.tuner.modules.TunerModule; import com.android.tv.tuner.sample.dvb.setup.SampleDvbTunerSetupActivity; import com.android.tv.tuner.sample.dvb.tvinput.SampleDvbTunerTvInputService; - +import com.android.tv.tuner.tvinput.factory.TunerSessionFactory; import dagger.Module; import dagger.Provides; /** Dagger module for {@link SampleDvbTuner}. */ @Module( includes = { - ApplicationModule.class, DefaultFlagsModule.class, SampleDvbTunerTvInputService.Module.class, SampleDvbTunerSetupActivity.Module.class, TunerModule.class, }) class SampleDvbTunerModule { + private final SampleDvbTuner mSampleDvbTuner; + + SampleDvbTunerModule(SampleDvbTuner sampleDvbTuner) { + mSampleDvbTuner = sampleDvbTuner; + } + + @Provides + public TunerSessionFactory providesTunerSessionFactory() { + return mSampleDvbTuner.getTunerSessionFactory(); + } @Provides TunerFactory providesTunerFactory() { - return DvbTunerHalFactory.INSTANCE; + return BuiltInTunerHalFactory.INSTANCE; } } diff --git a/tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/setup/SampleDvbTunerSetupActivity.java b/tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/setup/SampleDvbTunerSetupActivity.java index e2b5063c..f9ef29c4 100644 --- a/tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/setup/SampleDvbTunerSetupActivity.java +++ b/tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/setup/SampleDvbTunerSetupActivity.java @@ -36,7 +36,6 @@ import com.android.tv.common.ui.setup.SetupFragment; import com.android.tv.common.ui.setup.SetupMultiPaneFragment; import com.android.tv.common.util.PostalCodeUtils; import com.android.tv.tuner.sample.dvb.R; -import com.android.tv.tuner.sample.dvb.util.SampleDvbConstants; import com.android.tv.tuner.setup.BaseTunerSetupActivity; import com.android.tv.tuner.setup.ConnectionTypeFragment; import com.android.tv.tuner.setup.LineupFragment; @@ -56,7 +55,7 @@ import dagger.android.ContributesAndroidInjector; import java.util.ArrayList; import java.util.List; -/** An activity that serves Sample DVB tuner setup process. */ +/** An activity that serves Live TV tuner setup process. */ public class SampleDvbTunerSetupActivity extends BaseTunerSetupActivity { private static final String TAG = "SampleDvbTunerSetupActivity"; private static final boolean DEBUG = false; @@ -79,10 +78,6 @@ public class SampleDvbTunerSetupActivity extends BaseTunerSetupActivity { private final Runnable cancelFetchLineupTaskRunnable = this::cancelFetchLineup; private String embeddedInputId; - public SampleDvbTunerSetupActivity() { - super(SampleDvbConstants.TUNER_INPUT_ID); - } - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -198,7 +193,6 @@ public class SampleDvbTunerSetupActivity extends BaseTunerSetupActivity { case ScanFragment.ACTION_CATEGORY: switch (actionId) { case ScanFragment.ACTION_CANCEL: - clearTunerHal(); getFragmentManager().popBackStack(); return true; case ScanFragment.ACTION_FINISH: diff --git a/tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/util/SampleDvbConstants.java b/tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/util/SampleDvbConstants.java deleted file mode 100644 index f7b34cef..00000000 --- a/tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/util/SampleDvbConstants.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2019 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.tuner.sample.dvb.util; - -/** Static constants for Sample DVB Tuner */ -public final class SampleDvbConstants { - - /** The Input ID for the embedded tuner in Sample DVB Tuner */ - public static final String TUNER_INPUT_ID = - "com.android.tv.tuner.sample.dvb/.tvinput.SampleDvbTunerTvInputService"; - - private SampleDvbConstants() {} -} diff --git a/tuner/SampleNetworkTuner/AndroidManifest.xml b/tuner/SampleNetworkTuner/AndroidManifest.xml index 22b03567..0ec9afca 100755 --- a/tuner/SampleNetworkTuner/AndroidManifest.xml +++ b/tuner/SampleNetworkTuner/AndroidManifest.xml @@ -19,19 +19,16 @@ <uses-sdk android:minSdkVersion="23" - android:targetSdkVersion="28" /> + android:targetSdkVersion="27" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> - <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.READ_CONTENT_RATING_SYSTEMS" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_TV_LISTINGS" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA" /> <uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" /> - <!-- Permission to modify Recorded Program --> - <uses-permission android:name="com.android.providers.tv.permission.ACCESS_ALL_EPG_DATA" /> <!-- Permissions/feature for USB tuner --> <uses-permission android:name="android.permission.DVB_DEVICE" /> diff --git a/tuner/SampleNetworkTuner/build.gradle b/tuner/SampleNetworkTuner/build.gradle index 28ad3e4a..657a4258 100644 --- a/tuner/SampleNetworkTuner/build.gradle +++ b/tuner/SampleNetworkTuner/build.gradle @@ -19,35 +19,48 @@ * Experimental gradle configuration. This file may not be up to date. */ +buildscript { + repositories { + mavenCentral() + google() + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:3.1.4' + classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.5' + } +} apply plugin: 'com.android.application' apply plugin: 'com.google.protobuf' - android { - compileSdkVersion 28 - buildToolsVersion '28.0.3' + compileSdkVersion 26 + buildToolsVersion '28.0.2' - compileOptions() { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + dexOptions { + preDexLibraries = false + additionalParameters=['--core-library'] + javaMaxHeapSize "6g" + } + android { + defaultConfig { + resConfigs "en" + } } - defaultConfig { minSdkVersion 23 - resConfigs "en" - targetSdkVersion 28 + targetSdkVersion 26 versionCode 1 versionName "1.0" } - buildTypes { debug { minifyEnabled false } - release { - minifyEnabled true - } } - + compileOptions() { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } sourceSets { main { res.srcDirs = ['res'] @@ -57,18 +70,22 @@ android { } } -dependencies { - implementation 'androidx.leanback:leanback:1.1.0-alpha02' - implementation 'androidx.palette:palette:1.0.0' - implementation 'androidx.tvprovider:tvprovider:1.0.0' - - annotationProcessor 'com.google.auto.value:auto-value:1.5.3' - implementation 'com.google.auto.value:auto-value:1.5.3' - implementation 'com.google.dagger:dagger:2.23' - implementation 'com.google.dagger:dagger-android:2.23' - annotationProcessor 'com.google.dagger:dagger-android-processor:2.23' - annotationProcessor 'com.google.dagger:dagger-compiler:2.23' +repositories { + mavenCentral() + jcenter() + google() +} - implementation project(':common') - implementation project(':tuner') +final String SUPPORT_LIBS_VERSION = '26.1.0' +dependencies { + implementation 'com.google.android.exoplayer:exoplayer-core:2.9.0' + implementation 'com.google.android.exoplayer:exoplayer:r1.5.16' + implementation "com.android.support:palette-v7:${SUPPORT_LIBS_VERSION}" + implementation "com.android.support:leanback-v17:${SUPPORT_LIBS_VERSION}" + implementation "com.android.support:support-tv-provider:${SUPPORT_LIBS_VERSION}" + /*Not building with latest one (1.6.2)*/ + annotationProcessor 'com.google.auto.value:auto-value:1.5.4' + implementation 'com.google.auto.value:auto-value:1.5.4' + implementation project(':common') + implementation project(':tuner') } diff --git a/tuner/SampleNetworkTuner/robotests/javatests/com/android/tv/tuner/sample/network/util/SampleNetworkConstantsTest.java b/tuner/SampleNetworkTuner/robotests/javatests/com/android/tv/tuner/sample/network/util/SampleNetworkConstantsTest.java deleted file mode 100644 index 5c860ef0..00000000 --- a/tuner/SampleNetworkTuner/robotests/javatests/com/android/tv/tuner/sample/network/util/SampleNetworkConstantsTest.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2019 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.tuner.sample.network.util; - -import static com.google.common.truth.Truth.assertThat; - -import android.content.ComponentName; - -import androidx.test.core.app.ApplicationProvider; - -import com.android.tv.testing.constants.ConfigConstants; -import com.android.tv.tuner.sample.network.tvinput.SampleNetworkTunerTvInputService; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -/** Tests for {@link SampleNetworkConstants}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class SampleNetworkConstantsTest { - - @Test - public void tunerInputId() { - assertThat(ComponentName.unflattenFromString(SampleNetworkConstants.TUNER_INPUT_ID)) - .isEqualTo( - new ComponentName( - ApplicationProvider.getApplicationContext(), - SampleNetworkTunerTvInputService.class)); - } -} diff --git a/tuner/SampleNetworkTuner/src/com/android/tv/tuner/sample/network/AndroidManifest.xml b/tuner/SampleNetworkTuner/src/com/android/tv/tuner/sample/network/AndroidManifest.xml index 73313917..dddd8a4b 100644 --- a/tuner/SampleNetworkTuner/src/com/android/tv/tuner/sample/network/AndroidManifest.xml +++ b/tuner/SampleNetworkTuner/src/com/android/tv/tuner/sample/network/AndroidManifest.xml @@ -21,15 +21,12 @@ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> - <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.READ_CONTENT_RATING_SYSTEMS" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_TV_LISTINGS" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA" /> <uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" /> - <!-- Permission to modify Recorded Program --> - <uses-permission android:name="com.android.providers.tv.permission.ACCESS_ALL_EPG_DATA" /> <!-- Permissions/feature for USB tuner --> <uses-permission android:name="android.permission.DVB_DEVICE" /> @@ -39,7 +36,7 @@ <uses-feature android:name="android.software.leanback" android:required="true" /> <uses-feature android:name="android.software.live_tv" android:required="true" /> <uses-feature android:name="android.hardware.touchscreen" android:required="false"/> - <uses-sdk android:targetSdkVersion="28" android:minSdkVersion="23"/> + <uses-sdk android:targetSdkVersion="27" android:minSdkVersion="23"/> <application android:name=".app.SampleNetworkTuner" android:icon="@mipmap/ic_launcher" diff --git a/tuner/SampleNetworkTuner/src/com/android/tv/tuner/sample/network/app/SampleNetworkTuner.java b/tuner/SampleNetworkTuner/src/com/android/tv/tuner/sample/network/app/SampleNetworkTuner.java index 0f9d24e6..eb5b2ad4 100644 --- a/tuner/SampleNetworkTuner/src/com/android/tv/tuner/sample/network/app/SampleNetworkTuner.java +++ b/tuner/SampleNetworkTuner/src/com/android/tv/tuner/sample/network/app/SampleNetworkTuner.java @@ -18,18 +18,16 @@ package com.android.tv.tuner.sample.network.app; import android.content.ComponentName; import android.media.tv.TvContract; - import com.android.tv.common.BaseApplication; -import com.android.tv.common.dagger.ApplicationModule; import com.android.tv.common.singletons.HasSingletons; import com.android.tv.tuner.modules.TunerSingletonsModule; import com.android.tv.tuner.sample.network.singletons.SampleNetworkSingletons; import com.android.tv.tuner.sample.network.tvinput.SampleNetworkTunerTvInputService; - +import com.android.tv.tuner.tvinput.factory.TunerSessionFactory; +import com.android.tv.tuner.tvinput.factory.TunerSessionFactoryImpl; import dagger.android.AndroidInjector; - import com.android.tv.common.flags.CloudEpgFlags; - +import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags; import javax.inject.Inject; /** The top level application for Sample DVB Tuner. */ @@ -38,6 +36,8 @@ public class SampleNetworkTuner extends BaseApplication private String mEmbeddedInputId; @Inject CloudEpgFlags mCloudEpgFlags; + @Inject ConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags; + @Inject TunerSessionFactoryImpl mTunerSessionFactory; @Override public void onCreate() { @@ -47,7 +47,7 @@ public class SampleNetworkTuner extends BaseApplication @Override protected AndroidInjector<SampleNetworkTuner> applicationInjector() { return DaggerSampleNetworkTunerComponent.builder() - .applicationModule(new ApplicationModule(this)) + .sampleNetworkTunerModule(new SampleNetworkTunerModule(this)) .tunerSingletonsModule(new TunerSingletonsModule(this)) .build(); } @@ -73,7 +73,16 @@ public class SampleNetworkTuner extends BaseApplication } @Override + public ConcurrentDvrPlaybackFlags getConcurrentDvrPlaybackFlags() { + return mConcurrentDvrPlaybackFlags; + } + + @Override public SampleNetworkSingletons singletons() { return this; } + + public TunerSessionFactory getTunerSessionFactory() { + return mTunerSessionFactory; + } } diff --git a/tuner/SampleNetworkTuner/src/com/android/tv/tuner/sample/network/app/SampleNetworkTunerModule.java b/tuner/SampleNetworkTuner/src/com/android/tv/tuner/sample/network/app/SampleNetworkTunerModule.java index 3fa45027..d974e20a 100644 --- a/tuner/SampleNetworkTuner/src/com/android/tv/tuner/sample/network/app/SampleNetworkTunerModule.java +++ b/tuner/SampleNetworkTuner/src/com/android/tv/tuner/sample/network/app/SampleNetworkTunerModule.java @@ -15,30 +15,38 @@ */ package com.android.tv.tuner.sample.network.app; -import com.android.tv.common.dagger.ApplicationModule; import com.android.tv.common.flags.impl.DefaultFlagsModule; import com.android.tv.tuner.api.TunerFactory; -import com.android.tv.tuner.hdhomerun.HdHomeRunTunerHalFactory; +import com.android.tv.tuner.builtin.BuiltInTunerHalFactory; import com.android.tv.tuner.modules.TunerModule; import com.android.tv.tuner.sample.network.setup.SampleNetworkTunerSetupActivity; import com.android.tv.tuner.sample.network.tvinput.SampleNetworkTunerTvInputService; - +import com.android.tv.tuner.tvinput.factory.TunerSessionFactory; import dagger.Module; import dagger.Provides; /** Dagger module for {@link SampleNetworkTuner}. */ @Module( includes = { - ApplicationModule.class, DefaultFlagsModule.class, SampleNetworkTunerTvInputService.Module.class, SampleNetworkTunerSetupActivity.Module.class, TunerModule.class, }) class SampleNetworkTunerModule { + private final SampleNetworkTuner mSampleNetworkTuner; + + SampleNetworkTunerModule(SampleNetworkTuner sampleNetworkTuner) { + mSampleNetworkTuner = sampleNetworkTuner; + } + + @Provides + public TunerSessionFactory providesTunerSessionFactory() { + return mSampleNetworkTuner.getTunerSessionFactory(); + } @Provides TunerFactory providesTunerFactory() { - return HdHomeRunTunerHalFactory.INSTANCE; + return BuiltInTunerHalFactory.INSTANCE; } } diff --git a/tuner/SampleNetworkTuner/src/com/android/tv/tuner/sample/network/setup/SampleNetworkTunerSetupActivity.java b/tuner/SampleNetworkTuner/src/com/android/tv/tuner/sample/network/setup/SampleNetworkTunerSetupActivity.java index 755e0bb9..fd783c4f 100644 --- a/tuner/SampleNetworkTuner/src/com/android/tv/tuner/sample/network/setup/SampleNetworkTunerSetupActivity.java +++ b/tuner/SampleNetworkTuner/src/com/android/tv/tuner/sample/network/setup/SampleNetworkTunerSetupActivity.java @@ -36,7 +36,6 @@ import com.android.tv.common.ui.setup.SetupFragment; import com.android.tv.common.ui.setup.SetupMultiPaneFragment; import com.android.tv.common.util.PostalCodeUtils; import com.android.tv.tuner.sample.network.R; -import com.android.tv.tuner.sample.network.util.SampleNetworkConstants; import com.android.tv.tuner.setup.BaseTunerSetupActivity; import com.android.tv.tuner.setup.ConnectionTypeFragment; import com.android.tv.tuner.setup.LineupFragment; @@ -56,7 +55,7 @@ import dagger.android.ContributesAndroidInjector; import java.util.ArrayList; import java.util.List; -/** An activity that serves TV app tuner setup process. */ +/** An activity that serves Live TV tuner setup process. */ public class SampleNetworkTunerSetupActivity extends BaseTunerSetupActivity { private static final String TAG = "SampleNetworkTunerSetupActivity"; private static final boolean DEBUG = false; @@ -79,10 +78,6 @@ public class SampleNetworkTunerSetupActivity extends BaseTunerSetupActivity { private final Runnable cancelFetchLineupTaskRunnable = this::cancelFetchLineup; private String embeddedInputId; - public SampleNetworkTunerSetupActivity() { - super(SampleNetworkConstants.TUNER_INPUT_ID); - } - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/tuner/SampleNetworkTuner/src/com/android/tv/tuner/sample/network/util/SampleNetworkConstants.java b/tuner/SampleNetworkTuner/src/com/android/tv/tuner/sample/network/util/SampleNetworkConstants.java deleted file mode 100644 index d0a8d254..00000000 --- a/tuner/SampleNetworkTuner/src/com/android/tv/tuner/sample/network/util/SampleNetworkConstants.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2019 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.tuner.sample.network.util; - -/** Static constants for Sample Network Tuner */ -public final class SampleNetworkConstants { - - /** The Input ID for the embedded tuner in Sample Network Tuner */ - public static final String TUNER_INPUT_ID = - "com.android.tv.tuner.sample.network/.tvinput.SampleNetworkTunerTvInputService"; - - private SampleNetworkConstants() {} -} diff --git a/tuner/build.gradle b/tuner/build.gradle index b00b4609..0f40a29b 100644 --- a/tuner/build.gradle +++ b/tuner/build.gradle @@ -21,24 +21,39 @@ apply plugin: 'com.android.library' apply plugin: 'com.google.protobuf' - +buildscript { + repositories { + mavenCentral() + google() + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:3.1.4' + classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.5' + } +} android { - compileSdkVersion 28 - buildToolsVersion '28.0.3' + compileSdkVersion 26 + buildToolsVersion '28.0.2' - compileOptions() { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + dexOptions { + preDexLibraries = false + additionalParameters = ['--core-library'] + javaMaxHeapSize "6g" + } + + android { + defaultConfig { + resConfigs "en" + } } defaultConfig { minSdkVersion 23 - resConfigs "en" - targetSdkVersion 28 + targetSdkVersion 26 versionCode 1 versionName "1.0" } - buildTypes { debug { minifyEnabled false @@ -47,6 +62,10 @@ android { minifyEnabled true } } + compileOptions() { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } sourceSets { main { @@ -54,54 +73,43 @@ android { java.srcDirs = ['src'] manifest.srcFile 'AndroidManifest.xml' proto { - srcDir 'proto/src/main/proto' + srcDir 'proto/' } } } } -dependencies { - implementation 'androidx.annotation:annotation:1.1.0' - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.leanback:leanback:1.1.0-alpha02' - implementation 'androidx.recyclerview:recyclerview:1.0.0' - implementation 'androidx.recyclerview:recyclerview-selection:1.0.0' - implementation 'androidx.tvprovider:tvprovider:1.0.0' - - implementation 'com.google.android.exoplayer:exoplayer:r1.5.16' - api 'com.google.android.exoplayer:exoplayer-core:2.10.1' - annotationProcessor 'com.google.auto.factory:auto-factory:1.0-beta6' - implementation 'com.google.auto.factory:auto-factory:1.0-beta6' - implementation 'com.google.dagger:dagger:2.23' - implementation 'com.google.dagger:dagger-android:2.23' - annotationProcessor 'com.google.dagger:dagger-android-processor:2.23' - annotationProcessor 'com.google.dagger:dagger-compiler:2.23' - implementation 'com.google.guava:guava:28.0-jre' - implementation 'com.google.protobuf:protobuf-java:3.0.0' +repositories { + mavenCentral() + google() + jcenter() +} - implementation project(':common') +final String SUPPORT_LIBS_VERSION = '26.1.0' +dependencies { + implementation 'com.google.android.exoplayer:exoplayer-core:2.9.0' + implementation 'com.google.android.exoplayer:exoplayer:r1.5.16' + implementation "com.android.support:support-tv-provider:${SUPPORT_LIBS_VERSION}" + implementation "com.android.support:appcompat-v7:${SUPPORT_LIBS_VERSION}" + implementation "com.android.support:leanback-v17:${SUPPORT_LIBS_VERSION}" + implementation 'com.google.guava:guava:26.0-android' + implementation 'com.google.protobuf.nano:protobuf-javanano:3.2.0rc2' + implementation project(':common') } protobuf { // Configure the protoc executable protoc { - artifact = 'com.google.protobuf:protoc:3.0.0' - - plugins { - javalite { - // The codegen for lite comes as a separate artifact - artifact = 'com.google.protobuf:protoc-gen-javalite:3.0.0' - } - } + artifact = 'com.google.protobuf:protoc:3.1.0' generateProtoTasks { all().each { task -> task.builtins { remove java - } - task.plugins { - javalite {} + javanano { + option "enum_style=java" } + } } } } -} +}
\ No newline at end of file diff --git a/tuner/proto/Android.bp b/tuner/proto/Android.bp index d1728a64..67f35f82 100644 --- a/tuner/proto/Android.bp +++ b/tuner/proto/Android.bp @@ -19,7 +19,8 @@ java_library { srcs: ["*.proto"], sdk_version: "system_current", proto: { - type: "lite", + type: "nano", + output_params: ["enum_style=java"], canonical_path_from_root: false, }, min_sdk_version: "23", diff --git a/tuner/proto/channel.proto b/tuner/proto/channel.proto index 815ffbca..ff372ad5 100644 --- a/tuner/proto/channel.proto +++ b/tuner/proto/channel.proto @@ -18,13 +18,18 @@ syntax = 'proto2'; package com.android.tv.tuner.data; -import "track.proto"; - option java_package = "com.android.tv.tuner.data"; option java_outer_classname = "Channel"; + +// AOSP_Comment_Out import "third_party/android/nanoproto/nano_descriptor.proto"; + +import "track.proto"; + // Holds information about a channel used in the tuners. message TunerChannelProto { +// AOSP_Comment_Out option (proto2.nano.message_as_lite) = false; + optional TunerType type = 1; optional string short_name = 2; optional string long_name = 3; @@ -46,24 +51,22 @@ message TunerChannelProto { optional int32 audio_track_index = 19; repeated AtscCaptionTrack caption_tracks = 20; optional bool has_caption_track = 21; - optional AtscServiceType service_type = 22 - [default = SERVICE_TYPE_ATSC_DIGITAL_TELEVISION]; + optional AtscServiceType service_type = 22 [default = SERVICE_TYPE_ATSC_DIGITAL_TELEVISION]; optional bool recording_prohibited = 23; optional string video_format = 24; /** * The flag indicating whether this TV channel is locked or not. - * This is primarily used for alternative parental control to prevent - * unauthorized users from watching the current channel regardless of the - * content rating - * @see <a - * href="https://developer.android.com/reference/android/media/tv/TvContract.Channels.html#COLUMN_LOCKED">link</a> + * This is primarily used for alternative parental control to prevent unauthorized users from + * watching the current channel regardless of the content rating + * @see <a href="https://developer.android.com/reference/android/media/tv/TvContract.Channels.html#COLUMN_LOCKED">link</a> */ optional bool locked = 25; - optional DeliverySystemType delivery_system_type = 26; } // Enum describing the types of tuner. enum TunerType { +// AOSP_Comment_Out option (proto2.nano.enum_as_lite) = false; + TYPE_TUNER = 0; TYPE_FILE = 1; TYPE_NETWORK = 2; @@ -71,10 +74,8 @@ enum TunerType { // Enum describing the types of video stream. enum VideoStreamType { - // Default unset value. The spec says 0 is reserved. - UNSET = 0x00; - // DEPRECATED: previously used as default or unset value - INVALID_STREAMTYPE = -1 [deprecated=true]; +// AOSP_Comment_Out option (proto2.nano.enum_as_lite) = false; + // ISO/IEC 11172 Video (MPEG-1) MPEG1 = 0x01; // ISO/IEC 13818-2 (MPEG-2) Video @@ -89,6 +90,8 @@ enum VideoStreamType { // Enum describing the types of audio stream. enum AudioStreamType { +// AOSP_Comment_Out option (proto2.nano.enum_as_lite) = false; + // ISO/IEC 11172 Audio (MPEG-1) MPEG1AUDIO = 0x03; // ISO/IEC 13818-3 Audio (MPEG-2) @@ -106,6 +109,8 @@ enum AudioStreamType { // Enum describing ATSC service types // See ATSC Code Points Registry. enum AtscServiceType { +// AOSP_Comment_Out option (proto2.nano.enum_as_lite) = false; + SERVICE_TYPE_ATSC_RESERVED = 0x0; SERVICE_TYPE_ANALOG_TELEVISION_CHANNELS = 0x1; SERVICE_TYPE_ATSC_DIGITAL_TELEVISION = 0x2; @@ -117,15 +122,3 @@ enum AtscServiceType { SERVICE_TYPE_ATSC_NRT_SERVICE = 0x8; SERVICE_TYPE_EXTENDED_PARAMERTERIZED_SERVICE = 0x9; } - -// Enum describing the types of delivery system. -enum DeliverySystemType { - // Do not reorder. Must match Tuner.java - DELIVERY_SYSTEM_UNDEFINED = 0; - DELIVERY_SYSTEM_ATSC = 1; - DELIVERY_SYSTEM_DVBC = 2; - DELIVERY_SYSTEM_DVBS = 3; - DELIVERY_SYSTEM_DVBS2 = 4; - DELIVERY_SYSTEM_DVBT = 5; - DELIVERY_SYSTEM_DVBT2 = 6; -} diff --git a/tuner/proto/track.proto b/tuner/proto/track.proto index a4a20dbc..11ca784d 100644 --- a/tuner/proto/track.proto +++ b/tuner/proto/track.proto @@ -18,11 +18,15 @@ syntax = "proto2"; package com.android.tv.tuner.data; +// AOSP_Comment_Out import "third_party/android/nanoproto/nano_descriptor.proto"; + option java_package = "com.android.tv.tuner.data"; option java_outer_classname = "Track"; // Represents a AC3 audio track. message AtscAudioTrack { +// AOSP_Comment_Out option (proto2.nano.message_as_lite) = false; + optional string language = 1; optional AudioType audio_type = 2; optional int32 index = 3; @@ -32,6 +36,8 @@ message AtscAudioTrack { // Enum describing the types of a audio track. // See ISO/IEC 138181-1:2000(e) Table 2-53. enum AudioType { +// AOSP_Comment_Out option (proto2.nano.enum_as_lite) = false; + AUDIOTYPE_UNDEFINED = 0; AUDIOTYPE_CLEAN_EFFECTS = 1; AUDIOTYPE_HEARING_IMPAIRED = 2; @@ -41,8 +47,11 @@ message AtscAudioTrack { // Represents a CEA-708 caption track. message AtscCaptionTrack { +// AOSP_Comment_Out option (proto2.nano.message_as_lite) = false; + optional string language = 1; optional int32 service_number = 2; optional bool easy_reader = 3; optional bool wide_aspect_ratio = 4; } + diff --git a/tuner/res/layout/guided_action_editable.xml b/tuner/res/layout/guided_action_editable.xml index 4d3c87fd..84f56f8d 100644 --- a/tuner/res/layout/guided_action_editable.xml +++ b/tuner/res/layout/guided_action_editable.xml @@ -15,13 +15,13 @@ ~ limitations under the License. --> -<androidx.leanback.widget.GuidedActionItemContainer +<android.support.v17.leanback.widget.GuidedActionItemContainer xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/guidedactions_editable" style="?attr/guidedActionItemContainerStyle" android:layout_height="88dp"> - <androidx.leanback.widget.NonOverlappingLinearLayout + <android.support.v17.leanback.widget.NonOverlappingLinearLayout android:id="@+id/guidedactions_item_content" style="?attr/guidedActionItemContentStyle" > @@ -32,10 +32,10 @@ android:textColor="@color/lb_guidedactions_item_unselected_text_color" android:textSize="16sp" /> - <androidx.leanback.widget.GuidedActionEditText + <android.support.v17.leanback.widget.GuidedActionEditText android:id="@+id/guidedactions_item_description" style="?attr/guidedActionItemDescriptionStyle" /> - </androidx.leanback.widget.NonOverlappingLinearLayout> + </android.support.v17.leanback.widget.NonOverlappingLinearLayout> -</androidx.leanback.widget.GuidedActionItemContainer>
\ No newline at end of file +</android.support.v17.leanback.widget.GuidedActionItemContainer>
\ No newline at end of file diff --git a/tuner/res/raw/ut_euro_dvbt_all b/tuner/res/raw/ut_euro_dvbt_all index a2ff03b2..101ee3eb 100644 --- a/tuner/res/raw/ut_euro_dvbt_all +++ b/tuner/res/raw/ut_euro_dvbt_all @@ -1,6 +1,66 @@ # Euro DVB-T frequencies # Only Germany and England frequencies are added now. +# Frequencies from Germany +T 474000000 QAM16 +T 474000000 QAM64 +T 482000000 QAM16 +T 490000000 QAM16 +T 498000000 QAM16 +T 498000000 QAM64 +T 506000000 QAM16 +T 506000000 QAM64 +T 514000000 QAM16 +T 522000000 QAM16 +T 522000000 QAM64 +T 530000000 QAM16 +T 538000000 QAM16 +T 538000000 QAM64 +T 546000000 QAM16 +T 554000000 QAM16 +T 554000000 QAM64 +T 562000000 QAM16 +T 562000000 QAM64 +T 570000000 QAM16 +T 578000000 QAM16 +T 578000000 QAM64 +T 586000000 QAM16 +T 594000000 QAM16 +T 602000000 QAM16 +T 602000000 QAM64 +T 610000000 QAM16 +T 610000000 QAM64 +T 618000000 QAM16 +T 618000000 QAM64 +T 626000000 QAM16 +T 634000000 QAM16 +T 634000000 QAM64 +T 642000000 QAM16 +T 650000000 QAM16 +T 658000000 QAM16 +T 666000000 QAM16 +T 674000000 QAM16 +T 674000000 QAM64 +T 682000000 QAM16 +T 690000000 QAM16 +T 690000000 QAM64 +T 698000000 QAM16 +T 698000000 QAM64 +T 706000000 QAM16 +T 722000000 QAM16 +T 730000000 QAM16 +T 730000000 QAM64 +T 738000000 QAM16 +T 738000000 QAM64 +T 746000000 QAM16 +T 746000000 QPSK +T 754000000 QAM16 +T 762000000 QAM16 +T 770000000 QAM16 +T 778000000 QAM16 +T 786000000 QAM16 + +# Frequencies from England T 474000000 QAM16 T 474000000 QAM64 T 474167000 QAM16 @@ -70,7 +130,6 @@ T 562000000 QAM64 T 562167000 QAM16 T 569833000 QAM64 T 570000000 QAM16 -T 570000000 QAM64 T 570167000 QAM16 T 577833000 QAM16 T 578000000 QAM16 @@ -79,9 +138,7 @@ T 578166670 QAM16 T 578167000 QAM16 T 578167000 QAM64 T 586000000 QAM16 -T 586000000 QAM256 T 594000000 QAM16 -T 594000000 QAM64 T 602000000 QAM16 T 602000000 QAM64 T 610000000 QAM16 @@ -167,13 +224,11 @@ T 745833000 QAM64 T 746000000 QAM16 T 746000000 QAM64 T 746000000 QPSK -T 746000000 QAM256 T 746167000 QAM64 T 753833000 QAM16 T 753833000 QAM64 T 754000000 QAM16 T 754000000 QAM64 -T 754000000 QAM256 T 754167000 QAM16 T 761833000 QAM16 T 761833000 QAM64 diff --git a/tuner/src/com/android/tv/tuner/dvb/DvbDeviceAccessor.java b/tuner/src/com/android/tv/tuner/DvbDeviceAccessor.java index 8be27c91..217433d2 100644 --- a/tuner/src/com/android/tv/tuner/dvb/DvbDeviceAccessor.java +++ b/tuner/src/com/android/tv/tuner/DvbDeviceAccessor.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.tv.tuner.dvb; +package com.android.tv.tuner; import android.content.Context; import android.media.tv.TvInputManager; diff --git a/tuner/src/com/android/tv/tuner/dvb/DvbTunerHal.java b/tuner/src/com/android/tv/tuner/DvbTunerHal.java index 7f68e379..c802ebbb 100644 --- a/tuner/src/com/android/tv/tuner/dvb/DvbTunerHal.java +++ b/tuner/src/com/android/tv/tuner/DvbTunerHal.java @@ -14,14 +14,13 @@ * limitations under the License. */ -package com.android.tv.tuner.dvb; +package com.android.tv.tuner; import android.content.Context; import android.os.ParcelFileDescriptor; import android.util.Log; import com.android.tv.common.compat.TvInputConstantCompat; -import com.android.tv.tuner.TunerHal; -import com.android.tv.tuner.dvb.DvbDeviceAccessor.DvbDeviceInfoWrapper; +import com.android.tv.tuner.DvbDeviceAccessor.DvbDeviceInfoWrapper; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; diff --git a/tuner/src/com/android/tv/tuner/TunerHal.java b/tuner/src/com/android/tv/tuner/TunerHal.java index 3f469d60..dce4f4c4 100644 --- a/tuner/src/com/android/tv/tuner/TunerHal.java +++ b/tuner/src/com/android/tv/tuner/TunerHal.java @@ -36,7 +36,6 @@ public abstract class TunerHal implements Tuner { private static final int DEFAULT_QAM_TUNE_TIMEOUT_MS = 4000; // Some device takes time for @DeliverySystemType private int mDeliverySystemType; - @DeliverySystemType private int[] mDeliverySystemTypes; private boolean mIsStreaming; private int mFrequency; private String mModulation; @@ -58,16 +57,9 @@ public abstract class TunerHal implements Tuner { } protected void getDeliverySystemTypeFromDevice() { - getDeliverySystemTypesFromDevice(); - } - - protected void getDeliverySystemTypesFromDevice() { if (mDeliverySystemType == DELIVERY_SYSTEM_UNDEFINED) { mDeliverySystemType = nativeGetDeliverySystemType(getDeviceId()); } - if (mDeliverySystemTypes == null) { - mDeliverySystemTypes = nativeGetDeliverySystemTypes(getDeviceId()); - } } /** @@ -87,34 +79,18 @@ public abstract class TunerHal implements Tuner { protected native void nativeFinalize(long deviceId); - @Override - public synchronized boolean tune( - int frequency, @ModulationType String modulation, - String channelNumber) { - return tuneInternal(mDeliverySystemType, frequency, modulation, channelNumber); - } - - @Override - public synchronized boolean tune( - int deliverySystemType, int frequency, @ModulationType String modulation, - String channelNumber) { - return tuneInternal(deliverySystemType, frequency, modulation, channelNumber); - } - /** * Sets the tuner channel. This should be called after acquiring a tuner device. * - * @param deliverySystemType a system delivery type of the channel to tune to * @param frequency a frequency of the channel to tune to * @param modulation a modulation method of the channel to tune to * @param channelNumber channel number when channel number is already known. Some tuner HAL may * use channelNumber instead of frequency for tune. * @return {@code true} if the operation was successful, {@code false} otherwise */ - protected boolean tuneInternal( - int deliverySystemType, int frequency, @ModulationType String modulation, - String channelNumber) { - + @Override + public synchronized boolean tune( + int frequency, @ModulationType String modulation, String channelNumber) { if (!isDeviceOpen()) { Log.e(TAG, "There's no available device"); return false; @@ -123,76 +99,40 @@ public abstract class TunerHal implements Tuner { nativeCloseAllPidFilters(getDeviceId()); mIsStreaming = false; } - if (mDeliverySystemTypes != null) { - int i; - for (i = 0; i < mDeliverySystemTypes.length; i++) { - if (deliverySystemType == mDeliverySystemTypes[i]) { - break; - } - } - - if (i == mDeliverySystemTypes.length) { - Log.e(TAG, "Unsupported delivery system type for device"); - return false; - } - } // When tuning to a new channel in the same frequency, there's no need to stop current tuner // device completely and the only thing necessary for tuning is reopening pid filters. if (mFrequency == frequency && Objects.equals(mModulation, modulation)) { addPidFilter(PID_PAT, FILTER_TYPE_OTHER); addPidFilter(PID_ATSC_SI_BASE, FILTER_TYPE_OTHER); - if (Tuner.isDvbDeliverySystem(deliverySystemType)) { + if (Tuner.isDvbDeliverySystem(mDeliverySystemType)) { addPidFilter(PID_DVB_SDT, FILTER_TYPE_OTHER); addPidFilter(PID_DVB_EIT, FILTER_TYPE_OTHER); } mIsStreaming = true; return true; } - int timeout_ms = modulation.equals(MODULATION_8VSB) ? DEFAULT_VSB_TUNE_TIMEOUT_MS : DEFAULT_QAM_TUNE_TIMEOUT_MS; - - boolean tuneStatus; - switch(deliverySystemType) { - case DELIVERY_SYSTEM_UNDEFINED: - case DELIVERY_SYSTEM_ATSC: - tuneStatus = nativeTune(getDeviceId(), frequency, modulation, timeout_ms); - break; - case DELIVERY_SYSTEM_DVBT: - case DELIVERY_SYSTEM_DVBT2: - tuneStatus = nativeTune(getDeviceId(), deliverySystemType, frequency, modulation, - timeout_ms); - break; - default: - Log.e(TAG, "Unsupported delivery system type for device"); - return false; - } - - if (tuneStatus == true) { + if (nativeTune(getDeviceId(), frequency, modulation, timeout_ms)) { addPidFilter(PID_PAT, FILTER_TYPE_OTHER); addPidFilter(PID_ATSC_SI_BASE, FILTER_TYPE_OTHER); - if (Tuner.isDvbDeliverySystem(deliverySystemType)) { + if (Tuner.isDvbDeliverySystem(mDeliverySystemType)) { addPidFilter(PID_DVB_SDT, FILTER_TYPE_OTHER); addPidFilter(PID_DVB_EIT, FILTER_TYPE_OTHER); } mFrequency = frequency; mModulation = modulation; mIsStreaming = true; + return true; } - - return tuneStatus; + return false; } protected native boolean nativeTune( - long deviceId, int frequency, - @ModulationType String modulation, int timeout_ms); - - protected native boolean nativeTune( - long deviceId, int deliverySystemType, int frequency, - @ModulationType String modulation, int timeout_ms); + long deviceId, int frequency, @ModulationType String modulation, int timeout_ms); /** * Sets a pid filter. This should be set after setting a channel. @@ -222,8 +162,6 @@ public abstract class TunerHal implements Tuner { protected native int nativeGetDeliverySystemType(long deviceId); - protected native int[] nativeGetDeliverySystemTypes(long deviceId); - protected native int nativeGetSignalStrength(long deviceId); /** @@ -253,11 +191,6 @@ public abstract class TunerHal implements Tuner { return mDeliverySystemType; } - @Override - public int[] getDeliverySystemTypes() { - return mDeliverySystemTypes; - } - protected native void nativeStopTune(long deviceId); /** diff --git a/tuner/src/com/android/tv/tuner/api/ScanChannel.java b/tuner/src/com/android/tv/tuner/api/ScanChannel.java index 1c7a6e79..56e5493c 100644 --- a/tuner/src/com/android/tv/tuner/api/ScanChannel.java +++ b/tuner/src/com/android/tv/tuner/api/ScanChannel.java @@ -15,15 +15,11 @@ */ package com.android.tv.tuner.api; -import android.util.Log; -import com.android.tv.tuner.data.Channel; - +import com.android.tv.tuner.data.nano.Channel; /** Channel information gathered from a <em>scan</em> */ public final class ScanChannel { - private static final String TAG = "ScanChannel"; public final int type; - public final Channel.DeliverySystemType deliverySystemType; public final int frequency; public final String modulation; public final String filename; @@ -35,60 +31,25 @@ public final class ScanChannel { public final Integer radioFrequencyNumber; public static ScanChannel forTuner( - String deliverySystemType, int frequency, String modulation, - Integer radioFrequencyNumber) { + int frequency, String modulation, Integer radioFrequencyNumber) { return new ScanChannel( - Channel.TunerType.TYPE_TUNER_VALUE, lookupDeliveryStringToInt(deliverySystemType), - frequency, modulation, null, radioFrequencyNumber); + Channel.TunerType.TYPE_TUNER, frequency, modulation, null, radioFrequencyNumber); } public static ScanChannel forFile(int frequency, String filename) { - return new ScanChannel(Channel.TunerType.TYPE_FILE_VALUE, - Channel.DeliverySystemType.DELIVERY_SYSTEM_UNDEFINED, frequency, "file:", - filename, null); + return new ScanChannel(Channel.TunerType.TYPE_FILE, frequency, "file:", filename, null); } private ScanChannel( int type, - Channel.DeliverySystemType deliverySystemType, int frequency, String modulation, String filename, Integer radioFrequencyNumber) { this.type = type; - this.deliverySystemType = deliverySystemType; this.frequency = frequency; this.modulation = modulation; this.filename = filename; this.radioFrequencyNumber = radioFrequencyNumber; } - - private static Channel.DeliverySystemType lookupDeliveryStringToInt(String deliverySystemType) { - Channel.DeliverySystemType ret; - switch (deliverySystemType) { - case "A": - ret = Channel.DeliverySystemType.DELIVERY_SYSTEM_ATSC; - break; - case "C": - ret = Channel.DeliverySystemType.DELIVERY_SYSTEM_DVBC; - break; - case "S": - ret = Channel.DeliverySystemType.DELIVERY_SYSTEM_DVBS; - break; - case "S2": - ret = Channel.DeliverySystemType.DELIVERY_SYSTEM_DVBS2; - break; - case "T": - ret = Channel.DeliverySystemType.DELIVERY_SYSTEM_DVBT; - break; - case "T2": - ret = Channel.DeliverySystemType.DELIVERY_SYSTEM_DVBT2; - break; - default: - Log.e(TAG, "Unknown delivery system type"); - ret = Channel.DeliverySystemType.DELIVERY_SYSTEM_UNDEFINED; - break; - } - return ret; - } } diff --git a/tuner/src/com/android/tv/tuner/api/Tuner.java b/tuner/src/com/android/tv/tuner/api/Tuner.java index 02df3ca1..6f7e9d94 100644 --- a/tuner/src/com/android/tv/tuner/api/Tuner.java +++ b/tuner/src/com/android/tv/tuner/api/Tuner.java @@ -28,8 +28,6 @@ public interface Tuner extends AutoCloseable { int FILTER_TYPE_VIDEO = 2; int FILTER_TYPE_PCR = 3; String MODULATION_8VSB = "8VSB"; - String MODULATION_QAM16 = "QAM16"; - String MODULATION_QAM64 = "QAM64"; String MODULATION_QAM256 = "QAM256"; int DELIVERY_SYSTEM_UNDEFINED = 0; int DELIVERY_SYSTEM_ATSC = 1; @@ -42,7 +40,6 @@ public interface Tuner extends AutoCloseable { int TUNER_TYPE_USB = 2; int TUNER_TYPE_NETWORK = 3; int BUILT_IN_TUNER_TYPE_LINUX_DVB = 1; - int BUILT_IN_TUNER_TYPE_ARCHER = 100; /** Check a delivery system is for DVB or not. */ static boolean isDvbDeliverySystem(@DeliverySystemType int deliverySystemType) { @@ -69,11 +66,6 @@ public interface Tuner extends AutoCloseable { boolean tune(int frequency, @ModulationType String modulation, String channelNumber); - default boolean tune(@DeliverySystemType int deliverySystemType, int frequency, - @ModulationType String modulation, String channelNumber) { - return tune(frequency, modulation, channelNumber); - } - boolean addPidFilter(int pid, @FilterType int filterType); void stopTune(); @@ -81,10 +73,6 @@ public interface Tuner extends AutoCloseable { void setHasPendingTune(boolean hasPendingTune); int getDeliverySystemType(); - default int[] getDeliverySystemTypes() { - int[] deliverySystemTypes = {DELIVERY_SYSTEM_UNDEFINED}; - return deliverySystemTypes; - }; int readTsStream(byte[] javaBuffer, int javaBufferSize); @@ -96,7 +84,7 @@ public interface Tuner extends AutoCloseable { public @interface FilterType {} /** Modulation Type */ - @StringDef({MODULATION_8VSB, MODULATION_QAM256, MODULATION_QAM16, MODULATION_QAM64}) + @StringDef({MODULATION_8VSB, MODULATION_QAM256}) @Retention(RetentionPolicy.SOURCE) public @interface ModulationType {} @@ -120,7 +108,6 @@ public interface Tuner extends AutoCloseable { /** Built in tuner type */ @IntDef({ - BUILT_IN_TUNER_TYPE_ARCHER, BUILT_IN_TUNER_TYPE_LINUX_DVB }) @Retention(RetentionPolicy.SOURCE) diff --git a/tuner/src/com/android/tv/tuner/dvb/DvbTunerHalFactory.java b/tuner/src/com/android/tv/tuner/builtin/BuiltInTunerHalFactory.java index 24d7e1fc..9a0be740 100644 --- a/tuner/src/com/android/tv/tuner/dvb/DvbTunerHalFactory.java +++ b/tuner/src/com/android/tv/tuner/builtin/BuiltInTunerHalFactory.java @@ -14,29 +14,39 @@ * limitations under the License. */ -package com.android.tv.tuner.dvb; +package com.android.tv.tuner.builtin; import android.content.Context; import android.support.annotation.WorkerThread; import android.util.Log; import android.util.Pair; - +import com.android.tv.common.customization.CustomizationManager; +import com.android.tv.common.feature.Model; +import com.android.tv.tuner.DvbTunerHal; import com.android.tv.tuner.api.Tuner; import com.android.tv.tuner.api.TunerFactory; + /** TunerHal factory that creates all built in tuner types. */ -public final class DvbTunerHalFactory implements TunerFactory { - private static final String TAG = "DvbTunerHalFactory"; +public final class BuiltInTunerHalFactory implements TunerFactory { + private static final String TAG = "BuiltInTunerHalFactory"; private static final boolean DEBUG = false; - private final int mBuiltInTunerType = Tuner.BUILT_IN_TUNER_TYPE_LINUX_DVB; + private Integer mBuiltInTunerType; - public static final TunerFactory INSTANCE = new DvbTunerHalFactory(); + public static final TunerFactory INSTANCE = new BuiltInTunerHalFactory(); - private DvbTunerHalFactory() {} + private BuiltInTunerHalFactory() {} @Tuner.BuiltInTunerType private int getBuiltInTunerType(Context context) { + if (mBuiltInTunerType == null) { + mBuiltInTunerType = 0; + if (CustomizationManager.hasLinuxDvbBuiltInTuner(context) + && DvbTunerHal.getNumberOfDevices(context) > 0) { + mBuiltInTunerType = Tuner.BUILT_IN_TUNER_TYPE_LINUX_DVB; + } + } return mBuiltInTunerType; } @@ -70,6 +80,17 @@ public final class DvbTunerHalFactory implements TunerFactory { @Override @WorkerThread public Pair<Integer, Integer> getTunerTypeAndCount(Context context) { - return Pair.create(Tuner.TUNER_TYPE_BUILT_IN, DvbTunerHal.getNumberOfDevices(context)); + if (useBuiltInTuner(context)) { + if (getBuiltInTunerType(context) == Tuner.BUILT_IN_TUNER_TYPE_LINUX_DVB) { + return new Pair<>( + Tuner.TUNER_TYPE_BUILT_IN, DvbTunerHal.getNumberOfDevices(context)); + } + } else { + int usbTunerCount = DvbTunerHal.getNumberOfDevices(context); + if (usbTunerCount > 0) { + return new Pair<>(Tuner.TUNER_TYPE_USB, usbTunerCount); + } + } + return new Pair<>(null, 0); } } diff --git a/tuner/src/com/android/tv/tuner/cc/CaptionLayout.java b/tuner/src/com/android/tv/tuner/cc/CaptionLayout.java index 62a4e157..eb9ad463 100644 --- a/tuner/src/com/android/tv/tuner/cc/CaptionLayout.java +++ b/tuner/src/com/android/tv/tuner/cc/CaptionLayout.java @@ -18,7 +18,7 @@ package com.android.tv.tuner.cc; import android.content.Context; import android.util.AttributeSet; -import com.android.tv.tuner.data.Track.AtscCaptionTrack; +import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack; import com.android.tv.tuner.layout.ScaledLayout; /** diff --git a/tuner/src/com/android/tv/tuner/cc/CaptionTrackRenderer.java b/tuner/src/com/android/tv/tuner/cc/CaptionTrackRenderer.java index 75776d6a..4a1c7c1b 100644 --- a/tuner/src/com/android/tv/tuner/cc/CaptionTrackRenderer.java +++ b/tuner/src/com/android/tv/tuner/cc/CaptionTrackRenderer.java @@ -27,7 +27,7 @@ import com.android.tv.tuner.data.Cea708Data.CaptionPenLocation; import com.android.tv.tuner.data.Cea708Data.CaptionWindow; import com.android.tv.tuner.data.Cea708Data.CaptionWindowAttr; import com.android.tv.tuner.data.Cea708Parser; -import com.android.tv.tuner.data.Track.AtscCaptionTrack; +import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack; import java.util.ArrayList; /** Decodes and renders CEA-708. */ @@ -89,7 +89,7 @@ public class CaptionTrackRenderer implements Handler.Callback { return; } if (DEBUG) { - Log.d(TAG, "Start captionTrack " + captionTrack.getLanguage()); + Log.d(TAG, "Start captionTrack " + captionTrack.language); } reset(); mCaptionLayout.setCaptionTrack(captionTrack); diff --git a/tuner/src/com/android/tv/tuner/cc/CaptionWindowLayout.java b/tuner/src/com/android/tv/tuner/cc/CaptionWindowLayout.java index 8c699d55..13c6ff47 100644 --- a/tuner/src/com/android/tv/tuner/cc/CaptionWindowLayout.java +++ b/tuner/src/com/android/tv/tuner/cc/CaptionWindowLayout.java @@ -459,14 +459,14 @@ public class CaptionWindowLayout extends RelativeLayout implements View.OnLayout private boolean isKoreanLanguageTrack() { return mCaptionLayout != null && mCaptionLayout.getCaptionTrack() != null - && mCaptionLayout.getCaptionTrack().hasLanguage() - && "KOR".equalsIgnoreCase(mCaptionLayout.getCaptionTrack().getLanguage()); + && mCaptionLayout.getCaptionTrack().language != null + && "KOR".compareToIgnoreCase(mCaptionLayout.getCaptionTrack().language) == 0; } private boolean isWideAspectRatio() { return mCaptionLayout != null && mCaptionLayout.getCaptionTrack() != null - && mCaptionLayout.getCaptionTrack().getWideAspectRatio(); + && mCaptionLayout.getCaptionTrack().wideAspectRatio; } private void updateWidestChar() { diff --git a/tuner/src/com/android/tv/tuner/data/Cea708Parser.java b/tuner/src/com/android/tv/tuner/data/Cea708Parser.java index 7a5538c8..92834b27 100644 --- a/tuner/src/com/android/tv/tuner/data/Cea708Parser.java +++ b/tuner/src/com/android/tv/tuner/data/Cea708Parser.java @@ -138,7 +138,6 @@ public class Cea708Parser { private long mLastDiscoveryLaunchedMs = SystemClock.elapsedRealtime(); private int mCommand = 0; private int mListenServiceNumber = 0; - private int mDtvCcPacketCalculatedSize = 0; private boolean mDtvCcPacking = false; private boolean mFirstServiceNumberDiscovered; @@ -230,7 +229,6 @@ public class Cea708Parser { mBuffer.setLength(0); mDiscoveredNumBytes.clear(); mCommand = 0; - mDtvCcPacketCalculatedSize = 0; mDtvCcPacking = false; } @@ -286,33 +284,29 @@ public class Cea708Parser { for (int i = 0; i < ccPacket.ccCount; ++i) { boolean ccValid = (bytes[pos] & 0x04) != 0; int ccType = bytes[pos] & 0x03; + + // The dtvcc should be considered complete: + // - if either ccValid is set and ccType is 3 + // - or ccValid is clear and ccType is 2 or 3. if (ccValid) { - // The dtvcc should be considered complete: - // if ccType is 3 or if the packet size is reached. if (ccType == CC_TYPE_DTVCC_PACKET_START) { if (mDtvCcPacking) { parseDtvCcPacket(mDtvCcPacket.buffer(), mDtvCcPacket.length()); mDtvCcPacket.clear(); - mDtvCcPacketCalculatedSize = 0; } mDtvCcPacking = true; - int packetSize = bytes[pos + 1] & 0x3F; // last 6 bits - if (packetSize == 0) { - packetSize = DTVCC_MAX_PACKET_SIZE; - } - mDtvCcPacketCalculatedSize = packetSize * DTVCC_PACKET_SIZE_SCALE_FACTOR; mDtvCcPacket.append(bytes[pos + 1]); mDtvCcPacket.append(bytes[pos + 2]); } else if (mDtvCcPacking && ccType == CC_TYPE_DTVCC_PACKET_DATA) { mDtvCcPacket.append(bytes[pos + 1]); mDtvCcPacket.append(bytes[pos + 2]); } + } else { if ((ccType == CC_TYPE_DTVCC_PACKET_START || ccType == CC_TYPE_DTVCC_PACKET_DATA) - && mDtvCcPacking && mDtvCcPacket.length() == mDtvCcPacketCalculatedSize) { + && mDtvCcPacking) { mDtvCcPacking = false; parseDtvCcPacket(mDtvCcPacket.buffer(), mDtvCcPacket.length()); mDtvCcPacket.clear(); - mDtvCcPacketCalculatedSize = 0; } } pos += 3; diff --git a/tuner/src/com/android/tv/tuner/data/PsiData.java b/tuner/src/com/android/tv/tuner/data/PsiData.java index 74f16035..9b7c2e2c 100644 --- a/tuner/src/com/android/tv/tuner/data/PsiData.java +++ b/tuner/src/com/android/tv/tuner/data/PsiData.java @@ -16,8 +16,8 @@ package com.android.tv.tuner.data; -import com.android.tv.tuner.data.Track.AtscAudioTrack; -import com.android.tv.tuner.data.Track.AtscCaptionTrack; +import com.android.tv.tuner.data.nano.Track.AtscAudioTrack; +import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack; import java.util.List; /** Collection of MPEG PSI table items. */ diff --git a/tuner/src/com/android/tv/tuner/data/PsipData.java b/tuner/src/com/android/tv/tuner/data/PsipData.java index 108ce3f2..d4af0934 100644 --- a/tuner/src/com/android/tv/tuner/data/PsipData.java +++ b/tuner/src/com/android/tv/tuner/data/PsipData.java @@ -20,8 +20,8 @@ import android.support.annotation.NonNull; import android.text.TextUtils; import android.text.format.DateUtils; import com.android.tv.common.util.StringUtils; -import com.android.tv.tuner.data.Track.AtscAudioTrack; -import com.android.tv.tuner.data.Track.AtscCaptionTrack; +import com.android.tv.tuner.data.nano.Track.AtscAudioTrack; +import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack; import com.android.tv.tuner.util.ConvertUtils; import java.util.ArrayList; import java.util.HashMap; @@ -495,10 +495,10 @@ public class PsipData { public String toString() { return String.format( Locale.US, - "AC3 audio stream sampleRateCode: %d, bsid: %d, bitRateCode: %d, surroundMode:" - + " %d, bsmod: %d, numChannels: %d, fullSvc: %s, langCod: %d, langCod2:" - + " %d, mainId: %d, priority: %d, avcflags: %d, text: %s, language: %s," - + " language2: %s", + "AC3 audio stream sampleRateCode: %d, bsid: %d, bitRateCode: %d, " + + "surroundMode: %d, bsmod: %d, numChannels: %d, fullSvc: %s, langCod: %d, " + + "langCod2: %d, mainId: %d, priority: %d, avcflags: %d, text: %s, language: %s" + + ", language2: %s", mSampleRateCode, mBsid, mBitRateCode, @@ -832,7 +832,7 @@ public class PsipData { } ArrayList<String> languages = new ArrayList<>(); for (AtscAudioTrack audioTrack : mAudioTracks) { - languages.add(audioTrack.getLanguage()); + languages.add(audioTrack.language); } return TextUtils.join(",", languages); } diff --git a/tuner/src/com/android/tv/tuner/data/SectionParser.java b/tuner/src/com/android/tv/tuner/data/SectionParser.java index 3c16749e..d3dba6ba 100644 --- a/tuner/src/com/android/tv/tuner/data/SectionParser.java +++ b/tuner/src/com/android/tv/tuner/data/SectionParser.java @@ -24,8 +24,7 @@ import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; import android.util.SparseArray; -import com.android.tv.common.feature.Model; -import com.android.tv.tuner.data.Channel.AtscServiceType; + import com.android.tv.tuner.data.PsiData.PatItem; import com.android.tv.tuner.data.PsiData.PmtItem; import com.android.tv.tuner.data.PsipData.Ac3AudioDescriptor; @@ -46,8 +45,9 @@ import com.android.tv.tuner.data.PsipData.ServiceDescriptor; import com.android.tv.tuner.data.PsipData.ShortEventDescriptor; import com.android.tv.tuner.data.PsipData.TsDescriptor; import com.android.tv.tuner.data.PsipData.VctItem; -import com.android.tv.tuner.data.Track.AtscAudioTrack; -import com.android.tv.tuner.data.Track.AtscCaptionTrack; +import com.android.tv.tuner.data.nano.Channel; +import com.android.tv.tuner.data.nano.Track.AtscAudioTrack; +import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack; import com.android.tv.tuner.util.ByteArrayBuffer; import com.android.tv.tuner.util.ConvertUtils; import java.io.UnsupportedEncodingException; @@ -105,7 +105,7 @@ public class SectionParser { private static final int RATING_REGION_US_TV = 1; private static final int RATING_REGION_KR_TV = 4; - // The following values are defined in the TV app. + // The following values are defined in the live channels app. // See https://developer.android.com/reference/android/media/tv/TvContentRating.html. private static final String RATING_DOMAIN = "com.android.tv"; private static final String RATING_REGION_RATING_SYSTEM_US_TV = "US_TV"; @@ -916,8 +916,8 @@ public class SectionParser { Log.d( TAG, String.format( - "Found channel [%s] %s - serviceType: %d tsid: 0x%x program: %d" - + " channel: %d-%d encrypted: %b hidden: %b, descriptors: %d", + "Found channel [%s] %s - serviceType: %d tsid: 0x%x program: %d " + + "channel: %d-%d encrypted: %b hidden: %b, descriptors: %d", shortName, longName, serviceType, @@ -929,14 +929,14 @@ public class SectionParser { hidden, descriptors.size())); } - if ((serviceType == AtscServiceType.SERVICE_TYPE_ATSC_AUDIO_VALUE + if (!accessControlled + && !hidden + && (serviceType == Channel.AtscServiceType.SERVICE_TYPE_ATSC_AUDIO || serviceType - == AtscServiceType.SERVICE_TYPE_ATSC_DIGITAL_TELEVISION_VALUE + == Channel.AtscServiceType.SERVICE_TYPE_ATSC_DIGITAL_TELEVISION || serviceType - == AtscServiceType - .SERVICE_TYPE_UNASSOCIATED_SMALL_SCREEN_SERVICE_VALUE) - && !accessControlled - && !hidden) { + == Channel.AtscServiceType + .SERVICE_TYPE_UNASSOCIATED_SMALL_SCREEN_SERVICE)) { // Hide hidden, encrypted, or unsupported ATSC service type channels results.add( new VctItem( @@ -1212,20 +1212,16 @@ public class SectionParser { for (TsDescriptor descriptor : descriptors) { if (descriptor instanceof Ac3AudioDescriptor) { Ac3AudioDescriptor audioDescriptor = (Ac3AudioDescriptor) descriptor; - String language = null; + AtscAudioTrack audioTrack = new AtscAudioTrack(); if (audioDescriptor.getLanguage() != null) { - language = audioDescriptor.getLanguage(); + audioTrack.language = audioDescriptor.getLanguage(); } - if (language == null) { - language = ""; + if (audioTrack.language == null) { + audioTrack.language = ""; } - AtscAudioTrack audioTrack = - AtscAudioTrack.newBuilder() - .setLanguage(language) - .setAudioType(AtscAudioTrack.AudioType.AUDIOTYPE_UNDEFINED) - .setChannelCount(audioDescriptor.getNumChannels()) - .setSampleRate(audioDescriptor.getSampleRate()) - .build(); + audioTrack.audioType = AtscAudioTrack.AudioType.AUDIOTYPE_UNDEFINED; + audioTrack.channelCount = audioDescriptor.getNumChannels(); + audioTrack.sampleRate = audioDescriptor.getSampleRate(); ac3Tracks.add(audioTrack); } } @@ -1258,27 +1254,26 @@ public class SectionParser { } int size = Math.max(ac3Tracks.size(), iso639LanguageTracks.size()); for (int i = 0; i < size; ++i) { - AtscAudioTrack.Builder audioTrack = null; + AtscAudioTrack audioTrack = null; if (i < ac3Tracks.size()) { - audioTrack = ac3Tracks.get(i).toBuilder(); + audioTrack = ac3Tracks.get(i); } if (i < iso639LanguageTracks.size()) { if (audioTrack == null) { - audioTrack = iso639LanguageTracks.get(i).toBuilder(); + audioTrack = iso639LanguageTracks.get(i); } else { AtscAudioTrack iso639LanguageTrack = iso639LanguageTracks.get(i); - if (!audioTrack.hasLanguage() - || TextUtils.equals(audioTrack.getLanguage(), "")) { - audioTrack.setLanguage(iso639LanguageTrack.getLanguage()); + if (audioTrack.language == null || TextUtils.equals(audioTrack.language, "")) { + audioTrack.language = iso639LanguageTrack.language; } - audioTrack.setAudioType(iso639LanguageTrack.getAudioType()); + audioTrack.audioType = iso639LanguageTrack.audioType; } } - String language = ISO_LANGUAGE_CODE_MAP.get(audioTrack.getLanguage()); + String language = ISO_LANGUAGE_CODE_MAP.get(audioTrack.language); if (language != null) { - audioTrack = audioTrack.setLanguage(language); + audioTrack.language = language; } - tracks.add(audioTrack.build()); + tracks.add(audioTrack); } return tracks; } @@ -1597,16 +1592,10 @@ public class SectionParser { return null; } String language = new String(data, pos, 3); - int audioTypeInt = data[pos + 3] & 0xff; - AtscAudioTrack.AudioType audioType = AtscAudioTrack.AudioType.forNumber(audioTypeInt); - if (audioType == null) { - audioType = AtscAudioTrack.AudioType.AUDIOTYPE_UNDEFINED; - } - AtscAudioTrack audioTrack = - AtscAudioTrack.newBuilder() - .setLanguage(language) - .setAudioType(audioType) - .build(); + int audioType = data[pos + 3] & 0xff; + AtscAudioTrack audioTrack = new AtscAudioTrack(); + audioTrack.language = language; + audioTrack.audioType = audioType; audioTracks.add(audioTrack); pos += 4; } @@ -1645,13 +1634,11 @@ public class SectionParser { reserved[0] |= (byte) ((data[pos + 1] & 0xc0) >>> 6); reserved[1] = (byte) ((data[pos + 1] & 0x3f) << 2); pos += 2; - AtscCaptionTrack captionTrack = - AtscCaptionTrack.newBuilder() - .setLanguage(language) - .setServiceNumber(captionServiceNumber) - .setEasyReader(easyReader) - .setWideAspectRatio(wideAspectRatio) - .build(); + AtscCaptionTrack captionTrack = new AtscCaptionTrack(); + captionTrack.language = language; + captionTrack.serviceNumber = captionServiceNumber; + captionTrack.easyReader = easyReader; + captionTrack.wideAspectRatio = wideAspectRatio; services.add(captionTrack); } return new CaptionServiceDescriptor(services); @@ -2088,11 +2075,6 @@ public class SectionParser { } private static boolean checkSanity(byte[] data) { - // Skipping CRC checking on Archer since TS data here was modified without updating CRC - // value. For details, see b/28616908. - if (Model.ARCHER.isEnabled()) { - return true; - } if (data.length <= 1) { return false; } diff --git a/tuner/src/com/android/tv/tuner/data/TunerChannel.java b/tuner/src/com/android/tv/tuner/data/TunerChannel.java index 5872cd55..d20c343b 100644 --- a/tuner/src/com/android/tv/tuner/data/TunerChannel.java +++ b/tuner/src/com/android/tv/tuner/data/TunerChannel.java @@ -20,10 +20,12 @@ import android.database.Cursor; import android.support.annotation.NonNull; import android.util.Log; import com.android.tv.common.util.StringUtils; -import com.android.tv.tuner.data.Channel.DeliverySystemType; -import com.android.tv.tuner.data.Channel.TunerChannelProto; -import com.android.tv.tuner.data.Track.AtscAudioTrack; -import com.android.tv.tuner.data.Track.AtscCaptionTrack; +import com.android.tv.tuner.data.nano.Channel; +import com.android.tv.tuner.data.nano.Channel.TunerChannelProto; +import com.android.tv.tuner.data.nano.Track.AtscAudioTrack; +import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack; +import com.android.tv.tuner.util.Ints; +import com.google.protobuf.nano.MessageNano; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; @@ -53,7 +55,7 @@ public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracks "Extended Parameterized Service" }; private static final String ATSC_SERVICE_TYPE_NAME_RESERVED = - ATSC_SERVICE_TYPE_NAMES[Channel.AtscServiceType.SERVICE_TYPE_ATSC_RESERVED_VALUE]; + ATSC_SERVICE_TYPE_NAMES[Channel.AtscServiceType.SERVICE_TYPE_ATSC_RESERVED]; public static final int INVALID_FREQUENCY = -1; @@ -64,128 +66,93 @@ public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracks public static final int INVALID_STREAMTYPE = -1; // @GuardedBy(this) Writing operations and toByteArray will be guarded. b/34197766 - private TunerChannelProto mProto; + private final TunerChannelProto mProto; private TunerChannel( - PsipData.VctItem channel, - int programNumber, - List<PsiData.PmtItem> pmtItems, - Channel.TunerType type) { - String shortName = ""; - String longName = ""; - String description = ""; - int tsid = 0; - int virtualMajor = 0; - int virtualMinor = 0; - Channel.AtscServiceType serviceType = - Channel.AtscServiceType.SERVICE_TYPE_ATSC_DIGITAL_TELEVISION; - if (channel != null) { - shortName = channel.getShortName(); - tsid = channel.getChannelTsid(); - programNumber = channel.getProgramNumber(); - virtualMajor = channel.getMajorChannelNumber(); - virtualMinor = channel.getMinorChannelNumber(); - Channel.AtscServiceType chanServiceType = - Channel.AtscServiceType.forNumber(channel.getServiceType()); - if (chanServiceType != null) { - serviceType = chanServiceType; + PsipData.VctItem channel, int programNumber, List<PsiData.PmtItem> pmtItems, int type) { + mProto = new TunerChannelProto(); + if (channel == null) { + mProto.shortName = ""; + mProto.tsid = 0; + mProto.programNumber = programNumber; + mProto.virtualMajor = 0; + mProto.virtualMinor = 0; + } else { + mProto.shortName = channel.getShortName(); + if (channel.getLongName() != null) { + mProto.longName = channel.getLongName(); } - longName = (channel.getLongName() != null ? channel.getLongName() : longName); - description = - (channel.getDescription() != null ? channel.getDescription() : description); + mProto.tsid = channel.getChannelTsid(); + mProto.programNumber = channel.getProgramNumber(); + mProto.virtualMajor = channel.getMajorChannelNumber(); + mProto.virtualMinor = channel.getMinorChannelNumber(); + if (channel.getDescription() != null) { + mProto.description = channel.getDescription(); + } + mProto.serviceType = channel.getServiceType(); } - TunerChannelProto tunerChannelProto = - TunerChannelProto.newBuilder() - .setShortName(shortName) - .setTsid(tsid) - .setProgramNumber(programNumber) - .setVirtualMajor(virtualMajor) - .setVirtualMinor(virtualMinor) - .setServiceType(serviceType) - .setLongName(longName) - .setDescription(description) - .build(); - initProto(pmtItems, type, tunerChannelProto); - } - - private void initProto( - List<PsiData.PmtItem> pmtItems, - Channel.TunerType type, - TunerChannelProto tunerChannelProto) { - int videoPid = INVALID_PID; - int pcrPid = 0; - Channel.VideoStreamType videoStreamType = Channel.VideoStreamType.UNSET; + initProto(pmtItems, type); + } + + private void initProto(List<PsiData.PmtItem> pmtItems, int type) { + mProto.type = type; + mProto.channelId = -1L; + mProto.frequency = INVALID_FREQUENCY; + mProto.videoPid = INVALID_PID; + mProto.videoStreamType = INVALID_STREAMTYPE; List<Integer> audioPids = new ArrayList<>(); - List<Channel.AudioStreamType> audioStreamTypes = new ArrayList<>(); + List<Integer> audioStreamTypes = new ArrayList<>(); for (PsiData.PmtItem pmt : pmtItems) { switch (pmt.getStreamType()) { // MPEG ES stream video types - case Channel.VideoStreamType.MPEG1_VALUE: - case Channel.VideoStreamType.MPEG2_VALUE: - case Channel.VideoStreamType.H263_VALUE: - case Channel.VideoStreamType.H264_VALUE: - case Channel.VideoStreamType.H265_VALUE: - videoPid = pmt.getEsPid(); - videoStreamType = Channel.VideoStreamType.forNumber(pmt.getStreamType()); + case Channel.VideoStreamType.MPEG1: + case Channel.VideoStreamType.MPEG2: + case Channel.VideoStreamType.H263: + case Channel.VideoStreamType.H264: + case Channel.VideoStreamType.H265: + mProto.videoPid = pmt.getEsPid(); + mProto.videoStreamType = pmt.getStreamType(); break; // MPEG ES stream audio types - case Channel.AudioStreamType.MPEG1AUDIO_VALUE: - case Channel.AudioStreamType.MPEG2AUDIO_VALUE: - case Channel.AudioStreamType.MPEG2AACAUDIO_VALUE: - case Channel.AudioStreamType.MPEG4LATMAACAUDIO_VALUE: - case Channel.AudioStreamType.A52AC3AUDIO_VALUE: - case Channel.AudioStreamType.EAC3AUDIO_VALUE: + case Channel.AudioStreamType.MPEG1AUDIO: + case Channel.AudioStreamType.MPEG2AUDIO: + case Channel.AudioStreamType.MPEG2AACAUDIO: + case Channel.AudioStreamType.MPEG4LATMAACAUDIO: + case Channel.AudioStreamType.A52AC3AUDIO: + case Channel.AudioStreamType.EAC3AUDIO: audioPids.add(pmt.getEsPid()); - audioStreamTypes.add(Channel.AudioStreamType.forNumber(pmt.getStreamType())); + audioStreamTypes.add(pmt.getStreamType()); break; // Non MPEG ES stream types case 0x100: // PmtItem.ES_PID_PCR: - pcrPid = pmt.getEsPid(); + mProto.pcrPid = pmt.getEsPid(); break; default: // fall out } } - mProto = - TunerChannelProto.newBuilder(tunerChannelProto) - .setType(type) - .setChannelId(-1L) - .setFrequency(INVALID_FREQUENCY) - .setVideoPid(videoPid) - .setVideoStreamType(videoStreamType) - .addAllAudioPids(audioPids) - .setAudioTrackIndex(audioPids.isEmpty() ? -1 : 0) - .addAllAudioStreamTypes(audioStreamTypes) - .setPcrPid(pcrPid) - .build(); + mProto.audioPids = Ints.toArray(audioPids); + mProto.audioStreamTypes = Ints.toArray(audioStreamTypes); + mProto.audioTrackIndex = (audioPids.size() > 0) ? 0 : -1; } private TunerChannel( - int programNumber, - Channel.TunerType type, - PsipData.SdtItem channel, - List<PsiData.PmtItem> pmtItems) { - String shortName = ""; - Channel.AtscServiceType serviceType = - Channel.AtscServiceType.SERVICE_TYPE_ATSC_DIGITAL_TELEVISION; - if (channel != null) { - shortName = channel.getServiceName(); - programNumber = channel.getServiceId(); - Channel.AtscServiceType chanServiceType = - Channel.AtscServiceType.forNumber(channel.getServiceType()); - if (chanServiceType != null) { - serviceType = chanServiceType; - } + int programNumber, int type, PsipData.SdtItem channel, List<PsiData.PmtItem> pmtItems) { + mProto = new TunerChannelProto(); + mProto.tsid = 0; + mProto.virtualMajor = 0; + mProto.virtualMinor = 0; + if (channel == null) { + mProto.shortName = ""; + mProto.programNumber = programNumber; + } else { + mProto.shortName = channel.getServiceName(); + mProto.programNumber = channel.getServiceId(); + mProto.serviceType = channel.getServiceType(); } - TunerChannelProto tunerChannelProto = - TunerChannelProto.newBuilder() - .setShortName(shortName) - .setProgramNumber(programNumber) - .setServiceType(serviceType) - .build(); - initProto(pmtItems, type, tunerChannelProto); + initProto(pmtItems, type); } /** Initialize tuner channel with VCT items and PMT items. */ @@ -266,23 +233,23 @@ public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracks } public String getName() { - return !mProto.getShortName().isEmpty() ? mProto.getShortName() : mProto.getLongName(); + return (!mProto.shortName.isEmpty()) ? mProto.shortName : mProto.longName; } public String getShortName() { - return mProto.getShortName(); + return mProto.shortName; } public int getProgramNumber() { - return mProto.getProgramNumber(); + return mProto.programNumber; } public int getServiceType() { - return mProto.getServiceType().getNumber(); + return mProto.serviceType; } public String getServiceTypeName() { - int serviceType = getServiceType(); + int serviceType = mProto.serviceType; if (serviceType >= 0 && serviceType < ATSC_SERVICE_TYPE_NAMES.length) { return ATSC_SERVICE_TYPE_NAMES[serviceType]; } @@ -290,129 +257,105 @@ public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracks } public int getVirtualMajor() { - return mProto.getVirtualMajor(); + return mProto.virtualMajor; } public int getVirtualMinor() { - return mProto.getVirtualMinor(); - } - - public DeliverySystemType getDeliverySystemType() { - return mProto.getDeliverySystemType(); + return mProto.virtualMinor; } public int getFrequency() { - return mProto.getFrequency(); + return mProto.frequency; } public String getModulation() { - return mProto.getModulation(); + return mProto.modulation; } public int getTsid() { - return mProto.getTsid(); + return mProto.tsid; } public int getVideoPid() { - return mProto.getVideoPid(); + return mProto.videoPid; } public synchronized void setVideoPid(int videoPid) { - mProto = mProto.toBuilder().setVideoPid(videoPid).build(); + mProto.videoPid = videoPid; } public int getVideoStreamType() { - return mProto.getVideoStreamType().getNumber(); + return mProto.videoStreamType; } public int getAudioPid() { - if (!mProto.hasAudioTrackIndex() || mProto.getAudioTrackIndex() == -1) { + if (mProto.audioTrackIndex == -1) { return INVALID_PID; } - return mProto.getAudioPids(mProto.getAudioTrackIndex()); + return mProto.audioPids[mProto.audioTrackIndex]; } public int getAudioStreamType() { - if (!mProto.hasAudioTrackIndex() || mProto.getAudioTrackIndex() == -1) { + if (mProto.audioTrackIndex == -1) { return INVALID_STREAMTYPE; } - return mProto.getAudioStreamTypes(mProto.getAudioTrackIndex()).getNumber(); + return mProto.audioStreamTypes[mProto.audioTrackIndex]; } public List<Integer> getAudioPids() { - return mProto.getAudioPidsList(); + return Ints.asList(mProto.audioPids); } public synchronized void setAudioPids(List<Integer> audioPids) { - mProto = mProto.toBuilder().clearAudioPids().addAllAudioPids(audioPids).build(); + mProto.audioPids = Ints.toArray(audioPids); } public List<Integer> getAudioStreamTypes() { - List<Channel.AudioStreamType> audioStreamTypes = mProto.getAudioStreamTypesList(); - List<Integer> audioStreamTypesValues = new ArrayList<>(audioStreamTypes.size()); - - for (Channel.AudioStreamType audioStreamType : audioStreamTypes) { - audioStreamTypesValues.add(audioStreamType.getNumber()); - } - return audioStreamTypesValues; + return Ints.asList(mProto.audioStreamTypes); } - public synchronized void setAudioStreamTypes(List<Integer> audioStreamTypesValues) { - List<Channel.AudioStreamType> audioStreamTypes = - new ArrayList<>(audioStreamTypesValues.size()); - - for (Integer audioStreamTypesValue : audioStreamTypesValues) { - audioStreamTypes.add(Channel.AudioStreamType.forNumber(audioStreamTypesValue)); - } - mProto = - mProto.toBuilder() - .clearAudioStreamTypes() - .addAllAudioStreamTypes(audioStreamTypes) - .build(); + public synchronized void setAudioStreamTypes(List<Integer> audioStreamTypes) { + mProto.audioStreamTypes = Ints.toArray(audioStreamTypes); } public int getPcrPid() { - return mProto.getPcrPid(); + return mProto.pcrPid; } - public Channel.TunerType getType() { - return mProto.getType(); + public int getType() { + return mProto.type; } public synchronized void setFilepath(String filepath) { - mProto = mProto.toBuilder().setFilepath(filepath == null ? "" : filepath).build(); + mProto.filepath = filepath == null ? "" : filepath; } public String getFilepath() { - return mProto.getFilepath(); + return mProto.filepath; } public synchronized void setVirtualMajor(int virtualMajor) { - mProto = mProto.toBuilder().setVirtualMajor(virtualMajor).build(); + mProto.virtualMajor = virtualMajor; } public synchronized void setVirtualMinor(int virtualMinor) { - mProto = mProto.toBuilder().setVirtualMinor(virtualMinor).build(); + mProto.virtualMinor = virtualMinor; } public synchronized void setShortName(String shortName) { - mProto = mProto.toBuilder().setShortName(shortName == null ? "" : shortName).build(); - } - - public synchronized void setDeliverySystemType(DeliverySystemType deliverySystemType) { - mProto = mProto.toBuilder().setDeliverySystemType(deliverySystemType).build(); + mProto.shortName = shortName == null ? "" : shortName; } public synchronized void setFrequency(int frequency) { - mProto = mProto.toBuilder().setFrequency(frequency).build(); + mProto.frequency = frequency; } public synchronized void setModulation(String modulation) { - mProto = mProto.toBuilder().setModulation(modulation == null ? "" : modulation).build(); + mProto.modulation = modulation == null ? "" : modulation; } public boolean hasVideo() { - return mProto.hasVideoPid() && mProto.getVideoPid() != INVALID_PID; + return mProto.videoPid != INVALID_PID; } public boolean hasAudio() { @@ -420,11 +363,11 @@ public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracks } public long getChannelId() { - return mProto.getChannelId(); + return mProto.channelId; } public synchronized void setChannelId(long channelId) { - mProto = mProto.toBuilder().setChannelId(channelId).build(); + mProto.channelId = channelId; } /** @@ -436,11 +379,11 @@ public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracks * href="https://developer.android.com/reference/android/media/tv/TvContract.Channels.html#COLUMN_LOCKED">link</a> */ public boolean isLocked() { - return mProto.getLocked(); + return mProto.locked; } public synchronized void setLocked(boolean locked) { - mProto = mProto.toBuilder().setLocked(locked).build(); + mProto.locked = locked; } public String getDisplayNumber() { @@ -448,91 +391,92 @@ public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracks } public String getDisplayNumber(boolean ignoreZeroMinorNumber) { - if (getVirtualMajor() != 0 && (getVirtualMinor() != 0 || !ignoreZeroMinorNumber)) { + if (mProto.virtualMajor != 0 && (mProto.virtualMinor != 0 || !ignoreZeroMinorNumber)) { return String.format( - "%d%c%d", getVirtualMajor(), CHANNEL_NUMBER_SEPARATOR, getVirtualMinor()); - } else if (getVirtualMajor() != 0) { - return Integer.toString(getVirtualMajor()); + "%d%c%d", mProto.virtualMajor, CHANNEL_NUMBER_SEPARATOR, mProto.virtualMinor); + } else if (mProto.virtualMajor != 0) { + return Integer.toString(mProto.virtualMajor); } else { - return Integer.toString(getProgramNumber()); + return Integer.toString(mProto.programNumber); } } public String getDescription() { - return mProto.getDescription(); + return mProto.description; } @Override public synchronized void setHasCaptionTrack() { - mProto = mProto.toBuilder().setHasCaptionTrack(true).build(); + mProto.hasCaptionTrack = true; } @Override public boolean hasCaptionTrack() { - return mProto.getHasCaptionTrack(); + return mProto.hasCaptionTrack; } @Override public List<AtscAudioTrack> getAudioTracks() { - return mProto.getAudioTracksList(); + return Collections.unmodifiableList(Arrays.asList(mProto.audioTracks)); } public synchronized void setAudioTracks(List<AtscAudioTrack> audioTracks) { - mProto = mProto.toBuilder().clearAudioTracks().addAllAudioTracks(audioTracks).build(); + mProto.audioTracks = audioTracks.toArray(new AtscAudioTrack[audioTracks.size()]); } @Override public List<AtscCaptionTrack> getCaptionTracks() { - return mProto.getCaptionTracksList(); + return Collections.unmodifiableList(Arrays.asList(mProto.captionTracks)); } public synchronized void setCaptionTracks(List<AtscCaptionTrack> captionTracks) { - mProto = mProto.toBuilder().clearCaptionTracks().addAllCaptionTracks(captionTracks).build(); + mProto.captionTracks = captionTracks.toArray(new AtscCaptionTrack[captionTracks.size()]); } public synchronized void selectAudioTrack(int index) { - if (index < 0 || index >= mProto.getAudioPidsCount()) { - index = -1; + if (0 <= index && index < mProto.audioPids.length) { + mProto.audioTrackIndex = index; + } else { + mProto.audioTrackIndex = -1; } - mProto = mProto.toBuilder().setAudioTrackIndex(index).build(); } public synchronized void setRecordingProhibited(boolean recordingProhibited) { - mProto = mProto.toBuilder().setRecordingProhibited(recordingProhibited).build(); + mProto.recordingProhibited = recordingProhibited; } public boolean isRecordingProhibited() { - return mProto.getRecordingProhibited(); + return mProto.recordingProhibited; } public synchronized void setVideoFormat(String videoFormat) { - mProto = mProto.toBuilder().setVideoFormat(videoFormat == null ? "" : videoFormat).build(); + mProto.videoFormat = videoFormat == null ? "" : videoFormat; } public String getVideoFormat() { - return mProto.getVideoFormat(); + return mProto.videoFormat; } @Override public String toString() { - switch (getType()) { - case TYPE_FILE: + switch (mProto.type) { + case Channel.TunerType.TYPE_FILE: return String.format( "{%d-%d %s} Filepath: %s, ProgramNumber %d", - getVirtualMajor(), - getVirtualMinor(), - getShortName(), - getFilepath(), - getProgramNumber()); + mProto.virtualMajor, + mProto.virtualMinor, + mProto.shortName, + mProto.filepath, + mProto.programNumber); // case Channel.TunerType.TYPE_TUNER: default: return String.format( "{%d-%d %s} Frequency: %d, ProgramNumber %d", - getVirtualMajor(), - getVirtualMinor(), - getShortName(), - getFrequency(), - getProgramNumber()); + mProto.virtualMajor, + mProto.virtualMinor, + mProto.shortName, + mProto.frequency, + mProto.programNumber); } } @@ -551,9 +495,6 @@ public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracks if (ret != 0) { return ret; } - if (getDeliverySystemType() != channel.getDeliverySystemType()) { - return 1; - } // For FileTsStreamer, file paths should be compared. return StringUtils.compare(getFilepath(), channel.getFilepath()); } @@ -568,21 +509,20 @@ public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracks @Override public int hashCode() { - return Objects.hash(getDeliverySystemType(), getFrequency(), getProgramNumber(), getName(), - getFilepath()); + return Objects.hash(getFrequency(), getProgramNumber(), getName(), getFilepath()); } // Serialization public synchronized byte[] toByteArray() { try { - return mProto.toByteArray(); + return MessageNano.toByteArray(mProto); } catch (Exception e) { // Retry toByteArray. b/34197766 Log.w( TAG, "TunerChannel or its variables are modified in multiple thread without lock", e); - return mProto.toByteArray(); + return MessageNano.toByteArray(mProto); } } diff --git a/tuner/src/com/android/tv/tuner/exoplayer/ExoPlayerSampleExtractor.java b/tuner/src/com/android/tv/tuner/exoplayer/ExoPlayerSampleExtractor.java index 2a22db17..e48cb03c 100644 --- a/tuner/src/com/android/tv/tuner/exoplayer/ExoPlayerSampleExtractor.java +++ b/tuner/src/com/android/tv/tuner/exoplayer/ExoPlayerSampleExtractor.java @@ -26,32 +26,32 @@ import android.os.SystemClock; import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; import android.util.Pair; - import com.android.tv.tuner.exoplayer.audio.MpegTsDefaultAudioTrackRenderer; import com.android.tv.tuner.exoplayer.buffer.BufferManager; import com.android.tv.tuner.exoplayer.buffer.PlaybackBufferListener; import com.android.tv.tuner.exoplayer.buffer.RecordingSampleBuffer; import com.android.tv.tuner.exoplayer.buffer.SimpleSampleBuffer; - import com.google.android.exoplayer.MediaFormat; import com.google.android.exoplayer.MediaFormatHolder; import com.google.android.exoplayer.SampleHolder; +import com.google.android.exoplayer.upstream.DataSource; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.FormatHolder; +import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.source.ExtractorMediaSource; +import com.google.android.exoplayer2.source.ExtractorMediaSource.EventListener; import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.SampleStream; import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.trackselection.FixedTrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelection; -import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.DefaultAllocator; -import com.google.auto.factory.AutoFactory; -import com.google.auto.factory.Provided; - +import com.google.android.exoplayer2.upstream.TransferListener; +import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; @@ -72,6 +72,7 @@ public class ExoPlayerSampleExtractor implements SampleExtractor { private final long mId; private final Handler.Callback mSourceReaderWorker; + private final ConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags; private BufferManager.SampleBuffer mSampleBuffer; private Handler mSourceReaderHandler; @@ -88,29 +89,13 @@ public class ExoPlayerSampleExtractor implements SampleExtractor { private Handler mOnCompletionListenerHandler; private IOException mError; - /** - * Factory for {@link ExoPlayerSampleExtractor}. - * - * <p>This wrapper class keeps other classes from needing to reference the {@link AutoFactory} - * generated class. - */ - public interface Factory { - public ExoPlayerSampleExtractor create( - Uri uri, - DataSource source, - @Nullable BufferManager bufferManager, - PlaybackBufferListener bufferListener, - boolean isRecording); - } - - @AutoFactory(implementing = Factory.class) public ExoPlayerSampleExtractor( Uri uri, - DataSource source, - @Nullable BufferManager bufferManager, + final DataSource source, + BufferManager bufferManager, PlaybackBufferListener bufferListener, boolean isRecording, - @Provided RecordingSampleBuffer.Factory recordingSampleBufferFactory) { + ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlagsoncurrentDvrPlaybackFlags) { this( uri, source, @@ -119,7 +104,7 @@ public class ExoPlayerSampleExtractor implements SampleExtractor { isRecording, Looper.myLooper(), new HandlerThread("SourceReaderThread"), - recordingSampleBufferFactory); + concurrentDvrPlaybackFlagsoncurrentDvrPlaybackFlags); } @VisibleForTesting @@ -132,35 +117,98 @@ public class ExoPlayerSampleExtractor implements SampleExtractor { boolean isRecording, Looper workerLooper, HandlerThread sourceReaderThread, - RecordingSampleBuffer.Factory recordingSampleBufferFactory) { + ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags) { // It'll be used as a timeshift file chunk name's prefix. mId = System.currentTimeMillis(); + mConcurrentDvrPlaybackFlags = concurrentDvrPlaybackFlags; + + EventListener eventListener = + new EventListener() { + @Override + public void onLoadError(IOException error) { + mError = error; + } + }; mSourceReaderThread = sourceReaderThread; mSourceReaderWorker = new SourceReaderWorker( new ExtractorMediaSource( uri, - /* dataSourceFactory= */ () -> source, + new com.google.android.exoplayer2.upstream.DataSource.Factory() { + @Override + public com.google.android.exoplayer2.upstream.DataSource + createDataSource() { + // Returns an adapter implementation for ExoPlayer V2 + // DataSource interface. + return new com.google.android.exoplayer2.upstream + .DataSource() { + + private @Nullable Uri uri; + + // TODO: uncomment once this is part of the public API. + // @Override + public void addTransferListener( + TransferListener transferListener) { + // Do nothing. Unsupported in V1. + } + + @Override + public long open(DataSpec dataSpec) throws IOException { + this.uri = dataSpec.uri; + return source.open( + new com.google.android.exoplayer.upstream + .DataSpec( + dataSpec.uri, + dataSpec.postBody, + dataSpec.absoluteStreamPosition, + dataSpec.position, + dataSpec.length, + dataSpec.key, + dataSpec.flags)); + } + + @Override + public int read( + byte[] buffer, int offset, int readLength) + throws IOException { + return source.read(buffer, offset, readLength); + } + + @Override + public @Nullable Uri getUri() { + return uri; + } + + @Override + public void close() throws IOException { + source.close(); + uri = null; + } + }; + } + }, new ExoPlayerExtractorsFactory(), new Handler(workerLooper), - /* eventListener= */ error -> mError = error)); + eventListener)); if (isRecording) { mSampleBuffer = - recordingSampleBufferFactory.create( + new RecordingSampleBuffer( bufferManager, bufferListener, false, + mConcurrentDvrPlaybackFlags, RecordingSampleBuffer.BUFFER_REASON_RECORDING); } else { if (bufferManager == null) { mSampleBuffer = new SimpleSampleBuffer(bufferListener); } else { mSampleBuffer = - recordingSampleBufferFactory.create( + new RecordingSampleBuffer( bufferManager, bufferListener, true, + mConcurrentDvrPlaybackFlags, RecordingSampleBuffer.BUFFER_REASON_LIVE_PLAYBACK); } } @@ -192,11 +240,15 @@ public class ExoPlayerSampleExtractor implements SampleExtractor { public SourceReaderWorker(MediaSource sampleSource) { mSampleSource = sampleSource; mSampleSourceListener = - (source, timeline, manifest) -> { - // Dynamic stream change is not supported yet. b/28169263 - // For now, this will cause EOS and playback reset. + new MediaSource.SourceInfoRefreshListener() { + @Override + public void onSourceInfoRefreshed( + MediaSource source, Timeline timeline, Object manifest) { + // Dynamic stream change is not supported yet. b/28169263 + // For now, this will cause EOS and playback reset. + } }; - mSampleSource.prepareSource(mSampleSourceListener, null); + mSampleSource.prepareSource(null, false, mSampleSourceListener, null); mDecoderInputBuffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL); mSampleHolder = new SampleHolder(SampleHolder.BUFFER_REPLACEMENT_MODE_NORMAL); @@ -313,8 +365,9 @@ public class ExoPlayerSampleExtractor implements SampleExtractor { mMediaPeriod = mSampleSource.createPeriod( new MediaSource.MediaPeriodId(0), - new DefaultAllocator(true, C.DEFAULT_BUFFER_SEGMENT_SIZE), - 0); + new DefaultAllocator(true, C.DEFAULT_BUFFER_SEGMENT_SIZE) +// AOSP_Comment_Out , 0 + ); mMediaPeriod.prepare(this, 0); try { mMediaPeriod.maybeThrowPrepareError(); @@ -433,7 +486,7 @@ public class ExoPlayerSampleExtractor implements SampleExtractor { sample.data.position(0); sample.data.put(mDecoderInputBuffer.data); sample.data.flip(); - mPendingSamples.add(Pair.create(index, sample)); + mPendingSamples.add(new Pair<>(index, sample)); return; } mVideoTrackMet = true; diff --git a/tuner/src/com/android/tv/tuner/exoplayer/FileSampleExtractor.java b/tuner/src/com/android/tv/tuner/exoplayer/FileSampleExtractor.java index aaca043b..9749e4ba 100644 --- a/tuner/src/com/android/tv/tuner/exoplayer/FileSampleExtractor.java +++ b/tuner/src/com/android/tv/tuner/exoplayer/FileSampleExtractor.java @@ -17,18 +17,14 @@ package com.android.tv.tuner.exoplayer; import android.os.Handler; - import com.android.tv.tuner.exoplayer.buffer.BufferManager; import com.android.tv.tuner.exoplayer.buffer.PlaybackBufferListener; import com.android.tv.tuner.exoplayer.buffer.RecordingSampleBuffer; - import com.google.android.exoplayer.MediaFormat; import com.google.android.exoplayer.MediaFormatHolder; import com.google.android.exoplayer.MediaFormatUtil; import com.google.android.exoplayer.SampleHolder; -import com.google.auto.factory.AutoFactory; -import com.google.auto.factory.Provided; - +import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -48,28 +44,16 @@ public class FileSampleExtractor implements SampleExtractor { private final BufferManager mBufferManager; private final PlaybackBufferListener mBufferListener; private BufferManager.SampleBuffer mSampleBuffer; - private final RecordingSampleBuffer.Factory mRecordingSampleBufferFactory; - - /** - * Factory for {@link FileSampleExtractor}}. - * - * <p>This wrapper class keeps other classes from needing to reference the {@link AutoFactory} - * generated class. - */ - public interface Factory { - public FileSampleExtractor create( - BufferManager bufferManager, PlaybackBufferListener bufferListener); - } + private final ConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags; - @AutoFactory(implementing = Factory.class) public FileSampleExtractor( BufferManager bufferManager, PlaybackBufferListener bufferListener, - @Provided RecordingSampleBuffer.Factory recordingSampleBufferFactory) { + ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags) { mBufferManager = bufferManager; mBufferListener = bufferListener; + mConcurrentDvrPlaybackFlags = concurrentDvrPlaybackFlags; mTrackCount = -1; - mRecordingSampleBufferFactory = recordingSampleBufferFactory; } @Override @@ -92,10 +76,11 @@ public class FileSampleExtractor implements SampleExtractor { mTrackFormats.add(MediaFormatUtil.createMediaFormat(trackFormat.format)); } mSampleBuffer = - mRecordingSampleBufferFactory.create( + new RecordingSampleBuffer( mBufferManager, mBufferListener, true, + mConcurrentDvrPlaybackFlags, RecordingSampleBuffer.BUFFER_REASON_RECORDED_PLAYBACK); mSampleBuffer.init(ids, mTrackFormats); return true; diff --git a/tuner/src/com/android/tv/tuner/exoplayer/MpegTsPlayer.java b/tuner/src/com/android/tv/tuner/exoplayer/MpegTsPlayer.java index 67cf992c..6781c616 100644 --- a/tuner/src/com/android/tv/tuner/exoplayer/MpegTsPlayer.java +++ b/tuner/src/com/android/tv/tuner/exoplayer/MpegTsPlayer.java @@ -43,8 +43,7 @@ import com.google.android.exoplayer.MediaFormat; import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.audio.AudioCapabilities; import com.google.android.exoplayer.audio.AudioTrack; -import com.google.android.exoplayer2.upstream.DataSource; - +import com.google.android.exoplayer.upstream.DataSource; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -148,7 +147,7 @@ public class MpegTsPlayer * * @param rendererBuilder the builder of track renderers * @param handler the handler for the playback events in track renderers - * @param sourceManager the manager for {@link TsDataSource} + * @param sourceManager the manager for {@link DataSource} * @param capabilities the {@link AudioCapabilities} of the current device * @param listener the listener for playback state changes */ @@ -215,7 +214,7 @@ public class MpegTsPlayer } /** - * Creates renderers and {@link TsDataSource} and initializes player. + * Creates renderers and {@link DataSource} and initializes player. * * @param context a {@link Context} instance * @param channel to play diff --git a/tuner/src/com/android/tv/tuner/exoplayer/MpegTsRendererBuilder.java b/tuner/src/com/android/tv/tuner/exoplayer/MpegTsRendererBuilder.java index f860631c..e043907f 100644 --- a/tuner/src/com/android/tv/tuner/exoplayer/MpegTsRendererBuilder.java +++ b/tuner/src/com/android/tv/tuner/exoplayer/MpegTsRendererBuilder.java @@ -17,51 +17,33 @@ package com.android.tv.tuner.exoplayer; import android.content.Context; -import android.support.annotation.Nullable; - import com.android.tv.tuner.exoplayer.MpegTsPlayer.RendererBuilder; import com.android.tv.tuner.exoplayer.MpegTsPlayer.RendererBuilderCallback; import com.android.tv.tuner.exoplayer.audio.MpegTsDefaultAudioTrackRenderer; import com.android.tv.tuner.exoplayer.buffer.BufferManager; import com.android.tv.tuner.exoplayer.buffer.PlaybackBufferListener; - import com.google.android.exoplayer.MediaCodecSelector; import com.google.android.exoplayer.SampleSource; import com.google.android.exoplayer.TrackRenderer; -import com.google.android.exoplayer2.upstream.DataSource; -import com.google.auto.factory.AutoFactory; -import com.google.auto.factory.Provided; +import com.google.android.exoplayer.upstream.DataSource; +import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags; /** Builder for renderer objects for {@link MpegTsPlayer}. */ public class MpegTsRendererBuilder implements RendererBuilder { private final Context mContext; private final BufferManager mBufferManager; private final PlaybackBufferListener mBufferListener; - private final MpegTsSampleExtractor.Factory mMpegTsSampleExtractorFactory; - - /** - * Factory for {@link MpegTsRendererBuilder}. - * - * <p>This wrapper class keeps other classes from needing to reference the {@link AutoFactory} - * generated class. - */ - public interface Factory { - public MpegTsRendererBuilder create( - Context context, - @Nullable BufferManager bufferManager, - PlaybackBufferListener bufferListener); - } + private final ConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags; - @AutoFactory(implementing = Factory.class) public MpegTsRendererBuilder( Context context, - @Nullable BufferManager bufferManager, + BufferManager bufferManager, PlaybackBufferListener bufferListener, - @Provided MpegTsSampleExtractor.Factory mpegTsSampleExtractorFactory) { + ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags) { mContext = context; mBufferManager = bufferManager; mBufferListener = bufferListener; - mMpegTsSampleExtractorFactory = mpegTsSampleExtractorFactory; + mConcurrentDvrPlaybackFlags = concurrentDvrPlaybackFlags; } @Override @@ -70,9 +52,13 @@ public class MpegTsRendererBuilder implements RendererBuilder { // Build the video and audio renderers. SampleExtractor extractor = dataSource == null - ? mMpegTsSampleExtractorFactory.create(mBufferManager, mBufferListener) - : mMpegTsSampleExtractorFactory.create( - dataSource, mBufferManager, mBufferListener); + ? new MpegTsSampleExtractor( + mBufferManager, mBufferListener, mConcurrentDvrPlaybackFlags) + : new MpegTsSampleExtractor( + dataSource, + mBufferManager, + mBufferListener, + mConcurrentDvrPlaybackFlags); SampleSource sampleSource = new MpegTsSampleSource(extractor); MpegTsVideoTrackRenderer videoRenderer = new MpegTsVideoTrackRenderer( diff --git a/tuner/src/com/android/tv/tuner/exoplayer/MpegTsSampleExtractor.java b/tuner/src/com/android/tv/tuner/exoplayer/MpegTsSampleExtractor.java index 8d3668ef..582f18c5 100644 --- a/tuner/src/com/android/tv/tuner/exoplayer/MpegTsSampleExtractor.java +++ b/tuner/src/com/android/tv/tuner/exoplayer/MpegTsSampleExtractor.java @@ -18,21 +18,16 @@ package com.android.tv.tuner.exoplayer; import android.net.Uri; import android.os.Handler; -import android.support.annotation.Nullable; - import com.android.tv.tuner.exoplayer.buffer.BufferManager; import com.android.tv.tuner.exoplayer.buffer.PlaybackBufferListener; import com.android.tv.tuner.exoplayer.buffer.SamplePool; - import com.google.android.exoplayer.MediaFormat; import com.google.android.exoplayer.MediaFormatHolder; import com.google.android.exoplayer.SampleHolder; import com.google.android.exoplayer.SampleSource; +import com.google.android.exoplayer.upstream.DataSource; import com.google.android.exoplayer.util.MimeTypes; -import com.google.android.exoplayer2.upstream.DataSource; -import com.google.auto.factory.AutoFactory; -import com.google.auto.factory.Provided; - +import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags; import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -64,37 +59,27 @@ public final class MpegTsSampleExtractor implements SampleExtractor { } /** - * Factory for {@link MpegTsSampleExtractor}. - * - * <p>This wrapper class keeps other classes from needing to reference the {@link AutoFactory} - * generated class. - */ - public interface Factory { - public MpegTsSampleExtractor create( - BufferManager bufferManager, PlaybackBufferListener bufferListener); - - public MpegTsSampleExtractor create( - DataSource source, - @Nullable BufferManager bufferManager, - PlaybackBufferListener bufferListener); - } - - /** - * Creates MpegTsSampleExtractor for a {@link DataSource}. + * Creates MpegTsSampleExtractor for {@link DataSource}. * * @param source the {@link DataSource} to extract from * @param bufferManager the manager for reading & writing samples backed by physical storage * @param bufferListener the {@link PlaybackBufferListener} to notify buffer storage status + * @param concurrentDvrPlaybackFlags */ - @AutoFactory(implementing = Factory.class) public MpegTsSampleExtractor( DataSource source, - @Nullable BufferManager bufferManager, + BufferManager bufferManager, PlaybackBufferListener bufferListener, - @Provided ExoPlayerSampleExtractor.Factory exoPlayerSampleExtractorFactory) { + ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags) { + mSampleExtractor = - exoPlayerSampleExtractorFactory.create( - Uri.EMPTY, source, bufferManager, bufferListener, false); + new ExoPlayerSampleExtractor( + Uri.EMPTY, + source, + bufferManager, + bufferListener, + false, + concurrentDvrPlaybackFlags); init(); } @@ -105,12 +90,12 @@ public final class MpegTsSampleExtractor implements SampleExtractor { * @param bufferListener the {@link PlaybackBufferListener} to notify buffer storage status * change */ - @AutoFactory(implementing = Factory.class) public MpegTsSampleExtractor( BufferManager bufferManager, PlaybackBufferListener bufferListener, - @Provided FileSampleExtractor.Factory fileSampleExtractorFactory) { - mSampleExtractor = fileSampleExtractorFactory.create(bufferManager, bufferListener); + ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags) { + mSampleExtractor = + new FileSampleExtractor(bufferManager, bufferListener, concurrentDvrPlaybackFlags); init(); } diff --git a/tuner/src/com/android/tv/tuner/exoplayer/audio/MpegTsDefaultAudioTrackRenderer.java b/tuner/src/com/android/tv/tuner/exoplayer/audio/MpegTsDefaultAudioTrackRenderer.java index fb88e5b7..bab74c9d 100644 --- a/tuner/src/com/android/tv/tuner/exoplayer/audio/MpegTsDefaultAudioTrackRenderer.java +++ b/tuner/src/com/android/tv/tuner/exoplayer/audio/MpegTsDefaultAudioTrackRenderer.java @@ -246,7 +246,6 @@ public class MpegTsDefaultAudioTrackRenderer extends TrackRenderer implements Me mSource.seekToUs(positionUs); AUDIO_TRACK.reset(); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { - // b/21824483 workaround // resetSessionId() will create a new framework AudioTrack instead of reusing old one. AUDIO_TRACK.resetSessionId(); } @@ -285,7 +284,6 @@ public class MpegTsDefaultAudioTrackRenderer extends TrackRenderer implements Me // Ensure playback stops, after EoS was notified. // Sometimes MediaCodecTrackRenderer does not fetch EoS timely // after EoS was notified here long before. - // see b/21909113 long diff = SystemClock.elapsedRealtime() - mEndOfStreamMs; if (diff >= KEEP_ALIVE_AFTER_EOS_DURATION_MS && !mIsStopped) { throw new ExoPlaybackException("Much time has elapsed after EoS"); @@ -594,7 +592,6 @@ public class MpegTsDefaultAudioTrackRenderer extends TrackRenderer implements Me } mCurrentPositionUs = Math.max(mPresentationTimeUs, mCurrentPositionUs); } else { - // TODO: Remove this workaround when b/22023809 is resolved. if (mPreviousPositionUs > audioTrackCurrentPositionUs + BACKWARD_AUDIO_TRACK_MOVE_THRESHOLD_US) { Log.e( diff --git a/tuner/src/com/android/tv/tuner/exoplayer/buffer/BufferManager.java b/tuner/src/com/android/tv/tuner/exoplayer/buffer/BufferManager.java index b8d85230..c32540c1 100644 --- a/tuner/src/com/android/tv/tuner/exoplayer/buffer/BufferManager.java +++ b/tuner/src/com/android/tv/tuner/exoplayer/buffer/BufferManager.java @@ -23,13 +23,10 @@ import android.support.annotation.VisibleForTesting; import android.util.ArrayMap; import android.util.Log; import android.util.Pair; - import com.android.tv.common.SoftPreconditions; import com.android.tv.common.util.CommonUtils; import com.android.tv.tuner.exoplayer.SampleExtractor; - import com.google.android.exoplayer.SampleHolder; - import java.io.File; import java.io.IOException; import java.util.ArrayList; @@ -403,13 +400,13 @@ public class BufferManager { SampleChunk sampleChunk = mSampleChunkCreator.createSampleChunk( samplePool, file, positionUs, mChunkCallback); - map.put(positionUs, Pair.create(sampleChunk, 0)); + map.put(positionUs, new Pair(sampleChunk, 0)); if (updateIndexFile) { mStorageManager.updateIndexFile(id, map.size(), positionUs, sampleChunk, 0); } return sampleChunk; } else { - map.put(positionUs, Pair.create(currentChunk, currentOffset)); + map.put(positionUs, new Pair(currentChunk, currentOffset)); if (updateIndexFile) { mStorageManager.updateIndexFile( id, map.size(), positionUs, currentChunk, currentOffset); @@ -450,7 +447,7 @@ public class BufferManager { chunk); basePositionUs = position.basePositionUs; } - map.put(position.positionUs, Pair.create(chunk, position.offset)); + map.put(position.positionUs, new Pair(chunk, position.offset)); } } diff --git a/tuner/src/com/android/tv/tuner/exoplayer/buffer/DvrStorageManager.java b/tuner/src/com/android/tv/tuner/exoplayer/buffer/DvrStorageManager.java index 0e1cbe9f..f19756ec 100644 --- a/tuner/src/com/android/tv/tuner/exoplayer/buffer/DvrStorageManager.java +++ b/tuner/src/com/android/tv/tuner/exoplayer/buffer/DvrStorageManager.java @@ -19,7 +19,8 @@ package com.android.tv.tuner.exoplayer.buffer; import android.media.MediaFormat; import android.util.Log; import android.util.Pair; -import com.android.tv.tuner.data.Track.AtscCaptionTrack; +import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack; +import com.google.protobuf.nano.MessageNano; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; @@ -368,7 +369,7 @@ public class DvrStorageManager implements BufferManager.StorageManager { META_FILE_TYPE_CAPTION + ((i == 0) ? META_FILE_SUFFIX : (i + META_FILE_SUFFIX)); File file = new File(getBufferDir(), fileName); try (DataOutputStream out = new DataOutputStream(new FileOutputStream(file))) { - track.writeTo(out); + out.write(MessageNano.toByteArray(track)); } catch (Exception e) { Log.e(TAG, "Fail to write caption info to files", e); } diff --git a/tuner/src/com/android/tv/tuner/exoplayer/buffer/RecordingSampleBuffer.java b/tuner/src/com/android/tv/tuner/exoplayer/buffer/RecordingSampleBuffer.java index df2cd2e6..d95642c2 100644 --- a/tuner/src/com/android/tv/tuner/exoplayer/buffer/RecordingSampleBuffer.java +++ b/tuner/src/com/android/tv/tuner/exoplayer/buffer/RecordingSampleBuffer.java @@ -20,18 +20,14 @@ import android.os.ConditionVariable; import android.support.annotation.IntDef; import android.support.annotation.NonNull; import android.util.Log; - import com.android.tv.tuner.exoplayer.MpegTsPlayer; import com.android.tv.tuner.exoplayer.SampleExtractor; - import com.google.android.exoplayer.C; import com.google.android.exoplayer.MediaFormat; import com.google.android.exoplayer.SampleHolder; import com.google.android.exoplayer.SampleSource; import com.google.android.exoplayer.util.Assertions; -import com.google.auto.factory.AutoFactory; -import com.google.auto.factory.Provided; - +import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -73,7 +69,7 @@ public class RecordingSampleBuffer private final BufferManager mBufferManager; private final PlaybackBufferListener mBufferListener; private final @BufferReason int mBufferReason; - private final SampleChunkIoHelper.Factory mSampleChunkIoHelperFactory; + private final ConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags; private int mTrackCount; private boolean[] mTrackSelected; @@ -102,42 +98,28 @@ public class RecordingSampleBuffer }; /** - * Factory for {@link RecordingSampleBuffer}. - * - * <p>This wrapper class keeps other classes from needing to reference the {@link AutoFactory} - * generated class. - */ - public interface Factory { - public RecordingSampleBuffer create( - BufferManager bufferManager, - PlaybackBufferListener bufferListener, - boolean enableTrickplay, - @BufferReason int bufferReason); - } - - /** * Creates {@link BufferManager.SampleBuffer} with cached I/O backed by physical storage (e.g. * trickplay,recording,recorded-playback). * * @param bufferManager the manager of {@link SampleChunk} * @param bufferListener the listener for buffer I/O event * @param enableTrickplay {@code true} when trickplay should be enabled + * @param concurrentDvrPlaybackFlags * @param bufferReason the reason for caching samples {@link BufferReason} */ - @AutoFactory(implementing = Factory.class) public RecordingSampleBuffer( BufferManager bufferManager, PlaybackBufferListener bufferListener, boolean enableTrickplay, - @BufferReason int bufferReason, - @Provided SampleChunkIoHelper.Factory sampleChunkIoHelperFactory) { + ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags, + @BufferReason int bufferReason) { mBufferManager = bufferManager; mBufferListener = bufferListener; + mConcurrentDvrPlaybackFlags = concurrentDvrPlaybackFlags; if (bufferListener != null) { bufferListener.onBufferStateChanged(enableTrickplay); } mBufferReason = bufferReason; - mSampleChunkIoHelperFactory = sampleChunkIoHelperFactory; } @Override @@ -150,8 +132,14 @@ public class RecordingSampleBuffer mTrackSelected = new boolean[mTrackCount]; mReadSampleQueues = new ArrayList<>(); mSampleChunkIoHelper = - mSampleChunkIoHelperFactory.create( - ids, mediaFormats, mBufferReason, mBufferManager, mSamplePool, mIoCallback); + new SampleChunkIoHelper( + ids, + mediaFormats, + mBufferReason, + mBufferManager, + mSamplePool, + mIoCallback, + mConcurrentDvrPlaybackFlags); for (int i = 0; i < mTrackCount; ++i) { mReadSampleQueues.add(i, new SampleQueue(mSamplePool)); } diff --git a/tuner/src/com/android/tv/tuner/exoplayer/buffer/SampleChunkIoHelper.java b/tuner/src/com/android/tv/tuner/exoplayer/buffer/SampleChunkIoHelper.java index 82bf0df8..f4d3bf8e 100644 --- a/tuner/src/com/android/tv/tuner/exoplayer/buffer/SampleChunkIoHelper.java +++ b/tuner/src/com/android/tv/tuner/exoplayer/buffer/SampleChunkIoHelper.java @@ -24,17 +24,12 @@ import android.os.Message; import android.util.ArraySet; import android.util.Log; import android.util.Pair; - import com.android.tv.common.SoftPreconditions; -import com.android.tv.common.flags.DvrFlags; import com.android.tv.tuner.exoplayer.buffer.RecordingSampleBuffer.BufferReason; - import com.google.android.exoplayer.MediaFormat; import com.google.android.exoplayer.SampleHolder; import com.google.android.exoplayer.util.MimeTypes; -import com.google.auto.factory.AutoFactory; -import com.google.auto.factory.Provided; - +import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags; import java.io.IOException; import java.util.ArrayList; import java.util.LinkedList; @@ -69,7 +64,7 @@ public class SampleChunkIoHelper implements Handler.Callback { private final BufferManager mBufferManager; private final SamplePool mSamplePool; private final IoCallback mIoCallback; - private final DvrFlags mDvrFlags; + private final ConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags; private Handler mIoHandler; private final ConcurrentLinkedQueue<SampleHolder> mReadSampleBuffers[]; @@ -118,22 +113,6 @@ public class SampleChunkIoHelper implements Handler.Callback { } /** - * Factory for {@link SampleChunkIoHelper}. - * - * <p>This wrapper class keeps other classes from needing to reference the {@link AutoFactory} - * generated class. - */ - public interface Factory { - public SampleChunkIoHelper create( - List<String> ids, - List<MediaFormat> mediaFormats, - @BufferReason int bufferReason, - BufferManager bufferManager, - SamplePool samplePool, - IoCallback ioCallback); - } - - /** * Creates {@link SampleChunk} I/O handler. * * @param ids track names @@ -142,8 +121,8 @@ public class SampleChunkIoHelper implements Handler.Callback { * @param bufferManager manager of {@link SampleChunk} collections * @param samplePool allocator for a sample * @param ioCallback listeners for I/O events + * @param concurrentDvrPlaybackFlags */ - @AutoFactory(implementing = Factory.class) public SampleChunkIoHelper( List<String> ids, List<MediaFormat> mediaFormats, @@ -151,7 +130,7 @@ public class SampleChunkIoHelper implements Handler.Callback { BufferManager bufferManager, SamplePool samplePool, IoCallback ioCallback, - @Provided DvrFlags dvrFlags) { + ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags) { mTrackCount = ids.size(); mIds = ids; mMediaFormats = mediaFormats; @@ -159,7 +138,7 @@ public class SampleChunkIoHelper implements Handler.Callback { mBufferManager = bufferManager; mSamplePool = samplePool; mIoCallback = ioCallback; - mDvrFlags = dvrFlags; + mConcurrentDvrPlaybackFlags = concurrentDvrPlaybackFlags; mReadSampleBuffers = new ConcurrentLinkedQueue[mTrackCount]; mHandlerReadSampleBuffers = new ConcurrentLinkedQueue[mTrackCount]; @@ -205,7 +184,9 @@ public class SampleChunkIoHelper implements Handler.Callback { } try { - if (mBufferReason == RecordingSampleBuffer.BUFFER_REASON_RECORDING && mTrackCount > 0) { + if (mConcurrentDvrPlaybackFlags.enabled() + && mBufferReason == RecordingSampleBuffer.BUFFER_REASON_RECORDING + && mTrackCount > 0) { // Saves meta information for recording. List<BufferManager.TrackFormat> audios = new ArrayList<>(mTrackCount); List<BufferManager.TrackFormat> videos = new ArrayList<>(mTrackCount); @@ -213,14 +194,6 @@ public class SampleChunkIoHelper implements Handler.Callback { android.media.MediaFormat format = mMediaFormats.get(i).getFrameworkMediaFormatV16(); format.setLong(android.media.MediaFormat.KEY_DURATION, mBufferDurationUs); - if (mDvrFlags.storeVideoAspectRatio() && - mMediaFormats.get(i).pixelWidthHeightRatio > 0) { - // MediaFormats doesn't store aspect ratio so updating the width - // to maintain aspect ratio. - format.setInteger(android.media.MediaFormat.KEY_WIDTH, - (int) (mMediaFormats.get(i).width * - mMediaFormats.get(i).pixelWidthHeightRatio)); - } if (MimeTypes.isAudio(mMediaFormats.get(i).mimeType)) { audios.add(new BufferManager.TrackFormat(mIds.get(i), format)); } else if (MimeTypes.isVideo(mMediaFormats.get(i).mimeType)) { @@ -329,14 +302,6 @@ public class SampleChunkIoHelper implements Handler.Callback { android.media.MediaFormat format = mMediaFormats.get(i).getFrameworkMediaFormatV16(); format.setLong(android.media.MediaFormat.KEY_DURATION, mBufferDurationUs); - if (mDvrFlags.storeVideoAspectRatio() && - mMediaFormats.get(i).pixelWidthHeightRatio > 0) { - // MediaFormats doesn't store aspect ratio so updating the width - // to maintain aspect ratio. - format.setInteger(android.media.MediaFormat.KEY_WIDTH, - (int) (mMediaFormats.get(i).width * - mMediaFormats.get(i).pixelWidthHeightRatio)); - } if (MimeTypes.isAudio(mMediaFormats.get(i).mimeType)) { audios.add(new BufferManager.TrackFormat(mIds.get(i), format)); } else if (MimeTypes.isVideo(mMediaFormats.get(i).mimeType)) { @@ -419,7 +384,8 @@ public class SampleChunkIoHelper implements Handler.Callback { private void doOpenWrite(int index) throws IOException { boolean updateIndexFile = - (mBufferReason == RecordingSampleBuffer.BUFFER_REASON_RECORDING) + mConcurrentDvrPlaybackFlags.enabled() + && (mBufferReason == RecordingSampleBuffer.BUFFER_REASON_RECORDING) && (MimeTypes.isVideo(mMediaFormats.get(index).mimeType) || MimeTypes.isAudio(mMediaFormats.get(index).mimeType)); @@ -460,10 +426,13 @@ public class SampleChunkIoHelper implements Handler.Callback { SampleHolder sample = mReadIoStates[index].read(); if (sample != null) { mHandlerReadSampleBuffers[index].offer(sample); - mReadChunkOffset[index] = mReadIoStates[index].getOffset(); - mReadChunkPositionUs[index] = sample.timeUs; + if (mConcurrentDvrPlaybackFlags.enabled()) { + mReadChunkOffset[index] = mReadIoStates[index].getOffset(); + mReadChunkPositionUs[index] = sample.timeUs; + } } else { - if (mBufferReason == RecordingSampleBuffer.BUFFER_REASON_RECORDED_PLAYBACK) { + if (mConcurrentDvrPlaybackFlags.enabled() + && mBufferReason == RecordingSampleBuffer.BUFFER_REASON_RECORDED_PLAYBACK) { // Update Index, to load new Samples updateIndex(index, mReadChunkOffset[index]); } @@ -516,7 +485,9 @@ public class SampleChunkIoHelper implements Handler.Callback { : mWriteIoStates[params.index].getChunk(); int currentOffset = (int) mWriteIoStates[params.index].getOffset(); boolean updateIndexFile = - (mBufferReason == RecordingSampleBuffer.BUFFER_REASON_RECORDING) + mConcurrentDvrPlaybackFlags.enabled() + && (mBufferReason + == RecordingSampleBuffer.BUFFER_REASON_RECORDING) && (MimeTypes.isVideo(mMediaFormats.get(index).mimeType) || MimeTypes.isAudio( mMediaFormats.get(index).mimeType)); diff --git a/tuner/src/com/android/tv/tuner/exoplayer2/VideoRendererExoV2.java b/tuner/src/com/android/tv/tuner/exoplayer2/VideoRendererExoV2.java index a71352f3..12039002 100644 --- a/tuner/src/com/android/tv/tuner/exoplayer2/VideoRendererExoV2.java +++ b/tuner/src/com/android/tv/tuner/exoplayer2/VideoRendererExoV2.java @@ -24,6 +24,7 @@ import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.mediacodec.MediaCodecInfo; import com.google.android.exoplayer2.mediacodec.MediaCodecSelector; import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException; +import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.video.MediaCodecVideoRenderer; import com.google.android.exoplayer2.video.VideoRendererEventListener; import java.lang.reflect.Field; @@ -47,8 +48,8 @@ public class VideoRendererExoV2 extends MediaCodecVideoRenderer { private static final String SOFTWARE_DECODER_NAME_PREFIX = "OMX.google."; private static final long ALLOWED_JOINING_TIME_MS = 5000; private static final int DROPPED_FRAMES_NOTIFICATION_THRESHOLD = 10; - // private static final int MIN_HD_HEIGHT = 720; - private static Field sRenderedFirstFrameField; + private static final int MIN_HD_HEIGHT = 720; + private static Field sRenderedFirstFrameField; private final boolean mIsSwCodecEnabled; private boolean mCodecIsSwPreferred; @@ -107,18 +108,16 @@ public class VideoRendererExoV2 extends MediaCodecVideoRenderer { return decoderInfos; } - // TODO: Uncomment once ExoPlayer v2.10.0 is released [Internal ref: b/130625979]. - // @Override - // protected void onInputFormatChanged(FormatHolder formatHolder) throws ExoPlaybackException { - // Format format = formatHolder.format; - // mCodecIsSwPreferred = - // MimeTypes.VIDEO_MPEG2.equals(format.sampleMimeType) - // && format.height < MIN_HD_HEIGHT; - // super.onInputFormatChanged(format); - // } + @Override + protected void onInputFormatChanged(Format format) throws ExoPlaybackException { + mCodecIsSwPreferred = + MimeTypes.VIDEO_MPEG2.equals(format.sampleMimeType) + && format.height < MIN_HD_HEIGHT; + super.onInputFormatChanged(format); + } - @Override - protected void onPositionReset(long positionUs, boolean joining) throws ExoPlaybackException { + @Override + protected void onPositionReset(long positionUs, boolean joining) throws ExoPlaybackException { super.onPositionReset(positionUs, joining); // Disabling pre-rendering of the first frame in order to avoid a frozen picture when // starting the playback. We do this only once, when the renderer is enabled at first, since diff --git a/tuner/src/com/android/tv/tuner/features/TunerFeatures.java b/tuner/src/com/android/tv/tuner/features/TunerFeatures.java index 6ee5aa8c..6033a3a6 100644 --- a/tuner/src/com/android/tv/tuner/features/TunerFeatures.java +++ b/tuner/src/com/android/tv/tuner/features/TunerFeatures.java @@ -19,9 +19,9 @@ package com.android.tv.tuner.features; import static com.android.tv.common.feature.FeatureUtils.OFF; import com.android.tv.common.feature.CommonFeatures; -import com.android.tv.common.feature.DeveloperPreferenceFeature; import com.android.tv.common.feature.Feature; import com.android.tv.common.feature.Model; +import com.android.tv.common.feature.PropertyFeature; import com.android.tv.common.feature.Sdk; /** @@ -39,11 +39,10 @@ public class TunerFeatures extends CommonFeatures { * <p>Prefer software based codec for SD channels. */ public static final Feature USE_SW_CODEC_FOR_SD = - DeveloperPreferenceFeature.create( + PropertyFeature.create( "use_sw_codec_for_sd", - // On Nexus Player, SW codec is better than HW codec in terms of picture - // quality. - Model.NEXUS_PLAYER.isEnabled()); + false + ); /** * Does the TvProvider on the installed device allow systems inserts to the programs table. diff --git a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunChannelScan.java b/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunChannelScan.java deleted file mode 100644 index 38610dd1..00000000 --- a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunChannelScan.java +++ /dev/null @@ -1,206 +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.tuner.hdhomerun; - -import android.content.Context; -import android.media.tv.TvContract; -import android.os.ConditionVariable; -import android.util.Log; -import android.util.Xml; -import com.android.tv.tuner.api.ChannelScanListener; -import com.android.tv.tuner.data.TunerChannel; -import com.android.tv.tuner.ts.EventDetector.EventListener; -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.regex.Pattern; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -/** A helper class to perform channel scan on HDHomeRun tuner. */ -public class HdHomeRunChannelScan { - private static final String TAG = "HdHomeRunChannelScan"; - private static final boolean DEBUG = false; - - private static final String LINEUP_FILENAME = "lineup.xml"; - private static final String NAME_LINEUP = "Lineup"; - private static final String NAME_PROGRAM = "Program"; - private static final String NAME_GUIDE_NUMBER = "GuideNumber"; - private static final String NAME_GUIDE_NAME = "GuideName"; - private static final String NAME_HD = "HD"; - private static final String NAME_TAGS = "Tags"; - private static final String NAME_DRM = "DRM"; - - private final Context mContext; - private final ChannelScanListener mEventListener; - private final HdHomeRunTunerHal mTunerHal; - private int mProgramCount; - - public HdHomeRunChannelScan( - Context context, EventListener eventListener, HdHomeRunTunerHal hal) { - mContext = context; - mEventListener = eventListener; - mTunerHal = hal; - } - - public void scan(ConditionVariable conditionStopped) { - String urlString = "http://" + mTunerHal.getIpAddress() + "/" + LINEUP_FILENAME; - if (DEBUG) Log.d(TAG, "Reading " + urlString); - URL url; - HttpURLConnection connection = null; - InputStream inputStream; - try { - url = new URL(urlString); - connection = (HttpURLConnection) url.openConnection(); - connection.setReadTimeout(HdHomeRunTunerHal.READ_TIMEOUT_MS_FOR_URLCONNECTION); - connection.setConnectTimeout(HdHomeRunTunerHal.CONNECTION_TIMEOUT_MS_FOR_URLCONNECTION); - connection.setRequestMethod("GET"); - connection.setDoInput(true); - connection.connect(); - inputStream = connection.getInputStream(); - } catch (IOException e) { - Log.e(TAG, "Connection failed: " + urlString, e); - if (connection != null) { - connection.disconnect(); - } - return; - } - if (conditionStopped.block(-1)) { - try { - inputStream.close(); - } catch (IOException e) { - // Does nothing. - } - connection.disconnect(); - return; - } - - XmlPullParser parser = Xml.newPullParser(); - try { - parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false); - parser.setInput(inputStream, null); - parser.nextTag(); - parser.require(XmlPullParser.START_TAG, null, NAME_LINEUP); - while (parser.next() != XmlPullParser.END_TAG) { - if (conditionStopped.block(-1)) { - break; - } - if (parser.getEventType() != XmlPullParser.START_TAG) { - continue; - } - String name = parser.getName(); - // Starts by looking for the program tag - if (name.equals(NAME_PROGRAM)) { - readProgram(parser); - } else { - skip(parser); - } - } - inputStream.close(); - } catch (IOException | XmlPullParserException e) { - Log.e(TAG, "Parse error", e); - } - connection.disconnect(); - mTunerHal.markAsScannedDevice(mContext); - } - - private void readProgram(XmlPullParser parser) throws XmlPullParserException, IOException { - parser.require(XmlPullParser.START_TAG, null, NAME_PROGRAM); - String guideNumber = ""; - String guideName = ""; - String videoFormat = null; - String tags = ""; - boolean recordingProhibited = false; - while (parser.next() != XmlPullParser.END_TAG) { - if (parser.getEventType() != XmlPullParser.START_TAG) { - continue; - } - String name = parser.getName(); - if (name.equals(NAME_GUIDE_NUMBER)) { - guideNumber = readText(parser, NAME_GUIDE_NUMBER); - } else if (name.equals(NAME_GUIDE_NAME)) { - guideName = readText(parser, NAME_GUIDE_NAME); - } else if (name.equals(NAME_HD)) { - videoFormat = TvContract.Channels.VIDEO_FORMAT_720P; - skip(parser); - } else if (name.equals(NAME_TAGS)) { - tags = readText(parser, NAME_TAGS); - } else if (name.equals(NAME_DRM)) { - String drm = readText(parser, NAME_DRM); - try { - recordingProhibited = (Integer.parseInt(drm)) != 0; - } catch (NumberFormatException e) { - Log.e(TAG, "Load DRM property failed: illegal number: " + drm); - // If DRM property is present, we treat it as copy-once or copy-never. - recordingProhibited = true; - } - } else { - skip(parser); - } - } - if (!tags.isEmpty()) { - // Skip encrypted channels since we don't know how to decrypt them. - return; - } - int major; - int minor = 0; - final String separator = Character.toString(HdHomeRunTunerHal.VCHANNEL_SEPARATOR); - if (guideNumber.contains(separator)) { - String[] parts = guideNumber.split(Pattern.quote(separator)); - major = Integer.parseInt(parts[0]); - minor = Integer.parseInt(parts[1]); - } else { - major = Integer.parseInt(guideNumber); - } - // Need to assign a unique program number (i.e. mProgramCount) to avoid being duplicated. - mEventListener.onChannelDetected( - TunerChannel.forNetwork( - major, minor, mProgramCount++, guideName, recordingProhibited, videoFormat), - true); - } - - private String readText(XmlPullParser parser, String name) - throws IOException, XmlPullParserException { - String result = ""; - parser.require(XmlPullParser.START_TAG, null, name); - if (parser.next() == XmlPullParser.TEXT) { - result = parser.getText(); - parser.nextTag(); - } - parser.require(XmlPullParser.END_TAG, null, name); - if (DEBUG) Log.d(TAG, "<" + name + ">=" + result); - return result; - } - - private void skip(XmlPullParser parser) throws XmlPullParserException, IOException { - if (parser.getEventType() != XmlPullParser.START_TAG) { - throw new IllegalStateException(); - } - int depth = 1; - while (depth != 0) { - switch (parser.next()) { - case XmlPullParser.END_TAG: - depth--; - break; - case XmlPullParser.START_TAG: - depth++; - break; - } - } - } -} diff --git a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunControlSocket.java b/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunControlSocket.java deleted file mode 100644 index ce7c5180..00000000 --- a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunControlSocket.java +++ /dev/null @@ -1,226 +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.tuner.hdhomerun; - -import android.support.annotation.Nullable; -import android.util.Log; -import android.util.Pair; -import com.android.tv.tuner.hdhomerun.HdHomeRunDiscover.HdHomeRunDiscoverDevice; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.List; - -/** - * A class to send/receive control commands and results to/from HDHomeRun devices via TCP sockets. - * {@link #close()} method should be called after usage to close the TCP socket. - */ -class HdHomeRunControlSocket implements AutoCloseable { - private static final String TAG = "HdHomeRunControlSocket"; - private static final boolean DEBUG = false; - - private int mDesiredDeviceId; - private int mDesiredDeviceIp; - private int mActualDeviceId; - private int mActualDeviceIp; - private Socket mSocket; - - HdHomeRunControlSocket(int deviceId, int deviceIp) { - mDesiredDeviceId = deviceId; - mDesiredDeviceIp = deviceIp; - mActualDeviceId = 0; - mActualDeviceIp = 0; - } - - /** - * Gets control settings from HDHomeRun devices. - * - * @param name the name of the field whose value we want to get. - */ - @Nullable - String get(String name) { - byte[] data = new byte[name.length() + 3]; - ByteBuffer buffer = ByteBuffer.wrap(data); - buffer.put(HdHomeRunUtils.HDHOMERUN_TAG_GETSET_NAME); - buffer.put((byte) (name.length() + 1)); - buffer.put(name.getBytes()); - - // Send & Receive. - byte[] result = - sendAndReceive( - data, - HdHomeRunUtils.HDHOMERUN_TYPE_GETSET_REQUEST, - HdHomeRunUtils.HDHOMERUN_CONTROL_RECEIVE_TIMEOUT_MS); - if (result == null) { - if (DEBUG) Log.d(TAG, "Cannot get result for " + name); - return null; - } - - // Response. - buffer = ByteBuffer.wrap(result); - while (true) { - Pair<Byte, byte[]> tagAndValue = HdHomeRunUtils.readTaggedValue(buffer); - if (tagAndValue == null) { - break; - } - switch (tagAndValue.first) { - case HdHomeRunUtils.HDHOMERUN_TAG_GETSET_VALUE: - // Removes the 0 tail. - return new String( - Arrays.copyOfRange( - tagAndValue.second, 0, tagAndValue.second.length - 1)); - case HdHomeRunUtils.HDHOMERUN_TAG_ERROR_MESSAGE: - return null; - } - } - return null; - } - - /** Gets ID of HDHomeRun devices. */ - int getDeviceId() { - if (!connectAndUpdateDeviceInfo()) { - return 0; - } - return mActualDeviceId; - } - - private boolean connectAndUpdateDeviceInfo() { - if (mSocket != null) { - return true; - } - if ((mDesiredDeviceId == 0) && (mDesiredDeviceIp == 0)) { - if (DEBUG) Log.d(TAG, "Desired ID and IP cannot be both zero."); - return false; - } - if (HdHomeRunUtils.isIpMulticast(mDesiredDeviceIp)) { - if (DEBUG) Log.d(TAG, "IP cannot be multicast IP."); - return false; - } - - // Find device. - List<HdHomeRunDiscoverDevice> result = - HdHomeRunUtils.findHdHomeRunDevices( - mDesiredDeviceIp, - HdHomeRunUtils.HDHOMERUN_DEVICE_TYPE_WILDCARD, - mDesiredDeviceId, - 1); - if (result.isEmpty()) { - if (DEBUG) Log.d(TAG, "Cannot find device on: " + mDesiredDeviceIp); - return false; - } - mActualDeviceIp = result.get(0).mIpAddress; - mActualDeviceId = result.get(0).mDeviceId; - - // Create socket and initiate connection. - mSocket = new Socket(); - try { - mSocket.connect( - new InetSocketAddress( - HdHomeRunUtils.intToAddress(mActualDeviceIp), - HdHomeRunUtils.HDHOMERUN_CONTROL_TCP_PORT), - HdHomeRunUtils.HDHOMERUN_CONTROL_CONNECT_TIMEOUT_MS); - } catch (IOException e) { - if (DEBUG) Log.d(TAG, "Cannot connect to socket: " + mSocket); - mSocket = null; - return false; - } - - // Success. - Log.i(TAG, "Connected to socket: " + mSocket); - return true; - } - - private byte[] sendAndReceive(byte[] data, short type, int timeout) { - byte[] sealedData = HdHomeRunUtils.sealFrame(data, type); - for (int i = 0; i < 2; i++) { - if (mSocket == null && !connectAndUpdateDeviceInfo()) { - return null; - } - if (!send(sealedData)) { - continue; - } - Pair<Short, byte[]> receivedData = receive(timeout); - if (receivedData == null || receivedData.first == null) { - continue; - } - if (receivedData.first != type + 1) { - if (DEBUG) Log.d(TAG, "Returned type incorrect: " + receivedData.first); - close(); - continue; - } - return receivedData.second; - } - return null; - } - - private boolean send(byte[] data) { - try { - OutputStream out = mSocket.getOutputStream(); - mSocket.setSoTimeout(HdHomeRunUtils.HDHOMERUN_CONTROL_SEND_TIMEOUT_MS); - out.write(data); - } catch (IOException e) { - if (DEBUG) Log.d(TAG, "Cannot send packet to socket: " + mSocket); - close(); - return false; - } - return true; - } - - private Pair<Short, byte[]> receive(int timeout) { - byte[] receivedData = new byte[3074]; - try { - InputStream input = mSocket.getInputStream(); - mSocket.setSoTimeout(timeout); - int index = 0; - long startTime = System.currentTimeMillis(); - while (System.currentTimeMillis() - startTime < timeout) { - int length = receivedData.length - index; - index += input.read(receivedData, index, length); - Pair<Short, byte[]> result = HdHomeRunUtils.openFrame(receivedData, index); - if (result != null) { - if (result.first == HdHomeRunUtils.HDHOMERUN_TYPE_INVALID) { - if (DEBUG) Log.d(TAG, "Returned type is invalid."); - close(); - return null; - } - return result; - } - if (DEBUG) Log.d(TAG, "Received result is null!"); - } - } catch (IOException e) { - if (DEBUG) Log.d(TAG, "Cannot receive from socket: " + mSocket); - close(); - } - return null; - } - - @Override - public void close() { - if (mSocket != null) { - try { - mSocket.close(); - } catch (IOException e) { - // Do nothing - } - mSocket = null; - } - } -} diff --git a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunDevice.java b/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunDevice.java deleted file mode 100644 index dcf87cad..00000000 --- a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunDevice.java +++ /dev/null @@ -1,177 +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.tuner.hdhomerun; - -import android.os.Parcel; -import android.os.Parcelable; -import android.text.TextUtils; - -/** - * An HDHomeRun device detected on the network. This abstraction only contains network data - * necessary to establish a connection with the device and does not represent a communication - * channel with the device itself. Currently, we only support devices with HTTP streaming - * functionality. - */ -public class HdHomeRunDevice implements Parcelable { - private int mIpAddress; - private int mDeviceType; - private int mDeviceId; - private int mTunerIndex; - private String mDeviceModel; - - /** - * Creates {@code HdHomeRunDevice} object from a parcel. - * - * @param parcel The parcel to create {@code HdHomeRunDevice} object from. - */ - public HdHomeRunDevice(Parcel parcel) { - mIpAddress = parcel.readInt(); - mDeviceType = parcel.readInt(); - mDeviceId = parcel.readInt(); - mTunerIndex = parcel.readInt(); - mDeviceModel = parcel.readString(); - } - - /** - * Creates {@code HdHomeRunDevice} object from IP address, device type, device ID and tuner - * index. - * - * @param ipAddress The IP address to create {@code HdHomeRunDevice} object from. - * @param deviceType The device type to create {@code HdHomeRunDevice} object from. - * @param deviceId The device ID to create {@code HdHomeRunDevice} object from. - * @param tunerIndex The tuner index to {@code HdHomeRunDevice} object from. - */ - public HdHomeRunDevice( - int ipAddress, int deviceType, int deviceId, int tunerIndex, String deviceModel) { - mIpAddress = ipAddress; - mDeviceType = deviceType; - mDeviceId = deviceId; - mTunerIndex = tunerIndex; - mDeviceModel = deviceModel; - } - - /** - * Returns the IP address. - * - * @return the IP address of this homerun device. - */ - public int getIpAddress() { - return mIpAddress; - } - - /** - * Returns the device type. - * - * @return the type of device for this homerun device. - */ - public int getDeviceType() { - return mDeviceType; - } - - /** - * Returns the device ID. - * - * @return the device ID of this homerun device. - */ - public int getDeviceId() { - return mDeviceId; - } - - /** - * Returns the tuner index. - * - * @return the tuner index of this homerun device. - */ - public int getTunerIndex() { - return mTunerIndex; - } - - /** - * Returns the device model. - * - * @return the device model of this homerun device. - */ - public String getDeviceModel() { - return mDeviceModel; - } - - @Override - public String toString() { - String ipAddress = - "" - + ((mIpAddress >>> 24) & 0xff) - + "." - + ((mIpAddress >>> 16) & 0xff) - + "." - + ((mIpAddress >>> 8) & 0xff) - + "." - + (mIpAddress & 0xff); - return String.format("[%x-%d:%s]", mDeviceId, mTunerIndex, ipAddress); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(mIpAddress); - out.writeInt(mDeviceType); - out.writeInt(mDeviceId); - out.writeInt(mTunerIndex); - out.writeString(mDeviceModel); - } - - @Override - public int hashCode() { - int hash = 17; - hash = hash * 31 + getIpAddress(); - hash = hash * 31 + getDeviceType(); - hash = hash * 31 + getDeviceId(); - hash = hash * 31 + getTunerIndex(); - return hash; - } - - @Override - public boolean equals(Object o) { - if (!(o instanceof HdHomeRunDevice)) { - return false; - } - HdHomeRunDevice rhs = (HdHomeRunDevice) o; - return rhs != null - && getIpAddress() == rhs.getIpAddress() - && getDeviceType() == rhs.getDeviceType() - && getDeviceId() == rhs.getDeviceId() - && getTunerIndex() == rhs.getTunerIndex() - && TextUtils.equals(getDeviceModel(), rhs.getDeviceModel()); - } - - public static final Parcelable.Creator<HdHomeRunDevice> CREATOR = - new Parcelable.Creator<HdHomeRunDevice>() { - - @Override - public HdHomeRunDevice createFromParcel(Parcel in) { - return new HdHomeRunDevice(in); - } - - @Override - public HdHomeRunDevice[] newArray(int size) { - return new HdHomeRunDevice[size]; - } - }; -} diff --git a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunDiscover.java b/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunDiscover.java deleted file mode 100644 index 85b3450e..00000000 --- a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunDiscover.java +++ /dev/null @@ -1,446 +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.tuner.hdhomerun; - -import android.support.annotation.NonNull; -import android.util.Log; -import android.util.Pair; -import java.io.IOException; -import java.net.DatagramPacket; -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.InterfaceAddress; -import java.net.NetworkInterface; -import java.net.SocketException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.List; - -/** A class to discover HDHomeRun devices on the network with UDP broadcasting. */ -class HdHomeRunDiscover { - private static final String TAG = "HdHomeRunDiscover"; - private static final boolean DEBUG = false; - - private static final int HDHOMERUN_DISCOVER_MAX_SOCK_COUNT = 16; - private static final int HDHOMERUN_DISCOVER_RETRY_LIMIT = 2; - private static final int HDHOMERUN_DISCOVER_TIMEOUT_MS = 500; - private static final int HDHOMERUN_DISCOVER_RECEIVE_WAITE_TIME_MS = 10; - - private List<HdHomeRunDiscoverSocket> mSockets = new ArrayList<>(); - - /** Creates a discover object. If cannot add a default socket, return {@code null}. */ - static HdHomeRunDiscover create() { - HdHomeRunDiscover hdHomeRunDiscover = new HdHomeRunDiscover(); - // Create a routable socket (always first entry). - if (!hdHomeRunDiscover.addSocket(0, 0)) { - return null; - } - return hdHomeRunDiscover; - } - - /** Closes and releases all sockets required by this discover object. */ - void close() { - for (HdHomeRunDiscoverSocket discoverSocket : mSockets) { - discoverSocket.close(); - } - } - - /** Finds HDHomeRun devices. */ - @NonNull - List<HdHomeRunDiscoverDevice> findDevices( - int targetIp, int deviceType, int deviceId, int maxCount) { - List<HdHomeRunDiscoverDevice> resultList = new ArrayList<>(); - resetLocalIpSockets(); - for (int retry = 0; - retry < HDHOMERUN_DISCOVER_RETRY_LIMIT && resultList.isEmpty(); - retry++) { - int localIpSent = send(targetIp, deviceType, deviceId); - if (localIpSent == 0) { - if (DEBUG) { - Log.d(TAG, "Cannot send to target ip: " + HdHomeRunUtils.getIpString(targetIp)); - } - continue; - } - long timeout = System.currentTimeMillis() + HDHOMERUN_DISCOVER_TIMEOUT_MS * localIpSent; - while (System.currentTimeMillis() < timeout) { - HdHomeRunDiscoverDevice result = new HdHomeRunDiscoverDevice(); - if (!receive(result)) { - continue; - } - // Filter. - if (deviceType != HdHomeRunUtils.HDHOMERUN_DEVICE_TYPE_WILDCARD - && deviceType != result.mDeviceType) { - continue; - } - if (deviceId != HdHomeRunUtils.HDHOMERUN_DEVICE_ID_WILDCARD - && deviceId != result.mDeviceId) { - continue; - } - if (isObsoleteDevice(deviceId)) { - continue; - } - // Ensure not already in list. - if (resultList.contains(result)) { - continue; - } - // Add to list. - resultList.add(result); - if (resultList.size() >= maxCount) { - break; - } - } - } - return resultList; - } - - private boolean addSocket(int localIp, int subnetMask) { - for (int i = 1; i < mSockets.size(); i++) { - HdHomeRunDiscoverSocket discoverSocket = mSockets.get(i); - if ((discoverSocket.mLocalIp == localIp) - && (discoverSocket.mSubnetMask == subnetMask)) { - discoverSocket.mDetected = true; - return true; - } - } - if (mSockets.size() >= HDHOMERUN_DISCOVER_MAX_SOCK_COUNT) { - return false; - } - DatagramSocket socket; - try { - socket = new DatagramSocket(0, HdHomeRunUtils.intToAddress(localIp)); - socket.setBroadcast(true); - } catch (IOException e) { - if (DEBUG) Log.d(TAG, "Cannot create socket: " + HdHomeRunUtils.getIpString(localIp)); - return false; - } - // Write socket entry. - mSockets.add(new HdHomeRunDiscoverSocket(socket, true, localIp, subnetMask)); - return true; - } - - private void resetLocalIpSockets() { - for (int i = 1; i < mSockets.size(); i++) { - mSockets.get(i).mDetected = false; - mSockets.get(i).mDiscoverPacketSent = false; - } - List<LocalIpInfo> ipInfoList = getLocalIpInfo(HDHOMERUN_DISCOVER_MAX_SOCK_COUNT); - for (LocalIpInfo ipInfo : ipInfoList) { - if (DEBUG) { - Log.d( - TAG, - "Add local IP: " - + HdHomeRunUtils.getIpString(ipInfo.mIpAddress) - + ", " - + HdHomeRunUtils.getIpString(ipInfo.mSubnetMask)); - } - addSocket(ipInfo.mIpAddress, ipInfo.mSubnetMask); - } - Iterator<HdHomeRunDiscoverSocket> iterator = mSockets.iterator(); - while (iterator.hasNext()) { - HdHomeRunDiscoverSocket discoverSocket = iterator.next(); - if (!discoverSocket.mDetected) { - discoverSocket.close(); - iterator.remove(); - } - } - } - - private List<LocalIpInfo> getLocalIpInfo(int maxCount) { - Enumeration<NetworkInterface> interfaces; - try { - interfaces = NetworkInterface.getNetworkInterfaces(); - } catch (SocketException e) { - return Collections.emptyList(); - } - List<LocalIpInfo> result = new ArrayList<>(); - while (interfaces.hasMoreElements()) { - NetworkInterface networkInterface = interfaces.nextElement(); - for (InterfaceAddress interfaceAddress : networkInterface.getInterfaceAddresses()) { - InetAddress inetAddress = interfaceAddress.getAddress(); - if (!inetAddress.isAnyLocalAddress() - && !inetAddress.isLinkLocalAddress() - && !inetAddress.isLoopbackAddress() - && !inetAddress.isMulticastAddress()) { - LocalIpInfo localIpInfo = new LocalIpInfo(); - localIpInfo.mIpAddress = HdHomeRunUtils.addressToInt(inetAddress.getAddress()); - localIpInfo.mSubnetMask = - (0x7fffffff >> (31 - interfaceAddress.getNetworkPrefixLength())); - result.add(localIpInfo); - if (result.size() >= maxCount) { - return result; - } - } - } - } - return result; - } - - private int send(int targetIp, int deviceType, int deviceId) { - return targetIp == 0 - ? sendWildcardIp(deviceType, deviceId) - : sendTargetIp(targetIp, deviceType, deviceId); - } - - private int sendWildcardIp(int deviceType, int deviceId) { - int localIpSent = 0; - - // Send subnet broadcast using each local ip socket. - // This will work with multiple separate 169.254.x.x interfaces. - for (int i = 1; i < mSockets.size(); i++) { - HdHomeRunDiscoverSocket discoverSocket = mSockets.get(i); - int targetIp = discoverSocket.mLocalIp | ~discoverSocket.mSubnetMask; - if (DEBUG) Log.d(TAG, "Send: " + HdHomeRunUtils.getIpString(targetIp)); - localIpSent += discoverSocket.send(targetIp, deviceType, deviceId) ? 1 : 0; - } - // If no local ip sockets then fall back to sending a global broadcast letting - // the OS choose the interface. - if (localIpSent == 0) { - if (DEBUG) Log.d(TAG, "Send: " + HdHomeRunUtils.getIpString(0xFFFFFFFF)); - localIpSent = mSockets.get(0).send(0xFFFFFFFF, deviceType, deviceId) ? 1 : 0; - } - return localIpSent; - } - - private int sendTargetIp(int targetIp, int deviceType, int deviceId) { - int localIpSent = 0; - - // Send targeted packet from any local ip that is in the same subnet. - // This will work with multiple separate 169.254.x.x interfaces. - for (int i = 1; i < mSockets.size(); i++) { - HdHomeRunDiscoverSocket discoverSocket = mSockets.get(i); - if (discoverSocket.mSubnetMask == 0) { - continue; - } - if ((targetIp & discoverSocket.mSubnetMask) - != (discoverSocket.mLocalIp & discoverSocket.mSubnetMask)) { - continue; - } - localIpSent += discoverSocket.send(targetIp, deviceType, deviceId) ? 1 : 0; - } - // If target IP does not match a local subnet then fall back to letting the OS choose - // the gateway interface. - if (localIpSent == 0) { - localIpSent = mSockets.get(0).send(targetIp, deviceType, deviceId) ? 1 : 0; - } - return localIpSent; - } - - private boolean receive(HdHomeRunDiscoverDevice result) { - for (HdHomeRunDiscoverSocket discoverSocket : mSockets) { - if (discoverSocket.mDiscoverPacketSent && discoverSocket.receive(result)) { - return true; - } - } - return false; - } - - private boolean isObsoleteDevice(int deviceId) { - switch (deviceId >> 20) { - case 0x100: /* TECH-US/TECH3-US */ - return (deviceId < 0x10040000); - case 0x120: /* TECH3-EU */ - return (deviceId < 0x12030000); - case 0x101: /* HDHR-US */ - case 0x102: /* HDHR-T1-US */ - case 0x103: /* HDHR3-US */ - case 0x111: /* HDHR3-DT */ - case 0x121: /* HDHR-EU */ - case 0x122: /* HDHR3-EU */ - return true; - default: - return false; - } - } - - static class HdHomeRunDiscoverDevice { - int mIpAddress; - int mDeviceType; - int mDeviceId; - int mTunerCount; - String mBaseUrl; - - @Override - public boolean equals(Object other) { - if (this == other) { - return true; - } else if (other instanceof HdHomeRunDiscoverDevice) { - HdHomeRunDiscoverDevice o = (HdHomeRunDiscoverDevice) other; - return mIpAddress == o.mIpAddress - && mDeviceType == o.mDeviceType - && mDeviceId == o.mDeviceId; - } - return false; - } - - @Override - public int hashCode() { - int result = mIpAddress; - result = 31 * result + mDeviceType; - result = 31 * result + mDeviceId; - return result; - } - } - - private static class HdHomeRunDiscoverSocket { - DatagramSocket mSocket; - boolean mDetected; - boolean mDiscoverPacketSent; - int mLocalIp; - int mSubnetMask; - - private HdHomeRunDiscoverSocket( - DatagramSocket socket, boolean detected, int localIp, int subnetMask) { - mSocket = socket; - mDetected = detected; - mLocalIp = localIp; - mSubnetMask = subnetMask; - } - - private boolean send(int targetIp, int deviceType, int deviceId) { - byte[] data = new byte[12]; - ByteBuffer buffer = ByteBuffer.wrap(data); - buffer.put(HdHomeRunUtils.HDHOMERUN_TAG_DEVICE_TYPE); - buffer.put((byte) 4); - buffer.putInt(deviceType); - buffer.put(HdHomeRunUtils.HDHOMERUN_TAG_DEVICE_ID); - buffer.put((byte) 4); - buffer.putInt(deviceId); - data = HdHomeRunUtils.sealFrame(data, HdHomeRunUtils.HDHOMERUN_TYPE_DISCOVER_REQUEST); - try { - DatagramPacket packet = - new DatagramPacket( - data, - data.length, - HdHomeRunUtils.intToAddress(targetIp), - HdHomeRunUtils.HDHOMERUN_DISCOVER_UDP_PORT); - mSocket.send(packet); - if (DEBUG) { - Log.d(TAG, "Discover packet sent to: " + HdHomeRunUtils.getIpString(targetIp)); - } - mDiscoverPacketSent = true; - } catch (IOException e) { - if (DEBUG) { - Log.d( - TAG, - "Cannot send discover packet to socket(" - + HdHomeRunUtils.getIpString(mLocalIp) - + ")"); - } - mDiscoverPacketSent = false; - } - return mDiscoverPacketSent; - } - - private boolean receive(HdHomeRunDiscoverDevice result) { - DatagramPacket packet = new DatagramPacket(new byte[3074], 3074); - try { - mSocket.setSoTimeout(HDHOMERUN_DISCOVER_RECEIVE_WAITE_TIME_MS); - mSocket.receive(packet); - if (DEBUG) Log.d(TAG, "Received packet, size: " + packet.getLength()); - } catch (IOException e) { - if (DEBUG) { - Log.d( - TAG, - "Cannot receive from socket(" - + HdHomeRunUtils.getIpString(mLocalIp) - + ")"); - } - return false; - } - - Pair<Short, byte[]> data = - HdHomeRunUtils.openFrame(packet.getData(), packet.getLength()); - if (data == null - || data.first == null - || data.first != HdHomeRunUtils.HDHOMERUN_TYPE_DISCOVER_REPLY) { - if (DEBUG) Log.d(TAG, "Ill-formed packet: " + Arrays.toString(packet.getData())); - return false; - } - result.mIpAddress = HdHomeRunUtils.addressToInt(packet.getAddress().getAddress()); - if (DEBUG) { - Log.d(TAG, "Get Device IP: " + HdHomeRunUtils.getIpString(result.mIpAddress)); - } - ByteBuffer buffer = ByteBuffer.wrap(data.second); - while (true) { - Pair<Byte, byte[]> tagAndValue = HdHomeRunUtils.readTaggedValue(buffer); - if (tagAndValue == null) { - break; - } - switch (tagAndValue.first) { - case HdHomeRunUtils.HDHOMERUN_TAG_DEVICE_TYPE: - if (tagAndValue.second.length != 4) { - break; - } - result.mDeviceType = ByteBuffer.wrap(tagAndValue.second).getInt(); - if (DEBUG) Log.d(TAG, "Get Device Type: " + result.mDeviceType); - break; - case HdHomeRunUtils.HDHOMERUN_TAG_DEVICE_ID: - if (tagAndValue.second.length != 4) { - break; - } - result.mDeviceId = ByteBuffer.wrap(tagAndValue.second).getInt(); - if (DEBUG) Log.d(TAG, "Get Device ID: " + result.mDeviceId); - break; - case HdHomeRunUtils.HDHOMERUN_TAG_TUNER_COUNT: - if (tagAndValue.second.length != 1) { - break; - } - result.mTunerCount = tagAndValue.second[0]; - if (DEBUG) Log.d(TAG, "Get Tuner Count: " + result.mTunerCount); - break; - case HdHomeRunUtils.HDHOMERUN_TAG_BASE_URL: - result.mBaseUrl = new String(tagAndValue.second); - if (DEBUG) Log.d(TAG, "Get Base URL: " + result.mBaseUrl); - break; - default: - break; - } - } - // Fixup for old firmware. - if (result.mTunerCount == 0) { - switch (result.mDeviceId >> 20) { - case 0x102: - result.mTunerCount = 1; - break; - case 0x100: - case 0x101: - case 0x121: - result.mTunerCount = 2; - break; - default: - break; - } - } - return true; - } - - private void close() { - if (mSocket != null) { - mSocket.close(); - } - } - } - - private static class LocalIpInfo { - int mIpAddress; - int mSubnetMask; - } -} diff --git a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunInterface.java b/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunInterface.java deleted file mode 100644 index 2928aba7..00000000 --- a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunInterface.java +++ /dev/null @@ -1,134 +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.tuner.hdhomerun; - -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.WorkerThread; -import android.util.Log; -import com.android.tv.tuner.hdhomerun.HdHomeRunDiscover.HdHomeRunDiscoverDevice; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** An interface class provides methods to access physical HDHomeRun devices. */ -@WorkerThread -public class HdHomeRunInterface { - private static final String TAG = "HdHomeRunInterface"; - private static final boolean DEBUG = false; - - private static final int FETCH_DEVICE_NAME_TRY_NUM = 2; - private static final int MAX_DEVICES = 1; - private static final boolean DISABLE_CABLE = false; - - /** - * Scans for HDHomeRun devices on the network. - * - * @param deviceId The target device ID we want to find, scans for all available devices if - * {@code null} or the given ID cannot be found. - * @return A set of HDHomeRun devices - */ - @NonNull - public static Set<HdHomeRunDevice> scanDevices(Integer deviceId) { - List<HdHomeRunDiscoverDevice> discoveredDevices = null; - if (deviceId != null) { - discoveredDevices = - HdHomeRunUtils.findHdHomeRunDevices( - 0, HdHomeRunUtils.HDHOMERUN_DEVICE_TYPE_TUNER, deviceId, 1); - if (discoveredDevices.isEmpty()) { - Log.i(TAG, "Can't find device with ID: " + deviceId); - } - } - if (discoveredDevices == null || discoveredDevices.isEmpty()) { - discoveredDevices = - HdHomeRunUtils.findHdHomeRunDevices( - 0, - HdHomeRunUtils.HDHOMERUN_DEVICE_TYPE_TUNER, - HdHomeRunUtils.HDHOMERUN_DEVICE_ID_WILDCARD, - MAX_DEVICES); - if (DEBUG) Log.d(TAG, "Found " + discoveredDevices.size() + " devices"); - } - Set<HdHomeRunDevice> result = new HashSet<>(); - for (HdHomeRunDiscoverDevice discoveredDevice : discoveredDevices) { - String model = - fetchDeviceModel(discoveredDevice.mDeviceId, discoveredDevice.mIpAddress); - if (model == null) { - Log.e(TAG, "Fetching device model failed: " + discoveredDevice.mDeviceId); - continue; - } else if (DEBUG) { - Log.d(TAG, "Fetch Device Model: " + model); - } - if (DISABLE_CABLE) { - if (model != null && model.contains("cablecard")) { - // filter out CableCARD devices - continue; - } - } - for (int i = 0; i < discoveredDevice.mTunerCount; i++) { - result.add( - new HdHomeRunDevice( - discoveredDevice.mIpAddress, - discoveredDevice.mDeviceType, - discoveredDevice.mDeviceId, - i, - model)); - } - } - return result; - } - - /** - * Returns {@code true} if the given device IP, ID and tuner index is available for use. - * - * @param deviceId The target device ID, 0 denotes a wildcard match. - * @param deviceIp The target device IP. - * @param tunerIndex The target tuner index of the target device. This parameter is only - * meaningful when the target device has multiple tuners. - */ - public static boolean isDeviceAvailable(int deviceId, int deviceIp, int tunerIndex) { - // TODO: check the lock state for the given tuner. - if ((deviceId == 0) && (deviceIp == 0)) { - return false; - } - if (HdHomeRunUtils.isIpMulticast(deviceIp)) { - return false; - } - if ((deviceId == 0) || (deviceId == HdHomeRunUtils.HDHOMERUN_DEVICE_ID_WILDCARD)) { - try (HdHomeRunControlSocket controlSock = - new HdHomeRunControlSocket(deviceId, deviceIp)) { - deviceId = controlSock.getDeviceId(); - } - } - return deviceId != 0; - } - - @Nullable - private static String fetchDeviceModel(int deviceId, int deviceIp) { - for (int i = 0; i < FETCH_DEVICE_NAME_TRY_NUM; i++) { - try (HdHomeRunControlSocket controlSock = - new HdHomeRunControlSocket(deviceId, deviceIp)) { - String model = controlSock.get("/sys/model"); - if (model != null) { - return model; - } - } - } - return null; - } - - private HdHomeRunInterface() {} -} diff --git a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunTunerHal.java b/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunTunerHal.java deleted file mode 100644 index 81682991..00000000 --- a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunTunerHal.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.tuner.hdhomerun; - -import android.content.Context; -import android.text.TextUtils; -import android.util.Log; -import com.android.tv.common.SoftPreconditions; -import com.android.tv.common.compat.TvInputConstantCompat; -import com.android.tv.tuner.api.Tuner; -import com.android.tv.tuner.data.TunerChannel; -import java.io.BufferedInputStream; -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLConnection; - -/** Tuner implementation for HdHomeRun */ -public class HdHomeRunTunerHal implements Tuner { - private static final String TAG = "HdHomeRunTunerHal"; - private static final boolean DEBUG = false; - - private static final String CABLECARD_MODEL = "cablecard"; - private static final String ATSC_MODEL = "atsc"; - private static final String DVBC_MODEL = "dvbc"; - private static final String DVBT_MODEL = "dvbt"; - - private final HdHomeRunTunerManager mTunerManager; - private HdHomeRunDevice mDevice; - private BufferedInputStream mInputStream; - private HttpURLConnection mConnection; - private String mHttpConnectionAddress; - private final Context mContext; - - @DeliverySystemType private int mDeliverySystemType = DELIVERY_SYSTEM_UNDEFINED; - - public static final char VCHANNEL_SEPARATOR = '.'; - public static final int CONNECTION_TIMEOUT_MS_FOR_URLCONNECTION = 3000; // 3 sec - public static final int READ_TIMEOUT_MS_FOR_URLCONNECTION = 10000; // 10 sec - - public HdHomeRunTunerHal(Context context) { - mTunerManager = HdHomeRunTunerManager.getInstance(); - mContext = context; - } - - @Override - public boolean openFirstAvailable() { - SoftPreconditions.checkState(mDevice == null); - try { - mDevice = mTunerManager.acquireDevice(mContext); - if (mDevice != null) { - if (mDeliverySystemType == DELIVERY_SYSTEM_UNDEFINED) { - mDeliverySystemType = nativeGetDeliverySystemType(getDeviceId()); - } - } - return mDevice != null; - } catch (Exception e) { - Log.w(TAG, "Failed to open first available device", e); - return false; - } - } - - @Override - public boolean isDeviceOpen() { - return mDevice != null; - } - - @Override - public boolean isReusable() { - return false; - } - - @Override - public long getDeviceId() { - return mDevice == null ? 0 : mDevice.getDeviceId(); - } - - @Override - public void close() throws Exception { - closeInputStreamAndDisconnect(); - if (mDevice != null) { - mTunerManager.releaseDevice(mDevice); - mDevice = null; - } - } - - @Override - public synchronized boolean tune( - int frequency, @ModulationType String modulation, String channelNumber) { - if (DEBUG) { - Log.d( - TAG, - "tune(frequency=" - + frequency - + ", modulation=" - + modulation - + ", channelNumber=" - + channelNumber - + ")"); - } - closeInputStreamAndDisconnect(); - if (TextUtils.isEmpty(channelNumber)) { - return false; - } - channelNumber = - channelNumber.replace(TunerChannel.CHANNEL_NUMBER_SEPARATOR, VCHANNEL_SEPARATOR); - mHttpConnectionAddress = "http://" + getIpAddress() + ":5004/auto/v" + channelNumber; - return connectAndOpenInputStream(); - } - - private boolean connectAndOpenInputStream() { - URL url; - try { - url = new URL(mHttpConnectionAddress); - } catch (MalformedURLException e) { - Log.e(TAG, "Invalid address: " + mHttpConnectionAddress, e); - return false; - } - URLConnection connection; - try { - connection = url.openConnection(); - connection.setConnectTimeout(CONNECTION_TIMEOUT_MS_FOR_URLCONNECTION); - connection.setReadTimeout(READ_TIMEOUT_MS_FOR_URLCONNECTION); - if (connection instanceof HttpURLConnection) { - mConnection = (HttpURLConnection) connection; - } - } catch (IOException e) { - Log.e(TAG, "Connection failed: " + mHttpConnectionAddress, e); - return false; - } - try { - mInputStream = new BufferedInputStream(connection.getInputStream()); - } catch (IOException e) { - closeInputStreamAndDisconnect(); - Log.e(TAG, "Failed to get input stream from " + mHttpConnectionAddress, e); - return false; - } - if (DEBUG) Log.d(TAG, "tuning to " + mHttpConnectionAddress); - return true; - } - - @Override - public synchronized boolean addPidFilter(int pid, @FilterType int filterType) { - // no-op - return true; - } - - @Override - public synchronized void stopTune() { - closeInputStreamAndDisconnect(); - } - - @Override - public synchronized int readTsStream(byte[] javaBuffer, int javaBufferSize) { - if (mInputStream != null) { - try { - // Note: this call sometimes take more than 500ms, because the data is - // streamed through network unlike connected tuner devices. - return mInputStream.read(javaBuffer, 0, javaBufferSize); - } catch (IOException e) { - Log.e(TAG, "Failed to read stream", e); - closeInputStreamAndDisconnect(); - } - } - if (connectAndOpenInputStream()) { - Log.w(TAG, "Tuned by http connection again"); - } else { - Log.e(TAG, "Tuned by http connection again failed"); - } - return 0; - } - - @Override - public void setHasPendingTune(boolean hasPendingTune) { - // no-op - } - - protected int nativeGetDeliverySystemType(long deviceId) { - String deviceModel = mDevice.getDeviceModel(); - if (SoftPreconditions.checkState(!TextUtils.isEmpty(deviceModel))) { - if (deviceModel.contains(CABLECARD_MODEL) || deviceModel.contains(ATSC_MODEL)) { - return DELIVERY_SYSTEM_ATSC; - } else if (deviceModel.contains(DVBC_MODEL)) { - return DELIVERY_SYSTEM_DVBC; - } else if (deviceModel.contains(DVBT_MODEL)) { - return DELIVERY_SYSTEM_DVBT; - } - } - return DELIVERY_SYSTEM_UNDEFINED; - } - - private void closeInputStreamAndDisconnect() { - if (mInputStream != null) { - try { - mInputStream.close(); - } catch (IOException e) { - Log.e(TAG, "Failed to close input stream", e); - } - mInputStream = null; - } - if (mConnection != null) { - mConnection.disconnect(); - mConnection = null; - } - } - - /** Gets the number of tuners in a given HDHomeRun devices. */ - public static int getNumberOfDevices() { - return HdHomeRunTunerManager.getInstance().getTunerCount(); - } - - /** Returns the IP address. */ - public String getIpAddress() { - return HdHomeRunUtils.getIpString(mDevice.getIpAddress()); - } - - /** - * Marks the device associated to this instance as a scanned device. Scanned device has higher - * priority among multiple HDHomeRun devices. - */ - public void markAsScannedDevice(Context context) { - HdHomeRunTunerManager.markAsScannedDevice(context, mDevice); - } - - @Override - @DeliverySystemType - public int getDeliverySystemType() { - return Tuner.DELIVERY_SYSTEM_UNDEFINED; - } - - @Override - public int getSignalStrength() { - return TvInputConstantCompat.SIGNAL_STRENGTH_NOT_USED; - } -} diff --git a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunTunerHalFactory.java b/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunTunerHalFactory.java deleted file mode 100644 index 6f6b1864..00000000 --- a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunTunerHalFactory.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2019 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.tuner.hdhomerun; - -import android.content.Context; -import android.support.annotation.WorkerThread; -import android.util.Pair; - -import com.android.tv.tuner.api.Tuner; -import com.android.tv.tuner.api.TunerFactory; - -/** TunerHal factory that creates all built in tuner types. */ -public final class HdHomeRunTunerHalFactory implements TunerFactory { - public static final TunerFactory INSTANCE = new HdHomeRunTunerHalFactory(); - - private HdHomeRunTunerHalFactory() {} - /** - * Creates a TunerHal instance. - * - * @param context context for creating the TunerHal instance - * @return the TunerHal instance - */ - @Override - @WorkerThread - public synchronized Tuner createInstance(Context context) { - Tuner tunerHal = null; - if (tunerHal == null) { - tunerHal = new HdHomeRunTunerHal(context); - } - return tunerHal.openFirstAvailable() ? tunerHal : null; - } - - /** - * Returns if tuner input service would use built-in tuners instead of USB tuners or network - * tuners. - */ - @Override - public boolean useBuiltInTuner(Context context) { - return false; - } - - /** Gets the number of tuner devices currently present. */ - @Override - @WorkerThread - public Pair<Integer, Integer> getTunerTypeAndCount(Context context) { - return Pair.create(Tuner.TUNER_TYPE_NETWORK, HdHomeRunTunerHal.getNumberOfDevices()); - } -} diff --git a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunTunerManager.java b/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunTunerManager.java deleted file mode 100644 index 9e3ea595..00000000 --- a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunTunerManager.java +++ /dev/null @@ -1,122 +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.tuner.hdhomerun; - -import android.content.Context; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; -import android.support.annotation.WorkerThread; -import android.util.Log; -import java.util.HashSet; -import java.util.Set; - -/** - * A class to manage tuner resources of HDHomeRun devices. It handles tuner resource acquisition and - * release. - */ -class HdHomeRunTunerManager { - private static final String TAG = "HdHomeRunTunerManager"; - private static final boolean DEBUG = false; - - private static final String PREF_KEY_SCANNED_DEVICE_ID = "scanned_device_id"; - - private static HdHomeRunTunerManager sInstance; - - private final Set<HdHomeRunDevice> mHdHomeRunDevices = new HashSet<>(); - private final Set<HdHomeRunDevice> mUsedDevices = new HashSet<>(); - - private HdHomeRunTunerManager() {} - - /** Returns the instance of this manager. */ - public static synchronized HdHomeRunTunerManager getInstance() { - if (sInstance == null) { - sInstance = new HdHomeRunTunerManager(); - } - return sInstance; - } - - /** Returns number of tuners. */ - @WorkerThread - synchronized int getTunerCount() { - updateDevicesLocked(null); - if (DEBUG) Log.d(TAG, "getTunerCount: " + mHdHomeRunDevices.size()); - return mHdHomeRunDevices.size(); - } - - /** Creates an HDHomeRun device. If there is no available one, returns {@code null}. */ - @WorkerThread - synchronized HdHomeRunDevice acquireDevice(Context context) { - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); - int scannedDeviceId = sp.getInt(PREF_KEY_SCANNED_DEVICE_ID, 0); - updateDevicesLocked(scannedDeviceId == 0 ? null : scannedDeviceId); - if (DEBUG) Log.d(TAG, "createDevice: device count = " + mHdHomeRunDevices.size()); - HdHomeRunDevice availableDevice = null; - // Use the device used for scanning first since other devices might have different line-up. - if (scannedDeviceId != 0) { - for (HdHomeRunDevice device : mHdHomeRunDevices) { - if (!mUsedDevices.contains(device) && scannedDeviceId == device.getDeviceId()) { - if (!HdHomeRunInterface.isDeviceAvailable( - device.getDeviceId(), device.getIpAddress(), device.getTunerIndex())) { - if (DEBUG) Log.d(TAG, "Device not available: " + device); - continue; - } - availableDevice = device; - break; - } - } - } - if (availableDevice == null) { - for (HdHomeRunDevice device : mHdHomeRunDevices) { - if (!mUsedDevices.contains(device)) { - if (!HdHomeRunInterface.isDeviceAvailable( - device.getDeviceId(), device.getIpAddress(), device.getTunerIndex())) { - if (DEBUG) Log.d(TAG, "Device not available: " + device); - continue; - } - availableDevice = device; - break; - } - } - } - if (availableDevice != null) { - if (DEBUG) Log.d(TAG, "created device " + availableDevice); - mUsedDevices.add(availableDevice); - return availableDevice; - } - return null; - } - - /** Releases a created device by {@link #acquireDevice(Context)}. */ - synchronized void releaseDevice(HdHomeRunDevice device) { - if (DEBUG) Log.d(TAG, "releaseDevice: " + device); - mUsedDevices.remove(device); - } - - /** - * Marks the device associated to this instance as a scanned device. Scanned device has higher - * priority among multiple HDHomeRun devices. - */ - static void markAsScannedDevice(Context context, HdHomeRunDevice device) { - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); - sp.edit().putInt(PREF_KEY_SCANNED_DEVICE_ID, device.getDeviceId()).apply(); - } - - private void updateDevicesLocked(Integer deviceId) { - mHdHomeRunDevices.clear(); - mHdHomeRunDevices.addAll(HdHomeRunInterface.scanDevices(deviceId)); - } -} diff --git a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunUtils.java b/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunUtils.java deleted file mode 100644 index 733fc96f..00000000 --- a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunUtils.java +++ /dev/null @@ -1,194 +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.tuner.hdhomerun; - -import android.support.annotation.NonNull; -import android.util.Log; -import android.util.Pair; - -import com.android.tv.tuner.hdhomerun.HdHomeRunDiscover.HdHomeRunDiscoverDevice; - -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.BufferUnderflowException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.zip.CRC32; - -class HdHomeRunUtils { - private static final String TAG = "HdHomeRunUtils"; - private static final boolean DEBUG = false; - - static final int HDHOMERUN_DEVICE_TYPE_WILDCARD = 0xFFFFFFFF; - static final int HDHOMERUN_DEVICE_TYPE_TUNER = 0x00000001; - static final int HDHOMERUN_DEVICE_ID_WILDCARD = 0xFFFFFFFF; - - static final int HDHOMERUN_DISCOVER_UDP_PORT = 65001; - static final int HDHOMERUN_CONTROL_TCP_PORT = 65001; - - static final short HDHOMERUN_TYPE_INVALID = -1; - static final short HDHOMERUN_TYPE_DISCOVER_REQUEST = 0x0002; - static final short HDHOMERUN_TYPE_DISCOVER_REPLY = 0x0003; - static final short HDHOMERUN_TYPE_GETSET_REQUEST = 0x0004; - static final short HDHOMERUN_TYPE_GETSET_REPLY = 0x0005; - - static final byte HDHOMERUN_TAG_DEVICE_TYPE = 0x01; - static final byte HDHOMERUN_TAG_DEVICE_ID = 0x02; - static final byte HDHOMERUN_TAG_GETSET_NAME = 0x03; - static final int HDHOMERUN_TAG_GETSET_VALUE = 0x04; - static final int HDHOMERUN_TAG_ERROR_MESSAGE = 0x05; - static final int HDHOMERUN_TAG_TUNER_COUNT = 0x10; - static final int HDHOMERUN_TAG_BASE_URL = 0x2A; - - static final int HDHOMERUN_CONTROL_CONNECT_TIMEOUT_MS = 2500; - static final int HDHOMERUN_CONTROL_SEND_TIMEOUT_MS = 2500; - static final int HDHOMERUN_CONTROL_RECEIVE_TIMEOUT_MS = 2500; - - /** - * Finds HDHomeRun devices with given IP, type, and ID. - * - * @param targetIp {@code 0} to find target devices with broadcasting. - * @param deviceType The type of target devices. - * @param deviceId The ID of target devices. - * @param maxCount Maximum number of devices should be returned. - */ - @NonNull - static List<HdHomeRunDiscoverDevice> findHdHomeRunDevices( - int targetIp, int deviceType, int deviceId, int maxCount) { - if (isIpMulticast(targetIp)) { - if (DEBUG) Log.d(TAG, "Target IP cannot be multicast IP."); - return Collections.emptyList(); - } - try { - HdHomeRunDiscover ds = HdHomeRunDiscover.create(); - if (ds == null) { - if (DEBUG) Log.d(TAG, "Cannot create discover object."); - return Collections.emptyList(); - } - List<HdHomeRunDiscoverDevice> result = - ds.findDevices(targetIp, deviceType, deviceId, maxCount); - ds.close(); - return result; - } catch (Exception e) { - Log.w(TAG, "Failed to find HdHomeRun Devices", e); - return Collections.emptyList(); - } - } - - /** Returns {@code true} if the given IP is a multi-cast IP. */ - static boolean isIpMulticast(long ip) { - return (ip >= 0xE0000000) && (ip < 0xF0000000); - } - - /** Translates a {@code byte[]} address to its integer representation. */ - static int addressToInt(byte[] address) { - return ByteBuffer.wrap(address).order(ByteOrder.LITTLE_ENDIAN).getInt(); - } - - /** Translates an {@code int} address to a corresponding {@link InetAddress}. */ - static InetAddress intToAddress(int address) throws UnknownHostException { - return InetAddress.getByAddress( - ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(address).array()); - } - - /** Gets {@link String} representation of an {@code int} address. */ - static String getIpString(int ip) { - return String.format( - "%d.%d.%d.%d", (ip & 0xff), (ip >> 8 & 0xff), (ip >> 16 & 0xff), (ip >> 24 & 0xff)); - } - - /** - * Opens the packet returned from HDHomeRun devices to acquire the real content and verify it. - */ - static Pair<Short, byte[]> openFrame(byte[] data, int length) { - if (length < 4) { - return null; - } - ByteBuffer buffer = ByteBuffer.wrap(data); - short resultType = buffer.getShort(); - int dataLength = buffer.getShort() & 0xffff; - - if (dataLength + 8 > length) { - // Not finished yet. - return null; - } - byte[] result = new byte[dataLength]; - buffer.get(result); - byte[] calculatedCrc = getCrcFromBytes(Arrays.copyOfRange(data, 0, dataLength + 4)); - byte[] packetCrc = new byte[4]; - buffer.get(packetCrc); - - if (!Arrays.equals(calculatedCrc, packetCrc)) { - return Pair.create(HDHOMERUN_TYPE_INVALID, null); - } - - return Pair.create(resultType, result); - } - - /** Seals the contents in a packet to send to HDHomeRun devices. */ - static byte[] sealFrame(byte[] data, short frameType) { - byte[] result = new byte[data.length + 8]; - ByteBuffer buffer = ByteBuffer.wrap(result); - buffer.putShort(frameType); - buffer.putShort((short) data.length); - buffer.put(data); - buffer.put(getCrcFromBytes(Arrays.copyOfRange(result, 0, data.length + 4))); - return result; - } - - /** Reads a (tag, value) pair from packets returned from HDHomeRun devices. */ - static Pair<Byte, byte[]> readTaggedValue(ByteBuffer buffer) { - try { - Byte tag = buffer.get(); - byte[] value = readVarLength(buffer); - return Pair.create(tag, value); - } catch (BufferUnderflowException e) { - return null; - } - } - - private static byte[] readVarLength(ByteBuffer buffer) { - short length; - Byte lengthByte1 = buffer.get(); - if ((lengthByte1 & 0x80) != 0) { - length = buffer.get(); - length = (short) ((length << 7) + (lengthByte1 & 0x7F)); - } else { - length = lengthByte1; - } - byte[] result = new byte[length]; - buffer.get(result); - return result; - } - - private static byte[] getCrcFromBytes(byte[] data) { - CRC32 crc32 = new CRC32(); - crc32.update(data); - long crc = crc32.getValue(); - byte[] result = new byte[4]; - for (int offset = 0; offset < 4; offset++) { - result[offset] = (byte) (crc & 0xFF); - crc >>= 8; - } - return result; - } - - private HdHomeRunUtils() {} -} diff --git a/tuner/src/com/android/tv/tuner/modules/TunerModule.java b/tuner/src/com/android/tv/tuner/modules/TunerModule.java index ff86e09f..4843f383 100644 --- a/tuner/src/com/android/tv/tuner/modules/TunerModule.java +++ b/tuner/src/com/android/tv/tuner/modules/TunerModule.java @@ -15,86 +15,9 @@ */ package com.android.tv.tuner.modules; -import com.android.tv.tuner.exoplayer.ExoPlayerSampleExtractor; -import com.android.tv.tuner.exoplayer.ExoPlayerSampleExtractorFactory; -import com.android.tv.tuner.exoplayer.FileSampleExtractor; -import com.android.tv.tuner.exoplayer.FileSampleExtractorFactory; -import com.android.tv.tuner.exoplayer.MpegTsRendererBuilder; -import com.android.tv.tuner.exoplayer.MpegTsRendererBuilderFactory; -import com.android.tv.tuner.exoplayer.MpegTsSampleExtractor; -import com.android.tv.tuner.exoplayer.MpegTsSampleExtractorFactory; -import com.android.tv.tuner.exoplayer.buffer.RecordingSampleBuffer; -import com.android.tv.tuner.exoplayer.buffer.RecordingSampleBufferFactory; -import com.android.tv.tuner.exoplayer.buffer.SampleChunkIoHelper; -import com.android.tv.tuner.exoplayer.buffer.SampleChunkIoHelperFactory; import com.android.tv.tuner.source.TunerSourceModule; -import com.android.tv.tuner.tvinput.TunerRecordingSessionFactoryImpl; -import com.android.tv.tuner.tvinput.TunerRecordingSessionWorker; -import com.android.tv.tuner.tvinput.TunerRecordingSessionWorkerFactory; -import com.android.tv.tuner.tvinput.TunerSessionExoV2Factory; -import com.android.tv.tuner.tvinput.TunerSessionV1Factory; -import com.android.tv.tuner.tvinput.TunerSessionWorker; -import com.android.tv.tuner.tvinput.TunerSessionWorkerExoV2; -import com.android.tv.tuner.tvinput.TunerSessionWorkerExoV2Factory; -import com.android.tv.tuner.tvinput.TunerSessionWorkerFactory; -import com.android.tv.tuner.tvinput.factory.TunerRecordingSessionFactory; -import com.android.tv.tuner.tvinput.factory.TunerSessionFactory; - -import dagger.Binds; import dagger.Module; -import dagger.Provides; - -import com.android.tv.common.flags.TunerFlags; /** Dagger module for TV Tuners. */ @Module(includes = {TunerSingletonsModule.class, TunerSourceModule.class}) -public abstract class TunerModule { - - @Provides - static TunerSessionFactory tunerSessionFactory( - TunerFlags tunerFlags, - TunerSessionV1Factory tunerSessionFactory, - TunerSessionExoV2Factory tunerSessionExoV2Factory) { - return tunerFlags.useExoplayerV2() ? tunerSessionExoV2Factory : tunerSessionFactory; - } - - @Binds - abstract TunerRecordingSessionWorker.Factory tunerRecordingSessionWorkerFactory( - TunerRecordingSessionWorkerFactory tunerRecordingSessionWorkerFactory); - - @Binds - abstract TunerSessionWorker.Factory tunerSessionWorkerFactory( - TunerSessionWorkerFactory tunerSessionWorkerFactory); - - @Binds - abstract TunerSessionWorkerExoV2.Factory tunerSessionWorkerExoV2Factory( - TunerSessionWorkerExoV2Factory tunerSessionWorkerExoV2Factory); - - @Binds - abstract TunerRecordingSessionFactory tunerRecordingSessionFactory( - TunerRecordingSessionFactoryImpl impl); - - @Binds - abstract MpegTsRendererBuilder.Factory mpegTsRendererBuilderFactory( - MpegTsRendererBuilderFactory mpegTsRendererBuilderFactory); - - @Binds - abstract MpegTsSampleExtractor.Factory mpegTsSampleExtractorFactory( - MpegTsSampleExtractorFactory mpegTsSampleExtractorFactory); - - @Binds - abstract FileSampleExtractor.Factory fileSampleExtractorFactory( - FileSampleExtractorFactory fileSampleExtractorFactory); - - @Binds - abstract RecordingSampleBuffer.Factory recordingSampleBufferFactory( - RecordingSampleBufferFactory recordingSampleBufferFactory); - - @Binds - abstract ExoPlayerSampleExtractor.Factory exoPlayerSampleExtractorFactory( - ExoPlayerSampleExtractorFactory exoPlayerSampleExtractorFactory); - - @Binds - abstract SampleChunkIoHelper.Factory sampleChunkIoHelperFactory( - SampleChunkIoHelperFactory sampleChunkIoHelperFactory); -} +public class TunerModule {} diff --git a/tuner/src/com/android/tv/tuner/setup/BaseTunerSetupActivity.java b/tuner/src/com/android/tv/tuner/setup/BaseTunerSetupActivity.java index 05026907..44f689bf 100644 --- a/tuner/src/com/android/tv/tuner/setup/BaseTunerSetupActivity.java +++ b/tuner/src/com/android/tv/tuner/setup/BaseTunerSetupActivity.java @@ -75,14 +75,11 @@ public abstract class BaseTunerSetupActivity extends SetupActivity { R.raw.ut_kr_cable_standard_center_frequencies_qam256, R.raw.ut_kr_all, R.raw.ut_kr_dev_cj_cable_center_frequencies_qam256, + R.raw.ut_euro_dvbt_all, + R.raw.ut_euro_dvbt_all, R.raw.ut_euro_dvbt_all - /* these two resource files are obsolete and removed, so comment them out - R.raw.ut_euro_all, - R.raw.ut_euro_all */ }; - protected final String mInputId; - protected ScanFragment mLastScanFragment; protected Integer mTunerType; protected boolean mNeedToShowPostalCodeFragment; @@ -93,10 +90,6 @@ public abstract class BaseTunerSetupActivity extends SetupActivity { private TunerHalCreator mTunerHalCreator; - protected BaseTunerSetupActivity(String mInputId) { - this.mInputId = mInputId; - } - @Override protected void onCreate(Bundle savedInstanceState) { if (DEBUG) { @@ -229,7 +222,6 @@ public abstract class BaseTunerSetupActivity extends SetupActivity { args1.putInt( ScanFragment.EXTRA_FOR_CHANNEL_SCAN_FILE, CHANNEL_MAP_SCAN_FILE[actionId]); args1.putInt(KEY_TUNER_TYPE, mTunerType); - args1.putString(ScanFragment.EXTRA_FOR_INPUT_ID, mInputId); mLastScanFragment.setArguments(args1); showFragment(mLastScanFragment, true); return true; diff --git a/tuner/src/com/android/tv/tuner/setup/ChannelScanFileParser.java b/tuner/src/com/android/tv/tuner/setup/ChannelScanFileParser.java index 2e782705..43c584ed 100644 --- a/tuner/src/com/android/tv/tuner/setup/ChannelScanFileParser.java +++ b/tuner/src/com/android/tv/tuner/setup/ChannelScanFileParser.java @@ -56,7 +56,6 @@ public final class ChannelScanFileParser { } scanChannelList.add( ScanChannel.forTuner( - tokens[0], Integer.parseInt(tokens[1]), tokens[2], tokens.length == 4 ? Integer.parseInt(tokens[3]) : null)); diff --git a/tuner/src/com/android/tv/tuner/setup/ConnectionTypeFragment.java b/tuner/src/com/android/tv/tuner/setup/ConnectionTypeFragment.java index db297426..ebe4e41e 100644 --- a/tuner/src/com/android/tv/tuner/setup/ConnectionTypeFragment.java +++ b/tuner/src/com/android/tv/tuner/setup/ConnectionTypeFragment.java @@ -18,12 +18,14 @@ package com.android.tv.tuner.setup; import android.os.Bundle; import android.support.annotation.NonNull; -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.leanback.widget.GuidedAction; +import com.android.tv.common.BuildConfig; import com.android.tv.common.ui.setup.SetupGuidedStepFragment; import com.android.tv.common.ui.setup.SetupMultiPaneFragment; import com.android.tv.tuner.R; import java.util.List; +import java.util.TimeZone; /** A fragment for connection type selection. */ public class ConnectionTypeFragment extends SetupMultiPaneFragment { @@ -65,6 +67,7 @@ public class ConnectionTypeFragment extends SetupMultiPaneFragment { /** The content fragment of {@link ConnectionTypeFragment}. */ public static class ContentFragment extends SetupGuidedStepFragment { + @NonNull @Override public Guidance onCreateGuidance(Bundle savedInstanceState) { diff --git a/tuner/src/com/android/tv/tuner/setup/LineupFragment.java b/tuner/src/com/android/tv/tuner/setup/LineupFragment.java index 224237d9..41f755df 100644 --- a/tuner/src/com/android/tv/tuner/setup/LineupFragment.java +++ b/tuner/src/com/android/tv/tuner/setup/LineupFragment.java @@ -20,8 +20,8 @@ import android.content.res.Resources; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.leanback.widget.GuidedAction; import android.util.Log; import android.view.View; import com.android.tv.common.ui.setup.SetupGuidedStepFragment; diff --git a/tuner/src/com/android/tv/tuner/setup/LiveTvTunerSetupActivity.java b/tuner/src/com/android/tv/tuner/setup/LiveTvTunerSetupActivity.java new file mode 100644 index 00000000..741edc78 --- /dev/null +++ b/tuner/src/com/android/tv/tuner/setup/LiveTvTunerSetupActivity.java @@ -0,0 +1,119 @@ +/* + * 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.tuner.setup; + +import android.app.FragmentManager; +import android.content.pm.PackageManager; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.view.KeyEvent; +import com.android.tv.common.util.PostalCodeUtils; +import dagger.android.ContributesAndroidInjector; + +/** An activity that serves tuner setup process. */ +public class LiveTvTunerSetupActivity extends BaseTunerSetupActivity { + private static final String TAG = "LiveTvTunerSetupActivity"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // TODO(shubang): use LocationFragment + if (checkSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) + != PackageManager.PERMISSION_GRANTED) { + // No need to check the request result. + requestPermissions( + new String[] {android.Manifest.permission.ACCESS_COARSE_LOCATION}, + PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION); + } + } + + @Override + protected void executeGetTunerTypeAndCountAsyncTask() { + new AsyncTask<Void, Void, Integer>() { + @Override + protected Integer doInBackground(Void... arg0) { + return mTunerFactory.getTunerTypeAndCount(LiveTvTunerSetupActivity.this).first; + } + + @Override + protected void onPostExecute(Integer result) { + if (!LiveTvTunerSetupActivity.this.isDestroyed()) { + mTunerType = result; + if (result == null) { + finish(); + } else if (!mActivityStopped) { + showInitialFragment(); + } else { + mPendingShowInitialFragment = true; + } + } + } + }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + FragmentManager manager = getFragmentManager(); + int count = manager.getBackStackEntryCount(); + if (count > 0) { + String lastTag = manager.getBackStackEntryAt(count - 1).getName(); + if (ScanResultFragment.class.getCanonicalName().equals(lastTag) && count >= 2) { + String secondLastTag = manager.getBackStackEntryAt(count - 2).getName(); + if (ScanFragment.class.getCanonicalName().equals(secondLastTag)) { + // Pops fragment including ScanFragment. + manager.popBackStack( + secondLastTag, FragmentManager.POP_BACK_STACK_INCLUSIVE); + return true; + } + } else if (ScanFragment.class.getCanonicalName().equals(lastTag)) { + mLastScanFragment.finishScan(true); + return true; + } + } + } + return super.onKeyUp(keyCode, event); + } + + @Override + public void onRequestPermissionsResult( + int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + if (requestCode == PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION) { + if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + try { + // Updating postal code takes time, therefore we should update postal code + // right after the permission is granted, so that the subsequent operations, + // especially EPG fetcher, could get the newly updated postal code. + PostalCodeUtils.updatePostalCode(this); + } catch (Exception e) { + // Do nothing + } + } + } + } + + /** + * Exports {@link LiveTvTunerSetupActivity} for Dagger codegen to create the appropriate + * injector. + */ + @dagger.Module + public abstract static class Module { + @ContributesAndroidInjector + abstract LiveTvTunerSetupActivity contributeLiveTvTunerSetupActivityInjector(); + } +} diff --git a/tuner/src/com/android/tv/tuner/setup/LocationFragment.java b/tuner/src/com/android/tv/tuner/setup/LocationFragment.java index f950405f..1234ae20 100644 --- a/tuner/src/com/android/tv/tuner/setup/LocationFragment.java +++ b/tuner/src/com/android/tv/tuner/setup/LocationFragment.java @@ -23,14 +23,16 @@ import android.location.Address; import android.os.Bundle; import android.os.Handler; import android.support.annotation.NonNull; +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.leanback.widget.GuidedAction; import android.util.Log; -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; + import com.android.tv.common.ui.setup.SetupActionHelper; import com.android.tv.common.ui.setup.SetupGuidedStepFragment; import com.android.tv.common.ui.setup.SetupMultiPaneFragment; import com.android.tv.common.util.LocationUtils; import com.android.tv.tuner.R; + import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -38,7 +40,7 @@ import java.util.List; /** A fragment shows the rationale of location permission */ public class LocationFragment extends SetupMultiPaneFragment { private static final String TAG = "com.android.tv.tuner.setup.LocationFragment"; - private static final boolean DEBUG = false; + private static final boolean DEBUG = true; public static final String ACTION_CATEGORY = "com.android.tv.tuner.setup.LocationFragment"; public static final String KEY_POSTAL_CODE = "key_postal_code"; @@ -77,7 +79,8 @@ public class LocationFragment extends SetupMultiPaneFragment { () -> { synchronized (mPostalCodeLock) { if (DEBUG) { - Log.d(TAG, "get location timeout. mPostalCode=" + mPostalCode); + Log.d(TAG, + "get location timeout. mPostalCode=" + mPostalCode); } if (mPostalCode == null) { // timeout. setup activity will get null postal code @@ -118,7 +121,8 @@ public class LocationFragment extends SetupMultiPaneFragment { .id(ACTION_GETTING_LOCATION) .title(getString(R.string.location_choices_getting_location)) .focusable(false) - .build()); + .build() + ); } @Override @@ -143,8 +147,8 @@ public class LocationFragment extends SetupMultiPaneFragment { } @Override - public void onRequestPermissionsResult( - int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, + @NonNull int[] grantResults) { if (requestCode == PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { diff --git a/tuner/src/com/android/tv/tuner/setup/PostalCodeFragment.java b/tuner/src/com/android/tv/tuner/setup/PostalCodeFragment.java index f9ea1675..52247972 100644 --- a/tuner/src/com/android/tv/tuner/setup/PostalCodeFragment.java +++ b/tuner/src/com/android/tv/tuner/setup/PostalCodeFragment.java @@ -18,9 +18,9 @@ package com.android.tv.tuner.setup; import android.os.Bundle; import android.support.annotation.NonNull; -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; -import androidx.leanback.widget.GuidedActionsStylist; +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.leanback.widget.GuidedAction; +import android.support.v17.leanback.widget.GuidedActionsStylist; import android.text.InputFilter; import android.text.InputFilter.AllCaps; import android.view.View; diff --git a/tuner/src/com/android/tv/tuner/setup/ScanFragment.java b/tuner/src/com/android/tv/tuner/setup/ScanFragment.java index 87a79e35..7d59284c 100644 --- a/tuner/src/com/android/tv/tuner/setup/ScanFragment.java +++ b/tuner/src/com/android/tv/tuner/setup/ScanFragment.java @@ -40,9 +40,11 @@ import com.android.tv.common.ui.setup.SetupFragment; import com.android.tv.tuner.R; import com.android.tv.tuner.api.ScanChannel; import com.android.tv.tuner.api.Tuner; -import com.android.tv.tuner.data.Channel.TunerType; import com.android.tv.tuner.data.PsipData; import com.android.tv.tuner.data.TunerChannel; +import com.android.tv.tuner.data.nano.Channel; + + import com.android.tv.tuner.prefs.TunerPreferences; import com.android.tv.tuner.source.FileTsStreamer; import com.android.tv.tuner.source.TsDataSource; @@ -72,13 +74,7 @@ public class ScanFragment extends SetupFragment { public static final int ACTION_FINISH = 2; public static final String EXTRA_FOR_CHANNEL_SCAN_FILE = "scan_file_choice"; - public static final String EXTRA_FOR_INPUT_ID = "input_id"; public static final String KEY_CHANNEL_NUMBERS = "channel_numbers"; - - // Allows adding audio-only channels (CJ music channel) for which VCT is not present. - private static final boolean ADD_CJ_MUSIC_CHANNELS = false; - private static final int CJ_MUSIC_CHANNEL_FREQUENCY = 585000000; - private static final long CHANNEL_SCAN_SHOW_DELAY_MS = 10000; private static final long CHANNEL_SCAN_PERIOD_MS = 4000; private static final long SHOW_PROGRESS_DIALOG_DELAY_MS = 300; @@ -103,6 +99,8 @@ public class ScanFragment extends SetupFragment { if (DEBUG) Log.d(TAG, "onCreateView"); View view = super.onCreateView(inflater, container, savedInstanceState); mChannelNumbers = new ArrayList<>(); + mChannelDataManager = new ChannelDataManager(getActivity().getApplicationContext()); + mChannelDataManager.checkDataVersion(getActivity()); mAdapter = new ChannelAdapter(); mProgressBar = (ProgressBar) view.findViewById(R.id.tune_progress); mScanningMessage = (TextView) view.findViewById(R.id.tune_description); @@ -124,6 +122,8 @@ public class ScanFragment extends SetupFragment { }); Bundle args = getArguments(); int tunerType = (args == null ? 0 : args.getInt(BaseTunerSetupActivity.KEY_TUNER_TYPE, 0)); + // TODO: Handle the case when the fragment is restored. + startScan(args == null ? 0 : args.getInt(EXTRA_FOR_CHANNEL_SCAN_FILE, 0)); TextView scanTitleView = (TextView) view.findViewById(R.id.tune_title); switch (tunerType) { case Tuner.TUNER_TYPE_USB: @@ -139,28 +139,6 @@ public class ScanFragment extends SetupFragment { } @Override - public void onStart() { - super.onStart(); - Bundle args = getArguments(); - String inputId = args == null ? null : args.getString(ScanFragment.EXTRA_FOR_INPUT_ID); - if (inputId == null) { - Log.w(TAG, "No input ID, stopping setup activity."); - getActivity().finish(); - } - - mChannelDataManager = new ChannelDataManager(getContext().getApplicationContext(), inputId); - mChannelDataManager.checkDataVersion(getActivity()); - } - - @Override - public void onStop() { - if (mChannelDataManager != null) { - mChannelDataManager.release(); - } - super.onStop(); - } - - @Override protected int getLayoutResourceId() { return R.layout.ut_channel_scan; } @@ -176,13 +154,6 @@ public class ScanFragment extends SetupFragment { } @Override - public void onResume() { - Bundle args = getArguments(); - startScan(args == null ? 0 : args.getInt(EXTRA_FOR_CHANNEL_SCAN_FILE, 0)); - super.onResume(); - } - - @Override public void onPause() { Log.d(TAG, "onPause"); if (mChannelScanTask != null) { @@ -279,7 +250,6 @@ public class ScanFragment extends SetupFragment { private final Activity mActivity; private final int mChannelMapId; -// AOSP_Comment_Out private final com.android.tv.tuner.hdhomerun.HdHomeRunTunerHal mNetworkTuner; private final TsStreamer mScanTsStreamer; private final TsStreamer mFileTsStreamer; private final ConditionVariable mConditionStopped; @@ -300,13 +270,6 @@ public class ScanFragment extends SetupFragment { if (hal == null) { throw new RuntimeException("Failed to open a DVB device"); } - /* Begin_AOSP_Comment_Out - if (hal instanceof com.android.tv.tuner.hdhomerun.HdHomeRunTunerHal) { - mNetworkTuner = (com.android.tv.tuner.hdhomerun.HdHomeRunTunerHal) hal; - } else { - mNetworkTuner = null; - } - End_AOSP_Comment_Out */ mScanTsStreamer = new TunerTsStreamer(hal, this); } mFileTsStreamer = SCAN_LOCAL_STREAMS ? new FileTsStreamer(this, mActivity) : null; @@ -351,18 +314,6 @@ public class ScanFragment extends SetupFragment { @Override protected Void doInBackground(Void... params) { - /* Begin_AOSP_Comment_Out - if (mNetworkTuner != null) { - mChannelDataManager.notifyScanStarted(); - com.android.tv.tuner.hdhomerun.HdHomeRunChannelScan hdHomeRunChannelScan = - new com.android.tv.tuner.hdhomerun.HdHomeRunChannelScan( - mActivity.getApplicationContext(), this, mNetworkTuner); - hdHomeRunChannelScan.scan(mConditionStopped); - mChannelDataManager.notifyScanCompleted(); - publishProgress(MAX_PROGRESS); - return null; - } - End_AOSP_Comment_Out */ mScanChannelList.clear(); if (SCAN_LOCAL_STREAMS) { FileTsStreamer.addLocalStreamFiles(mScanChannelList); @@ -425,10 +376,6 @@ public class ScanFragment extends SetupFragment { e); } streamer.stopStream(); - - if (ADD_CJ_MUSIC_CHANNELS) { - addCjMusicChannel(frequency, modulation); - } addChannelsWithoutVct(scanChannel); if (System.currentTimeMillis() > startMs + CHANNEL_SCAN_SHOW_DELAY_MS && !mChannelListVisible) { @@ -447,24 +394,6 @@ public class ScanFragment extends SetupFragment { if (DEBUG) Log.i(TAG, "Channel scan ended"); } - private void addCjMusicChannel(int frequency, String modulation) { - if (frequency == CJ_MUSIC_CHANNEL_FREQUENCY - && mChannelMapId == R.raw.ut_kr_dev_cj_cable_center_frequencies_qam256) { - List<TunerChannel> incompleteChannels = - mScanTsStreamer instanceof TunerTsStreamer - ? ((TunerTsStreamer) mScanTsStreamer).getMalFormedChannels() - : new ArrayList<>(); - for (TunerChannel tunerChannel : incompleteChannels) { - if ((tunerChannel.getVideoPid() == TunerChannel.INVALID_PID) - && (tunerChannel.getAudioPid() != TunerChannel.INVALID_PID)) { - tunerChannel.setFrequency(frequency); - tunerChannel.setModulation(modulation); - onChannelDetected(tunerChannel, true); - } - } - } - } - private void addChannelsWithoutVct(ScanChannel scanChannel) { if (scanChannel.radioFrequencyNumber == null || !(mScanTsStreamer instanceof TunerTsStreamer)) { @@ -474,7 +403,6 @@ public class ScanFragment extends SetupFragment { ((TunerTsStreamer) mScanTsStreamer).getMalFormedChannels()) { if ((tunerChannel.getVideoPid() != TunerChannel.INVALID_PID) && (tunerChannel.getAudioPid() != TunerChannel.INVALID_PID)) { - tunerChannel.setDeliverySystemType(scanChannel.deliverySystemType); tunerChannel.setFrequency(scanChannel.frequency); tunerChannel.setModulation(scanChannel.modulation); tunerChannel.setShortName( @@ -492,9 +420,9 @@ public class ScanFragment extends SetupFragment { private TsStreamer getStreamer(int type) { switch (type) { - case TunerType.TYPE_TUNER_VALUE: + case Channel.TunerType.TYPE_TUNER: return mScanTsStreamer; - case TunerType.TYPE_FILE_VALUE: + case Channel.TunerType.TYPE_FILE: return mFileTsStreamer; default: return null; diff --git a/tuner/src/com/android/tv/tuner/setup/ScanResultFragment.java b/tuner/src/com/android/tv/tuner/setup/ScanResultFragment.java index 01bcc9f2..bd3f9ad9 100644 --- a/tuner/src/com/android/tv/tuner/setup/ScanResultFragment.java +++ b/tuner/src/com/android/tv/tuner/setup/ScanResultFragment.java @@ -20,8 +20,8 @@ import android.content.Context; import android.content.res.Resources; import android.os.Bundle; import android.support.annotation.NonNull; -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.leanback.widget.GuidedAction; import com.android.tv.common.ui.setup.SetupGuidedStepFragment; import com.android.tv.common.ui.setup.SetupMultiPaneFragment; import com.android.tv.tuner.R; diff --git a/tuner/src/com/android/tv/tuner/setup/WelcomeFragment.java b/tuner/src/com/android/tv/tuner/setup/WelcomeFragment.java index dfa994b6..2a414df7 100644 --- a/tuner/src/com/android/tv/tuner/setup/WelcomeFragment.java +++ b/tuner/src/com/android/tv/tuner/setup/WelcomeFragment.java @@ -19,8 +19,8 @@ package com.android.tv.tuner.setup; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.leanback.widget.GuidedAction; import com.android.tv.common.ui.setup.SetupGuidedStepFragment; import com.android.tv.common.ui.setup.SetupMultiPaneFragment; import com.android.tv.tuner.R; diff --git a/tuner/src/com/android/tv/tuner/singletons/TunerSingletons.java b/tuner/src/com/android/tv/tuner/singletons/TunerSingletons.java index dfe9005b..48b17dcb 100644 --- a/tuner/src/com/android/tv/tuner/singletons/TunerSingletons.java +++ b/tuner/src/com/android/tv/tuner/singletons/TunerSingletons.java @@ -18,17 +18,4 @@ package com.android.tv.tuner.singletons; import com.android.tv.common.singletons.HasTvInputId; /** Singletons used in tuner applications */ -public interface TunerSingletons extends HasTvInputId { - - /* - * Do not add any new methods here. - * - * To move a getter to Injection. - * 1. Make a type injectable @Singleton. - * 2. Mark the getter here as deprecated. - * 3. Lazily inject the object in TvApplication. - * 4. Move easy usages of getters to injection instead. - * 5. Delete the method when all usages are migrated. - */ - -} +public interface TunerSingletons extends HasTvInputId {} diff --git a/tuner/src/com/android/tv/tuner/source/FileSourceEventDetector.java b/tuner/src/com/android/tv/tuner/source/FileSourceEventDetector.java index 5ee897bb..85932c8c 100644 --- a/tuner/src/com/android/tv/tuner/source/FileSourceEventDetector.java +++ b/tuner/src/com/android/tv/tuner/source/FileSourceEventDetector.java @@ -24,9 +24,9 @@ import com.android.tv.tuner.data.PsiData.PmtItem; import com.android.tv.tuner.data.PsipData.EitItem; import com.android.tv.tuner.data.PsipData.SdtItem; import com.android.tv.tuner.data.PsipData.VctItem; -import com.android.tv.tuner.data.Track.AtscAudioTrack; -import com.android.tv.tuner.data.Track.AtscCaptionTrack; import com.android.tv.tuner.data.TunerChannel; +import com.android.tv.tuner.data.nano.Track.AtscAudioTrack; +import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack; import com.android.tv.tuner.ts.EventDetector.EventListener; import com.android.tv.tuner.ts.TsParser; import java.util.ArrayList; diff --git a/tuner/src/com/android/tv/tuner/source/FileTsStreamer.java b/tuner/src/com/android/tv/tuner/source/FileTsStreamer.java index 15f3458a..99d37e39 100644 --- a/tuner/src/com/android/tv/tuner/source/FileTsStreamer.java +++ b/tuner/src/com/android/tv/tuner/source/FileTsStreamer.java @@ -17,9 +17,7 @@ package com.android.tv.tuner.source; import android.content.Context; -import android.net.Uri; import android.os.Environment; -import android.support.annotation.Nullable; import android.util.Log; import android.util.SparseBooleanArray; import com.android.tv.common.SoftPreconditions; @@ -28,8 +26,8 @@ import com.android.tv.tuner.data.TunerChannel; import com.android.tv.tuner.features.TunerFeatures; import com.android.tv.tuner.ts.EventDetector.EventListener; import com.android.tv.tuner.ts.TsParser; -import com.google.android.exoplayer2.upstream.DataSpec; -import com.google.android.exoplayer2.upstream.TransferListener; +import com.google.android.exoplayer.C; +import com.google.android.exoplayer.upstream.DataSpec; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; @@ -73,7 +71,6 @@ public class FileTsStreamer implements TsStreamer { public static class FileDataSource extends TsDataSource { private final FileTsStreamer mTsStreamer; private final AtomicLong mLastReadPosition = new AtomicLong(0); - private Uri mUri; private long mStartBufferedPosition; private FileDataSource(FileTsStreamer tsStreamer) { @@ -99,10 +96,9 @@ public class FileTsStreamer implements TsStreamer { } @Override - public long open(DataSpec dataSpec) { - mUri = dataSpec.uri; + public long open(DataSpec dataSpec) throws IOException { mLastReadPosition.set(0); - return com.google.android.exoplayer2.C.LENGTH_UNSET; + return C.LENGTH_UNBOUNDED; } @Override @@ -121,19 +117,6 @@ public class FileTsStreamer implements TsStreamer { } return ret; } - - // ExoPlayer V2 DataSource implementation. - - @Override - public void addTransferListener(TransferListener transferListener) { - // TODO: Implement to support metrics collection. - } - - @Nullable - @Override - public Uri getUri() { - return mUri; - } } /** diff --git a/tuner/src/com/android/tv/tuner/source/TsDataSource.java b/tuner/src/com/android/tv/tuner/source/TsDataSource.java index 18f4458b..cf3c25d9 100644 --- a/tuner/src/com/android/tv/tuner/source/TsDataSource.java +++ b/tuner/src/com/android/tv/tuner/source/TsDataSource.java @@ -17,7 +17,7 @@ package com.android.tv.tuner.source; import com.android.tv.common.compat.TvInputConstantCompat; -import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer.upstream.DataSource; /** {@link DataSource} for MPEG-TS stream, which will be used by {@link TsExtractor}. */ public abstract class TsDataSource implements DataSource { diff --git a/tuner/src/com/android/tv/tuner/source/TsDataSourceManager.java b/tuner/src/com/android/tv/tuner/source/TsDataSourceManager.java index 3c00b5cc..28756a93 100644 --- a/tuner/src/com/android/tv/tuner/source/TsDataSourceManager.java +++ b/tuner/src/com/android/tv/tuner/source/TsDataSourceManager.java @@ -19,8 +19,8 @@ package com.android.tv.tuner.source; import android.content.Context; import android.support.annotation.VisibleForTesting; import com.android.tv.tuner.api.Tuner; -import com.android.tv.tuner.data.Channel; import com.android.tv.tuner.data.TunerChannel; +import com.android.tv.tuner.data.nano.Channel; import com.android.tv.tuner.ts.EventDetector.EventListener; import com.google.auto.factory.AutoFactory; import com.google.auto.factory.Provided; diff --git a/tuner/src/com/android/tv/tuner/source/TunerTsStreamer.java b/tuner/src/com/android/tv/tuner/source/TunerTsStreamer.java index 19058c8a..9e68c910 100644 --- a/tuner/src/com/android/tv/tuner/source/TunerTsStreamer.java +++ b/tuner/src/com/android/tv/tuner/source/TunerTsStreamer.java @@ -17,11 +17,8 @@ package com.android.tv.tuner.source; import android.content.Context; -import android.net.Uri; -import android.support.annotation.Nullable; import android.util.Log; import android.util.Pair; - import com.android.tv.common.SoftPreconditions; import com.android.tv.tuner.api.ScanChannel; import com.android.tv.tuner.api.Tuner; @@ -29,10 +26,8 @@ import com.android.tv.tuner.data.TunerChannel; import com.android.tv.tuner.prefs.TunerPreferences; import com.android.tv.tuner.ts.EventDetector; import com.android.tv.tuner.ts.EventDetector.EventListener; - -import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.upstream.DataSpec; -import com.google.android.exoplayer2.upstream.TransferListener; +import com.google.android.exoplayer.C; +import com.google.android.exoplayer.upstream.DataSpec; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -71,7 +66,6 @@ public class TunerTsStreamer implements TsStreamer { private final TunerTsStreamer mTsStreamer; private final AtomicLong mLastReadPosition = new AtomicLong(0); private long mStartBufferedPosition; - private Uri mUri; private TunerDataSource(TunerTsStreamer tsStreamer) { mTsStreamer = tsStreamer; @@ -96,16 +90,13 @@ public class TunerTsStreamer implements TsStreamer { } @Override - public long open(DataSpec dataSpec) { - mUri = dataSpec.uri; + public long open(DataSpec dataSpec) throws IOException { mLastReadPosition.set(0); - return C.LENGTH_UNSET; + return C.LENGTH_UNBOUNDED; } @Override - public void close() { - mUri = null; - } + public void close() {} @Override public int read(byte[] buffer, int offset, int readLength) throws IOException { @@ -135,18 +126,6 @@ public class TunerTsStreamer implements TsStreamer { public int getSignalStrength() { return mTsStreamer.getSignalStrength(); } - - @Override - public void addTransferListener(TransferListener transferListener) { - // TODO: Implement to support metrics collection. - } - - @Nullable - @Override - public Uri getUri() { - return mUri; - } - } /** * Creates {@link TsStreamer} for playing or recording the specified channel. @@ -173,8 +152,7 @@ public class TunerTsStreamer implements TsStreamer { @Override public boolean startStream(TunerChannel channel) { if (mTunerHal.tune( - channel.getDeliverySystemType().getNumber(), channel.getFrequency(), - channel.getModulation(), channel.getDisplayNumber(false))) { + channel.getFrequency(), channel.getModulation(), channel.getDisplayNumber(false))) { if (channel.hasVideo()) { mTunerHal.addPidFilter(channel.getVideoPid(), Tuner.FILTER_TYPE_VIDEO); } @@ -192,7 +170,6 @@ public class TunerTsStreamer implements TsStreamer { mTunerHal.addPidFilter(channel.getPcrPid(), Tuner.FILTER_TYPE_PCR); if (mEventDetector != null) { mEventDetector.startDetecting( - channel.getDeliverySystemType(), channel.getFrequency(), channel.getModulation(), channel.getProgramNumber()); @@ -222,11 +199,9 @@ public class TunerTsStreamer implements TsStreamer { @Override public boolean startStream(ScanChannel channel) { - if (mTunerHal.tune(channel.deliverySystemType.getNumber(), channel.frequency, - channel.modulation, null)) { + if (mTunerHal.tune(channel.frequency, channel.modulation, null)) { mEventDetector.startDetecting( - channel.deliverySystemType, channel.frequency, channel.modulation, - EventDetector.ALL_PROGRAM_NUMBERS); + channel.frequency, channel.modulation, EventDetector.ALL_PROGRAM_NUMBERS); synchronized (mCircularBufferMonitor) { if (mStreaming) { Log.w(TAG, "Streaming should be stopped before start streaming"); @@ -320,7 +295,7 @@ public class TunerTsStreamer implements TsStreamer { public void registerListener(EventListener listener) { if (mEventDetector != null && listener != null) { synchronized (mEventListenerActions) { - mEventListenerActions.add(Pair.create(listener, true)); + mEventListenerActions.add(new Pair<>(listener, true)); } } } diff --git a/tuner/src/com/android/tv/tuner/ts/EventDetector.java b/tuner/src/com/android/tv/tuner/ts/EventDetector.java index 3a2d835e..6d1fc277 100644 --- a/tuner/src/com/android/tv/tuner/ts/EventDetector.java +++ b/tuner/src/com/android/tv/tuner/ts/EventDetector.java @@ -20,13 +20,12 @@ import android.util.Log; import android.util.SparseArray; import android.util.SparseBooleanArray; import com.android.tv.tuner.api.Tuner; -import com.android.tv.tuner.data.Channel.DeliverySystemType; import com.android.tv.tuner.data.PsiData; import com.android.tv.tuner.data.PsipData; import com.android.tv.tuner.data.PsipData.EitItem; -import com.android.tv.tuner.data.Track.AtscAudioTrack; -import com.android.tv.tuner.data.Track.AtscCaptionTrack; import com.android.tv.tuner.data.TunerChannel; +import com.android.tv.tuner.data.nano.Track.AtscAudioTrack; +import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -52,7 +51,6 @@ public class EventDetector { private final SparseBooleanArray mVctCaptionTracksFound = new SparseBooleanArray(); private final SparseBooleanArray mEitCaptionTracksFound = new SparseBooleanArray(); private final List<EventListener> mEventListeners = new ArrayList<>(); - private DeliverySystemType mDeliverySystemType; private int mFrequency; private String mModulation; private int mProgramNumber = ALL_PROGRAM_NUMBERS; @@ -172,7 +170,6 @@ public class EventDetector { } tunerChannel.setAudioTracks(audioTracks); tunerChannel.setCaptionTracks(captionTracks); - tunerChannel.setDeliverySystemType(mDeliverySystemType); tunerChannel.setFrequency(mFrequency); tunerChannel.setModulation(mModulation); mChannelMap.put(tunerChannel.getProgramNumber(), tunerChannel); @@ -212,7 +209,6 @@ public class EventDetector { int channelProgramNumber = channel.getServiceId(); tunerChannel.setAudioTracks(audioTracks); tunerChannel.setCaptionTracks(captionTracks); - tunerChannel.setDeliverySystemType(mDeliverySystemType); tunerChannel.setFrequency(mFrequency); tunerChannel.setModulation(mModulation); mChannelMap.put(tunerChannel.getProgramNumber(), tunerChannel); @@ -256,18 +252,10 @@ public class EventDetector { private void reset() { // TODO: Use TsParser.reset() - int[] deliverySystemTypes = mTunerHal.getDeliverySystemTypes(); - boolean isDvbSignal = false; - for (int i = 0; i < deliverySystemTypes.length; i++) { - if (Tuner.isDvbDeliverySystem(deliverySystemTypes[i])) { - isDvbSignal = true; - break; - } - } mTsParser = new TsParser( mTsOutputListener, - isDvbSignal); + Tuner.isDvbDeliverySystem(mTunerHal.getDeliverySystemType())); mPidSet.clear(); mVctProgramNumberSet.clear(); mSdtProgramNumberSet.clear(); @@ -284,10 +272,8 @@ public class EventDetector { * @param programNumber The program number if this is for handling tune request. For scanning * purpose, supply {@link #ALL_PROGRAM_NUMBERS}. */ - public void startDetecting(DeliverySystemType deliverySystemType, int frequency, - String modulation, int programNumber) { + public void startDetecting(int frequency, String modulation, int programNumber) { reset(); - mDeliverySystemType = deliverySystemType; mFrequency = frequency; mModulation = modulation; mProgramNumber = programNumber; diff --git a/tuner/src/com/android/tv/tuner/tvinput/BaseTunerTvInputService.java b/tuner/src/com/android/tv/tuner/tvinput/BaseTunerTvInputService.java index e47162ad..d22b6399 100644 --- a/tuner/src/com/android/tv/tuner/tvinput/BaseTunerTvInputService.java +++ b/tuner/src/com/android/tv/tuner/tvinput/BaseTunerTvInputService.java @@ -21,26 +21,17 @@ import android.app.job.JobScheduler; import android.content.ComponentName; import android.content.Context; import android.media.tv.TvInputService; -import android.net.Uri; import android.util.Log; - import com.android.tv.common.feature.CommonFeatures; +import com.android.tv.tuner.source.TsDataSourceManager; import com.android.tv.tuner.tvinput.datamanager.ChannelDataManager; -import com.android.tv.tuner.tvinput.factory.TunerRecordingSessionFactory; import com.android.tv.tuner.tvinput.factory.TunerSessionFactory; - -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.google.common.cache.RemovalListener; - import dagger.android.AndroidInjection; - +import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags; import java.util.Collections; import java.util.Set; import java.util.WeakHashMap; import java.util.concurrent.TimeUnit; - import javax.inject.Inject; /** {@link BaseTunerTvInputService} serves TV channels coming from a tuner device. */ @@ -51,19 +42,10 @@ public class BaseTunerTvInputService extends TvInputService { private static final int DVR_STORAGE_CLEANUP_JOB_ID = 100; private final Set<Session> mTunerSessions = Collections.newSetFromMap(new WeakHashMap<>()); - private final Set<RecordingSession> mTunerRecordingSession = - Collections.newSetFromMap(new WeakHashMap<>()); + private ChannelDataManager mChannelDataManager; + @Inject ConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags; + @Inject TsDataSourceManager.Factory mTsDataSourceManagerFactory; @Inject TunerSessionFactory mTunerSessionFactory; - @Inject TunerRecordingSessionFactory mTunerRecordingSessionFactory; - - LoadingCache<String, ChannelDataManager> mChannelDataManagers; - RemovalListener<String, ChannelDataManager> mChannelDataManagerRemovalListener = - notification -> { - ChannelDataManager cdm = notification.getValue(); - if (cdm != null) { - cdm.release(); - } - }; @Override public void onCreate() { @@ -75,17 +57,7 @@ public class BaseTunerTvInputService extends TvInputService { AndroidInjection.inject(this); super.onCreate(); if (DEBUG) Log.d(TAG, "onCreate"); - mChannelDataManagers = - CacheBuilder.newBuilder() - .weakValues() - .removalListener(mChannelDataManagerRemovalListener) - .build( - new CacheLoader<String, ChannelDataManager>() { - @Override - public ChannelDataManager load(String inputId) { - return createChannelDataManager(inputId); - } - }); + mChannelDataManager = new ChannelDataManager(getApplicationContext()); if (CommonFeatures.DVR.isEnabled(this)) { JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE); @@ -105,24 +77,21 @@ public class BaseTunerTvInputService extends TvInputService { } } - private ChannelDataManager createChannelDataManager(String inputId) { - return new ChannelDataManager(getApplicationContext(), inputId); - } - @Override public void onDestroy() { if (DEBUG) Log.d(TAG, "onDestroy"); super.onDestroy(); - mChannelDataManagers.invalidateAll(); + mChannelDataManager.release(); } @Override public RecordingSession onCreateRecordingSession(String inputId) { - RecordingSession session = - mTunerRecordingSessionFactory.create( - inputId, this::onReleased, mChannelDataManagers.getUnchecked(inputId)); - mTunerRecordingSession.add(session); - return session; + return new TunerRecordingSession( + this, + inputId, + mChannelDataManager, + mConcurrentDvrPlaybackFlags, + mTsDataSourceManagerFactory); } @Override @@ -134,12 +103,8 @@ public class BaseTunerTvInputService extends TvInputService { Log.d(TAG, "abort creating an session"); return null; } - final Session session = - mTunerSessionFactory.create( - mChannelDataManagers.getUnchecked(inputId), - this::onReleased, - this::getRecordingUri); + mTunerSessionFactory.create(this, mChannelDataManager, this::onReleased); mTunerSessions.add(session); session.setOverlayViewEnabled(true); return session; @@ -150,22 +115,7 @@ public class BaseTunerTvInputService extends TvInputService { } } - private Uri getRecordingUri(Uri channelUri) { - for (RecordingSession session : mTunerRecordingSession) { - TunerRecordingSession tunerSession = (TunerRecordingSession) session; - if (tunerSession.getChannelUri().equals(channelUri)) { - return tunerSession.getRecordingUri(); - } - } - return null; - } - private void onReleased(Session session) { mTunerSessions.remove(session); - mChannelDataManagers.cleanUp(); - } - - private void onReleased(RecordingSession session) { - mTunerRecordingSession.remove(session); } } diff --git a/tuner/src/com/android/tv/tuner/tvinput/TunerRecordingSession.java b/tuner/src/com/android/tv/tuner/tvinput/TunerRecordingSession.java index ed61f71b..55616931 100644 --- a/tuner/src/com/android/tv/tuner/tvinput/TunerRecordingSession.java +++ b/tuner/src/com/android/tv/tuner/tvinput/TunerRecordingSession.java @@ -22,40 +22,33 @@ import android.support.annotation.MainThread; import android.support.annotation.Nullable; import android.support.annotation.WorkerThread; import android.util.Log; - import com.android.tv.common.compat.RecordingSessionCompat; -import com.android.tv.common.dagger.annotations.ApplicationContext; +import com.android.tv.tuner.source.TsDataSourceManager; import com.android.tv.tuner.tvinput.datamanager.ChannelDataManager; -import com.android.tv.tuner.tvinput.factory.TunerRecordingSessionFactory; -import com.android.tv.tuner.tvinput.factory.TunerRecordingSessionFactory.RecordingSessionReleasedCallback; - -import com.google.auto.factory.AutoFactory; -import com.google.auto.factory.Provided; +import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags; /** Processes DVR recordings, and deletes the previously recorded contents. */ -@AutoFactory( - className = "TunerRecordingSessionFactoryImpl", - implementing = TunerRecordingSessionFactory.class) public class TunerRecordingSession extends RecordingSessionCompat { private static final String TAG = "TunerRecordingSession"; private static final boolean DEBUG = false; private final TunerRecordingSessionWorker mSessionWorker; - private final RecordingSessionReleasedCallback mReleasedCallback; - private Uri mChannelUri; - private Uri mRecordingUri; public TunerRecordingSession( - @Provided @ApplicationContext Context context, + Context context, String inputId, - RecordingSessionReleasedCallback releasedCallback, ChannelDataManager channelDataManager, - @Provided TunerRecordingSessionWorker.Factory tunerRecordingSessionWorkerFactory) { + ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags, + TsDataSourceManager.Factory tsDataSourceManagerFactory) { super(context); - mReleasedCallback = releasedCallback; mSessionWorker = - tunerRecordingSessionWorkerFactory.create( - context, inputId, channelDataManager, this); + new TunerRecordingSessionWorker( + context, + inputId, + channelDataManager, + this, + concurrentDvrPlaybackFlags, + tsDataSourceManagerFactory); } // RecordingSession @@ -76,7 +69,6 @@ public class TunerRecordingSession extends RecordingSessionCompat { Log.d(TAG, "Requesting recording session release."); } mSessionWorker.release(); - mReleasedCallback.onReleased(this); } @MainThread @@ -103,7 +95,6 @@ public class TunerRecordingSession extends RecordingSessionCompat { if (DEBUG) { Log.d(TAG, "Notifying recording session tuned."); } - mChannelUri = channelUri; notifyTuned(channelUri); } @@ -121,7 +112,6 @@ public class TunerRecordingSession extends RecordingSessionCompat { if (DEBUG) { Log.d(TAG, "Notifying record successfully finished."); } - mRecordingUri = null; notifyRecordingStopped(recordedProgramUri); } @@ -130,19 +120,4 @@ public class TunerRecordingSession extends RecordingSessionCompat { Log.w(TAG, "Notifying recording error: " + reason); notifyError(reason); } - - public void onRecordingStatePartial(Uri recUri) { - if (DEBUG) { - Log.d(TAG, "Updating recording session state to Partial"); - } - mRecordingUri = recUri; - } - - public Uri getChannelUri() { - return mChannelUri; - } - - public Uri getRecordingUri() { - return mRecordingUri; - } } diff --git a/tuner/src/com/android/tv/tuner/tvinput/TunerRecordingSessionWorker.java b/tuner/src/com/android/tv/tuner/tvinput/TunerRecordingSessionWorker.java index 97cd0572..2c0c09a6 100644 --- a/tuner/src/com/android/tv/tuner/tvinput/TunerRecordingSessionWorker.java +++ b/tuner/src/com/android/tv/tuner/tvinput/TunerRecordingSessionWorker.java @@ -37,19 +37,17 @@ import android.support.annotation.MainThread; import android.support.annotation.Nullable; import android.util.Log; import android.util.Pair; - import androidx.tvprovider.media.tv.Program; - import com.android.tv.common.BaseApplication; import com.android.tv.common.data.RecordedProgramState; import com.android.tv.common.recording.RecordingCapability; import com.android.tv.common.recording.RecordingStorageStatusManager; import com.android.tv.common.util.CommonUtils; +import com.android.tv.tuner.DvbDeviceAccessor; import com.android.tv.tuner.data.PsipData; import com.android.tv.tuner.data.PsipData.EitItem; -import com.android.tv.tuner.data.Track.AtscCaptionTrack; import com.android.tv.tuner.data.TunerChannel; -import com.android.tv.tuner.dvb.DvbDeviceAccessor; +import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack; import com.android.tv.tuner.exoplayer.ExoPlayerSampleExtractor; import com.android.tv.tuner.exoplayer.SampleExtractor; import com.android.tv.tuner.exoplayer.buffer.BufferManager; @@ -59,11 +57,8 @@ import com.android.tv.tuner.source.TsDataSource; import com.android.tv.tuner.source.TsDataSourceManager; import com.android.tv.tuner.ts.EventDetector.EventListener; import com.android.tv.tuner.tvinput.datamanager.ChannelDataManager; - import com.google.android.exoplayer.C; -import com.google.auto.factory.AutoFactory; -import com.google.auto.factory.Provided; - +import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags; import java.io.File; import java.io.IOException; import java.lang.annotation.Retention; @@ -147,6 +142,7 @@ public class TunerRecordingSessionWorker private static final long CHANNEL_ID_NONE = -1; private static final int MAX_TUNING_RETRY = 6; + private final ConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags; private final Context mContext; private final ChannelDataManager mChannelDataManager; @@ -172,31 +168,15 @@ public class TunerRecordingSessionWorker private PsipData.EitItem mCurrenProgram; private List<AtscCaptionTrack> mCaptionTracks; private DvrStorageManager mDvrStorageManager; - private final ExoPlayerSampleExtractor.Factory mExoPlayerSampleExtractorFactory; - /** - * Factory for {@link TunerRecordingSessionWorker}}. - * - * <p>This wrapper class keeps other classes from needing to reference the {@link AutoFactory} - * generated class. - */ - public interface Factory { - TunerRecordingSessionWorker create( - Context context, - String inputId, - ChannelDataManager dataManager, - TunerRecordingSession session); - } - - @AutoFactory(implementing = Factory.class) public TunerRecordingSessionWorker( Context context, String inputId, ChannelDataManager dataManager, TunerRecordingSession session, - @Provided ExoPlayerSampleExtractor.Factory exoPlayerSampleExtractorFactory, - @Provided TsDataSourceManager.Factory tsDataSourceManagerFactory) { - mExoPlayerSampleExtractorFactory = exoPlayerSampleExtractorFactory; + ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags, + TsDataSourceManager.Factory tsDataSourceManagerFactory) { + mConcurrentDvrPlaybackFlags = concurrentDvrPlaybackFlags; mRandom.setSeed(System.nanoTime()); mContext = context; HandlerThread handlerThread = new HandlerThread(TAG); @@ -237,7 +217,7 @@ public class TunerRecordingSessionWorker if (mChannel == null || mChannel.compareTo(channel) != 0) { return; } - mHandler.obtainMessage(MSG_UPDATE_CC_INFO, Pair.create(channel, items)).sendToTarget(); + mHandler.obtainMessage(MSG_UPDATE_CC_INFO, new Pair<>(channel, items)).sendToTarget(); mChannelDataManager.notifyEventDetected(channel, items); } @@ -382,7 +362,7 @@ public class TunerRecordingSessionWorker } case MSG_UPDATE_PARTIAL_STATE: { - updateRecordedProgramStatePartial(); + updateRecordedProgram(RecordedProgramState.PARTIAL, -1, -1); return true; } } @@ -476,30 +456,36 @@ public class TunerRecordingSessionWorker mRecordStartTime = System.currentTimeMillis(); mDvrStorageManager = new DvrStorageManager(mStorageDir, true); mRecorder = - mExoPlayerSampleExtractorFactory.create( - Uri.EMPTY, mTunerSource, new BufferManager(mDvrStorageManager), this, true); + new ExoPlayerSampleExtractor( + Uri.EMPTY, + mTunerSource, + new BufferManager(mDvrStorageManager), + this, + true, + mConcurrentDvrPlaybackFlags); mRecorder.setOnCompletionListener(this, mHandler); mProgramUri = programUri; mSessionState = STATE_RECORDING; mRecorderRunning = true; - mRecordedProgramUri = - insertRecordedProgram( - getRecordedProgram(), - mChannel.getChannelId(), - Uri.fromFile(mStorageDir).toString(), - calculateRecordingSizeInBytes(), - mRecordStartTime, - mRecordStartTime); - if (mRecordedProgramUri == null) { - new DeleteRecordingTask().execute(mStorageDir); - mSession.onError(TvInputManager.RECORDING_ERROR_UNKNOWN); - Log.e(TAG, "Inserting a recording to DB failed"); - return false; + if (mConcurrentDvrPlaybackFlags.enabled()) { + mRecordedProgramUri = + insertRecordedProgram( + getRecordedProgram(), + mChannel.getChannelId(), + Uri.fromFile(mStorageDir).toString(), + calculateRecordingSizeInBytes(), + mRecordStartTime, + mRecordStartTime); + if (mRecordedProgramUri == null) { + new DeleteRecordingTask().execute(mStorageDir); + mSession.onError(TvInputManager.RECORDING_ERROR_UNKNOWN); + Log.e(TAG, "Inserting a recording to DB failed"); + return false; + } + mSession.onRecordingUri(mRecordedProgramUri.toString()); + mHandler.sendEmptyMessageDelayed( + MSG_UPDATE_PARTIAL_STATE, MIN_PARTIAL_RECORDING_DURATION_MS); } - mSession.onRecordingUri(mRecordedProgramUri.toString()); - mHandler.sendEmptyMessageDelayed( - MSG_UPDATE_PARTIAL_STATE, MIN_PARTIAL_RECORDING_DURATION_MS); - mHandler.sendEmptyMessage(MSG_PREPARE_RECODER); mHandler.removeMessages(MSG_MONITOR_STORAGE_STATUS); mHandler.sendEmptyMessageDelayed(MSG_MONITOR_STORAGE_STATUS, STORAGE_MONITOR_INTERVAL_MS); @@ -606,7 +592,7 @@ public class TunerRecordingSessionWorker if (checkRecordedProgramTable(COLUMN_SERIES_ID)) { values.put(COLUMN_SERIES_ID, mSeriesId); } - if (checkRecordedProgramTable(COLUMN_STATE)) { + if (mConcurrentDvrPlaybackFlags.enabled() && checkRecordedProgramTable(COLUMN_STATE)) { values.put(COLUMN_STATE, RecordedProgramState.STARTED.name()); } if (program != null) { @@ -616,24 +602,18 @@ public class TunerRecordingSessionWorker .insert(TvContract.RecordedPrograms.CONTENT_URI, values); } - private void updateRecordedProgramStateFinished(long endTime, long totalBytes) { + private void updateRecordedProgram(RecordedProgramState state, long endTime, long totalBytes) { ContentValues values = new ContentValues(); - values.put(RecordedPrograms.COLUMN_RECORDING_DATA_BYTES, totalBytes); - values.put(RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS, endTime - mRecordStartTime); - values.put(RecordedPrograms.COLUMN_END_TIME_UTC_MILLIS, endTime); if (checkRecordedProgramTable(COLUMN_STATE)) { - values.put(COLUMN_STATE, RecordedProgramState.FINISHED.name()); + values.put(COLUMN_STATE, state.name()); } - mContext.getContentResolver().update(mRecordedProgramUri, values, null, null); - } - - private void updateRecordedProgramStatePartial() { - mSession.onRecordingStatePartial(mRecordedProgramUri); - if (checkRecordedProgramTable(COLUMN_STATE)) { - ContentValues values = new ContentValues(); - values.put(COLUMN_STATE, RecordedProgramState.PARTIAL.name()); - mContext.getContentResolver().update(mRecordedProgramUri, values, null, null); + if (state.equals(RecordedProgramState.FINISHED)) { + values.put(RecordedPrograms.COLUMN_RECORDING_DATA_BYTES, totalBytes); + values.put( + RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS, endTime - mRecordStartTime); + values.put(RecordedPrograms.COLUMN_END_TIME_UTC_MILLIS, endTime); } + mContext.getContentResolver().update(mRecordedProgramUri, values, null, null); } private void onRecordingResult(boolean success, long lastExtractedPositionUs) { @@ -660,7 +640,25 @@ public class TunerRecordingSessionWorker (lastExtractedPositionUs == C.UNKNOWN_TIME_US) ? System.currentTimeMillis() : mRecordStartTime + lastExtractedPositionUs / 1000; - updateRecordedProgramStateFinished(recordEndTime, calculateRecordingSizeInBytes()); + if (!mConcurrentDvrPlaybackFlags.enabled()) { + mRecordedProgramUri = + insertRecordedProgram( + getRecordedProgram(), + mChannel.getChannelId(), + Uri.fromFile(mStorageDir).toString(), + calculateRecordingSizeInBytes(), + mRecordStartTime, + recordEndTime); + if (mRecordedProgramUri == null) { + new DeleteRecordingTask().execute(mStorageDir); + mSession.onError(TvInputManager.RECORDING_ERROR_UNKNOWN); + Log.e(TAG, "Inserting a recording to DB failed"); + return; + } + } else { + updateRecordedProgram( + RecordedProgramState.FINISHED, recordEndTime, calculateRecordingSizeInBytes()); + } mDvrStorageManager.writeCaptionInfoFiles(mCaptionTracks); mSession.onRecordFinished(mRecordedProgramUri); } diff --git a/tuner/src/com/android/tv/tuner/tvinput/TunerSession.java b/tuner/src/com/android/tv/tuner/tvinput/TunerSession.java index eb3a7d0c..fedb5f6b 100644 --- a/tuner/src/com/android/tv/tuner/tvinput/TunerSession.java +++ b/tuner/src/com/android/tv/tuner/tvinput/TunerSession.java @@ -27,24 +27,18 @@ import android.os.SystemClock; import android.util.Log; import android.view.Surface; import android.view.View; - import com.android.tv.common.CommonPreferences.CommonPreferencesChangedListener; import com.android.tv.common.compat.TisSessionCompat; -import com.android.tv.common.dagger.annotations.ApplicationContext; import com.android.tv.tuner.prefs.TunerPreferences; +import com.android.tv.tuner.source.TsDataSourceManager; import com.android.tv.tuner.tvinput.datamanager.ChannelDataManager; -import com.android.tv.tuner.tvinput.factory.TunerSessionFactory; -import com.android.tv.tuner.tvinput.factory.TunerSessionFactory.SessionRecordingCallback; import com.android.tv.tuner.tvinput.factory.TunerSessionFactory.SessionReleasedCallback; - -import com.google.auto.factory.AutoFactory; -import com.google.auto.factory.Provided; +import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags; /** * Provides a tuner TV input session. Main tuner input functions are implemented in {@link * TunerSessionWorker}. */ -@AutoFactory(className = "TunerSessionV1Factory", implementing = TunerSessionFactory.class) public class TunerSession extends TisSessionCompat implements CommonPreferencesChangedListener { private static final String TAG = "TunerSession"; @@ -53,26 +47,26 @@ public class TunerSession extends TisSessionCompat implements CommonPreferencesC private final TunerSessionOverlay mTunerSessionOverlay; private final TunerSessionWorker mSessionWorker; private final SessionReleasedCallback mReleasedCallback; - private final SessionRecordingCallback mRecordingCallback; private boolean mPlayPaused; private long mTuneStartTimestamp; public TunerSession( - @Provided @ApplicationContext Context context, + Context context, ChannelDataManager channelDataManager, SessionReleasedCallback releasedCallback, - SessionRecordingCallback recordingCallback, - @Provided TunerSessionWorker.Factory tunerSessionWorkerFactory) { + ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags, + TsDataSourceManager.Factory tsDataSourceManagerFactory) { super(context); mReleasedCallback = releasedCallback; - mRecordingCallback = recordingCallback; mTunerSessionOverlay = new TunerSessionOverlay(context); mSessionWorker = - tunerSessionWorkerFactory.create( + new TunerSessionWorker( context, channelDataManager, this, - mTunerSessionOverlay); + mTunerSessionOverlay, + concurrentDvrPlaybackFlags, + tsDataSourceManagerFactory); TunerPreferences.setCommonPreferencesChangedListener(this); } @@ -210,8 +204,4 @@ public class TunerSession extends TisSessionCompat implements CommonPreferencesC public void onCommonPreferencesChanged() { mSessionWorker.sendMessage(TunerSessionWorker.MSG_TUNER_PREFERENCES_CHANGED); } - - public Uri getRecordingUri(Uri channelUri) { - return mRecordingCallback.getRecordingUri(channelUri); - } } diff --git a/tuner/src/com/android/tv/tuner/tvinput/TunerSessionExoV2.java b/tuner/src/com/android/tv/tuner/tvinput/TunerSessionExoV2.java index 7ebb2b21..4eca44d6 100644 --- a/tuner/src/com/android/tv/tuner/tvinput/TunerSessionExoV2.java +++ b/tuner/src/com/android/tv/tuner/tvinput/TunerSessionExoV2.java @@ -27,21 +27,15 @@ import android.os.SystemClock; import android.util.Log; import android.view.Surface; import android.view.View; - import com.android.tv.common.CommonPreferences.CommonPreferencesChangedListener; import com.android.tv.common.compat.TisSessionCompat; -import com.android.tv.common.dagger.annotations.ApplicationContext; import com.android.tv.tuner.prefs.TunerPreferences; +import com.android.tv.tuner.source.TsDataSourceManager; import com.android.tv.tuner.tvinput.datamanager.ChannelDataManager; -import com.android.tv.tuner.tvinput.factory.TunerSessionFactory; -import com.android.tv.tuner.tvinput.factory.TunerSessionFactory.SessionRecordingCallback; import com.android.tv.tuner.tvinput.factory.TunerSessionFactory.SessionReleasedCallback; - -import com.google.auto.factory.AutoFactory; -import com.google.auto.factory.Provided; +import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags; /** Provides a tuner TV input session. */ -@AutoFactory(implementing = TunerSessionFactory.class) public class TunerSessionExoV2 extends TisSessionCompat implements CommonPreferencesChangedListener { @@ -51,26 +45,26 @@ public class TunerSessionExoV2 extends TisSessionCompat private final TunerSessionOverlay mTunerSessionOverlay; private final TunerSessionWorkerExoV2 mSessionWorker; private final SessionReleasedCallback mReleasedCallback; - private final SessionRecordingCallback mRecordingCallback; private boolean mPlayPaused; private long mTuneStartTimestamp; public TunerSessionExoV2( - @Provided @ApplicationContext Context context, + Context context, ChannelDataManager channelDataManager, SessionReleasedCallback releasedCallback, - SessionRecordingCallback recordingCallback, - @Provided TunerSessionWorkerExoV2.Factory tunerSessionWorkerExoV2Factory) { + ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags, + TsDataSourceManager.Factory tsDataSourceManagerFactory) { super(context); mReleasedCallback = releasedCallback; - mRecordingCallback = recordingCallback; mTunerSessionOverlay = new TunerSessionOverlay(context); mSessionWorker = - tunerSessionWorkerExoV2Factory.create( + new TunerSessionWorkerExoV2( context, channelDataManager, this, - mTunerSessionOverlay); + mTunerSessionOverlay, + concurrentDvrPlaybackFlags, + tsDataSourceManagerFactory); TunerPreferences.setCommonPreferencesChangedListener(this); } @@ -209,8 +203,4 @@ public class TunerSessionExoV2 extends TisSessionCompat public void onCommonPreferencesChanged() { mSessionWorker.sendMessage(TunerSessionWorkerExoV2.MSG_TUNER_PREFERENCES_CHANGED); } - - public Uri getRecordingUri(Uri channelUri) { - return mRecordingCallback.getRecordingUri(channelUri); - } } diff --git a/tuner/src/com/android/tv/tuner/tvinput/TunerSessionOverlay.java b/tuner/src/com/android/tv/tuner/tvinput/TunerSessionOverlay.java index 53e0bcc2..9f21e16a 100644 --- a/tuner/src/com/android/tv/tuner/tvinput/TunerSessionOverlay.java +++ b/tuner/src/com/android/tv/tuner/tvinput/TunerSessionOverlay.java @@ -26,18 +26,17 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import android.widget.Toast; - +import com.android.tv.common.util.SystemPropertiesProxy; import com.android.tv.tuner.R; import com.android.tv.tuner.cc.CaptionLayout; import com.android.tv.tuner.cc.CaptionTrackRenderer; import com.android.tv.tuner.data.Cea708Data.CaptionEvent; -import com.android.tv.tuner.data.Track.AtscCaptionTrack; +import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack; import com.android.tv.tuner.util.GlobalSettingsUtils; import com.android.tv.tuner.util.StatusTextUtils; /** Executes {@link Session} overlay changes on the main thread. */ /* package */ final class TunerSessionOverlay implements Handler.Callback { - private static final boolean DEBUG = false; /** Displays the given {@link String} message object in the message view. */ public static final int MSG_UI_SHOW_MESSAGE = 1; @@ -68,6 +67,8 @@ import com.android.tv.tuner.util.StatusTextUtils; /** Displays a toast signalling that a re-scan is required. Does not expect a message object. */ public static final int MSG_UI_TOAST_RESCAN_NEEDED = 11; + private static final String USBTUNER_SHOW_DEBUG = "persist.tv.tuner.show_debug"; + private final Context mContext; private final Handler mHandler; private final View mOverlayView; @@ -87,12 +88,13 @@ import com.android.tv.tuner.util.StatusTextUtils; mHandler = new Handler(this); LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + boolean showDebug = SystemPropertiesProxy.getBoolean(USBTUNER_SHOW_DEBUG, false); mOverlayView = inflater.inflate(R.layout.ut_overlay_view, null); mMessageLayout = mOverlayView.findViewById(R.id.message_layout); mMessageLayout.setVisibility(View.INVISIBLE); mMessageView = mOverlayView.findViewById(R.id.message); mStatusView = mOverlayView.findViewById(R.id.tuner_status); - mStatusView.setVisibility(DEBUG ? View.VISIBLE : View.INVISIBLE); + mStatusView.setVisibility(showDebug ? View.VISIBLE : View.INVISIBLE); mAudioStatusView = mOverlayView.findViewById(R.id.audio_status); mAudioStatusView.setVisibility(View.INVISIBLE); CaptionLayout captionLayout = mOverlayView.findViewById(R.id.caption); diff --git a/tuner/src/com/android/tv/tuner/tvinput/TunerSessionWorker.java b/tuner/src/com/android/tv/tuner/tvinput/TunerSessionWorker.java index 792dfaab..d3f9409b 100644 --- a/tuner/src/com/android/tv/tuner/tvinput/TunerSessionWorker.java +++ b/tuner/src/com/android/tv/tuner/tvinput/TunerSessionWorker.java @@ -44,22 +44,22 @@ import android.util.Pair; import android.util.SparseArray; import android.view.Surface; import android.view.accessibility.CaptioningManager; - import com.android.tv.common.CommonPreferences.TrickplaySetting; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.TvContentRatingCache; import com.android.tv.common.compat.TvInputConstantCompat; import com.android.tv.common.customization.CustomizationManager; import com.android.tv.common.customization.CustomizationManager.TRICKPLAY_MODE; -import com.android.tv.common.dev.DeveloperPreferences; +import com.android.tv.common.experiments.Experiments; import com.android.tv.common.feature.CommonFeatures; +import com.android.tv.common.util.SystemPropertiesProxy; import com.android.tv.tuner.data.Cea708Data; -import com.android.tv.tuner.data.Channel; import com.android.tv.tuner.data.PsipData.EitItem; import com.android.tv.tuner.data.PsipData.TvTracksInterface; -import com.android.tv.tuner.data.Track.AtscAudioTrack; -import com.android.tv.tuner.data.Track.AtscCaptionTrack; import com.android.tv.tuner.data.TunerChannel; +import com.android.tv.tuner.data.nano.Channel; +import com.android.tv.tuner.data.nano.Track.AtscAudioTrack; +import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack; import com.android.tv.tuner.exoplayer.MpegTsPlayer; import com.android.tv.tuner.exoplayer.MpegTsRendererBuilder; import com.android.tv.tuner.exoplayer.buffer.BufferManager; @@ -74,15 +74,10 @@ import com.android.tv.tuner.ts.EventDetector.EventListener; import com.android.tv.tuner.tvinput.datamanager.ChannelDataManager; import com.android.tv.tuner.tvinput.debug.TunerDebug; import com.android.tv.tuner.util.StatusTextUtils; - import com.google.android.exoplayer.ExoPlayer; import com.google.android.exoplayer.audio.AudioCapabilities; -import com.google.auto.factory.AutoFactory; -import com.google.auto.factory.Provided; import com.google.common.collect.ImmutableList; - -import com.android.tv.common.flags.LegacyFlags; - +import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags; import java.io.File; import java.util.ArrayList; import java.util.Iterator; @@ -108,6 +103,8 @@ public class TunerSessionWorker private static final boolean DEBUG = false; private static final boolean ENABLE_PROFILER = true; private static final String PLAY_FROM_CHANNEL = "channel"; + private static final String MAX_BUFFER_SIZE_KEY = "tv.tuner.buffersize_mbytes"; + private static final int MAX_BUFFER_SIZE_DEF = 2 * 1024; // 2GB private static final int MIN_BUFFER_SIZE_DEF = 256; // 256MB // Public messages @@ -192,8 +189,6 @@ public class TunerSessionWorker private final int mMaxTrickplayBufferSizeMb; private final File mTrickplayBufferDir; private final @TRICKPLAY_MODE int mTrickplayModeCustomization; - private final LegacyFlags mLegacyFlags; - private final MpegTsRendererBuilder.Factory mMpegTsRendererBuilderFactory; private volatile Surface mSurface; private volatile float mVolume = 1.0f; private volatile boolean mCaptionEnabled; @@ -236,44 +231,25 @@ public class TunerSessionWorker private boolean mIsActiveSession; private boolean mReleaseRequested; // Guarded by mReleaseLock private final Object mReleaseLock = new Object(); - private Uri mChannelUri; - private Uri mRecordingUri; - private boolean mOnTuneUsesRecording = false; + private final ConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags; private int mSignalStrength; private long mRecordedProgramStartTimeMs; - /** - * Factory for {@link TunerSessionWorker}. - * - * <p>This wrapper class keeps other classes from needing to reference the {@link AutoFactory} - * generated class. - */ - public interface Factory { - public TunerSessionWorker create( - Context context, - ChannelDataManager channelDataManager, - TunerSession tunerSession, - TunerSessionOverlay tunerSessionOverlay); - } - - @AutoFactory(implementing = Factory.class) public TunerSessionWorker( Context context, ChannelDataManager channelDataManager, TunerSession tunerSession, TunerSessionOverlay tunerSessionOverlay, - @Provided LegacyFlags legacyFlags, - @Provided MpegTsRendererBuilder.Factory mpegTsRendererBuilderFactory, - @Provided TsDataSourceManager.Factory tsDataSourceManagerFactory) { + ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags, + TsDataSourceManager.Factory tsDataSourceManagerFactory) { this( context, channelDataManager, tunerSession, tunerSessionOverlay, null, - legacyFlags, - mpegTsRendererBuilderFactory, + concurrentDvrPlaybackFlags, tsDataSourceManagerFactory); } @@ -284,10 +260,9 @@ public class TunerSessionWorker TunerSession tunerSession, TunerSessionOverlay tunerSessionOverlay, @Nullable Handler handler, - LegacyFlags legacyFlags, - MpegTsRendererBuilder.Factory mpegTsRendererBuilderFactory, + ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags, TsDataSourceManager.Factory tsDataSourceManagerFactory) { - mLegacyFlags = legacyFlags; + this.mConcurrentDvrPlaybackFlags = concurrentDvrPlaybackFlags; if (DEBUG) Log.d(TAG, "TunerSessionWorker created"); mContext = context; if (handler != null) { @@ -302,8 +277,6 @@ public class TunerSessionWorker mSession = tunerSession; mTunerSessionOverlay = tunerSessionOverlay; mChannelDataManager = channelDataManager; - mMpegTsRendererBuilderFactory = mpegTsRendererBuilderFactory; - mRecordingUri = null; mChannelDataManager.setListener(this); mChannelDataManager.checkDataVersion(mContext); mSourceManager = tsDataSourceManagerFactory.create(false); @@ -320,7 +293,8 @@ public class TunerSessionWorker (CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE); mCaptionEnabled = captioningManager.isEnabled(); mPlaybackParams.setSpeed(1.0f); - mMaxTrickplayBufferSizeMb = DeveloperPreferences.MAX_BUFFER_SIZE_MBYTES.get(context); + mMaxTrickplayBufferSizeMb = + SystemPropertiesProxy.getInt(MAX_BUFFER_SIZE_KEY, MAX_BUFFER_SIZE_DEF); mTrickplayModeCustomization = CustomizationManager.getTrickplayMode(context); if (mTrickplayModeCustomization == CustomizationManager.TRICKPLAY_MODE_USE_EXTERNAL_STORAGE) { @@ -513,11 +487,6 @@ public class TunerSessionWorker // Final status // notification of STATE_ENDED from MpegTsPlayer will be ignored afterwards. Log.i(TAG, "Player ended: end of stream"); - if (mOnTuneUsesRecording) { - mRecordingUri = null; - mSession.notifyChannelRetuned(mChannelUri); - sendMessage(MSG_TUNE, mChannelUri); - } if (mChannel != null) { sendMessage(MSG_RETRY_PLAYBACK, System.identityHashCode(mPlayer)); } @@ -546,10 +515,10 @@ public class TunerSessionWorker @Override public void onVideoSizeChanged(int width, int height, float pixelWidthHeight) { if (mChannel != null && mChannel.hasVideo()) { - updateVideoTrack(width, height, pixelWidthHeight); + updateVideoTrack(width, height); } if (mRecordingId != null) { - updateVideoTrack(width, height, pixelWidthHeight); + updateVideoTrack(width, height); } } @@ -563,9 +532,6 @@ public class TunerSessionWorker } else { mBufferStartTimeMs = mRecordStartTimeMs = System.currentTimeMillis(); } - if (mOnTuneUsesRecording) { - mBufferStartTimeMs = mRecordStartTimeMs = mRecordedProgramStartTimeMs; - } notifyVideoAvailable(); mReportedDrawnToSurface = true; @@ -621,7 +587,7 @@ public class TunerSessionWorker // ChannelDataManager.ProgramInfoListener @Override public void onProgramsArrived(TunerChannel channel, List<EitItem> programs) { - sendMessage(MSG_SCHEDULE_OF_PROGRAMS, Pair.create(channel, programs)); + sendMessage(MSG_SCHEDULE_OF_PROGRAMS, new Pair<>(channel, programs)); } @Override @@ -636,7 +602,7 @@ public class TunerSessionWorker @Override public void onRequestProgramsResponse(TunerChannel channel, List<EitItem> programs) { - sendMessage(MSG_PROGRAM_DATA_RESULT, Pair.create(channel, programs)); + sendMessage(MSG_PROGRAM_DATA_RESULT, new Pair<>(channel, programs)); } // PlaybackBufferListener @@ -684,7 +650,7 @@ public class TunerSessionWorker } private static class RecordedProgram { - private final long mChannelId; + // private final long mChannelId; private final String mDataUri; private final long mStartTimeMillis; @@ -696,13 +662,14 @@ public class TunerSessionWorker public RecordedProgram(Cursor cursor) { int index = 0; - mChannelId = cursor.getLong(index++); + // mChannelId = cursor.getLong(index++); + index++; mDataUri = cursor.getString(index++); mStartTimeMillis = cursor.getLong(index++); } public RecordedProgram(long channelId, String dataUri) { - mChannelId = channelId; + // mChannelId = channelId; mDataUri = dataUri; mStartTimeMillis = 0; } @@ -722,10 +689,6 @@ public class TunerSessionWorker public long getStartTime() { return mStartTimeMillis; } - - public long getChannelId() { - return mChannelId; - } } private RecordedProgram getRecordedProgram(Uri recordedUri) { @@ -748,13 +711,9 @@ public class TunerSessionWorker } } - private String parseRecording(Uri uri, long channelId) { + private String parseRecording(Uri uri) { RecordedProgram recording = getRecordedProgram(uri); if (recording != null) { - if (channelId != -1 && channelId != recording.getChannelId()) { - // Recorded URI is of some other channel - return null; - } mRecordedProgramStartTimeMs = recording.getStartTime(); return recording.getDataUri(); } @@ -867,20 +826,10 @@ public class TunerSessionWorker mIsActiveSession = true; } String recording = null; - mOnTuneUsesRecording = false; long channelId = parseChannel(channelUri); TunerChannel channel = (channelId == -1) ? null : mChannelDataManager.getChannel(channelId); - mRecordingUri = mSession.getRecordingUri(channelUri); if (channelId == -1) { - recording = parseRecording(channelUri, channelId); - - } else if (mRecordingUri != null) { - mChannelUri = channelUri; - recording = parseRecording(mRecordingUri, channelId); - if (recording != null) { - mOnTuneUsesRecording = true; - channel = null; - } + recording = parseRecording(channelUri); } if (channel == null && recording == null) { Log.w(TAG, "onTune() is failed. Can't find channel for " + channelUri); @@ -1184,15 +1133,8 @@ public class TunerSessionWorker if (mPlayer == null) { return true; } - long seekPosMs = timeMs; - if (mRecordingId != null) { - long systemBufferTime = System.currentTimeMillis() - SEEK_MARGIN_MS; - if (seekPosMs > systemBufferTime) { - seekPosMs = systemBufferTime; - } - } setTrickplayEnabledIfNeeded(); - doTimeShiftSeekTo(seekPosMs); + doTimeShiftSeekTo(timeMs); return true; } @@ -1490,7 +1432,8 @@ public class TunerSessionWorker } MpegTsPlayer player = new MpegTsPlayer( - mMpegTsRendererBuilderFactory.create(mContext, bufferManager, this), + new MpegTsRendererBuilder( + mContext, bufferManager, this, mConcurrentDvrPlaybackFlags), mHandler, mSourceManager, capabilities, @@ -1501,7 +1444,7 @@ public class TunerSessionWorker player.setVideoEventListener(this); player.setCaptionServiceNumber( mCaptionTrack != null - ? mCaptionTrack.getServiceNumber() + ? mCaptionTrack.serviceNumber : Cea708Data.EMPTY_SERVICE_NUMBER); return player; } @@ -1511,7 +1454,7 @@ public class TunerSessionWorker mTunerSessionOverlay.sendUiMessage( TunerSessionOverlay.MSG_UI_START_CAPTION_TRACK, mCaptionTrack); if (mPlayer != null) { - mPlayer.setCaptionServiceNumber(mCaptionTrack.getServiceNumber()); + mPlayer.setCaptionServiceNumber(mCaptionTrack.serviceNumber); } } } @@ -1568,13 +1511,12 @@ public class TunerSessionWorker } } - private void updateVideoTrack(int width, int height, float pixelWidthHeight) { + private void updateVideoTrack(int width, int height) { removeTvTracks(TvTrackInfo.TYPE_VIDEO); mTvTracks.add( new TvTrackInfo.Builder(TvTrackInfo.TYPE_VIDEO, VIDEO_TRACK_ID) .setVideoWidth(width) .setVideoHeight(height) - .setVideoPixelAspectRatio(pixelWidthHeight) .build()); mSession.notifyTracksChanged(mTvTracks); mSession.notifyTrackSelected(TvTrackInfo.TYPE_VIDEO, VIDEO_TRACK_ID); @@ -1588,7 +1530,7 @@ public class TunerSessionWorker if (audioTracks != null) { int index = 0; for (AtscAudioTrack audioTrack : audioTracks) { - audioTrack = audioTrack.toBuilder().setIndex(index).build(); + audioTrack.index = index; mAudioTrackMap.put(index, audioTrack); ++index; } @@ -1618,10 +1560,10 @@ public class TunerSessionWorker String language = !TextUtils.isEmpty(infoFromPlayer.language) ? infoFromPlayer.language - : (infoFromEit != null && infoFromEit.hasLanguage()) - ? infoFromEit.getLanguage() - : (infoFromVct != null && infoFromVct.hasLanguage()) - ? infoFromVct.getLanguage() + : (infoFromEit != null && infoFromEit.language != null) + ? infoFromEit.language + : (infoFromVct != null && infoFromVct.language != null) + ? infoFromVct.language : null; TvTrackInfo.Builder builder = new TvTrackInfo.Builder(TvTrackInfo.TYPE_AUDIO, AUDIO_TRACK_PREFIX + i); @@ -1642,20 +1584,20 @@ public class TunerSessionWorker mCaptionTrackMap.clear(); if (captionTracks != null) { for (AtscCaptionTrack captionTrack : captionTracks) { - if (mCaptionTrackMap.indexOfKey(captionTrack.getServiceNumber()) >= 0) { + if (mCaptionTrackMap.indexOfKey(captionTrack.serviceNumber) >= 0) { continue; } - String language = captionTrack.getLanguage(); + String language = captionTrack.language; // The service number of the caption service is used for track id of a subtitle. // Later, when a subtitle is chosen, track id will be passed on to TsParser. TvTrackInfo.Builder builder = new TvTrackInfo.Builder( TvTrackInfo.TYPE_SUBTITLE, - SUBTITLE_TRACK_PREFIX + captionTrack.getServiceNumber()); + SUBTITLE_TRACK_PREFIX + captionTrack.serviceNumber); builder.setLanguage(language); mTvTracks.add(builder.build()); - mCaptionTrackMap.put(captionTrack.getServiceNumber(), captionTrack); + mCaptionTrackMap.put(captionTrack.serviceNumber, captionTrack); } } mSession.notifyTracksChanged(mTvTracks); @@ -1835,9 +1777,6 @@ public class TunerSessionWorker } else { mBufferStartTimeMs = mRecordStartTimeMs = System.currentTimeMillis(); } - if (mOnTuneUsesRecording) { - mBufferStartTimeMs = mRecordStartTimeMs = mRecordedProgramStartTimeMs; - } mLastPositionMs = 0; mCaptionTrack = null; mSignalStrength = TvInputConstantCompat.SIGNAL_STRENGTH_UNKNOWN; @@ -1845,14 +1784,6 @@ public class TunerSessionWorker mSession.notifySignalStrength(mSignalStrength); } mHandler.sendEmptyMessage(MSG_PARENTAL_CONTROLS); - if (mOnTuneUsesRecording) { - mHandler.obtainMessage( - MSG_TIMESHIFT_SEEK_TO, - 1, - 0, - System.currentTimeMillis() - SEEK_MARGIN_MS) - .sendToTarget(); - } } private void doReschedulePrograms() { @@ -1874,7 +1805,7 @@ public class TunerSessionWorker + " current program: " + getCurrentProgram()); } - mHandler.obtainMessage(MSG_SCHEDULE_OF_PROGRAMS, Pair.create(mChannel, mPrograms)) + mHandler.obtainMessage(MSG_SCHEDULE_OF_PROGRAMS, new Pair<>(mChannel, mPrograms)) .sendToTarget(); } mHandler.removeMessages(MSG_RESCHEDULE_PROGRAMS); @@ -2035,12 +1966,10 @@ public class TunerSessionWorker private void doDiscoverCaptionServiceNumber(int serviceNumber) { int index = mCaptionTrackMap.indexOfKey(serviceNumber); if (index < 0) { - AtscCaptionTrack captionTrack = - AtscCaptionTrack.newBuilder() - .setServiceNumber(serviceNumber) - .setWideAspectRatio(false) - .setEasyReader(false) - .build(); + AtscCaptionTrack captionTrack = new AtscCaptionTrack(); + captionTrack.serviceNumber = serviceNumber; + captionTrack.wideAspectRatio = false; + captionTrack.easyReader = false; mCaptionTrackMap.put(serviceNumber, captionTrack); mTvTracks.add( new TvTrackInfo.Builder( @@ -2059,7 +1988,7 @@ public class TunerSessionWorker ImmutableList<TvContentRating> ratings = mTvContentRatingCache.getRatings(currentProgram.getContentRating()); if ((ratings == null || ratings.isEmpty())) { - if (mLegacyFlags.enableUnratedContentSettings()) { + if (Experiments.ENABLE_UNRATED_CONTENT_SETTINGS.get()) { ratings = ImmutableList.of(TvContentRating.UNRATED); } else { ratings = NO_CONTENT_RATINGS; diff --git a/tuner/src/com/android/tv/tuner/tvinput/TunerSessionWorkerExoV2.java b/tuner/src/com/android/tv/tuner/tvinput/TunerSessionWorkerExoV2.java index f56e4879..82afff15 100644 --- a/tuner/src/com/android/tv/tuner/tvinput/TunerSessionWorkerExoV2.java +++ b/tuner/src/com/android/tv/tuner/tvinput/TunerSessionWorkerExoV2.java @@ -44,22 +44,22 @@ import android.util.Pair; import android.util.SparseArray; import android.view.Surface; import android.view.accessibility.CaptioningManager; - import com.android.tv.common.CommonPreferences.TrickplaySetting; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.TvContentRatingCache; import com.android.tv.common.compat.TvInputConstantCompat; import com.android.tv.common.customization.CustomizationManager; import com.android.tv.common.customization.CustomizationManager.TRICKPLAY_MODE; -import com.android.tv.common.dev.DeveloperPreferences; +import com.android.tv.common.experiments.Experiments; import com.android.tv.common.feature.CommonFeatures; +import com.android.tv.common.util.SystemPropertiesProxy; import com.android.tv.tuner.data.Cea708Data; -import com.android.tv.tuner.data.Channel; import com.android.tv.tuner.data.PsipData.EitItem; import com.android.tv.tuner.data.PsipData.TvTracksInterface; -import com.android.tv.tuner.data.Track.AtscAudioTrack; -import com.android.tv.tuner.data.Track.AtscCaptionTrack; import com.android.tv.tuner.data.TunerChannel; +import com.android.tv.tuner.data.nano.Channel; +import com.android.tv.tuner.data.nano.Track.AtscAudioTrack; +import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack; import com.android.tv.tuner.exoplayer.MpegTsPlayer; import com.android.tv.tuner.exoplayer.MpegTsRendererBuilder; import com.android.tv.tuner.exoplayer.buffer.BufferManager; @@ -74,15 +74,10 @@ import com.android.tv.tuner.ts.EventDetector.EventListener; import com.android.tv.tuner.tvinput.datamanager.ChannelDataManager; import com.android.tv.tuner.tvinput.debug.TunerDebug; import com.android.tv.tuner.util.StatusTextUtils; - import com.google.android.exoplayer.ExoPlayer; import com.google.android.exoplayer.audio.AudioCapabilities; -import com.google.auto.factory.AutoFactory; -import com.google.auto.factory.Provided; import com.google.common.collect.ImmutableList; - -import com.android.tv.common.flags.LegacyFlags; - +import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags; import java.io.File; import java.util.ArrayList; import java.util.Iterator; @@ -105,6 +100,8 @@ public class TunerSessionWorkerExoV2 private static final boolean DEBUG = false; private static final boolean ENABLE_PROFILER = true; private static final String PLAY_FROM_CHANNEL = "channel"; + private static final String MAX_BUFFER_SIZE_KEY = "tv.tuner.buffersize_mbytes"; + private static final int MAX_BUFFER_SIZE_DEF = 2 * 1024; // 2GB private static final int MIN_BUFFER_SIZE_DEF = 256; // 256MB // Public messages @@ -191,7 +188,6 @@ public class TunerSessionWorkerExoV2 private final int mMaxTrickplayBufferSizeMb; private final File mTrickplayBufferDir; private final @TRICKPLAY_MODE int mTrickplayModeCustomization; - private final MpegTsRendererBuilder.Factory mMpegTsRendererBuilderFactory; private volatile Surface mSurface; private volatile float mVolume = 1.0f; private volatile boolean mCaptionEnabled; @@ -234,45 +230,25 @@ public class TunerSessionWorkerExoV2 private boolean mIsActiveSession; private boolean mReleaseRequested; // Guarded by mReleaseLock private final Object mReleaseLock = new Object(); - private final LegacyFlags mLegacyFlags; - private Uri mChannelUri; - private Uri mRecordingUri; - private boolean mOnTuneUsesRecording = false; + private final ConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags; private int mSignalStrength; private long mRecordedProgramStartTimeMs; - /** - * Factory for {@link TunerSessionWorkerExoV2}. - * - * <p>This wrapper class keeps other classes from needing to reference the {@link AutoFactory} - * generated class. - */ - public interface Factory { - public TunerSessionWorkerExoV2 create( - Context context, - ChannelDataManager channelDataManager, - TunerSessionExoV2 tunerSession, - TunerSessionOverlay tunerSessionOverlay); - } - - @AutoFactory(implementing = Factory.class) public TunerSessionWorkerExoV2( Context context, ChannelDataManager channelDataManager, TunerSessionExoV2 tunerSession, TunerSessionOverlay tunerSessionOverlay, - @Provided LegacyFlags legacyFlags, - @Provided MpegTsRendererBuilder.Factory mpegTsRendererBuilderFactory, - @Provided TsDataSourceManager.Factory tsDataSourceManagerFactory) { + ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags, + TsDataSourceManager.Factory tsDataSourceManagerFactory) { this( context, channelDataManager, tunerSession, tunerSessionOverlay, null, - legacyFlags, - mpegTsRendererBuilderFactory, + concurrentDvrPlaybackFlags, tsDataSourceManagerFactory); } @@ -283,10 +259,9 @@ public class TunerSessionWorkerExoV2 TunerSessionExoV2 tunerSession, TunerSessionOverlay tunerSessionOverlay, @Nullable Handler handler, - LegacyFlags legacyFlags, - MpegTsRendererBuilder.Factory mpegTsRendererBuilderFactory, + ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags, TsDataSourceManager.Factory tsDataSourceManagerFactory) { - mLegacyFlags = legacyFlags; + mConcurrentDvrPlaybackFlags = concurrentDvrPlaybackFlags; if (DEBUG) { Log.d(TAG, "TunerSessionWorkerExoV2 created"); } @@ -303,8 +278,6 @@ public class TunerSessionWorkerExoV2 mSession = tunerSession; mTunerSessionOverlay = tunerSessionOverlay; mChannelDataManager = channelDataManager; - mMpegTsRendererBuilderFactory = mpegTsRendererBuilderFactory; - mRecordingUri = null; mChannelDataManager.setListener(this); mChannelDataManager.checkDataVersion(mContext); mSourceManager = tsDataSourceManagerFactory.create(false); @@ -321,7 +294,8 @@ public class TunerSessionWorkerExoV2 (CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE); mCaptionEnabled = captioningManager.isEnabled(); mPlaybackParams.setSpeed(1.0f); - mMaxTrickplayBufferSizeMb = DeveloperPreferences.MAX_BUFFER_SIZE_MBYTES.get(context); + mMaxTrickplayBufferSizeMb = + SystemPropertiesProxy.getInt(MAX_BUFFER_SIZE_KEY, MAX_BUFFER_SIZE_DEF); mTrickplayModeCustomization = CustomizationManager.getTrickplayMode(context); if (mTrickplayModeCustomization == CustomizationManager.TRICKPLAY_MODE_USE_EXTERNAL_STORAGE) { @@ -519,11 +493,6 @@ public class TunerSessionWorkerExoV2 // Final status // notification of STATE_ENDED from MpegTsPlayer will be ignored afterwards. Log.i(TAG, "Player ended: end of stream"); - if (mOnTuneUsesRecording) { - mRecordingUri = null; - mSession.notifyChannelRetuned(mChannelUri); - sendMessage(MSG_TUNE, mChannelUri); - } if (mChannel != null) { sendMessage(MSG_RETRY_PLAYBACK, System.identityHashCode(mPlayer)); } @@ -552,10 +521,10 @@ public class TunerSessionWorkerExoV2 @Override public void onVideoSizeChanged(int width, int height, float pixelWidthHeight) { if (mChannel != null && mChannel.hasVideo()) { - updateVideoTrack(width, height, pixelWidthHeight); + updateVideoTrack(width, height); } if (mRecordingId != null) { - updateVideoTrack(width, height, pixelWidthHeight); + updateVideoTrack(width, height); } } @@ -571,9 +540,6 @@ public class TunerSessionWorkerExoV2 } else { mBufferStartTimeMs = mRecordStartTimeMs = System.currentTimeMillis(); } - if (mOnTuneUsesRecording) { - mBufferStartTimeMs = mRecordStartTimeMs = mRecordedProgramStartTimeMs; - } notifyVideoAvailable(); mReportedDrawnToSurface = true; @@ -629,7 +595,7 @@ public class TunerSessionWorkerExoV2 // ChannelDataManager.ProgramInfoListener @Override public void onProgramsArrived(TunerChannel channel, List<EitItem> programs) { - sendMessage(MSG_SCHEDULE_OF_PROGRAMS, Pair.create(channel, programs)); + sendMessage(MSG_SCHEDULE_OF_PROGRAMS, new Pair<>(channel, programs)); } @Override @@ -644,7 +610,7 @@ public class TunerSessionWorkerExoV2 @Override public void onRequestProgramsResponse(TunerChannel channel, List<EitItem> programs) { - sendMessage(MSG_PROGRAM_DATA_RESULT, Pair.create(channel, programs)); + sendMessage(MSG_PROGRAM_DATA_RESULT, new Pair<>(channel, programs)); } // PlaybackBufferListener @@ -692,7 +658,7 @@ public class TunerSessionWorkerExoV2 } private static class RecordedProgram { - private final long mChannelId; + // private final long mChannelId; private final String mDataUri; private final long mStartTimeMillis; @@ -704,13 +670,14 @@ public class TunerSessionWorkerExoV2 public RecordedProgram(Cursor cursor) { int index = 0; - mChannelId = cursor.getLong(index++); + // mChannelId = cursor.getLong(index++); + index++; mDataUri = cursor.getString(index++); mStartTimeMillis = cursor.getLong(index++); } public RecordedProgram(long channelId, String dataUri) { - mChannelId = channelId; + // mChannelId = channelId; mDataUri = dataUri; mStartTimeMillis = 0; } @@ -730,10 +697,6 @@ public class TunerSessionWorkerExoV2 public long getStartTime() { return mStartTimeMillis; } - - public long getChannelId() { - return mChannelId; - } } private RecordedProgram getRecordedProgram(Uri recordedUri) { @@ -758,13 +721,9 @@ public class TunerSessionWorkerExoV2 } } - private String parseRecording(Uri uri, long channelId) { + private String parseRecording(Uri uri) { RecordedProgram recording = getRecordedProgram(uri); if (recording != null) { - if (channelId != -1 && channelId != recording.getChannelId()) { - // Recorded URI is of some other channel - return null; - } mRecordedProgramStartTimeMs = recording.getStartTime(); return recording.getDataUri(); } @@ -877,19 +836,10 @@ public class TunerSessionWorkerExoV2 mIsActiveSession = true; } String recording = null; - mOnTuneUsesRecording = false; long channelId = parseChannel(channelUri); TunerChannel channel = (channelId == -1) ? null : mChannelDataManager.getChannel(channelId); - mRecordingUri = mSession.getRecordingUri(channelUri); if (channelId == -1) { - recording = parseRecording(channelUri, channelId); - } else if (mRecordingUri != null) { - mChannelUri = channelUri; - recording = parseRecording(mRecordingUri, channelId); - if (recording != null) { - mOnTuneUsesRecording = true; - channel = null; - } + recording = parseRecording(channelUri); } if (channel == null && recording == null) { Log.w(TAG, "onTune() is failed. Can't find channel for " + channelUri); @@ -1492,7 +1442,8 @@ public class TunerSessionWorkerExoV2 } MpegTsPlayer player = new MpegTsPlayer( - mMpegTsRendererBuilderFactory.create(mContext, bufferManager, this), + new MpegTsRendererBuilder( + mContext, bufferManager, this, mConcurrentDvrPlaybackFlags), mHandler, mSourceManager, capabilities, @@ -1505,7 +1456,7 @@ public class TunerSessionWorkerExoV2 player.setVideoEventListener(this); player.setCaptionServiceNumber( mCaptionTrack != null - ? mCaptionTrack.getServiceNumber() + ? mCaptionTrack.serviceNumber : Cea708Data.EMPTY_SERVICE_NUMBER); return player; } @@ -1515,7 +1466,7 @@ public class TunerSessionWorkerExoV2 mTunerSessionOverlay.sendUiMessage( TunerSessionOverlay.MSG_UI_START_CAPTION_TRACK, mCaptionTrack); if (mPlayer != null) { - mPlayer.setCaptionServiceNumber(mCaptionTrack.getServiceNumber()); + mPlayer.setCaptionServiceNumber(mCaptionTrack.serviceNumber); } } } @@ -1572,13 +1523,12 @@ public class TunerSessionWorkerExoV2 } } - private void updateVideoTrack(int width, int height, float pixelWidthHeight) { + private void updateVideoTrack(int width, int height) { removeTvTracks(TvTrackInfo.TYPE_VIDEO); mTvTracks.add( new TvTrackInfo.Builder(TvTrackInfo.TYPE_VIDEO, VIDEO_TRACK_ID) .setVideoWidth(width) .setVideoHeight(height) - .setVideoPixelAspectRatio(pixelWidthHeight) .build()); mSession.notifyTracksChanged(mTvTracks); mSession.notifyTrackSelected(TvTrackInfo.TYPE_VIDEO, VIDEO_TRACK_ID); @@ -1592,7 +1542,7 @@ public class TunerSessionWorkerExoV2 if (audioTracks != null) { int index = 0; for (AtscAudioTrack audioTrack : audioTracks) { - audioTrack = audioTrack.toBuilder().setIndex(index).build(); + audioTrack.index = index; mAudioTrackMap.put(index, audioTrack); ++index; } @@ -1622,10 +1572,10 @@ public class TunerSessionWorkerExoV2 String language = !TextUtils.isEmpty(infoFromPlayer.language) ? infoFromPlayer.language - : (infoFromEit != null && infoFromEit.hasLanguage()) - ? infoFromEit.getLanguage() - : (infoFromVct != null && infoFromVct.hasLanguage()) - ? infoFromVct.getLanguage() + : (infoFromEit != null && infoFromEit.language != null) + ? infoFromEit.language + : (infoFromVct != null && infoFromVct.language != null) + ? infoFromVct.language : null; TvTrackInfo.Builder builder = new TvTrackInfo.Builder(TvTrackInfo.TYPE_AUDIO, AUDIO_TRACK_PREFIX + i); @@ -1646,20 +1596,20 @@ public class TunerSessionWorkerExoV2 mCaptionTrackMap.clear(); if (captionTracks != null) { for (AtscCaptionTrack captionTrack : captionTracks) { - if (mCaptionTrackMap.indexOfKey(captionTrack.getServiceNumber()) >= 0) { + if (mCaptionTrackMap.indexOfKey(captionTrack.serviceNumber) >= 0) { continue; } - String language = captionTrack.getLanguage(); + String language = captionTrack.language; // The service number of the caption service is used for track id of a subtitle. // Later, when a subtitle is chosen, track id will be passed on to TsParser. TvTrackInfo.Builder builder = new TvTrackInfo.Builder( TvTrackInfo.TYPE_SUBTITLE, - SUBTITLE_TRACK_PREFIX + captionTrack.getServiceNumber()); + SUBTITLE_TRACK_PREFIX + captionTrack.serviceNumber); builder.setLanguage(language); mTvTracks.add(builder.build()); - mCaptionTrackMap.put(captionTrack.getServiceNumber(), captionTrack); + mCaptionTrackMap.put(captionTrack.serviceNumber, captionTrack); } } mSession.notifyTracksChanged(mTvTracks); @@ -1841,9 +1791,6 @@ public class TunerSessionWorkerExoV2 } else { mBufferStartTimeMs = mRecordStartTimeMs = System.currentTimeMillis(); } - if (mOnTuneUsesRecording) { - mBufferStartTimeMs = mRecordStartTimeMs = mRecordedProgramStartTimeMs; - } mLastPositionMs = 0; mCaptionTrack = null; mSignalStrength = TvInputConstantCompat.SIGNAL_STRENGTH_UNKNOWN; @@ -1851,14 +1798,6 @@ public class TunerSessionWorkerExoV2 mSession.notifySignalStrength(mSignalStrength); } mHandler.sendEmptyMessage(MSG_PARENTAL_CONTROLS); - if (mOnTuneUsesRecording) { - mHandler.obtainMessage( - MSG_TIMESHIFT_SEEK_TO, - 1, - 0, - System.currentTimeMillis() - SEEK_MARGIN_MS) - .sendToTarget(); - } } private void doReschedulePrograms() { @@ -1880,7 +1819,7 @@ public class TunerSessionWorkerExoV2 + " current program: " + getCurrentProgram()); } - mHandler.obtainMessage(MSG_SCHEDULE_OF_PROGRAMS, Pair.create(mChannel, mPrograms)) + mHandler.obtainMessage(MSG_SCHEDULE_OF_PROGRAMS, new Pair<>(mChannel, mPrograms)) .sendToTarget(); } mHandler.removeMessages(MSG_RESCHEDULE_PROGRAMS); @@ -2041,13 +1980,10 @@ public class TunerSessionWorkerExoV2 private void doDiscoverCaptionServiceNumber(int serviceNumber) { int index = mCaptionTrackMap.indexOfKey(serviceNumber); if (index < 0) { - AtscCaptionTrack.Builder captionTrackBuilder = AtscCaptionTrack.newBuilder(); - AtscCaptionTrack captionTrack = - captionTrackBuilder - .setServiceNumber(serviceNumber) - .setWideAspectRatio(false) - .setEasyReader(false) - .build(); + AtscCaptionTrack captionTrack = new AtscCaptionTrack(); + captionTrack.serviceNumber = serviceNumber; + captionTrack.wideAspectRatio = false; + captionTrack.easyReader = false; mCaptionTrackMap.put(serviceNumber, captionTrack); mTvTracks.add( new TvTrackInfo.Builder( @@ -2066,7 +2002,7 @@ public class TunerSessionWorkerExoV2 ImmutableList<TvContentRating> ratings = mTvContentRatingCache.getRatings(currentProgram.getContentRating()); if ((ratings == null || ratings.isEmpty())) { - if (mLegacyFlags.enableUnratedContentSettings()) { + if (Experiments.ENABLE_UNRATED_CONTENT_SETTINGS.get()) { ratings = ImmutableList.of(TvContentRating.UNRATED); } else { ratings = NO_CONTENT_RATINGS; diff --git a/tuner/src/com/android/tv/tuner/tvinput/datamanager/ChannelDataManager.java b/tuner/src/com/android/tv/tuner/tvinput/datamanager/ChannelDataManager.java index 447618a4..585b28bc 100644 --- a/tuner/src/com/android/tv/tuner/tvinput/datamanager/ChannelDataManager.java +++ b/tuner/src/com/android/tv/tuner/tvinput/datamanager/ChannelDataManager.java @@ -29,10 +29,11 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.os.RemoteException; -import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.format.DateUtils; import android.util.Log; +import com.android.tv.common.singletons.HasSingletons; +import com.android.tv.common.singletons.HasTvInputId; import com.android.tv.common.util.PermissionUtils; import com.android.tv.tuner.data.PsipData.EitItem; import com.android.tv.tuner.data.TunerChannel; @@ -50,7 +51,7 @@ import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -/** Manages the channel info and EPG data for a specific inputId. */ +/** Manages the channel info and EPG data through {@link TvInputManager}. */ public class ChannelDataManager implements Handler.Callback { private static final String TAG = "ChannelDataManager"; @@ -145,9 +146,9 @@ public class ChannelDataManager implements Handler.Callback { void onChannelHandlingDone(); } - public ChannelDataManager(Context context, String inputId) { + public ChannelDataManager(Context context) { mContext = context; - mInputId = inputId; + mInputId = HasSingletons.get(HasTvInputId.class, context).getEmbeddedTunerInputId(); mChannelsUri = TvContract.buildChannelsUriForInput(mInputId); mTunerChannelMap = new ConcurrentHashMap<>(); mTunerChannelIdMap = new ConcurrentSkipListMap<>(); @@ -381,12 +382,6 @@ public class ChannelDataManager implements Handler.Callback { return false; } - @NonNull - @Override - public String toString() { - return "ChannelDataManager[" + mInputId + "]"; - } - // Private methods private void handleEvents(TunerChannel channel, List<EitItem> items) { long channelId = getChannelId(channel); diff --git a/tuner/src/com/android/tv/tuner/tvinput/factory/TunerRecordingSessionFactory.java b/tuner/src/com/android/tv/tuner/tvinput/factory/TunerRecordingSessionFactory.java deleted file mode 100644 index c5950756..00000000 --- a/tuner/src/com/android/tv/tuner/tvinput/factory/TunerRecordingSessionFactory.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2019 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.tuner.tvinput.factory; - -import android.media.tv.TvInputService.RecordingSession; - -import com.android.tv.tuner.tvinput.datamanager.ChannelDataManager; - -/** {@link RecordingSession} factory */ -public interface TunerRecordingSessionFactory { - - /** Called when a recording session is released */ - interface RecordingSessionReleasedCallback { - - /** - * Called when the given recording session is released. - * - * @param session The recording session that has been released. - */ - void onReleased(RecordingSession session); - } - - RecordingSession create( - String inputId, - RecordingSessionReleasedCallback releasedCallback, - ChannelDataManager channelDataManager); -} diff --git a/tuner/src/com/android/tv/tuner/tvinput/factory/TunerSessionFactory.java b/tuner/src/com/android/tv/tuner/tvinput/factory/TunerSessionFactory.java index e22562ac..a27cb22a 100644 --- a/tuner/src/com/android/tv/tuner/tvinput/factory/TunerSessionFactory.java +++ b/tuner/src/com/android/tv/tuner/tvinput/factory/TunerSessionFactory.java @@ -1,24 +1,7 @@ -/* - * Copyright (C) 2019 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.tuner.tvinput.factory; +import android.content.Context; import android.media.tv.TvInputService.Session; -import android.net.Uri; - import com.android.tv.tuner.tvinput.datamanager.ChannelDataManager; /** {@link android.media.tv.TvInputService.Session} factory */ @@ -35,19 +18,8 @@ public interface TunerSessionFactory { void onReleased(Session session); } - /** Called when recording URI is required for playback */ - interface SessionRecordingCallback { - - /** - * Called when recording URI is required for playback. - * - * @param channelUri for which recording URI is requested. - */ - Uri getRecordingUri(Uri channelUri); - } - Session create( + Context context, ChannelDataManager channelDataManager, - SessionReleasedCallback releasedCallback, - SessionRecordingCallback recordingCallback); + SessionReleasedCallback releasedCallback); } diff --git a/tuner/src/com/android/tv/tuner/tvinput/factory/TunerSessionFactoryImpl.java b/tuner/src/com/android/tv/tuner/tvinput/factory/TunerSessionFactoryImpl.java new file mode 100644 index 00000000..54e959e6 --- /dev/null +++ b/tuner/src/com/android/tv/tuner/tvinput/factory/TunerSessionFactoryImpl.java @@ -0,0 +1,49 @@ +package com.android.tv.tuner.tvinput.factory; + +import android.content.Context; +import android.media.tv.TvInputService.Session; +import com.android.tv.tuner.source.TsDataSourceManager; +import com.android.tv.tuner.tvinput.TunerSession; +import com.android.tv.tuner.tvinput.TunerSessionExoV2; +import com.android.tv.tuner.tvinput.datamanager.ChannelDataManager; +import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags; +import com.android.tv.common.flags.TunerFlags; +import javax.inject.Inject; + +/** Creates a {@link TunerSessionFactory}. */ +public class TunerSessionFactoryImpl implements TunerSessionFactory { + + private final TunerFlags mTunerFlags; + private final ConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags; + private final TsDataSourceManager.Factory mTsDataSourceManagerFactory; + + @Inject + public TunerSessionFactoryImpl( + TunerFlags tunerFlags, + ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags, + TsDataSourceManager.Factory tsDataSourceManagerFactory) { + mTunerFlags = tunerFlags; + mConcurrentDvrPlaybackFlags = concurrentDvrPlaybackFlags; + mTsDataSourceManagerFactory = tsDataSourceManagerFactory; + } + + @Override + public Session create( + Context context, + ChannelDataManager channelDataManager, + SessionReleasedCallback releasedCallback) { + return mTunerFlags.useExoplayerV2() + ? new TunerSessionExoV2( + context, + channelDataManager, + releasedCallback, + mConcurrentDvrPlaybackFlags, + mTsDataSourceManagerFactory) + : new TunerSession( + context, + channelDataManager, + releasedCallback, + mConcurrentDvrPlaybackFlags, + mTsDataSourceManagerFactory); + } +} diff --git a/tuner/tests/robotests/Android.mk b/tuner/tests/robotests/Android.mk deleted file mode 100644 index 16af9e9c..00000000 --- a/tuner/tests/robotests/Android.mk +++ /dev/null @@ -1,68 +0,0 @@ -############################################################# -# Tv Robolectric test target. # -############################################################# -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_MODULE := TvTunerRoboTests -LOCAL_MODULE_CLASS := JAVA_LIBRARIES - -LOCAL_SRC_FILES := $(call all-java-files-under, javatests) - -LOCAL_JAVA_LIBRARIES := \ - Robolectric_all-target \ - mockito-robolectric-prebuilt \ - robolectric_android-all-stub \ - -LOCAL_STATIC_JAVA_LIBRARIES := \ - tv-lib-dagger - -LOCAL_STATIC_ANDROID_LIBRARIES := \ - androidx.test.core \ - tv-lib-dagger-android \ - tv-test-common \ - tv-test-common-robo \ - tv-tuner-testing \ - -LOCAL_ANNOTATION_PROCESSORS := \ - tv-lib-dagger-android-processor \ - tv-lib-dagger-compiler \ - -LOCAL_ANNOTATION_PROCESSOR_CLASSES := \ - dagger.internal.codegen.ComponentProcessor,dagger.android.processor.AndroidProcessor - -LOCAL_INSTRUMENTATION_FOR := LiveTv - -LOCAL_MODULE_TAGS := optional - -include $(BUILD_STATIC_JAVA_LIBRARY) - -############################################################# -# Tv runner target to run the previous target. # -############################################################# -include $(CLEAR_VARS) -LOCAL_MODULE := RunTvTunerRoboTests - -BASE_DIR = com/android/tv/tuner -EXCLUDE_FILES := \ - $(BASE_DIR)/dvb/DvbTunerHalTest.java \ - $(BASE_DIR)/exoplayer/tests/SampleSourceExtractorTest.java \ - -LOCAL_ROBOTEST_FILES := $(call find-files-in-subdirs,$(LOCAL_PATH)/javatests,*Test.java,.) -LOCAL_ROBOTEST_FILES := $(filter-out $(EXCLUDE_FILES),$(LOCAL_ROBOTEST_FILES)) - -LOCAL_JAVA_LIBRARIES := \ - Robolectric_all-target \ - TvTunerRoboTests \ - mockito-robolectric-prebuilt \ - robolectric_android-all-stub \ - tv-lib-truth \ - tv-test-common \ - tv-test-common-robo \ - tv-tuner-testing \ - -LOCAL_TEST_PACKAGE := LiveTv - -LOCAL_ROBOTEST_TIMEOUT := 36000 - -include external/robolectric-shadows/run_robotests.mk diff --git a/tuner/tests/robotests/javatests/com/android/tv/tuner/data/SectionParserTest.java b/tuner/tests/robotests/javatests/com/android/tv/tuner/data/SectionParserTest.java deleted file mode 100644 index e40abdc4..00000000 --- a/tuner/tests/robotests/javatests/com/android/tv/tuner/data/SectionParserTest.java +++ /dev/null @@ -1,181 +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.tuner.data; - -import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth.assertWithMessage; - -import com.android.tv.testing.constants.ConfigConstants; -import com.android.tv.tuner.data.PsipData.ContentAdvisoryDescriptor; -import com.android.tv.tuner.data.PsipData.RatingRegion; -import com.android.tv.tuner.data.PsipData.RegionalRating; -import com.android.tv.tuner.data.PsipData.TsDescriptor; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** Tests for {@link com.android.tv.tuner.data.SectionParser}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class SectionParserTest { - private static final Map<String, String> US_RATING_MAP = new HashMap<>(); - private static final int RATING_REGION_US = 1; - - static { - // These mappings are from table 3 of ANSI-CEA-766-D - US_RATING_MAP.put("1 0 0 0 0 0 0 X", ""); // TV-None - US_RATING_MAP.put("0 0 0 0 0 1 0 X", "com.android.tv/US_TV/US_TV_Y"); - US_RATING_MAP.put("0 0 0 0 0 2 0 X", "com.android.tv/US_TV/US_TV_Y7"); - US_RATING_MAP.put("0 0 0 0 0 2 1 X", "com.android.tv/US_TV/US_TV_Y7/US_TV_FV"); - US_RATING_MAP.put("2 0 0 0 0 0 0 X", "com.android.tv/US_TV/US_TV_G"); - US_RATING_MAP.put("3 0 0 0 0 0 0 X", "com.android.tv/US_TV/US_TV_PG"); - US_RATING_MAP.put("3 1 0 0 0 0 0 X", "com.android.tv/US_TV/US_TV_PG/US_TV_D"); - US_RATING_MAP.put("3 0 1 0 0 0 0 X", "com.android.tv/US_TV/US_TV_PG/US_TV_L"); - US_RATING_MAP.put("3 0 0 1 0 0 0 X", "com.android.tv/US_TV/US_TV_PG/US_TV_S"); - US_RATING_MAP.put("3 0 0 0 1 0 0 X", "com.android.tv/US_TV/US_TV_PG/US_TV_V"); - US_RATING_MAP.put("3 1 1 0 0 0 0 X", "com.android.tv/US_TV/US_TV_PG/US_TV_D/US_TV_L"); - US_RATING_MAP.put("3 1 0 1 0 0 0 X", "com.android.tv/US_TV/US_TV_PG/US_TV_D/US_TV_S"); - US_RATING_MAP.put("3 1 0 0 1 0 0 X", "com.android.tv/US_TV/US_TV_PG/US_TV_D/US_TV_V"); - US_RATING_MAP.put("3 0 1 1 0 0 0 X", "com.android.tv/US_TV/US_TV_PG/US_TV_L/US_TV_S"); - US_RATING_MAP.put("3 0 1 0 1 0 0 X", "com.android.tv/US_TV/US_TV_PG/US_TV_L/US_TV_V"); - US_RATING_MAP.put("3 0 0 1 1 0 0 X", "com.android.tv/US_TV/US_TV_PG/US_TV_S/US_TV_V"); - US_RATING_MAP.put( - "3 1 1 1 0 0 0 X", "com.android.tv/US_TV/US_TV_PG/US_TV_D/US_TV_L/US_TV_S"); - US_RATING_MAP.put( - "3 1 1 0 1 0 0 X", "com.android.tv/US_TV/US_TV_PG/US_TV_D/US_TV_L/US_TV_V"); - US_RATING_MAP.put( - "3 1 0 1 1 0 0 X", "com.android.tv/US_TV/US_TV_PG/US_TV_D/US_TV_S/US_TV_V"); - US_RATING_MAP.put( - "3 0 1 1 1 0 0 X", "com.android.tv/US_TV/US_TV_PG/US_TV_L/US_TV_S/US_TV_V"); - US_RATING_MAP.put( - "3 1 1 1 1 0 0 X", "com.android.tv/US_TV/US_TV_PG/US_TV_D/US_TV_L/US_TV_S/US_TV_V"); - US_RATING_MAP.put("4 0 0 0 0 0 0 X", "com.android.tv/US_TV/US_TV_14"); - US_RATING_MAP.put("4 1 0 0 0 0 0 X", "com.android.tv/US_TV/US_TV_14/US_TV_D"); - US_RATING_MAP.put("4 0 1 0 0 0 0 X", "com.android.tv/US_TV/US_TV_14/US_TV_L"); - US_RATING_MAP.put("4 0 0 1 0 0 0 X", "com.android.tv/US_TV/US_TV_14/US_TV_S"); - US_RATING_MAP.put("4 0 0 0 1 0 0 X", "com.android.tv/US_TV/US_TV_14/US_TV_V"); - US_RATING_MAP.put("4 1 1 0 0 0 0 X", "com.android.tv/US_TV/US_TV_14/US_TV_D/US_TV_L"); - US_RATING_MAP.put("4 1 0 1 0 0 0 X", "com.android.tv/US_TV/US_TV_14/US_TV_D/US_TV_S"); - US_RATING_MAP.put("4 1 0 0 1 0 0 X", "com.android.tv/US_TV/US_TV_14/US_TV_D/US_TV_V"); - US_RATING_MAP.put("4 0 1 1 0 0 0 X", "com.android.tv/US_TV/US_TV_14/US_TV_L/US_TV_S"); - US_RATING_MAP.put("4 0 1 0 1 0 0 X", "com.android.tv/US_TV/US_TV_14/US_TV_L/US_TV_V"); - US_RATING_MAP.put("4 0 0 1 1 0 0 X", "com.android.tv/US_TV/US_TV_14/US_TV_S/US_TV_V"); - US_RATING_MAP.put( - "4 1 1 1 0 0 0 X", "com.android.tv/US_TV/US_TV_14/US_TV_D/US_TV_L/US_TV_S"); - US_RATING_MAP.put( - "4 1 1 0 1 0 0 X", "com.android.tv/US_TV/US_TV_14/US_TV_D/US_TV_L/US_TV_V"); - US_RATING_MAP.put( - "4 1 0 1 1 0 0 X", "com.android.tv/US_TV/US_TV_14/US_TV_D/US_TV_S/US_TV_V"); - US_RATING_MAP.put( - "4 0 1 1 1 0 0 X", "com.android.tv/US_TV/US_TV_14/US_TV_L/US_TV_S/US_TV_V"); - US_RATING_MAP.put( - "4 1 1 1 1 0 0 X", "com.android.tv/US_TV/US_TV_14/US_TV_D/US_TV_L/US_TV_S/US_TV_V"); - US_RATING_MAP.put("5 0 0 0 0 0 0 X", "com.android.tv/US_TV/US_TV_MA"); - US_RATING_MAP.put("5 0 1 0 0 0 0 X", "com.android.tv/US_TV/US_TV_MA/US_TV_L"); - US_RATING_MAP.put("5 0 0 1 0 0 0 X", "com.android.tv/US_TV/US_TV_MA/US_TV_S"); - US_RATING_MAP.put("5 0 0 0 1 0 0 X", "com.android.tv/US_TV/US_TV_MA/US_TV_V"); - US_RATING_MAP.put("5 0 1 1 0 0 0 X", "com.android.tv/US_TV/US_TV_MA/US_TV_L/US_TV_S"); - US_RATING_MAP.put("5 0 1 0 1 0 0 X", "com.android.tv/US_TV/US_TV_MA/US_TV_L/US_TV_V"); - US_RATING_MAP.put("5 0 0 1 1 0 0 X", "com.android.tv/US_TV/US_TV_MA/US_TV_S/US_TV_V"); - US_RATING_MAP.put( - "5 0 1 1 1 0 0 X", "com.android.tv/US_TV/US_TV_MA/US_TV_L/US_TV_S/US_TV_V"); - US_RATING_MAP.put("X X X X X X X 1", ""); // MPAA-N/A - US_RATING_MAP.put("X X X X X X X 2", "com.android.tv/US_MV/US_MV_G"); - US_RATING_MAP.put("X X X X X X X 3", "com.android.tv/US_MV/US_MV_PG"); - US_RATING_MAP.put("X X X X X X X 4", "com.android.tv/US_MV/US_MV_PG13"); - US_RATING_MAP.put("X X X X X X X 5", "com.android.tv/US_MV/US_MV_R"); - US_RATING_MAP.put("X X X X X X X 6", "com.android.tv/US_MV/US_MV_NC17"); - // MPAA-X was replaced by NC17 - US_RATING_MAP.put("X X X X X X X 7", "com.android.tv/US_MV/US_MV_NC17"); - US_RATING_MAP.put("X X X X X X X 8", ""); // MPAA - Not Rated - } - - @Test - public void testGenerateContentRating_emptyInput() { - assertThat(SectionParser.generateContentRating(new ArrayList<TsDescriptor>())).isEmpty(); - } - - @Test - public void testGenerateContentRating_validInputs() { - for (Map.Entry<String, String> entry : US_RATING_MAP.entrySet()) { - RatingRegion ratingRegion = createRatingRegionForTest(entry.getKey(), RATING_REGION_US); - ContentAdvisoryDescriptor descriptor = createDescriptorForTest(ratingRegion); - assertWithMessage("key = " + entry.getKey()) - .that( - SectionParser.generateContentRating( - Collections.singletonList((TsDescriptor) descriptor))) - .isEqualTo(entry.getValue()); - } - } - - @Test - public void testGenerateContentRating_invalidInput() { - // Invalid because the value of the first dimension is lost. - RatingRegion ratingRegion = createRatingRegionForTest("X 1 0 0 0 0 0 X", RATING_REGION_US); - ContentAdvisoryDescriptor descriptor = createDescriptorForTest(ratingRegion); - assertThat( - SectionParser.generateContentRating( - Collections.singletonList((TsDescriptor) descriptor))) - .isEmpty(); - } - - @Test - public void testGenerateContentRating_multipleRatings() { - // TV-MA - RatingRegion ratingRegionTv = - createRatingRegionForTest("5 0 0 0 0 0 0 X", RATING_REGION_US); - // MPAA-R - RatingRegion ratingRegionMv = - createRatingRegionForTest("X X X X X X X 5", RATING_REGION_US); - ContentAdvisoryDescriptor descriptorTv = createDescriptorForTest(ratingRegionTv); - ContentAdvisoryDescriptor descriptorMv = createDescriptorForTest(ratingRegionMv); - assertThat( - SectionParser.generateContentRating( - Arrays.<TsDescriptor>asList(descriptorTv, descriptorMv))) - .isEqualTo("com.android.tv/US_MV/US_MV_R,com.android.tv/US_TV/US_TV_MA"); - } - - private static RatingRegion createRatingRegionForTest(String values, int region) { - String[] valueArray = values.split(" "); - List<RegionalRating> regionalRatings = new ArrayList<>(); - for (int i = 0; i < valueArray.length; i++) { - try { - int value = Integer.valueOf(valueArray[i]); - if (value != 0) { - // value 0 means the dimension should be omitted from the descriptor - regionalRatings.add(new RegionalRating(i, value)); - } - } catch (NumberFormatException e) { - // do nothing - } - } - return new RatingRegion(region, "", regionalRatings); - } - - private static ContentAdvisoryDescriptor createDescriptorForTest(RatingRegion... regions) { - return new ContentAdvisoryDescriptor(Arrays.asList(regions)); - } -} diff --git a/tuner/tests/robotests/javatests/com/android/tv/tuner/dvb/DvbTunerHalTest.java b/tuner/tests/robotests/javatests/com/android/tv/tuner/dvb/DvbTunerHalTest.java deleted file mode 100644 index 13fb06a3..00000000 --- a/tuner/tests/robotests/javatests/com/android/tv/tuner/dvb/DvbTunerHalTest.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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.tuner.dvb; - -import static com.google.common.truth.Truth.assertThat; - -import com.android.tv.common.compat.TvInputConstantCompat; -import com.android.tv.testing.TestSingletonApp; -import com.android.tv.testing.constants.ConfigConstants; -import com.android.tv.tuner.tvinput.TunerSessionWorker; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -/** Tests for {@link TunerSessionWorker}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK, application = TestSingletonApp.class) -public class DvbTunerHalTest { - private int mSignal = 0; - - DvbTunerHal mDvbTunerHal = - new DvbTunerHal(RuntimeEnvironment.application) { - @Override - protected int nativeGetSignalStrength(long deviceId) { - return mSignal; - } - }; - - @Test - public void getSignalStrength_notUsed() { - mSignal = -3; - int signal = mDvbTunerHal.getSignalStrength(); - assertThat(signal).isEqualTo(TvInputConstantCompat.SIGNAL_STRENGTH_NOT_USED); - } - - @Test - public void getSignalStrength_errorMax() { - mSignal = Integer.MAX_VALUE; - int signal = mDvbTunerHal.getSignalStrength(); - assertThat(signal).isEqualTo(TvInputConstantCompat.SIGNAL_STRENGTH_ERROR); - } - - @Test - public void getSignalStrength_errorMin() { - mSignal = Integer.MIN_VALUE; - int signal = mDvbTunerHal.getSignalStrength(); - assertThat(signal).isEqualTo(TvInputConstantCompat.SIGNAL_STRENGTH_ERROR); - } - - @Test - public void getSignalStrength_error() { - mSignal = -1; - int signal = mDvbTunerHal.getSignalStrength(); - assertThat(signal).isEqualTo(TvInputConstantCompat.SIGNAL_STRENGTH_ERROR); - } - - @Test - public void getSignalStrength_curvedMax() { - mSignal = 65535; - int signal = mDvbTunerHal.getSignalStrength(); - assertThat(signal).isEqualTo(100); - } - - @Test - public void getSignalStrength_curvedHalf() { - mSignal = 58982; - int signal = mDvbTunerHal.getSignalStrength(); - assertThat(signal).isEqualTo(50); - } - - @Test - public void getSignalStrength_curvedMin() { - mSignal = 0; - int signal = mDvbTunerHal.getSignalStrength(); - assertThat(signal).isEqualTo(0); - } -} diff --git a/tuner/tests/robotests/javatests/com/android/tv/tuner/exoplayer/tests/AssetDataSource.java b/tuner/tests/robotests/javatests/com/android/tv/tuner/exoplayer/tests/AssetDataSource.java deleted file mode 100644 index 52faa1d2..00000000 --- a/tuner/tests/robotests/javatests/com/android/tv/tuner/exoplayer/tests/AssetDataSource.java +++ /dev/null @@ -1,134 +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.tuner.exoplayer.tests; - -import android.content.Context; -import android.content.res.AssetManager; -import android.net.Uri; -import com.google.android.exoplayer.C; -import com.google.android.exoplayer2.upstream.DataSource; -import com.google.android.exoplayer2.upstream.DataSpec; -import com.google.android.exoplayer2.upstream.TransferListener; -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; - -/** A local asset. */ -// Copied from com.google.android.exoplayer.upstream.AssetDataSource for test. -final class AssetDataSource implements DataSource { - /** Thrown when an {@link IOException} is encountered reading a local asset. */ - private static final class AssetDataSourceException extends IOException { - private AssetDataSourceException(IOException cause) { - super(cause); - } - } - - private final AssetManager mAssetManager; - - private InputStream mInputStream; - private long mBytesRemaining; - private Uri mUri; - - /** Constructs a new {@link DataSource} that retrieves data from a local asset. */ - AssetDataSource(Context context) { - mAssetManager = context.getAssets(); - } - - @Override - public long open(DataSpec dataSpec) throws AssetDataSourceException { - try { - String path = dataSpec.uri.getPath(); - if (path.startsWith("/android_asset/")) { - path = path.substring(15); - } else if (path.startsWith("/")) { - path = path.substring(1); - } - mInputStream = mAssetManager.open(path, AssetManager.ACCESS_RANDOM); - long skipped = mInputStream.skip(dataSpec.position); - if (skipped < dataSpec.position) { - // mAssetManager.open() returns an AssetInputStream, whose skip() implementation - // only skips fewer bytes than requested if the skip is beyond the end of the - // asset's data. - throw new EOFException(); - } - if (dataSpec.length != C.LENGTH_UNBOUNDED) { - mBytesRemaining = dataSpec.length; - } else { - mBytesRemaining = mInputStream.available(); - if (mBytesRemaining == Integer.MAX_VALUE) { - // mAssetManager.open() returns an AssetInputStream, whose available() - // implementation returns Integer.MAX_VALUE if the remaining length is greater - // than (or equal to) Integer.MAX_VALUE. We don't know the true length in this - // case, so treat as unbounded. - mBytesRemaining = C.LENGTH_UNBOUNDED; - } - } - } catch (IOException e) { - throw new AssetDataSourceException(e); - } - - mUri = dataSpec.uri; - return mBytesRemaining; - } - - @Override - public int read(byte[] buffer, int offset, int readLength) throws AssetDataSourceException { - if (mBytesRemaining == 0) { - return -1; - } else { - int bytesRead = 0; - try { - int bytesToRead = - mBytesRemaining == C.LENGTH_UNBOUNDED - ? readLength - : (int) Math.min(mBytesRemaining, readLength); - bytesRead = mInputStream.read(buffer, offset, bytesToRead); - } catch (IOException e) { - throw new AssetDataSourceException(e); - } - - if (bytesRead > 0 && mBytesRemaining != C.LENGTH_UNBOUNDED) { - mBytesRemaining -= bytesRead; - } - - return bytesRead; - } - } - - @Override - public void close() throws AssetDataSourceException { - mUri = null; - if (mInputStream != null) { - try { - mInputStream.close(); - } catch (IOException e) { - throw new AssetDataSourceException(e); - } finally { - mInputStream = null; - } - } - } - - @Override - public void addTransferListener(TransferListener transferListener) { - // TODO: Implement to support metrics collection. - } - - @Override - public Uri getUri() { - return mUri; - } -} diff --git a/tuner/tests/robotests/javatests/com/android/tv/tuner/exoplayer/tests/SampleSourceExtractorTest.java b/tuner/tests/robotests/javatests/com/android/tv/tuner/exoplayer/tests/SampleSourceExtractorTest.java deleted file mode 100644 index 5af30b93..00000000 --- a/tuner/tests/robotests/javatests/com/android/tv/tuner/exoplayer/tests/SampleSourceExtractorTest.java +++ /dev/null @@ -1,298 +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.tuner.exoplayer.tests; - -import static com.google.common.truth.Truth.assertWithMessage; - -import static junit.framework.Assert.fail; - -import android.content.Context; -import android.net.Uri; -import android.os.HandlerThread; -import android.os.Looper; -import android.util.Pair; - -import com.android.tv.testing.constants.ConfigConstants; -import com.android.tv.tuner.exoplayer.ExoPlayerSampleExtractor; -import com.android.tv.tuner.exoplayer.buffer.BufferManager; -import com.android.tv.tuner.exoplayer.buffer.BufferManager.StorageManager; -import com.android.tv.tuner.exoplayer.buffer.PlaybackBufferListener; -import com.android.tv.tuner.exoplayer.buffer.SampleChunk; -import com.android.tv.tuner.testing.buffer.VerySlowSampleChunk; - -import com.google.android.exoplayer.MediaFormat; -import com.google.android.exoplayer.SampleHolder; -import com.google.android.exoplayer.SampleSource; -import com.google.android.exoplayer2.upstream.DataSource; - -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.Shadows; -import org.robolectric.annotation.Config; -import org.robolectric.shadows.ShadowLooper; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.SortedMap; - -/** Tests for {@link ExoPlayerSampleExtractor} */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class SampleSourceExtractorTest { - // Maximum bandwidth of 1080p channel is about 2.2MB/s. 2MB for a sample will suffice. - private static final int SAMPLE_BUFFER_SIZE = 1024 * 1024 * 2; - private static final int CONSUMING_SAMPLES_PERIOD = 100; - private Uri testStreamUri; - private HandlerThread handlerThread; - private DataSource dataSource; - - @Before - public void setUp() { - testStreamUri = Uri.parse("asset:///capture_stream.ts"); - handlerThread = new HandlerThread("test"); - dataSource = new AssetDataSource(RuntimeEnvironment.application); - } - - @Test - public void testTrickplayDisabled() throws Throwable { - DataSource source = new AssetDataSource(RuntimeEnvironment.application); - MockPlaybackBufferListener listener = new MockPlaybackBufferListener(); - ExoPlayerSampleExtractor extractor = - new ExoPlayerSampleExtractor( - testStreamUri, - source, - null, - listener, - false, - Looper.getMainLooper(), - handlerThread, - (bufferManager, bufferListener, enableTrickplay, bufferReason) -> null); - assertWithMessage("Trickplay should be disabled").that(listener.getLastState()).isFalse(); - // Prepares the extractor. - extractor.prepare(); - // Looper is nat available until prepare is called at least once - Looper handlerLooper = handlerThread.getLooper(); - try { - while (!extractor.prepare()) { - - ShadowLooper.getShadowMainLooper().runOneTask(); - Shadows.shadowOf(handlerLooper).runOneTask(); - } - } catch (IOException e) { - fail("Exception occurred while preparing: " + e.getMessage()); - } - // Selects all tracks. - List<MediaFormat> trackFormats = extractor.getTrackFormats(); - for (int i = 0; i < trackFormats.size(); ++i) { - extractor.selectTrack(i); - } - // Consumes over some period. - SampleHolder sampleHolder = new SampleHolder(SampleHolder.BUFFER_REPLACEMENT_MODE_NORMAL); - sampleHolder.ensureSpaceForWrite(SAMPLE_BUFFER_SIZE); - - Shadows.shadowOf(handlerLooper).idle(); - for (int i = 0; i < CONSUMING_SAMPLES_PERIOD; ++i) { - boolean found = false; - while (!found) { - for (int j = 0; j < trackFormats.size(); ++j) { - int result = extractor.readSample(j, sampleHolder); - switch (result) { - case SampleSource.SAMPLE_READ: - found = true; - break; - case SampleSource.END_OF_STREAM: - fail("Failed to read samples"); - break; - default: - } - if (found) { - break; - } - } - Shadows.shadowOf(handlerLooper).runOneTask(); - ShadowLooper.getShadowMainLooper().runOneTask(); - } - } - extractor.release(); - } - - @Ignore("b/70338667") - @Test - public void testDiskTooSlowTrickplayDisabled() throws Throwable { - StorageManager storageManager = new StubStorageManager(RuntimeEnvironment.application); - BufferManager bufferManager = - new BufferManager( - storageManager, new VerySlowSampleChunk.VerySlowSampleChunkCreator()); - bufferManager.setMinimumSampleSizeForSpeedCheck(0); - MockPlaybackBufferListener listener = new MockPlaybackBufferListener(); - ExoPlayerSampleExtractor extractor = - new ExoPlayerSampleExtractor( - testStreamUri, - dataSource, - bufferManager, - listener, - false, - Looper.getMainLooper(), - handlerThread, - (bufferManager2, bufferListener, enableTrickplay, bufferReason) -> null); - - assertWithMessage("Trickplay should be enabled at the first") - .that(Boolean.TRUE) - .isEqualTo(listener.getLastState()); - // Prepares the extractor. - extractor.prepare(); - // Looper is nat available until prepare is called at least once - Looper handlerLooper = handlerThread.getLooper(); - try { - while (!extractor.prepare()) { - - ShadowLooper.getShadowMainLooper().runOneTask(); - Shadows.shadowOf(handlerLooper).runOneTask(); - } - } catch (IOException e) { - fail("Exception occurred while preparing: " + e.getMessage()); - } - // Selects all tracks. - List<MediaFormat> trackFormats = extractor.getTrackFormats(); - for (int i = 0; i < trackFormats.size(); ++i) { - extractor.selectTrack(i); - } - // Consumes until once speed check is done. - SampleHolder sampleHolder = new SampleHolder(SampleHolder.BUFFER_REPLACEMENT_MODE_NORMAL); - sampleHolder.ensureSpaceForWrite(SAMPLE_BUFFER_SIZE); - while (!bufferManager.hasSpeedCheckDone()) { - boolean found = false; - while (!found) { - for (int j = 0; j < trackFormats.size(); ++j) { - int result = extractor.readSample(j, sampleHolder); - switch (result) { - case SampleSource.SAMPLE_READ: - found = true; - break; - case SampleSource.END_OF_STREAM: - fail("Failed to read samples"); - break; - default: - } - if (found) { - break; - } - } - ShadowLooper.getShadowMainLooper().runOneTask(); - Shadows.shadowOf(handlerLooper).runOneTask(); - } - } - extractor.release(); - ShadowLooper.getShadowMainLooper().idle(); - Shadows.shadowOf(handlerLooper).idle(); - assertWithMessage("Disk too slow event should be reported") - .that(listener.isReportedDiskTooSlow()) - .isTrue(); - } - - private static class StubStorageManager implements StorageManager { - private final Context mContext; - - StubStorageManager(Context context) { - mContext = context; - } - - @Override - public File getBufferDir() { - return mContext.getCacheDir(); - } - - @Override - public boolean isPersistent() { - return false; - } - - @Override - public boolean reachedStorageMax(long bufferSize, long pendingDelete) { - return false; - } - - @Override - public boolean hasEnoughBuffer(long pendingDelete) { - return true; - } - - @Override - public List<BufferManager.TrackFormat> readTrackInfoFiles(boolean isAudio) { - return null; - } - - @Override - public ArrayList<BufferManager.PositionHolder> readIndexFile(String trackId) - throws IOException { - return null; - } - - @Override - public void writeTrackInfoFiles(List<BufferManager.TrackFormat> formatList, boolean isAudio) - throws IOException { - // No-op. - } - - @Override - public void writeIndexFile( - String trackName, SortedMap<Long, Pair<SampleChunk, Integer>> index) - throws IOException { - // No-op. - } - - @Override - public void updateIndexFile( - String trackName, int size, long position, SampleChunk sampleChunk, int offset) - throws IOException { - // No-op - } - } - - public static class MockPlaybackBufferListener implements PlaybackBufferListener { - private Boolean mLastState; - private boolean mIsReportedDiskTooSlow; - - public Boolean getLastState() { - return mLastState; - } - - public boolean isReportedDiskTooSlow() { - return mIsReportedDiskTooSlow; - } - // PlaybackBufferListener - @Override - public void onBufferStartTimeChanged(long startTimeMs) { - // No-op. - } - - @Override - public void onBufferStateChanged(boolean available) { - mLastState = available; - } - - @Override - public void onDiskTooSlow() { - mIsReportedDiskTooSlow = true; - } - } -} diff --git a/tuner/tests/robotests/javatests/com/android/tv/tuner/testing/TvTunerRobolectricTestRunner.java b/tuner/tests/robotests/javatests/com/android/tv/tuner/testing/TvTunerRobolectricTestRunner.java deleted file mode 100644 index 31dc25d5..00000000 --- a/tuner/tests/robotests/javatests/com/android/tv/tuner/testing/TvTunerRobolectricTestRunner.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2019 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.tuner.testing; - -import org.junit.runners.model.InitializationError; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; -import org.robolectric.manifest.AndroidManifest; -import org.robolectric.res.Fs; -import org.robolectric.res.ResourcePath; - -import java.util.List; - -/** - * Custom test runner TV tuner. This is needed because the default behavior for robolectric is just - * to grab the resource directory in the target package. We want to override this to add several - * spanning different projects. - * - * <p><b>Note</b> copied from - * http://cs/android/packages/apps/Settings/tests/robotests/src/com/android/settings/testutils/SettingsRobolectricTestRunner.java - */ -public class TvTunerRobolectricTestRunner extends RobolectricTestRunner { - - /** We don't actually want to change this behavior, so we just call super. */ - public TvTunerRobolectricTestRunner(Class<?> testClass) throws InitializationError { - super(testClass); - } - - /** - * We are going to create our own custom manifest so that we can add multiple resource paths to - * it. - */ - @Override - protected AndroidManifest getAppManifest(Config config) { - final String packageName = "com.android.tv.tuner"; - - // By adding any resources from libraries we need the AndroidManifest, we can access - // them from within the parallel universe's resource loader. - return new AndroidManifest( - Fs.fileFromPath(config.manifest()), - Fs.fileFromPath(config.resourceDir()), - Fs.fileFromPath(config.assetDir()), - packageName) { - @Override - public List<ResourcePath> getIncludedResourcePaths() { - List<ResourcePath> paths = super.getIncludedResourcePaths(); - TvTunerRobolectricTestRunner.getIncludedResourcePaths(paths); - return paths; - } - }; - } - - public static void getIncludedResourcePaths(List<ResourcePath> paths) { - paths.add( - new ResourcePath( - null, - Fs.fileFromPath("./packages/apps/TV/tuner/res"), - null)); - } -} diff --git a/tuner/tests/robotests/javatests/com/android/tv/tuner/tvinput/TunerSessionWorkerExoV2Test.java b/tuner/tests/robotests/javatests/com/android/tv/tuner/tvinput/TunerSessionWorkerExoV2Test.java deleted file mode 100644 index 24adbaa9..00000000 --- a/tuner/tests/robotests/javatests/com/android/tv/tuner/tvinput/TunerSessionWorkerExoV2Test.java +++ /dev/null @@ -1,201 +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.tuner.tvinput; - -import static com.android.tv.common.customization.CustomizationManager.TRICKPLAY_MODE_ENABLED; - -import static com.google.common.truth.Truth.assertThat; - -import android.app.Application; -import android.content.Context; -import android.net.Uri; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.view.accessibility.CaptioningManager; - -import com.android.tv.common.CommonConstants; -import com.android.tv.common.CommonPreferences; -import com.android.tv.common.compat.TvInputConstantCompat; -import com.android.tv.common.customization.CustomizationManager; -import com.android.tv.common.flags.impl.DefaultLegacyFlags; -import com.android.tv.testing.TestSingletonApp; -import com.android.tv.testing.constants.ConfigConstants; -import com.android.tv.tuner.exoplayer.MpegTsPlayer; -import com.android.tv.tuner.source.TsDataSourceManager; -import com.android.tv.tuner.source.TunerTsStreamerManager; -import com.android.tv.tuner.testing.TvTunerRobolectricTestRunner; -import com.android.tv.tuner.tvinput.datamanager.ChannelDataManager; - -import com.google.android.exoplayer.audio.AudioCapabilities; - -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentMatchers; -import org.mockito.Mockito; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; -import org.robolectric.shadow.api.Shadow; -import org.robolectric.shadows.ShadowContextImpl; - -import java.lang.reflect.Field; - -import javax.inject.Provider; - -/** Tests for {@link TunerSessionWorkerExoV2}. */ -@RunWith(TvTunerRobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK, application = TestSingletonApp.class) -public class TunerSessionWorkerExoV2Test { - - private TunerSessionWorkerExoV2 tunerSessionWorker; - private int mSignalStrength = TvInputConstantCompat.SIGNAL_STRENGTH_UNKNOWN; - private MpegTsPlayer mPlayer = Mockito.mock(MpegTsPlayer.class); - private Handler mHandler; - private DefaultLegacyFlags mLegacyFlags; - - @Before - public void setUp() throws NoSuchFieldException, IllegalAccessException { - Application context = RuntimeEnvironment.application; - mLegacyFlags = DefaultLegacyFlags.DEFAULT; - CaptioningManager captioningManager = Mockito.mock(CaptioningManager.class); - - // TODO (b/65160115) - Field field = CustomizationManager.class.getDeclaredField("sCustomizationPackage"); - field.setAccessible(true); - field.set(null, CommonConstants.BASE_PACKAGE + ".tuner"); - field = CustomizationManager.class.getDeclaredField("sTrickplayMode"); - field.setAccessible(true); - field.set(null, TRICKPLAY_MODE_ENABLED); - - ShadowContextImpl shadowContext = Shadow.extract(context.getBaseContext()); - shadowContext.setSystemService(Context.CAPTIONING_SERVICE, captioningManager); - - CommonPreferences.initialize(context); - ChannelDataManager channelDataManager = new ChannelDataManager(context, "testInput"); - - mHandler = new Handler(Looper.getMainLooper(), null); - - Provider<TunerTsStreamerManager> tsStreamerManagerProvider = - () -> new TunerTsStreamerManager(null); - TsDataSourceManager.Factory tsDataSourceManagerFactory = - new TsDataSourceManager.Factory(tsStreamerManagerProvider); - - new TunerSessionExoV2( - context, - channelDataManager, - session -> {}, - recordingSession -> Uri.parse("recordingUri"), - (context1, channelDataManager1, tunerSession1, tunerSessionOverlay) -> { - tunerSessionWorker = - new TunerSessionWorkerExoV2( - context1, - channelDataManager1, - tunerSession1, - tunerSessionOverlay, - mHandler, - mLegacyFlags, - (context2, bufferManager, bufferListener) -> null, - tsDataSourceManagerFactory) { - @Override - protected void notifySignal(int signal) { - mSignalStrength = signal; - } - - @Override - protected MpegTsPlayer createPlayer( - AudioCapabilities capabilities) { - return mPlayer; - } - }; - return tunerSessionWorker; - }); - } - - @Test - public void doSelectTrack_mPlayerIsNull() { - Message msg = new Message(); - msg.what = TunerSessionWorker.MSG_SELECT_TRACK; - assertThat(tunerSessionWorker.handleMessage(msg)).isFalse(); - } - - @Test - public void doCheckSignalStrength_mPlayerIsNull() { - Message msg = new Message(); - msg.what = TunerSessionWorker.MSG_CHECK_SIGNAL_STRENGTH; - assertThat(tunerSessionWorker.handleMessage(msg)).isFalse(); - } - - @Test - public void handleSignal_isNotUsed() { - assertThat(tunerSessionWorker.handleSignal(TvInputConstantCompat.SIGNAL_STRENGTH_NOT_USED)) - .isTrue(); - assertThat(mSignalStrength).isEqualTo(TvInputConstantCompat.SIGNAL_STRENGTH_NOT_USED); - } - - @Test - public void handleSignal_isError() { - assertThat(tunerSessionWorker.handleSignal(TvInputConstantCompat.SIGNAL_STRENGTH_ERROR)) - .isTrue(); - assertThat(mSignalStrength).isEqualTo(TvInputConstantCompat.SIGNAL_STRENGTH_ERROR); - } - - @Test - public void handleSignal_isUnknown() { - assertThat(tunerSessionWorker.handleSignal(TvInputConstantCompat.SIGNAL_STRENGTH_UNKNOWN)) - .isTrue(); - assertThat(mSignalStrength).isEqualTo(TvInputConstantCompat.SIGNAL_STRENGTH_UNKNOWN); - } - - @Test - public void handleSignal_isNotifySignal() { - assertThat(tunerSessionWorker.handleSignal(100)).isTrue(); - assertThat(mSignalStrength).isEqualTo(100); - } - - @Test - public void preparePlayback_playerIsNotReady() { - Mockito.when( - mPlayer.prepare( - Mockito.eq(RuntimeEnvironment.application), - ArgumentMatchers.any(), - ArgumentMatchers.anyBoolean(), - ArgumentMatchers.any())) - .thenReturn(false); - tunerSessionWorker.preparePlayback(); - assertThat(mHandler.hasMessages(TunerSessionWorker.MSG_TUNE)).isFalse(); - assertThat(mHandler.hasMessages(TunerSessionWorker.MSG_RETRY_PLAYBACK)).isTrue(); - assertThat(mHandler.hasMessages(TunerSessionWorker.MSG_CHECK_SIGNAL_STRENGTH)).isFalse(); - assertThat(mHandler.hasMessages(TunerSessionWorker.MSG_CHECK_SIGNAL)).isFalse(); - } - - @Test - @Ignore - public void preparePlayback_playerIsReady() { - Mockito.when( - mPlayer.prepare( - RuntimeEnvironment.application, - ArgumentMatchers.any(), - ArgumentMatchers.anyBoolean(), - ArgumentMatchers.any())) - .thenReturn(true); - tunerSessionWorker.preparePlayback(); - assertThat(mHandler.hasMessages(TunerSessionWorker.MSG_RETRY_PLAYBACK)).isFalse(); - assertThat(mHandler.hasMessages(TunerSessionWorker.MSG_CHECK_SIGNAL_STRENGTH)).isTrue(); - assertThat(mHandler.hasMessages(TunerSessionWorker.MSG_CHECK_SIGNAL)).isTrue(); - } -} diff --git a/tuner/tests/robotests/javatests/com/android/tv/tuner/tvinput/TunerSessionWorkerTest.java b/tuner/tests/robotests/javatests/com/android/tv/tuner/tvinput/TunerSessionWorkerTest.java deleted file mode 100644 index 536af60c..00000000 --- a/tuner/tests/robotests/javatests/com/android/tv/tuner/tvinput/TunerSessionWorkerTest.java +++ /dev/null @@ -1,200 +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.tuner.tvinput; - -import static com.android.tv.common.customization.CustomizationManager.TRICKPLAY_MODE_ENABLED; - -import static com.google.common.truth.Truth.assertThat; - -import android.app.Application; -import android.content.Context; -import android.net.Uri; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.view.accessibility.CaptioningManager; - -import com.android.tv.common.CommonConstants; -import com.android.tv.common.CommonPreferences; -import com.android.tv.common.compat.TvInputConstantCompat; -import com.android.tv.common.customization.CustomizationManager; -import com.android.tv.common.flags.impl.DefaultLegacyFlags; -import com.android.tv.testing.TestSingletonApp; -import com.android.tv.testing.constants.ConfigConstants; -import com.android.tv.tuner.exoplayer.MpegTsPlayer; -import com.android.tv.tuner.source.TsDataSourceManager; -import com.android.tv.tuner.source.TunerTsStreamerManager; -import com.android.tv.tuner.testing.TvTunerRobolectricTestRunner; -import com.android.tv.tuner.tvinput.datamanager.ChannelDataManager; - -import com.google.android.exoplayer.audio.AudioCapabilities; - -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentMatchers; -import org.mockito.Mockito; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; -import org.robolectric.shadow.api.Shadow; -import org.robolectric.shadows.ShadowContextImpl; - -import java.lang.reflect.Field; - -import javax.inject.Provider; - -/** Tests for {@link TunerSessionWorker}. */ -@RunWith(TvTunerRobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK, application = TestSingletonApp.class) -public class TunerSessionWorkerTest { - - private TunerSessionWorker tunerSessionWorker; - private int mSignalStrength = TvInputConstantCompat.SIGNAL_STRENGTH_UNKNOWN; - private MpegTsPlayer mPlayer = Mockito.mock(MpegTsPlayer.class); - private Handler mHandler; - private DefaultLegacyFlags mLegacyFlags; - - @Before - public void setUp() throws NoSuchFieldException, IllegalAccessException { - Application context = RuntimeEnvironment.application; - CaptioningManager captioningManager = Mockito.mock(CaptioningManager.class); - mLegacyFlags = DefaultLegacyFlags.DEFAULT; - - // TODO (b/65160115) - Field field = CustomizationManager.class.getDeclaredField("sCustomizationPackage"); - field.setAccessible(true); - field.set(null, CommonConstants.BASE_PACKAGE + ".tuner"); - field = CustomizationManager.class.getDeclaredField("sTrickplayMode"); - field.setAccessible(true); - field.set(null, TRICKPLAY_MODE_ENABLED); - - ShadowContextImpl shadowContext = Shadow.extract(context.getBaseContext()); - shadowContext.setSystemService(Context.CAPTIONING_SERVICE, captioningManager); - - CommonPreferences.initialize(context); - ChannelDataManager channelDataManager = new ChannelDataManager(context, "testInput"); - - mHandler = new Handler(Looper.getMainLooper(), null); - Provider<TunerTsStreamerManager> tsStreamerManagerProvider = - () -> new TunerTsStreamerManager(null); - TsDataSourceManager.Factory tsdm = - new TsDataSourceManager.Factory(tsStreamerManagerProvider); - - new TunerSession( - context, - channelDataManager, - session -> {}, - recordingSession -> Uri.parse("recordingUri"), - (context1, channelDataManager1, tunerSession1, tunerSessionOverlay) -> { - tunerSessionWorker = - new TunerSessionWorker( - context1, - channelDataManager1, - tunerSession1, - new TunerSessionOverlay(context1), - mHandler, - mLegacyFlags, - (context2, bufferManager, bufferListener) -> null, - tsdm) { - @Override - protected void notifySignal(int signal) { - mSignalStrength = signal; - } - - @Override - protected MpegTsPlayer createPlayer( - AudioCapabilities capabilities) { - return mPlayer; - } - }; - return tunerSessionWorker; - }); - } - - @Test - public void doSelectTrack_mPlayerIsNull() { - Message msg = new Message(); - msg.what = TunerSessionWorker.MSG_SELECT_TRACK; - assertThat(tunerSessionWorker.handleMessage(msg)).isFalse(); - } - - @Test - public void doCheckSignalStrength_mPlayerIsNull() { - Message msg = new Message(); - msg.what = TunerSessionWorker.MSG_CHECK_SIGNAL_STRENGTH; - assertThat(tunerSessionWorker.handleMessage(msg)).isFalse(); - } - - @Test - public void handleSignal_isNotUsed() { - assertThat(tunerSessionWorker.handleSignal(TvInputConstantCompat.SIGNAL_STRENGTH_NOT_USED)) - .isTrue(); - assertThat(mSignalStrength).isEqualTo(TvInputConstantCompat.SIGNAL_STRENGTH_NOT_USED); - } - - @Test - public void handleSignal_isError() { - assertThat(tunerSessionWorker.handleSignal(TvInputConstantCompat.SIGNAL_STRENGTH_ERROR)) - .isTrue(); - assertThat(mSignalStrength).isEqualTo(TvInputConstantCompat.SIGNAL_STRENGTH_ERROR); - } - - @Test - public void handleSignal_isUnknown() { - assertThat(tunerSessionWorker.handleSignal(TvInputConstantCompat.SIGNAL_STRENGTH_UNKNOWN)) - .isTrue(); - assertThat(mSignalStrength).isEqualTo(TvInputConstantCompat.SIGNAL_STRENGTH_UNKNOWN); - } - - @Test - public void handleSignal_isNotifySignal() { - assertThat(tunerSessionWorker.handleSignal(100)).isTrue(); - assertThat(mSignalStrength).isEqualTo(100); - } - - @Test - public void preparePlayback_playerIsNotReady() { - Mockito.when( - mPlayer.prepare( - Mockito.eq(RuntimeEnvironment.application), - ArgumentMatchers.any(), - ArgumentMatchers.anyBoolean(), - ArgumentMatchers.any())) - .thenReturn(false); - tunerSessionWorker.preparePlayback(); - assertThat(mHandler.hasMessages(TunerSessionWorker.MSG_TUNE)).isFalse(); - assertThat(mHandler.hasMessages(TunerSessionWorker.MSG_RETRY_PLAYBACK)).isTrue(); - assertThat(mHandler.hasMessages(TunerSessionWorker.MSG_CHECK_SIGNAL_STRENGTH)).isFalse(); - assertThat(mHandler.hasMessages(TunerSessionWorker.MSG_CHECK_SIGNAL)).isFalse(); - } - - @Test - @Ignore - public void preparePlayback_playerIsReady() { - Mockito.when( - mPlayer.prepare( - RuntimeEnvironment.application, - ArgumentMatchers.any(), - ArgumentMatchers.anyBoolean(), - ArgumentMatchers.any())) - .thenReturn(true); - tunerSessionWorker.preparePlayback(); - assertThat(mHandler.hasMessages(TunerSessionWorker.MSG_RETRY_PLAYBACK)).isFalse(); - assertThat(mHandler.hasMessages(TunerSessionWorker.MSG_CHECK_SIGNAL_STRENGTH)).isTrue(); - assertThat(mHandler.hasMessages(TunerSessionWorker.MSG_CHECK_SIGNAL)).isTrue(); - } -} diff --git a/tuner/tests/robotests/javatests/com/android/tv/tuner/tvinput/datamanager/ChannelDataManagerTest.java b/tuner/tests/robotests/javatests/com/android/tv/tuner/tvinput/datamanager/ChannelDataManagerTest.java deleted file mode 100644 index 0da76ef8..00000000 --- a/tuner/tests/robotests/javatests/com/android/tv/tuner/tvinput/datamanager/ChannelDataManagerTest.java +++ /dev/null @@ -1,90 +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.tuner.tvinput.datamanager; - -import static com.google.common.truth.Truth.assertThat; - -import android.content.ContentValues; -import android.content.pm.ProviderInfo; -import android.media.tv.TvContract; - -import com.android.tv.testing.TestSingletonApp; -import com.android.tv.testing.constants.ConfigConstants; -import com.android.tv.testing.fakes.FakeTvProvider; -import com.android.tv.tuner.data.Channel; -import com.android.tv.tuner.data.TunerChannel; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; -import org.robolectric.shadows.ShadowContentResolver; -import org.robolectric.shadows.ShadowContextWrapper; - -/** Tests for {@link com.android.tv.tuner.tvinput.datamanager.ChannelDataManager}. */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK, application = TestSingletonApp.class) -public class ChannelDataManagerTest { - - private ChannelDataManager mChannelDataManager; - - @Before - public void setup() { - ProviderInfo info = new ProviderInfo(); - info.authority = TvContract.AUTHORITY; - FakeTvProvider provider = - Robolectric.buildContentProvider(FakeTvProvider.class).create(info).get(); - provider.setCallingPackage("com.android.tv"); - provider.onCreate(); - ShadowContextWrapper shadowContextWrapper = new ShadowContextWrapper(); - shadowContextWrapper.grantPermissions(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS); - ShadowContentResolver.registerProviderInternal(TvContract.AUTHORITY, provider); - provider.delete(TvContract.Channels.CONTENT_URI, null, null); - ContentValues contentValues = new ContentValues(); - contentValues.put(TvContract.Channels.COLUMN_INPUT_ID, "com.android.tv"); - contentValues.put( - TvContract.Channels.COLUMN_INTERNAL_PROVIDER_DATA, - Channel.TunerChannelProto.getDefaultInstance().toByteArray()); - contentValues.put(TvContract.Channels.COLUMN_LOCKED, 0); - provider.insert(TvContract.Channels.CONTENT_URI, contentValues); - contentValues.put(TvContract.Channels.COLUMN_LOCKED, 1); - provider.insert(TvContract.Channels.CONTENT_URI, contentValues); - - mChannelDataManager = new ChannelDataManager(RuntimeEnvironment.application, "testInput"); - } - - @After - public void tearDown() { - mChannelDataManager.releaseSafely(); - } - - @Test - public void getChannel_locked() { - TunerChannel tunerChannel = mChannelDataManager.getChannel(2L); - assertThat(tunerChannel.isLocked()).isTrue(); - } - - @Test - public void getChannel_unlocked() { - TunerChannel tunerChannel = mChannelDataManager.getChannel(1L); - assertThat(tunerChannel.isLocked()).isFalse(); - } -} diff --git a/tuner/tests/robotests/javatests/com/android/tv/tuner/util/PostalCodeUtilsTest.java b/tuner/tests/robotests/javatests/com/android/tv/tuner/util/PostalCodeUtilsTest.java deleted file mode 100644 index 5a49904e..00000000 --- a/tuner/tests/robotests/javatests/com/android/tv/tuner/util/PostalCodeUtilsTest.java +++ /dev/null @@ -1,84 +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.tuner.util; - -import static com.google.common.truth.Truth.assertThat; - -import com.android.tv.common.util.PostalCodeUtils; -import com.android.tv.testing.constants.ConfigConstants; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import java.util.Locale; - -/** Tests for {@link PostalCodeUtils} */ -@RunWith(RobolectricTestRunner.class) -@Config(sdk = ConfigConstants.SDK) -public class PostalCodeUtilsTest { - - private static final String[] VALID_POSTCODES_US = {"94043", "94063", "90007"}; - private static final String[] INVALID_POSTCODES_US = { - "", "9404", "ABC", "BCD8", "G777", "BT777", "OXX33", "E1WW", "SW1XX", "E11W", "SW10X", - "GIR", "B8", "G77", "BT7", "OX33", "E1W", "SW1X" - }; - private static final String[] VALID_POSTCODES_GB = { - "GIR", "B8", "G77", "BT7", "OX33", "E1W", "SW1X", "GIR 0AA", "GIR0AA", "B8 2NE", "PR10BJ" - }; - private static final String[] INVALID_POSTCODES_GB = { - "", "9404", "ABC", "BCD8", "G777", "BT777", "OXX33", "E1WW", "SW1XX", "E11W", "SW10X", - "94043", "94063", "90007", "B8 ", "OX331D" - }; - - @Test - public void validPostcodesUs() { - for (String postcode : VALID_POSTCODES_US) { - assertThat(PostalCodeUtils.matches(postcode, Locale.US.getCountry())).isTrue(); - } - } - - @Test - public void validPostcodesGb() { - for (String postcode : VALID_POSTCODES_GB) { - assertThat(PostalCodeUtils.matches(postcode, Locale.UK.getCountry())).isTrue(); - } - } - - @Test - public void invalidPostcodesUs() { - for (String postcode : INVALID_POSTCODES_US) { - assertThat(PostalCodeUtils.matches(postcode, Locale.US.getCountry())).isFalse(); - } - } - - @Test - public void invalidPostcodesGb() { - for (String postcode : INVALID_POSTCODES_GB) { - assertThat(PostalCodeUtils.matches(postcode, Locale.UK.getCountry())).isFalse(); - } - } - - @Test - public void unsupportedRegion() { - for (String postcode : INVALID_POSTCODES_US) { - // {@link Locale.ROOT} is an empty Locale - assertThat(PostalCodeUtils.matches(postcode, Locale.ROOT.getCountry())).isTrue(); - } - } -} diff --git a/tuner/tests/testing/Android.mk b/tuner/tests/testing/Android.mk index 864f5f3e..79e35e5a 100644 --- a/tuner/tests/testing/Android.mk +++ b/tuner/tests/testing/Android.mk @@ -10,7 +10,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ android-support-annotations \ androidx.test.runner \ tv-guava-android-jar \ - mockito-robolectric-prebuilt \ + mockito-target \ tv-lib-truth \ ub-uiautomator \ diff --git a/tuner/tests/testing/AndroidManifest.xml b/tuner/tests/testing/AndroidManifest.xml index 9fcecf9c..7e07a52a 100644 --- a/tuner/tests/testing/AndroidManifest.xml +++ b/tuner/tests/testing/AndroidManifest.xml @@ -18,6 +18,6 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.tv.tuner.testing" android:versionCode="1"> - <uses-sdk android:targetSdkVersion="28" android:minSdkVersion="23"/> + <uses-sdk android:targetSdkVersion="27" android:minSdkVersion="23"/> <application /> </manifest> diff --git a/tuner/tests/unittests/javatests/AndroidManifest.xml b/tuner/tests/unittests/javatests/AndroidManifest.xml index ddbddd0b..62caefa1 100644 --- a/tuner/tests/unittests/javatests/AndroidManifest.xml +++ b/tuner/tests/unittests/javatests/AndroidManifest.xml @@ -18,7 +18,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.tv.tuner.layout.tests" > - <uses-sdk android:minSdkVersion="23" android:targetSdkVersion="28"/> + <uses-sdk android:minSdkVersion="23" android:targetSdkVersion="27"/> <instrumentation android:name="android.test.InstrumentationTestRunner" diff --git a/tuner/tests/unittests/javatests/com/android/tv/tuner/AndroidManifest.xml b/tuner/tests/unittests/javatests/com/android/tv/tuner/AndroidManifest.xml index 6956426d..6fe0b85a 100644 --- a/tuner/tests/unittests/javatests/com/android/tv/tuner/AndroidManifest.xml +++ b/tuner/tests/unittests/javatests/com/android/tv/tuner/AndroidManifest.xml @@ -18,11 +18,11 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.tv.tuner.tests" > - <uses-sdk android:minSdkVersion="23" android:targetSdkVersion="28" /> + <uses-sdk android:minSdkVersion="23" android:targetSdkVersion="27" /> <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" - android:targetPackage="com.android.tv.tuner.sample.dvb" /> + android:targetPackage="com.android.tv" /> <application android:label="TunerTvInputTests" > <uses-library android:name="android.test.runner" /> diff --git a/tuner/tests/unittests/javatests/com/android/tv/tuner/ZappingTimeTest.java b/tuner/tests/unittests/javatests/com/android/tv/tuner/ZappingTimeTest.java index 031cec51..ef653f86 100644 --- a/tuner/tests/unittests/javatests/com/android/tv/tuner/ZappingTimeTest.java +++ b/tuner/tests/unittests/javatests/com/android/tv/tuner/ZappingTimeTest.java @@ -21,34 +21,24 @@ import android.graphics.SurfaceTexture; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; -import android.support.annotation.Nullable; import android.test.InstrumentationTestCase; import android.util.Log; import android.view.Surface; - import androidx.test.filters.LargeTest; - +import com.android.tv.common.flags.impl.DefaultConcurrentDvrPlaybackFlags; import com.android.tv.tuner.data.Cea708Data; -import com.android.tv.tuner.data.Channel.AudioStreamType; -import com.android.tv.tuner.data.Channel.VideoStreamType; import com.android.tv.tuner.data.PsiData; import com.android.tv.tuner.data.PsipData; import com.android.tv.tuner.data.TunerChannel; +import com.android.tv.tuner.data.nano.Channel; import com.android.tv.tuner.exoplayer.MpegTsPlayer; import com.android.tv.tuner.exoplayer.MpegTsRendererBuilder; -import com.android.tv.tuner.exoplayer.MpegTsSampleExtractor; import com.android.tv.tuner.exoplayer.buffer.BufferManager; import com.android.tv.tuner.exoplayer.buffer.PlaybackBufferListener; import com.android.tv.tuner.exoplayer.buffer.TrickplayStorageManager; import com.android.tv.tuner.source.TsDataSourceManager; -import com.android.tv.tuner.source.TsDataSourceManager.Factory; import com.android.tv.tuner.ts.EventDetector.EventListener; - import com.google.android.exoplayer.ExoPlayer; -import com.google.android.exoplayer2.upstream.DataSource; - -import org.junit.Ignore; - import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -59,6 +49,7 @@ import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; +import org.junit.Ignore; /** This class use {@link FileTunerHal} to simulate tunerhal's actions to test zapping time. */ @LargeTest @@ -97,6 +88,8 @@ public class ZappingTimeTest extends InstrumentationTestCase { private MockMpegTsPlayerListener mMpegTsPlayerListener = new MockMpegTsPlayerListener(); private MockPlaybackBufferListener mPlaybackBufferListener = new MockPlaybackBufferListener(); private MockChannelScanListener mEventListener = new MockChannelScanListener(); + private DefaultConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags = + new DefaultConcurrentDvrPlaybackFlags(); @Override protected void setUp() throws Exception { @@ -106,10 +99,10 @@ public class ZappingTimeTest extends InstrumentationTestCase { HandlerThread handlerThread = new HandlerThread(TAG); handlerThread.start(); List<PsiData.PmtItem> pmtItems = new ArrayList<>(); - pmtItems.add(new PsiData.PmtItem(VideoStreamType.MPEG2_VALUE, VIDEO_PID, null, null)); + pmtItems.add(new PsiData.PmtItem(Channel.VideoStreamType.MPEG2, VIDEO_PID, null, null)); for (int audioPid : AUDIO_PIDS) { pmtItems.add( - new PsiData.PmtItem(AudioStreamType.A52AC3AUDIO_VALUE, audioPid, null, null)); + new PsiData.PmtItem(Channel.AudioStreamType.A52AC3AUDIO, audioPid, null, null)); } Context context = getInstrumentation().getContext(); @@ -124,25 +117,8 @@ public class ZappingTimeTest extends InstrumentationTestCase { mChannel.setModulation(MODULATION); mTunerHal = new FileTunerHal(context, tsCacheFile); mTunerHal.openFirstAvailable(); - TsDataSourceManager.Factory tsFactory = new Factory(null); - mSourceManager = tsFactory.create(false); + mSourceManager = TsDataSourceManager.createSourceManager(false); mSourceManager.addTunerHalForTest(mTunerHal); - MpegTsSampleExtractor.Factory mpegTsSampleExtractorFactory = - new MpegTsSampleExtractor.Factory() { - @Override - public MpegTsSampleExtractor create( - BufferManager bufferManager, PlaybackBufferListener bufferListener) { - return null; - } - - @Override - public MpegTsSampleExtractor create( - DataSource source, - @Nullable BufferManager bufferManager, - PlaybackBufferListener bufferListener) { - return null; - } - }; mHandler = new Handler( handlerThread.getLooper(), @@ -174,14 +150,13 @@ public class ZappingTimeTest extends InstrumentationTestCase { } mChannel.setFrequency(frequency); mSourceManager.setKeepTuneStatus(true); - mPlayer = new MpegTsPlayer( new MpegTsRendererBuilder( mTargetContext, bufferManager, mPlaybackBufferListener, - mpegTsSampleExtractorFactory), + mConcurrentDvrPlaybackFlags), mHandler, mSourceManager, null, diff --git a/tuner/tests/unittests/javatests/com/android/tv/tuner/layout/tests/AndroidManifest.xml b/tuner/tests/unittests/javatests/com/android/tv/tuner/layout/tests/AndroidManifest.xml index 79b09872..77c7f40a 100644 --- a/tuner/tests/unittests/javatests/com/android/tv/tuner/layout/tests/AndroidManifest.xml +++ b/tuner/tests/unittests/javatests/com/android/tv/tuner/layout/tests/AndroidManifest.xml @@ -17,7 +17,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.tv.tuner" android:versionCode="1"> - <uses-sdk android:targetSdkVersion="28" android:minSdkVersion="23"/> + <uses-sdk android:targetSdkVersion="27" android:minSdkVersion="23"/> <application android:label="TunerTvInputLayoutTests" > <activity android:name="com.android.tv.tuner.layout.tests.ScaledLayoutActivity" android:label="ScaledLayout Test" /> diff --git a/tuner/tests/unittests/javatests/com/android/tv/tuner/setup/AndroidManifest.xml b/tuner/tests/unittests/javatests/com/android/tv/tuner/setup/AndroidManifest.xml deleted file mode 100644 index 19cc0e5d..00000000 --- a/tuner/tests/unittests/javatests/com/android/tv/tuner/setup/AndroidManifest.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2019 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. - --> - -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.tv.tuner.setup.tests" > - - <uses-sdk android:minSdkVersion="23" android:targetSdkVersion="28" /> - - <instrumentation - android:name="androidx.test.runner.AndroidJUnitRunner" - android:targetPackage="com.android.tv.tuner.sample.dvb" /> - - <application android:label="TunerTvInputTests" > - <uses-library android:name="android.test.runner" /> - </application> - -</manifest> diff --git a/tuner/tests/unittests/javatests/com/android/tv/tuner/setup/TunerHalCreatorTest.java b/tuner/tests/unittests/javatests/com/android/tv/tuner/setup/TunerHalCreatorTest.java index cc5e5c59..a3a32084 100644 --- a/tuner/tests/unittests/javatests/com/android/tv/tuner/setup/TunerHalCreatorTest.java +++ b/tuner/tests/unittests/javatests/com/android/tv/tuner/setup/TunerHalCreatorTest.java @@ -21,18 +21,14 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import android.os.AsyncTask; - import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; - import com.android.tv.tuner.api.Tuner; import com.android.tv.tuner.setup.BaseTunerSetupActivity.TunerHalCreator; - +import java.util.concurrent.Executor; import org.junit.Test; import org.junit.runner.RunWith; -import java.util.concurrent.Executor; - /** Tests for {@link TunerHalCreator}. */ @SmallTest @RunWith(AndroidJUnit4.class) @@ -41,7 +37,7 @@ public class TunerHalCreatorTest { private static class TestTunerHalCreator extends TunerHalCreator { private TestTunerHalCreator(Executor executor) { - super(null, executor, null); + super(null, executor); } @Override |