aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk57
-rw-r--r--AndroidManifest.xml64
-rw-r--r--common/BuildConfig.java.in1
-rw-r--r--common/res/values/strings.xml1
-rw-r--r--common/src/com/android/tv/common/AutoCloseableUtils.java (renamed from common/src/com/android/tv/common/util/AutoCloseableUtils.java)2
-rw-r--r--common/src/com/android/tv/common/BaseApplication.java112
-rw-r--r--common/src/com/android/tv/common/BaseSingletons.java35
-rw-r--r--common/src/com/android/tv/common/CollectionUtils.java (renamed from common/src/com/android/tv/common/util/CollectionUtils.java)2
-rw-r--r--common/src/com/android/tv/common/SharedPreferencesUtils.java (renamed from common/src/com/android/tv/common/util/SharedPreferencesUtils.java)5
-rw-r--r--common/src/com/android/tv/common/SoftPreconditions.java107
-rw-r--r--common/src/com/android/tv/common/TvCommonConstants.java (renamed from common/src/com/android/tv/common/CommonConstants.java)16
-rw-r--r--common/src/com/android/tv/common/TvCommonUtils.java72
-rw-r--r--common/src/com/android/tv/common/annotation/UsedByNative.java43
-rw-r--r--common/src/com/android/tv/common/annotation/UsedByReflection.java (renamed from common/src/com/android/tv/common/experiments/ExperimentLoader.java)20
-rw-r--r--common/src/com/android/tv/common/feature/CommonFeatures.java61
-rw-r--r--common/src/com/android/tv/common/feature/ExperimentFeature.java44
-rw-r--r--common/src/com/android/tv/common/feature/FeatureUtils.java15
-rw-r--r--common/src/com/android/tv/common/feature/PropertyFeature.java7
-rw-r--r--common/src/com/android/tv/common/feature/Sdk.java8
-rw-r--r--common/src/com/android/tv/common/feature/SharedPreferencesFeature.java2
-rw-r--r--common/src/com/android/tv/common/feature/TestableFeature.java12
-rw-r--r--common/src/com/android/tv/common/recording/RecordingStorageStatusManager.java256
-rw-r--r--common/src/com/android/tv/common/ui/setup/SetupGuidedStepFragment.java25
-rw-r--r--common/src/com/android/tv/common/ui/setup/SetupMultiPaneFragment.java3
-rw-r--r--common/src/com/android/tv/common/ui/setup/animation/TranslationAnimationCreator.java15
-rw-r--r--common/src/com/android/tv/common/util/CommonUtils.java148
-rw-r--r--icu/icu4j/main/classes/core/src/com/ibm/icu/text/SCSU.java405
-rw-r--r--icu/icu4j/main/classes/core/src/com/ibm/icu/text/UnicodeDecompressor.java795
-rw-r--r--jni/DvbManager.cpp10
-rw-r--r--jni/DvbManager.h1
-rwxr-xr-xjni/gen_jni.sh15
-rw-r--r--jni/tunertvinput_jni.cpp2
-rw-r--r--libs/exoplayer-core-2-SNAPHOT-20180114.aarbin1101772 -> 0 bytes
-rw-r--r--libs/exoplayer-r1.5.16.aarbin737991 -> 0 bytes
-rw-r--r--libs/exoplayer.jarbin0 -> 792705 bytes
-rw-r--r--libs/exoplayer_v2.jarbin0 -> 1077775 bytes
-rw-r--r--libs/exoplayer_v2_ext_ffmpeg.jarbin0 -> 7271 bytes
-rw-r--r--proguard.flags33
-rw-r--r--proto/channel.proto (renamed from tuner/proto/channel.proto)7
-rw-r--r--proto/track.proto (renamed from tuner/proto/track.proto)0
-rw-r--r--res/drawable-xhdpi/ic_launcher.png (renamed from res/drawable-xhdpi/ic_live_channels_96x96.png)bin3325 -> 3325 bytes
-rw-r--r--res/drawable-xhdpi/ic_live_channels.pngbin33740 -> 0 bytes
-rw-r--r--res/layout/dvr_recording_card_view.xml2
-rw-r--r--res/layout/guided_action_editable.xml (renamed from tuner/res/layout/guided_action_editable.xml)0
-rw-r--r--res/layout/lb_details_overview.xml (renamed from res/layout/details_overview.xml)0
-rw-r--r--res/values/arrays.xml2
-rw-r--r--res/values/strings.xml24
-rw-r--r--res/xml/remote_config_defaults.xml (renamed from tuner/tests/unittests/javatests/com/google/android/tv/tuner/AndroidManifest.xml)32
-rw-r--r--src/com/android/exoplayer/MediaFormatUtil.java (renamed from tuner/src/com/google/android/exoplayer/MediaFormatUtil.java)8
-rw-r--r--src/com/android/exoplayer/MediaSoftwareCodecUtil.java (renamed from tuner/src/com/google/android/exoplayer/MediaSoftwareCodecUtil.java)0
-rw-r--r--src/com/android/exoplayer/text/SubtitleView.java (renamed from tuner/src/com/android/tv/tuner/exoplayer/text/SubtitleView.java)6
-rw-r--r--src/com/android/exoplayer2/ext/ffmpeg/FfmpegAudioDecoder.java126
-rw-r--r--src/com/android/exoplayer2/ext/ffmpeg/FfmpegLibrary.java75
-rw-r--r--src/com/android/tv/ApplicationSingletons.java (renamed from src/com/android/tv/TvSingletons.java)40
-rw-r--r--src/com/android/tv/AudioManagerHelper.java36
-rw-r--r--src/com/android/tv/Features.java193
-rw-r--r--src/com/android/tv/InputSessionManager.java2
-rw-r--r--src/com/android/tv/LauncherActivity.java27
-rw-r--r--src/com/android/tv/MainActivity.java366
-rw-r--r--src/com/android/tv/MediaSessionWrapper.java18
-rw-r--r--src/com/android/tv/SetupPassthroughActivity.java51
-rw-r--r--src/com/android/tv/Starter.java42
-rw-r--r--src/com/android/tv/TimeShiftManager.java11
-rw-r--r--src/com/android/tv/TvApplication.java243
-rw-r--r--src/com/android/tv/TvFeatures.java103
-rw-r--r--src/com/android/tv/analytics/SendChannelStatusRunnable.java3
-rw-r--r--src/com/android/tv/app/LiveTvApplication.java137
-rw-r--r--src/com/android/tv/config/ConfigKeys.java (renamed from tuner/src/com/android/tv/tuner/tvinput/LiveTvTunerTvInputService.java)11
-rw-r--r--src/com/android/tv/config/DefaultConfigManager.java (renamed from common/src/com/android/tv/common/config/DefaultConfigManager.java)3
-rw-r--r--src/com/android/tv/config/RemoteConfig.java (renamed from common/src/com/android/tv/common/config/api/RemoteConfig.java)7
-rw-r--r--src/com/android/tv/config/RemoteConfigFeature.java (renamed from common/src/com/android/tv/common/config/RemoteConfigFeature.java)11
-rw-r--r--src/com/android/tv/config/RemoteConfigUtils.java (renamed from common/src/com/android/tv/common/config/RemoteConfigUtils.java)9
-rw-r--r--src/com/android/tv/customization/CustomAction.java (renamed from common/src/com/android/tv/common/customization/CustomAction.java)2
-rw-r--r--src/com/android/tv/customization/TvCustomizationManager.java (renamed from common/src/com/android/tv/common/customization/CustomizationManager.java)8
-rw-r--r--src/com/android/tv/data/Channel.java9
-rw-r--r--src/com/android/tv/data/ChannelDataManager.java5
-rw-r--r--src/com/android/tv/data/ChannelLogoFetcher.java5
-rw-r--r--src/com/android/tv/data/ChannelNumber.java19
-rw-r--r--src/com/android/tv/data/InternalDataUtils.java1
-rw-r--r--src/com/android/tv/data/Lineup.java53
-rw-r--r--src/com/android/tv/data/PreviewDataManager.java15
-rw-r--r--src/com/android/tv/data/PreviewProgramContent.java49
-rw-r--r--src/com/android/tv/data/Program.java8
-rw-r--r--src/com/android/tv/data/ProgramDataManager.java3
-rw-r--r--src/com/android/tv/data/WatchedHistoryManager.java18
-rw-r--r--src/com/android/tv/data/epg/AutoValue_EpgReader_EpgChannel.java86
-rw-r--r--src/com/android/tv/data/epg/EpgFetchHelper.java9
-rw-r--r--src/com/android/tv/data/epg/EpgFetchService.java70
-rw-r--r--src/com/android/tv/data/epg/EpgFetcher.java705
-rw-r--r--src/com/android/tv/data/epg/EpgFetcherImpl.java814
-rw-r--r--src/com/android/tv/data/epg/EpgInputWhiteList.java92
-rw-r--r--src/com/android/tv/data/epg/EpgReader.java24
-rw-r--r--src/com/android/tv/data/epg/StubEpgReader.java11
-rw-r--r--src/com/android/tv/dialog/DvrHistoryDialogFragment.java6
-rw-r--r--src/com/android/tv/dialog/PinDialogFragment.java8
-rw-r--r--src/com/android/tv/dialog/SafeDismissDialogFragment.java4
-rw-r--r--src/com/android/tv/dvr/BaseDvrDataManager.java2
-rw-r--r--src/com/android/tv/dvr/DvrDataManagerImpl.java31
-rw-r--r--src/com/android/tv/dvr/DvrManager.java16
-rw-r--r--src/com/android/tv/dvr/DvrScheduleManager.java14
-rw-r--r--src/com/android/tv/dvr/DvrStorageStatusManager.java286
-rw-r--r--src/com/android/tv/dvr/DvrWatchedPositionManager.java2
-rw-r--r--src/com/android/tv/dvr/data/RecordedProgram.java4
-rw-r--r--src/com/android/tv/dvr/data/ScheduledRecording.java22
-rw-r--r--src/com/android/tv/dvr/data/SeriesRecording.java2
-rw-r--r--src/com/android/tv/dvr/provider/AsyncDvrDbTask.java3
-rw-r--r--src/com/android/tv/dvr/provider/DvrDatabaseHelper.java2
-rw-r--r--src/com/android/tv/dvr/provider/DvrDbSync.java6
-rw-r--r--src/com/android/tv/dvr/provider/EpisodicProgramLoadTask.java6
-rw-r--r--src/com/android/tv/dvr/recorder/ConflictChecker.java34
-rw-r--r--src/com/android/tv/dvr/recorder/DvrRecordingService.java12
-rw-r--r--src/com/android/tv/dvr/recorder/DvrStartRecordingReceiver.java7
-rw-r--r--src/com/android/tv/dvr/recorder/InputTaskScheduler.java3
-rw-r--r--src/com/android/tv/dvr/recorder/RecordingScheduler.java9
-rw-r--r--src/com/android/tv/dvr/recorder/RecordingTask.java13
-rw-r--r--src/com/android/tv/dvr/recorder/ScheduledProgramReaper.java2
-rw-r--r--src/com/android/tv/dvr/recorder/SeriesRecordingScheduler.java34
-rw-r--r--src/com/android/tv/dvr/ui/DvrAlreadyRecordedFragment.java4
-rw-r--r--src/com/android/tv/dvr/ui/DvrAlreadyScheduledFragment.java4
-rw-r--r--src/com/android/tv/dvr/ui/DvrChannelRecordDurationOptionFragment.java6
-rw-r--r--src/com/android/tv/dvr/ui/DvrConflictFragment.java10
-rw-r--r--src/com/android/tv/dvr/ui/DvrGuidedStepFragment.java16
-rw-r--r--src/com/android/tv/dvr/ui/DvrInsufficientSpaceErrorFragment.java4
-rw-r--r--src/com/android/tv/dvr/ui/DvrPrioritySettingsFragment.java10
-rw-r--r--src/com/android/tv/dvr/ui/DvrScheduleFragment.java14
-rw-r--r--src/com/android/tv/dvr/ui/DvrSeriesDeletionActivity.java4
-rw-r--r--src/com/android/tv/dvr/ui/DvrSeriesDeletionFragment.java8
-rw-r--r--src/com/android/tv/dvr/ui/DvrSeriesScheduledFragment.java8
-rw-r--r--src/com/android/tv/dvr/ui/DvrSeriesSettingsActivity.java4
-rw-r--r--src/com/android/tv/dvr/ui/DvrSeriesSettingsFragment.java14
-rw-r--r--src/com/android/tv/dvr/ui/DvrStopRecordingFragment.java4
-rw-r--r--src/com/android/tv/dvr/ui/DvrStopSeriesRecordingFragment.java5
-rw-r--r--src/com/android/tv/dvr/ui/DvrUiHelper.java23
-rw-r--r--src/com/android/tv/dvr/ui/TrackedGuidedStepFragment.java4
-rw-r--r--src/com/android/tv/dvr/ui/browse/CurrentRecordingDetailsFragment.java6
-rw-r--r--src/com/android/tv/dvr/ui/browse/DetailsContent.java6
-rw-r--r--src/com/android/tv/dvr/ui/browse/DetailsViewBackgroundHelper.java1
-rw-r--r--src/com/android/tv/dvr/ui/browse/DvrBrowseActivity.java4
-rw-r--r--src/com/android/tv/dvr/ui/browse/DvrBrowseFragment.java9
-rw-r--r--src/com/android/tv/dvr/ui/browse/DvrDetailsActivity.java4
-rw-r--r--src/com/android/tv/dvr/ui/browse/DvrDetailsFragment.java10
-rw-r--r--src/com/android/tv/dvr/ui/browse/DvrItemPresenter.java5
-rw-r--r--src/com/android/tv/dvr/ui/browse/FullSchedulesCardPresenter.java4
-rw-r--r--src/com/android/tv/dvr/ui/browse/RecordedProgramDetailsFragment.java8
-rw-r--r--src/com/android/tv/dvr/ui/browse/RecordedProgramPresenter.java4
-rw-r--r--src/com/android/tv/dvr/ui/browse/RecordingCardView.java4
-rw-r--r--src/com/android/tv/dvr/ui/browse/RecordingDetailsFragment.java4
-rw-r--r--src/com/android/tv/dvr/ui/browse/ScheduledRecordingDetailsFragment.java4
-rw-r--r--src/com/android/tv/dvr/ui/browse/ScheduledRecordingPresenter.java4
-rw-r--r--src/com/android/tv/dvr/ui/browse/SeriesRecordingDetailsFragment.java8
-rw-r--r--src/com/android/tv/dvr/ui/browse/SeriesRecordingPresenter.java5
-rw-r--r--src/com/android/tv/dvr/ui/list/BaseDvrSchedulesFragment.java7
-rw-r--r--src/com/android/tv/dvr/ui/list/DvrSchedulesActivity.java4
-rw-r--r--src/com/android/tv/dvr/ui/list/DvrSeriesSchedulesFragment.java5
-rw-r--r--src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java8
-rw-r--r--src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java10
-rw-r--r--src/com/android/tv/dvr/ui/list/SchedulesHeaderRowPresenter.java6
-rw-r--r--src/com/android/tv/dvr/ui/list/SeriesScheduleRowAdapter.java5
-rw-r--r--src/com/android/tv/dvr/ui/playback/DvrPlaybackActivity.java4
-rw-r--r--src/com/android/tv/dvr/ui/playback/DvrPlaybackMediaSessionHelper.java6
-rw-r--r--src/com/android/tv/dvr/ui/playback/DvrPlaybackOverlayFragment.java6
-rw-r--r--src/com/android/tv/experiments/ExperimentFlag.java (renamed from common/src/com/android/tv/common/experiments/ExperimentFlag.java)12
-rw-r--r--src/com/android/tv/experiments/Experiments.java (renamed from common/src/com/android/tv/common/experiments/Experiments.java)31
-rw-r--r--src/com/android/tv/guide/ProgramGuide.java7
-rw-r--r--src/com/android/tv/guide/ProgramItemView.java8
-rw-r--r--src/com/android/tv/guide/ProgramTableAdapter.java21
-rw-r--r--src/com/android/tv/license/LicenseUtils.java1
-rw-r--r--src/com/android/tv/menu/ChannelsRowAdapter.java20
-rw-r--r--src/com/android/tv/menu/CustomizableOptionsRowAdapter.java2
-rw-r--r--src/com/android/tv/menu/Menu.java10
-rw-r--r--src/com/android/tv/menu/MenuLayoutManager.java4
-rw-r--r--src/com/android/tv/menu/MenuRowFactory.java17
-rw-r--r--src/com/android/tv/menu/OptionsRowAdapter.java4
-rw-r--r--src/com/android/tv/menu/PartnerOptionsRowAdapter.java2
-rw-r--r--src/com/android/tv/menu/PlayControlsRowView.java10
-rw-r--r--src/com/android/tv/menu/TvOptionsRowAdapter.java10
-rw-r--r--src/com/android/tv/onboarding/NewSourcesFragment.java11
-rw-r--r--src/com/android/tv/onboarding/OnboardingActivity.java19
-rw-r--r--src/com/android/tv/onboarding/SetupSourcesFragment.java21
-rw-r--r--src/com/android/tv/onboarding/WelcomeFragment.java107
-rw-r--r--src/com/android/tv/parental/ContentRatingsManager.java12
-rw-r--r--src/com/android/tv/parental/ContentRatingsParser.java1
-rw-r--r--src/com/android/tv/parental/ParentalControlSettings.java2
-rw-r--r--src/com/android/tv/perf/EventNames.java1
-rw-r--r--src/com/android/tv/receiver/AudioCapabilitiesReceiver.java11
-rw-r--r--src/com/android/tv/receiver/BootCompletedReceiver.java13
-rw-r--r--src/com/android/tv/receiver/GlobalKeyReceiver.java6
-rw-r--r--src/com/android/tv/receiver/PackageIntentsReceiver.java11
-rw-r--r--src/com/android/tv/recommendation/ChannelPreviewUpdater.java15
-rw-r--r--src/com/android/tv/recommendation/ChannelRecord.java14
-rw-r--r--src/com/android/tv/recommendation/NotificationService.java18
-rw-r--r--src/com/android/tv/recommendation/RecommendationDataManager.java7
-rw-r--r--src/com/android/tv/recommendation/RecordedProgramPreviewUpdater.java13
-rw-r--r--src/com/android/tv/search/DataManagerSearch.java9
-rw-r--r--src/com/android/tv/search/LocalSearchProvider.java10
-rw-r--r--src/com/android/tv/search/ProgramGuideSearchFragment.java7
-rw-r--r--src/com/android/tv/search/TvProviderSearch.java3
-rw-r--r--src/com/android/tv/setup/SystemSetupActivity.java9
-rw-r--r--src/com/android/tv/tuner/ChannelScanFileParser.java (renamed from tuner/src/com/android/tv/tuner/ChannelScanFileParser.java)8
-rw-r--r--src/com/android/tv/tuner/DvbDeviceAccessor.java (renamed from tuner/src/com/android/tv/tuner/DvbDeviceAccessor.java)0
-rw-r--r--src/com/android/tv/tuner/DvbTunerHal.java (renamed from tuner/src/com/android/tv/tuner/DvbTunerHal.java)0
-rw-r--r--src/com/android/tv/tuner/TunerHal.java (renamed from tuner/src/com/android/tv/tuner/TunerHal.java)18
-rw-r--r--src/com/android/tv/tuner/TunerInputController.java430
-rw-r--r--src/com/android/tv/tuner/TunerPreferenceProvider.java (renamed from common/src/com/android/tv/common/CommonPreferenceProvider.java)8
-rw-r--r--src/com/android/tv/tuner/TunerPreferences.java (renamed from common/src/com/android/tv/common/CommonPreferences.java)252
-rw-r--r--src/com/android/tv/tuner/cc/CaptionLayout.java (renamed from tuner/src/com/android/tv/tuner/cc/CaptionLayout.java)0
-rw-r--r--src/com/android/tv/tuner/cc/CaptionTrackRenderer.java (renamed from tuner/src/com/android/tv/tuner/cc/CaptionTrackRenderer.java)0
-rw-r--r--src/com/android/tv/tuner/cc/CaptionWindowLayout.java (renamed from tuner/src/com/android/tv/tuner/cc/CaptionWindowLayout.java)4
-rw-r--r--src/com/android/tv/tuner/cc/Cea708Parser.java (renamed from tuner/src/com/android/tv/tuner/cc/Cea708Parser.java)0
-rw-r--r--src/com/android/tv/tuner/data/Cea708Data.java (renamed from tuner/src/com/android/tv/tuner/data/Cea708Data.java)0
-rw-r--r--src/com/android/tv/tuner/data/PsiData.java (renamed from tuner/src/com/android/tv/tuner/data/PsiData.java)0
-rw-r--r--src/com/android/tv/tuner/data/PsipData.java (renamed from tuner/src/com/android/tv/tuner/data/PsipData.java)2
-rw-r--r--src/com/android/tv/tuner/data/TunerChannel.java (renamed from tuner/src/com/android/tv/tuner/data/TunerChannel.java)77
-rw-r--r--src/com/android/tv/tuner/exoplayer/Cea708TextTrackRenderer.java (renamed from tuner/src/com/android/tv/tuner/exoplayer/Cea708TextTrackRenderer.java)4
-rw-r--r--src/com/android/tv/tuner/exoplayer/ExoPlayerExtractorsFactory.java (renamed from tuner/src/com/android/tv/tuner/exoplayer/ExoPlayerExtractorsFactory.java)6
-rw-r--r--src/com/android/tv/tuner/exoplayer/ExoPlayerSampleExtractor.java (renamed from tuner/src/com/android/tv/tuner/exoplayer/ExoPlayerSampleExtractor.java)43
-rw-r--r--src/com/android/tv/tuner/exoplayer/FileSampleExtractor.java (renamed from tuner/src/com/android/tv/tuner/exoplayer/FileSampleExtractor.java)6
-rw-r--r--src/com/android/tv/tuner/exoplayer/MpegTsPlayer.java (renamed from tuner/src/com/android/tv/tuner/exoplayer/MpegTsPlayer.java)20
-rw-r--r--src/com/android/tv/tuner/exoplayer/MpegTsRendererBuilder.java (renamed from tuner/src/com/android/tv/tuner/exoplayer/MpegTsRendererBuilder.java)12
-rw-r--r--src/com/android/tv/tuner/exoplayer/MpegTsSampleExtractor.java (renamed from tuner/src/com/android/tv/tuner/exoplayer/MpegTsSampleExtractor.java)6
-rw-r--r--src/com/android/tv/tuner/exoplayer/MpegTsSampleSource.java (renamed from tuner/src/com/android/tv/tuner/exoplayer/MpegTsSampleSource.java)0
-rw-r--r--src/com/android/tv/tuner/exoplayer/MpegTsVideoTrackRenderer.java (renamed from tuner/src/com/android/tv/tuner/exoplayer/MpegTsVideoTrackRenderer.java)19
-rw-r--r--src/com/android/tv/tuner/exoplayer/SampleExtractor.java (renamed from tuner/src/com/android/tv/tuner/exoplayer/SampleExtractor.java)0
-rw-r--r--src/com/android/tv/tuner/exoplayer/audio/AudioClock.java (renamed from tuner/src/com/android/tv/tuner/exoplayer/audio/AudioClock.java)0
-rw-r--r--src/com/android/tv/tuner/exoplayer/audio/AudioDecoder.java (renamed from tuner/src/com/android/tv/tuner/exoplayer/audio/AudioDecoder.java)0
-rw-r--r--src/com/android/tv/tuner/exoplayer/audio/AudioTrackMonitor.java (renamed from tuner/src/com/android/tv/tuner/exoplayer/audio/AudioTrackMonitor.java)0
-rw-r--r--src/com/android/tv/tuner/exoplayer/audio/AudioTrackWrapper.java (renamed from tuner/src/com/android/tv/tuner/exoplayer/audio/AudioTrackWrapper.java)0
-rw-r--r--src/com/android/tv/tuner/exoplayer/audio/MediaCodecAudioDecoder.java (renamed from tuner/src/com/android/tv/tuner/exoplayer/audio/MediaCodecAudioDecoder.java)0
-rw-r--r--src/com/android/tv/tuner/exoplayer/audio/MpegTsDefaultAudioTrackRenderer.java (renamed from tuner/src/com/android/tv/tuner/exoplayer/audio/MpegTsDefaultAudioTrackRenderer.java)20
-rw-r--r--src/com/android/tv/tuner/exoplayer/audio/MpegTsMediaCodecAudioTrackRenderer.java (renamed from tuner/src/com/android/tv/tuner/exoplayer/audio/MpegTsMediaCodecAudioTrackRenderer.java)0
-rw-r--r--src/com/android/tv/tuner/exoplayer/buffer/BufferManager.java (renamed from tuner/src/com/android/tv/tuner/exoplayer/buffer/BufferManager.java)6
-rw-r--r--src/com/android/tv/tuner/exoplayer/buffer/DvrStorageManager.java (renamed from tuner/src/com/android/tv/tuner/exoplayer/buffer/DvrStorageManager.java)1
-rw-r--r--src/com/android/tv/tuner/exoplayer/buffer/RecordingSampleBuffer.java (renamed from tuner/src/com/android/tv/tuner/exoplayer/buffer/RecordingSampleBuffer.java)6
-rw-r--r--src/com/android/tv/tuner/exoplayer/buffer/SampleChunk.java (renamed from tuner/src/com/android/tv/tuner/exoplayer/buffer/SampleChunk.java)5
-rw-r--r--src/com/android/tv/tuner/exoplayer/buffer/SampleChunkIoHelper.java (renamed from tuner/src/com/android/tv/tuner/exoplayer/buffer/SampleChunkIoHelper.java)4
-rw-r--r--src/com/android/tv/tuner/exoplayer/buffer/SamplePool.java (renamed from tuner/src/com/android/tv/tuner/exoplayer/buffer/SamplePool.java)0
-rw-r--r--src/com/android/tv/tuner/exoplayer/buffer/SampleQueue.java (renamed from tuner/src/com/android/tv/tuner/exoplayer/buffer/SampleQueue.java)0
-rw-r--r--src/com/android/tv/tuner/exoplayer/buffer/SimpleSampleBuffer.java (renamed from tuner/src/com/android/tv/tuner/exoplayer/buffer/SimpleSampleBuffer.java)6
-rw-r--r--src/com/android/tv/tuner/exoplayer/buffer/TrickplayStorageManager.java (renamed from tuner/src/com/android/tv/tuner/exoplayer/buffer/TrickplayStorageManager.java)0
-rw-r--r--src/com/android/tv/tuner/exoplayer/ffmpeg/FfmpegDecoderClient.java247
-rw-r--r--src/com/android/tv/tuner/exoplayer/ffmpeg/FfmpegDecoderService.java202
-rw-r--r--src/com/android/tv/tuner/exoplayer/ffmpeg/IFfmpegDecoder.aidl (renamed from tuner/src/com/mediatek/tunerservice/IMtkTuner.aidl)22
-rw-r--r--src/com/android/tv/tuner/layout/ScaledLayout.java (renamed from tuner/src/com/android/tv/tuner/layout/ScaledLayout.java)0
-rw-r--r--src/com/android/tv/tuner/setup/ConnectionTypeFragment.java (renamed from tuner/src/com/android/tv/tuner/setup/ConnectionTypeFragment.java)9
-rw-r--r--src/com/android/tv/tuner/setup/PostalCodeFragment.java (renamed from tuner/src/com/android/tv/tuner/setup/PostalCodeFragment.java)36
-rw-r--r--src/com/android/tv/tuner/setup/ScanFragment.java (renamed from tuner/src/com/android/tv/tuner/setup/ScanFragment.java)29
-rw-r--r--src/com/android/tv/tuner/setup/ScanResultFragment.java (renamed from tuner/src/com/android/tv/tuner/setup/ScanResultFragment.java)18
-rw-r--r--src/com/android/tv/tuner/setup/TunerSetupActivity.java (renamed from tuner/src/com/android/tv/tuner/setup/BaseTunerSetupActivity.java)337
-rw-r--r--src/com/android/tv/tuner/setup/WelcomeFragment.java (renamed from tuner/src/com/android/tv/tuner/setup/WelcomeFragment.java)6
-rw-r--r--src/com/android/tv/tuner/source/FileTsStreamer.java (renamed from tuner/src/com/android/tv/tuner/source/FileTsStreamer.java)12
-rw-r--r--src/com/android/tv/tuner/source/TsDataSource.java (renamed from tuner/src/com/android/tv/tuner/source/TsDataSource.java)0
-rw-r--r--src/com/android/tv/tuner/source/TsDataSourceManager.java (renamed from tuner/src/com/android/tv/tuner/source/TsDataSourceManager.java)2
-rw-r--r--src/com/android/tv/tuner/source/TsStreamWriter.java (renamed from tuner/src/com/android/tv/tuner/source/TsStreamWriter.java)0
-rw-r--r--src/com/android/tv/tuner/source/TsStreamer.java (renamed from tuner/src/com/android/tv/tuner/source/TsStreamer.java)0
-rw-r--r--src/com/android/tv/tuner/source/TunerTsStreamer.java (renamed from tuner/src/com/android/tv/tuner/source/TunerTsStreamer.java)4
-rw-r--r--src/com/android/tv/tuner/source/TunerTsStreamerManager.java (renamed from tuner/src/com/android/tv/tuner/source/TunerTsStreamerManager.java)2
-rw-r--r--src/com/android/tv/tuner/ts/SectionParser.java (renamed from tuner/src/com/android/tv/tuner/ts/SectionParser.java)44
-rw-r--r--src/com/android/tv/tuner/ts/TsParser.java (renamed from tuner/src/com/android/tv/tuner/ts/TsParser.java)0
-rw-r--r--src/com/android/tv/tuner/tvinput/ChannelDataManager.java (renamed from tuner/src/com/android/tv/tuner/tvinput/ChannelDataManager.java)39
-rw-r--r--src/com/android/tv/tuner/tvinput/EventDetector.java (renamed from tuner/src/com/android/tv/tuner/tvinput/EventDetector.java)0
-rw-r--r--src/com/android/tv/tuner/tvinput/FileSourceEventDetector.java (renamed from tuner/src/com/android/tv/tuner/tvinput/FileSourceEventDetector.java)2
-rw-r--r--src/com/android/tv/tuner/tvinput/PlaybackBufferListener.java (renamed from tuner/src/com/android/tv/tuner/tvinput/PlaybackBufferListener.java)0
-rw-r--r--src/com/android/tv/tuner/tvinput/TunerDebug.java (renamed from tuner/src/com/android/tv/tuner/tvinput/TunerDebug.java)0
-rw-r--r--src/com/android/tv/tuner/tvinput/TunerRecordingSession.java (renamed from tuner/src/com/android/tv/tuner/tvinput/TunerRecordingSession.java)0
-rw-r--r--src/com/android/tv/tuner/tvinput/TunerRecordingSessionWorker.java (renamed from tuner/src/com/android/tv/tuner/tvinput/TunerRecordingSessionWorker.java)193
-rw-r--r--src/com/android/tv/tuner/tvinput/TunerSession.java (renamed from tuner/src/com/android/tv/tuner/tvinput/TunerSession.java)14
-rw-r--r--src/com/android/tv/tuner/tvinput/TunerSessionWorker.java (renamed from tuner/src/com/android/tv/tuner/tvinput/TunerSessionWorker.java)202
-rw-r--r--src/com/android/tv/tuner/tvinput/TunerStorageCleanUpService.java (renamed from tuner/src/com/android/tv/tuner/tvinput/TunerStorageCleanUpService.java)20
-rw-r--r--src/com/android/tv/tuner/tvinput/TunerTvInputService.java (renamed from tuner/src/com/android/tv/tuner/tvinput/BaseTunerTvInputService.java)27
-rw-r--r--src/com/android/tv/tuner/util/ByteArrayBuffer.java (renamed from tuner/src/com/android/tv/tuner/util/ByteArrayBuffer.java)3
-rw-r--r--src/com/android/tv/tuner/util/ConvertUtils.java (renamed from tuner/src/com/android/tv/tuner/util/ConvertUtils.java)0
-rw-r--r--src/com/android/tv/tuner/util/GlobalSettingsUtils.java (renamed from tuner/src/com/android/tv/tuner/util/GlobalSettingsUtils.java)0
-rw-r--r--src/com/android/tv/tuner/util/Ints.java (renamed from tuner/src/com/android/tv/tuner/util/Ints.java)15
-rw-r--r--src/com/android/tv/tuner/util/PostalCodeUtils.java (renamed from common/src/com/android/tv/common/util/PostalCodeUtils.java)9
-rw-r--r--src/com/android/tv/tuner/util/StatusTextUtils.java (renamed from tuner/src/com/android/tv/tuner/util/StatusTextUtils.java)0
-rw-r--r--src/com/android/tv/tuner/util/SystemPropertiesProxy.java (renamed from common/src/com/android/tv/common/util/SystemPropertiesProxy.java)2
-rw-r--r--src/com/android/tv/tuner/util/TisConfiguration.java20
-rw-r--r--src/com/android/tv/tuner/util/TunerInputInfoUtils.java (renamed from tuner/src/com/android/tv/tuner/util/TunerInputInfoUtils.java)11
-rw-r--r--src/com/android/tv/ui/AppLayerTvView.java6
-rw-r--r--src/com/android/tv/ui/ChannelBannerView.java6
-rw-r--r--src/com/android/tv/ui/KeypadChannelSwitchView.java6
-rw-r--r--src/com/android/tv/ui/SelectInputView.java11
-rw-r--r--src/com/android/tv/ui/TunableTvView.java29
-rw-r--r--src/com/android/tv/ui/TvOverlayManager.java13
-rw-r--r--src/com/android/tv/ui/TvViewUiManager.java4
-rw-r--r--src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java2
-rw-r--r--src/com/android/tv/ui/sidepanel/DeveloperOptionFragment.java26
-rw-r--r--src/com/android/tv/ui/sidepanel/SettingsFragment.java32
-rw-r--r--src/com/android/tv/ui/sidepanel/SideFragment.java8
-rw-r--r--src/com/android/tv/ui/sidepanel/parentalcontrols/ChannelsBlockedFragment.java11
-rw-r--r--src/com/android/tv/ui/sidepanel/parentalcontrols/RatingsFragment.java2
-rw-r--r--src/com/android/tv/util/AccountHelper.java (renamed from src/com/android/tv/util/account/AccountHelperImpl.java)29
-rw-r--r--src/com/android/tv/util/AsyncDbTask.java4
-rw-r--r--src/com/android/tv/util/BitmapUtils.java1
-rw-r--r--src/com/android/tv/util/Clock.java (renamed from common/src/com/android/tv/common/util/Clock.java)2
-rw-r--r--src/com/android/tv/util/Debug.java (renamed from common/src/com/android/tv/common/util/Debug.java)6
-rw-r--r--src/com/android/tv/util/DurationTimer.java (renamed from common/src/com/android/tv/common/util/DurationTimer.java)2
-rw-r--r--src/com/android/tv/util/ImageLoader.java1
-rw-r--r--src/com/android/tv/util/LocationUtils.java (renamed from common/src/com/android/tv/common/util/LocationUtils.java)9
-rw-r--r--src/com/android/tv/util/NamedThreadFactory.java (renamed from common/src/com/android/tv/common/concurrent/NamedThreadFactory.java)8
-rw-r--r--src/com/android/tv/util/NetworkTrafficTags.java (renamed from common/src/com/android/tv/common/util/NetworkTrafficTags.java)2
-rw-r--r--src/com/android/tv/util/OnboardingUtils.java8
-rw-r--r--src/com/android/tv/util/PermissionUtils.java (renamed from common/src/com/android/tv/common/util/PermissionUtils.java)17
-rw-r--r--src/com/android/tv/util/RecurringRunner.java2
-rw-r--r--src/com/android/tv/util/SetupUtils.java53
-rw-r--r--src/com/android/tv/util/SqlParams.java74
-rw-r--r--src/com/android/tv/util/StringUtils.java (renamed from common/src/com/android/tv/common/util/StringUtils.java)2
-rw-r--r--src/com/android/tv/util/SystemProperties.java (renamed from common/src/com/android/tv/common/util/SystemProperties.java)6
-rw-r--r--src/com/android/tv/util/TvInputManagerHelper.java104
-rw-r--r--src/com/android/tv/util/Utils.java69
-rw-r--r--src/com/android/tv/util/ViewCache.java15
-rw-r--r--src/com/android/tv/util/account/AccountHelper.java38
-rw-r--r--tests/common/Android.mk9
-rw-r--r--tests/common/src/com/android/tv/testing/ChannelInfo.java (renamed from tests/common/src/com/android/tv/testing/data/ChannelInfo.java)2
-rw-r--r--tests/common/src/com/android/tv/testing/ChannelNumberSubject.java66
-rw-r--r--tests/common/src/com/android/tv/testing/ChannelUtils.java (renamed from tests/common/src/com/android/tv/testing/data/ChannelUtils.java)13
-rw-r--r--tests/common/src/com/android/tv/testing/Constants.java (renamed from tests/common/src/com/android/tv/testing/constants/Constants.java)2
-rw-r--r--tests/common/src/com/android/tv/testing/DbTestingUtils.java40
-rw-r--r--tests/common/src/com/android/tv/testing/EpgTestData.java197
-rw-r--r--tests/common/src/com/android/tv/testing/FakeClock.java2
-rw-r--r--tests/common/src/com/android/tv/testing/FakeEpgFetcher.java57
-rw-r--r--tests/common/src/com/android/tv/testing/FakeEpgReader.java163
-rw-r--r--tests/common/src/com/android/tv/testing/FakeRemoteConfig.java47
-rw-r--r--tests/common/src/com/android/tv/testing/FakeTvInputManager.java117
-rw-r--r--tests/common/src/com/android/tv/testing/FakeTvInputManagerHelper.java32
-rw-r--r--tests/common/src/com/android/tv/testing/FakeTvProvider.java2605
-rw-r--r--tests/common/src/com/android/tv/testing/ProgramInfo.java (renamed from tests/common/src/com/android/tv/testing/data/ProgramInfo.java)19
-rw-r--r--tests/common/src/com/android/tv/testing/ProgramUtils.java (renamed from tests/common/src/com/android/tv/testing/data/ProgramUtils.java)3
-rw-r--r--tests/common/src/com/android/tv/testing/SingletonProvider.java37
-rw-r--r--tests/common/src/com/android/tv/testing/TestSingletonApp.java219
-rw-r--r--tests/common/src/com/android/tv/testing/TvContentRatingConstants.java (renamed from tests/common/src/com/android/tv/testing/constants/TvContentRatingConstants.java)2
-rw-r--r--tests/common/src/com/android/tv/testing/Utils.java (renamed from tests/common/src/com/android/tv/testing/utils/Utils.java)15
-rw-r--r--tests/common/src/com/android/tv/testing/shadows/ShadowMediaSession.java89
-rw-r--r--tests/common/src/com/android/tv/testing/testinput/ChannelState.java2
-rw-r--r--tests/common/src/com/android/tv/testing/testinput/TestInputControlConnection.java2
-rw-r--r--tests/common/src/com/android/tv/testing/testinput/TvTestInputConstants.java2
-rw-r--r--tests/common/src/com/android/tv/testing/uihelper/LiveChannelsUiDeviceHelper.java17
-rw-r--r--tests/func/src/com/android/tv/tests/ui/LiveChannelsAppTest.java8
-rw-r--r--tests/func/src/com/android/tv/tests/ui/LiveChannelsTestCase.java2
-rw-r--r--tests/func/src/com/android/tv/tests/ui/PlayControlsRowViewTest.java3
-rw-r--r--tests/input/func.sh24
-rw-r--r--tests/input/src/com/android/tv/testinput/TestInputControl.java4
-rw-r--r--tests/input/src/com/android/tv/testinput/TestTvInputService.java3
-rw-r--r--tests/input/src/com/android/tv/testinput/TestTvInputSetupActivity.java10
-rw-r--r--tests/input/src/com/android/tv/testinput/instrument/TestSetupInstrumentation.java2
-rwxr-xr-xtests/input/tools/get_test_logos.sh57
-rw-r--r--tests/input/unit.sh24
-rw-r--r--tests/tunerscripts/measure-tuning-time.awk32
-rwxr-xr-xtests/tunerscripts/usbtuner-test.sh159
-rw-r--r--tests/tunerunit/Android.mk25
-rw-r--r--tests/tunerunit/AndroidManifest.xml32
-rw-r--r--tests/tunerunit/src/com/android/tv/tuner/exoplayer/buffer/VerySlowSampleChunk.java51
-rw-r--r--tests/tunerunit/src/com/android/tv/tuner/exoplayer/tests/AssetDataSource.java124
-rw-r--r--tests/tunerunit/src/com/android/tv/tuner/exoplayer/tests/SampleSourceExtractorTest.java246
-rw-r--r--tests/unit/src/com/android/tv/BaseMainActivityTestCase.java2
-rw-r--r--tests/unit/src/com/android/tv/CurrentPositionMediatorTest.java34
-rw-r--r--tests/unit/src/com/android/tv/FeaturesTest.java7
-rw-r--r--tests/unit/src/com/android/tv/MainActivityTest.java15
-rw-r--r--tests/unit/src/com/android/tv/TimeShiftManagerTest.java47
-rw-r--r--tests/unit/src/com/android/tv/data/ChannelDataManagerTest.java131
-rw-r--r--tests/unit/src/com/android/tv/data/ChannelNumberTest.java89
-rw-r--r--tests/unit/src/com/android/tv/data/ChannelTest.java35
-rw-r--r--tests/unit/src/com/android/tv/data/GenreItemTest.java31
-rw-r--r--tests/unit/src/com/android/tv/data/ProgramDataManagerTest.java114
-rw-r--r--tests/unit/src/com/android/tv/data/ProgramTest.java40
-rw-r--r--tests/unit/src/com/android/tv/data/TvInputNewComparatorTest.java3
-rw-r--r--tests/unit/src/com/android/tv/data/WatchedHistoryManagerTest.java41
-rw-r--r--tests/unit/src/com/android/tv/dvr/BaseDvrDataManagerTest.java89
-rw-r--r--tests/unit/src/com/android/tv/dvr/DvrDataManagerImplTest.java81
-rw-r--r--tests/unit/src/com/android/tv/dvr/DvrDataManagerInMemoryImpl.java310
-rw-r--r--tests/unit/src/com/android/tv/dvr/DvrScheduleManagerTest.java831
-rw-r--r--tests/unit/src/com/android/tv/dvr/ScheduledRecordingTest.java119
-rw-r--r--tests/unit/src/com/android/tv/dvr/data/SeriesRecordingTest.java140
-rw-r--r--tests/unit/src/com/android/tv/dvr/provider/DvrDbSyncTest.java168
-rw-r--r--tests/unit/src/com/android/tv/dvr/provider/EpisodicProgramLoadTaskTest.java89
-rw-r--r--tests/unit/src/com/android/tv/dvr/recorder/InputTaskSchedulerTest.java251
-rw-r--r--tests/unit/src/com/android/tv/dvr/recorder/RecordingTaskTest.java157
-rw-r--r--tests/unit/src/com/android/tv/dvr/recorder/ScheduledProgramReaperTest.java136
-rw-r--r--tests/unit/src/com/android/tv/dvr/recorder/SchedulerTest.java131
-rw-r--r--tests/unit/src/com/android/tv/dvr/recorder/SeriesRecordingSchedulerTest.java148
-rw-r--r--tests/unit/src/com/android/tv/dvr/ui/SortedArrayAdapterTest.java246
-rw-r--r--tests/unit/src/com/android/tv/experiments/ExperimentsTest.java41
-rw-r--r--tests/unit/src/com/android/tv/menu/TvOptionsRowAdapterTest.java2
-rw-r--r--tests/unit/src/com/android/tv/recommendation/ChannelRecordTest.java2
-rw-r--r--tests/unit/src/com/android/tv/recommendation/EvaluatorTestCase.java2
-rw-r--r--tests/unit/src/com/android/tv/recommendation/RecommendationUtils.java2
-rw-r--r--tests/unit/src/com/android/tv/recommendation/RecommenderTest.java28
-rw-r--r--tests/unit/src/com/android/tv/recommendation/RoutineWatchEvaluatorTest.java40
-rw-r--r--tests/unit/src/com/android/tv/search/LocalSearchProviderTest.java23
-rw-r--r--tests/unit/src/com/android/tv/tests/TvActivityTest.java2
-rw-r--r--tests/unit/src/com/android/tv/util/ImageCacheTest.java3
-rw-r--r--tests/unit/src/com/android/tv/util/MockApplicationSingletons.java (renamed from tests/unit/src/com/android/tv/util/MockTvSingletons.java)72
-rw-r--r--tests/unit/src/com/android/tv/util/MultiLongSparseArrayTest.java104
-rw-r--r--tests/unit/src/com/android/tv/util/ScaledBitmapInfoTest.java18
-rw-r--r--tests/unit/src/com/android/tv/util/TvInputManagerHelperTest.java3
-rw-r--r--tests/unit/src/com/android/tv/util/TvTrackInfoUtilsTest.java3
-rw-r--r--tests/unit/src/com/android/tv/util/UtilsTest_GetDurationString.java446
-rw-r--r--tests/unit/src/com/android/tv/util/UtilsTest_GetMultiAudioString.java107
-rw-r--r--tests/unit/src/com/android/tv/util/UtilsTest_IsInGivenDay.java65
-rw-r--r--tuner/Android.mk46
-rw-r--r--tuner/AndroidManifest.xml22
-rw-r--r--tuner/BuildConfig.java.in8
-rw-r--r--tuner/buildconfig.mk39
-rw-r--r--tuner/src/com/android/tv/tuner/TunerFeatures.java102
-rw-r--r--tuner/src/com/android/tv/tuner/TunerPreferences.java98
-rw-r--r--tuner/src/com/android/tv/tuner/setup/LiveTvTunerSetupActivity.java75
-rw-r--r--tuner/tests/unittests/javatests/AndroidManifest.xml34
-rw-r--r--tuner/tests/unittests/javatests/assets/capture_kqed.tsbin31457280 -> 0 bytes
-rw-r--r--tuner/tests/unittests/javatests/assets/capture_stream.tsbin73699196 -> 0 bytes
-rw-r--r--tuner/tests/unittests/javatests/com/google/android/tv/tuner/FakeTunerHal.java79
-rw-r--r--tuner/tests/unittests/javatests/com/google/android/tv/tuner/FileTunerHal.java274
-rw-r--r--tuner/tests/unittests/javatests/com/google/android/tv/tuner/ZappingTimeTest.java413
-rw-r--r--tuner/tests/unittests/javatests/com/google/android/tv/tuner/layout/tests/AndroidManifest.xml25
-rw-r--r--tuner/tests/unittests/javatests/com/google/android/tv/tuner/layout/tests/ScaledLayoutActivity.java83
-rw-r--r--tuner/tests/unittests/javatests/com/google/android/tv/tuner/layout/tests/ScaledLayoutTest.java147
-rw-r--r--tuner/tests/unittests/javatests/com/google/android/tv/tuner/setup/TunerHalFactoryTest.java79
-rw-r--r--tuner/tests/unittests/javatests/res/layout/activity_scaled_layout_test.xml53
-rw-r--r--tuner/tests/unittests/javatests/res/values/attrs.xml25
-rw-r--r--usbtuner-res/drawable-xhdpi/recommendation_antenna.png (renamed from tuner/res/drawable-xhdpi/recommendation_antenna.png)bin1662 -> 1662 bytes
-rw-r--r--usbtuner-res/drawable-xhdpi/usb_antenna.png (renamed from tuner/res/drawable-xhdpi/usb_antenna.png)bin1639 -> 1639 bytes
-rw-r--r--usbtuner-res/drawable/ut_scan_progress.xml (renamed from tuner/res/drawable/ut_scan_progress.xml)0
-rw-r--r--usbtuner-res/layout/ut_channel_list.xml (renamed from tuner/res/layout/ut_channel_list.xml)0
-rw-r--r--usbtuner-res/layout/ut_channel_scan.xml (renamed from tuner/res/layout/ut_channel_scan.xml)0
-rw-r--r--usbtuner-res/layout/ut_overlay_view.xml (renamed from tuner/res/layout/ut_overlay_view.xml)0
-rw-r--r--usbtuner-res/raw/ut_euro_dvbt_all (renamed from tuner/res/raw/ut_euro_dvbt_all)0
-rw-r--r--usbtuner-res/raw/ut_kr_all (renamed from tuner/res/raw/ut_kr_all)0
-rw-r--r--usbtuner-res/raw/ut_kr_atsc_center_frequencies_8vsb (renamed from tuner/res/raw/ut_kr_atsc_center_frequencies_8vsb)0
-rw-r--r--usbtuner-res/raw/ut_kr_cable_standard_center_frequencies_qam256 (renamed from tuner/res/raw/ut_kr_cable_standard_center_frequencies_qam256)0
-rw-r--r--usbtuner-res/raw/ut_kr_dev_cj_cable_center_frequencies_qam256 (renamed from tuner/res/raw/ut_kr_dev_cj_cable_center_frequencies_qam256)0
-rw-r--r--usbtuner-res/raw/ut_us_all (renamed from tuner/res/raw/ut_us_all)0
-rw-r--r--usbtuner-res/raw/ut_us_atsc_center_frequencies_8vsb (renamed from tuner/res/raw/ut_us_atsc_center_frequencies_8vsb)0
-rw-r--r--usbtuner-res/raw/ut_us_cable_standard_center_frequencies_qam256 (renamed from tuner/res/raw/ut_us_cable_standard_center_frequencies_qam256)0
-rw-r--r--usbtuner-res/values-af/strings.xml90
-rw-r--r--usbtuner-res/values-am/strings.xml90
-rw-r--r--usbtuner-res/values-ar/strings.xml102
-rw-r--r--usbtuner-res/values-az-rAZ/strings.xml90
-rw-r--r--usbtuner-res/values-bg/strings.xml90
-rw-r--r--usbtuner-res/values-bn-rBD/strings.xml90
-rw-r--r--usbtuner-res/values-ca/strings.xml90
-rw-r--r--usbtuner-res/values-cs/strings.xml96
-rw-r--r--usbtuner-res/values-da/strings.xml90
-rw-r--r--usbtuner-res/values-de/strings.xml90
-rw-r--r--usbtuner-res/values-el/strings.xml90
-rw-r--r--usbtuner-res/values-en-rAU/strings.xml90
-rw-r--r--usbtuner-res/values-en-rGB/strings.xml90
-rw-r--r--usbtuner-res/values-en-rIN/strings.xml90
-rw-r--r--usbtuner-res/values-es-rUS/strings.xml90
-rw-r--r--usbtuner-res/values-es/strings.xml90
-rw-r--r--usbtuner-res/values-et-rEE/strings.xml90
-rw-r--r--usbtuner-res/values-eu-rES/strings.xml90
-rw-r--r--usbtuner-res/values-fa/strings.xml90
-rw-r--r--usbtuner-res/values-fi/strings.xml90
-rw-r--r--usbtuner-res/values-fr-rCA/strings.xml90
-rw-r--r--usbtuner-res/values-fr/strings.xml90
-rw-r--r--usbtuner-res/values-gl-rES/strings.xml90
-rw-r--r--usbtuner-res/values-hi/strings.xml90
-rw-r--r--usbtuner-res/values-hr/strings.xml93
-rw-r--r--usbtuner-res/values-hu/strings.xml90
-rw-r--r--usbtuner-res/values-hy-rAM/strings.xml90
-rw-r--r--usbtuner-res/values-in/strings.xml90
-rw-r--r--usbtuner-res/values-is-rIS/strings.xml90
-rw-r--r--usbtuner-res/values-it/strings.xml90
-rw-r--r--usbtuner-res/values-iw/strings.xml96
-rw-r--r--usbtuner-res/values-ja/strings.xml90
-rw-r--r--usbtuner-res/values-ka-rGE/strings.xml90
-rw-r--r--usbtuner-res/values-kk-rKZ/strings.xml90
-rw-r--r--usbtuner-res/values-km-rKH/strings.xml90
-rw-r--r--usbtuner-res/values-kn-rIN/strings.xml90
-rw-r--r--usbtuner-res/values-ko/strings.xml90
-rw-r--r--usbtuner-res/values-ky-rKG/strings.xml90
-rw-r--r--usbtuner-res/values-lo-rLA/strings.xml90
-rw-r--r--usbtuner-res/values-lt/strings.xml96
-rw-r--r--usbtuner-res/values-lv/strings.xml93
-rw-r--r--usbtuner-res/values-mk-rMK/strings.xml90
-rw-r--r--usbtuner-res/values-ml-rIN/strings.xml90
-rw-r--r--usbtuner-res/values-mn-rMN/strings.xml90
-rw-r--r--usbtuner-res/values-mr-rIN/strings.xml90
-rw-r--r--usbtuner-res/values-ms-rMY/strings.xml90
-rw-r--r--usbtuner-res/values-my-rMM/strings.xml90
-rw-r--r--usbtuner-res/values-nb/strings.xml90
-rw-r--r--usbtuner-res/values-ne-rNP/strings.xml90
-rw-r--r--usbtuner-res/values-nl/strings.xml90
-rw-r--r--usbtuner-res/values-pl/strings.xml96
-rw-r--r--usbtuner-res/values-pt-rPT/strings.xml90
-rw-r--r--usbtuner-res/values-pt/strings.xml90
-rw-r--r--usbtuner-res/values-ro/strings.xml93
-rw-r--r--usbtuner-res/values-ru/strings.xml92
-rw-r--r--usbtuner-res/values-si-rLK/strings.xml90
-rw-r--r--usbtuner-res/values-sk/strings.xml96
-rw-r--r--usbtuner-res/values-sl/strings.xml96
-rw-r--r--usbtuner-res/values-sr/strings.xml93
-rw-r--r--usbtuner-res/values-sv/strings.xml90
-rw-r--r--usbtuner-res/values-sw/strings.xml90
-rw-r--r--usbtuner-res/values-ta-rIN/strings.xml90
-rw-r--r--usbtuner-res/values-te-rIN/strings.xml90
-rw-r--r--usbtuner-res/values-th/strings.xml90
-rw-r--r--usbtuner-res/values-tl/strings.xml90
-rw-r--r--usbtuner-res/values-tr/strings.xml90
-rw-r--r--usbtuner-res/values-uk/strings.xml96
-rw-r--r--usbtuner-res/values-ur-rPK/strings.xml90
-rw-r--r--usbtuner-res/values-uz-rUZ/strings.xml90
-rw-r--r--usbtuner-res/values-vi/strings.xml90
-rw-r--r--usbtuner-res/values-zh-rCN/strings.xml90
-rw-r--r--usbtuner-res/values-zh-rHK/strings.xml90
-rw-r--r--usbtuner-res/values-zh-rTW/strings.xml90
-rw-r--r--usbtuner-res/values-zu/strings.xml90
-rw-r--r--usbtuner-res/values/attrs.xml (renamed from tuner/res/values/attrs.xml)0
-rw-r--r--usbtuner-res/values/colors.xml (renamed from tuner/res/values/colors.xml)0
-rw-r--r--usbtuner-res/values/dimens.xml (renamed from tuner/res/values/dimens.xml)0
-rw-r--r--usbtuner-res/values/integers.xml (renamed from tuner/res/values/integers.xml)0
-rw-r--r--usbtuner-res/values/strings.xml (renamed from tuner/res/values/strings.xml)46
-rw-r--r--usbtuner-res/xml/ut_tvinputservice.xml (renamed from tuner/res/xml/ut_tvinputservice.xml)2
-rw-r--r--version.mk6
513 files changed, 16166 insertions, 11624 deletions
diff --git a/Android.mk b/Android.mk
index 29729415..07f17e68 100644
--- a/Android.mk
+++ b/Android.mk
@@ -23,7 +23,9 @@ LOCAL_MODULE_TAGS := optional
include $(LOCAL_PATH)/version.mk
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := \
+ $(call all-java-files-under, src) \
+ $(call all-proto-files-under, proto)
LOCAL_PACKAGE_NAME := LiveTv
@@ -38,14 +40,18 @@ LOCAL_MIN_SDK_VERSION := 23 # M
LOCAL_USE_AAPT2 := true
LOCAL_RESOURCE_DIR := \
- $(LOCAL_PATH)/common/res \
- $(LOCAL_PATH)/tuner/res \
$(LOCAL_PATH)/res \
+ $(LOCAL_PATH)/usbtuner-res
+
+LOCAL_SRC_FILES += \
+ src/com/android/tv/tuner/exoplayer/ffmpeg/IFfmpegDecoder.aidl
LOCAL_STATIC_JAVA_LIBRARIES := \
- android-support-annotations \
- javax-annotations-jar \
- jsr330-jar \
+ icu4j-usbtuner \
+ lib-exoplayer \
+ lib-exoplayer-v2 \
+ lib-exoplayer-v2-ext-ffmpeg \
+ android-support-annotations
LOCAL_STATIC_ANDROID_LIBRARIES := \
android-support-compat \
@@ -54,8 +60,7 @@ LOCAL_STATIC_ANDROID_LIBRARIES := \
android-support-v7-palette \
android-support-v7-recyclerview \
android-support-v17-leanback \
- live-tv-tuner \
- tv-common \
+ tv-common
LOCAL_JAVACFLAGS := -Xlint:deprecation -Xlint:unchecked
@@ -63,11 +68,33 @@ LOCAL_AAPT_FLAGS += \
--version-name "$(version_name_package)" \
--version-code $(version_code_package) \
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+
LOCAL_JNI_SHARED_LIBRARIES := libtunertvinput_jni
LOCAL_AAPT_FLAGS += --extra-packages com.android.tv.tuner
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/proto/
+
include $(BUILD_PACKAGE)
+# --------------------------------------------------------------
+# Build a tiny icu4j library out of the classes necessary for the project.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := icu4j-usbtuner
+LOCAL_MODULE_TAGS := optional
+icu4j_path := icu/icu4j
+LOCAL_SRC_FILES := \
+ $(icu4j_path)/main/classes/core/src/com/ibm/icu/text/SCSU.java \
+ $(icu4j_path)/main/classes/core/src/com/ibm/icu/text/UnicodeDecompressor.java
+LOCAL_SDK_VERSION := system_current
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
#############################################################
# Pre-built dependency jars
#############################################################
@@ -76,17 +103,13 @@ include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
- lib-exoplayer:libs/exoplayer-r1.5.16.aar \
- lib-exoplayer-v2-core:libs/exoplayer-core-2-SNAPHOT-20180114.aar \
-
-# TODO use external/jsr330
-LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES += auto-value-jar:../../../prebuilts/tools/common/m2/repository/com/google/auto/value/auto-value/1.5.2/auto-value-1.5.2.jar
-LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES += guava-22-0-jar:../../../prebuilts/tools/common/m2/repository/com/google/guava/guava/22.0/guava-22.0.jar
-LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES += javax-annotations-jar:../../../prebuilts/tools/common/m2/repository/javax/annotation/javax.annotation-api/1.2/javax.annotation-api-1.2.jar
-LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES += jsr330-jar:../../../prebuilts/tools/common/m2/repository/javax/inject/javax.inject/1/javax.inject-1.jar
-LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES += truth-0-36-prebuilt-jar:../../../prebuilts/tools/common/m2/repository/com/google/truth/truth/0.36/truth-0.36.jar
+ lib-exoplayer:libs/exoplayer.jar \
+ lib-exoplayer-v2:libs/exoplayer_v2.jar \
+ lib-exoplayer-v2-ext-ffmpeg:libs/exoplayer_v2_ext_ffmpeg.jar \
include $(BUILD_MULTI_PREBUILT)
+
include $(call all-makefiles-under,$(LOCAL_PATH))
+
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 88c86e31..8770301e 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -22,7 +22,6 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_HDMI_CEC_ACTIVE_SOURCE" />
<uses-permission android:name="android.permission.GLOBAL_SEARCH" tools:ignore="ProtectedPermissions"/>
- <uses-permission android:name="android.permission.HDMI_CEC" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.MODIFY_PARENTAL_CONTROLS" />
<uses-permission android:name="android.permission.READ_CONTENT_RATING_SYSTEMS" />
@@ -43,6 +42,7 @@
<uses-feature android:name="android.software.live_tv" android:required="true" />
<uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
+
<!-- Receives input events from the TV app. -->
<permission android:name="com.android.tv.permission.RECEIVE_INPUT_EVENT"
android:protectionLevel="signatureOrSystem"
@@ -59,9 +59,9 @@
<uses-sdk android:targetSdkVersion="26" android:minSdkVersion="23"/>
<application android:label="@string/app_name"
- android:name="com.android.tv.app.LiveTvApplication"
+ android:name=".TvApplication"
android:allowBackup="true"
- android:icon="@drawable/ic_live_channels"
+ android:icon="@drawable/ic_launcher"
android:banner="@drawable/banner"
android:supportsRtl="true"
android:theme="@style/Theme.TV">
@@ -100,11 +100,11 @@
android:resource="@xml/searchable" />
</activity>
- <activity android:name="com.android.tv.LauncherActivity"
+ <activity android:name=".LauncherActivity"
android:configChanges="keyboard|keyboardHidden"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
- <activity android:name="com.android.tv.SetupPassthroughActivity"
+ <activity android:name=".SetupPassthroughActivity"
android:configChanges="keyboard|keyboardHidden"
android:theme="@android:style/Theme.Translucent.NoTitleBar">
<intent-filter>
@@ -113,17 +113,17 @@
</intent-filter>
</activity>
- <activity android:name="com.android.tv.SelectInputActivity"
+ <activity android:name=".SelectInputActivity"
android:configChanges="keyboard|keyboardHidden"
android:launchMode="singleTask"
android:theme="@style/Theme.SelectInputActivity" />
- <activity android:name="com.android.tv.onboarding.OnboardingActivity"
+ <activity android:name=".onboarding.OnboardingActivity"
android:configChanges="keyboard|keyboardHidden"
android:launchMode="singleTop"
android:theme="@style/Theme.Setup.GuidedStep" />
- <activity android:name="com.android.tv.dvr.ui.browse.DvrBrowseActivity"
+ <activity android:name=".dvr.ui.browse.DvrBrowseActivity"
android:configChanges="keyboard|keyboardHidden"
android:launchMode="singleTask"
android:theme="@style/Theme.Leanback.Browse">
@@ -138,7 +138,7 @@
</intent-filter>
</activity>
- <activity android:name="com.android.tv.dvr.ui.playback.DvrPlaybackActivity"
+ <activity android:name=".dvr.ui.playback.DvrPlaybackActivity"
android:configChanges="keyboard|keyboardHidden|screenSize|smallestScreenSize|screenLayout|orientation"
android:launchMode="singleTask"
android:theme="@style/Theme.Leanback">
@@ -149,36 +149,35 @@
</intent-filter>
</activity>
- <activity android:name="com.android.tv.dvr.ui.browse.DvrDetailsActivity"
+ <activity android:name=".dvr.ui.browse.DvrDetailsActivity"
android:configChanges="keyboard|keyboardHidden"
android:theme="@style/Theme.TV.Dvr.Browse.Details" />
- <activity android:name="com.android.tv.dvr.ui.DvrSeriesSettingsActivity"
+ <activity android:name=".dvr.ui.DvrSeriesSettingsActivity"
android:configChanges="keyboard|keyboardHidden"
android:theme="@style/Theme.TV.Dvr.Series.Settings.GuidedStep" />
- <activity android:name="com.android.tv.dvr.ui.DvrSeriesDeletionActivity"
+ <activity android:name=".dvr.ui.DvrSeriesDeletionActivity"
android:configChanges="keyboard|keyboardHidden"
android:theme="@style/Theme.TV.Dvr.Series.Deletion.GuidedStep" />
- <activity android:name="com.android.tv.dvr.ui.DvrSeriesScheduledDialogActivity"
+ <activity android:name=".dvr.ui.DvrSeriesScheduledDialogActivity"
android:theme="@style/Theme.TV.dialog.HalfSizedDialog"/>
- <activity android:name="com.android.tv.dvr.ui.list.DvrSchedulesActivity"
+ <activity android:name=".dvr.ui.list.DvrSchedulesActivity"
android:configChanges="keyboard|keyboardHidden"
android:theme="@style/Theme.Leanback.Details" />
<provider android:name="com.android.tv.search.LocalSearchProvider"
android:authorities="com.android.tv.search"
android:exported="true"
- android:enabled="true" tools:ignore="ExportedContentProvider"
- >
+ android:enabled="true" tools:ignore="ExportedContentProvider">
<meta-data android:name="SupportedSwitchActionType" android:value="CHANNEL|TVINPUT" />
</provider>
<service android:name="com.android.tv.recommendation.NotificationService"
android:exported="false" />
- <service android:name="com.android.tv.recommendation.ChannelPreviewUpdater$ChannelPreviewUpdateService"
+ <service android:name=".recommendation.ChannelPreviewUpdater$ChannelPreviewUpdateService"
android:permission="android.permission.BIND_JOB_SERVICE" />
<receiver android:name="com.android.tv.receiver.BootCompletedReceiver">
@@ -213,7 +212,7 @@
</receiver>
<!-- USB tuner components definition -->
- <activity android:name="com.android.tv.tuner.setup.LiveTvTunerSetupActivity"
+ <activity android:name="com.android.tv.tuner.setup.TunerSetupActivity"
android:configChanges="keyboard|keyboardHidden"
android:label="@string/bt_app_name"
android:launchMode="singleInstance"
@@ -224,7 +223,7 @@
</intent-filter>
</activity>
- <service android:name="com.android.tv.tuner.tvinput.LiveTvTunerTvInputService"
+ <service android:name=".tuner.tvinput.TunerTvInputService"
android:enabled="false"
android:process="com.android.tv.tuner"
android:label="@string/bt_app_name"
@@ -235,13 +234,19 @@
<meta-data android:name="android.media.tv.input"
android:resource="@xml/ut_tvinputservice" />
</service>
-
- <provider android:name="com.android.tv.common.CommonPreferenceProvider"
- android:authorities="com.android.tv.common.preferences"
- android:process="com.android.tv.common"
+ <service android:name=".tuner.exoplayer.ffmpeg.FfmpegDecoderService"
+ android:isolatedProcess="true"
+ android:process="com.android.tv.ffmpeg" >
+ <intent-filter>
+ <action android:name=".tuner.exoplayer.ffmpeg.IFfmpegDecoder" />
+ </intent-filter>
+ </service>
+ <provider android:name=".tuner.TunerPreferenceProvider"
+ android:authorities="com.android.tv.tuner.preferences"
+ android:process="com.android.tv.tuner"
android:exported="false" />
<!-- System initial setup component definition -->
- <activity android:name="com.android.tv.setup.SystemSetupActivity"
+ <activity android:name=".setup.SystemSetupActivity"
android:configChanges="keyboard|keyboardHidden"
android:label="@string/bt_app_name"
android:launchMode="singleInstance"
@@ -252,7 +257,7 @@
</intent-filter>
</activity>
<!-- TunerInputController should be the same process with MainActivity to check status of MainActivity -->
- <receiver android:name="com.android.tv.tuner.TunerInputController$IntentReceiver"
+ <receiver android:name=".tuner.TunerInputController$IntentReceiver"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
@@ -265,16 +270,17 @@
</receiver>
<!-- DVR -->
- <service android:name="com.android.tv.dvr.recorder.DvrRecordingService" android:label="@string/dvr_service_name" />
- <receiver android:name="com.android.tv.dvr.recorder.DvrStartRecordingReceiver" />
+ <service android:name=".dvr.recorder.DvrRecordingService" android:label="@string/dvr_service_name" />
+ <receiver android:name=".dvr.recorder.DvrStartRecordingReceiver" />
- <service android:name="com.android.tv.tuner.tvinput.TunerStorageCleanUpService"
+ <service android:name=".tuner.tvinput.TunerStorageCleanUpService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:process="com.android.tv.tuner"
android:exported="true" />
- <service android:name="com.android.tv.data.epg.EpgFetchService"
+ <service android:name=".data.epg.EpgFetcher$EpgFetchService"
android:permission="android.permission.BIND_JOB_SERVICE" />
+
</application>
</manifest>
diff --git a/common/BuildConfig.java.in b/common/BuildConfig.java.in
index 10816db1..f4631340 100644
--- a/common/BuildConfig.java.in
+++ b/common/BuildConfig.java.in
@@ -4,6 +4,5 @@ package com.android.tv.common;
public final class BuildConfig {
public static final boolean DEBUG = %DEBUG%;
public static final boolean ENG = %ENG%;
- public static final boolean NO_JNI_TEST = false;
private BuildConfig() {}
} \ No newline at end of file
diff --git a/common/res/values/strings.xml b/common/res/values/strings.xml
index aa7adac4..ec029136 100644
--- a/common/res/values/strings.xml
+++ b/common/res/values/strings.xml
@@ -18,7 +18,6 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done">Done</string>
<string name="action_text_skip">Skip</string>
- <string name="action_text_retry">Retry</string>
<!-- The episode display format with season and episode number used in series details view.
"S" is an abbreviation for Season and "Ep." is an abbreviation for episode. ":" is used as a separator.
For example, "S1: Ep. 1"-->
diff --git a/common/src/com/android/tv/common/util/AutoCloseableUtils.java b/common/src/com/android/tv/common/AutoCloseableUtils.java
index 605715ef..03d7bd9a 100644
--- a/common/src/com/android/tv/common/util/AutoCloseableUtils.java
+++ b/common/src/com/android/tv/common/AutoCloseableUtils.java
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.tv.common.util;
+package com.android.tv.common;
import android.util.Log;
diff --git a/common/src/com/android/tv/common/BaseApplication.java b/common/src/com/android/tv/common/BaseApplication.java
deleted file mode 100644
index 75e689ad..00000000
--- a/common/src/com/android/tv/common/BaseApplication.java
+++ /dev/null
@@ -1,112 +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 android.annotation.TargetApi;
-import android.app.Application;
-import android.content.Context;
-import android.content.Intent;
-import android.os.AsyncTask;
-import android.os.Build;
-import android.os.StrictMode;
-import android.support.annotation.VisibleForTesting;
-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 com.android.tv.common.util.PermissionUtils;
-import com.android.tv.common.util.SystemProperties;
-
-/** The base application class for Live TV applications. */
-public abstract class BaseApplication extends Application implements BaseSingletons {
- private RecordingStorageStatusManager mRecordingStorageStatusManager;
-
- /**
- * An instance of {@link BaseSingletons}. Note that this can be set directly only for the test
- * purpose.
- */
- @VisibleForTesting public static BaseSingletons sSingletons;
-
- /** Returns the {@link BaseSingletons} using the application context. */
- public static BaseSingletons getSingletons(Context context) {
- // STOP-SHIP: changing the method to protected once the Tuner application is created.
- // No need to be "synchronized" because this doesn't create any instance.
- if (sSingletons == null) {
- sSingletons = (BaseSingletons) context.getApplicationContext();
- }
- return sSingletons;
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- if (!PermissionUtils.hasInternet(this)) {
- // When an isolated process starts, just skip all the initialization.
- return;
- }
- Debug.getTimer(Debug.TAG_START_UP_TIMER).start();
- Debug.getTimer(Debug.TAG_START_UP_TIMER)
- .log("Start " + this.getClass().getSimpleName() + ".onCreate");
- CommonPreferences.initialize(this);
-
- // Only set StrictMode for ENG builds because the build server only produces userdebug
- // builds.
- 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.
- StrictMode.VmPolicy.Builder vmPolicyBuilder =
- new StrictMode.VmPolicy.Builder().detectAll().penaltyLog();
-
- if (!CommonUtils.isRunningInTest()) {
- threadPolicyBuilder.penaltyDialog();
- }
- StrictMode.setThreadPolicy(threadPolicyBuilder.build());
- StrictMode.setVmPolicy(vmPolicyBuilder.build());
- }
- if (CommonFeatures.DVR.isEnabled(this)) {
- getRecordingStorageStatusManager();
- }
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... params) {
- // Fetch remote config
- getRemoteConfig().fetch(null);
- return null;
- }
- }.execute();
- }
-
- @Override
- public Clock getClock() {
- return Clock.SYSTEM;
- }
-
- /** Returns {@link RecordingStorageStatusManager}. */
- @Override
- @TargetApi(Build.VERSION_CODES.N)
- public RecordingStorageStatusManager getRecordingStorageStatusManager() {
- if (mRecordingStorageStatusManager == null) {
- mRecordingStorageStatusManager = new RecordingStorageStatusManager(this);
- }
- return mRecordingStorageStatusManager;
- }
-
- @Override
- public abstract Intent getTunerSetupIntent(Context context);
-}
diff --git a/common/src/com/android/tv/common/BaseSingletons.java b/common/src/com/android/tv/common/BaseSingletons.java
deleted file mode 100644
index e735cdb4..00000000
--- a/common/src/com/android/tv/common/BaseSingletons.java
+++ /dev/null
@@ -1,35 +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 android.content.Context;
-import android.content.Intent;
-import com.android.tv.common.config.api.RemoteConfig.HasRemoteConfig;
-import com.android.tv.common.recording.RecordingStorageStatusManager;
-import com.android.tv.common.util.Clock;
-
-/** Injection point for the base app */
-public interface BaseSingletons extends HasRemoteConfig {
-
- Clock getClock();
-
- RecordingStorageStatusManager getRecordingStorageStatusManager();
-
- Intent getTunerSetupIntent(Context context);
-
- String getEmbeddedTunerInputId();
-}
diff --git a/common/src/com/android/tv/common/util/CollectionUtils.java b/common/src/com/android/tv/common/CollectionUtils.java
index 8ca7e3cc..79f6a9e0 100644
--- a/common/src/com/android/tv/common/util/CollectionUtils.java
+++ b/common/src/com/android/tv/common/CollectionUtils.java
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.tv.common.util;
+package com.android.tv.common;
import java.util.ArrayList;
import java.util.Arrays;
diff --git a/common/src/com/android/tv/common/util/SharedPreferencesUtils.java b/common/src/com/android/tv/common/SharedPreferencesUtils.java
index f93951dd..18f5d7bb 100644
--- a/common/src/com/android/tv/common/util/SharedPreferencesUtils.java
+++ b/common/src/com/android/tv/common/SharedPreferencesUtils.java
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.tv.common.util;
+package com.android.tv.common;
import android.content.Context;
import android.os.AsyncTask;
@@ -28,8 +28,7 @@ public final class SharedPreferencesUtils {
public static final String SHARED_PREF_WATCHED_HISTORY = "watched_history_shared_preference";
public static final String SHARED_PREF_DVR_WATCHED_POSITION =
"dvr_watched_position_shared_preference";
- public static final String SHARED_PREF_AUDIO_CAPABILITIES =
- "com.android.tv.audio_capabilities";
+ public static final String SHARED_PREF_AUDIO_CAPABILITIES = "com.android.tv.audio_capabilities";
public static final String SHARED_PREF_RECURRING_RUNNER = "sharedPreferencesRecurringRunner";
public static final String SHARED_PREF_EPG = "epg_preferences";
public static final String SHARED_PREF_SERIES_RECORDINGS = "seriesRecordings";
diff --git a/common/src/com/android/tv/common/SoftPreconditions.java b/common/src/com/android/tv/common/SoftPreconditions.java
index 3b0510d8..9fe0137b 100644
--- a/common/src/com/android/tv/common/SoftPreconditions.java
+++ b/common/src/com/android/tv/common/SoftPreconditions.java
@@ -17,11 +17,9 @@
package com.android.tv.common;
import android.content.Context;
-import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
import com.android.tv.common.feature.Feature;
-import com.android.tv.common.util.CommonUtils;
/**
* Simple static methods to be called at the start of your own methods to verify correct arguments
@@ -41,24 +39,13 @@ public final class SoftPreconditions {
* @param expression a boolean expression
* @param tag Used to identify the source of a log message. It usually identifies the class or
* activity where the log call occurs.
- * @param errorMessageTemplate a template for the exception message should the check fail. The
- * message is formed by replacing each {@code %s} placeholder in the template with an
- * argument. These are matched by position - the first {@code %s} gets {@code
- * errorMessageArgs[0]}, etc. Unmatched arguments will be appended to the formatted message
- * in square braces. Unmatched placeholders will be left as-is.
- * @param errorMessageArgs the arguments to be substituted into the message template. Arguments
- * are converted to strings using {@link String#valueOf(Object)}.
+ * @param msg The message you would like logged.
* @return the evaluation result of the boolean expression
* @throws IllegalArgumentException if {@code expression} is true
*/
- public static boolean checkArgument(
- final boolean expression,
- String tag,
- @Nullable String errorMessageTemplate,
- @Nullable Object... errorMessageArgs) {
+ public static boolean checkArgument(final boolean expression, String tag, String msg) {
if (!expression) {
- String msg = format(errorMessageTemplate, errorMessageArgs);
- warn(tag, "Illegal argument", new IllegalArgumentException(msg), msg);
+ warn(tag, "Illegal argument", msg, new IllegalArgumentException(msg));
}
return expression;
}
@@ -81,24 +68,13 @@ public final class SoftPreconditions {
* @param reference an object reference
* @param tag Used to identify the source of a log message. It usually identifies the class or
* activity where the log call occurs.
- * @param errorMessageTemplate a template for the exception message should the check fail. The
- * message is formed by replacing each {@code %s} placeholder in the template with an
- * argument. These are matched by position - the first {@code %s} gets {@code
- * errorMessageArgs[0]}, etc. Unmatched arguments will be appended to the formatted message
- * in square braces. Unmatched placeholders will be left as-is.
- * @param errorMessageArgs the arguments to be substituted into the message template. Arguments
- * are converted to strings using {@link String#valueOf(Object)}.
+ * @param msg The message you would like logged.
* @return true if the object is null
* @throws NullPointerException if {@code reference} is null
*/
- public static <T> T checkNotNull(
- final T reference,
- String tag,
- @Nullable String errorMessageTemplate,
- @Nullable Object... errorMessageArgs) {
+ public static <T> T checkNotNull(final T reference, String tag, String msg) {
if (reference == null) {
- String msg = format(errorMessageTemplate, errorMessageArgs);
- warn(tag, "Null Pointer", new NullPointerException(msg), msg);
+ warn(tag, "Null Pointer", msg, new NullPointerException(msg));
}
return reference;
}
@@ -121,24 +97,13 @@ public final class SoftPreconditions {
* @param expression a boolean expression
* @param tag Used to identify the source of a log message. It usually identifies the class or
* activity where the log call occurs.
- * @param errorMessageTemplate a template for the exception message should the check fail. The
- * message is formed by replacing each {@code %s} placeholder in the template with an
- * argument. These are matched by position - the first {@code %s} gets {@code
- * errorMessageArgs[0]}, etc. Unmatched arguments will be appended to the formatted message
- * in square braces. Unmatched placeholders will be left as-is.
- * @param errorMessageArgs the arguments to be substituted into the message template. Arguments
- * are converted to strings using {@link String#valueOf(Object)}.
+ * @param msg The message you would like logged.
* @return the evaluation result of the boolean expression
* @throws IllegalStateException if {@code expression} is true
*/
- public static boolean checkState(
- final boolean expression,
- String tag,
- @Nullable String errorMessageTemplate,
- @Nullable Object... errorMessageArgs) {
+ public static boolean checkState(final boolean expression, String tag, String msg) {
if (!expression) {
- String msg = format(errorMessageTemplate, errorMessageArgs);
- warn(tag, "Illegal State", new IllegalStateException(msg), msg);
+ warn(tag, "Illegal State", msg, new IllegalStateException(msg));
}
return expression;
}
@@ -170,15 +135,14 @@ public final class SoftPreconditions {
}
/**
- * Throws a {@link RuntimeException} if {@link BuildConfig#ENG} is true and not running in a
- * test, else log a warning.
+ * Throws a {@link RuntimeException} if {@link BuildConfig#ENG} is true, else log a warning.
*
* @param tag Used to identify the source of a log message. It usually identifies the class or
* activity where the log call occurs.
+ * @param msg The message you would like logged
* @param e The exception to wrap with a RuntimeException when thrown.
- * @param msg The message to be logged
*/
- public static void warn(String tag, String prefix, Exception e, String msg)
+ public static void warn(String tag, String prefix, String msg, Exception e)
throws RuntimeException {
if (TextUtils.isEmpty(tag)) {
tag = TAG;
@@ -192,57 +156,12 @@ public final class SoftPreconditions {
logMessage = prefix + ": " + msg;
}
- if (BuildConfig.ENG && !CommonUtils.isRunningInTest()) {
+ if (BuildConfig.ENG) {
throw new RuntimeException(msg, e);
} else {
Log.w(tag, logMessage, e);
}
}
- /**
- * Substitutes each {@code %s} in {@code template} with an argument. These are matched by
- * position: the first {@code %s} gets {@code args[0]}, etc. If there are more arguments than
- * placeholders, the unmatched arguments will be appended to the end of the formatted message in
- * square braces.
- *
- * @param template a string containing 0 or more {@code %s} placeholders. null is treated as
- * "null".
- * @param args the arguments to be substituted into the message template. Arguments are
- * converted to strings using {@link String#valueOf(Object)}. Arguments can be null.
- */
- static String format(@Nullable String template, @Nullable Object... args) {
- template = String.valueOf(template); // null -> "null"
-
- args = args == null ? new Object[] {"(Object[])null"} : args;
-
- // start substituting the arguments into the '%s' placeholders
- StringBuilder builder = new StringBuilder(template.length() + 16 * args.length);
- int templateStart = 0;
- int i = 0;
- while (i < args.length) {
- int placeholderStart = template.indexOf("%s", templateStart);
- if (placeholderStart == -1) {
- break;
- }
- builder.append(template, templateStart, placeholderStart);
- builder.append(args[i++]);
- templateStart = placeholderStart + 2;
- }
- builder.append(template, templateStart, template.length());
-
- // if we run out of placeholders, append the extra args in square braces
- if (i < args.length) {
- builder.append(" [");
- builder.append(args[i++]);
- while (i < args.length) {
- builder.append(", ");
- builder.append(args[i++]);
- }
- builder.append(']');
- }
-
- return builder.toString();
- }
-
private SoftPreconditions() {}
}
diff --git a/common/src/com/android/tv/common/CommonConstants.java b/common/src/com/android/tv/common/TvCommonConstants.java
index 26d68b4d..0c64a346 100644
--- a/common/src/com/android/tv/common/CommonConstants.java
+++ b/common/src/com/android/tv/common/TvCommonConstants.java
@@ -18,15 +18,15 @@ package com.android.tv.common;
import android.media.tv.TvInputInfo;
-/** Constants for common use in apps and tests. */
-public final class CommonConstants {
+/** Constants for common use in TV app and tests. */
+public final class TvCommonConstants {
/** A constant for the key of the extra data for the app linking intent. */
public static final String EXTRA_APP_LINK_CHANNEL_URI = "app_link_channel_uri";
/**
* An intent action to launch setup activity of a TV input. The intent should include TV input
- * ID in the value of {@link #EXTRA_INPUT_ID}. Optionally, given the value of {@link
- * #EXTRA_ACTIVITY_AFTER_COMPLETION}, the activity will be launched after the setup activity
+ * ID in the value of {@link EXTRA_INPUT_ID}. Optionally, given the value of {@link
+ * EXTRA_ACTIVITY_AFTER_COMPLETION}, the activity will be launched after the setup activity
* successfully finishes.
*/
public static final String INTENT_ACTION_INPUT_SETUP =
@@ -34,7 +34,7 @@ public final class CommonConstants {
/**
* A constant of the key to indicate a TV input ID for the intent action {@link
- * #INTENT_ACTION_INPUT_SETUP}.
+ * INTENT_ACTION_INPUT_SETUP}.
*
* <p>Value type: String
*/
@@ -42,7 +42,7 @@ public final class CommonConstants {
/**
* A constant of the key for intent to launch actual TV input setup activity used with {@link
- * #INTENT_ACTION_INPUT_SETUP}.
+ * INTENT_ACTION_INPUT_SETUP}.
*
* <p>Value type: Intent (Parcelable)
*/
@@ -50,12 +50,12 @@ public final class CommonConstants {
/**
* A constant of the key to indicate an Activity launch intent for the intent action {@link
- * #INTENT_ACTION_INPUT_SETUP}.
+ * INTENT_ACTION_INPUT_SETUP}.
*
* <p>Value type: Intent (Parcelable)
*/
public static final String EXTRA_ACTIVITY_AFTER_COMPLETION =
"com.android.tv.intent.extra.ACTIVITY_AFTER_COMPLETION";
- private CommonConstants() {}
+ private TvCommonConstants() {}
}
diff --git a/common/src/com/android/tv/common/TvCommonUtils.java b/common/src/com/android/tv/common/TvCommonUtils.java
new file mode 100644
index 00000000..2172e1c4
--- /dev/null
+++ b/common/src/com/android/tv/common/TvCommonUtils.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 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.common;
+
+import android.content.Intent;
+import android.media.tv.TvInputInfo;
+
+/** Util class for common use in TV app and inputs. */
+public final class TvCommonUtils {
+ private static Boolean sRunningInTest;
+
+ private TvCommonUtils() {}
+
+ /**
+ * Returns an intent to start the setup activity for the TV input using {@link
+ * TvCommonConstants#INTENT_ACTION_INPUT_SETUP}.
+ */
+ public static Intent createSetupIntent(Intent originalSetupIntent, String inputId) {
+ if (originalSetupIntent == null) {
+ return null;
+ }
+ Intent setupIntent = new Intent(originalSetupIntent);
+ if (!TvCommonConstants.INTENT_ACTION_INPUT_SETUP.equals(originalSetupIntent.getAction())) {
+ Intent intentContainer = new Intent(TvCommonConstants.INTENT_ACTION_INPUT_SETUP);
+ intentContainer.putExtra(TvCommonConstants.EXTRA_SETUP_INTENT, originalSetupIntent);
+ intentContainer.putExtra(TvCommonConstants.EXTRA_INPUT_ID, inputId);
+ setupIntent = intentContainer;
+ }
+ return setupIntent;
+ }
+
+ /**
+ * Returns an intent to start the setup activity for this TV input using {@link
+ * TvCommonConstants#INTENT_ACTION_INPUT_SETUP}.
+ */
+ public static Intent createSetupIntent(TvInputInfo input) {
+ return createSetupIntent(input.createSetupIntent(), input.getId());
+ }
+
+ /**
+ * Checks if this application is running in tests.
+ *
+ * <p>{@link android.app.ActivityManager#isRunningInTestHarness} doesn't return {@code true} for
+ * the usual devices even the application is running in tests. We need to figure it out by
+ * checking whether the class in tv-tests-common module can be loaded or not.
+ */
+ public static synchronized boolean isRunningInTest() {
+ if (sRunningInTest == null) {
+ try {
+ Class.forName("com.android.tv.testing.Utils");
+ sRunningInTest = true;
+ } catch (ClassNotFoundException e) {
+ sRunningInTest = false;
+ }
+ }
+ return sRunningInTest;
+ }
+}
diff --git a/common/src/com/android/tv/common/annotation/UsedByNative.java b/common/src/com/android/tv/common/annotation/UsedByNative.java
deleted file mode 100644
index dc829e08..00000000
--- a/common/src/com/android/tv/common/annotation/UsedByNative.java
+++ /dev/null
@@ -1,43 +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.annotation;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Target;
-
-/**
- * Annotation used for marking methods and fields that are called from native
- * code. Useful for keeping components that would otherwise be removed by
- * Proguard. Use the value parameter to mention a file that calls this method.
- *
- * Note that adding this annotation to a method is not enough to guarantee that
- * it is kept - either its class must be referenced elsewhere in the program, or
- * the class must be annotated with this as well.
- *
- * Usage example:<br />
- * <pre>{@code
- * @UsedByNative("NativeCrashHandler.cpp")
- * public static void reportCrash(int signal, int code, int address) {
- * ...
- * }
- * </pre>
- *
- */
-@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE, ElementType.CONSTRUCTOR})
-public @interface UsedByNative {
- String value();
-}
diff --git a/common/src/com/android/tv/common/experiments/ExperimentLoader.java b/common/src/com/android/tv/common/annotation/UsedByReflection.java
index 5f012e11..7e0ac31a 100644
--- a/common/src/com/android/tv/common/experiments/ExperimentLoader.java
+++ b/common/src/com/android/tv/common/annotation/UsedByReflection.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,15 +14,15 @@
* limitations under the License.
*/
-package com.android.tv.common.experiments;
+package com.android.tv.common.annotation;
-import android.content.Context;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
-/** Used to sync {@link ExperimentFlag}s. */
-public class ExperimentLoader {
+import java.lang.annotation.Retention;
- /** Starts a background task to update {@link ExperimentFlag}s */
- public void asyncRefreshExperiments(Context context) {
- // Override for your experiment system
- }
-}
+/**
+ * Denotes that the method or field is used by reflection even though it is not ever called
+ * directly.
+ */
+@Retention(SOURCE)
+public @interface UsedByReflection {}
diff --git a/common/src/com/android/tv/common/feature/CommonFeatures.java b/common/src/com/android/tv/common/feature/CommonFeatures.java
index 8f75d483..792e59c6 100644
--- a/common/src/com/android/tv/common/feature/CommonFeatures.java
+++ b/common/src/com/android/tv/common/feature/CommonFeatures.java
@@ -19,24 +19,12 @@ package com.android.tv.common.feature;
import static com.android.tv.common.feature.FeatureUtils.AND;
import static com.android.tv.common.feature.TestableFeature.createTestableFeature;
-import android.content.Context;
-import android.os.Build;
-import android.text.TextUtils;
-import android.util.Log;
-import com.android.tv.common.config.api.RemoteConfig.HasRemoteConfig;
-import com.android.tv.common.experiments.Experiments;
-import com.android.tv.common.util.CommonUtils;
-import com.android.tv.common.util.LocationUtils;
-
/**
* List of {@link Feature} that affect more than just the Live TV app.
*
* <p>Remove the {@code Feature} once it is launched.
*/
public class CommonFeatures {
- private static final String TAG = "CommonFeatures";
- private static final boolean DEBUG = false;
-
/**
* DVR
*
@@ -53,46 +41,13 @@ public class CommonFeatures {
* <p>Enables dvr recording regardless of storage status.
*/
public static final Feature FORCE_RECORDING_UNTIL_NO_SPACE =
- PropertyFeature.create("force_recording_until_no_space", false);
-
- public static final Feature TUNER =
- new Feature() {
- @Override
- public boolean isEnabled(Context context) {
-
- if (CommonUtils.isDeveloper()) {
- // we enable tuner for developers to test tuner in any platform.
- return true;
- }
-
- // This is special handling just for USB Tuner.
- // It does not require any N API's but relies on a improvements in N for AC3
- // support
- return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;
- }
- };
+ new PropertyFeature("force_recording_until_no_space", false);
- /** Show postal code fragment before channel scan. */
- public static final Feature ENABLE_CLOUD_EPG_REGION =
- new Feature() {
- private final String[] supportedRegions = {
- };
-
-
- @Override
- public boolean isEnabled(Context context) {
- if (!Experiments.CLOUD_EPG.get()) {
- if (DEBUG) Log.d(TAG, "Experiments.CLOUD_EPG is false");
- return false;
- }
- String country = LocationUtils.getCurrentCountry(context);
- for (int i = 0; i < supportedRegions.length; i++) {
- if (supportedRegions[i].equalsIgnoreCase(country)) {
- return true;
- }
- }
- if (DEBUG) Log.d(TAG, "EPG flag false after country check");
- return false;
- }
- };
+ /**
+ * USE_SW_CODEC_FOR_SD
+ *
+ * <p>Prefer software based codec for SD channels.
+ */
+ public static final Feature USE_SW_CODEC_FOR_SD =
+ new PropertyFeature("use_sw_codec_for_sd", false);
}
diff --git a/common/src/com/android/tv/common/feature/ExperimentFeature.java b/common/src/com/android/tv/common/feature/ExperimentFeature.java
deleted file mode 100644
index 820eda49..00000000
--- a/common/src/com/android/tv/common/feature/ExperimentFeature.java
+++ /dev/null
@@ -1,44 +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.feature;
-
-import android.content.Context;
-import com.android.tv.common.experiments.ExperimentFlag;
-
-/** A {@link Feature} base on an {@link ExperimentFlag}. */
-public final class ExperimentFeature implements Feature {
-
- public static Feature from(ExperimentFlag<Boolean> flag) {
- return new ExperimentFeature(flag);
- }
-
- private final ExperimentFlag<Boolean> mFlag;
-
- private ExperimentFeature(ExperimentFlag<Boolean> flag) {
- mFlag = flag;
- }
-
- @Override
- public boolean isEnabled(Context context) {
- 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 8650d151..bbaa2107 100644
--- a/common/src/com/android/tv/common/feature/FeatureUtils.java
+++ b/common/src/com/android/tv/common/feature/FeatureUtils.java
@@ -17,7 +17,6 @@
package com.android.tv.common.feature;
import android.content.Context;
-import com.android.tv.common.util.CommonUtils;
import java.util.Arrays;
/** Static utilities for features. */
@@ -99,19 +98,5 @@ public class FeatureUtils {
}
};
- /** True if running in robolectric. */
- public static final Feature ROBOLECTRIC =
- new Feature() {
- @Override
- public boolean isEnabled(Context context) {
- return CommonUtils.isRoboTest();
- }
-
- @Override
- public String toString() {
- return "isRobolecteric";
- }
- };
-
private FeatureUtils() {}
}
diff --git a/common/src/com/android/tv/common/feature/PropertyFeature.java b/common/src/com/android/tv/common/feature/PropertyFeature.java
index 0cf36317..33227bdf 100644
--- a/common/src/com/android/tv/common/feature/PropertyFeature.java
+++ b/common/src/com/android/tv/common/feature/PropertyFeature.java
@@ -25,11 +25,6 @@ import com.android.tv.common.BooleanSystemProperty;
* <p>See {@link BooleanSystemProperty} for instructions on how to set using adb.
*/
public final class PropertyFeature implements Feature {
-
- public static PropertyFeature create(String key, boolean defaultValue) {
- return new PropertyFeature(key, defaultValue);
- }
-
private final BooleanSystemProperty mProperty;
/**
@@ -38,7 +33,7 @@ public final class PropertyFeature implements Feature {
* @param key the system property key. Length must be <= 31 characters.
* @param defaultValue the value to return if the property is undefined or empty.
*/
- private PropertyFeature(String key, boolean defaultValue) {
+ public PropertyFeature(String key, boolean defaultValue) {
if (key.length() > 31) {
// Since Features are initialized at startup and the keys are static go ahead and kill
// the application.
diff --git a/common/src/com/android/tv/common/feature/Sdk.java b/common/src/com/android/tv/common/feature/Sdk.java
index 5588939f..b6ab04a9 100644
--- a/common/src/com/android/tv/common/feature/Sdk.java
+++ b/common/src/com/android/tv/common/feature/Sdk.java
@@ -29,13 +29,5 @@ public class Sdk {
}
};
- public static final Feature AT_LEAST_O =
- new Feature() {
- @Override
- public boolean isEnabled(Context context) {
- return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
- }
- };
-
private Sdk() {}
}
diff --git a/common/src/com/android/tv/common/feature/SharedPreferencesFeature.java b/common/src/com/android/tv/common/feature/SharedPreferencesFeature.java
index ef2260d6..d4ec81ae 100644
--- a/common/src/com/android/tv/common/feature/SharedPreferencesFeature.java
+++ b/common/src/com/android/tv/common/feature/SharedPreferencesFeature.java
@@ -19,7 +19,7 @@ package com.android.tv.common.feature;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
-import com.android.tv.common.util.SharedPreferencesUtils;
+import com.android.tv.common.SharedPreferencesUtils;
/** Feature controlled by shared preferences. */
public final class SharedPreferencesFeature implements Feature {
diff --git a/common/src/com/android/tv/common/feature/TestableFeature.java b/common/src/com/android/tv/common/feature/TestableFeature.java
index 1f18639d..c37da766 100644
--- a/common/src/com/android/tv/common/feature/TestableFeature.java
+++ b/common/src/com/android/tv/common/feature/TestableFeature.java
@@ -19,7 +19,7 @@ package com.android.tv.common.feature;
import android.content.Context;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
-import com.android.tv.common.util.CommonUtils;
+import com.android.tv.common.TvCommonUtils;
/**
* When run in a test harness this feature can be turned on or off, overriding the normal value.
@@ -56,7 +56,7 @@ public class TestableFeature implements Feature {
@VisibleForTesting
public void enableForTest() {
- if (!CommonUtils.isRunningInTest()) {
+ if (!TvCommonUtils.isRunningInTest()) {
Log.e(TAG, "Not enabling for test:" + this, new IllegalStateException(DETAIL_MESSAGE));
} else {
mTestValue = true;
@@ -65,7 +65,7 @@ public class TestableFeature implements Feature {
@VisibleForTesting
public void disableForTests() {
- if (!CommonUtils.isRunningInTest()) {
+ if (!TvCommonUtils.isRunningInTest()) {
Log.e(
TAG,
"Not disabling for test: " + this,
@@ -77,7 +77,7 @@ public class TestableFeature implements Feature {
@VisibleForTesting
public void resetForTests() {
- if (!CommonUtils.isRunningInTest()) {
+ if (!TvCommonUtils.isRunningInTest()) {
Log.e(TAG, "Not resetting feature: " + this, new IllegalStateException(DETAIL_MESSAGE));
} else {
mTestValue = null;
@@ -86,7 +86,7 @@ public class TestableFeature implements Feature {
@Override
public boolean isEnabled(Context context) {
- if (CommonUtils.isRunningInTest() && mTestValue != null) {
+ if (TvCommonUtils.isRunningInTest() && mTestValue != null) {
return mTestValue;
}
return mDelegate.isEnabled(context);
@@ -95,7 +95,7 @@ public class TestableFeature implements Feature {
@Override
public String toString() {
String msg = mDelegate.toString();
- if (CommonUtils.isRunningInTest()) {
+ if (TvCommonUtils.isRunningInTest()) {
if (mTestValue == null) {
msg = "Testable Feature is unchanged: " + msg;
} else {
diff --git a/common/src/com/android/tv/common/recording/RecordingStorageStatusManager.java b/common/src/com/android/tv/common/recording/RecordingStorageStatusManager.java
deleted file mode 100644
index 8b45a730..00000000
--- a/common/src/com/android/tv/common/recording/RecordingStorageStatusManager.java
+++ /dev/null
@@ -1,256 +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.common.recording;
-
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Environment;
-import android.os.Looper;
-import android.os.StatFs;
-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.feature.CommonFeatures;
-import java.io.File;
-import java.io.IOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.CopyOnWriteArraySet;
-
-/** Signals DVR storage status change such as plugging/unplugging. */
-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
-
- private static final long MIN_FREE_STORAGE_SIZE_FOR_DVR_IN_BYTES =
- 10 * 1024 * 1024 * 1024L; // 10GB
- private static final String RECORDING_DATA_SUB_PATH = "/recording";
-
- /** Storage status constants. */
- @IntDef({
- STORAGE_STATUS_OK,
- STORAGE_STATUS_TOTAL_CAPACITY_TOO_SMALL,
- STORAGE_STATUS_FREE_SPACE_INSUFFICIENT,
- STORAGE_STATUS_MISSING
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface StorageStatus {}
-
- /** Current storage is OK to record a program. */
- public static final int STORAGE_STATUS_OK = 0;
-
- /** Current storage's total capacity is smaller than DVR requirement. */
- public static final int STORAGE_STATUS_TOTAL_CAPACITY_TOO_SMALL = 1;
-
- /** Current storage's free space is insufficient to record programs. */
- public static final int STORAGE_STATUS_FREE_SPACE_INSUFFICIENT = 2;
-
- /** Current storage is missing. */
- public static final int STORAGE_STATUS_MISSING = 3;
-
- private final Context mContext;
- private final Set<OnStorageMountChangedListener> mOnStorageMountChangedListeners =
- new CopyOnWriteArraySet<>();
- private MountedStorageStatus mMountedStorageStatus;
- private boolean mStorageValid;
-
- private class MountedStorageStatus {
- private final boolean mStorageMounted;
- private final File mStorageMountedDir;
- private final long mStorageMountedCapacity;
-
- private MountedStorageStatus(boolean mounted, File mountedDir, long capacity) {
- mStorageMounted = mounted;
- mStorageMountedDir = mountedDir;
- mStorageMountedCapacity = capacity;
- }
-
- private boolean isValidForDvr() {
- return mStorageMounted && mStorageMountedCapacity >= MIN_STORAGE_SIZE_FOR_DVR_IN_BYTES;
- }
-
- @Override
- public boolean equals(Object other) {
- if (!(other instanceof MountedStorageStatus)) {
- return false;
- }
- MountedStorageStatus status = (MountedStorageStatus) other;
- return mStorageMounted == status.mStorageMounted
- && Objects.equals(mStorageMountedDir, status.mStorageMountedDir)
- && mStorageMountedCapacity == status.mStorageMountedCapacity;
- }
- }
-
- public interface OnStorageMountChangedListener {
-
- /**
- * Listener for DVR storage status change.
- *
- * @param storageMounted {@code true} when DVR possible storage is mounted, {@code false}
- * otherwise.
- */
- void onStorageMountChanged(boolean storageMounted);
- }
-
- private final class StorageStatusBroadcastReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- MountedStorageStatus result = getStorageStatusInternal();
- if (mMountedStorageStatus.equals(result)) {
- return;
- }
- mMountedStorageStatus = result;
- if (result.mStorageMounted) {
- cleanUpDbIfNeeded();
- }
- boolean valid = result.isValidForDvr();
- if (valid == mStorageValid) {
- return;
- }
- mStorageValid = valid;
- for (OnStorageMountChangedListener l : mOnStorageMountChangedListeners) {
- l.onStorageMountChanged(valid);
- }
- }
- }
-
- /**
- * Creates RecordingStorageStatusManager.
- *
- * @param context {@link Context}
- */
- public RecordingStorageStatusManager(final Context context) {
- mContext = context;
- mMountedStorageStatus = getStorageStatusInternal();
- mStorageValid = mMountedStorageStatus.isValidForDvr();
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_MEDIA_MOUNTED);
- filter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
- filter.addAction(Intent.ACTION_MEDIA_EJECT);
- filter.addAction(Intent.ACTION_MEDIA_REMOVED);
- filter.addAction(Intent.ACTION_MEDIA_BAD_REMOVAL);
- filter.addDataScheme(ContentResolver.SCHEME_FILE);
- mContext.registerReceiver(new StorageStatusBroadcastReceiver(), filter);
- }
-
- /**
- * Adds the listener for receiving storage status change.
- *
- * @param listener
- */
- public void addListener(OnStorageMountChangedListener listener) {
- mOnStorageMountChangedListeners.add(listener);
- }
-
- /** Removes the current listener. */
- public void removeListener(OnStorageMountChangedListener listener) {
- mOnStorageMountChangedListeners.remove(listener);
- }
-
- /** Returns true if a storage is mounted. */
- public boolean isStorageMounted() {
- return mMountedStorageStatus.mStorageMounted;
- }
-
- /** Returns the path to DVR recording data directory. This can take for a while sometimes. */
- @WorkerThread
- public File getRecordingRootDataDirectory() {
- SoftPreconditions.checkState(Looper.myLooper() != Looper.getMainLooper());
- if (mMountedStorageStatus.mStorageMountedDir == null) {
- return null;
- }
- File root = mContext.getExternalFilesDir(null);
- String rootPath;
- try {
- rootPath = root != null ? root.getCanonicalPath() : null;
- } catch (IOException | SecurityException e) {
- return null;
- }
- return rootPath == null ? null : new File(rootPath + RECORDING_DATA_SUB_PATH);
- }
-
- /**
- * Returns the current storage status for DVR recordings.
- *
- * @return {@link StorageStatus}
- */
- @AnyThread
- public @StorageStatus int getDvrStorageStatus() {
- MountedStorageStatus status = mMountedStorageStatus;
- if (status.mStorageMountedDir == null) {
- return STORAGE_STATUS_MISSING;
- }
- if (CommonFeatures.FORCE_RECORDING_UNTIL_NO_SPACE.isEnabled(mContext)) {
- return STORAGE_STATUS_OK;
- }
- if (status.mStorageMountedCapacity < MIN_STORAGE_SIZE_FOR_DVR_IN_BYTES) {
- return STORAGE_STATUS_TOTAL_CAPACITY_TOO_SMALL;
- }
- try {
- StatFs statFs = new StatFs(status.mStorageMountedDir.toString());
- if (statFs.getAvailableBytes() < MIN_FREE_STORAGE_SIZE_FOR_DVR_IN_BYTES) {
- return STORAGE_STATUS_FREE_SPACE_INSUFFICIENT;
- }
- } catch (IllegalArgumentException e) {
- // In rare cases, storage status change was not notified yet.
- SoftPreconditions.checkState(false);
- return STORAGE_STATUS_FREE_SPACE_INSUFFICIENT;
- }
- return STORAGE_STATUS_OK;
- }
-
- /**
- * Returns whether the storage has sufficient storage.
- *
- * @return {@code true} when there is sufficient storage, {@code false} otherwise
- */
- public boolean isStorageSufficient() {
- return getDvrStorageStatus() == STORAGE_STATUS_OK;
- }
-
- /** APPs that want to clean up DB for recordings should override this method to do the job. */
- protected void cleanUpDbIfNeeded() {}
-
- private MountedStorageStatus getStorageStatusInternal() {
- boolean storageMounted =
- Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
- File storageMountedDir = storageMounted ? Environment.getExternalStorageDirectory() : null;
- storageMounted = storageMounted && storageMountedDir != null;
- long storageMountedCapacity = 0L;
- if (storageMounted) {
- try {
- StatFs statFs = new StatFs(storageMountedDir.toString());
- storageMountedCapacity = statFs.getTotalBytes();
- } catch (IllegalArgumentException e) {
- Log.e(TAG, "Storage mount status was changed.");
- storageMounted = false;
- storageMountedDir = null;
- }
- }
- return new MountedStorageStatus(storageMounted, storageMountedDir, storageMountedCapacity);
- }
-}
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 59ac5b02..7a649285 100644
--- a/common/src/com/android/tv/common/ui/setup/SetupGuidedStepFragment.java
+++ b/common/src/com/android/tv/common/ui/setup/SetupGuidedStepFragment.java
@@ -16,8 +16,6 @@
package com.android.tv.common.ui.setup;
-import static android.content.Context.ACCESSIBILITY_SERVICE;
-
import android.os.Bundle;
import android.support.v17.leanback.app.GuidedStepFragment;
import android.support.v17.leanback.widget.GuidanceStylist;
@@ -27,7 +25,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.MarginLayoutParams;
-import android.view.accessibility.AccessibilityManager;
import android.widget.LinearLayout;
import com.android.tv.common.R;
@@ -40,8 +37,6 @@ public abstract class SetupGuidedStepFragment extends GuidedStepFragment {
*/
public static final String KEY_THREE_PANE = "key_three_pane";
- private View mContentFragment;
-
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@@ -49,9 +44,10 @@ public abstract class SetupGuidedStepFragment extends GuidedStepFragment {
Bundle arguments = getArguments();
view.findViewById(android.support.v17.leanback.R.id.action_fragment_root)
.setPadding(0, 0, 0, 0);
- mContentFragment = view.findViewById(android.support.v17.leanback.R.id.content_fragment);
LinearLayout.LayoutParams guidanceLayoutParams =
- (LinearLayout.LayoutParams) mContentFragment.getLayoutParams();
+ (LinearLayout.LayoutParams)
+ view.findViewById(android.support.v17.leanback.R.id.content_fragment)
+ .getLayoutParams();
guidanceLayoutParams.weight = 0;
if (arguments != null && arguments.getBoolean(KEY_THREE_PANE, false)) {
// Content fragment.
@@ -99,17 +95,6 @@ public abstract class SetupGuidedStepFragment extends GuidedStepFragment {
}
@Override
- public void onResume() {
- super.onResume();
- AccessibilityManager am =
- (AccessibilityManager) getActivity().getSystemService(ACCESSIBILITY_SERVICE);
- if (am.isEnabled() && am.isTouchExplorationEnabled()) {
- mContentFragment.setFocusable(true);
- mContentFragment.requestFocus();
- }
- }
-
- @Override
public GuidanceStylist onCreateGuidanceStylist() {
return new GuidanceStylist() {
@Override
@@ -127,10 +112,6 @@ public abstract class SetupGuidedStepFragment extends GuidedStepFragment {
protected abstract String getActionCategory();
- protected View getDoneButton() {
- return getActivity().findViewById(R.id.button_done);
- }
-
@Override
public void onGuidedActionClicked(GuidedAction action) {
SetupActionHelper.onActionClick(this, getActionCategory(), (int) action.getId());
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 c02d3f56..e05a40c8 100644
--- a/common/src/com/android/tv/common/ui/setup/SetupMultiPaneFragment.java
+++ b/common/src/com/android/tv/common/ui/setup/SetupMultiPaneFragment.java
@@ -32,9 +32,8 @@ public abstract class SetupMultiPaneFragment extends SetupFragment {
public static final int ACTION_DONE = Integer.MAX_VALUE;
public static final int ACTION_SKIP = ACTION_DONE - 1;
- public static final int MAX_SUBCLASSES_ID = ACTION_SKIP - 1;
- public static final String CONTENT_FRAGMENT_TAG = "content_fragment";
+ private static final String CONTENT_FRAGMENT_TAG = "content_fragment";
@Override
public View onCreateView(
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 13b89ea1..38fccbbe 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
@@ -1,18 +1,3 @@
-/*
- * 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.ui.setup.animation;
import android.animation.Animator;
diff --git a/common/src/com/android/tv/common/util/CommonUtils.java b/common/src/com/android/tv/common/util/CommonUtils.java
deleted file mode 100644
index 865d4c43..00000000
--- a/common/src/com/android/tv/common/util/CommonUtils.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright 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.common.util;
-
-import android.content.Context;
-import android.content.Intent;
-import android.media.tv.TvInputInfo;
-import android.os.Build;
-import android.util.ArraySet;
-import com.android.tv.common.BuildConfig;
-import com.android.tv.common.CommonConstants;
-import com.android.tv.common.experiments.Experiments;
-import java.io.File;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Locale;
-import java.util.Set;
-
-/** Util class for common use in TV app and inputs. */
-@SuppressWarnings("AndroidApiChecker") // TODO(b/32513850) remove when error prone is updated
-public final class CommonUtils {
- private static final String LC_PACKAGE_NAME = "com.android.tv";
- private static final ThreadLocal<SimpleDateFormat> ISO_8601 =
- new ThreadLocal() {
- private final SimpleDateFormat value =
- new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US);
-
- @Override
- protected SimpleDateFormat initialValue() {
- return value;
- }
- };
- // Hardcoded list for known bundled inputs not written by OEM/SOCs.
- // Bundled (system) inputs not in the list will get the high priority
- // so they and their channels come first in the UI.
- private static final Set<String> BUNDLED_PACKAGE_SET = new ArraySet<>();
-
- static {
- BUNDLED_PACKAGE_SET.add("com.android.tv");
- }
-
- private static Boolean sRunningInTest;
-
- private CommonUtils() {}
-
- /**
- * Returns an intent to start the setup activity for the TV input using {@link
- * CommonConstants#INTENT_ACTION_INPUT_SETUP}.
- */
- public static Intent createSetupIntent(Intent originalSetupIntent, String inputId) {
- if (originalSetupIntent == null) {
- return null;
- }
- Intent setupIntent = new Intent(originalSetupIntent);
- if (!CommonConstants.INTENT_ACTION_INPUT_SETUP.equals(originalSetupIntent.getAction())) {
- Intent intentContainer = new Intent(CommonConstants.INTENT_ACTION_INPUT_SETUP);
- intentContainer.putExtra(CommonConstants.EXTRA_SETUP_INTENT, originalSetupIntent);
- intentContainer.putExtra(CommonConstants.EXTRA_INPUT_ID, inputId);
- setupIntent = intentContainer;
- }
- return setupIntent;
- }
-
- /**
- * Returns an intent to start the setup activity for this TV input using {@link
- * CommonConstants#INTENT_ACTION_INPUT_SETUP}.
- */
- public static Intent createSetupIntent(TvInputInfo input) {
- return createSetupIntent(input.createSetupIntent(), input.getId());
- }
-
- /**
- * Checks if this application is running in tests.
- *
- * <p>{@link android.app.ActivityManager#isRunningInTestHarness} doesn't return {@code true} for
- * the usual devices even the application is running in tests. We need to figure it out by
- * checking whether the class in tv-tests-common module can be loaded or not.
- */
- public static synchronized boolean isRunningInTest() {
- if (sRunningInTest == null) {
- try {
- Class.forName("com.android.tv.testing.utils.Utils");
- sRunningInTest = true;
- } catch (ClassNotFoundException e) {
- sRunningInTest = false;
- }
- }
- return sRunningInTest;
- }
-
- /** Checks whether a given package is in our bundled package set. */
- public static boolean isInBundledPackageSet(String packageName) {
- return BUNDLED_PACKAGE_SET.contains(packageName);
- }
-
- /** Checks whether a given input is a bundled input. */
- public static boolean isBundledInput(String inputId) {
- for (String prefix : BUNDLED_PACKAGE_SET) {
- if (inputId.startsWith(prefix + "/")) {
- return true;
- }
- }
- return false;
- }
-
- /** Returns true if the application is packaged with Live TV. */
- public static boolean isPackagedWithLiveChannels(Context context) {
- return (LC_PACKAGE_NAME.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));
- }
-
- /** Deletes a file or a directory. */
- public static void deleteDirOrFile(File fileOrDirectory) {
- if (fileOrDirectory.isDirectory()) {
- for (File child : fileOrDirectory.listFiles()) {
- deleteDirOrFile(child);
- }
- }
- fileOrDirectory.delete();
- }
-
- public static boolean isRoboTest() {
- return "robolectric".equals(Build.FINGERPRINT);
- }
-}
diff --git a/icu/icu4j/main/classes/core/src/com/ibm/icu/text/SCSU.java b/icu/icu4j/main/classes/core/src/com/ibm/icu/text/SCSU.java
new file mode 100644
index 00000000..a257c1c6
--- /dev/null
+++ b/icu/icu4j/main/classes/core/src/com/ibm/icu/text/SCSU.java
@@ -0,0 +1,405 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html#License
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2007, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ */
+
+package com.ibm.icu.text;
+
+/**
+ * An interface defining constants for the Standard Compression Scheme for Unicode (SCSU) as
+ * outlined in <A HREF="http://www.unicode.org/unicode/reports/tr6">Unicode Technical Report #6</A>.
+ *
+ * @author Stephen F. Booth
+ * @version 1.1 05 Aug 99
+ * @version 1.0 26 Jul 99
+ */
+interface SCSU {
+ // ==========================
+ // Generic window shift
+ // ==========================
+ static final int COMPRESSIONOFFSET = 0x80;
+
+ // ==========================
+ // Number of windows
+ // ==========================
+ static final int NUMWINDOWS = 8;
+ static final int NUMSTATICWINDOWS = 8;
+
+ // ==========================
+ // Indicates a window index is invalid
+ // ==========================
+ static final int INVALIDWINDOW = -1;
+
+ // ==========================
+ // Indicates a character doesn't exist in input (past end of buffer)
+ // ==========================
+ static final int INVALIDCHAR = -1;
+
+ // ==========================
+ // Compression modes
+ // ==========================
+ static final int SINGLEBYTEMODE = 0;
+ static final int UNICODEMODE = 1;
+
+ // ==========================
+ // Maximum value for a window's index
+ // ==========================
+ static final int MAXINDEX = 0xFF;
+
+ // ==========================
+ // Reserved index value (characters belongs to first block)
+ // ==========================
+ static final int RESERVEDINDEX = 0x00;
+
+ // ==========================
+ // Indices for scripts which cross a half-block boundary
+ // ==========================
+ static final int LATININDEX = 0xF9;
+ static final int IPAEXTENSIONINDEX = 0xFA;
+ static final int GREEKINDEX = 0xFB;
+ static final int ARMENIANINDEX = 0xFC;
+ static final int HIRAGANAINDEX = 0xFD;
+ static final int KATAKANAINDEX = 0xFE;
+ static final int HALFWIDTHKATAKANAINDEX = 0xFF;
+
+ // ==========================
+ // Single-byte mode tags
+ // ==========================
+ static final int SDEFINEX = 0x0B;
+ static final int SRESERVED = 0x0C; // reserved value
+ static final int SQUOTEU = 0x0E;
+ static final int SCHANGEU = 0x0F;
+
+ static final int SQUOTE0 = 0x01;
+ static final int SQUOTE1 = 0x02;
+ static final int SQUOTE2 = 0x03;
+ static final int SQUOTE3 = 0x04;
+ static final int SQUOTE4 = 0x05;
+ static final int SQUOTE5 = 0x06;
+ static final int SQUOTE6 = 0x07;
+ static final int SQUOTE7 = 0x08;
+
+ static final int SCHANGE0 = 0x10;
+ static final int SCHANGE1 = 0x11;
+ static final int SCHANGE2 = 0x12;
+ static final int SCHANGE3 = 0x13;
+ static final int SCHANGE4 = 0x14;
+ static final int SCHANGE5 = 0x15;
+ static final int SCHANGE6 = 0x16;
+ static final int SCHANGE7 = 0x17;
+
+ static final int SDEFINE0 = 0x18;
+ static final int SDEFINE1 = 0x19;
+ static final int SDEFINE2 = 0x1A;
+ static final int SDEFINE3 = 0x1B;
+ static final int SDEFINE4 = 0x1C;
+ static final int SDEFINE5 = 0x1D;
+ static final int SDEFINE6 = 0x1E;
+ static final int SDEFINE7 = 0x1F;
+
+ // ==========================
+ // Unicode mode tags
+ // ==========================
+ static final int UCHANGE0 = 0xE0;
+ static final int UCHANGE1 = 0xE1;
+ static final int UCHANGE2 = 0xE2;
+ static final int UCHANGE3 = 0xE3;
+ static final int UCHANGE4 = 0xE4;
+ static final int UCHANGE5 = 0xE5;
+ static final int UCHANGE6 = 0xE6;
+ static final int UCHANGE7 = 0xE7;
+
+ static final int UDEFINE0 = 0xE8;
+ static final int UDEFINE1 = 0xE9;
+ static final int UDEFINE2 = 0xEA;
+ static final int UDEFINE3 = 0xEB;
+ static final int UDEFINE4 = 0xEC;
+ static final int UDEFINE5 = 0xED;
+ static final int UDEFINE6 = 0xEE;
+ static final int UDEFINE7 = 0xEF;
+
+ static final int UQUOTEU = 0xF0;
+ static final int UDEFINEX = 0xF1;
+ static final int URESERVED = 0xF2; // reserved value
+
+ // ==========================
+ // Class variables
+ // ==========================
+
+ /** For window offset mapping */
+ static final int[] sOffsetTable = {
+ // table generated by CompressionTableGenerator
+ 0x0,
+ 0x80,
+ 0x100,
+ 0x180,
+ 0x200,
+ 0x280,
+ 0x300,
+ 0x380,
+ 0x400,
+ 0x480,
+ 0x500,
+ 0x580,
+ 0x600,
+ 0x680,
+ 0x700,
+ 0x780,
+ 0x800,
+ 0x880,
+ 0x900,
+ 0x980,
+ 0xa00,
+ 0xa80,
+ 0xb00,
+ 0xb80,
+ 0xc00,
+ 0xc80,
+ 0xd00,
+ 0xd80,
+ 0xe00,
+ 0xe80,
+ 0xf00,
+ 0xf80,
+ 0x1000,
+ 0x1080,
+ 0x1100,
+ 0x1180,
+ 0x1200,
+ 0x1280,
+ 0x1300,
+ 0x1380,
+ 0x1400,
+ 0x1480,
+ 0x1500,
+ 0x1580,
+ 0x1600,
+ 0x1680,
+ 0x1700,
+ 0x1780,
+ 0x1800,
+ 0x1880,
+ 0x1900,
+ 0x1980,
+ 0x1a00,
+ 0x1a80,
+ 0x1b00,
+ 0x1b80,
+ 0x1c00,
+ 0x1c80,
+ 0x1d00,
+ 0x1d80,
+ 0x1e00,
+ 0x1e80,
+ 0x1f00,
+ 0x1f80,
+ 0x2000,
+ 0x2080,
+ 0x2100,
+ 0x2180,
+ 0x2200,
+ 0x2280,
+ 0x2300,
+ 0x2380,
+ 0x2400,
+ 0x2480,
+ 0x2500,
+ 0x2580,
+ 0x2600,
+ 0x2680,
+ 0x2700,
+ 0x2780,
+ 0x2800,
+ 0x2880,
+ 0x2900,
+ 0x2980,
+ 0x2a00,
+ 0x2a80,
+ 0x2b00,
+ 0x2b80,
+ 0x2c00,
+ 0x2c80,
+ 0x2d00,
+ 0x2d80,
+ 0x2e00,
+ 0x2e80,
+ 0x2f00,
+ 0x2f80,
+ 0x3000,
+ 0x3080,
+ 0x3100,
+ 0x3180,
+ 0x3200,
+ 0x3280,
+ 0x3300,
+ 0x3380,
+ 0xe000,
+ 0xe080,
+ 0xe100,
+ 0xe180,
+ 0xe200,
+ 0xe280,
+ 0xe300,
+ 0xe380,
+ 0xe400,
+ 0xe480,
+ 0xe500,
+ 0xe580,
+ 0xe600,
+ 0xe680,
+ 0xe700,
+ 0xe780,
+ 0xe800,
+ 0xe880,
+ 0xe900,
+ 0xe980,
+ 0xea00,
+ 0xea80,
+ 0xeb00,
+ 0xeb80,
+ 0xec00,
+ 0xec80,
+ 0xed00,
+ 0xed80,
+ 0xee00,
+ 0xee80,
+ 0xef00,
+ 0xef80,
+ 0xf000,
+ 0xf080,
+ 0xf100,
+ 0xf180,
+ 0xf200,
+ 0xf280,
+ 0xf300,
+ 0xf380,
+ 0xf400,
+ 0xf480,
+ 0xf500,
+ 0xf580,
+ 0xf600,
+ 0xf680,
+ 0xf700,
+ 0xf780,
+ 0xf800,
+ 0xf880,
+ 0xf900,
+ 0xf980,
+ 0xfa00,
+ 0xfa80,
+ 0xfb00,
+ 0xfb80,
+ 0xfc00,
+ 0xfc80,
+ 0xfd00,
+ 0xfd80,
+ 0xfe00,
+ 0xfe80,
+ 0xff00,
+ 0xff80,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0xc0,
+ 0x250,
+ 0x370,
+ 0x530,
+ 0x3040,
+ 0x30a0,
+ 0xff60
+ };
+
+ /** Static compression window offsets */
+ static final int[] sOffsets = {
+ 0x0000, // for quoting single-byte mode tags
+ 0x0080, // Latin-1 Supplement
+ 0x0100, // Latin Extended-A
+ 0x0300, // Combining Diacritical Marks
+ 0x2000, // General Punctuation
+ 0x2080, // Curency Symbols
+ 0x2100, // Letterlike Symbols and Number Forms
+ 0x3000 // CJK Symbols and Punctuation
+ };
+}
diff --git a/icu/icu4j/main/classes/core/src/com/ibm/icu/text/UnicodeDecompressor.java b/icu/icu4j/main/classes/core/src/com/ibm/icu/text/UnicodeDecompressor.java
new file mode 100644
index 00000000..6e2a2d71
--- /dev/null
+++ b/icu/icu4j/main/classes/core/src/com/ibm/icu/text/UnicodeDecompressor.java
@@ -0,0 +1,795 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html#License
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2016, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ */
+
+package com.ibm.icu.text;
+
+/**
+ * A decompression engine implementing the Standard Compression Scheme for Unicode (SCSU) as
+ * outlined in <A HREF="http://www.unicode.org/unicode/reports/tr6">Unicode Technical Report #6</A>.
+ *
+ * <p><STRONG>USAGE</STRONG>
+ *
+ * <p>The static methods on <TT>UnicodeDecompressor</TT> may be used in a straightforward manner to
+ * decompress simple strings:
+ *
+ * <PRE>
+ * byte [] compressed = ... ; // get compressed bytes from somewhere
+ * String result = UnicodeDecompressor.decompress(compressed);
+ * </PRE>
+ *
+ * <p>The static methods have a fairly large memory footprint. For finer-grained control over memory
+ * usage, <TT>UnicodeDecompressor</TT> offers more powerful APIs allowing iterative decompression:
+ *
+ * <PRE>
+ * // Decompress an array "bytes" of length "len" using a buffer of 512 chars
+ * // to the Writer "out"
+ *
+ * UnicodeDecompressor myDecompressor = new UnicodeDecompressor();
+ * final static int BUFSIZE = 512;
+ * char [] charBuffer = new char [ BUFSIZE ];
+ * int charsWritten = 0;
+ * int [] bytesRead = new int [1];
+ * int totalBytesDecompressed = 0;
+ * int totalCharsWritten = 0;
+ *
+ * do {
+ * // do the decompression
+ * charsWritten = myDecompressor.decompress(bytes, totalBytesDecompressed,
+ * len, bytesRead,
+ * charBuffer, 0, BUFSIZE);
+ *
+ * // do something with the current set of chars
+ * out.write(charBuffer, 0, charsWritten);
+ *
+ * // update the no. of bytes decompressed
+ * totalBytesDecompressed += bytesRead[0];
+ *
+ * // update the no. of chars written
+ * totalCharsWritten += charsWritten;
+ *
+ * } while(totalBytesDecompressed &lt; len);
+ *
+ * myDecompressor.reset(); // reuse decompressor
+ * </PRE>
+ *
+ * <p>Decompression is performed according to the standard set forth in <A
+ * HREF="http://www.unicode.org/unicode/reports/tr6">Unicode Technical Report #6</A>
+ *
+ * @see UnicodeCompressor
+ * @author Stephen F. Booth
+ * @stable ICU 2.4
+ */
+public final class UnicodeDecompressor implements SCSU {
+ // ==========================
+ // Instance variables
+ // ==========================
+
+ /** Alias to current dynamic window */
+ private int fCurrentWindow = 0;
+
+ /** Dynamic compression window offsets */
+ private int[] fOffsets = new int[NUMWINDOWS];
+
+ /** Current compression mode */
+ private int fMode = SINGLEBYTEMODE;
+
+ /** Size of our internal buffer */
+ private static final int BUFSIZE = 3;
+
+ /** Internal buffer for saving state */
+ private byte[] fBuffer = new byte[BUFSIZE];
+
+ /** Number of characters in our internal buffer */
+ private int fBufferLength = 0;
+
+ /**
+ * Create a UnicodeDecompressor. Sets all windows to their default values.
+ *
+ * @see #reset
+ * @stable ICU 2.4
+ */
+ public UnicodeDecompressor() {
+ reset(); // initialize to defaults
+ }
+
+ /**
+ * Decompress a byte array into a String.
+ *
+ * @param buffer The byte array to decompress.
+ * @return A String containing the decompressed characters.
+ * @see #decompress(byte [], int, int)
+ * @stable ICU 2.4
+ */
+ public static String decompress(byte[] buffer) {
+ char[] buf = decompress(buffer, 0, buffer.length);
+ return new String(buf);
+ }
+
+ /**
+ * Decompress a byte array into a Unicode character array.
+ *
+ * @param buffer The byte array to decompress.
+ * @param start The start of the byte run to decompress.
+ * @param limit The limit of the byte run to decompress.
+ * @return A character array containing the decompressed bytes.
+ * @see #decompress(byte [])
+ * @stable ICU 2.4
+ */
+ public static char[] decompress(byte[] buffer, int start, int limit) {
+ UnicodeDecompressor comp = new UnicodeDecompressor();
+
+ // use a buffer we know will never overflow
+ // in the worst case, each byte will decompress
+ // to a surrogate pair (buffer must be at least 2 chars)
+ int len = Math.max(2, 2 * (limit - start));
+ char[] temp = new char[len];
+
+ int charCount = comp.decompress(buffer, start, limit, null, temp, 0, len);
+
+ char[] result = new char[charCount];
+ System.arraycopy(temp, 0, result, 0, charCount);
+ return result;
+ }
+
+ /**
+ * Decompress a byte array into a Unicode character array.
+ *
+ * <p>This function will either completely fill the output buffer, or consume the entire input.
+ *
+ * @param byteBuffer The byte buffer to decompress.
+ * @param byteBufferStart The start of the byte run to decompress.
+ * @param byteBufferLimit The limit of the byte run to decompress.
+ * @param bytesRead A one-element array. If not null, on return the number of bytes read from
+ * byteBuffer.
+ * @param charBuffer A buffer to receive the decompressed data. This buffer must be at minimum
+ * two characters in size.
+ * @param charBufferStart The starting offset to which to write decompressed data.
+ * @param charBufferLimit The limiting offset for writing decompressed data.
+ * @return The number of Unicode characters written to charBuffer.
+ * @stable ICU 2.4
+ */
+ public int decompress(
+ byte[] byteBuffer,
+ int byteBufferStart,
+ int byteBufferLimit,
+ int[] bytesRead,
+ char[] charBuffer,
+ int charBufferStart,
+ int charBufferLimit) {
+ // the current position in the source byte buffer
+ int bytePos = byteBufferStart;
+
+ // the current position in the target char buffer
+ int ucPos = charBufferStart;
+
+ // the current byte from the source buffer
+ int aByte = 0x00;
+
+ // charBuffer must be at least 2 chars in size
+ if (charBuffer.length < 2 || (charBufferLimit - charBufferStart) < 2)
+ throw new IllegalArgumentException("charBuffer.length < 2");
+
+ // if our internal buffer isn't empty, flush its contents
+ // to the output buffer before doing any more decompression
+ if (fBufferLength > 0) {
+
+ int newBytes = 0;
+
+ // fill the buffer completely, to guarantee one full character
+ if (fBufferLength != BUFSIZE) {
+ newBytes = fBuffer.length - fBufferLength;
+
+ // verify there are newBytes bytes in byteBuffer
+ if (byteBufferLimit - byteBufferStart < newBytes)
+ newBytes = byteBufferLimit - byteBufferStart;
+
+ System.arraycopy(byteBuffer, byteBufferStart, fBuffer, fBufferLength, newBytes);
+ }
+
+ // reset buffer length to 0 before recursive call
+ fBufferLength = 0;
+
+ // call self recursively to decompress the buffer
+ int count =
+ decompress(
+ fBuffer,
+ 0,
+ fBuffer.length,
+ null,
+ charBuffer,
+ charBufferStart,
+ charBufferLimit);
+
+ // update the positions into the arrays
+ ucPos += count;
+ bytePos += newBytes;
+ }
+
+ // the main decompression loop
+ mainLoop:
+ while (bytePos < byteBufferLimit && ucPos < charBufferLimit) {
+ switch (fMode) {
+ case SINGLEBYTEMODE:
+ // single-byte mode decompression loop
+ singleByteModeLoop:
+ while (bytePos < byteBufferLimit && ucPos < charBufferLimit) {
+ aByte = byteBuffer[bytePos++] & 0xFF;
+ switch (aByte) {
+ // All bytes from 0x80 through 0xFF are remapped
+ // to chars or surrogate pairs according to the
+ // currently active window
+ case 0x80:
+ case 0x81:
+ case 0x82:
+ case 0x83:
+ case 0x84:
+ case 0x85:
+ case 0x86:
+ case 0x87:
+ case 0x88:
+ case 0x89:
+ case 0x8A:
+ case 0x8B:
+ case 0x8C:
+ case 0x8D:
+ case 0x8E:
+ case 0x8F:
+ case 0x90:
+ case 0x91:
+ case 0x92:
+ case 0x93:
+ case 0x94:
+ case 0x95:
+ case 0x96:
+ case 0x97:
+ case 0x98:
+ case 0x99:
+ case 0x9A:
+ case 0x9B:
+ case 0x9C:
+ case 0x9D:
+ case 0x9E:
+ case 0x9F:
+ case 0xA0:
+ case 0xA1:
+ case 0xA2:
+ case 0xA3:
+ case 0xA4:
+ case 0xA5:
+ case 0xA6:
+ case 0xA7:
+ case 0xA8:
+ case 0xA9:
+ case 0xAA:
+ case 0xAB:
+ case 0xAC:
+ case 0xAD:
+ case 0xAE:
+ case 0xAF:
+ case 0xB0:
+ case 0xB1:
+ case 0xB2:
+ case 0xB3:
+ case 0xB4:
+ case 0xB5:
+ case 0xB6:
+ case 0xB7:
+ case 0xB8:
+ case 0xB9:
+ case 0xBA:
+ case 0xBB:
+ case 0xBC:
+ case 0xBD:
+ case 0xBE:
+ case 0xBF:
+ case 0xC0:
+ case 0xC1:
+ case 0xC2:
+ case 0xC3:
+ case 0xC4:
+ case 0xC5:
+ case 0xC6:
+ case 0xC7:
+ case 0xC8:
+ case 0xC9:
+ case 0xCA:
+ case 0xCB:
+ case 0xCC:
+ case 0xCD:
+ case 0xCE:
+ case 0xCF:
+ case 0xD0:
+ case 0xD1:
+ case 0xD2:
+ case 0xD3:
+ case 0xD4:
+ case 0xD5:
+ case 0xD6:
+ case 0xD7:
+ case 0xD8:
+ case 0xD9:
+ case 0xDA:
+ case 0xDB:
+ case 0xDC:
+ case 0xDD:
+ case 0xDE:
+ case 0xDF:
+ case 0xE0:
+ case 0xE1:
+ case 0xE2:
+ case 0xE3:
+ case 0xE4:
+ case 0xE5:
+ case 0xE6:
+ case 0xE7:
+ case 0xE8:
+ case 0xE9:
+ case 0xEA:
+ case 0xEB:
+ case 0xEC:
+ case 0xED:
+ case 0xEE:
+ case 0xEF:
+ case 0xF0:
+ case 0xF1:
+ case 0xF2:
+ case 0xF3:
+ case 0xF4:
+ case 0xF5:
+ case 0xF6:
+ case 0xF7:
+ case 0xF8:
+ case 0xF9:
+ case 0xFA:
+ case 0xFB:
+ case 0xFC:
+ case 0xFD:
+ case 0xFE:
+ case 0xFF:
+ // For offsets <= 0xFFFF, convert to a single char
+ // by adding the window's offset and subtracting
+ // the generic compression offset
+ if (fOffsets[fCurrentWindow] <= 0xFFFF) {
+ charBuffer[ucPos++] =
+ (char)
+ (aByte
+ + fOffsets[fCurrentWindow]
+ - COMPRESSIONOFFSET);
+ }
+ // For offsets > 0x10000, convert to a surrogate pair by
+ // normBase = window's offset - 0x10000
+ // high surr. = 0xD800 + (normBase >> 10)
+ // low surr. = 0xDC00 + (normBase & 0x3FF) + (byte & 0x7F)
+ else {
+ // make sure there is enough room to write
+ // both characters
+ // if not, save state and break out
+ if ((ucPos + 1) >= charBufferLimit) {
+ --bytePos;
+ System.arraycopy(
+ byteBuffer,
+ bytePos,
+ fBuffer,
+ 0,
+ byteBufferLimit - bytePos);
+ fBufferLength = byteBufferLimit - bytePos;
+ bytePos += fBufferLength;
+ break mainLoop;
+ }
+
+ int normalizedBase = fOffsets[fCurrentWindow] - 0x10000;
+ charBuffer[ucPos++] = (char) (0xD800 + (normalizedBase >> 10));
+ charBuffer[ucPos++] =
+ (char)
+ (0xDC00
+ + (normalizedBase & 0x3FF)
+ + (aByte & 0x7F));
+ }
+ break;
+
+ // bytes from 0x20 through 0x7F are treated as ASCII and
+ // are remapped to chars by padding the high byte
+ // (this is the same as quoting from static window 0)
+ // NUL (0x00), HT (0x09), CR (0x0A), LF (0x0D)
+ // are treated as ASCII as well
+ case 0x00:
+ case 0x09:
+ case 0x0A:
+ case 0x0D:
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2A:
+ case 0x2B:
+ case 0x2C:
+ case 0x2D:
+ case 0x2E:
+ case 0x2F:
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ case 0x38:
+ case 0x39:
+ case 0x3A:
+ case 0x3B:
+ case 0x3C:
+ case 0x3D:
+ case 0x3E:
+ case 0x3F:
+ case 0x40:
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ case 0x44:
+ case 0x45:
+ case 0x46:
+ case 0x47:
+ case 0x48:
+ case 0x49:
+ case 0x4A:
+ case 0x4B:
+ case 0x4C:
+ case 0x4D:
+ case 0x4E:
+ case 0x4F:
+ case 0x50:
+ case 0x51:
+ case 0x52:
+ case 0x53:
+ case 0x54:
+ case 0x55:
+ case 0x56:
+ case 0x57:
+ case 0x58:
+ case 0x59:
+ case 0x5A:
+ case 0x5B:
+ case 0x5C:
+ case 0x5D:
+ case 0x5E:
+ case 0x5F:
+ case 0x60:
+ case 0x61:
+ case 0x62:
+ case 0x63:
+ case 0x64:
+ case 0x65:
+ case 0x66:
+ case 0x67:
+ case 0x68:
+ case 0x69:
+ case 0x6A:
+ case 0x6B:
+ case 0x6C:
+ case 0x6D:
+ case 0x6E:
+ case 0x6F:
+ case 0x70:
+ case 0x71:
+ case 0x72:
+ case 0x73:
+ case 0x74:
+ case 0x75:
+ case 0x76:
+ case 0x77:
+ case 0x78:
+ case 0x79:
+ case 0x7A:
+ case 0x7B:
+ case 0x7C:
+ case 0x7D:
+ case 0x7E:
+ case 0x7F:
+ charBuffer[ucPos++] = (char) aByte;
+ break;
+
+ // quote unicode
+ case SQUOTEU:
+ // verify we have two bytes following tag
+ // if not, save state and break out
+ if ((bytePos + 1) >= byteBufferLimit) {
+ --bytePos;
+ System.arraycopy(
+ byteBuffer,
+ bytePos,
+ fBuffer,
+ 0,
+ byteBufferLimit - bytePos);
+ fBufferLength = byteBufferLimit - bytePos;
+ bytePos += fBufferLength;
+ break mainLoop;
+ }
+
+ aByte = byteBuffer[bytePos++];
+ charBuffer[ucPos++] =
+ (char) (aByte << 8 | (byteBuffer[bytePos++] & 0xFF));
+ break;
+
+ // switch to Unicode mode
+ case SCHANGEU:
+ fMode = UNICODEMODE;
+ break singleByteModeLoop;
+ // break;
+
+ // handle all quote tags
+ case SQUOTE0:
+ case SQUOTE1:
+ case SQUOTE2:
+ case SQUOTE3:
+ case SQUOTE4:
+ case SQUOTE5:
+ case SQUOTE6:
+ case SQUOTE7:
+ // verify there is a byte following the tag
+ // if not, save state and break out
+ if (bytePos >= byteBufferLimit) {
+ --bytePos;
+ System.arraycopy(
+ byteBuffer,
+ bytePos,
+ fBuffer,
+ 0,
+ byteBufferLimit - bytePos);
+ fBufferLength = byteBufferLimit - bytePos;
+ bytePos += fBufferLength;
+ break mainLoop;
+ }
+
+ // if the byte is in the range 0x00 - 0x7F, use
+ // static window n otherwise, use dynamic window n
+ int dByte = byteBuffer[bytePos++] & 0xFF;
+ charBuffer[ucPos++] =
+ (char)
+ (dByte
+ + (dByte >= 0x00 && dByte < 0x80
+ ? sOffsets[aByte - SQUOTE0]
+ : (fOffsets[aByte - SQUOTE0]
+ - COMPRESSIONOFFSET)));
+ break;
+
+ // handle all change tags
+ case SCHANGE0:
+ case SCHANGE1:
+ case SCHANGE2:
+ case SCHANGE3:
+ case SCHANGE4:
+ case SCHANGE5:
+ case SCHANGE6:
+ case SCHANGE7:
+ fCurrentWindow = aByte - SCHANGE0;
+ break;
+
+ // handle all define tags
+ case SDEFINE0:
+ case SDEFINE1:
+ case SDEFINE2:
+ case SDEFINE3:
+ case SDEFINE4:
+ case SDEFINE5:
+ case SDEFINE6:
+ case SDEFINE7:
+ // verify there is a byte following the tag
+ // if not, save state and break out
+ if (bytePos >= byteBufferLimit) {
+ --bytePos;
+ System.arraycopy(
+ byteBuffer,
+ bytePos,
+ fBuffer,
+ 0,
+ byteBufferLimit - bytePos);
+ fBufferLength = byteBufferLimit - bytePos;
+ bytePos += fBufferLength;
+ break mainLoop;
+ }
+
+ fCurrentWindow = aByte - SDEFINE0;
+ fOffsets[fCurrentWindow] =
+ sOffsetTable[byteBuffer[bytePos++] & 0xFF];
+ break;
+
+ // handle define extended tag
+ case SDEFINEX:
+ // verify we have two bytes following tag
+ // if not, save state and break out
+ if ((bytePos + 1) >= byteBufferLimit) {
+ --bytePos;
+ System.arraycopy(
+ byteBuffer,
+ bytePos,
+ fBuffer,
+ 0,
+ byteBufferLimit - bytePos);
+ fBufferLength = byteBufferLimit - bytePos;
+ bytePos += fBufferLength;
+ break mainLoop;
+ }
+
+ aByte = byteBuffer[bytePos++] & 0xFF;
+ fCurrentWindow = (aByte & 0xE0) >> 5;
+ fOffsets[fCurrentWindow] =
+ 0x10000
+ + (0x80
+ * (((aByte & 0x1F) << 8)
+ | (byteBuffer[bytePos++] & 0xFF)));
+ break;
+
+ // reserved, shouldn't happen
+ case SRESERVED:
+ break;
+ } // end switch
+ } // end while
+ break;
+
+ case UNICODEMODE:
+ // unicode mode decompression loop
+ unicodeModeLoop:
+ while (bytePos < byteBufferLimit && ucPos < charBufferLimit) {
+ aByte = byteBuffer[bytePos++] & 0xFF;
+ switch (aByte) {
+ // handle all define tags
+ case UDEFINE0:
+ case UDEFINE1:
+ case UDEFINE2:
+ case UDEFINE3:
+ case UDEFINE4:
+ case UDEFINE5:
+ case UDEFINE6:
+ case UDEFINE7:
+ // verify there is a byte following tag
+ // if not, save state and break out
+ if (bytePos >= byteBufferLimit) {
+ --bytePos;
+ System.arraycopy(
+ byteBuffer,
+ bytePos,
+ fBuffer,
+ 0,
+ byteBufferLimit - bytePos);
+ fBufferLength = byteBufferLimit - bytePos;
+ bytePos += fBufferLength;
+ break mainLoop;
+ }
+
+ fCurrentWindow = aByte - UDEFINE0;
+ fOffsets[fCurrentWindow] =
+ sOffsetTable[byteBuffer[bytePos++] & 0xFF];
+ fMode = SINGLEBYTEMODE;
+ break unicodeModeLoop;
+ // break;
+
+ // handle define extended tag
+ case UDEFINEX:
+ // verify we have two bytes following tag
+ // if not, save state and break out
+ if ((bytePos + 1) >= byteBufferLimit) {
+ --bytePos;
+ System.arraycopy(
+ byteBuffer,
+ bytePos,
+ fBuffer,
+ 0,
+ byteBufferLimit - bytePos);
+ fBufferLength = byteBufferLimit - bytePos;
+ bytePos += fBufferLength;
+ break mainLoop;
+ }
+
+ aByte = byteBuffer[bytePos++] & 0xFF;
+ fCurrentWindow = (aByte & 0xE0) >> 5;
+ fOffsets[fCurrentWindow] =
+ 0x10000
+ + (0x80
+ * (((aByte & 0x1F) << 8)
+ | (byteBuffer[bytePos++] & 0xFF)));
+ fMode = SINGLEBYTEMODE;
+ break unicodeModeLoop;
+ // break;
+
+ // handle all change tags
+ case UCHANGE0:
+ case UCHANGE1:
+ case UCHANGE2:
+ case UCHANGE3:
+ case UCHANGE4:
+ case UCHANGE5:
+ case UCHANGE6:
+ case UCHANGE7:
+ fCurrentWindow = aByte - UCHANGE0;
+ fMode = SINGLEBYTEMODE;
+ break unicodeModeLoop;
+ // break;
+
+ // quote unicode
+ case UQUOTEU:
+ // verify we have two bytes following tag
+ // if not, save state and break out
+ if (bytePos >= byteBufferLimit - 1) {
+ --bytePos;
+ System.arraycopy(
+ byteBuffer,
+ bytePos,
+ fBuffer,
+ 0,
+ byteBufferLimit - bytePos);
+ fBufferLength = byteBufferLimit - bytePos;
+ bytePos += fBufferLength;
+ break mainLoop;
+ }
+
+ aByte = byteBuffer[bytePos++];
+ charBuffer[ucPos++] =
+ (char) (aByte << 8 | (byteBuffer[bytePos++] & 0xFF));
+ break;
+
+ default:
+ // verify there is a byte following tag
+ // if not, save state and break out
+ if (bytePos >= byteBufferLimit) {
+ --bytePos;
+ System.arraycopy(
+ byteBuffer,
+ bytePos,
+ fBuffer,
+ 0,
+ byteBufferLimit - bytePos);
+ fBufferLength = byteBufferLimit - bytePos;
+ bytePos += fBufferLength;
+ break mainLoop;
+ }
+
+ charBuffer[ucPos++] =
+ (char) (aByte << 8 | (byteBuffer[bytePos++] & 0xFF));
+ break;
+ } // end switch
+ } // end while
+ break;
+ } // end switch( fMode )
+ } // end while
+
+ // fill in output parameter
+ if (bytesRead != null) bytesRead[0] = (bytePos - byteBufferStart);
+
+ // return # of chars written
+ return (ucPos - charBufferStart);
+ }
+
+ /**
+ * Reset the decompressor to its initial state.
+ *
+ * @stable ICU 2.4
+ */
+ public void reset() {
+ // reset dynamic windows
+ fOffsets[0] = 0x0080; // Latin-1
+ fOffsets[1] = 0x00C0; // Latin-1 Supplement + Latin Extended-A
+ fOffsets[2] = 0x0400; // Cyrillic
+ fOffsets[3] = 0x0600; // Arabic
+ fOffsets[4] = 0x0900; // Devanagari
+ fOffsets[5] = 0x3040; // Hiragana
+ fOffsets[6] = 0x30A0; // Katakana
+ fOffsets[7] = 0xFF00; // Fullwidth ASCII
+
+ fCurrentWindow = 0; // Make current window Latin-1
+ fMode = SINGLEBYTEMODE; // Always start in single-byte mode
+ fBufferLength = 0; // Empty buffer
+ }
+}
diff --git a/jni/DvbManager.cpp b/jni/DvbManager.cpp
index e55d07c5..b344f803 100644
--- a/jni/DvbManager.cpp
+++ b/jni/DvbManager.cpp
@@ -39,12 +39,14 @@ static double currentTimeMillis() {
DvbManager::DvbManager(JNIEnv *env, jobject)
: mFeFd(-1),
+ mDemuxFd(-1),
mDvrFd(-1),
mPatFilterFd(-1),
mDvbApiVersion(DVB_API_VERSION_UNDEFINED),
mDeliverySystemType(-1),
mFeHasLock(false),
mHasPendingTune(false) {
+ (void) mDemuxFd; // suppress unused warning
jclass clazz = env->FindClass(
"com/android/tv/tuner/TunerHal");
mOpenDvbFrontEndMethodID = env->GetMethodID(
@@ -116,13 +118,11 @@ int DvbManager::tune(JNIEnv *env, jobject thiz,
if (mDvbApiVersion == DVB_API_VERSION5) {
struct dtv_property deliverySystemProperty = {
- .cmd = DTV_DELIVERY_SYSTEM
+ .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_ATSC
};
- deliverySystemProperty.u.data = SYS_ATSC;
struct dtv_property frequencyProperty = {
- .cmd = DTV_FREQUENCY
+ .cmd = DTV_FREQUENCY, .u.data = static_cast<__u32>(frequency)
};
- frequencyProperty.u.data = static_cast<__u32>(frequency);
struct dtv_property modulationProperty = { .cmd = DTV_MODULATION };
if (strncmp(modulationStr, "QAM", 3) == 0) {
modulationProperty.u.data = QAM_AUTO;
@@ -503,4 +503,4 @@ int DvbManager::getDeliverySystemType(JNIEnv *env, jobject thiz) {
}
}
return mDeliverySystemType;
-} \ No newline at end of file
+}
diff --git a/jni/DvbManager.h b/jni/DvbManager.h
index 6289d645..2252332c 100644
--- a/jni/DvbManager.h
+++ b/jni/DvbManager.h
@@ -61,6 +61,7 @@ class DvbManager {
int mFeFd;
+ int mDemuxFd;
int mDvrFd;
int mPatFilterFd;
int mDvbApiVersion;
diff --git a/jni/gen_jni.sh b/jni/gen_jni.sh
index 2c246189..aa52b248 100755
--- a/jni/gen_jni.sh
+++ b/jni/gen_jni.sh
@@ -1,18 +1,3 @@
#!/bin/bash
-#
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
javah -jni -classpath ../../bin/classes:../../../../../../prebuilts/sdk/current/android.jar -o tunertvinput_jni.h com.android.tv.tuner.TunerHal
diff --git a/jni/tunertvinput_jni.cpp b/jni/tunertvinput_jni.cpp
index 40091779..9ad15141 100644
--- a/jni/tunertvinput_jni.cpp
+++ b/jni/tunertvinput_jni.cpp
@@ -172,4 +172,4 @@ Java_com_android_tv_tuner_TunerHal_nativeGetDeliverySystemType
sDvbManagers.insert(std::pair<jlong, DvbManager *>(deviceId, dvbManager));
return dvbManager->getDeliverySystemType(env, thiz);
}
-} \ No newline at end of file
+}
diff --git a/libs/exoplayer-core-2-SNAPHOT-20180114.aar b/libs/exoplayer-core-2-SNAPHOT-20180114.aar
deleted file mode 100644
index 90af2e63..00000000
--- a/libs/exoplayer-core-2-SNAPHOT-20180114.aar
+++ /dev/null
Binary files differ
diff --git a/libs/exoplayer-r1.5.16.aar b/libs/exoplayer-r1.5.16.aar
deleted file mode 100644
index 364104fc..00000000
--- a/libs/exoplayer-r1.5.16.aar
+++ /dev/null
Binary files differ
diff --git a/libs/exoplayer.jar b/libs/exoplayer.jar
new file mode 100644
index 00000000..43aea971
--- /dev/null
+++ b/libs/exoplayer.jar
Binary files differ
diff --git a/libs/exoplayer_v2.jar b/libs/exoplayer_v2.jar
new file mode 100644
index 00000000..6cfcde9c
--- /dev/null
+++ b/libs/exoplayer_v2.jar
Binary files differ
diff --git a/libs/exoplayer_v2_ext_ffmpeg.jar b/libs/exoplayer_v2_ext_ffmpeg.jar
new file mode 100644
index 00000000..65117267
--- /dev/null
+++ b/libs/exoplayer_v2_ext_ffmpeg.jar
Binary files differ
diff --git a/proguard.flags b/proguard.flags
index 69b17861..0edd14f3 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -27,6 +27,12 @@
-dontwarn com.google.android.volley.**
-dontwarn com.google.android.common.**
+# Keep the methods called from native code.
+-keepclasseswithmembers class com.android.tv.tuner.TunerHal {
+ int openDvbFrontEndFd();
+ int openDvbDemuxFd();
+ int openDvbDvrFd();
+}
-keepclasseswithmembers class com.android.tv.tuner.*DataSource {
int readAt(long, byte[], int, int);
long getSize();
@@ -36,28 +42,10 @@
native <methods>;
}
-# Configuration of proguard via annotations. Apply them to
-# the elements of your program not only to ensure correct proguard
-# functionality, but to document non-obvious entry points to your code to make
-# it survive refactorings.
-
-# Annotations are implemented as attributes, so we have to explicitly keep them.
-# Catch all which encompasses attributes like RuntimeVisibleParameterAnnotations
-# and RuntimeVisibleTypeAnnotations
--keepattributes RuntimeVisible*Annotation*
-
-# JNI is an entry point that's hard to keep track of, so there's
-# an annotation to mark fields and methods used by native code.
-
-# Keep the annotations that proguard needs to process.
--keep class com.android.tv.common.annotation.UsedBy*
-
-# Just because native code accesses members of a class, does not mean that the
-# class itself needs to be annotated - only annotate classes that are
-# referenced themselves in native code.
--keep @com.android.tv.common.annotation.UsedBy* class *
--keepclassmembers class * {
- @com.android.tv.common.annotation.UsedBy* *;
+# Keep method which is used for reflection.
+-keep @com.android.tv.common.annotation.UsedByReflection class * {*;}
+-keepclasseswithmembers class * {
+ @com.android.tv.common.annotation.UsedByReflection <methods>;
}
# For tests
@@ -68,3 +56,4 @@
# Grpc used by epg via reflection
-keep class io.grpc.internal.DnsNameResolverProvider
+
diff --git a/tuner/proto/channel.proto b/proto/channel.proto
index 1f994522..b4e67e07 100644
--- a/tuner/proto/channel.proto
+++ b/proto/channel.proto
@@ -49,13 +49,6 @@ message TunerChannelProto {
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>
- */
- optional bool locked = 25;
}
// Enum describing the types of tuner.
diff --git a/tuner/proto/track.proto b/proto/track.proto
index fe60fed5..fe60fed5 100644
--- a/tuner/proto/track.proto
+++ b/proto/track.proto
diff --git a/res/drawable-xhdpi/ic_live_channels_96x96.png b/res/drawable-xhdpi/ic_launcher.png
index 7f4eb10d..7f4eb10d 100644
--- a/res/drawable-xhdpi/ic_live_channels_96x96.png
+++ b/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_live_channels.png b/res/drawable-xhdpi/ic_live_channels.png
deleted file mode 100644
index bb1c2d9d..00000000
--- a/res/drawable-xhdpi/ic_live_channels.png
+++ /dev/null
Binary files differ
diff --git a/res/layout/dvr_recording_card_view.xml b/res/layout/dvr_recording_card_view.xml
index 3e953510..53a7cf3d 100644
--- a/res/layout/dvr_recording_card_view.xml
+++ b/res/layout/dvr_recording_card_view.xml
@@ -15,7 +15,7 @@
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tv="http://schemas.android.com/apk/res-auto"
+ xmlns:tv="http://schemas.android.com/apk/res/com.android.tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
diff --git a/tuner/res/layout/guided_action_editable.xml b/res/layout/guided_action_editable.xml
index 84f56f8d..84f56f8d 100644
--- a/tuner/res/layout/guided_action_editable.xml
+++ b/res/layout/guided_action_editable.xml
diff --git a/res/layout/details_overview.xml b/res/layout/lb_details_overview.xml
index dbcf2055..dbcf2055 100644
--- a/res/layout/details_overview.xml
+++ b/res/layout/lb_details_overview.xml
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index e57b0546..a6c8735b 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -65,7 +65,7 @@
<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>
+\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.
diff --git a/res/values/strings.xml b/res/values/strings.xml
index bdc5811e..57049aba 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -129,7 +129,7 @@
<string name="multi_audio_unknown_language">Unknown language</string>
<!-- Default string for unknown language used in "Closed Caption" options. [CHAR LIMIT=30] -->
- <string name="closed_caption_unknown_language">Closed captions <xliff:g id="unknown_language_index" example="1">%1$d</xliff:g></string>
+ <string name="closed_caption_unknown_language">Closed captions %1$d</string>
<!-- Inside "Closed captions" option side panel -->
<eat-comment />
@@ -162,7 +162,7 @@
<!-- Label of audio track with eight audio channels [CHAR LIMIT=30] -->
<string name="multi_audio_channel_surround_8">7.1 surround</string>
<!-- Label of audio track with other audio channels than 1, 2, 6, and 8 [CHAR LIMIT=30] -->
- <string name="multi_audio_channel_suffix"><xliff:g id="audio_channel_count" example="5">%d</xliff:g> channels</string>
+ <string name="multi_audio_channel_suffix">%d channels</string>
<!-- Inside "Edit Channels for a specific input" option side panel -->
<eat-comment />
@@ -330,6 +330,15 @@
<!-- Toast message when an user couldn't pass the PIN confirmation. [CHAR LIMIT=NONE] -->
<string name="pin_toast_not_match">Try again, PIN doesn\'t match</string>
+ <!-- Title of postal/zip code input guided step fragment [CHAR LIMIT=30] -->
+ <string name="postal_code_guidance_title">Enter your ZIP Code.</string>
+ <!-- Description of postal/zip code input guided step fragment [CHAR LIMIT=NONE] -->
+ <string name="postal_code_guidance_description">Live TV app will use the ZIP Code to provide a complete program guide for the TV channels.</string>
+ <!-- Description of postal/zip code input edit text view to prompt users entering ZIP Code [CHAR LIMIT=30] -->
+ <string name="postal_code_action_description">Enter your ZIP Code</string>
+ <!-- Warning message shown in description field of postal/zip code input edit text view when user enters an invalid ZIP Code and presses Done [CHAR LIMIT=30] -->
+ <string name="postal_code_invalid_warning">Invalid ZIP Code</string>
+
<!-- menu for "Settings" option -->
<eat-comment />
<!-- Title of "Settings" option. [CHAR LIMIT=30] -->
@@ -513,13 +522,6 @@
<!-- Content text of DVR recording service's notification during updating schedules. -->
<string name="dvr_notification_content_text_loading" translatable="false">Live TV 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>
- <!-- Default application name for tuner installing notifications. -->
- <string name="tuner_install_default_application_name" translatable="false">Tuner Package</string>
- <!-- Default content text of tuner installing notifications. -->
- <string name="tuner_install_notification_content_text" translatable="false">Install tuner package to watch tuner channels.</string>
-
<!-- EPG Search strings. -->
<!-- Remove translatable="false" once UI is finalized -->
<string name="search_result_no_result" translatable="false">No result</string>
@@ -531,7 +533,7 @@
<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>
+\n\nGet started by setting up the channel sources already installed. Or browse Google Play Store for more apps that offer live channels.</string>
<!-- Menu item label to start DVR manager UI. -->
<string name="channels_item_dvr">Recordings &amp; schedules</string>
@@ -752,7 +754,7 @@
<!-- Dialog title which will be shown when the current storage is too small for DVR. -->
<string name="dvr_error_small_sized_storage_title">DVR needs more storage</string>
<!-- Dialog description which will be shown when the current storage is too small for DVR. -->
- <string name="dvr_error_small_sized_storage_description">You will be able to record programs with DVR. However there is not enough storage on your device now for DVR to work. Please connect an external drive that is <xliff:g id="storage_size" example="10GB">%1$d</xliff:g>GB or larger and follow the steps to format it as device storage.</string>
+ <string name="dvr_error_small_sized_storage_description">You will be able to record programs with DVR. However there is not enough storage on your device now for DVR to work. Please connect an external drive that is <xliff:g id="storage size" example="10GB">%1$d</xliff:g>GB or larger and follow the steps to format it as device storage.</string>
<!-- Dialog title which will be shown when there is no free space on the current storage for DVR. -->
<string name="dvr_error_no_free_space_title">Not enough storage</string>
<!-- Dialog description which will be shown when there is no free space on the current storage for DVR. -->
diff --git a/tuner/tests/unittests/javatests/com/google/android/tv/tuner/AndroidManifest.xml b/res/xml/remote_config_defaults.xml
index 04f23650..6ecad191 100644
--- a/tuner/tests/unittests/javatests/com/google/android/tv/tuner/AndroidManifest.xml
+++ b/res/xml/remote_config_defaults.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2015 The Android Open Source Project
+ ~ 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.
@@ -14,18 +14,24 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
+<defaultsMap>
+ <entry>
+ <key>live_channels_ac3_software_decoder</key>
+ <value>false</value>
+ </entry>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tv.tuner.tests" >
+ <entry>
+ <key>live_channels_epg_host_and_port</key>
+ <value>datamixer-pa.googleapis.com:443</value>
+ </entry>
- <uses-sdk android:minSdkVersion="23" android:targetSdkVersion="23" />
+ <entry>
+ <key>live_channels_epg_fetcher_interval_hour</key>
+ <value>4</value>
+ </entry>
- <instrumentation
- android:name="android.support.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.tv" />
-
- <application android:label="TunerTvInputTests" >
- <uses-library android:name="android.test.runner" />
- </application>
-
-</manifest>
+ <entry>
+ <key>live_channels_epg_reader_max_channels_per_program_fetch</key>
+ <value>20</value>
+ </entry>
+</defaultsMap> \ No newline at end of file
diff --git a/tuner/src/com/google/android/exoplayer/MediaFormatUtil.java b/src/com/android/exoplayer/MediaFormatUtil.java
index c7571b23..151c6dd5 100644
--- a/tuner/src/com/google/android/exoplayer/MediaFormatUtil.java
+++ b/src/com/android/exoplayer/MediaFormatUtil.java
@@ -57,7 +57,7 @@ public class MediaFormatUtil {
MimeTypes.AUDIO_RAW.equals(mimeType) ? C.ENCODING_PCM_16BIT : MediaFormat.NO_VALUE;
MediaFormat mediaFormat =
new MediaFormat(
- null, // trackId
+ null,
mimeType,
MediaFormat.NO_VALUE,
maxInputSize,
@@ -77,10 +77,8 @@ public class MediaFormatUtil {
pcmEncoding,
encoderDelay,
encoderPadding,
- null, // projectionData
- MediaFormat.NO_VALUE,
- null // colorValue
- );
+ null,
+ MediaFormat.NO_VALUE);
mediaFormat.setFrameworkFormatV16(format);
return mediaFormat;
}
diff --git a/tuner/src/com/google/android/exoplayer/MediaSoftwareCodecUtil.java b/src/com/android/exoplayer/MediaSoftwareCodecUtil.java
index cf74f106..cf74f106 100644
--- a/tuner/src/com/google/android/exoplayer/MediaSoftwareCodecUtil.java
+++ b/src/com/android/exoplayer/MediaSoftwareCodecUtil.java
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/text/SubtitleView.java b/src/com/android/exoplayer/text/SubtitleView.java
index 91bee7a0..e930ef2d 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/text/SubtitleView.java
+++ b/src/com/android/exoplayer/text/SubtitleView.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.tv.tuner.exoplayer.text;
+package com.google.android.exoplayer.text;
import android.annotation.TargetApi;
import android.content.Context;
@@ -32,10 +32,8 @@ import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.View;
-import com.google.android.exoplayer.text.CaptionStyleCompat;
import com.google.android.exoplayer.util.Util;
import java.util.ArrayList;
-import java.util.Objects;
/**
* Since this class does not exist in recent version of ExoPlayer and used by {@link
@@ -188,7 +186,7 @@ public class SubtitleView extends View {
}
private void setTypeface(Typeface typeface) {
- if (Objects.equals(mTextPaint.getTypeface(), (typeface))) {
+ if (mTextPaint.getTypeface() != typeface) {
mTextPaint.setTypeface(typeface);
forceUpdate(true);
}
diff --git a/src/com/android/exoplayer2/ext/ffmpeg/FfmpegAudioDecoder.java b/src/com/android/exoplayer2/ext/ffmpeg/FfmpegAudioDecoder.java
new file mode 100644
index 00000000..321e19da
--- /dev/null
+++ b/src/com/android/exoplayer2/ext/ffmpeg/FfmpegAudioDecoder.java
@@ -0,0 +1,126 @@
+/*
+ * 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.google.android.exoplayer2.ext.ffmpeg;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import com.android.tv.common.SoftPreconditions;
+import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
+import com.google.android.exoplayer2.decoder.SimpleOutputBuffer;
+import com.google.android.exoplayer2.util.MimeTypes;
+import java.nio.ByteBuffer;
+
+/**
+ * Audio decoder which uses ffmpeg extension of ExoPlayer2. Since {@link FfmpegDecoder} is package
+ * private, expose the decoder via this class. Supported formats are AC3 and MP2.
+ */
+public class FfmpegAudioDecoder {
+ private static final int NUM_DECODER_BUFFERS = 1;
+
+ // The largest AC3 sample size. This is bigger than the largest MP2 sample size (1729).
+ private static final int INITIAL_INPUT_BUFFER_SIZE = 2560;
+ private static boolean AVAILABLE;
+
+ static {
+ AVAILABLE =
+ FfmpegLibrary.supportsFormat(MimeTypes.AUDIO_AC3)
+ && FfmpegLibrary.supportsFormat(MimeTypes.AUDIO_MPEG_L2);
+ }
+
+ private FfmpegDecoder mDecoder;
+ private DecoderInputBuffer mInputBuffer;
+ private SimpleOutputBuffer mOutputBuffer;
+ private boolean mStarted;
+
+ /** Return whether Ffmpeg based software audio decoder is available. */
+ public static boolean isAvailable() {
+ return AVAILABLE;
+ }
+
+ /** Creates an Ffmpeg based software audio decoder. */
+ public FfmpegAudioDecoder(Context context) {
+ if (context.checkSelfPermission("android.permission.INTERNET")
+ == PackageManager.PERMISSION_GRANTED) {
+ throw new IllegalStateException("This code should run in an isolated process");
+ }
+ }
+
+ /**
+ * Decodes an audio sample.
+ *
+ * @param timeUs presentation timestamp of the sample
+ * @param sample data
+ */
+ public void decode(long timeUs, byte[] sample) {
+ SoftPreconditions.checkState(AVAILABLE);
+ mInputBuffer.data.clear();
+ mInputBuffer.data.put(sample);
+ mInputBuffer.data.flip();
+ mInputBuffer.timeUs = timeUs;
+ mDecoder.decode(mInputBuffer, mOutputBuffer, !mStarted);
+ if (!mStarted) {
+ mStarted = true;
+ }
+ }
+
+ /** Returns a decoded sample from decoder. */
+ public ByteBuffer getDecodedSample() {
+ return mOutputBuffer.data;
+ }
+
+ /** Returns the presentation time for the decoded sample. */
+ public long getDecodedTimeUs() {
+ return mOutputBuffer.timeUs;
+ }
+
+ /**
+ * Clear previous decode state if any. Prepares to decode samples of the specified encoding.
+ * This method should be called before using decode.
+ *
+ * @param mime audio encoding
+ */
+ public void resetDecoderState(String mime) {
+ SoftPreconditions.checkState(AVAILABLE);
+ release();
+ try {
+ mDecoder =
+ new FfmpegDecoder(
+ NUM_DECODER_BUFFERS,
+ NUM_DECODER_BUFFERS,
+ INITIAL_INPUT_BUFFER_SIZE,
+ mime,
+ null);
+ mStarted = false;
+ mInputBuffer = mDecoder.createInputBuffer();
+ // Since native JNI requires direct buffer, we should allocate it by #allocateDirect.
+ mInputBuffer.data = ByteBuffer.allocateDirect(INITIAL_INPUT_BUFFER_SIZE);
+ mOutputBuffer = mDecoder.createOutputBuffer();
+ } catch (FfmpegDecoderException e) {
+ // if AVAILABLE is {@code true}, this will not happen.
+ }
+ }
+
+ /** Releases all the resource. */
+ public void release() {
+ SoftPreconditions.checkState(AVAILABLE);
+ if (mDecoder != null) {
+ mDecoder.release();
+ mInputBuffer = null;
+ mOutputBuffer = null;
+ mDecoder = null;
+ }
+ }
+}
diff --git a/src/com/android/exoplayer2/ext/ffmpeg/FfmpegLibrary.java b/src/com/android/exoplayer2/ext/ffmpeg/FfmpegLibrary.java
new file mode 100644
index 00000000..a33d4020
--- /dev/null
+++ b/src/com/android/exoplayer2/ext/ffmpeg/FfmpegLibrary.java
@@ -0,0 +1,75 @@
+/*
+ * 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.google.android.exoplayer2.ext.ffmpeg;
+
+import com.google.android.exoplayer2.util.LibraryLoader;
+import com.google.android.exoplayer2.util.MimeTypes;
+
+/**
+ * This class is based on com.google.android.exoplayer2.ext.ffmpeg.FfmpegLibrary from ExoPlayer2 in
+ * order to support mp2 decoder. Configures and queries the underlying native library.
+ */
+public final class FfmpegLibrary {
+
+ private static final LibraryLoader LOADER =
+ new LibraryLoader("avutil", "avresample", "avcodec", "ffmpeg");
+
+ private FfmpegLibrary() {}
+
+ /**
+ * Overrides the names of the FFmpeg native libraries. If an application wishes to call this
+ * method, it must do so before calling any other method defined by this class, and before
+ * instantiating a {@link FfmpegAudioRenderer} instance.
+ */
+ public static void setLibraries(String... libraries) {
+ LOADER.setLibraries(libraries);
+ }
+
+ /** Returns whether the underlying library is available, loading it if necessary. */
+ public static boolean isAvailable() {
+ return LOADER.isAvailable();
+ }
+
+ /** Returns the version of the underlying library if available, or null otherwise. */
+ public static String getVersion() {
+ return isAvailable() ? ffmpegGetVersion() : null;
+ }
+
+ /** Returns whether the underlying library supports the specified MIME type. */
+ public static boolean supportsFormat(String mimeType) {
+ if (!isAvailable()) {
+ return false;
+ }
+ String codecName = getCodecName(mimeType);
+ return codecName != null && ffmpegHasDecoder(codecName);
+ }
+
+ /** Returns the name of the FFmpeg decoder that could be used to decode {@code mimeType}. */
+ /* package */ static String getCodecName(String mimeType) {
+ switch (mimeType) {
+ case MimeTypes.AUDIO_MPEG_L2:
+ return "mp2";
+ case MimeTypes.AUDIO_AC3:
+ return "ac3";
+ default:
+ return null;
+ }
+ }
+
+ private static native String ffmpegGetVersion();
+
+ private static native boolean ffmpegHasDecoder(String codecName);
+}
diff --git a/src/com/android/tv/TvSingletons.java b/src/com/android/tv/ApplicationSingletons.java
index 80c74576..f9eaf58e 100644
--- a/src/com/android/tv/TvSingletons.java
+++ b/src/com/android/tv/ApplicationSingletons.java
@@ -16,41 +16,27 @@
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.config.RemoteConfig;
import com.android.tv.data.ChannelDataManager;
import com.android.tv.data.PreviewDataManager;
import com.android.tv.data.ProgramDataManager;
-import com.android.tv.data.epg.EpgFetcher;
-import com.android.tv.data.epg.EpgReader;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.DvrManager;
import com.android.tv.dvr.DvrScheduleManager;
+import com.android.tv.dvr.DvrStorageStatusManager;
import com.android.tv.dvr.DvrWatchedPositionManager;
import com.android.tv.dvr.recorder.RecordingScheduler;
import com.android.tv.perf.PerformanceMonitor;
-import com.android.tv.tuner.TunerInputController;
-import com.android.tv.util.SetupUtils;
+import com.android.tv.util.AccountHelper;
import com.android.tv.util.TvInputManagerHelper;
-import com.android.tv.util.account.AccountHelper;
-import javax.inject.Provider;
/** Interface with getters for application scoped singletons. */
-public interface TvSingletons extends BaseSingletons {
-
- /** Returns the @{@link TvSingletons} using the application context. */
- static TvSingletons getSingletons(Context context) {
- return (TvSingletons) BaseApplication.getSingletons(context);
- }
+public interface ApplicationSingletons {
Analytics getAnalytics();
- void handleInputCountChanged();
-
ChannelDataManager getChannelDataManager();
/**
@@ -71,6 +57,8 @@ public interface TvSingletons extends BaseSingletons {
DvrDataManager getDvrDataManager();
+ DvrStorageStatusManager getDvrStorageStatusManager();
+
DvrScheduleManager getDvrScheduleManager();
DvrManager getDvrManager();
@@ -83,23 +71,15 @@ public interface TvSingletons extends BaseSingletons {
Tracker getTracker();
+ TvInputManagerHelper getTvInputManagerHelper();
+
MainActivityWrapper getMainActivityWrapper();
AccountHelper getAccountHelper();
+ RemoteConfig getRemoteConfig();
+
boolean isRunningInMainProcess();
PerformanceMonitor getPerformanceMonitor();
-
- TvInputManagerHelper getTvInputManagerHelper();
-
- Provider<EpgReader> providesEpgReader();
-
- EpgFetcher getEpgFetcher();
-
- SetupUtils getSetupUtils();
-
- TunerInputController getTunerInputController();
-
- ExperimentLoader getExperimentLoader();
}
diff --git a/src/com/android/tv/AudioManagerHelper.java b/src/com/android/tv/AudioManagerHelper.java
index b0187617..f4bfdb9a 100644
--- a/src/com/android/tv/AudioManagerHelper.java
+++ b/src/com/android/tv/AudioManagerHelper.java
@@ -1,18 +1,3 @@
-/*
- * 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 android.app.Activity;
@@ -61,33 +46,20 @@ class AudioManagerHelper implements AudioManager.OnAudioFocusChangeListener {
if (mTvView.isPlaying()) {
switch (mAudioFocusStatus) {
case AudioManager.AUDIOFOCUS_GAIN:
- if (mTvView.isTimeShiftAvailable()) {
- mTvView.timeshiftPlay();
- } else {
- mTvView.setStreamVolume(AUDIO_MAX_VOLUME);
- }
+ mTvView.setStreamVolume(AUDIO_MAX_VOLUME);
break;
case AudioManager.AUDIOFOCUS_LOSS:
- if (TvFeatures.PICTURE_IN_PICTURE.isEnabled(mActivity)
+ if (Features.PICTURE_IN_PICTURE.isEnabled(mActivity)
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
&& mActivity.isInPictureInPictureMode()) {
mActivity.finish();
break;
}
- // fall through
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
- if (mTvView.isTimeShiftAvailable()) {
- mTvView.timeshiftPause();
- } else {
- mTvView.setStreamVolume(AUDIO_MIN_VOLUME);
- }
+ mTvView.setStreamVolume(AUDIO_MIN_VOLUME);
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
- if (mTvView.isTimeShiftAvailable()) {
- mTvView.timeshiftPause();
- } else {
- mTvView.setStreamVolume(AUDIO_DUCKING_VOLUME);
- }
+ mTvView.setStreamVolume(AUDIO_DUCKING_VOLUME);
break;
}
}
diff --git a/src/com/android/tv/Features.java b/src/com/android/tv/Features.java
new file mode 100644
index 00000000..3f8e56a8
--- /dev/null
+++ b/src/com/android/tv/Features.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.tv;
+
+import static com.android.tv.common.feature.EngOnlyFeature.ENG_ONLY_FEATURE;
+import static com.android.tv.common.feature.FeatureUtils.AND;
+import static com.android.tv.common.feature.FeatureUtils.OFF;
+import static com.android.tv.common.feature.FeatureUtils.ON;
+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 android.util.Log;
+import com.android.tv.common.feature.Feature;
+import com.android.tv.common.feature.GServiceFeature;
+import com.android.tv.common.feature.PropertyFeature;
+import com.android.tv.experiments.Experiments;
+import com.android.tv.util.LocationUtils;
+import com.android.tv.util.PermissionUtils;
+import com.android.tv.util.Utils;
+import java.util.Locale;
+
+/**
+ * List of {@link Feature} for the Live TV App.
+ *
+ * <p>Remove the {@code Feature} once it is launched.
+ */
+public final class Features {
+ private static final String TAG = "Features";
+ private static final boolean DEBUG = false;
+
+ /**
+ * UI for opting in to analytics.
+ *
+ * <p>Do not turn this on until the splash screen asking existing users to opt-in is launched.
+ * See <a href="http://b/20228119">b/20228119</a>
+ */
+ public static final Feature ANALYTICS_OPT_IN = ENG_ONLY_FEATURE;
+
+ /**
+ * 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);
+
+ public static final Feature EPG_SEARCH =
+ new PropertyFeature("feature_tv_use_epg_search", false);
+
+ public static final Feature TUNER =
+ new Feature() {
+ @Override
+ public boolean isEnabled(Context context) {
+
+ if (Utils.isDeveloper()) {
+ // we enable tuner for developers to test tuner in any platform.
+ return true;
+ }
+
+ // This is special handling just for USB Tuner.
+ // It does not require any N API's but relies on a improvements in N for AC3
+ // support
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;
+ }
+ };
+
+ /** Use network tuner if it is available and there is no other tuner types. */
+ public static final Feature NETWORK_TUNER =
+ new Feature() {
+ @Override
+ public boolean isEnabled(Context context) {
+ if (!TUNER.isEnabled(context)) {
+ return false;
+ }
+ if (Utils.isDeveloper()) {
+ // Network tuner will be enabled for developers.
+ return true;
+ }
+ return Locale.US
+ .getCountry()
+ .equalsIgnoreCase(LocationUtils.getCurrentCountry(context));
+ }
+ };
+
+ private static final String GSERVICE_KEY_UNHIDE = "live_channels_unhide";
+ /** A flag which indicates that LC app is unhidden even when there is no input. */
+ public static final Feature UNHIDE =
+ OR(
+ new GServiceFeature(GSERVICE_KEY_UNHIDE, false),
+ new Feature() {
+ @Override
+ public boolean isEnabled(Context context) {
+ // If LC app runs as non-system app, we unhide the app.
+ return !PermissionUtils.hasAccessAllEpg(context);
+ }
+ });
+
+ public static final Feature PICTURE_IN_PICTURE =
+ new Feature() {
+ private Boolean mEnabled;
+
+ @Override
+ public boolean isEnabled(Context context) {
+ if (mEnabled == null) {
+ mEnabled =
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
+ && context.getPackageManager()
+ .hasSystemFeature(
+ PackageManager.FEATURE_PICTURE_IN_PICTURE);
+ }
+ return mEnabled;
+ }
+ };
+
+ /** Use AC3 software decode. */
+ public static final Feature AC3_SOFTWARE_DECODE =
+ new Feature() {
+ private final String[] SUPPORTED_REGIONS = {};
+
+ private Boolean mEnabled;
+
+ @Override
+ public boolean isEnabled(Context context) {
+ if (mEnabled == null) {
+ if (mEnabled == null) {
+ // We will not cache the result of fallback solution.
+ String country = LocationUtils.getCurrentCountry(context);
+ for (int i = 0; i < SUPPORTED_REGIONS.length; ++i) {
+ if (SUPPORTED_REGIONS[i].equalsIgnoreCase(country)) {
+ return true;
+ }
+ }
+ if (DEBUG) Log.d(TAG, "AC3 flag false after country check");
+ return false;
+ }
+ }
+ if (DEBUG) Log.d(TAG, "AC3 flag " + mEnabled);
+ return mEnabled;
+ }
+ };
+
+ /** Show postal code fragment before channel scan. */
+ public static final Feature ENABLE_CLOUD_EPG_REGION =
+ new Feature() {
+ private final String[] SUPPORTED_REGIONS = {};
+
+ @Override
+ public boolean isEnabled(Context context) {
+ if (!Experiments.CLOUD_EPG.get()) {
+ if (DEBUG) Log.d(TAG, "Experiments.CLOUD_EPG is false");
+ return false;
+ }
+ String country = LocationUtils.getCurrentCountry(context);
+ for (int i = 0; i < SUPPORTED_REGIONS.length; i++) {
+ if (SUPPORTED_REGIONS[i].equalsIgnoreCase(country)) {
+ return true;
+ }
+ }
+ if (DEBUG) Log.d(TAG, "EPG flag false after country check");
+ return false;
+ }
+ };
+
+ /** Enable a conflict dialog between currently watched channel and upcoming recording. */
+ public static final Feature SHOW_UPCOMING_CONFLICT_DIALOG = OFF;
+
+ /** Use input blacklist to disable partner's tuner input. */
+ public static final Feature USE_PARTNER_INPUT_BLACKLIST = ON;
+
+ /** Enable Dvb parsers and listeners. */
+ public static final Feature ENABLE_FILE_DVB = OFF;
+
+ @VisibleForTesting
+ public static final Feature TEST_FEATURE = new PropertyFeature("test_feature", false);
+
+ private Features() {}
+}
diff --git a/src/com/android/tv/InputSessionManager.java b/src/com/android/tv/InputSessionManager.java
index 416dbb68..709ed4a4 100644
--- a/src/com/android/tv/InputSessionManager.java
+++ b/src/com/android/tv/InputSessionManager.java
@@ -76,7 +76,7 @@ public class InputSessionManager {
public InputSessionManager(Context context) {
mContext = context.getApplicationContext();
- mInputManager = TvSingletons.getSingletons(context).getTvInputManagerHelper();
+ mInputManager = TvApplication.getSingletons(context).getTvInputManagerHelper();
}
/**
diff --git a/src/com/android/tv/LauncherActivity.java b/src/com/android/tv/LauncherActivity.java
index 3aca35a4..545d49b1 100644
--- a/src/com/android/tv/LauncherActivity.java
+++ b/src/com/android/tv/LauncherActivity.java
@@ -27,16 +27,15 @@ 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}, 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.
+ * 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";
- public static final String ERROR_MESSAGE =
- "com.android.tv.LauncherActivity.ErrorMessage";
+ public static final String ERROR_MESSAGE = "com.android.tv.LauncherActivity.ErrorMessage";
private static final int REQUEST_CODE_DEFAULT = 0;
private static final int REQUEST_START_ACTIVITY = 100;
@@ -53,6 +52,22 @@ public class LauncherActivity extends Activity {
createIntent(baseActivity, intentToLaunch, false), REQUEST_CODE_DEFAULT);
}
+ /**
+ * Starts an activity by calling {@link Activity#startActivityForResult}.
+ *
+ * <p>Note: {@code requestCode} should not be 0. The value is reserved for internal use.
+ */
+ public static void startActivityForResultSafe(
+ Activity baseActivity, Intent intentToLaunch, int requestCode) {
+ if (requestCode == REQUEST_CODE_DEFAULT) {
+ throw new IllegalArgumentException("requestCode should not be 0.");
+ }
+ // To avoid the app termination when the new activity crashes, LauncherActivity should be
+ // started by calling startActivityForResult().
+ baseActivity.startActivityForResult(
+ createIntent(baseActivity, intentToLaunch, true), requestCode);
+ }
+
private static Intent createIntent(
Context context, Intent intentToLaunch, boolean requestResult) {
Intent intent = new Intent(context, LauncherActivity.class);
diff --git a/src/com/android/tv/MainActivity.java b/src/com/android/tv/MainActivity.java
index 22ee9321..427d562a 100644
--- a/src/com/android/tv/MainActivity.java
+++ b/src/com/android/tv/MainActivity.java
@@ -17,7 +17,6 @@
package com.android.tv;
import android.app.Activity;
-import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -67,18 +66,13 @@ import com.android.tv.analytics.SendChannelStatusRunnable;
import com.android.tv.analytics.SendConfigInfoRunnable;
import com.android.tv.analytics.Tracker;
import com.android.tv.common.BuildConfig;
-import com.android.tv.common.CommonPreferences;
import com.android.tv.common.MemoryManageable;
import com.android.tv.common.SoftPreconditions;
+import com.android.tv.common.TvCommonUtils;
import com.android.tv.common.TvContentRatingCache;
import com.android.tv.common.WeakHandler;
import com.android.tv.common.feature.CommonFeatures;
import com.android.tv.common.ui.setup.OnActionClickListener;
-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.common.util.SystemProperties;
import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
import com.android.tv.data.OnCurrentProgramUpdatedListener;
@@ -86,6 +80,7 @@ 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.epg.EpgFetcher;
import com.android.tv.dialog.HalfSizedDialogFragment;
import com.android.tv.dialog.PinDialogFragment;
import com.android.tv.dialog.PinDialogFragment.OnPinCheckedListener;
@@ -95,17 +90,21 @@ import com.android.tv.dvr.data.ScheduledRecording;
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.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.EventNames;
import com.android.tv.perf.PerformanceMonitor;
+import com.android.tv.perf.StubPerformanceMonitor;
import com.android.tv.perf.TimerEvent;
import com.android.tv.recommendation.ChannelPreviewUpdater;
import com.android.tv.recommendation.NotificationService;
import com.android.tv.search.ProgramGuideSearchFragment;
+import com.android.tv.tuner.TunerInputController;
+import com.android.tv.tuner.TunerPreferences;
+import com.android.tv.tuner.setup.TunerSetupActivity;
+import com.android.tv.tuner.tvinput.TunerTvInputService;
import com.android.tv.ui.ChannelBannerView;
import com.android.tv.ui.InputBannerView;
import com.android.tv.ui.KeypadChannelSwitchView;
@@ -125,16 +124,19 @@ 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.util.CaptionSettings;
+import com.android.tv.util.Debug;
+import com.android.tv.util.DurationTimer;
import com.android.tv.util.ImageCache;
import com.android.tv.util.OnboardingUtils;
+import com.android.tv.util.PermissionUtils;
import com.android.tv.util.RecurringRunner;
import com.android.tv.util.SetupUtils;
+import com.android.tv.util.SystemProperties;
import com.android.tv.util.TvInputManagerHelper;
import com.android.tv.util.TvSettings;
import com.android.tv.util.TvTrackInfoUtils;
import com.android.tv.util.Utils;
import com.android.tv.util.ViewCache;
-import com.android.tv.util.account.AccountHelper;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayDeque;
@@ -146,7 +148,6 @@ import java.util.Set;
import java.util.concurrent.TimeUnit;
/** The main activity for the Live TV app. */
-@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed
public class MainActivity extends Activity implements OnActionClickListener, OnPinCheckedListener {
private static final String TAG = "MainActivity";
private static final boolean DEBUG = false;
@@ -175,7 +176,6 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
// Tracker screen names.
public static final String SCREEN_NAME = "Main";
- private static final String SCREEN_PIP = "PIP";
private static final String SCREEN_BEHIND_NAME = "Behind";
private static final float REFRESH_RATE_EPSILON = 0.01f;
@@ -205,7 +205,6 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
}
private static final int REQUEST_CODE_START_SETUP_ACTIVITY = 1;
- private static final int REQUEST_CODE_NOW_PLAYING = 2;
private static final String KEY_INIT_CHANNEL_ID = "com.android.tv.init_channel_id";
@@ -240,7 +239,6 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
private final DurationTimer mTuneDurationTimer = new DurationTimer();
private DvrManager mDvrManager;
private ConflictChecker mDvrConflictChecker;
- private SetupUtils mSetupUtils;
private View mContentView;
private TunableTvView mTvView;
@@ -273,7 +271,6 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
private boolean mOtherActivityLaunched;
private PerformanceMonitor mPerformanceMonitor;
- private boolean mIsInPIPMode;
private boolean mIsFilmModeSet;
private float mDefaultRefreshRate;
@@ -310,9 +307,10 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
case Intent.ACTION_SCREEN_OFF:
if (DEBUG) Log.d(TAG, "Received ACTION_SCREEN_OFF");
// We need to stop TvView, when the screen is turned off. If not and TIS
- // uses MediaPlayer, a device may not go to the sleep mode and audio
- // can be heard, because MediaPlayer keeps playing media by its wake
- // lock.
+ // uses
+ // MediaPlayer, a device may not go to the sleep mode and audio can be
+ // heard,
+ // because MediaPlayer keeps playing media by its wake lock.
mScreenOffIntentReceived = true;
markCurrentChannelDuringScreenOff();
stopAll(true);
@@ -321,9 +319,10 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
if (DEBUG) Log.d(TAG, "Received ACTION_SCREEN_ON");
if (!mActivityResumed && mVisibleBehind) {
// ACTION_SCREEN_ON is usually called after onResume. But, if media
- // is played under launcher with requestVisibleBehind(true),
- // onResume will not be called. In this case, we need to resume
- // TvView explicitly.
+ // is
+ // played under launcher with requestVisibleBehind(true), onResume
+ // will
+ // not be called. In this case, we need to resume TvView explicitly.
resumeTvIfNeeded();
}
break;
@@ -340,7 +339,6 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
tune(true);
}
break;
- default: // fall out
}
}
};
@@ -369,7 +367,7 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
public void onLoadFinished() {
Debug.getTimer(Debug.TAG_START_UP_TIMER)
.log("MainActivity.mChannelTunerListener.onLoadFinished");
- mSetupUtils.markNewChannelsBrowsable();
+ SetupUtils.getInstance(MainActivity.this).markNewChannelsBrowsable();
if (mActivityResumed) {
resumeTvIfNeeded();
}
@@ -407,16 +405,13 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
new TvInputCallback() {
@Override
public void onInputAdded(String inputId) {
- if (TvFeatures.TUNER.isEnabled(MainActivity.this)
+ if (Features.TUNER.isEnabled(MainActivity.this)
&& mTunerInputId.equals(inputId)
- && CommonPreferences.shouldShowSetupActivity(MainActivity.this)) {
- Intent intent =
- TvSingletons
- .getSingletons(MainActivity.this)
- .getTunerSetupIntent(MainActivity.this);
+ && TunerPreferences.shouldShowSetupActivity(MainActivity.this)) {
+ Intent intent = TunerSetupActivity.createSetupActivity(MainActivity.this);
startActivity(intent);
- CommonPreferences.setShouldShowSetupActivity(MainActivity.this, false);
- mSetupUtils.markAsKnownInput(mTunerInputId);
+ TunerPreferences.setShouldShowSetupActivity(MainActivity.this, false);
+ SetupUtils.getInstance(MainActivity.this).markAsKnownInput(mTunerInputId);
}
}
};
@@ -432,9 +427,7 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
@Override
protected void onCreate(Bundle savedInstanceState) {
- TvSingletons tvSingletons = TvSingletons.getSingletons(this);
- mPerformanceMonitor = tvSingletons.getPerformanceMonitor();
- TimerEvent timer = mPerformanceMonitor.startTimer();
+ TimerEvent timer = StubPerformanceMonitor.startBootstrapTimer();
DurationTimer startUpDebugTimer = Debug.getTimer(Debug.TAG_START_UP_TIMER);
if (!startUpDebugTimer.isStarted()
|| startUpDebugTimer.getDuration() > START_UP_TIMER_RESET_THRESHOLD_MS) {
@@ -443,18 +436,16 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
startUpDebugTimer.start();
}
startUpDebugTimer.log("MainActivity.onCreate");
- if (DEBUG) {
- Log.d(TAG, "onCreate()");
- }
- Starter.start(this);
+ if (DEBUG) Log.d(TAG, "onCreate()");
+ TvApplication.setCurrentRunningProcess(this, true);
super.onCreate(savedInstanceState);
- if (!tvSingletons.getTvInputManagerHelper().hasTvInputManager()) {
+ ApplicationSingletons applicationSingletons = TvApplication.getSingletons(this);
+ if (!applicationSingletons.getTvInputManagerHelper().hasTvInputManager()) {
Log.wtf(TAG, "Stopping because device does not have a TvInputManager");
finishAndRemoveTask();
return;
}
- mPerformanceMonitor = tvSingletons.getPerformanceMonitor();
- mSetupUtils = tvSingletons.getSetupUtils();
+ mPerformanceMonitor = applicationSingletons.getPerformanceMonitor();
TvApplication tvApplication = (TvApplication) getApplication();
mChannelDataManager = tvApplication.getChannelDataManager();
@@ -469,7 +460,7 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
if ((OnboardingUtils.isFirstRunWithCurrentVersion(this)
|| channelLoadedAndNoChannelAvailable)
&& !tuneToPassthroughInput
- && !CommonUtils.isRunningInTest()) {
+ && !TvCommonUtils.isRunningInTest()) {
startOnboardingActivity();
return;
}
@@ -504,9 +495,7 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
});
long channelId = Utils.getLastWatchedChannelId(this);
String inputId = Utils.getLastWatchedTunerInputId(this);
- if (!isPassthroughInput
- && inputId != null
- && channelId != Channel.INVALID_ID) {
+ if (!isPassthroughInput && inputId != null && channelId != Channel.INVALID_ID) {
mTvView.warmUpInput(inputId, TvContract.buildChannelUri(channelId));
}
@@ -515,10 +504,10 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
Toast.makeText(this, "Using Strict Mode for eng builds", Toast.LENGTH_SHORT).show();
}
mTracker = tvApplication.getTracker();
- if (TvFeatures.TUNER.isEnabled(this)) {
+ if (Features.TUNER.isEnabled(this)) {
mTvInputManagerHelper.addCallback(mTvInputCallback);
}
- mTunerInputId = tvSingletons.getEmbeddedTunerInputId();
+ mTunerInputId = TunerTvInputService.getInputId(this);
mProgramDataManager.addOnCurrentProgramUpdatedListener(
Channel.INVALID_ID, mOnCurrentProgramUpdatedListener);
mProgramDataManager.setPrefetchEnabled(true);
@@ -646,10 +635,7 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
mSearchFragment);
mAudioManagerHelper = new AudioManagerHelper(this, mTvView);
- Intent nowPlayingIntent = new Intent(this, MainActivity.class);
- PendingIntent pendingIntent =
- PendingIntent.getActivity(this, REQUEST_CODE_NOW_PLAYING, nowPlayingIntent, 0);
- mMediaSessionWrapper = new MediaSessionWrapper(this, pendingIntent);
+ mMediaSessionWrapper = new MediaSessionWrapper(this);
mTvViewUiManager.restoreDisplayMode(false);
if (!handleIntent(getIntent())) {
@@ -673,7 +659,7 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
// To avoid not updating Rating systems when changing language.
mTvInputManagerHelper.getContentRatingsManager().update();
if (CommonFeatures.DVR.isEnabled(this)
- && TvFeatures.SHOW_UPCOMING_CONFLICT_DIALOG.isEnabled(this)) {
+ && Features.SHOW_UPCOMING_CONFLICT_DIALOG.isEnabled(this)) {
mDvrConflictChecker = new ConflictChecker(this);
}
initForTest();
@@ -752,9 +738,7 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
@Override
protected void onNewIntent(Intent intent) {
- if (DEBUG) {
- Log.d(TAG, "onNewIntent(): " + intent);
- }
+ if (DEBUG) Log.d(TAG, "onNewIntent(): " + intent);
if (mOverlayManager == null) {
// It's called before onCreate. The intent will be handled at onCreate. b/30725058
return;
@@ -770,9 +754,7 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
@Override
protected void onStart() {
TimerEvent timer = mPerformanceMonitor.startTimer();
- if (DEBUG) {
- Log.d(TAG, "onStart()");
- }
+ if (DEBUG) Log.d(TAG, "onStart()");
super.onStart();
mScreenOffIntentReceived = false;
mActivityStarted = true;
@@ -787,9 +769,9 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
notificationIntent.setAction(NotificationService.ACTION_SHOW_RECOMMENDATION);
startService(notificationIntent);
}
- TvSingletons singletons = TvSingletons.getSingletons(this);
- singletons.getTunerInputController().executeNetworkTunerDiscoveryAsyncTask(this);
- singletons.getEpgFetcher().fetchImmediatelyIfNeeded();
+ TunerInputController.executeNetworkTunerDiscoveryAsyncTask(this);
+
+ EpgFetcher.getInstance(this).fetchImmediatelyIfNeeded();
mPerformanceMonitor.stopTimer(timer, EventNames.MAIN_ACTIVITY_ONSTART);
}
@@ -799,7 +781,6 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
Debug.getTimer(Debug.TAG_START_UP_TIMER).log("MainActivity.onResume start");
if (DEBUG) Log.d(TAG, "onResume()");
super.onResume();
- mIsInPIPMode = false;
if (!PermissionUtils.hasAccessAllEpg(this)
&& checkSelfPermission(PERMISSION_READ_TV_LISTINGS)
!= PackageManager.PERMISSION_GRANTED) {
@@ -837,7 +818,7 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
}
if (mChannelTuner.areAllChannelsLoaded()) {
- mSetupUtils.markNewChannelsBrowsable();
+ SetupUtils.getInstance(this).markNewChannelsBrowsable();
resumeTvIfNeeded();
}
mOverlayManager.showMenuWithTimeShiftPauseIfNeeded();
@@ -849,11 +830,13 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
mInputToSetUp = null;
} else if (mShowProgramGuide) {
mShowProgramGuide = false;
- // This will delay the start of the animation until after the Live Channel app is
- // shown. Without this the animation is completed before it is actually visible on
- // the screen.
mHandler.post(
new Runnable() {
+ // This will delay the start of the animation until after the Live Channel
+ // app is
+ // shown. Without this the animation is completed before it is actually
+ // visible on
+ // the screen.
@Override
public void run() {
mOverlayManager.showProgramGuide();
@@ -861,12 +844,16 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
});
} else if (mShowSelectInputView) {
mShowSelectInputView = false;
- // mShowSelectInputView is true when the activity is started/resumed because the
- // TV_INPUT button was pressed in a different app. This will delay the start of
- // the animation until after the Live Channel app is shown. Without this the
- // animation is completed before it is actually visible on the screen.
mHandler.post(
new Runnable() {
+ // mShowSelectInputView is true when the activity is started/resumed because
+ // the
+ // TV_INPUT button was pressed in a different app.
+ // This will delay the start of the animation until after the Live Channel
+ // app is
+ // shown. Without this the animation is completed before it is actually
+ // visible on
+ // the screen.
@Override
public void run() {
mOverlayManager.showSelectInputView();
@@ -894,17 +881,12 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
mShowLockedChannelsTemporarily = false;
mShouldTuneToTunerChannel = false;
if (!mVisibleBehind) {
- if (mIsInPIPMode) {
- mTracker.sendScreenView(SCREEN_PIP);
- } else {
- mTracker.sendScreenView("");
- mAudioManagerHelper.abandonAudioFocus();
- mMediaSessionWrapper.setPlaybackState(false);
- }
+ mAudioManagerHelper.abandonAudioFocus();
+ mMediaSessionWrapper.setPlaybackState(false);
+ mTracker.sendScreenView("");
} else {
mTracker.sendScreenView(SCREEN_BEHIND_NAME);
}
- TvSingletons.getSingletons(this).getExperimentLoader().asyncRefreshExperiments(this);
super.onPause();
}
@@ -942,11 +924,10 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
mOverlayManager
.getSideFragmentManager()
.show(new ParentalControlsFragment(), false);
- // fall through.
+ // Pass through.
case PinDialogFragment.PIN_DIALOG_TYPE_NEW_PIN:
mOverlayManager.getSideFragmentManager().showSidePanel(true);
break;
- default: // fall out
}
} else if (type == PinDialogFragment.PIN_DIALOG_TYPE_ENTER_PIN) {
mOverlayManager.getSideFragmentManager().hideAll(false);
@@ -1094,7 +1075,7 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
* @param calledByPopup If true, startSetupActivity is invoked from the setup fragment.
*/
public void startSetupActivity(TvInputInfo input, boolean calledByPopup) {
- Intent intent = CommonUtils.createSetupIntent(input);
+ Intent intent = TvCommonUtils.createSetupIntent(input);
if (intent == null) {
Toast.makeText(this, R.string.msg_no_setup_activity, Toast.LENGTH_SHORT).show();
return;
@@ -1238,6 +1219,15 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
LauncherActivity.startActivitySafe(this, intent);
}
+ /**
+ * Call {@link Activity#startActivityForResult} in a safe way.
+ *
+ * @see LauncherActivity
+ */
+ private void startActivityForResultSafe(Intent intent, int requestCode) {
+ LauncherActivity.startActivityForResultSafe(this, intent, requestCode);
+ }
+
/** Show settings fragment. */
public void showSettingsFragment() {
if (!mChannelTuner.areAllChannelsLoaded()) {
@@ -1330,39 +1320,31 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
- switch (requestCode) {
- case REQUEST_CODE_START_SETUP_ACTIVITY:
- if (resultCode == RESULT_OK) {
- int count = mChannelDataManager.getChannelCountForInput(mInputIdUnderSetup);
- String text;
- if (count > 0) {
- text =
- getResources()
- .getQuantityString(
- R.plurals.msg_channel_added, count, count);
- } else {
- text = getString(R.string.msg_no_channel_added);
- }
- Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT).show();
- mInputIdUnderSetup = null;
- if (mChannelTuner.getCurrentChannel() == null) {
- mChannelTuner.moveToAdjacentBrowsableChannel(true);
- }
- if (mTunePending) {
- tune(true);
- }
+ if (requestCode == REQUEST_CODE_START_SETUP_ACTIVITY) {
+ if (resultCode == RESULT_OK) {
+ int count = mChannelDataManager.getChannelCountForInput(mInputIdUnderSetup);
+ String text;
+ if (count > 0) {
+ text =
+ getResources()
+ .getQuantityString(R.plurals.msg_channel_added, count, count);
} else {
- mInputIdUnderSetup = null;
+ text = getString(R.string.msg_no_channel_added);
}
- if (!mIsSetupActivityCalledByPopup) {
- mOverlayManager.getSideFragmentManager().showSidePanel(false);
+ Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT).show();
+ mInputIdUnderSetup = null;
+ if (mChannelTuner.getCurrentChannel() == null) {
+ mChannelTuner.moveToAdjacentBrowsableChannel(true);
}
- break;
- case REQUEST_CODE_NOW_PLAYING:
- // nothing needs to be done. onResume will restore everything.
- break;
- default:
- // do nothing
+ if (mTunePending) {
+ tune(true);
+ }
+ } else {
+ mInputIdUnderSetup = null;
+ }
+ if (!mIsSetupActivityCalledByPopup) {
+ mOverlayManager.getSideFragmentManager().showSidePanel(false);
+ }
}
if (data != null) {
String errorMessage = data.getStringExtra(LauncherActivity.ERROR_MESSAGE);
@@ -1554,7 +1536,7 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
mAudioManagerHelper.abandonAudioFocus();
mMediaSessionWrapper.setPlaybackState(false);
}
- TvSingletons.getSingletons(this)
+ TvApplication.getSingletons(this)
.getMainActivityWrapper()
.notifyCurrentChannelChange(this, null);
mChannelTuner.resetCurrentChannel();
@@ -1601,8 +1583,8 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
finish();
return;
}
-
- if (mSetupUtils.isFirstTune()) {
+ SetupUtils setupUtils = SetupUtils.getInstance(this);
+ if (setupUtils.isFirstTune()) {
if (!mChannelTuner.areAllChannelsLoaded()) {
// tune() will be called, once all channels are loaded.
stopTv("tune()", false);
@@ -1631,9 +1613,9 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
}
return;
}
- if (!CommonUtils.isRunningInTest()
+ if (!TvCommonUtils.isRunningInTest()
&& mShowNewSourcesFragment
- && mSetupUtils.hasUnrecognizedInput(mTvInputManagerHelper)) {
+ && setupUtils.hasUnrecognizedInput(mTvInputManagerHelper)) {
// Show new channel sources fragment.
runAfterAttachedToWindow(
new Runnable() {
@@ -1649,7 +1631,7 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
}
});
}
- mSetupUtils.onTuned();
+ setupUtils.onTuned();
if (mTuneParams != null) {
Long initChannelId = mTuneParams.getLong(KEY_INIT_CHANNEL_ID);
if (initChannelId == channel.getId()) {
@@ -1689,7 +1671,7 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
addToRecentChannels(channel.getId());
}
Utils.setLastWatchedChannel(this, channel);
- TvSingletons.getSingletons(this)
+ TvApplication.getSingletons(this)
.getMainActivityWrapper()
.notifyCurrentChannelChange(this, channel);
}
@@ -1989,7 +1971,7 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
}
if (mTvInputManagerHelper != null) {
mTvInputManagerHelper.clearTvInputLabels();
- if (TvFeatures.TUNER.isEnabled(this)) {
+ if (Features.TUNER.isEnabled(this)) {
mTvInputManagerHelper.removeCallback(mTvInputCallback);
}
}
@@ -2010,7 +1992,7 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
return false;
case KEY_EVENT_HANDLER_RESULT_PASSTHROUGH:
default:
- // fall through
+ // pass through
}
if (mSearchFragment.isVisible()) {
return super.onKeyDown(keyCode, event);
@@ -2048,7 +2030,6 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
mTracker.sendChannelDown();
}
return true;
- default: // fall out
}
}
return super.onKeyDown(keyCode, event);
@@ -2089,7 +2070,7 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
return false;
case KEY_EVENT_HANDLER_RESULT_PASSTHROUGH:
default:
- // fall through
+ // pass through
}
if (mSearchFragment.isVisible()) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
@@ -2119,7 +2100,6 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
case KeyEvent.KEYCODE_MENU:
showSettingsFragment();
return true;
- default: // fall out
}
} else {
if (KeypadChannelSwitchView.isChannelNumberKey(keyCode)) {
@@ -2187,74 +2167,82 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
if (!SystemProperties.USE_DEBUG_KEYS.getValue()) {
break;
}
- // fall through.
+ // Pass through.
case KeyEvent.KEYCODE_CAPTIONS:
- mOverlayManager.getSideFragmentManager().show(new ClosedCaptionFragment());
- return true;
+ {
+ mOverlayManager.getSideFragmentManager().show(new ClosedCaptionFragment());
+ return true;
+ }
case KeyEvent.KEYCODE_A:
if (!SystemProperties.USE_DEBUG_KEYS.getValue()) {
break;
}
- // fall through.
+ // Pass through.
case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK:
- mOverlayManager.getSideFragmentManager().show(new MultiAudioFragment());
- return true;
+ {
+ mOverlayManager.getSideFragmentManager().show(new MultiAudioFragment());
+ return true;
+ }
case KeyEvent.KEYCODE_INFO:
- mOverlayManager.showBanner();
- return true;
+ {
+ mOverlayManager.showBanner();
+ return true;
+ }
case KeyEvent.KEYCODE_MEDIA_RECORD:
case KeyEvent.KEYCODE_V:
- Channel currentChannel = getCurrentChannel();
- if (currentChannel != null && mDvrManager != null) {
- boolean isRecording =
- mDvrManager.getCurrentRecording(currentChannel.getId()) != null;
- if (!isRecording) {
- if (!mDvrManager.isChannelRecordable(currentChannel)) {
- Toast.makeText(
- this,
- R.string.dvr_msg_cannot_record_program,
- Toast.LENGTH_SHORT)
- .show();
+ {
+ Channel currentChannel = getCurrentChannel();
+ if (currentChannel != null && mDvrManager != null) {
+ boolean isRecording =
+ mDvrManager.getCurrentRecording(currentChannel.getId()) != null;
+ if (!isRecording) {
+ if (!mDvrManager.isChannelRecordable(currentChannel)) {
+ Toast.makeText(
+ this,
+ R.string.dvr_msg_cannot_record_program,
+ Toast.LENGTH_SHORT)
+ .show();
+ } else {
+ Program program =
+ mProgramDataManager.getCurrentProgram(
+ currentChannel.getId());
+ DvrUiHelper.checkStorageStatusAndShowErrorMessage(
+ this,
+ currentChannel.getInputId(),
+ new Runnable() {
+ @Override
+ public void run() {
+ DvrUiHelper.requestRecordingCurrentProgram(
+ MainActivity.this,
+ currentChannel,
+ program,
+ false);
+ }
+ });
+ }
} else {
- Program program =
- mProgramDataManager.getCurrentProgram(
- currentChannel.getId());
- DvrUiHelper.checkStorageStatusAndShowErrorMessage(
+ DvrUiHelper.showStopRecordingDialog(
this,
- currentChannel.getInputId(),
- new Runnable() {
+ currentChannel.getId(),
+ DvrStopRecordingFragment.REASON_USER_STOP,
+ new HalfSizedDialogFragment.OnActionClickListener() {
@Override
- public void run() {
- DvrUiHelper.requestRecordingCurrentProgram(
- MainActivity.this,
- currentChannel,
- program,
- false);
+ public void onActionClick(long actionId) {
+ if (actionId
+ == DvrStopRecordingFragment.ACTION_STOP) {
+ ScheduledRecording currentRecording =
+ mDvrManager.getCurrentRecording(
+ currentChannel.getId());
+ if (currentRecording != null) {
+ mDvrManager.stopRecording(currentRecording);
+ }
+ }
}
});
}
- } else {
- DvrUiHelper.showStopRecordingDialog(
- this,
- currentChannel.getId(),
- DvrStopRecordingFragment.REASON_USER_STOP,
- new HalfSizedDialogFragment.OnActionClickListener() {
- @Override
- public void onActionClick(long actionId) {
- if (actionId == DvrStopRecordingFragment.ACTION_STOP) {
- ScheduledRecording currentRecording =
- mDvrManager.getCurrentRecording(
- currentChannel.getId());
- if (currentRecording != null) {
- mDvrManager.stopRecording(currentRecording);
- }
- }
- }
- });
}
+ return true;
}
- return true;
- default: // fall out
}
}
if (keyCode == KeyEvent.KEYCODE_WINDOW) {
@@ -2292,7 +2280,6 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
case KeyEvent.KEYCODE_D:
mOverlayManager.getSideFragmentManager().show(new DeveloperOptionFragment());
return true;
- default: // fall out
}
}
return super.onKeyUp(keyCode, event);
@@ -2327,19 +2314,14 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
// We need to hide overlay first, before moving the activity to PIP. If not, UI will
// be shown during PIP stack resizing, because UI and its animation is stuck during
// PIP resizing.
- mIsInPIPMode = true;
- if (mOverlayManager.isOverlayOpened()) {
- mOverlayManager.hideOverlays(TvOverlayManager.FLAG_HIDE_OVERLAYS_WITHOUT_ANIMATION);
- mHandler.post(
- new Runnable() {
- @Override
- public void run() {
- MainActivity.super.enterPictureInPictureMode();
- }
- });
- } else {
- MainActivity.super.enterPictureInPictureMode();
- }
+ mOverlayManager.hideOverlays(TvOverlayManager.FLAG_HIDE_OVERLAYS_WITHOUT_ANIMATION);
+ mHandler.post(
+ new Runnable() {
+ @Override
+ public void run() {
+ MainActivity.super.enterPictureInPictureMode();
+ }
+ });
}
@Override
@@ -2421,7 +2403,7 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
} else if (channel.equals(mTvView.getCurrentChannel())) {
mOverlayManager.updateChannelBannerAndShowIfNeeded(
TvOverlayManager.UPDATE_CHANNEL_BANNER_REASON_TUNE);
- } else if (channel.equals(mChannelTuner.getCurrentChannel())) {
+ } else if (channel == mChannelTuner.getCurrentChannel()) {
// Channel banner is already updated in moveToAdjacentChannel
tune(false);
} else if (mChannelTuner.moveToChannel(channel)) {
@@ -2551,8 +2533,7 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
private void updateAvailabilityToast() {
if (mTvView.isVideoAvailable()
- || !Objects.equals(
- mTvView.getCurrentChannel(), mChannelTuner.getCurrentChannel())) {
+ || mTvView.getCurrentChannel() != mChannelTuner.getCurrentChannel()) {
return;
}
@@ -2616,7 +2597,7 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
// Initialize TV app for test. The setup process should be finished before the Live TV app is
// started. We only enable all the channels here.
private void initForTest() {
- if (!CommonUtils.isRunningInTest()) {
+ if (!TvCommonUtils.isRunningInTest()) {
return;
}
@@ -2688,7 +2669,6 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
sendMessageDelayed(Message.obtain(msg), getDelay(startTime));
mainActivity.moveToAdjacentChannel(true, true);
break;
- default: // fall out
}
}
@@ -2735,7 +2715,7 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
if (info.isVideoAvailable() && mTuneDurationTimer.isRunning()) {
mTracker.sendChannelTuneTime(info.getCurrentChannel(), mTuneDurationTimer.reset());
}
- if (info.isVideoOrAudioAvailable() && mChannel.equals(getCurrentChannel())) {
+ if (info.isVideoOrAudioAvailable() && mChannel == getCurrentChannel()) {
mOverlayManager.updateChannelBannerAndShowIfNeeded(
TvOverlayManager.UPDATE_CHANNEL_BANNER_REASON_UPDATE_STREAM_INFO);
}
diff --git a/src/com/android/tv/MediaSessionWrapper.java b/src/com/android/tv/MediaSessionWrapper.java
index b3472ba5..2cc898c3 100644
--- a/src/com/android/tv/MediaSessionWrapper.java
+++ b/src/com/android/tv/MediaSessionWrapper.java
@@ -16,7 +16,6 @@
package com.android.tv;
-import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
@@ -29,7 +28,6 @@ import android.media.tv.TvInputInfo;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import com.android.tv.data.Channel;
import com.android.tv.data.Program;
@@ -42,16 +40,14 @@ import com.android.tv.util.Utils;
*/
class MediaSessionWrapper {
private static final String MEDIA_SESSION_TAG = "com.android.tv.mediasession";
-
- private static final PlaybackState MEDIA_SESSION_STATE_PLAYING =
+ private static PlaybackState MEDIA_SESSION_STATE_PLAYING =
new PlaybackState.Builder()
.setState(
PlaybackState.STATE_PLAYING,
PlaybackState.PLAYBACK_POSITION_UNKNOWN,
1.0f)
.build();
-
- private static final PlaybackState MEDIA_SESSION_STATE_STOPPED =
+ private static PlaybackState MEDIA_SESSION_STATE_STOPPED =
new PlaybackState.Builder()
.setState(
PlaybackState.STATE_STOPPED,
@@ -64,7 +60,7 @@ class MediaSessionWrapper {
private int mNowPlayingCardWidth;
private int mNowPlayingCardHeight;
- MediaSessionWrapper(Context context, PendingIntent pendingIntent) {
+ MediaSessionWrapper(Context context) {
mContext = context;
mMediaSession = new MediaSession(context, MEDIA_SESSION_TAG);
mMediaSession.setCallback(
@@ -78,7 +74,6 @@ class MediaSessionWrapper {
mMediaSession.setFlags(
MediaSession.FLAG_HANDLES_MEDIA_BUTTONS
| MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
- mMediaSession.setSessionActivity(pendingIntent);
mNowPlayingCardWidth =
mContext.getResources().getDimensionPixelSize(R.dimen.notif_card_img_max_width);
mNowPlayingCardHeight =
@@ -156,7 +151,7 @@ class MediaSessionWrapper {
private String getChannelName(Channel channel) {
if (channel.isPassthrough()) {
TvInputInfo input =
- TvSingletons.getSingletons(mContext)
+ TvApplication.getSingletons(mContext)
.getTvInputManagerHelper()
.getTvInputInfo(channel.getInputId());
return Utils.loadLabel(mContext, input);
@@ -218,11 +213,6 @@ class MediaSessionWrapper {
}.execute();
}
- @VisibleForTesting
- MediaSession getMediaSession() {
- return mMediaSession;
- }
-
private static class ProgramPosterArtCallback
extends ImageLoader.ImageLoaderCallback<MediaSessionWrapper> {
private final Channel mChannel;
diff --git a/src/com/android/tv/SetupPassthroughActivity.java b/src/com/android/tv/SetupPassthroughActivity.java
index 40d38118..d1158682 100644
--- a/src/com/android/tv/SetupPassthroughActivity.java
+++ b/src/com/android/tv/SetupPassthroughActivity.java
@@ -26,14 +26,12 @@ 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.experiments.Experiments;
+import com.android.tv.common.TvCommonConstants;
import com.android.tv.data.ChannelDataManager;
import com.android.tv.data.ChannelDataManager.Listener;
import com.android.tv.data.epg.EpgFetcher;
-import com.android.tv.data.epg.EpgInputWhiteList;
-
+import com.android.tv.experiments.Experiments;
import com.android.tv.util.SetupUtils;
import com.android.tv.util.TvInputManagerHelper;
import com.android.tv.util.Utils;
@@ -55,47 +53,35 @@ public class SetupPassthroughActivity extends Activity {
private TvInputInfo mTvInputInfo;
private Intent mActivityAfterCompletion;
private boolean mEpgFetcherDuringScan;
- private EpgInputWhiteList mEpgInputWhiteList;
@Override
public void onCreate(Bundle savedInstanceState) {
if (DEBUG) Log.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
- TvSingletons tvSingletons = TvSingletons.getSingletons(this);
- TvInputManagerHelper inputManager = tvSingletons.getTvInputManagerHelper();
+ ApplicationSingletons appSingletons = TvApplication.getSingletons(this);
+ TvInputManagerHelper inputManager = appSingletons.getTvInputManagerHelper();
Intent intent = getIntent();
- String inputId = intent.getStringExtra(CommonConstants.EXTRA_INPUT_ID);
+ String inputId = intent.getStringExtra(TvCommonConstants.EXTRA_INPUT_ID);
mTvInputInfo = inputManager.getTvInputInfo(inputId);
- mEpgInputWhiteList = new EpgInputWhiteList(tvSingletons.getRemoteConfig());
mActivityAfterCompletion =
- intent.getParcelableExtra(CommonConstants.EXTRA_ACTIVITY_AFTER_COMPLETION);
+ intent.getParcelableExtra(TvCommonConstants.EXTRA_ACTIVITY_AFTER_COMPLETION);
boolean needToFetchEpg =
- mTvInputInfo != null
- && Utils.isInternalTvInput(this, mTvInputInfo.getId())
- && Experiments.CLOUD_EPG.get();
+ Utils.isInternalTvInput(this, mTvInputInfo.getId()) && Experiments.CLOUD_EPG.get();
if (needToFetchEpg) {
// In case when the activity is restored, this flag should be restored as well.
mEpgFetcherDuringScan = true;
}
if (savedInstanceState == null) {
- SoftPreconditions.checkArgument(
- CommonConstants.INTENT_ACTION_INPUT_SETUP.equals(intent.getAction()),
- TAG,
- "Unsupported action %s",
- intent.getAction());
+ SoftPreconditions.checkState(
+ intent.getAction().equals(TvCommonConstants.INTENT_ACTION_INPUT_SETUP));
if (DEBUG) Log.d(TAG, "TvInputId " + inputId + " / TvInputInfo " + mTvInputInfo);
if (mTvInputInfo == null) {
Log.w(TAG, "There is no input with the ID " + inputId + ".");
finish();
return;
}
- if (intent.getExtras() == null) {
- Log.w(TAG, "There is no extra info in the intent");
- finish();
- return;
- }
Intent setupIntent =
- intent.getExtras().getParcelable(CommonConstants.EXTRA_SETUP_INTENT);
+ intent.getExtras().getParcelable(TvCommonConstants.EXTRA_SETUP_INTENT);
if (DEBUG) Log.d(TAG, "Setup activity launch intent: " + setupIntent);
if (setupIntent == null) {
Log.w(TAG, "The input (" + mTvInputInfo.getId() + ") doesn't have setup.");
@@ -107,7 +93,7 @@ public class SetupPassthroughActivity extends Activity {
// If EXTRA_SETUP_INTENT is not removed, an infinite recursion happens during
// setupIntent.putExtras(intent.getExtras()).
Bundle extras = intent.getExtras();
- extras.remove(CommonConstants.EXTRA_SETUP_INTENT);
+ extras.remove(TvCommonConstants.EXTRA_SETUP_INTENT);
setupIntent.putExtras(extras);
try {
startActivityForResult(setupIntent, REQUEST_START_SETUP_ACTIVITY);
@@ -121,15 +107,14 @@ public class SetupPassthroughActivity extends Activity {
sScanTimeoutMonitor = new ScanTimeoutMonitor(this);
}
sScanTimeoutMonitor.startMonitoring();
- TvSingletons.getSingletons(this).getEpgFetcher().onChannelScanStarted();
+ EpgFetcher.getInstance(this).onChannelScanStarted();
}
}
}
@Override
public void onActivityResult(int requestCode, final int resultCode, final Intent data) {
- if (DEBUG)
- Log.d(TAG, "onActivityResult(" + requestCode + ", " + resultCode + ", " + data + ")");
+ if (DEBUG) Log.d(TAG, "onActivityResult");
if (sScanTimeoutMonitor != null) {
sScanTimeoutMonitor.stopMonitoring();
}
@@ -137,17 +122,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) {
- epgFetcher.onChannelScanFinished();
+ EpgFetcher.getInstance(this).onChannelScanFinished();
}
if (!setupComplete) {
setResult(resultCode, data);
finish();
return;
}
- TvSingletons.getSingletons(this)
- .getSetupUtils()
+ SetupUtils.getInstance(this)
.onTvInputSetupFinished(
mTvInputInfo.getId(),
new Runnable() {
@@ -209,7 +192,7 @@ public class SetupPassthroughActivity extends Activity {
private ScanTimeoutMonitor(Context context) {
mContext = context.getApplicationContext();
- mChannelDataManager = TvSingletons.getSingletons(context).getChannelDataManager();
+ mChannelDataManager = TvApplication.getSingletons(context).getChannelDataManager();
}
private void startMonitoring() {
@@ -237,7 +220,7 @@ public class SetupPassthroughActivity extends Activity {
private void onScanTimedOut() {
stopMonitoring();
- TvSingletons.getSingletons(mContext).getEpgFetcher().onChannelScanFinished();
+ EpgFetcher.getInstance(mContext).onChannelScanFinished();
}
}
}
diff --git a/src/com/android/tv/Starter.java b/src/com/android/tv/Starter.java
deleted file mode 100644
index 22fda0bd..00000000
--- a/src/com/android/tv/Starter.java
+++ /dev/null
@@ -1,42 +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 android.content.Context;
-import android.util.Log;
-
-/** Initializes TvApplication. */
-public interface Starter {
-
- /**
- * Initializes TvApplication.
- *
- * <p>Note: it should be called at the beginning of any Service.onCreate, Activity.onCreate, or
- * BroadcastReceiver.onCreate.
- */
- static void start(Context context) {
- // TODO(b/63064354) TvApplication should not have to know if it is "the main process"
- if (context.getApplicationContext() instanceof Starter) {
- Starter starter = (Starter) context.getApplicationContext();
- starter.start();
- } else {
- // Application context can be MockTvApplication.
- Log.w("Start", "It is not a context of TvApplication");
- }
- }
-
- void start();
-}
diff --git a/src/com/android/tv/TimeShiftManager.java b/src/com/android/tv/TimeShiftManager.java
index e37f190c..513fe3cd 100644
--- a/src/com/android/tv/TimeShiftManager.java
+++ b/src/com/android/tv/TimeShiftManager.java
@@ -146,8 +146,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 Live TV. 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;
@@ -1095,9 +1095,10 @@ public class TimeShiftManager {
SoftPreconditions.checkArgument(
endTimeMs - startTimeMs <= TWO_WEEKS_MS,
TAG,
- "createDummyProgram: long duration of dummy programs are requested ( %s , %s)",
- Utils.toTimeString(startTimeMs),
- Utils.toTimeString(endTimeMs));
+ "createDummyProgram: long duration of dummy programs are requested ("
+ + Utils.toTimeString(startTimeMs)
+ + ", "
+ + Utils.toTimeString(endTimeMs));
if (startTimeMs >= endTimeMs) {
return Collections.emptyList();
}
diff --git a/src/com/android/tv/TvApplication.java b/src/com/android/tv/TvApplication.java
index 01fe5b07..549ab6d8 100644
--- a/src/com/android/tv/TvApplication.java
+++ b/src/com/android/tv/TvApplication.java
@@ -18,6 +18,7 @@ package com.android.tv;
import android.annotation.TargetApi;
import android.app.Activity;
+import android.app.Application;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -28,24 +29,30 @@ import android.media.tv.TvContract;
import android.media.tv.TvInputInfo;
import android.media.tv.TvInputManager;
import android.media.tv.TvInputManager.TvInputCallback;
+import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
+import android.os.StrictMode;
import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
-import com.android.tv.common.BaseApplication;
+import com.android.tv.analytics.Analytics;
+import com.android.tv.analytics.StubAnalytics;
+import com.android.tv.analytics.Tracker;
+import com.android.tv.common.BuildConfig;
+import com.android.tv.common.SharedPreferencesUtils;
+import com.android.tv.common.SoftPreconditions;
+import com.android.tv.common.TvCommonUtils;
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.config.DefaultConfigManager;
+import com.android.tv.config.RemoteConfig;
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.EpgFetcherImpl;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.DvrDataManagerImpl;
import com.android.tv.dvr.DvrManager;
@@ -53,65 +60,80 @@ import com.android.tv.dvr.DvrScheduleManager;
import com.android.tv.dvr.DvrStorageStatusManager;
import com.android.tv.dvr.DvrWatchedPositionManager;
import com.android.tv.dvr.recorder.RecordingScheduler;
+import com.android.tv.perf.EventNames;
import com.android.tv.perf.PerformanceMonitor;
+import com.android.tv.perf.StubPerformanceMonitor;
+import com.android.tv.perf.TimerEvent;
import com.android.tv.recommendation.ChannelPreviewUpdater;
import com.android.tv.recommendation.RecordedProgramPreviewUpdater;
import com.android.tv.tuner.TunerInputController;
+import com.android.tv.tuner.TunerPreferences;
+import com.android.tv.tuner.tvinput.TunerTvInputService;
import com.android.tv.tuner.util.TunerInputInfoUtils;
+import com.android.tv.util.AccountHelper;
+import com.android.tv.util.Clock;
+import com.android.tv.util.Debug;
+import com.android.tv.util.PermissionUtils;
import com.android.tv.util.SetupUtils;
+import com.android.tv.util.SystemProperties;
import com.android.tv.util.TvInputManagerHelper;
import com.android.tv.util.Utils;
import java.util.List;
-/**
- * Live TV application.
- *
- * <p>This includes all the Google specific hooks.
- */
-public abstract class TvApplication extends BaseApplication implements TvSingletons, Starter {
+public class TvApplication extends Application implements ApplicationSingletons {
private static final String TAG = "TvApplication";
private static final boolean DEBUG = false;
+ private static final TimerEvent sAppStartTimer = StubPerformanceMonitor.startBootstrapTimer();
- /** Namespace for LiveChannels configs. LiveChannels configs are kept in piper. */
- public static final String CONFIGNS_P4 = "configns:p4";
+ /**
+ * An instance of {@link ApplicationSingletons}. Note that this can be set directly only for the
+ * test purpose.
+ */
+ @VisibleForTesting public static ApplicationSingletons sAppSingletons;
/**
* Broadcast Action: The user has updated LC to a new version that supports tuner input. {@link
- * com.android.tv.tuner.TunerInputController} will recevice this intent to check the
- * existence of tuner input when the new version is first launched.
+ * com.android.tv.tuner.TunerInputController} will recevice this intent to check the existence
+ * of tuner input when the new version is first launched.
*/
public static final String ACTION_APPLICATION_FIRST_LAUNCHED =
"com.android.tv.action.APPLICATION_FIRST_LAUNCHED";
private static final String PREFERENCE_IS_FIRST_LAUNCH = "is_first_launch";
+ private RemoteConfig mRemoteConfig;
private String mVersionName = "";
private final MainActivityWrapper mMainActivityWrapper = new MainActivityWrapper();
private SelectInputActivity mSelectInputActivity;
+ private Analytics mAnalytics;
+ private Tracker mTracker;
+ private TvInputManagerHelper mTvInputManagerHelper;
private ChannelDataManager mChannelDataManager;
private volatile ProgramDataManager mProgramDataManager;
private PreviewDataManager mPreviewDataManager;
private DvrManager mDvrManager;
private DvrScheduleManager mDvrScheduleManager;
private DvrDataManager mDvrDataManager;
+ private DvrStorageStatusManager mDvrStorageStatusManager;
private DvrWatchedPositionManager mDvrWatchedPositionManager;
private RecordingScheduler mRecordingScheduler;
- private RecordingStorageStatusManager mDvrStorageStatusManager;
@Nullable private InputSessionManager mInputSessionManager;
- // STOP-SHIP: Remove this variable when Tuner Process is split to another application.
+ private AccountHelper mAccountHelper;
// When this variable is null, we don't know in which process TvApplication runs.
private Boolean mRunningInMainProcess;
private PerformanceMonitor mPerformanceMonitor;
- private TvInputManagerHelper mTvInputManagerHelper;
- private boolean mStarted;
- private EpgFetcher mEpgFetcher;
- private TunerInputController mTunerInputController;
@Override
public void onCreate() {
super.onCreate();
+ if (!PermissionUtils.hasInternet(this)) {
+ // When an isolated process starts, just skip all the initialization.
+ return;
+ }
+ Debug.getTimer(Debug.TAG_START_UP_TIMER).start();
+ Debug.getTimer(Debug.TAG_START_UP_TIMER).log("Start TvApplication.onCreate");
SharedPreferencesUtils.initialize(
this,
new Runnable() {
@@ -122,6 +144,9 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet
}
}
});
+ // TunerPreferences is used to enable/disable the tuner input even when TUNER feature is
+ // disabled.
+ TunerPreferences.initialize(this);
try {
PackageInfo pInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
mVersionName = pInfo.versionName;
@@ -131,35 +156,66 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet
}
Log.i(TAG, "Starting Live TV " + getVersionName());
+ // Only set StrictMode for ENG builds because the build server only produces userdebug
+ // builds.
+ if (BuildConfig.ENG && SystemProperties.ALLOW_STRICT_MODE.getValue()) {
+ StrictMode.ThreadPolicy.Builder threadPolicyBuilder =
+ new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog();
+ StrictMode.VmPolicy.Builder vmPolicyBuilder =
+ new StrictMode.VmPolicy.Builder().detectAll().penaltyDeath();
+ if (!TvCommonUtils.isRunningInTest()) {
+ threadPolicyBuilder.penaltyDialog();
+ }
+ StrictMode.setThreadPolicy(threadPolicyBuilder.build());
+ StrictMode.setVmPolicy(vmPolicyBuilder.build());
+ }
+ if (BuildConfig.ENG && !SystemProperties.ALLOW_ANALYTICS_IN_ENG.getValue()) {
+ mAnalytics = StubAnalytics.getInstance(this);
+ } else {
+ mAnalytics = StubAnalytics.getInstance(this);
+ }
+ mTracker = mAnalytics.getDefaultTracker();
+ getTvInputManagerHelper();
// 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 Live TV " + mVersionName);
Debug.getTimer(Debug.TAG_START_UP_TIMER).log("finish TvApplication.onCreate");
+ getPerformanceMonitor().stopTimer(sAppStartTimer, EventNames.APPLICATION_ONCREATE);
}
- /** Initializes application. It is a noop if called twice. */
- @Override
- public void start() {
- if (mStarted) {
+ private void setCurrentRunningProcess(boolean isMainProcess) {
+ if (mRunningInMainProcess != null) {
+ SoftPreconditions.checkState(isMainProcess == mRunningInMainProcess);
return;
}
- mStarted = true;
- mRunningInMainProcess = true;
- Debug.getTimer(Debug.TAG_START_UP_TIMER).log("start TvApplication.start");
+ Debug.getTimer(Debug.TAG_START_UP_TIMER)
+ .log("start TvApplication.setCurrentRunningProcess");
+ mRunningInMainProcess = isMainProcess;
+ if (CommonFeatures.DVR.isEnabled(this)) {
+ mDvrStorageStatusManager = new DvrStorageStatusManager(this, mRunningInMainProcess);
+ }
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ // Fetch remote config
+ getRemoteConfig().fetch(null);
+ return null;
+ }
+ }.execute();
if (mRunningInMainProcess) {
getTvInputManagerHelper()
.addCallback(
new TvInputCallback() {
@Override
public void onInputAdded(String inputId) {
- if (TvFeatures.TUNER.isEnabled(TvApplication.this)
+ if (Features.TUNER.isEnabled(TvApplication.this)
&& TextUtils.equals(
- inputId, getEmbeddedTunerInputId())) {
+ inputId,
+ TunerTvInputService.getInputId(
+ TvApplication.this))) {
TunerInputInfoUtils.updateTunerInputInfo(
TvApplication.this);
}
@@ -171,7 +227,7 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet
handleInputCountChanged();
}
});
- if (TvFeatures.TUNER.isEnabled(this)) {
+ if (Features.TUNER.isEnabled(this)) {
// If the tuner input service is added before the app is started, we need to
// handle it here.
TunerInputInfoUtils.updateTunerInputInfo(TvApplication.this);
@@ -181,14 +237,15 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet
mDvrManager = new DvrManager(this);
mRecordingScheduler = RecordingScheduler.createScheduler(this);
}
- mEpgFetcher.startRoutineService();
+ EpgFetcher.getInstance(this).startRoutineService();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ChannelPreviewUpdater.getInstance(this).startRoutineService();
RecordedProgramPreviewUpdater.getInstance(this)
.updatePreviewDataForRecordedPrograms();
}
}
- Debug.getTimer(Debug.TAG_START_UP_TIMER).log("finish TvApplication.start");
+ Debug.getTimer(Debug.TAG_START_UP_TIMER)
+ .log("finish TvApplication.setCurrentRunningProcess");
}
private void checkTunerServiceOnFirstLaunch() {
@@ -198,24 +255,13 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet
boolean isFirstLaunch = sharedPreferences.getBoolean(PREFERENCE_IS_FIRST_LAUNCH, true);
if (isFirstLaunch) {
if (DEBUG) Log.d(TAG, "Congratulations, it's the first launch!");
- getTunerInputController()
- .onCheckingUsbTunerStatus(this, ACTION_APPLICATION_FIRST_LAUNCHED);
+ TunerInputController.onCheckingUsbTunerStatus(this, ACTION_APPLICATION_FIRST_LAUNCHED);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean(PREFERENCE_IS_FIRST_LAUNCH, false);
editor.apply();
}
}
- @Override
- public EpgFetcher getEpgFetcher() {
- return mEpgFetcher;
- }
-
- @Override
- public synchronized SetupUtils getSetupUtils() {
- return SetupUtils.createForTvSingletons(this);
- }
-
/** Returns the {@link DvrManager}. */
@Override
public DvrManager getDvrManager() {
@@ -253,6 +299,18 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet
return mInputSessionManager;
}
+ /** Returns the {@link Analytics}. */
+ @Override
+ public Analytics getAnalytics() {
+ return mAnalytics;
+ }
+
+ /** Returns the default tracker. */
+ @Override
+ public Tracker getTracker() {
+ return mTracker;
+ }
+
/** Returns {@link ChannelDataManager}. */
@Override
public ChannelDataManager getChannelDataManager() {
@@ -315,19 +373,11 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet
return mDvrDataManager;
}
- @Override
+ /** Returns {@link DvrStorageStatusManager}. */
@TargetApi(Build.VERSION_CODES.N)
- public RecordingStorageStatusManager getRecordingStorageStatusManager() {
- if (mDvrStorageStatusManager == null) {
- mDvrStorageStatusManager = new DvrStorageStatusManager(this);
- }
- return mDvrStorageStatusManager;
- }
-
- /** Returns the main activity information. */
@Override
- public MainActivityWrapper getMainActivityWrapper() {
- return mMainActivityWrapper;
+ public DvrStorageStatusManager getDvrStorageStatusManager() {
+ return mDvrStorageStatusManager;
}
/** Returns {@link TvInputManagerHelper}. */
@@ -340,14 +390,28 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet
return mTvInputManagerHelper;
}
+ /** Returns the main activity information. */
+ @Override
+ public MainActivityWrapper getMainActivityWrapper() {
+ return mMainActivityWrapper;
+ }
+
+ /** Returns the {@link AccountHelper}. */
+ @Override
+ public AccountHelper getAccountHelper() {
+ if (mAccountHelper == null) {
+ mAccountHelper = new AccountHelper(getApplicationContext());
+ }
+ return mAccountHelper;
+ }
+
@Override
- public synchronized TunerInputController getTunerInputController() {
- if (mTunerInputController == null) {
- mTunerInputController =
- new TunerInputController(
- ComponentName.unflattenFromString(getEmbeddedTunerInputId()));
+ public RemoteConfig getRemoteConfig() {
+ if (mRemoteConfig == null) {
+ // No need to synchronize this, it does not hurt to create two and throw one away.
+ mRemoteConfig = DefaultConfigManager.createInstance(this).getRemoteConfig();
}
- return mTunerInputController;
+ return mRemoteConfig;
}
@Override
@@ -355,6 +419,14 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet
return mRunningInMainProcess != null && mRunningInMainProcess;
}
+ @Override
+ public PerformanceMonitor getPerformanceMonitor() {
+ if (mPerformanceMonitor == null) {
+ mPerformanceMonitor = StubPerformanceMonitor.initialize(this);
+ }
+ return mPerformanceMonitor;
+ }
+
/**
* SelectInputActivity is set in {@link SelectInputActivity#onCreate} and cleared in {@link
* SelectInputActivity#onDestroy}.
@@ -441,10 +513,9 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet
}
/**
- * Checks the input counts and enable/disable TvActivity. Also upda162 the input list in {@link
+ * Checks the input counts and enable/disable TvActivity. Also updates the input list in {@link
* SetupUtils}.
*/
- @Override
public void handleInputCountChanged() {
handleInputCountChanged(false, false, false);
}
@@ -453,8 +524,8 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet
* Checks the input counts and enable/disable TvActivity. Also updates the input list in {@link
* SetupUtils}.
*
- * @param calledByTunerServiceChanged true if it is called when BaseTunerTvInputService is
- * enabled or disabled.
+ * @param calledByTunerServiceChanged true if it is called when TunerTvInputService is enabled
+ * or disabled.
* @param tunerServiceEnabled it's available only when calledByTunerServiceChanged is true.
* @param dontKillApp when TvActivity is enabled or disabled by this method, the app restarts by
* default. But, if dontKillApp is true, the app won't restart.
@@ -464,7 +535,7 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet
TvInputManager inputManager = (TvInputManager) getSystemService(Context.TV_INPUT_SERVICE);
boolean enable =
(calledByTunerServiceChanged && tunerServiceEnabled)
- || TvFeatures.UNHIDE.isEnabled(TvApplication.this);
+ || Features.UNHIDE.isEnabled(TvApplication.this);
if (!enable) {
List<TvInputInfo> inputs = inputManager.getTvInputList();
boolean skipTunerInputCheck = false;
@@ -473,7 +544,7 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet
for (TvInputInfo input : inputs) {
if (calledByTunerServiceChanged
&& !tunerServiceEnabled
- && getEmbeddedTunerInputId().equals(input.getId())) {
+ && TunerTvInputService.getInputId(this).equals(input.getId())) {
continue;
}
if (input.getType() == TvInputInfo.TYPE_TUNER) {
@@ -495,6 +566,34 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet
name, newState, dontKillApp ? PackageManager.DONT_KILL_APP : 0);
Log.i(TAG, (enable ? "Un-hide" : "Hide") + " Live TV.");
}
- getSetupUtils().onInputListUpdated(inputManager);
+ SetupUtils.getInstance(TvApplication.this).onInputListUpdated(inputManager);
+ }
+
+ /** Returns the @{@link ApplicationSingletons} using the application context. */
+ public static ApplicationSingletons getSingletons(Context context) {
+ // No need to be "synchronized" because this doesn't create any instance.
+ if (sAppSingletons == null) {
+ sAppSingletons = (ApplicationSingletons) context.getApplicationContext();
+ }
+ return sAppSingletons;
+ }
+
+ /**
+ * Sets true, if TvApplication is running on the main process. If TvApplication runs on tuner
+ * process or other process, it sets false.
+ *
+ * <p>Note: it should be called at the beginning of Service.onCreate Activity.onCreate, or
+ * BroadcastReceiver.onCreate. When it is firstly called after launch, it runs process specific
+ * initializations.
+ */
+ public static void setCurrentRunningProcess(Context context, boolean isMainProcess) {
+ // TODO(b/63064354) TvApplication should not have to know if it is "the main process"
+ if (context.getApplicationContext() instanceof TvApplication) {
+ TvApplication tvApplication = (TvApplication) context.getApplicationContext();
+ tvApplication.setCurrentRunningProcess(isMainProcess);
+ } else {
+ // Application context can be MockTvApplication.
+ Log.w(TAG, "It is not a context of TvApplication");
+ }
}
}
diff --git a/src/com/android/tv/TvFeatures.java b/src/com/android/tv/TvFeatures.java
deleted file mode 100644
index 64141e8c..00000000
--- a/src/com/android/tv/TvFeatures.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.tv;
-
-import static com.android.tv.common.feature.EngOnlyFeature.ENG_ONLY_FEATURE;
-import static com.android.tv.common.feature.FeatureUtils.AND;
-import static com.android.tv.common.feature.FeatureUtils.OFF;
-import static com.android.tv.common.feature.FeatureUtils.ON;
-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.GServiceFeature;
-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.util.PermissionUtils;
-
-
-
-/**
- * List of {@link Feature} for the Live TV App.
- *
- * <p>Remove the {@code Feature} once it is launched.
- */
-public final class TvFeatures extends CommonFeatures {
-
- /** 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);
-
- public static final Feature EPG_SEARCH =
- PropertyFeature.create("feature_tv_use_epg_search", false);
-
- private static final String GSERVICE_KEY_UNHIDE = "live_channels_unhide";
- /** A flag which indicates that LC app is unhidden even when there is no input. */
- public static final Feature UNHIDE =
- OR(
- new GServiceFeature(GSERVICE_KEY_UNHIDE, false),
- new Feature() {
- @Override
- public boolean isEnabled(Context context) {
- // If LC app runs as non-system app, we unhide the app.
- return !PermissionUtils.hasAccessAllEpg(context);
- }
- });
-
- public static final Feature PICTURE_IN_PICTURE =
- new Feature() {
- private Boolean mEnabled;
-
- @Override
- public boolean isEnabled(Context context) {
- if (mEnabled == null) {
- mEnabled =
- Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
- && context.getPackageManager()
- .hasSystemFeature(
- PackageManager.FEATURE_PICTURE_IN_PICTURE);
- }
- return mEnabled;
- }
- };
-
- /** Enable a conflict dialog between currently watched channel and upcoming recording. */
- public static final Feature SHOW_UPCOMING_CONFLICT_DIALOG = OFF;
-
- /** 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/analytics/SendChannelStatusRunnable.java b/src/com/android/tv/analytics/SendChannelStatusRunnable.java
index 2f208828..601e82f7 100644
--- a/src/com/android/tv/analytics/SendChannelStatusRunnable.java
+++ b/src/com/android/tv/analytics/SendChannelStatusRunnable.java
@@ -31,8 +31,7 @@ import java.util.concurrent.TimeUnit;
*
* <p>
*
- * <p>This should only be started from a user activity like {@link
- * com.android.tv.MainActivity}.
+ * <p>This should only be started from a user activity like {@link com.android.tv.MainActivity}.
*/
@MainThread
public class SendChannelStatusRunnable implements Runnable {
diff --git a/src/com/android/tv/app/LiveTvApplication.java b/src/com/android/tv/app/LiveTvApplication.java
deleted file mode 100644
index 1c4f1522..00000000
--- a/src/com/android/tv/app/LiveTvApplication.java
+++ /dev/null
@@ -1,137 +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.app;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.media.tv.TvContract;
-import com.android.tv.tuner.tvinput.LiveTvTunerTvInputService;
-import com.android.tv.TvApplication;
-import com.android.tv.analytics.Analytics;
-import com.android.tv.analytics.StubAnalytics;
-import com.android.tv.analytics.Tracker;
-import com.android.tv.common.CommonConstants;
-import com.android.tv.common.config.DefaultConfigManager;
-import com.android.tv.common.config.api.RemoteConfig;
-import com.android.tv.common.experiments.ExperimentLoader;
-import com.android.tv.common.util.CommonUtils;
-import com.android.tv.data.epg.EpgReader;
-import com.android.tv.data.epg.StubEpgReader;
-import com.android.tv.perf.PerformanceMonitor;
-import com.android.tv.perf.StubPerformanceMonitor;
-import com.android.tv.tuner.setup.LiveTvTunerSetupActivity;
-import com.android.tv.util.account.AccountHelper;
-import com.android.tv.util.account.AccountHelperImpl;
-import javax.inject.Provider;
-
-/** The top level application for Live TV. */
-public class LiveTvApplication extends TvApplication {
- protected static final String TV_ACTIVITY_CLASS_NAME = "com.android.tv.TvActivity";
-
- private final StubPerformanceMonitor performanceMonitor = new StubPerformanceMonitor();
- private final Provider<EpgReader> mEpgReaderProvider =
- new Provider<EpgReader>() {
-
- @Override
- public EpgReader get() {
- return new StubEpgReader(LiveTvApplication.this);
- }
- };
-
- private AccountHelper mAccountHelper;
- private Analytics mAnalytics;
- private Tracker mTracker;
- private String mEmbeddedInputId;
- private RemoteConfig mRemoteConfig;
- private ExperimentLoader mExperimentLoader;
-
- /** Returns the {@link AccountHelperImpl}. */
- @Override
- public AccountHelper getAccountHelper() {
- if (mAccountHelper == null) {
- mAccountHelper = new AccountHelperImpl(getApplicationContext());
- }
- return mAccountHelper;
- }
-
- @Override
- public synchronized PerformanceMonitor getPerformanceMonitor() {
- return performanceMonitor;
- }
-
- @Override
- public Provider<EpgReader> providesEpgReader() {
- return mEpgReaderProvider;
- }
-
- @Override
- public ExperimentLoader getExperimentLoader() {
- mExperimentLoader = new ExperimentLoader();
- return mExperimentLoader;
- }
-
- /** Returns the {@link Analytics}. */
- @Override
- public synchronized Analytics getAnalytics() {
- if (mAnalytics == null) {
- mAnalytics = StubAnalytics.getInstance(this);
- }
- return mAnalytics;
- }
-
- /** Returns the default tracker. */
- @Override
- public synchronized Tracker getTracker() {
- if (mTracker == null) {
- mTracker = getAnalytics().getDefaultTracker();
- }
- return mTracker;
- }
-
- @Override
- public Intent getTunerSetupIntent(Context context) {
- // Make an intent to launch the setup activity of TV tuner input.
- Intent intent =
- CommonUtils.createSetupIntent(
- new Intent(context, LiveTvTunerSetupActivity.class), mEmbeddedInputId);
- intent.putExtra(CommonConstants.EXTRA_INPUT_ID, mEmbeddedInputId);
- Intent tvActivityIntent = new Intent();
- tvActivityIntent.setComponent(new ComponentName(context, TV_ACTIVITY_CLASS_NAME));
- intent.putExtra(CommonConstants.EXTRA_ACTIVITY_AFTER_COMPLETION, tvActivityIntent);
- return intent;
- }
-
- @Override
- public synchronized String getEmbeddedTunerInputId() {
- if (mEmbeddedInputId == null) {
- mEmbeddedInputId =
- TvContract.buildInputId(
- new ComponentName(this, LiveTvTunerTvInputService.class));
- }
- return mEmbeddedInputId;
- }
-
- @Override
- public RemoteConfig getRemoteConfig() {
- if (mRemoteConfig == null) {
- // No need to synchronize this, it does not hurt to create two and throw one away.
- mRemoteConfig = DefaultConfigManager.createInstance(this).getRemoteConfig();
- }
- return mRemoteConfig;
- }
-}
diff --git a/tuner/src/com/android/tv/tuner/tvinput/LiveTvTunerTvInputService.java b/src/com/android/tv/config/ConfigKeys.java
index 67faca4f..135017ae 100644
--- a/tuner/src/com/android/tv/tuner/tvinput/LiveTvTunerTvInputService.java
+++ b/src/com/android/tv/config/ConfigKeys.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,9 +14,10 @@
* limitations under the License.
*/
-package com.android.tv.tuner.tvinput;
+package com.android.tv.config;
-import com.android.tv.tuner.tvinput.BaseTunerTvInputService;
+/** Static list of config keys. */
+public final class ConfigKeys {
-/** Live TV embedded tuner. */
-public class LiveTvTunerTvInputService extends BaseTunerTvInputService {}
+ private ConfigKeys() {}
+}
diff --git a/common/src/com/android/tv/common/config/DefaultConfigManager.java b/src/com/android/tv/config/DefaultConfigManager.java
index f8e706d1..4d754d1f 100644
--- a/common/src/com/android/tv/common/config/DefaultConfigManager.java
+++ b/src/com/android/tv/config/DefaultConfigManager.java
@@ -14,10 +14,9 @@
* limitations under the License.
*/
-package com.android.tv.common.config;
+package com.android.tv.config;
import android.content.Context;
-import com.android.tv.common.config.api.RemoteConfig;
/** Stub Remote Config. */
public class DefaultConfigManager {
diff --git a/common/src/com/android/tv/common/config/api/RemoteConfig.java b/src/com/android/tv/config/RemoteConfig.java
index 8c1bc44b..d72a1f3f 100644
--- a/common/src/com/android/tv/common/config/api/RemoteConfig.java
+++ b/src/com/android/tv/config/RemoteConfig.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.tv.common.config.api;
+package com.android.tv.config;
/**
* Manages Live TV Configuration, allowing remote updates.
@@ -24,11 +24,6 @@ package com.android.tv.common.config.api;
*/
public interface RemoteConfig {
- /** Used to inject a remote config */
- interface HasRemoteConfig {
- RemoteConfig getRemoteConfig();
- }
-
/** Notified on successful completion of a {@link #fetch)} */
interface OnRemoteConfigUpdatedListener {
void onRemoteConfigUpdated();
diff --git a/common/src/com/android/tv/common/config/RemoteConfigFeature.java b/src/com/android/tv/config/RemoteConfigFeature.java
index 66acb0cf..c22446be 100644
--- a/common/src/com/android/tv/common/config/RemoteConfigFeature.java
+++ b/src/com/android/tv/config/RemoteConfigFeature.java
@@ -14,16 +14,13 @@
* limitations under the License
*/
-package com.android.tv.common.config;
+package com.android.tv.config;
import android.content.Context;
-import com.android.tv.common.BaseApplication;
+import com.android.tv.TvApplication;
import com.android.tv.common.feature.Feature;
-/**
- * A {@link Feature} controlled by a {@link com.android.tv.common.config.api.RemoteConfig}
- * boolean.
- */
+/** A {@link Feature} controlled by a {@link RemoteConfig} boolean. */
public class RemoteConfigFeature implements Feature {
private final String mKey;
@@ -38,6 +35,6 @@ public class RemoteConfigFeature implements Feature {
@Override
public boolean isEnabled(Context context) {
- return BaseApplication.getSingletons(context).getRemoteConfig().getBoolean(mKey);
+ return TvApplication.getSingletons(context).getRemoteConfig().getBoolean(mKey);
}
}
diff --git a/common/src/com/android/tv/common/config/RemoteConfigUtils.java b/src/com/android/tv/config/RemoteConfigUtils.java
index 9d0ddf47..09d85239 100644
--- a/common/src/com/android/tv/common/config/RemoteConfigUtils.java
+++ b/src/com/android/tv/config/RemoteConfigUtils.java
@@ -14,22 +14,21 @@
* limitations under the License.
*/
-package com.android.tv.common.config;
+package com.android.tv.config;
import android.content.Context;
import android.util.Log;
-import com.android.tv.common.BaseApplication;
-import com.android.tv.common.config.api.RemoteConfig;
+import com.android.tv.TvApplication;
/** A utility class to get the remote config. */
-public final class RemoteConfigUtils {
+public class RemoteConfigUtils {
private static final String TAG = "RemoteConfigUtils";
private static final boolean DEBUG = false;
private RemoteConfigUtils() {}
public static long getRemoteConfig(Context context, String key, long defaultValue) {
- RemoteConfig remoteConfig = BaseApplication.getSingletons(context).getRemoteConfig();
+ RemoteConfig remoteConfig = TvApplication.getSingletons(context).getRemoteConfig();
try {
long remoteValue = remoteConfig.getLong(key);
if (DEBUG) Log.d(TAG, "Got " + key + " from remote: " + remoteValue);
diff --git a/common/src/com/android/tv/common/customization/CustomAction.java b/src/com/android/tv/customization/CustomAction.java
index ee18cb3c..77a5ae5e 100644
--- a/common/src/com/android/tv/common/customization/CustomAction.java
+++ b/src/com/android/tv/customization/CustomAction.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.tv.common.customization;
+package com.android.tv.customization;
import android.content.Intent;
import android.graphics.drawable.Drawable;
diff --git a/common/src/com/android/tv/common/customization/CustomizationManager.java b/src/com/android/tv/customization/TvCustomizationManager.java
index 5076f5d0..7d21c6d2 100644
--- a/common/src/com/android/tv/common/customization/CustomizationManager.java
+++ b/src/com/android/tv/customization/TvCustomizationManager.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.tv.common.customization;
+package com.android.tv.customization;
import android.content.Context;
import android.content.Intent;
@@ -35,8 +35,8 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
-public class CustomizationManager {
- private static final String TAG = "CustomizationManager";
+public class TvCustomizationManager {
+ private static final String TAG = "TvCustomizationManager";
private static final boolean DEBUG = false;
private static final String[] CUSTOMIZE_PERMISSIONS = {
@@ -88,7 +88,7 @@ public class CustomizationManager {
private String mPartnerRowTitle;
private final Map<String, List<CustomAction>> mRowIdToCustomActionsMap = new HashMap<>();
- public CustomizationManager(Context context) {
+ public TvCustomizationManager(Context context) {
mContext = context;
mInitialized = false;
}
diff --git a/src/com/android/tv/data/Channel.java b/src/com/android/tv/data/Channel.java
index 1204a49f..eda188e4 100644
--- a/src/com/android/tv/data/Channel.java
+++ b/src/com/android/tv/data/Channel.java
@@ -28,8 +28,7 @@ import android.support.annotation.UiThread;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.Log;
-import com.android.tv.common.CommonConstants;
-import com.android.tv.common.util.CommonUtils;
+import com.android.tv.common.TvCommonConstants;
import com.android.tv.util.ImageLoader;
import com.android.tv.util.TvInputManagerHelper;
import com.android.tv.util.Utils;
@@ -125,7 +124,7 @@ public final class Channel {
channel.mAppLinkIconUri = cursor.getString(index++);
channel.mAppLinkPosterArtUri = cursor.getString(index++);
channel.mAppLinkIntentUri = cursor.getString(index++);
- if (CommonUtils.isBundledInput(channel.mInputId)) {
+ if (Utils.isBundledInput(channel.mInputId)) {
channel.mRecordingProhibited = cursor.getInt(index++) != 0;
}
return channel;
@@ -626,7 +625,7 @@ public final class Channel {
if (intent.resolveActivityInfo(pm, 0) != null) {
mAppLinkIntent = intent;
mAppLinkIntent.putExtra(
- CommonConstants.EXTRA_APP_LINK_CHANNEL_URI, getUri().toString());
+ TvCommonConstants.EXTRA_APP_LINK_CHANNEL_URI, getUri().toString());
mAppLinkType = APP_LINK_TYPE_CHANNEL;
return;
} else {
@@ -643,7 +642,7 @@ public final class Channel {
mAppLinkIntent = pm.getLeanbackLaunchIntentForPackage(mPackageName);
if (mAppLinkIntent != null) {
mAppLinkIntent.putExtra(
- CommonConstants.EXTRA_APP_LINK_CHANNEL_URI, getUri().toString());
+ TvCommonConstants.EXTRA_APP_LINK_CHANNEL_URI, getUri().toString());
mAppLinkType = APP_LINK_TYPE_APP;
}
}
diff --git a/src/com/android/tv/data/ChannelDataManager.java b/src/com/android/tv/data/ChannelDataManager.java
index 68fbdb6a..e4d1cd85 100644
--- a/src/com/android/tv/data/ChannelDataManager.java
+++ b/src/com/android/tv/data/ChannelDataManager.java
@@ -38,11 +38,11 @@ import android.support.annotation.VisibleForTesting;
import android.util.ArraySet;
import android.util.Log;
import android.util.MutableInt;
+import com.android.tv.common.SharedPreferencesUtils;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.WeakHandler;
-import com.android.tv.common.util.PermissionUtils;
-import com.android.tv.common.util.SharedPreferencesUtils;
import com.android.tv.util.AsyncDbTask;
+import com.android.tv.util.PermissionUtils;
import com.android.tv.util.TvInputManagerHelper;
import com.android.tv.util.Utils;
import java.io.IOException;
@@ -62,7 +62,6 @@ import java.util.concurrent.CopyOnWriteArraySet;
* methods are called in only the main thread.
*/
@AnyThread
-@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed
public class ChannelDataManager {
private static final String TAG = "ChannelDataManager";
private static final boolean DEBUG = false;
diff --git a/src/com/android/tv/data/ChannelLogoFetcher.java b/src/com/android/tv/data/ChannelLogoFetcher.java
index 8aaaf73a..2dc43102 100644
--- a/src/com/android/tv/data/ChannelLogoFetcher.java
+++ b/src/com/android/tv/data/ChannelLogoFetcher.java
@@ -28,10 +28,10 @@ import android.os.RemoteException;
import android.support.annotation.MainThread;
import android.text.TextUtils;
import android.util.Log;
-import com.android.tv.common.util.PermissionUtils;
-import com.android.tv.common.util.SharedPreferencesUtils;
+import com.android.tv.common.SharedPreferencesUtils;
import com.android.tv.util.BitmapUtils;
import com.android.tv.util.BitmapUtils.ScaledBitmapInfo;
+import com.android.tv.util.PermissionUtils;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
@@ -42,7 +42,6 @@ import java.util.Map;
* Fetches channel logos from the cloud into the database. It's for the channels which have no logos
* or need update logos. This class is thread safe.
*/
-@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed
public class ChannelLogoFetcher {
private static final String TAG = "ChannelLogoFetcher";
private static final boolean DEBUG = false;
diff --git a/src/com/android/tv/data/ChannelNumber.java b/src/com/android/tv/data/ChannelNumber.java
index 1623b33d..63f8a972 100644
--- a/src/com/android/tv/data/ChannelNumber.java
+++ b/src/com/android/tv/data/ChannelNumber.java
@@ -19,7 +19,7 @@ package com.android.tv.data;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.view.KeyEvent;
-import com.android.tv.common.util.StringUtils;
+import com.android.tv.util.StringUtils;
import java.util.Objects;
/** A convenience class to handle channel number. */
@@ -43,23 +43,6 @@ public final class ChannelNumber implements Comparable<ChannelNumber> {
reset();
}
- /**
- * {@code lhs} and {@code rhs} are equivalent if {@link ChannelNumber#compare(String, String)}
- * is 0 or if only one has a delimiter and both {@link ChannelNumber#majorNumber} equals.
- */
- public static boolean equivalent(String lhs, String rhs) {
- if (compare(lhs, rhs) == 0) {
- return true;
- }
- // Match if only one has delimiter
- ChannelNumber lhsNumber = parseChannelNumber(lhs);
- ChannelNumber rhsNumber = parseChannelNumber(rhs);
- return lhsNumber != null
- && rhsNumber != null
- && lhsNumber.hasDelimiter != rhsNumber.hasDelimiter
- && lhsNumber.majorNumber.equals(rhsNumber.majorNumber);
- }
-
public void reset() {
setChannelNumber("", false, "");
}
diff --git a/src/com/android/tv/data/InternalDataUtils.java b/src/com/android/tv/data/InternalDataUtils.java
index 99a3d4e8..4c30d395 100644
--- a/src/com/android/tv/data/InternalDataUtils.java
+++ b/src/com/android/tv/data/InternalDataUtils.java
@@ -33,7 +33,6 @@ import java.util.List;
* android.media.tv.TvContract.Programs#COLUMN_INTERNAL_PROVIDER_DATA} field in the {@link
* android.media.tv.TvContract.Programs}.
*/
-@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed
public final class InternalDataUtils {
private static final boolean DEBUG = false;
private static final String TAG = "InternalDataUtils";
diff --git a/src/com/android/tv/data/Lineup.java b/src/com/android/tv/data/Lineup.java
index 4393cd3d..0f11c1cc 100644
--- a/src/com/android/tv/data/Lineup.java
+++ b/src/com/android/tv/data/Lineup.java
@@ -19,45 +19,23 @@ package com.android.tv.data;
import android.support.annotation.IntDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.Collections;
-import java.util.List;
/** A class that represents a lineup. */
public class Lineup {
/** The ID of this lineup. */
- public String getId() {
- return id;
- }
+ public final String id;
/** The type associated with this lineup. */
- public int getType() {
- return type;
- }
-
- /** The human readable name associated with this lineup. */
- public String getName() {
- return name;
- }
+ public final int type;
/** The human readable name associated with this lineup. */
- public String getLocation() {
- return location;
- }
-
- /** An unmodifiable list of channel numbers that this lineup has. */
- public List<String> getChannels() {
- return channels;
- }
+ public final String name;
- private final String id;
-
- private final int type;
-
- private final String name;
-
- private final String location;
-
- private final List<String> channels;
+ /**
+ * Location this lineup can be found. This is a human readable description of a geographic
+ * location.
+ */
+ public final String location;
@Retention(RetentionPolicy.SOURCE)
@IntDef({
@@ -66,9 +44,7 @@ public class Lineup {
LINEUP_BROADCAST_DIGITAL,
LINEUP_BROADCAST_ANALOG,
LINEUP_IPTV,
- LINEUP_MVPD,
- LINEUP_INTERNET,
- LINEUP_OTHER
+ LINEUP_MVPD
})
public @interface LineupType {}
@@ -88,23 +64,16 @@ public class Lineup {
public static final int LINEUP_IPTV = 4;
/**
- * Indicates the lineup is either satellite, cable or IPTV but we are not sure which specific
+ * Indicates the lineup is either satelite, cable or IPTV but we are not sure which specific
* type.
*/
public static final int LINEUP_MVPD = 5;
- /** Lineup type for Internet. */
- public static final int LINEUP_INTERNET = 6;
-
- /** Lineup type for other. */
- public static final int LINEUP_OTHER = 7;
-
/** Creates a lineup. */
- public Lineup(String id, int type, String name, String location, List<String> channels) {
+ public Lineup(String id, int type, String name, String location) {
this.id = id;
this.type = type;
this.name = name;
this.location = location;
- this.channels = Collections.unmodifiableList(channels);
}
}
diff --git a/src/com/android/tv/data/PreviewDataManager.java b/src/com/android/tv/data/PreviewDataManager.java
index ac78147b..b103a5d7 100644
--- a/src/com/android/tv/data/PreviewDataManager.java
+++ b/src/com/android/tv/data/PreviewDataManager.java
@@ -36,7 +36,7 @@ import android.support.media.tv.PreviewProgram;
import android.util.Log;
import android.util.Pair;
import com.android.tv.R;
-import com.android.tv.common.util.PermissionUtils;
+import com.android.tv.util.PermissionUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.HashMap;
@@ -47,22 +47,22 @@ import java.util.concurrent.CopyOnWriteArraySet;
/** Class to manage the preview data. */
@TargetApi(Build.VERSION_CODES.O)
@MainThread
-@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed
public class PreviewDataManager {
private static final String TAG = "PreviewDataManager";
- private static final boolean DEBUG = false;
+ // STOPSHIP: set it to false.
+ private static final boolean DEBUG = true;
/** Invalid preview channel ID. */
public static final long INVALID_PREVIEW_CHANNEL_ID = -1;
- @IntDef({TYPE_DEFAULT_PREVIEW_CHANNEL, TYPE_RECORDED_PROGRAM_PREVIEW_CHANNEL})
+ @IntDef({(int) TYPE_DEFAULT_PREVIEW_CHANNEL, (int) TYPE_RECORDED_PROGRAM_PREVIEW_CHANNEL})
@Retention(RetentionPolicy.SOURCE)
public @interface PreviewChannelType {}
/** Type of default preview channel */
- public static final int TYPE_DEFAULT_PREVIEW_CHANNEL = 1;
+ public static final long TYPE_DEFAULT_PREVIEW_CHANNEL = 1;
/** Type of recorded program channel */
- public static final int TYPE_RECORDED_PROGRAM_PREVIEW_CHANNEL = 2;
+ public static final long TYPE_RECORDED_PROGRAM_PREVIEW_CHANNEL = 2;
private final Context mContext;
private final ContentResolver mContentResolver;
@@ -604,8 +604,7 @@ public class PreviewDataManager {
.setPosterArtUri(program.getPosterArtUri())
.setIntentUri(program.getIntentUri())
.setPreviewVideoUri(program.getPreviewVideoUri())
- .setInternalProviderId(Long.toString(program.getId()))
- .setContentId(program.getIntentUri().toString());
+ .setInternalProviderId(Long.toString(program.getId()));
return builder.build();
}
diff --git a/src/com/android/tv/data/PreviewProgramContent.java b/src/com/android/tv/data/PreviewProgramContent.java
index 252092b0..845ca9d4 100644
--- a/src/com/android/tv/data/PreviewProgramContent.java
+++ b/src/com/android/tv/data/PreviewProgramContent.java
@@ -17,18 +17,17 @@
package com.android.tv.data;
import android.content.Context;
+import android.media.tv.TvContract;
import android.net.Uri;
-import android.support.annotation.VisibleForTesting;
-import android.support.media.tv.TvContractCompat;
import android.text.TextUtils;
import android.util.Pair;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.dvr.data.RecordedProgram;
import java.util.Objects;
/** A class to store the content of preview programs. */
public class PreviewProgramContent {
- @VisibleForTesting static final String PARAM_INPUT = "input";
+ private static final String PARAM_INPUT = "input";
private long mId;
private long mPreviewChannelId;
@@ -44,30 +43,17 @@ public class PreviewProgramContent {
public static PreviewProgramContent createFromProgram(
Context context, long previewChannelId, Program program) {
Channel channel =
- TvSingletons.getSingletons(context)
+ TvApplication.getSingletons(context)
.getChannelDataManager()
.getChannel(program.getChannelId());
- return channel == null ? null : createFromProgram(previewChannelId, program, channel);
- }
-
- /** Create preview program content from {@link RecordedProgram} */
- public static PreviewProgramContent createFromRecordedProgram(
- Context context, long previewChannelId, RecordedProgram recordedProgram) {
- Channel channel =
- TvSingletons.getSingletons(context)
- .getChannelDataManager()
- .getChannel(recordedProgram.getChannelId());
- return createFromRecordedProgram(previewChannelId, recordedProgram, channel);
- }
-
- @VisibleForTesting
- static PreviewProgramContent createFromProgram(
- long previewChannelId, Program program, Channel channel) {
+ if (channel == null) {
+ return null;
+ }
String channelDisplayName = channel.getDisplayName();
return new PreviewProgramContent.Builder()
.setId(program.getId())
.setPreviewChannelId(previewChannelId)
- .setType(TvContractCompat.PreviewPrograms.TYPE_CHANNEL)
+ .setType(TvContract.PreviewPrograms.TYPE_CHANNEL)
.setLive(true)
.setTitle(program.getTitle())
.setDescription(
@@ -82,15 +68,22 @@ public class PreviewProgramContent {
.build();
}
- @VisibleForTesting
- static PreviewProgramContent createFromRecordedProgram(
- long previewChannelId, RecordedProgram recordedProgram, Channel channel) {
- String channelDisplayName = channel == null ? null : channel.getDisplayName();
- Uri recordedProgramUri = TvContractCompat.buildRecordedProgramUri(recordedProgram.getId());
+ /** Create preview program content from {@link RecordedProgram} */
+ public static PreviewProgramContent createFromRecordedProgram(
+ Context context, long previewChannelId, RecordedProgram recordedProgram) {
+ Channel channel =
+ TvApplication.getSingletons(context)
+ .getChannelDataManager()
+ .getChannel(recordedProgram.getChannelId());
+ String channelDisplayName = null;
+ if (channel != null) {
+ channelDisplayName = channel.getDisplayName();
+ }
+ Uri recordedProgramUri = TvContract.buildRecordedProgramUri(recordedProgram.getId());
return new PreviewProgramContent.Builder()
.setId(recordedProgram.getId())
.setPreviewChannelId(previewChannelId)
- .setType(TvContractCompat.PreviewPrograms.TYPE_CLIP)
+ .setType(TvContract.PreviewPrograms.TYPE_CLIP)
.setTitle(recordedProgram.getTitle())
.setDescription(channelDisplayName != null ? channelDisplayName : "")
.setPosterArtUri(Uri.parse(recordedProgram.getPosterArtUri()))
diff --git a/src/com/android/tv/data/Program.java b/src/com/android/tv/data/Program.java
index 30a3033e..f47a3a06 100644
--- a/src/com/android/tv/data/Program.java
+++ b/src/com/android/tv/data/Program.java
@@ -33,9 +33,8 @@ import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.Log;
import com.android.tv.common.BuildConfig;
+import com.android.tv.common.CollectionUtils;
import com.android.tv.common.TvContentRatingCache;
-import com.android.tv.common.util.CollectionUtils;
-import com.android.tv.common.util.CommonUtils;
import com.android.tv.util.ImageLoader;
import com.android.tv.util.Utils;
import java.io.Serializable;
@@ -129,7 +128,7 @@ public final class Program extends BaseProgram implements Comparable<Program>, P
builder.setEndTimeUtcMillis(cursor.getLong(index++));
builder.setVideoWidth((int) cursor.getLong(index++));
builder.setVideoHeight((int) cursor.getLong(index++));
- if (CommonUtils.isInBundledPackageSet(packageName)) {
+ if (Utils.isInBundledPackageSet(packageName)) {
InternalDataUtils.deserializeInternalProviderData(cursor.getBlob(index), builder);
}
index++;
@@ -476,9 +475,6 @@ public final class Program extends BaseProgram implements Comparable<Program>, P
public static ContentValues toContentValues(Program program) {
ContentValues values = new ContentValues();
values.put(TvContract.Programs.COLUMN_CHANNEL_ID, program.getChannelId());
- if (!TextUtils.isEmpty(program.getPackageName())) {
- values.put(Programs.COLUMN_PACKAGE_NAME, program.getPackageName());
- }
putValue(values, TvContract.Programs.COLUMN_TITLE, program.getTitle());
putValue(values, TvContract.Programs.COLUMN_EPISODE_TITLE, program.getEpisodeTitle());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
diff --git a/src/com/android/tv/data/ProgramDataManager.java b/src/com/android/tv/data/ProgramDataManager.java
index 3a7693a4..639ac99a 100644
--- a/src/com/android/tv/data/ProgramDataManager.java
+++ b/src/com/android/tv/data/ProgramDataManager.java
@@ -35,8 +35,8 @@ import android.util.LongSparseArray;
import android.util.LruCache;
import com.android.tv.common.MemoryManageable;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.common.util.Clock;
import com.android.tv.util.AsyncDbTask;
+import com.android.tv.util.Clock;
import com.android.tv.util.MultiLongSparseArray;
import com.android.tv.util.Utils;
import java.util.ArrayList;
@@ -52,7 +52,6 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@MainThread
-@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed
public class ProgramDataManager implements MemoryManageable {
private static final String TAG = "ProgramDataManager";
private static final boolean DEBUG = false;
diff --git a/src/com/android/tv/data/WatchedHistoryManager.java b/src/com/android/tv/data/WatchedHistoryManager.java
index 25ba7716..8c9756b0 100644
--- a/src/com/android/tv/data/WatchedHistoryManager.java
+++ b/src/com/android/tv/data/WatchedHistoryManager.java
@@ -1,18 +1,3 @@
-/*
- * 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 android.content.Context;
@@ -27,7 +12,7 @@ import android.support.annotation.NonNull;
import android.support.annotation.VisibleForTesting;
import android.support.annotation.WorkerThread;
import android.util.Log;
-import com.android.tv.common.util.SharedPreferencesUtils;
+import com.android.tv.common.SharedPreferencesUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -43,7 +28,6 @@ import java.util.concurrent.TimeUnit;
*
* <p>Note that this class is not thread safe. Please use this on one thread.
*/
-@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed
public class WatchedHistoryManager {
private static final String TAG = "WatchedHistoryManager";
private static final boolean DEBUG = false;
diff --git a/src/com/android/tv/data/epg/AutoValue_EpgReader_EpgChannel.java b/src/com/android/tv/data/epg/AutoValue_EpgReader_EpgChannel.java
deleted file mode 100644
index 90d109d7..00000000
--- a/src/com/android/tv/data/epg/AutoValue_EpgReader_EpgChannel.java
+++ /dev/null
@@ -1,86 +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.data.epg;
-
-import com.android.tv.data.Channel;
-
-/**
- * Hand copy of generated Autovalue class.
- *
- * TODO get autovalue working
- */
-final class AutoValue_EpgReader_EpgChannel extends EpgReader.EpgChannel {
-
- private final Channel channel;
- private final String epgChannelId;
-
- AutoValue_EpgReader_EpgChannel(
- Channel channel,
- String epgChannelId) {
- if (channel == null) {
- throw new NullPointerException("Null channel");
- }
- this.channel = channel;
- if (epgChannelId == null) {
- throw new NullPointerException("Null epgChannelId");
- }
- this.epgChannelId = epgChannelId;
- }
-
- @Override
- public Channel getChannel() {
- return channel;
- }
-
- @Override
- public String getEpgChannelId() {
- return epgChannelId;
- }
-
- @Override
- public String toString() {
- return "EpgChannel{"
- + "channel=" + channel + ", "
- + "epgChannelId=" + epgChannelId
- + "}";
- }
-
- @Override
- public boolean equals(Object o) {
- if (o == this) {
- return true;
- }
- if (o instanceof EpgReader.EpgChannel) {
- EpgReader.EpgChannel that = (EpgReader.EpgChannel) o;
- return (this.channel.equals(that.getChannel()))
- && (this.epgChannelId.equals(that.getEpgChannelId()));
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- int h = 1;
- h *= 1000003;
- h ^= this.channel.hashCode();
- h *= 1000003;
- h ^= this.epgChannelId.hashCode();
- return h;
- }
-
-}
-
diff --git a/src/com/android/tv/data/epg/EpgFetchHelper.java b/src/com/android/tv/data/epg/EpgFetchHelper.java
index 30123ee5..89d5f494 100644
--- a/src/com/android/tv/data/epg/EpgFetchHelper.java
+++ b/src/com/android/tv/data/epg/EpgFetchHelper.java
@@ -27,15 +27,13 @@ import android.preference.PreferenceManager;
import android.support.annotation.WorkerThread;
import android.text.TextUtils;
import android.util.Log;
-import com.android.tv.common.util.Clock;
import com.android.tv.data.Program;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
-/** The helper class for {@link EpgFetcher} */
-@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed
+/** The helper class for {@link com.android.tv.data.epg.EpgFetcher} */
class EpgFetchHelper {
private static final String TAG = "EpgFetchHelper";
private static final boolean DEBUG = false;
@@ -66,14 +64,13 @@ class EpgFetchHelper {
* @param fetchedPrograms the newly fetched program data.
* @return {@code true} if new program data are successfully updated. Otherwise {@code false}.
*/
- static boolean updateEpgData(
- Context context, Clock clock, long channelId, List<Program> fetchedPrograms) {
+ static boolean updateEpgData(Context context, long channelId, List<Program> fetchedPrograms) {
final int fetchedProgramsCount = fetchedPrograms.size();
if (fetchedProgramsCount == 0) {
return false;
}
boolean updated = false;
- long startTimeMs = clock.currentTimeMillis();
+ long startTimeMs = System.currentTimeMillis();
long endTimeMs = startTimeMs + PROGRAM_QUERY_DURATION_MS;
List<Program> oldPrograms = queryPrograms(context, channelId, startTimeMs, endTimeMs);
int oldProgramsIndex = 0;
diff --git a/src/com/android/tv/data/epg/EpgFetchService.java b/src/com/android/tv/data/epg/EpgFetchService.java
deleted file mode 100644
index aa4f3588..00000000
--- a/src/com/android/tv/data/epg/EpgFetchService.java
+++ /dev/null
@@ -1,70 +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 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;
-
-/** JobService to Fetch EPG data. */
-public class EpgFetchService extends JobService {
- private EpgFetcher mEpgFetcher;
- private ChannelDataManager mChannelDataManager;
-
- @Override
- public void onCreate() {
- super.onCreate();
- Starter.start(this);
- TvSingletons tvSingletons = TvSingletons.getSingletons(getApplicationContext());
- mEpgFetcher = tvSingletons.getEpgFetcher();
- mChannelDataManager = tvSingletons.getChannelDataManager();
- }
-
- @Override
- public boolean onStartJob(JobParameters params) {
- if (!mChannelDataManager.isDbLoadFinished()) {
- mChannelDataManager.addListener(
- new ChannelDataManager.Listener() {
- @Override
- public void onLoadFinished() {
- mChannelDataManager.removeListener(this);
- if (!mEpgFetcher.executeFetchTaskIfPossible(
- EpgFetchService.this, params)) {
- jobFinished(params, false);
- }
- }
-
- @Override
- public void onChannelListUpdated() {}
-
- @Override
- public void onChannelBrowsableChanged() {}
- });
- return true;
- } else {
- return mEpgFetcher.executeFetchTaskIfPossible(this, params);
- }
- }
-
- @Override
- public boolean onStopJob(JobParameters params) {
- mEpgFetcher.stopFetchingJob();
- return false;
- }
-}
diff --git a/src/com/android/tv/data/epg/EpgFetcher.java b/src/com/android/tv/data/epg/EpgFetcher.java
index 9c24613d..b10bdc1b 100644
--- a/src/com/android/tv/data/epg/EpgFetcher.java
+++ b/src/com/android/tv/data/epg/EpgFetcher.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -16,13 +16,138 @@
package com.android.tv.data.epg;
+import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
import android.app.job.JobService;
+import android.content.ComponentName;
+import android.content.Context;
+import android.media.tv.TvInputInfo;
+import android.net.TrafficStats;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.support.annotation.AnyThread;
import android.support.annotation.MainThread;
+import android.support.annotation.Nullable;
+import android.support.annotation.WorkerThread;
+import android.text.TextUtils;
+import android.util.Log;
+import com.android.tv.ApplicationSingletons;
+import com.android.tv.Features;
+import com.android.tv.TvApplication;
+import com.android.tv.common.SoftPreconditions;
+import com.android.tv.common.TvCommonUtils;
+import com.android.tv.config.RemoteConfigUtils;
+import com.android.tv.data.Channel;
+import com.android.tv.data.ChannelDataManager;
+import com.android.tv.data.ChannelLogoFetcher;
+import com.android.tv.data.Lineup;
+import com.android.tv.data.Program;
+import com.android.tv.perf.EventNames;
+import com.android.tv.perf.PerformanceMonitor;
+import com.android.tv.perf.TimerEvent;
+import com.android.tv.tuner.util.PostalCodeUtils;
+import com.android.tv.util.LocationUtils;
+import com.android.tv.util.NetworkTrafficTags;
+import com.android.tv.util.Utils;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
-/** Fetch EPG routinely or on-demand during channel scanning */
-public interface EpgFetcher {
+/**
+ * The service class to fetch EPG routinely or on-demand during channel scanning
+ *
+ * <p>Since the default executor of {@link AsyncTask} is {@link AsyncTask#SERIAL_EXECUTOR}, only one
+ * task can run at a time. Because fetching EPG takes long time, the fetching task shouldn't run on
+ * the serial executor. Instead, it should run on the {@link AsyncTask#THREAD_POOL_EXECUTOR}.
+ */
+public class EpgFetcher {
+ private static final String TAG = "EpgFetcher";
+ private static final boolean DEBUG = false;
+
+ private static final int EPG_ROUTINELY_FETCHING_JOB_ID = 101;
+
+ private static final long INITIAL_BACKOFF_MS = TimeUnit.SECONDS.toMillis(10);
+
+ private static final int REASON_EPG_READER_NOT_READY = 1;
+ private static final int REASON_LOCATION_INFO_UNAVAILABLE = 2;
+ private static final int REASON_LOCATION_PERMISSION_NOT_GRANTED = 3;
+ private static final int REASON_NO_EPG_DATA_RETURNED = 4;
+ private static final int REASON_NO_NEW_EPG = 5;
+
+ private static final long FETCH_DURING_SCAN_WAIT_TIME_MS = TimeUnit.SECONDS.toMillis(10);
+
+ private static final long FETCH_DURING_SCAN_DURATION_SEC = TimeUnit.HOURS.toSeconds(3);
+ private static final long FAST_FETCH_DURATION_SEC = TimeUnit.DAYS.toSeconds(2);
+
+ private static final int DEFAULT_ROUTINE_INTERVAL_HOUR = 4;
+ private static final String KEY_ROUTINE_INTERVAL = "live_channels_epg_fetcher_interval_hour";
+
+ private static final int MSG_PREPARE_FETCH_DURING_SCAN = 1;
+ private static final int MSG_CHANNEL_UPDATED_DURING_SCAN = 2;
+ 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 static EpgFetcher sInstance;
+
+ private final Context mContext;
+ private final ChannelDataManager mChannelDataManager;
+ private final EpgReader mEpgReader;
+ private final PerformanceMonitor mPerformanceMonitor;
+ private FetchAsyncTask mFetchTask;
+ private FetchDuringScanHandler mFetchDuringScanHandler;
+ private long mEpgTimeStamp;
+ private List<Lineup> mPossibleLineups;
+ private final Object mPossibleLineupsLock = new Object();
+ private final Object mFetchDuringScanHandlerLock = new Object();
+ // A flag to block the re-entrance of onChannelScanStarted and onChannelScanFinished.
+ private boolean mScanStarted;
+
+ private final long mRoutineIntervalMs;
+ private final long mEpgDataExpiredTimeLimitMs;
+ private final long mFastFetchDurationSec;
+
+ public static EpgFetcher getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new EpgFetcher(context);
+ }
+ return sInstance;
+ }
+
+ /** Creates and returns {@link EpgReader}. */
+ public static EpgReader createEpgReader(Context context, String region) {
+ return new StubEpgReader(context);
+ }
+
+ private EpgFetcher(Context context) {
+ mContext = context.getApplicationContext();
+ ApplicationSingletons applicationSingletons = TvApplication.getSingletons(mContext);
+ mChannelDataManager = applicationSingletons.getChannelDataManager();
+ mPerformanceMonitor = applicationSingletons.getPerformanceMonitor();
+ mEpgReader = createEpgReader(mContext, LocationUtils.getCurrentCountry(mContext));
+
+ int remoteInteval =
+ (int)
+ RemoteConfigUtils.getRemoteConfig(
+ context, KEY_ROUTINE_INTERVAL, DEFAULT_ROUTINE_INTERVAL_HOUR);
+ mRoutineIntervalMs =
+ remoteInteval < 0
+ ? TimeUnit.HOURS.toMillis(DEFAULT_ROUTINE_INTERVAL_HOUR)
+ : TimeUnit.HOURS.toMillis(remoteInteval);
+ mEpgDataExpiredTimeLimitMs = mRoutineIntervalMs * 2;
+ mFastFetchDurationSec = FAST_FETCH_DURATION_SEC + mRoutineIntervalMs / 1000;
+ }
/**
* Starts the routine service of EPG fetching. It use {@link JobScheduler} to schedule the EPG
@@ -30,30 +155,590 @@ public interface EpgFetcher {
* channel scanning of tuner input is started.
*/
@MainThread
- void startRoutineService();
+ public void startRoutineService() {
+ JobScheduler jobScheduler =
+ (JobScheduler) mContext.getSystemService(Context.JOB_SCHEDULER_SERVICE);
+ for (JobInfo job : jobScheduler.getAllPendingJobs()) {
+ if (job.getId() == EPG_ROUTINELY_FETCHING_JOB_ID) {
+ return;
+ }
+ }
+ JobInfo job =
+ new JobInfo.Builder(
+ EPG_ROUTINELY_FETCHING_JOB_ID,
+ new ComponentName(mContext, EpgFetchService.class))
+ .setPeriodic(mRoutineIntervalMs)
+ .setBackoffCriteria(INITIAL_BACKOFF_MS, JobInfo.BACKOFF_POLICY_EXPONENTIAL)
+ .setPersisted(true)
+ .build();
+ jobScheduler.schedule(job);
+ Log.i(TAG, "EPG fetching routine service started.");
+ }
/**
* Fetches EPG immediately if current EPG data are out-dated, i.e., not successfully updated by
* routine fetching service due to various reasons.
*/
@MainThread
- void fetchImmediatelyIfNeeded();
+ public void fetchImmediatelyIfNeeded() {
+ if (TvCommonUtils.isRunningInTest()) {
+ // Do not run EpgFetcher in test.
+ return;
+ }
+ new AsyncTask<Void, Void, Long>() {
+ @Override
+ protected Long doInBackground(Void... args) {
+ return EpgFetchHelper.getLastEpgUpdatedTimestamp(mContext);
+ }
+
+ @Override
+ protected void onPostExecute(Long result) {
+ if (System.currentTimeMillis() - EpgFetchHelper.getLastEpgUpdatedTimestamp(mContext)
+ > mEpgDataExpiredTimeLimitMs) {
+ Log.i(TAG, "EPG data expired. Start fetching immediately.");
+ fetchImmediately();
+ }
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
/** Fetches EPG immediately. */
@MainThread
- void fetchImmediately();
+ public void fetchImmediately() {
+ if (!mChannelDataManager.isDbLoadFinished()) {
+ mChannelDataManager.addListener(
+ new ChannelDataManager.Listener() {
+ @Override
+ public void onLoadFinished() {
+ mChannelDataManager.removeListener(this);
+ executeFetchTaskIfPossible(null, null);
+ }
+
+ @Override
+ public void onChannelListUpdated() {}
+
+ @Override
+ public void onChannelBrowsableChanged() {}
+ });
+ } else {
+ executeFetchTaskIfPossible(null, null);
+ }
+ }
/** Notifies EPG fetch service that channel scanning is started. */
@MainThread
- void onChannelScanStarted();
+ public void onChannelScanStarted() {
+ if (mScanStarted || !Features.ENABLE_CLOUD_EPG_REGION.isEnabled(mContext)) {
+ return;
+ }
+ mScanStarted = true;
+ stopFetchingJob();
+ synchronized (mFetchDuringScanHandlerLock) {
+ if (mFetchDuringScanHandler == null) {
+ HandlerThread thread = new HandlerThread("EpgFetchDuringScan");
+ thread.start();
+ mFetchDuringScanHandler = new FetchDuringScanHandler(thread.getLooper());
+ }
+ mFetchDuringScanHandler.sendEmptyMessage(MSG_PREPARE_FETCH_DURING_SCAN);
+ }
+ Log.i(TAG, "EPG fetching on channel scanning started.");
+ }
/** Notifies EPG fetch service that channel scanning is finished. */
@MainThread
- void onChannelScanFinished();
+ public void onChannelScanFinished() {
+ if (!mScanStarted) {
+ return;
+ }
+ mScanStarted = false;
+ mFetchDuringScanHandler.sendEmptyMessage(MSG_FINISH_FETCH_DURING_SCAN);
+ }
@MainThread
- boolean executeFetchTaskIfPossible(JobService jobService, JobParameters params);
+ private void stopFetchingJob() {
+ if (DEBUG) Log.d(TAG, "Try to stop routinely fetching job...");
+ if (mFetchTask != null) {
+ mFetchTask.cancel(true);
+ mFetchTask = null;
+ Log.i(TAG, "EPG routinely fetching job stopped.");
+ }
+ }
@MainThread
- void stopFetchingJob();
+ private boolean executeFetchTaskIfPossible(JobService service, JobParameters params) {
+ SoftPreconditions.checkState(mChannelDataManager.isDbLoadFinished());
+ if (!TvCommonUtils.isRunningInTest() && checkFetchPrerequisite()) {
+ mFetchTask = new FetchAsyncTask(service, params);
+ mFetchTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ return true;
+ }
+ return false;
+ }
+
+ @MainThread
+ private boolean checkFetchPrerequisite() {
+ if (DEBUG) Log.d(TAG, "Check prerequisite of routinely fetching job.");
+ if (!Features.ENABLE_CLOUD_EPG_REGION.isEnabled(mContext)) {
+ Log.i(
+ TAG,
+ "Cannot start routine service: country not supported: "
+ + LocationUtils.getCurrentCountry(mContext));
+ return false;
+ }
+ if (mFetchTask != null) {
+ // Fetching job is already running or ready to run, no need to start again.
+ return false;
+ }
+ if (mFetchDuringScanHandler != null) {
+ if (DEBUG) Log.d(TAG, "Cannot start routine service: scanning channels.");
+ return false;
+ }
+ if (getTunerChannelCount() == 0) {
+ if (DEBUG) Log.d(TAG, "Cannot start routine service: no internal tuner channels.");
+ return false;
+ }
+ if (!TextUtils.isEmpty(EpgFetchHelper.getLastLineupId(mContext))) {
+ return true;
+ }
+ if (!TextUtils.isEmpty(PostalCodeUtils.getLastPostalCode(mContext))) {
+ return true;
+ }
+ return true;
+ }
+
+ @MainThread
+ private int getTunerChannelCount() {
+ for (TvInputInfo input :
+ TvApplication.getSingletons(mContext)
+ .getTvInputManagerHelper()
+ .getTvInputInfos(true, true)) {
+ String inputId = input.getId();
+ if (Utils.isInternalTvInput(mContext, inputId)) {
+ return mChannelDataManager.getChannelCountForInput(inputId);
+ }
+ }
+ return 0;
+ }
+
+ @AnyThread
+ private void clearUnusedLineups(@Nullable String lineupId) {
+ synchronized (mPossibleLineupsLock) {
+ if (mPossibleLineups == null) {
+ return;
+ }
+ for (Lineup lineup : mPossibleLineups) {
+ if (!TextUtils.equals(lineupId, lineup.id)) {
+ mEpgReader.clearCachedChannels(lineup.id);
+ }
+ }
+ mPossibleLineups = null;
+ }
+ }
+
+ @WorkerThread
+ private Integer prepareFetchEpg(boolean forceUpdatePossibleLineups) {
+ if (!mEpgReader.isAvailable()) {
+ Log.i(TAG, "EPG reader is temporarily unavailable.");
+ return REASON_EPG_READER_NOT_READY;
+ }
+ // Checks the EPG Timestamp.
+ mEpgTimeStamp = mEpgReader.getEpgTimestamp();
+ if (mEpgTimeStamp <= EpgFetchHelper.getLastEpgUpdatedTimestamp(mContext)) {
+ if (DEBUG) Log.d(TAG, "No new EPG.");
+ return REASON_NO_NEW_EPG;
+ }
+ // Updates postal code.
+ boolean postalCodeChanged = false;
+ try {
+ postalCodeChanged = PostalCodeUtils.updatePostalCode(mContext);
+ } catch (IOException e) {
+ if (DEBUG) Log.d(TAG, "Couldn't get the current location.", e);
+ if (TextUtils.isEmpty(PostalCodeUtils.getLastPostalCode(mContext))) {
+ return REASON_LOCATION_INFO_UNAVAILABLE;
+ }
+ } catch (SecurityException e) {
+ Log.w(TAG, "No permission to get the current location.");
+ if (TextUtils.isEmpty(PostalCodeUtils.getLastPostalCode(mContext))) {
+ return REASON_LOCATION_PERMISSION_NOT_GRANTED;
+ }
+ } catch (PostalCodeUtils.NoPostalCodeException e) {
+ Log.i(TAG, "Cannot get address or postal code.");
+ return REASON_LOCATION_INFO_UNAVAILABLE;
+ }
+ // Updates possible lineups if necessary.
+ SoftPreconditions.checkState(mPossibleLineups == null, TAG, "Possible lineups not reset.");
+ if (postalCodeChanged
+ || forceUpdatePossibleLineups
+ || EpgFetchHelper.getLastLineupId(mContext) == null) {
+ // To prevent main thread being blocked, though theoretically it should not happen.
+ List<Lineup> possibleLineups =
+ mEpgReader.getLineups(PostalCodeUtils.getLastPostalCode(mContext));
+ if (possibleLineups.isEmpty()) {
+ return REASON_NO_EPG_DATA_RETURNED;
+ }
+ for (Lineup lineup : possibleLineups) {
+ mEpgReader.preloadChannels(lineup.id);
+ }
+ synchronized (mPossibleLineupsLock) {
+ mPossibleLineups = possibleLineups;
+ }
+ EpgFetchHelper.setLastLineupId(mContext, null);
+ }
+ return null;
+ }
+
+ @WorkerThread
+ private void batchFetchEpg(List<Channel> channels, long durationSec) {
+ Log.i(TAG, "Start batch fetching (" + durationSec + ")...." + channels.size());
+ if (channels.size() == 0) {
+ return;
+ }
+ List<Long> queryChannelIds = new ArrayList<>(QUERY_CHANNEL_COUNT);
+ for (Channel channel : channels) {
+ queryChannelIds.add(channel.getId());
+ if (queryChannelIds.size() >= QUERY_CHANNEL_COUNT) {
+ batchUpdateEpg(mEpgReader.getPrograms(queryChannelIds, durationSec));
+ queryChannelIds.clear();
+ }
+ }
+ if (!queryChannelIds.isEmpty()) {
+ batchUpdateEpg(mEpgReader.getPrograms(queryChannelIds, durationSec));
+ }
+ }
+
+ @WorkerThread
+ private void batchUpdateEpg(Map<Long, List<Program>> allPrograms) {
+ for (Map.Entry<Long, List<Program>> entry : allPrograms.entrySet()) {
+ List<Program> programs = entry.getValue();
+ if (programs == null) {
+ continue;
+ }
+ Collections.sort(programs);
+ Log.i(
+ TAG,
+ "Batch fetched " + programs.size() + " programs for channel " + entry.getKey());
+ EpgFetchHelper.updateEpgData(mContext, entry.getKey(), programs);
+ }
+ }
+
+ @Nullable
+ @WorkerThread
+ private String pickBestLineupId(List<Channel> currentChannelList) {
+ String maxLineupId = null;
+ synchronized (mPossibleLineupsLock) {
+ if (mPossibleLineups == null) {
+ return null;
+ }
+ int maxCount = 0;
+ for (Lineup lineup : mPossibleLineups) {
+ int count = getMatchedChannelCount(lineup.id, currentChannelList);
+ Log.i(TAG, lineup.name + " (" + lineup.id + ") - " + count + " matches");
+ if (count > maxCount) {
+ maxCount = count;
+ maxLineupId = lineup.id;
+ }
+ }
+ }
+ return maxLineupId;
+ }
+
+ @WorkerThread
+ private int getMatchedChannelCount(String lineupId, List<Channel> currentChannelList) {
+ // Construct a list of display numbers for existing channels.
+ if (currentChannelList.isEmpty()) {
+ if (DEBUG) Log.d(TAG, "No existing channel to compare");
+ return 0;
+ }
+ List<String> numbers = new ArrayList<>(currentChannelList.size());
+ for (Channel channel : currentChannelList) {
+ // We only support channels from internal tuner inputs.
+ if (Utils.isInternalTvInput(mContext, channel.getInputId())) {
+ numbers.add(channel.getDisplayNumber());
+ }
+ }
+ numbers.retainAll(mEpgReader.getChannelNumbers(lineupId));
+ return numbers.size();
+ }
+
+ public static class EpgFetchService extends JobService {
+ private EpgFetcher mEpgFetcher;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ TvApplication.setCurrentRunningProcess(this, true);
+ mEpgFetcher = EpgFetcher.getInstance(this);
+ }
+
+ @Override
+ public boolean onStartJob(JobParameters params) {
+ if (!mEpgFetcher.mChannelDataManager.isDbLoadFinished()) {
+ mEpgFetcher.mChannelDataManager.addListener(
+ new ChannelDataManager.Listener() {
+ @Override
+ public void onLoadFinished() {
+ mEpgFetcher.mChannelDataManager.removeListener(this);
+ if (!mEpgFetcher.executeFetchTaskIfPossible(
+ EpgFetchService.this, params)) {
+ jobFinished(params, false);
+ }
+ }
+
+ @Override
+ public void onChannelListUpdated() {}
+
+ @Override
+ public void onChannelBrowsableChanged() {}
+ });
+ return true;
+ } else {
+ return mEpgFetcher.executeFetchTaskIfPossible(this, params);
+ }
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters params) {
+ mEpgFetcher.stopFetchingJob();
+ return false;
+ }
+ }
+
+ private class FetchAsyncTask extends AsyncTask<Void, Void, Integer> {
+ private final JobService mService;
+ private final JobParameters mParams;
+ private List<Channel> mCurrentChannelList;
+ private TimerEvent mTimerEvent;
+
+ private FetchAsyncTask(JobService service, JobParameters params) {
+ mService = service;
+ mParams = params;
+ }
+
+ @Override
+ protected void onPreExecute() {
+ mTimerEvent = mPerformanceMonitor.startTimer();
+ mCurrentChannelList = mChannelDataManager.getChannelList();
+ }
+
+ @Override
+ protected Integer doInBackground(Void... args) {
+ final int oldTag = TrafficStats.getThreadStatsTag();
+ TrafficStats.setThreadStatsTag(NetworkTrafficTags.EPG_FETCH);
+ try {
+ if (DEBUG) Log.d(TAG, "Start EPG routinely fetching.");
+ Integer failureReason = prepareFetchEpg(false);
+ // InterruptedException might be caught by RPC, we should check it here.
+ if (failureReason != null || this.isCancelled()) {
+ return failureReason;
+ }
+ String lineupId = EpgFetchHelper.getLastLineupId(mContext);
+ lineupId = lineupId == null ? pickBestLineupId(mCurrentChannelList) : lineupId;
+ if (lineupId != null) {
+ Log.i(TAG, "Selecting the lineup " + lineupId);
+ // During normal fetching process, the lineup ID should be confirmed since all
+ // channels are known, clear up possible lineups to save resources.
+ EpgFetchHelper.setLastLineupId(mContext, lineupId);
+ clearUnusedLineups(lineupId);
+ } else {
+ Log.i(TAG, "Failed to get lineup id");
+ return REASON_NO_EPG_DATA_RETURNED;
+ }
+ final List<Channel> channels = mEpgReader.getChannels(lineupId);
+ // InterruptedException might be caught by RPC, we should check it here.
+ if (this.isCancelled()) {
+ return null;
+ }
+ if (channels.isEmpty()) {
+ Log.i(TAG, "Failed to get EPG channels.");
+ return REASON_NO_EPG_DATA_RETURNED;
+ }
+ if (System.currentTimeMillis() - EpgFetchHelper.getLastEpgUpdatedTimestamp(mContext)
+ > mEpgDataExpiredTimeLimitMs) {
+ batchFetchEpg(channels, mFastFetchDurationSec);
+ }
+ new Handler(mContext.getMainLooper())
+ .post(
+ new Runnable() {
+ @Override
+ public void run() {
+ ChannelLogoFetcher.startFetchingChannelLogos(
+ mContext, channels);
+ }
+ });
+ for (Channel channel : channels) {
+ if (this.isCancelled()) {
+ return null;
+ }
+ long channelId = channel.getId();
+ List<Program> programs = new ArrayList<>(mEpgReader.getPrograms(channelId));
+ // InterruptedException might be caught by RPC, we should check it here.
+ Collections.sort(programs);
+ Log.i(TAG, "Fetched " + programs.size() + " programs for channel " + channelId);
+ EpgFetchHelper.updateEpgData(mContext, channelId, programs);
+ }
+ EpgFetchHelper.setLastEpgUpdatedTimestamp(mContext, mEpgTimeStamp);
+ if (DEBUG) Log.d(TAG, "Fetching EPG is finished.");
+ return null;
+ } finally {
+ TrafficStats.setThreadStatsTag(oldTag);
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Integer failureReason) {
+ mFetchTask = null;
+ if (failureReason == null
+ || failureReason == REASON_LOCATION_PERMISSION_NOT_GRANTED
+ || failureReason == REASON_NO_NEW_EPG) {
+ jobFinished(false);
+ } else {
+ // Applies back-off policy
+ jobFinished(true);
+ }
+ mPerformanceMonitor.stopTimer(mTimerEvent, EventNames.FETCH_EPG_TASK);
+ mPerformanceMonitor.recordMemory(EventNames.FETCH_EPG_TASK);
+ }
+
+ @Override
+ protected void onCancelled(Integer failureReason) {
+ clearUnusedLineups(null);
+ jobFinished(false);
+ }
+
+ private void jobFinished(boolean reschedule) {
+ if (mService != null && mParams != null) {
+ // Task is executed from JobService, need to report jobFinished.
+ mService.jobFinished(mParams, reschedule);
+ }
+ }
+ }
+
+ @WorkerThread
+ private class FetchDuringScanHandler extends Handler {
+ private final Set<Long> mFetchedChannelIdsDuringScan = new HashSet<>();
+ private String mPossibleLineupId;
+
+ private final ChannelDataManager.Listener mDuringScanChannelListener =
+ new ChannelDataManager.Listener() {
+ @Override
+ public void onLoadFinished() {
+ if (DEBUG) Log.d(TAG, "ChannelDataManager.onLoadFinished()");
+ if (getTunerChannelCount() >= MINIMUM_CHANNELS_TO_DECIDE_LINEUP
+ && !hasMessages(MSG_CHANNEL_UPDATED_DURING_SCAN)) {
+ Message.obtain(
+ FetchDuringScanHandler.this,
+ MSG_CHANNEL_UPDATED_DURING_SCAN,
+ new ArrayList<>(mChannelDataManager.getChannelList()))
+ .sendToTarget();
+ }
+ }
+
+ @Override
+ public void onChannelListUpdated() {
+ if (DEBUG) Log.d(TAG, "ChannelDataManager.onChannelListUpdated()");
+ if (getTunerChannelCount() >= MINIMUM_CHANNELS_TO_DECIDE_LINEUP
+ && !hasMessages(MSG_CHANNEL_UPDATED_DURING_SCAN)) {
+ Message.obtain(
+ FetchDuringScanHandler.this,
+ MSG_CHANNEL_UPDATED_DURING_SCAN,
+ mChannelDataManager.getChannelList())
+ .sendToTarget();
+ }
+ }
+
+ @Override
+ public void onChannelBrowsableChanged() {
+ // Do nothing
+ }
+ };
+
+ @AnyThread
+ private FetchDuringScanHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_PREPARE_FETCH_DURING_SCAN:
+ case MSG_RETRY_PREPARE_FETCH_DURING_SCAN:
+ onPrepareFetchDuringScan();
+ break;
+ case MSG_CHANNEL_UPDATED_DURING_SCAN:
+ if (!hasMessages(MSG_CHANNEL_UPDATED_DURING_SCAN)) {
+ onChannelUpdatedDuringScan((List<Channel>) msg.obj);
+ }
+ break;
+ case MSG_FINISH_FETCH_DURING_SCAN:
+ removeMessages(MSG_RETRY_PREPARE_FETCH_DURING_SCAN);
+ if (hasMessages(MSG_CHANNEL_UPDATED_DURING_SCAN)) {
+ sendEmptyMessage(MSG_FINISH_FETCH_DURING_SCAN);
+ } else {
+ onFinishFetchDuringScan();
+ }
+ break;
+ }
+ }
+
+ private void onPrepareFetchDuringScan() {
+ Integer failureReason = prepareFetchEpg(true);
+ if (failureReason != null) {
+ sendEmptyMessageDelayed(
+ MSG_RETRY_PREPARE_FETCH_DURING_SCAN, FETCH_DURING_SCAN_WAIT_TIME_MS);
+ return;
+ }
+ mChannelDataManager.addListener(mDuringScanChannelListener);
+ }
+
+ private void onChannelUpdatedDuringScan(List<Channel> currentChannelList) {
+ String lineupId = pickBestLineupId(currentChannelList);
+ Log.i(TAG, "Fast fetch channels for lineup ID: " + lineupId);
+ if (TextUtils.isEmpty(lineupId)) {
+ if (TextUtils.isEmpty(mPossibleLineupId)) {
+ return;
+ }
+ } else if (!TextUtils.equals(lineupId, mPossibleLineupId)) {
+ mFetchedChannelIdsDuringScan.clear();
+ mPossibleLineupId = lineupId;
+ }
+ List<Long> currentChannelIds = new ArrayList<>();
+ for (Channel channel : currentChannelList) {
+ currentChannelIds.add(channel.getId());
+ }
+ mFetchedChannelIdsDuringScan.retainAll(currentChannelIds);
+ List<Channel> newChannels = new ArrayList<>();
+ for (Channel channel : mEpgReader.getChannels(mPossibleLineupId)) {
+ if (!mFetchedChannelIdsDuringScan.contains(channel.getId())) {
+ newChannels.add(channel);
+ mFetchedChannelIdsDuringScan.add(channel.getId());
+ }
+ }
+ batchFetchEpg(newChannels, FETCH_DURING_SCAN_DURATION_SEC);
+ }
+
+ private void onFinishFetchDuringScan() {
+ mChannelDataManager.removeListener(mDuringScanChannelListener);
+ EpgFetchHelper.setLastLineupId(mContext, mPossibleLineupId);
+ clearUnusedLineups(null);
+ mFetchedChannelIdsDuringScan.clear();
+ synchronized (mFetchDuringScanHandlerLock) {
+ if (!hasMessages(MSG_PREPARE_FETCH_DURING_SCAN)) {
+ removeCallbacksAndMessages(null);
+ getLooper().quit();
+ mFetchDuringScanHandler = null;
+ }
+ }
+ // Clear timestamp to make routine service start right away.
+ EpgFetchHelper.setLastEpgUpdatedTimestamp(mContext, 0);
+ Log.i(TAG, "EPG Fetching during channel scanning finished.");
+ new Handler(Looper.getMainLooper())
+ .post(
+ new Runnable() {
+ @Override
+ public void run() {
+ fetchImmediately();
+ }
+ });
+ }
+ }
}
diff --git a/src/com/android/tv/data/epg/EpgFetcherImpl.java b/src/com/android/tv/data/epg/EpgFetcherImpl.java
deleted file mode 100644
index 523fc50c..00000000
--- a/src/com/android/tv/data/epg/EpgFetcherImpl.java
+++ /dev/null
@@ -1,814 +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.epg;
-
-import android.app.job.JobInfo;
-import android.app.job.JobParameters;
-import android.app.job.JobScheduler;
-import android.app.job.JobService;
-import android.content.ComponentName;
-import android.content.Context;
-import android.database.Cursor;
-import android.media.tv.TvContract;
-import android.media.tv.TvInputInfo;
-import android.net.TrafficStats;
-import android.os.AsyncTask;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.support.annotation.AnyThread;
-import android.support.annotation.MainThread;
-import android.support.annotation.Nullable;
-import android.support.annotation.VisibleForTesting;
-import android.support.annotation.WorkerThread;
-import android.text.TextUtils;
-import android.util.Log;
-import com.android.tv.TvFeatures;
-import com.android.tv.TvSingletons;
-import com.android.tv.common.BuildConfig;
-import com.android.tv.common.SoftPreconditions;
-import com.android.tv.common.config.RemoteConfigUtils;
-import com.android.tv.common.util.Clock;
-import com.android.tv.common.util.CommonUtils;
-import com.android.tv.common.util.LocationUtils;
-import com.android.tv.common.util.NetworkTrafficTags;
-import com.android.tv.common.util.PermissionUtils;
-import com.android.tv.common.util.PostalCodeUtils;
-import com.android.tv.data.Channel;
-import com.android.tv.data.ChannelDataManager;
-import com.android.tv.data.ChannelLogoFetcher;
-import com.android.tv.data.Lineup;
-import com.android.tv.data.Program;
-
-
-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 java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-/**
- * The service class to fetch EPG routinely or on-demand during channel scanning
- *
- * <p>Since the default executor of {@link AsyncTask} is {@link AsyncTask#SERIAL_EXECUTOR}, only one
- * task can run at a time. Because fetching EPG takes long time, the fetching task shouldn't run on
- * the serial executor. Instead, it should run on the {@link AsyncTask#THREAD_POOL_EXECUTOR}.
- */
-@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed
-public class EpgFetcherImpl implements EpgFetcher {
- private static final String TAG = "EpgFetcherImpl";
- private static final boolean DEBUG = false;
-
- private static final int EPG_ROUTINELY_FETCHING_JOB_ID = 101;
-
- private static final long INITIAL_BACKOFF_MS = TimeUnit.SECONDS.toMillis(10);
-
- @VisibleForTesting static final int REASON_EPG_READER_NOT_READY = 1;
- @VisibleForTesting static final int REASON_LOCATION_INFO_UNAVAILABLE = 2;
- @VisibleForTesting static final int REASON_LOCATION_PERMISSION_NOT_GRANTED = 3;
- @VisibleForTesting static final int REASON_NO_EPG_DATA_RETURNED = 4;
- @VisibleForTesting static final int REASON_NO_NEW_EPG = 5;
- @VisibleForTesting static final int REASON_ERROR = 6;
- @VisibleForTesting static final int REASON_CLOUD_EPG_FAILURE = 7;
- @VisibleForTesting static final int REASON_NO_BUILT_IN_CHANNELS = 8;
-
- private static final long FETCH_DURING_SCAN_WAIT_TIME_MS = TimeUnit.SECONDS.toMillis(10);
-
- private static final long FETCH_DURING_SCAN_DURATION_SEC = TimeUnit.HOURS.toSeconds(3);
- private static final long FAST_FETCH_DURATION_SEC = TimeUnit.DAYS.toSeconds(2);
-
- private static final int DEFAULT_ROUTINE_INTERVAL_HOUR = 4;
- private static final String KEY_ROUTINE_INTERVAL = "live_channels_epg_fetcher_interval_hour";
-
- private static final int MSG_PREPARE_FETCH_DURING_SCAN = 1;
- private static final int MSG_CHANNEL_UPDATED_DURING_SCAN = 2;
- 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;
- private final ChannelDataManager mChannelDataManager;
- private final EpgReader mEpgReader;
- private final PerformanceMonitor mPerformanceMonitor;
- private FetchAsyncTask mFetchTask;
- private FetchDuringScanHandler mFetchDuringScanHandler;
- private long mEpgTimeStamp;
- private List<Lineup> mPossibleLineups;
- private final Object mPossibleLineupsLock = new Object();
- private final Object mFetchDuringScanHandlerLock = new Object();
- // A flag to block the re-entrance of onChannelScanStarted and onChannelScanFinished.
- private boolean mScanStarted;
-
- private final long mRoutineIntervalMs;
- private final long mEpgDataExpiredTimeLimitMs;
- private final long mFastFetchDurationSec;
- private Clock mClock;
-
- 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();
- int routineIntervalMs =
- (int)
- RemoteConfigUtils.getRemoteConfig(
- context, KEY_ROUTINE_INTERVAL, DEFAULT_ROUTINE_INTERVAL_HOUR);
-
- return new EpgFetcherImpl(
- context,
- channelDataManager,
- epgReader,
- performanceMonitor,
- clock,
- routineIntervalMs);
- }
-
- @VisibleForTesting
- EpgFetcherImpl(
- Context context,
- ChannelDataManager channelDataManager,
- EpgReader epgReader,
- PerformanceMonitor performanceMonitor,
- Clock clock,
- long routineIntervalMs) {
- mContext = context;
- mChannelDataManager = channelDataManager;
- mEpgReader = epgReader;
- mPerformanceMonitor = performanceMonitor;
- mClock = clock;
- mRoutineIntervalMs =
- routineIntervalMs <= 0
- ? TimeUnit.HOURS.toMillis(DEFAULT_ROUTINE_INTERVAL_HOUR)
- : TimeUnit.HOURS.toMillis(routineIntervalMs);
- mEpgDataExpiredTimeLimitMs = routineIntervalMs * 2;
- mFastFetchDurationSec = FAST_FETCH_DURATION_SEC + routineIntervalMs / 1000;
- }
-
- private static Set<Channel> getExistingChannelsForMyPackage(Context context) {
- HashSet<Channel> channels = new HashSet<>();
- String selection = null;
- String[] selectionArgs = null;
- String myPackageName = context.getPackageName();
- if (PermissionUtils.hasAccessAllEpg(context)) {
- selection = "package_name=?";
- selectionArgs = new String[] {myPackageName};
- }
- try (Cursor c =
- context.getContentResolver()
- .query(
- TvContract.Channels.CONTENT_URI,
- Channel.PROJECTION,
- selection,
- selectionArgs,
- null)) {
- if (c != null) {
- while (c.moveToNext()) {
- Channel channel = Channel.fromCursor(c);
- if (DEBUG) Log.d(TAG, "Found " + channel);
- if (myPackageName.equals(channel.getPackageName())) {
- channels.add(channel);
- }
- }
- }
- }
- if (DEBUG)
- Log.d(TAG, "Found " + channels.size() + " channels for package " + myPackageName);
- return channels;
- }
-
- @Override
- @MainThread
- public void startRoutineService() {
- JobScheduler jobScheduler =
- (JobScheduler) mContext.getSystemService(Context.JOB_SCHEDULER_SERVICE);
- for (JobInfo job : jobScheduler.getAllPendingJobs()) {
- if (job.getId() == EPG_ROUTINELY_FETCHING_JOB_ID) {
- return;
- }
- }
- JobInfo job =
- new JobInfo.Builder(
- EPG_ROUTINELY_FETCHING_JOB_ID,
- new ComponentName(mContext, EpgFetchService.class))
- .setPeriodic(mRoutineIntervalMs)
- .setBackoffCriteria(INITIAL_BACKOFF_MS, JobInfo.BACKOFF_POLICY_EXPONENTIAL)
- .setPersisted(true)
- .build();
- jobScheduler.schedule(job);
- Log.i(TAG, "EPG fetching routine service started.");
- }
-
- @Override
- @MainThread
- public void fetchImmediatelyIfNeeded() {
- if (CommonUtils.isRunningInTest()) {
- // Do not run EpgFetcher in test.
- return;
- }
- new AsyncTask<Void, Void, Long>() {
- @Override
- protected Long doInBackground(Void... args) {
- return EpgFetchHelper.getLastEpgUpdatedTimestamp(mContext);
- }
-
- @Override
- protected void onPostExecute(Long result) {
- if (mClock.currentTimeMillis() - EpgFetchHelper.getLastEpgUpdatedTimestamp(mContext)
- > mEpgDataExpiredTimeLimitMs) {
- Log.i(TAG, "EPG data expired. Start fetching immediately.");
- fetchImmediately();
- }
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
-
- @Override
- @MainThread
- public void fetchImmediately() {
- if (DEBUG) Log.d(TAG, "fetchImmediately");
- if (!mChannelDataManager.isDbLoadFinished()) {
- mChannelDataManager.addListener(
- new ChannelDataManager.Listener() {
- @Override
- public void onLoadFinished() {
- mChannelDataManager.removeListener(this);
- executeFetchTaskIfPossible(null, null);
- }
-
- @Override
- public void onChannelListUpdated() {}
-
- @Override
- public void onChannelBrowsableChanged() {}
- });
- } else {
- executeFetchTaskIfPossible(null, null);
- }
- }
-
- @Override
- @MainThread
- public void onChannelScanStarted() {
- if (mScanStarted || !TvFeatures.ENABLE_CLOUD_EPG_REGION.isEnabled(mContext)) {
- return;
- }
- mScanStarted = true;
- stopFetchingJob();
- synchronized (mFetchDuringScanHandlerLock) {
- if (mFetchDuringScanHandler == null) {
- HandlerThread thread = new HandlerThread("EpgFetchDuringScan");
- thread.start();
- mFetchDuringScanHandler = new FetchDuringScanHandler(thread.getLooper());
- }
- mFetchDuringScanHandler.sendEmptyMessage(MSG_PREPARE_FETCH_DURING_SCAN);
- }
- Log.i(TAG, "EPG fetching on channel scanning started.");
- }
-
- @Override
- @MainThread
- public void onChannelScanFinished() {
- if (!mScanStarted) {
- return;
- }
- mScanStarted = false;
- mFetchDuringScanHandler.sendEmptyMessage(MSG_FINISH_FETCH_DURING_SCAN);
- }
-
- @MainThread
- @Override
- public void stopFetchingJob() {
- if (DEBUG) Log.d(TAG, "Try to stop routinely fetching job...");
- if (mFetchTask != null) {
- mFetchTask.cancel(true);
- mFetchTask = null;
- Log.i(TAG, "EPG routinely fetching job stopped.");
- }
- }
-
- @MainThread
- @Override
- public boolean executeFetchTaskIfPossible(JobService service, JobParameters params) {
- if (DEBUG) Log.d(TAG, "executeFetchTaskIfPossible");
- SoftPreconditions.checkState(mChannelDataManager.isDbLoadFinished());
- if (!CommonUtils.isRunningInTest() && checkFetchPrerequisite()) {
- mFetchTask = createFetchTask(service, params);
- mFetchTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- return true;
- }
- return false;
- }
-
- @VisibleForTesting
- FetchAsyncTask createFetchTask(JobService service, JobParameters params) {
- return new FetchAsyncTask(service, params);
- }
-
- @MainThread
- private boolean checkFetchPrerequisite() {
- if (DEBUG) Log.d(TAG, "Check prerequisite of routinely fetching job.");
- if (!TvFeatures.ENABLE_CLOUD_EPG_REGION.isEnabled(mContext)) {
- Log.i(
- TAG,
- "Cannot start routine service: country not supported: "
- + LocationUtils.getCurrentCountry(mContext));
- return false;
- }
- if (mFetchTask != null) {
- // Fetching job is already running or ready to run, no need to start again.
- return false;
- }
- if (mFetchDuringScanHandler != null) {
- if (DEBUG) Log.d(TAG, "Cannot start routine service: scanning channels.");
- return false;
- }
- return true;
- }
-
- @MainThread
- private int getTunerChannelCount() {
- for (TvInputInfo input :
- TvSingletons.getSingletons(mContext)
- .getTvInputManagerHelper()
- .getTvInputInfos(true, true)) {
- String inputId = input.getId();
- if (Utils.isInternalTvInput(mContext, inputId)) {
- return mChannelDataManager.getChannelCountForInput(inputId);
- }
- }
- return 0;
- }
-
- @AnyThread
- private void clearUnusedLineups(@Nullable String lineupId) {
- synchronized (mPossibleLineupsLock) {
- if (mPossibleLineups == null) {
- return;
- }
- for (Lineup lineup : mPossibleLineups) {
- if (!TextUtils.equals(lineupId, lineup.getId())) {
- mEpgReader.clearCachedChannels(lineup.getId());
- }
- }
- mPossibleLineups = null;
- }
- }
-
- @WorkerThread
- private Integer prepareFetchEpg(boolean forceUpdatePossibleLineups) {
- if (!mEpgReader.isAvailable()) {
- Log.i(TAG, "EPG reader is temporarily unavailable.");
- return REASON_EPG_READER_NOT_READY;
- }
- // Checks the EPG Timestamp.
- mEpgTimeStamp = mEpgReader.getEpgTimestamp();
- if (mEpgTimeStamp <= EpgFetchHelper.getLastEpgUpdatedTimestamp(mContext)) {
- if (DEBUG) Log.d(TAG, "No new EPG.");
- return REASON_NO_NEW_EPG;
- }
- // Updates postal code.
- boolean postalCodeChanged = false;
- try {
- postalCodeChanged = PostalCodeUtils.updatePostalCode(mContext);
- } catch (IOException e) {
- if (DEBUG) Log.d(TAG, "Couldn't get the current location.", e);
- if (TextUtils.isEmpty(PostalCodeUtils.getLastPostalCode(mContext))) {
- return REASON_LOCATION_INFO_UNAVAILABLE;
- }
- } catch (SecurityException e) {
- Log.w(TAG, "No permission to get the current location.");
- if (TextUtils.isEmpty(PostalCodeUtils.getLastPostalCode(mContext))) {
- return REASON_LOCATION_PERMISSION_NOT_GRANTED;
- }
- } catch (PostalCodeUtils.NoPostalCodeException e) {
- Log.i(TAG, "Cannot get address or postal code.");
- return REASON_LOCATION_INFO_UNAVAILABLE;
- }
- // Updates possible lineups if necessary.
- SoftPreconditions.checkState(mPossibleLineups == null, TAG, "Possible lineups not reset.");
- if (postalCodeChanged
- || forceUpdatePossibleLineups
- || EpgFetchHelper.getLastLineupId(mContext) == null) {
- // To prevent main thread being blocked, though theoretically it should not happen.
- String lastPostalCode = PostalCodeUtils.getLastPostalCode(mContext);
- List<Lineup> possibleLineups = mEpgReader.getLineups(lastPostalCode);
- if (possibleLineups.isEmpty()) {
- Log.i(TAG, "No lineups found for " + lastPostalCode);
- return REASON_NO_EPG_DATA_RETURNED;
- }
- for (Lineup lineup : possibleLineups) {
- mEpgReader.preloadChannels(lineup.getId());
- }
- synchronized (mPossibleLineupsLock) {
- mPossibleLineups = possibleLineups;
- }
- EpgFetchHelper.setLastLineupId(mContext, null);
- }
- return null;
- }
-
- @WorkerThread
- private void batchFetchEpg(Set<EpgReader.EpgChannel> epgChannels, long durationSec) {
- Log.i(TAG, "Start batch fetching (" + durationSec + ")...." + epgChannels.size());
- if (epgChannels.size() == 0) {
- return;
- }
- 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());
- if (programs == null) {
- continue;
- }
- Collections.sort(programs);
- Log.i(
- TAG,
- "Batch fetched " + programs.size() + " programs for channel " + entry.getKey());
- EpgFetchHelper.updateEpgData(
- mContext, mClock, entry.getKey().getChannel().getId(), programs);
- }
- }
-
- @Nullable
- @WorkerThread
- private String pickBestLineupId(Set<Channel> currentChannels) {
- String maxLineupId = null;
- synchronized (mPossibleLineupsLock) {
- if (mPossibleLineups == null) {
- return null;
- }
- int maxCount = 0;
- for (Lineup lineup : mPossibleLineups) {
- int count = getMatchedChannelCount(lineup.getId(), currentChannels);
- Log.i(TAG, lineup.getName() + " (" + lineup.getId() + ") - " + count + " matches");
- if (count > maxCount) {
- maxCount = count;
- maxLineupId = lineup.getId();
- }
- }
- }
- return maxLineupId;
- }
-
- @WorkerThread
- private int getMatchedChannelCount(String lineupId, Set<Channel> currentChannels) {
- // Construct a list of display numbers for existing channels.
- if (currentChannels.isEmpty()) {
- if (DEBUG) Log.d(TAG, "No existing channel to compare");
- return 0;
- }
- List<String> numbers = new ArrayList<>(currentChannels.size());
- for (Channel channel : currentChannels) {
- // We only support channels from internal tuner inputs.
- if (Utils.isInternalTvInput(mContext, channel.getInputId())) {
- numbers.add(channel.getDisplayNumber());
- }
- }
- numbers.retainAll(mEpgReader.getChannelNumbers(lineupId));
- return numbers.size();
- }
-
- @VisibleForTesting
- class FetchAsyncTask extends AsyncTask<Void, Void, Integer> {
- private final JobService mService;
- private final JobParameters mParams;
- private Set<Channel> mCurrentChannels;
- private TimerEvent mTimerEvent;
-
- private FetchAsyncTask(JobService service, JobParameters params) {
- mService = service;
- mParams = params;
- }
-
- @Override
- protected void onPreExecute() {
- mTimerEvent = mPerformanceMonitor.startTimer();
- mCurrentChannels = new HashSet<>(mChannelDataManager.getChannelList());
- }
-
- @Override
- protected Integer doInBackground(Void... args) {
- final int oldTag = TrafficStats.getThreadStatsTag();
- TrafficStats.setThreadStatsTag(NetworkTrafficTags.EPG_FETCH);
- try {
- if (DEBUG) Log.d(TAG, "Start EPG routinely fetching.");
- Integer builtInResult = fetchEpgForBuiltInTuner();
- boolean anyCloudEpgFailure = false;
- boolean anyCloudEpgSuccess = false;
- return builtInResult;
- } finally {
- TrafficStats.setThreadStatsTag(oldTag);
- }
- }
-
- private Set<Channel> getExistingChannelsFor(String inputId) {
- Set<Channel> result = new HashSet<>();
- try (Cursor cursor =
- mContext.getContentResolver()
- .query(
- TvContract.buildChannelsUriForInput(inputId),
- Channel.PROJECTION,
- null,
- null,
- null)) {
- while (cursor.moveToNext()) {
- result.add(Channel.fromCursor(cursor));
- }
- return result;
- }
- }
-
- private Integer fetchEpgForBuiltInTuner() {
- try {
- Integer failureReason = prepareFetchEpg(false);
- // InterruptedException might be caught by RPC, we should check it here.
- if (failureReason != null || this.isCancelled()) {
- return failureReason;
- }
- String lineupId = EpgFetchHelper.getLastLineupId(mContext);
- lineupId = lineupId == null ? pickBestLineupId(mCurrentChannels) : lineupId;
- if (lineupId != null) {
- Log.i(TAG, "Selecting the lineup " + lineupId);
- // During normal fetching process, the lineup ID should be confirmed since all
- // channels are known, clear up possible lineups to save resources.
- EpgFetchHelper.setLastLineupId(mContext, lineupId);
- clearUnusedLineups(lineupId);
- } else {
- Log.i(TAG, "Failed to get lineup id");
- return REASON_NO_EPG_DATA_RETURNED;
- }
- Set<Channel> existingChannelsForMyPackage =
- getExistingChannelsForMyPackage(mContext);
- if (existingChannelsForMyPackage.isEmpty()) {
- return REASON_NO_BUILT_IN_CHANNELS;
- }
- return fetchEpgFor(lineupId, existingChannelsForMyPackage);
- } catch (Exception e) {
- Log.w(TAG, "Failed to update EPG for builtin tuner", e);
- return REASON_ERROR;
- }
- }
-
- @Nullable
- private Integer fetchEpgFor(String lineupId, Set<Channel> existingChannels) {
- if (DEBUG) {
- Log.d(
- TAG,
- "Starting Fetching EPG is for "
- + lineupId
- + " with channelCount "
- + existingChannels.size());
- }
- final Set<EpgReader.EpgChannel> channels =
- mEpgReader.getChannels(existingChannels, lineupId);
- // InterruptedException might be caught by RPC, we should check it here.
- if (this.isCancelled()) {
- return null;
- }
- if (channels.isEmpty()) {
- Log.i(TAG, "Failed to get EPG channels for " + lineupId);
- return REASON_NO_EPG_DATA_RETURNED;
- }
- if (mClock.currentTimeMillis() - EpgFetchHelper.getLastEpgUpdatedTimestamp(mContext)
- > mEpgDataExpiredTimeLimitMs) {
- batchFetchEpg(channels, mFastFetchDurationSec);
- }
- new Handler(mContext.getMainLooper())
- .post(
- new Runnable() {
- @Override
- public void run() {
- ChannelLogoFetcher.startFetchingChannelLogos(
- mContext, asChannelList(channels));
- }
- });
- for (EpgReader.EpgChannel epgChannel : channels) {
- if (this.isCancelled()) {
- return null;
- }
- List<Program> programs = new ArrayList<>(mEpgReader.getPrograms(epgChannel));
- // InterruptedException might be caught by RPC, we should check it here.
- Collections.sort(programs);
- Log.i(
- TAG,
- "Fetched "
- + programs.size()
- + " programs for channel "
- + epgChannel.getChannel());
- EpgFetchHelper.updateEpgData(
- mContext, mClock, epgChannel.getChannel().getId(), programs);
- }
- EpgFetchHelper.setLastEpgUpdatedTimestamp(mContext, mEpgTimeStamp);
- if (DEBUG) Log.d(TAG, "Fetching EPG is for " + lineupId);
- return null;
- }
-
- @Override
- protected void onPostExecute(Integer failureReason) {
- mFetchTask = null;
- if (failureReason == null
- || failureReason == REASON_LOCATION_PERMISSION_NOT_GRANTED
- || failureReason == REASON_NO_NEW_EPG) {
- jobFinished(false);
- } else {
- // Applies back-off policy
- jobFinished(true);
- }
- mPerformanceMonitor.stopTimer(mTimerEvent, EventNames.FETCH_EPG_TASK);
- mPerformanceMonitor.recordMemory(EventNames.FETCH_EPG_TASK);
- }
-
- @Override
- protected void onCancelled(Integer failureReason) {
- clearUnusedLineups(null);
- jobFinished(false);
- }
-
- private void jobFinished(boolean reschedule) {
- if (mService != null && mParams != null) {
- // Task is executed from JobService, need to report jobFinished.
- mService.jobFinished(mParams, reschedule);
- }
- }
- }
-
- private List<Channel> asChannelList(Set<EpgReader.EpgChannel> epgChannels) {
- List<Channel> result = new ArrayList<>(epgChannels.size());
- for (EpgReader.EpgChannel epgChannel : epgChannels) {
- result.add(epgChannel.getChannel());
- }
- return result;
- }
-
- @WorkerThread
- private class FetchDuringScanHandler extends Handler {
- private final Set<Long> mFetchedChannelIdsDuringScan = new HashSet<>();
- private String mPossibleLineupId;
-
- private final ChannelDataManager.Listener mDuringScanChannelListener =
- new ChannelDataManager.Listener() {
- @Override
- public void onLoadFinished() {
- if (DEBUG) Log.d(TAG, "ChannelDataManager.onLoadFinished()");
- if (getTunerChannelCount() >= MINIMUM_CHANNELS_TO_DECIDE_LINEUP
- && !hasMessages(MSG_CHANNEL_UPDATED_DURING_SCAN)) {
- Message.obtain(
- FetchDuringScanHandler.this,
- MSG_CHANNEL_UPDATED_DURING_SCAN,
- getExistingChannelsForMyPackage(mContext))
- .sendToTarget();
- }
- }
-
- @Override
- public void onChannelListUpdated() {
- if (DEBUG) Log.d(TAG, "ChannelDataManager.onChannelListUpdated()");
- if (getTunerChannelCount() >= MINIMUM_CHANNELS_TO_DECIDE_LINEUP
- && !hasMessages(MSG_CHANNEL_UPDATED_DURING_SCAN)) {
- Message.obtain(
- FetchDuringScanHandler.this,
- MSG_CHANNEL_UPDATED_DURING_SCAN,
- getExistingChannelsForMyPackage(mContext))
- .sendToTarget();
- }
- }
-
- @Override
- public void onChannelBrowsableChanged() {
- // Do nothing
- }
- };
-
- @AnyThread
- private FetchDuringScanHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_PREPARE_FETCH_DURING_SCAN:
- case MSG_RETRY_PREPARE_FETCH_DURING_SCAN:
- onPrepareFetchDuringScan();
- break;
- case MSG_CHANNEL_UPDATED_DURING_SCAN:
- if (!hasMessages(MSG_CHANNEL_UPDATED_DURING_SCAN)) {
- onChannelUpdatedDuringScan((Set<Channel>) msg.obj);
- }
- break;
- case MSG_FINISH_FETCH_DURING_SCAN:
- removeMessages(MSG_RETRY_PREPARE_FETCH_DURING_SCAN);
- if (hasMessages(MSG_CHANNEL_UPDATED_DURING_SCAN)) {
- sendEmptyMessage(MSG_FINISH_FETCH_DURING_SCAN);
- } else {
- onFinishFetchDuringScan();
- }
- break;
- default:
- // do nothing
- }
- }
-
- private void onPrepareFetchDuringScan() {
- Integer failureReason = prepareFetchEpg(true);
- if (failureReason != null) {
- sendEmptyMessageDelayed(
- MSG_RETRY_PREPARE_FETCH_DURING_SCAN, FETCH_DURING_SCAN_WAIT_TIME_MS);
- return;
- }
- mChannelDataManager.addListener(mDuringScanChannelListener);
- }
-
- private void onChannelUpdatedDuringScan(Set<Channel> currentChannels) {
- String lineupId = pickBestLineupId(currentChannels);
- Log.i(TAG, "Fast fetch channels for lineup ID: " + lineupId);
- if (TextUtils.isEmpty(lineupId)) {
- if (TextUtils.isEmpty(mPossibleLineupId)) {
- return;
- }
- } else if (!TextUtils.equals(lineupId, mPossibleLineupId)) {
- mFetchedChannelIdsDuringScan.clear();
- mPossibleLineupId = lineupId;
- }
- List<Long> currentChannelIds = new ArrayList<>();
- for (Channel channel : currentChannels) {
- currentChannelIds.add(channel.getId());
- }
- mFetchedChannelIdsDuringScan.retainAll(currentChannelIds);
- Set<EpgReader.EpgChannel> newChannels = new HashSet<>();
- for (EpgReader.EpgChannel epgChannel :
- mEpgReader.getChannels(currentChannels, mPossibleLineupId)) {
- if (!mFetchedChannelIdsDuringScan.contains(epgChannel.getChannel().getId())) {
- newChannels.add(epgChannel);
- mFetchedChannelIdsDuringScan.add(epgChannel.getChannel().getId());
- }
- }
- batchFetchEpg(newChannels, FETCH_DURING_SCAN_DURATION_SEC);
- }
-
- private void onFinishFetchDuringScan() {
- mChannelDataManager.removeListener(mDuringScanChannelListener);
- EpgFetchHelper.setLastLineupId(mContext, mPossibleLineupId);
- clearUnusedLineups(null);
- mFetchedChannelIdsDuringScan.clear();
- synchronized (mFetchDuringScanHandlerLock) {
- if (!hasMessages(MSG_PREPARE_FETCH_DURING_SCAN)) {
- removeCallbacksAndMessages(null);
- getLooper().quit();
- mFetchDuringScanHandler = null;
- }
- }
- // Clear timestamp to make routine service start right away.
- EpgFetchHelper.setLastEpgUpdatedTimestamp(mContext, 0);
- Log.i(TAG, "EPG Fetching during channel scanning finished.");
- new Handler(Looper.getMainLooper())
- .post(
- new Runnable() {
- @Override
- public void run() {
- fetchImmediately();
- }
- });
- }
- }
-}
diff --git a/src/com/android/tv/data/epg/EpgInputWhiteList.java b/src/com/android/tv/data/epg/EpgInputWhiteList.java
deleted file mode 100644
index de0478fc..00000000
--- a/src/com/android/tv/data/epg/EpgInputWhiteList.java
+++ /dev/null
@@ -1,92 +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 android.support.annotation.Nullable;
-import android.support.annotation.VisibleForTesting;
-import android.text.TextUtils;
-import android.util.Log;
-import com.android.tv.common.BuildConfig;
-import com.android.tv.common.config.api.RemoteConfig;
-import com.android.tv.common.experiments.Experiments;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-/** Checks if a package or a input is white listed. */
-public final class EpgInputWhiteList {
- private static final boolean DEBUG = false;
- private static final String TAG = "EpgInputWhiteList";
- @VisibleForTesting public static final String KEY = "live_channels_3rd_party_epg_inputs";
- private static final String QA_DEV_INPUTS =
- "com.example.partnersupportsampletvinput/.SampleTvInputService";
-
- /** Returns the package portion of a inputId */
- @Nullable
- public static String getPackageFromInput(@Nullable String inputId) {
- return inputId == null ? null : inputId.substring(0, inputId.indexOf("/"));
- }
-
- private final RemoteConfig remoteConfig;
-
- public EpgInputWhiteList(RemoteConfig remoteConfig) {
- this.remoteConfig = remoteConfig;
- }
-
- public boolean isInputWhiteListed(String inputId) {
- return getWhiteListedInputs().contains(inputId);
- }
-
- public boolean isPackageWhiteListed(String packageName) {
- if (DEBUG) Log.d(TAG, "isPackageWhiteListed " + packageName);
- Set<String> whiteList = getWhiteListedInputs();
- for (String good : whiteList) {
- try {
- String goodPackage = getPackageFromInput(good);
- if (goodPackage.equals(packageName)) {
- return true;
- }
- } catch (Exception e) {
- if (DEBUG) Log.d(TAG, "Error parsing package name of " + good, e);
- continue;
- }
- }
- return false;
- }
-
- private Set<String> getWhiteListedInputs() {
- Set<String> result = toInputSet(remoteConfig.getString(KEY));
- if (BuildConfig.ENG || Experiments.ENABLE_QA_FEATURES.get()) {
- HashSet<String> moreInputs = new HashSet<>(toInputSet(QA_DEV_INPUTS));
- if (result.isEmpty()) {
- result = moreInputs;
- } else {
- result.addAll(moreInputs);
- }
- }
- if (DEBUG) Log.d(TAG, "getWhiteListedInputs " + result);
- return result;
- }
-
- private Set<String> toInputSet(String value) {
- if (TextUtils.isEmpty(value)) {
- return Collections.EMPTY_SET;
- }
- return new HashSet(Arrays.asList(value.split(",")));
- }
-}
diff --git a/src/com/android/tv/data/epg/EpgReader.java b/src/com/android/tv/data/epg/EpgReader.java
index 9c881439..d10a852c 100644
--- a/src/com/android/tv/data/epg/EpgReader.java
+++ b/src/com/android/tv/data/epg/EpgReader.java
@@ -23,27 +23,12 @@ import com.android.tv.data.Channel;
import com.android.tv.data.Lineup;
import com.android.tv.data.Program;
import com.android.tv.dvr.data.SeriesInfo;
-import java.util.Collection;
import java.util.List;
import java.util.Map;
-import java.util.Set;
/** An interface used to retrieve the EPG data. This class should be used in worker thread. */
@WorkerThread
public interface EpgReader {
-
- /** Value class that holds a EpgChannelId and its corresponding Channel */
- // TODO(b/72052568): Get autovalue to work in aosp
- abstract class EpgChannel {
- public static EpgChannel createEpgChannel(Channel channel, String epgChannelId) {
- return new AutoValue_EpgReader_EpgChannel(channel, epgChannelId);
- }
-
- public abstract Channel getChannel();
-
- public abstract String getEpgChannelId();
- }
-
/** Checks if the reader is available. */
boolean isAvailable();
@@ -70,7 +55,7 @@ public interface EpgReader {
* Returns the list of channels for the given lineup. The returned channels should map into the
* existing channels on the device. This method is usually called after selecting the lineup.
*/
- Set<EpgChannel> getChannels(Set<Channel> inputChannels, @NonNull String lineupId);
+ List<Channel> getChannels(@NonNull String lineupId);
/** Pre-loads and caches channels for a given lineup. */
void preloadChannels(@NonNull String lineupId);
@@ -80,19 +65,18 @@ public interface EpgReader {
void clearCachedChannels(@NonNull String lineupId);
/**
- * Returns the programs for the given channel. Must call {@link #getChannels(Set, String)}
+ * Returns the programs for the given channel. Must call {@link #getChannels(String)}
* beforehand. Note that the {@code Program} doesn't have valid program ID because it's not
* retrieved from TvProvider.
*/
- List<Program> getPrograms(EpgChannel epgChannel);
+ List<Program> getPrograms(long channelId);
/**
* Returns the programs for the given channels. Note that the {@code Program} doesn't have valid
* program ID because it's not retrieved from TvProvider. This method is only used to get
* programs for a short duration typically.
*/
- Map<EpgChannel, Collection<Program>> getPrograms(
- @NonNull Set<EpgChannel> epgChannels, long duration);
+ Map<Long, List<Program>> getPrograms(@NonNull List<Long> channelIds, long duration);
/** Returns the series information for the given series ID. */
SeriesInfo getSeriesInfo(@NonNull String seriesId);
diff --git a/src/com/android/tv/data/epg/StubEpgReader.java b/src/com/android/tv/data/epg/StubEpgReader.java
index 9a87619d..49409a1d 100644
--- a/src/com/android/tv/data/epg/StubEpgReader.java
+++ b/src/com/android/tv/data/epg/StubEpgReader.java
@@ -22,11 +22,9 @@ import com.android.tv.data.Channel;
import com.android.tv.data.Lineup;
import com.android.tv.data.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;
/** A stub class to read EPG. */
public class StubEpgReader implements EpgReader {
@@ -58,8 +56,8 @@ public class StubEpgReader implements EpgReader {
}
@Override
- public Set<EpgChannel> getChannels(Set<Channel> inputChannels, @NonNull String lineupId) {
- return Collections.emptySet();
+ public List<Channel> getChannels(@NonNull String lineupId) {
+ return Collections.emptyList();
}
@Override
@@ -73,13 +71,12 @@ public class StubEpgReader implements EpgReader {
}
@Override
- public List<Program> getPrograms(EpgChannel epgChannel) {
+ public List<Program> getPrograms(long channelId) {
return Collections.emptyList();
}
@Override
- public Map<EpgChannel, Collection<Program>> getPrograms(
- @NonNull Set<EpgChannel> channels, long duration) {
+ public Map<Long, List<Program>> getPrograms(@NonNull List<Long> channelIds, long duration) {
return Collections.emptyMap();
}
diff --git a/src/com/android/tv/dialog/DvrHistoryDialogFragment.java b/src/com/android/tv/dialog/DvrHistoryDialogFragment.java
index 173a2891..442a663d 100644
--- a/src/com/android/tv/dialog/DvrHistoryDialogFragment.java
+++ b/src/com/android/tv/dialog/DvrHistoryDialogFragment.java
@@ -30,8 +30,9 @@ import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
+import com.android.tv.ApplicationSingletons;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
import com.android.tv.dvr.DvrDataManager;
@@ -44,7 +45,6 @@ import java.util.List;
/** Displays the DVR history. */
@TargetApi(VERSION_CODES.N)
-@SuppressWarnings("AndroidApiChecker") // TODO(b/32513850) remove when error prone is updated
public class DvrHistoryDialogFragment extends SafeDismissDialogFragment {
public static final String DIALOG_TAG = DvrHistoryDialogFragment.class.getSimpleName();
@@ -53,7 +53,7 @@ public class DvrHistoryDialogFragment extends SafeDismissDialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
- TvSingletons singletons = TvSingletons.getSingletons(getContext());
+ ApplicationSingletons singletons = TvApplication.getSingletons(getContext());
DvrDataManager dataManager = singletons.getDvrDataManager();
ChannelDataManager channelDataManager = singletons.getChannelDataManager();
for (ScheduledRecording schedule : dataManager.getAllScheduledRecordings()) {
diff --git a/src/com/android/tv/dialog/PinDialogFragment.java b/src/com/android/tv/dialog/PinDialogFragment.java
index 71f45fbe..ccc3a983 100644
--- a/src/com/android/tv/dialog/PinDialogFragment.java
+++ b/src/com/android/tv/dialog/PinDialogFragment.java
@@ -45,13 +45,13 @@ import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.util.TvSettings;
public class PinDialogFragment extends SafeDismissDialogFragment {
private static final String TAG = "PinDialogFragment";
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = true;
/** PIN code dialog for unlock channel */
public static final int PIN_DIALOG_TYPE_UNLOCK_CHANNEL = 0;
@@ -68,7 +68,7 @@ public class PinDialogFragment extends SafeDismissDialogFragment {
/** PIN code dialog for set new PIN */
public static final int PIN_DIALOG_TYPE_NEW_PIN = 3;
- // PIN code dialog for checking old PIN. Only used in this class.
+ // PIN code dialog for checking old PIN. This is internal only.
private static final int PIN_DIALOG_TYPE_OLD_PIN = 4;
/** PIN code dialog for unlocking DVR playback */
@@ -192,7 +192,7 @@ public class PinDialogFragment extends SafeDismissDialogFragment {
mTitleView.setText(
getString(
R.string.pin_enter_unlock_dvr,
- TvSingletons.getSingletons(getContext())
+ TvApplication.getSingletons(getContext())
.getTvInputManagerHelper()
.getContentRatingsManager()
.getDisplayNameForRating(tvContentRating)));
diff --git a/src/com/android/tv/dialog/SafeDismissDialogFragment.java b/src/com/android/tv/dialog/SafeDismissDialogFragment.java
index 6eb67dfd..18460cb6 100644
--- a/src/com/android/tv/dialog/SafeDismissDialogFragment.java
+++ b/src/com/android/tv/dialog/SafeDismissDialogFragment.java
@@ -19,7 +19,7 @@ package com.android.tv.dialog;
import android.app.Activity;
import android.app.DialogFragment;
import com.android.tv.MainActivity;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.analytics.HasTrackerLabel;
import com.android.tv.analytics.Tracker;
@@ -37,7 +37,7 @@ public abstract class SafeDismissDialogFragment extends DialogFragment implement
if (activity instanceof MainActivity) {
mActivity = (MainActivity) activity;
}
- mTracker = TvSingletons.getSingletons(activity).getTracker();
+ mTracker = TvApplication.getSingletons(activity).getTracker();
if (mDismissPending) {
mDismissPending = false;
dismiss();
diff --git a/src/com/android/tv/dvr/BaseDvrDataManager.java b/src/com/android/tv/dvr/BaseDvrDataManager.java
index 0befba9c..342e4b21 100644
--- a/src/com/android/tv/dvr/BaseDvrDataManager.java
+++ b/src/com/android/tv/dvr/BaseDvrDataManager.java
@@ -25,11 +25,11 @@ import android.util.ArraySet;
import android.util.Log;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.feature.CommonFeatures;
-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.dvr.data.ScheduledRecording.RecordingState;
import com.android.tv.dvr.data.SeriesRecording;
+import com.android.tv.util.Clock;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
diff --git a/src/com/android/tv/dvr/DvrDataManagerImpl.java b/src/com/android/tv/dvr/DvrDataManagerImpl.java
index 28006b08..17ea63a0 100644
--- a/src/com/android/tv/dvr/DvrDataManagerImpl.java
+++ b/src/com/android/tv/dvr/DvrDataManagerImpl.java
@@ -38,12 +38,9 @@ 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.TvApplication;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.common.recording.RecordingStorageStatusManager;
-import com.android.tv.common.recording.RecordingStorageStatusManager.OnStorageMountChangedListener;
-import com.android.tv.common.util.Clock;
-import com.android.tv.common.util.CommonUtils;
+import com.android.tv.dvr.DvrStorageStatusManager.OnStorageMountChangedListener;
import com.android.tv.dvr.data.IdGenerator;
import com.android.tv.dvr.data.RecordedProgram;
import com.android.tv.dvr.data.ScheduledRecording;
@@ -61,9 +58,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.Clock;
import com.android.tv.util.Filter;
import com.android.tv.util.TvInputManagerHelper;
import com.android.tv.util.TvUriMatcher;
+import com.android.tv.util.Utils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -115,7 +114,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager {
private boolean mRecordedProgramLoadFinished;
private final Set<AsyncTask> mPendingTasks = new ArraySet<>();
private DvrDbSync mDbSync;
- private RecordingStorageStatusManager mStorageStatusManager;
+ private DvrStorageStatusManager mStorageStatusManager;
private final TvInputCallback mInputCallback =
new TvInputCallback() {
@@ -141,7 +140,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager {
@Override
public void onStorageMountChanged(boolean storageMounted) {
for (TvInputInfo input : mInputManager.getTvInputInfos(true, true)) {
- if (CommonUtils.isBundledInput(input.getId())) {
+ if (Utils.isBundledInput(input.getId())) {
if (storageMounted) {
unhideInput(input.getId());
} else {
@@ -170,9 +169,8 @@ public class DvrDataManagerImpl extends BaseDvrDataManager {
public DvrDataManagerImpl(Context context, Clock clock) {
super(context, clock);
mContext = context;
- mInputManager = TvSingletons.getSingletons(context).getTvInputManagerHelper();
- mStorageStatusManager =
- TvSingletons.getSingletons(context).getRecordingStorageStatusManager();
+ mInputManager = TvApplication.getSingletons(context).getTvInputManagerHelper();
+ mStorageStatusManager = TvApplication.getSingletons(context).getDvrStorageStatusManager();
}
public void start() {
@@ -610,8 +608,9 @@ public class DvrDataManagerImpl extends BaseDvrDataManager {
SoftPreconditions.checkArgument(
previousSeries == null,
TAG,
- "Attempt to add series" + " recording with the duplicate series ID: %s",
- r.getSeriesId());
+ "Attempt to add series"
+ + " recording with the duplicate series ID: "
+ + r.getSeriesId());
}
if (mDvrLoadFinished) {
notifySeriesRecordingAdded(seriesRecordings);
@@ -780,14 +779,13 @@ public class DvrDataManagerImpl extends BaseDvrDataManager {
if (!SoftPreconditions.checkArgument(
mSeriesRecordings.containsKey(r.getId()),
TAG,
- "Non Existing Series ID: %s",
- r)) {
+ "Non Existing Series ID: " + r)) {
continue;
}
SeriesRecording old1 = mSeriesRecordings.put(r.getId(), r);
SeriesRecording old2 = mSeriesId2SeriesRecordings.put(r.getSeriesId(), r);
SoftPreconditions.checkArgument(
- old1.equals(old2), TAG, "Series ID cannot be updated: %s", r);
+ old1.equals(old2), TAG, "Series ID cannot be" + " updated: " + r);
}
if (mDvrLoadFinished) {
notifySeriesRecordingChanged(seriesRecordings);
@@ -797,8 +795,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager {
private boolean isInputAvailable(String inputId) {
return mInputManager.hasTvInputInfo(inputId)
- && (!CommonUtils.isBundledInput(inputId)
- || mStorageStatusManager.isStorageMounted());
+ && (!Utils.isBundledInput(inputId) || mStorageStatusManager.isStorageMounted());
}
private void removeDeletedSchedules(ScheduledRecording... addedSchedules) {
diff --git a/src/com/android/tv/dvr/DvrManager.java b/src/com/android/tv/dvr/DvrManager.java
index 247e1bc5..50751d95 100644
--- a/src/com/android/tv/dvr/DvrManager.java
+++ b/src/com/android/tv/dvr/DvrManager.java
@@ -36,10 +36,10 @@ 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.ApplicationSingletons;
+import com.android.tv.TvApplication;
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.Channel;
import com.android.tv.data.Program;
import com.android.tv.dvr.DvrDataManager.OnRecordedProgramLoadFinishedListener;
@@ -78,9 +78,9 @@ public class DvrManager {
public DvrManager(Context context) {
SoftPreconditions.checkFeatureEnabled(context, CommonFeatures.DVR, TAG);
mAppContext = context.getApplicationContext();
- TvSingletons tvSingletons = TvSingletons.getSingletons(context);
- mDataManager = (WritableDvrDataManager) tvSingletons.getDvrDataManager();
- mScheduleManager = tvSingletons.getDvrScheduleManager();
+ ApplicationSingletons appSingletons = TvApplication.getSingletons(context);
+ mDataManager = (WritableDvrDataManager) appSingletons.getDvrDataManager();
+ mScheduleManager = appSingletons.getDvrScheduleManager();
if (mDataManager.isInitialized() && mScheduleManager.isInitialized()) {
createSeriesRecordingsForRecordedProgramsIfNeeded(mDataManager.getRecordedPrograms());
} else {
@@ -666,7 +666,7 @@ public class DvrManager {
return false;
}
Program program =
- TvSingletons.getSingletons(mAppContext)
+ TvApplication.getSingletons(mAppContext)
.getProgramDataManager()
.getCurrentProgram(channel.getId());
return program == null || !program.isRecordingProhibited();
@@ -683,7 +683,7 @@ public class DvrManager {
return false;
}
Channel channel =
- TvSingletons.getSingletons(mAppContext)
+ TvApplication.getSingletons(mAppContext)
.getChannelDataManager()
.getChannel(program.getChannelId());
if (channel == null || channel.isRecordingProhibited()) {
@@ -833,7 +833,7 @@ public class DvrManager {
if (!recordedProgramPath.exists()) {
if (DEBUG) Log.d(TAG, "File to delete not exist: " + recordedProgramPath);
} else {
- CommonUtils.deleteDirOrFile(recordedProgramPath);
+ Utils.deleteDirOrFile(recordedProgramPath);
if (DEBUG) {
Log.d(TAG, "Sucessfully deleted files of the recorded program: " + dataUri);
}
diff --git a/src/com/android/tv/dvr/DvrScheduleManager.java b/src/com/android/tv/dvr/DvrScheduleManager.java
index cbb89290..62f93c8b 100644
--- a/src/com/android/tv/dvr/DvrScheduleManager.java
+++ b/src/com/android/tv/dvr/DvrScheduleManager.java
@@ -25,7 +25,8 @@ 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.ApplicationSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
@@ -50,7 +51,6 @@ import java.util.concurrent.CopyOnWriteArraySet;
/** A class to manage the schedules. */
@TargetApi(Build.VERSION_CODES.N)
@MainThread
-@SuppressWarnings("AndroidApiChecker") // TODO(b/32513850) remove when error prone is updated
public class DvrScheduleManager {
private static final String TAG = "DvrScheduleManager";
@@ -94,9 +94,9 @@ public class DvrScheduleManager {
public DvrScheduleManager(Context context) {
mContext = context;
- TvSingletons tvSingletons = TvSingletons.getSingletons(context);
- mDataManager = (DvrDataManagerImpl) tvSingletons.getDvrDataManager();
- mChannelDataManager = tvSingletons.getChannelDataManager();
+ ApplicationSingletons appSingletons = TvApplication.getSingletons(context);
+ mDataManager = (DvrDataManagerImpl) appSingletons.getDvrDataManager();
+ mChannelDataManager = appSingletons.getChannelDataManager();
if (mDataManager.isDvrScheduleLoadFinished() && mChannelDataManager.isDbLoadFinished()) {
buildData();
} else {
@@ -126,7 +126,7 @@ public class DvrScheduleManager {
TvInputInfo input =
Utils.getTvInputInfoForInputId(mContext, schedule.getInputId());
if (!SoftPreconditions.checkArgument(
- input != null, TAG, "Input was removed for : %s", schedule)) {
+ input != null, TAG, "Input was removed for : " + schedule)) {
// Input removed.
mInputScheduleMap.remove(schedule.getInputId());
mInputConflictInfoMap.remove(schedule.getInputId());
@@ -190,7 +190,7 @@ public class DvrScheduleManager {
TvInputInfo input =
Utils.getTvInputInfoForInputId(mContext, schedule.getInputId());
if (!SoftPreconditions.checkArgument(
- input != null, TAG, "Input was removed for : %s", schedule)) {
+ input != null, TAG, "Input was removed for : " + schedule)) {
// Input removed.
mInputScheduleMap.remove(schedule.getInputId());
mInputConflictInfoMap.remove(schedule.getInputId());
diff --git a/src/com/android/tv/dvr/DvrStorageStatusManager.java b/src/com/android/tv/dvr/DvrStorageStatusManager.java
index fe5a47b8..a2f4bda8 100644
--- a/src/com/android/tv/dvr/DvrStorageStatusManager.java
+++ b/src/com/android/tv/dvr/DvrStorageStatusManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -11,56 +11,272 @@
* 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.
+ * limitations under the License
*/
+
package com.android.tv.dvr;
+import android.content.BroadcastReceiver;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.OperationApplicationException;
import android.database.Cursor;
+import android.media.tv.TvContract;
import android.media.tv.TvInputInfo;
import android.net.Uri;
import android.os.AsyncTask;
+import android.os.Environment;
+import android.os.Looper;
import android.os.RemoteException;
-import android.support.media.tv.TvContractCompat;
+import android.os.StatFs;
+import android.support.annotation.AnyThread;
+import android.support.annotation.IntDef;
+import android.support.annotation.WorkerThread;
import android.util.Log;
-import com.android.tv.TvSingletons;
-import com.android.tv.common.recording.RecordingStorageStatusManager;
-import com.android.tv.common.util.CommonUtils;
+import com.android.tv.TvApplication;
+import com.android.tv.common.SoftPreconditions;
+import com.android.tv.common.feature.CommonFeatures;
import com.android.tv.util.TvInputManagerHelper;
+import com.android.tv.util.Utils;
import java.io.File;
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
-/** A class for extending TV app-specific function to {@link RecordingStorageStatusManager}. */
-@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed
-public class DvrStorageStatusManager extends RecordingStorageStatusManager {
+/** Signals DVR storage status change such as plugging/unplugging. */
+public class DvrStorageStatusManager {
private static final String TAG = "DvrStorageStatusManager";
+ private static final boolean DEBUG = false;
- private final Context mContext;
- private CleanUpDbTask mCleanUpDbTask;
+ /** Minimum storage size to support DVR */
+ public static final long MIN_STORAGE_SIZE_FOR_DVR_IN_BYTES = 50 * 1024 * 1024 * 1024L; // 50GB
+
+ private static final long MIN_FREE_STORAGE_SIZE_FOR_DVR_IN_BYTES =
+ 10 * 1024 * 1024 * 1024L; // 10GB
+ private static final String RECORDING_DATA_SUB_PATH = "/recording";
private static final String[] PROJECTION = {
- TvContractCompat.RecordedPrograms._ID,
- TvContractCompat.RecordedPrograms.COLUMN_PACKAGE_NAME,
- TvContractCompat.RecordedPrograms.COLUMN_RECORDING_DATA_URI
+ TvContract.RecordedPrograms._ID,
+ TvContract.RecordedPrograms.COLUMN_PACKAGE_NAME,
+ TvContract.RecordedPrograms.COLUMN_RECORDING_DATA_URI
};
private static final int BATCH_OPERATION_COUNT = 100;
- public DvrStorageStatusManager(Context context) {
- super(context);
+ @IntDef({
+ STORAGE_STATUS_OK,
+ STORAGE_STATUS_TOTAL_CAPACITY_TOO_SMALL,
+ STORAGE_STATUS_FREE_SPACE_INSUFFICIENT,
+ STORAGE_STATUS_MISSING
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StorageStatus {}
+
+ /** Current storage is OK to record a program. */
+ public static final int STORAGE_STATUS_OK = 0;
+
+ /** Current storage's total capacity is smaller than DVR requirement. */
+ public static final int STORAGE_STATUS_TOTAL_CAPACITY_TOO_SMALL = 1;
+
+ /** Current storage's free space is insufficient to record programs. */
+ public static final int STORAGE_STATUS_FREE_SPACE_INSUFFICIENT = 2;
+
+ /** Current storage is missing. */
+ public static final int STORAGE_STATUS_MISSING = 3;
+
+ private final Context mContext;
+ private final Set<OnStorageMountChangedListener> mOnStorageMountChangedListeners =
+ new CopyOnWriteArraySet<>();
+ private final boolean mRunningInMainProcess;
+ private MountedStorageStatus mMountedStorageStatus;
+ private boolean mStorageValid;
+ private CleanUpDbTask mCleanUpDbTask;
+
+ private class MountedStorageStatus {
+ private final boolean mStorageMounted;
+ private final File mStorageMountedDir;
+ private final long mStorageMountedCapacity;
+
+ private MountedStorageStatus(boolean mounted, File mountedDir, long capacity) {
+ mStorageMounted = mounted;
+ mStorageMountedDir = mountedDir;
+ mStorageMountedCapacity = capacity;
+ }
+
+ private boolean isValidForDvr() {
+ return mStorageMounted && mStorageMountedCapacity >= MIN_STORAGE_SIZE_FOR_DVR_IN_BYTES;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof MountedStorageStatus)) {
+ return false;
+ }
+ MountedStorageStatus status = (MountedStorageStatus) other;
+ return mStorageMounted == status.mStorageMounted
+ && Objects.equals(mStorageMountedDir, status.mStorageMountedDir)
+ && mStorageMountedCapacity == status.mStorageMountedCapacity;
+ }
+ }
+
+ public interface OnStorageMountChangedListener {
+
+ /**
+ * Listener for DVR storage status change.
+ *
+ * @param storageMounted {@code true} when DVR possible storage is mounted, {@code false}
+ * otherwise.
+ */
+ void onStorageMountChanged(boolean storageMounted);
+ }
+
+ private final class StorageStatusBroadcastReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ MountedStorageStatus result = getStorageStatusInternal();
+ if (mMountedStorageStatus.equals(result)) {
+ return;
+ }
+ mMountedStorageStatus = result;
+ if (result.mStorageMounted && mRunningInMainProcess) {
+ // Cleans up DB in LC process.
+ // Tuner process is not always on.
+ if (mCleanUpDbTask != null) {
+ mCleanUpDbTask.cancel(true);
+ }
+ mCleanUpDbTask = new CleanUpDbTask();
+ mCleanUpDbTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+ boolean valid = result.isValidForDvr();
+ if (valid == mStorageValid) {
+ return;
+ }
+ mStorageValid = valid;
+ for (OnStorageMountChangedListener l : mOnStorageMountChangedListeners) {
+ l.onStorageMountChanged(valid);
+ }
+ }
+ }
+
+ /**
+ * Creates DvrStorageStatusManager.
+ *
+ * @param context {@link Context}
+ */
+ public DvrStorageStatusManager(final Context context, boolean runningInMainProcess) {
mContext = context;
+ mRunningInMainProcess = runningInMainProcess;
+ mMountedStorageStatus = getStorageStatusInternal();
+ mStorageValid = mMountedStorageStatus.isValidForDvr();
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_MEDIA_MOUNTED);
+ filter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
+ filter.addAction(Intent.ACTION_MEDIA_EJECT);
+ filter.addAction(Intent.ACTION_MEDIA_REMOVED);
+ filter.addAction(Intent.ACTION_MEDIA_BAD_REMOVAL);
+ filter.addDataScheme(ContentResolver.SCHEME_FILE);
+ mContext.registerReceiver(new StorageStatusBroadcastReceiver(), filter);
+ }
+
+ /**
+ * Adds the listener for receiving storage status change.
+ *
+ * @param listener
+ */
+ public void addListener(OnStorageMountChangedListener listener) {
+ mOnStorageMountChangedListeners.add(listener);
+ }
+
+ /** Removes the current listener. */
+ public void removeListener(OnStorageMountChangedListener listener) {
+ mOnStorageMountChangedListeners.remove(listener);
+ }
+
+ /** Returns true if a storage is mounted. */
+ public boolean isStorageMounted() {
+ return mMountedStorageStatus.mStorageMounted;
+ }
+
+ /** Returns the path to DVR recording data directory. This can take for a while sometimes. */
+ @WorkerThread
+ public File getRecordingRootDataDirectory() {
+ SoftPreconditions.checkState(Looper.myLooper() != Looper.getMainLooper());
+ if (mMountedStorageStatus.mStorageMountedDir == null) {
+ return null;
+ }
+ File root = mContext.getExternalFilesDir(null);
+ String rootPath;
+ try {
+ rootPath = root != null ? root.getCanonicalPath() : null;
+ } catch (IOException | SecurityException e) {
+ return null;
+ }
+ return rootPath == null ? null : new File(rootPath + RECORDING_DATA_SUB_PATH);
+ }
+
+ /**
+ * Returns the current storage status for DVR recordings.
+ *
+ * @return {@link StorageStatus}
+ */
+ @AnyThread
+ public @StorageStatus int getDvrStorageStatus() {
+ MountedStorageStatus status = mMountedStorageStatus;
+ if (status.mStorageMountedDir == null) {
+ return STORAGE_STATUS_MISSING;
+ }
+ if (CommonFeatures.FORCE_RECORDING_UNTIL_NO_SPACE.isEnabled(mContext)) {
+ return STORAGE_STATUS_OK;
+ }
+ if (status.mStorageMountedCapacity < MIN_STORAGE_SIZE_FOR_DVR_IN_BYTES) {
+ return STORAGE_STATUS_TOTAL_CAPACITY_TOO_SMALL;
+ }
+ try {
+ StatFs statFs = new StatFs(status.mStorageMountedDir.toString());
+ if (statFs.getAvailableBytes() < MIN_FREE_STORAGE_SIZE_FOR_DVR_IN_BYTES) {
+ return STORAGE_STATUS_FREE_SPACE_INSUFFICIENT;
+ }
+ } catch (IllegalArgumentException e) {
+ // In rare cases, storage status change was not notified yet.
+ SoftPreconditions.checkState(false);
+ return STORAGE_STATUS_FREE_SPACE_INSUFFICIENT;
+ }
+ return STORAGE_STATUS_OK;
}
- @Override
- protected void cleanUpDbIfNeeded() {
- if (mCleanUpDbTask != null) {
- mCleanUpDbTask.cancel(true);
+ /**
+ * Returns whether the storage has sufficient storage.
+ *
+ * @return {@code true} when there is sufficient storage, {@code false} otherwise
+ */
+ public boolean isStorageSufficient() {
+ return getDvrStorageStatus() == STORAGE_STATUS_OK;
+ }
+
+ private MountedStorageStatus getStorageStatusInternal() {
+ boolean storageMounted =
+ Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
+ File storageMountedDir = storageMounted ? Environment.getExternalStorageDirectory() : null;
+ storageMounted = storageMounted && storageMountedDir != null;
+ long storageMountedCapacity = 0L;
+ if (storageMounted) {
+ try {
+ StatFs statFs = new StatFs(storageMountedDir.toString());
+ storageMountedCapacity = statFs.getTotalBytes();
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Storage mount status was changed.");
+ storageMounted = false;
+ storageMountedDir = null;
+ }
}
- mCleanUpDbTask = new CleanUpDbTask();
- mCleanUpDbTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ return new MountedStorageStatus(storageMounted, storageMountedDir, storageMountedCapacity);
}
private class CleanUpDbTask extends AsyncTask<Void, Void, Boolean> {
@@ -72,11 +288,11 @@ public class DvrStorageStatusManager extends RecordingStorageStatusManager {
@Override
protected Boolean doInBackground(Void... params) {
- @StorageStatus int storageStatus = getDvrStorageStatus();
- if (storageStatus == STORAGE_STATUS_MISSING) {
+ @DvrStorageStatusManager.StorageStatus int storageStatus = getDvrStorageStatus();
+ if (storageStatus == DvrStorageStatusManager.STORAGE_STATUS_MISSING) {
return null;
}
- if (storageStatus == STORAGE_STATUS_TOTAL_CAPACITY_TOO_SMALL) {
+ if (storageStatus == DvrStorageStatusManager.STORAGE_STATUS_TOTAL_CAPACITY_TOO_SMALL) {
return true;
}
List<ContentProviderOperation> ops = getDeleteOps();
@@ -94,7 +310,7 @@ public class DvrStorageStatusManager extends RecordingStorageStatusManager {
ArrayList<ContentProviderOperation> batchOps =
new ArrayList<>(ops.subList(i, toIndex));
try {
- mContext.getContentResolver().applyBatch(TvContractCompat.AUTHORITY, batchOps);
+ mContext.getContentResolver().applyBatch(TvContract.AUTHORITY, batchOps);
} catch (RemoteException | OperationApplicationException e) {
Log.e(TAG, "Failed to clean up RecordedPrograms.", e);
}
@@ -105,16 +321,16 @@ public class DvrStorageStatusManager extends RecordingStorageStatusManager {
@Override
protected void onPostExecute(Boolean forgetStorage) {
if (forgetStorage != null && forgetStorage == true) {
- DvrManager dvrManager = TvSingletons.getSingletons(mContext).getDvrManager();
+ DvrManager dvrManager = TvApplication.getSingletons(mContext).getDvrManager();
TvInputManagerHelper tvInputManagerHelper =
- TvSingletons.getSingletons(mContext).getTvInputManagerHelper();
+ TvApplication.getSingletons(mContext).getTvInputManagerHelper();
List<TvInputInfo> tvInputInfoList =
tvInputManagerHelper.getTvInputInfos(true, false);
if (tvInputInfoList == null || tvInputInfoList.isEmpty()) {
return;
}
for (TvInputInfo info : tvInputInfoList) {
- if (CommonUtils.isBundledInput(info.getId())) {
+ if (Utils.isBundledInput(info.getId())) {
dvrManager.forgetStorage(info.getId());
}
}
@@ -129,7 +345,7 @@ public class DvrStorageStatusManager extends RecordingStorageStatusManager {
try (Cursor c =
mContentResolver.query(
- TvContractCompat.RecordedPrograms.CONTENT_URI,
+ TvContract.RecordedPrograms.CONTENT_URI,
PROJECTION,
null,
null,
@@ -138,8 +354,10 @@ public class DvrStorageStatusManager extends RecordingStorageStatusManager {
return null;
}
while (c.moveToNext()) {
- @StorageStatus int storageStatus = getDvrStorageStatus();
- if (isCancelled() || storageStatus == STORAGE_STATUS_MISSING) {
+ @DvrStorageStatusManager.StorageStatus
+ int storageStatus = getDvrStorageStatus();
+ if (isCancelled()
+ || storageStatus == DvrStorageStatusManager.STORAGE_STATUS_MISSING) {
ops.clear();
break;
}
@@ -150,7 +368,7 @@ public class DvrStorageStatusManager extends RecordingStorageStatusManager {
continue;
}
Uri dataUri = Uri.parse(dataUriString);
- if (!CommonUtils.isInBundledPackageSet(packageName)
+ if (!Utils.isInBundledPackageSet(packageName)
|| dataUri == null
|| dataUri.getPath() == null
|| !ContentResolver.SCHEME_FILE.equals(dataUri.getScheme())) {
@@ -160,7 +378,7 @@ public class DvrStorageStatusManager extends RecordingStorageStatusManager {
if (!recordedProgramDir.exists()) {
ops.add(
ContentProviderOperation.newDelete(
- TvContractCompat.buildRecordedProgramUri(
+ TvContract.buildRecordedProgramUri(
Long.parseLong(id)))
.build());
}
diff --git a/src/com/android/tv/dvr/DvrWatchedPositionManager.java b/src/com/android/tv/dvr/DvrWatchedPositionManager.java
index 8616962f..7da2bfc9 100644
--- a/src/com/android/tv/dvr/DvrWatchedPositionManager.java
+++ b/src/com/android/tv/dvr/DvrWatchedPositionManager.java
@@ -20,7 +20,7 @@ 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.common.SharedPreferencesUtils;
import com.android.tv.dvr.data.RecordedProgram;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/src/com/android/tv/dvr/data/RecordedProgram.java b/src/com/android/tv/dvr/data/RecordedProgram.java
index e1fbca8c..18841ae5 100644
--- a/src/com/android/tv/dvr/data/RecordedProgram.java
+++ b/src/com/android/tv/dvr/data/RecordedProgram.java
@@ -30,10 +30,10 @@ import android.support.annotation.Nullable;
import android.text.TextUtils;
import com.android.tv.common.R;
import com.android.tv.common.TvContentRatingCache;
-import com.android.tv.common.util.CommonUtils;
import com.android.tv.data.BaseProgram;
import com.android.tv.data.GenreItems;
import com.android.tv.data.InternalDataUtils;
+import com.android.tv.util.Utils;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
@@ -118,7 +118,7 @@ public class RecordedProgram extends BaseProgram {
.setInternalProviderFlag3(cursor.getInt(index++))
.setInternalProviderFlag4(cursor.getInt(index++))
.setVersionNumber(cursor.getInt(index++));
- if (CommonUtils.isInBundledPackageSet(builder.mPackageName)) {
+ if (Utils.isInBundledPackageSet(builder.mPackageName)) {
InternalDataUtils.deserializeInternalProviderData(cursor.getBlob(index), builder);
}
return builder.build();
diff --git a/src/com/android/tv/dvr/data/ScheduledRecording.java b/src/com/android/tv/dvr/data/ScheduledRecording.java
index aa1dfc72..7de37ebc 100644
--- a/src/com/android/tv/dvr/data/ScheduledRecording.java
+++ b/src/com/android/tv/dvr/data/ScheduledRecording.java
@@ -16,25 +16,23 @@
package com.android.tv.dvr.data;
-import android.annotation.TargetApi;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
-import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.IntDef;
import android.text.TextUtils;
import android.util.Range;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.common.util.CommonUtils;
import com.android.tv.data.Channel;
import com.android.tv.data.Program;
import com.android.tv.dvr.DvrScheduleManager;
import com.android.tv.dvr.provider.DvrContract.Schedules;
import com.android.tv.util.CompositeComparator;
+import com.android.tv.util.Utils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Collection;
@@ -42,8 +40,6 @@ import java.util.Comparator;
import java.util.Objects;
/** A data class for one recording contents. */
-@TargetApi(Build.VERSION_CODES.N)
-@SuppressWarnings("AndroidApiChecker") // TODO(b/32513850) remove when error prone is updated
public final class ScheduledRecording implements Parcelable {
private static final String TAG = "ScheduledRecording";
@@ -659,7 +655,7 @@ public final class ScheduledRecording implements Parcelable {
return mProgramTitle;
}
Channel channel =
- TvSingletons.getSingletons(context).getChannelDataManager().getChannel(mChannelId);
+ TvApplication.getSingletons(context).getChannelDataManager().getChannel(mChannelId);
return channel != null
? channel.getDisplayName()
: context.getString(R.string.no_program_information);
@@ -673,7 +669,7 @@ public final class ScheduledRecording implements Parcelable {
case Schedules.TYPE_PROGRAM:
return TYPE_PROGRAM;
default:
- SoftPreconditions.checkArgument(false, TAG, "Unknown recording type %s", type);
+ SoftPreconditions.checkArgument(false, TAG, "Unknown recording type " + type);
return TYPE_TIMED;
}
}
@@ -686,7 +682,7 @@ public final class ScheduledRecording implements Parcelable {
case TYPE_PROGRAM:
return Schedules.TYPE_PROGRAM;
default:
- SoftPreconditions.checkArgument(false, TAG, "Unknown recording type %s", type);
+ SoftPreconditions.checkArgument(false, TAG, "Unknown recording type " + type);
return Schedules.TYPE_TIMED;
}
}
@@ -712,7 +708,7 @@ public final class ScheduledRecording implements Parcelable {
case Schedules.STATE_RECORDING_CANCELED:
return STATE_RECORDING_CANCELED;
default:
- SoftPreconditions.checkArgument(false, TAG, "Unknown recording state %s", state);
+ SoftPreconditions.checkArgument(false, TAG, "Unknown recording state" + state);
return STATE_RECORDING_NOT_STARTED;
}
}
@@ -738,7 +734,7 @@ public final class ScheduledRecording implements Parcelable {
case STATE_RECORDING_CANCELED:
return Schedules.STATE_RECORDING_CANCELED;
default:
- SoftPreconditions.checkArgument(false, TAG, "Unknown recording state %s", state);
+ SoftPreconditions.checkArgument(false, TAG, "Unknown recording state" + state);
return Schedules.STATE_RECORDING_NOT_STARTED;
}
}
@@ -769,12 +765,12 @@ public final class ScheduledRecording implements Parcelable {
+ ",type="
+ mType
+ ",startTime="
- + CommonUtils.toIsoDateTimeString(mStartTimeMs)
+ + Utils.toIsoDateTimeString(mStartTimeMs)
+ "("
+ mStartTimeMs
+ ")"
+ ",endTime="
- + CommonUtils.toIsoDateTimeString(mEndTimeMs)
+ + Utils.toIsoDateTimeString(mEndTimeMs)
+ "("
+ mEndTimeMs
+ ")"
diff --git a/src/com/android/tv/dvr/data/SeriesRecording.java b/src/com/android/tv/dvr/data/SeriesRecording.java
index 96b3425a..1fd1cea3 100644
--- a/src/com/android/tv/dvr/data/SeriesRecording.java
+++ b/src/com/android/tv/dvr/data/SeriesRecording.java
@@ -568,7 +568,7 @@ public class SeriesRecording implements Parcelable {
mLongDescription,
mSeriesId,
mChannelOption,
- Arrays.hashCode(mCanonicalGenreIds),
+ mCanonicalGenreIds,
mPosterUri,
mPhotoUri,
mState);
diff --git a/src/com/android/tv/dvr/provider/AsyncDvrDbTask.java b/src/com/android/tv/dvr/provider/AsyncDvrDbTask.java
index db18e609..ad00bec8 100644
--- a/src/com/android/tv/dvr/provider/AsyncDvrDbTask.java
+++ b/src/com/android/tv/dvr/provider/AsyncDvrDbTask.java
@@ -20,18 +20,17 @@ import android.content.Context;
import android.database.Cursor;
import android.os.AsyncTask;
import android.support.annotation.Nullable;
-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.NamedThreadFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/** {@link AsyncTask} that defaults to executing on its own single threaded Executor Service. */
-@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed
public abstract class AsyncDvrDbTask<Params, Progress, Result>
extends AsyncTask<Params, Progress, Result> {
private static final NamedThreadFactory THREAD_FACTORY =
diff --git a/src/com/android/tv/dvr/provider/DvrDatabaseHelper.java b/src/com/android/tv/dvr/provider/DvrDatabaseHelper.java
index 0fb96d1b..fb793a0e 100644
--- a/src/com/android/tv/dvr/provider/DvrDatabaseHelper.java
+++ b/src/com/android/tv/dvr/provider/DvrDatabaseHelper.java
@@ -34,7 +34,7 @@ import com.android.tv.dvr.provider.DvrContract.SeriesRecordings;
/** A data class for one recorded contents. */
public class DvrDatabaseHelper extends SQLiteOpenHelper {
private static final String TAG = "DvrDatabaseHelper";
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = true;
private static final int DATABASE_VERSION = 17;
private static final String DB_NAME = "dvr.db";
diff --git a/src/com/android/tv/dvr/provider/DvrDbSync.java b/src/com/android/tv/dvr/provider/DvrDbSync.java
index 8bd16221..1cdeef24 100644
--- a/src/com/android/tv/dvr/provider/DvrDbSync.java
+++ b/src/com/android/tv/dvr/provider/DvrDbSync.java
@@ -29,7 +29,7 @@ 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.TvApplication;
import com.android.tv.data.ChannelDataManager;
import com.android.tv.data.Program;
import com.android.tv.dvr.DvrDataManager.ScheduledRecordingListener;
@@ -140,8 +140,8 @@ public class DvrDbSync {
this(
context,
dataManager,
- TvSingletons.getSingletons(context).getChannelDataManager(),
- TvSingletons.getSingletons(context).getDvrManager(),
+ TvApplication.getSingletons(context).getChannelDataManager(),
+ TvApplication.getSingletons(context).getDvrManager(),
SeriesRecordingScheduler.getInstance(context));
}
diff --git a/src/com/android/tv/dvr/provider/EpisodicProgramLoadTask.java b/src/com/android/tv/dvr/provider/EpisodicProgramLoadTask.java
index 7cdc7b73..e9ca11e5 100644
--- a/src/com/android/tv/dvr/provider/EpisodicProgramLoadTask.java
+++ b/src/com/android/tv/dvr/provider/EpisodicProgramLoadTask.java
@@ -25,9 +25,8 @@ 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.TvApplication;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.common.util.PermissionUtils;
import com.android.tv.data.Program;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.data.ScheduledRecording;
@@ -35,6 +34,7 @@ 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 com.android.tv.util.PermissionUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -91,7 +91,7 @@ public abstract class EpisodicProgramLoadTask {
*/
public EpisodicProgramLoadTask(Context context, Collection<SeriesRecording> seriesRecordings) {
mContext = context.getApplicationContext();
- mDataManager = TvSingletons.getSingletons(context).getDvrDataManager();
+ mDataManager = TvApplication.getSingletons(context).getDvrDataManager();
mSeriesRecordings.addAll(seriesRecordings);
}
diff --git a/src/com/android/tv/dvr/recorder/ConflictChecker.java b/src/com/android/tv/dvr/recorder/ConflictChecker.java
index f5bc7b9f..732815cd 100644
--- a/src/com/android/tv/dvr/recorder/ConflictChecker.java
+++ b/src/com/android/tv/dvr/recorder/ConflictChecker.java
@@ -27,10 +27,11 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.ArraySet;
import android.util.Log;
+import com.android.tv.ApplicationSingletons;
import com.android.tv.InputSessionManager;
import com.android.tv.InputSessionManager.OnTvViewChannelChangeListener;
import com.android.tv.MainActivity;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.common.WeakHandler;
import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
@@ -39,7 +40,6 @@ import com.android.tv.dvr.DvrScheduleManager;
import com.android.tv.dvr.data.ScheduledRecording;
import com.android.tv.dvr.ui.DvrUiHelper;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -88,35 +88,21 @@ public class ConflictChecker {
new ScheduledRecordingListener() {
@Override
public void onScheduledRecordingAdded(ScheduledRecording... scheduledRecordings) {
- if (DEBUG) {
- Log.d(
- TAG,
- "onScheduledRecordingAdded: "
- + Arrays.toString(scheduledRecordings));
- }
+ if (DEBUG) Log.d(TAG, "onScheduledRecordingAdded: " + scheduledRecordings);
mHandler.sendEmptyMessage(MSG_CHECK_CONFLICT);
}
@Override
public void onScheduledRecordingRemoved(ScheduledRecording... scheduledRecordings) {
- if (DEBUG) {
- Log.d(
- TAG,
- "onScheduledRecordingRemoved: "
- + Arrays.toString(scheduledRecordings));
- }
+ if (DEBUG) Log.d(TAG, "onScheduledRecordingRemoved: " + scheduledRecordings);
mHandler.sendEmptyMessage(MSG_CHECK_CONFLICT);
}
@Override
public void onScheduledRecordingStatusChanged(
ScheduledRecording... scheduledRecordings) {
- if (DEBUG) {
- Log.d(
- TAG,
- "onScheduledRecordingStatusChanged: "
- + Arrays.toString(scheduledRecordings));
- }
+ if (DEBUG)
+ Log.d(TAG, "onScheduledRecordingStatusChanged: " + scheduledRecordings);
mHandler.sendEmptyMessage(MSG_CHECK_CONFLICT);
}
};
@@ -133,10 +119,10 @@ public class ConflictChecker {
public ConflictChecker(MainActivity mainActivity) {
mMainActivity = mainActivity;
- TvSingletons tvSingletons = TvSingletons.getSingletons(mainActivity);
- mChannelDataManager = tvSingletons.getChannelDataManager();
- mScheduleManager = tvSingletons.getDvrScheduleManager();
- mSessionManager = tvSingletons.getInputSessionManager();
+ ApplicationSingletons appSingletons = TvApplication.getSingletons(mainActivity);
+ mChannelDataManager = appSingletons.getChannelDataManager();
+ mScheduleManager = appSingletons.getDvrScheduleManager();
+ mSessionManager = appSingletons.getInputSessionManager();
}
/** Starts checking the conflict. */
diff --git a/src/com/android/tv/dvr/recorder/DvrRecordingService.java b/src/com/android/tv/dvr/recorder/DvrRecordingService.java
index 9fdbf062..3b21bab2 100644
--- a/src/com/android/tv/dvr/recorder/DvrRecordingService.java
+++ b/src/com/android/tv/dvr/recorder/DvrRecordingService.java
@@ -29,15 +29,15 @@ import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
+import com.android.tv.ApplicationSingletons;
import com.android.tv.InputSessionManager;
import com.android.tv.InputSessionManager.OnRecordingSessionChangeListener;
import com.android.tv.R;
-import com.android.tv.Starter;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.feature.CommonFeatures;
-import com.android.tv.common.util.Clock;
import com.android.tv.dvr.WritableDvrDataManager;
+import com.android.tv.util.Clock;
import com.android.tv.util.RecurringRunner;
/**
@@ -114,12 +114,12 @@ public class DvrRecordingService extends Service {
@Override
public void onCreate() {
- Starter.start(this);
+ TvApplication.setCurrentRunningProcess(this, true);
if (DEBUG) Log.d(TAG, "onCreate");
super.onCreate();
SoftPreconditions.checkFeatureEnabled(this, CommonFeatures.DVR, TAG);
sInstance = this;
- TvSingletons singletons = TvSingletons.getSingletons(this);
+ ApplicationSingletons singletons = TvApplication.getSingletons(this);
WritableDvrDataManager dataManager =
(WritableDvrDataManager) singletons.getDvrDataManager();
mSessionManager = singletons.getInputSessionManager();
@@ -183,6 +183,7 @@ public class DvrRecordingService extends Service {
@VisibleForTesting
protected void startForegroundInternal(boolean hasUpcomingRecording) {
+ // STOPSHIP: Replace the content title with real UX strings
Notification.Builder builder =
new Notification.Builder(this)
.setContentTitle(mContentTitle)
@@ -203,6 +204,7 @@ public class DvrRecordingService extends Service {
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ // STOPSHIP: Replace the channel name with real UX strings
mNotificationChannel =
new NotificationChannel(
DVR_NOTIFICATION_CHANNEL_ID,
diff --git a/src/com/android/tv/dvr/recorder/DvrStartRecordingReceiver.java b/src/com/android/tv/dvr/recorder/DvrStartRecordingReceiver.java
index bb5ea99d..f7521d6a 100644
--- a/src/com/android/tv/dvr/recorder/DvrStartRecordingReceiver.java
+++ b/src/com/android/tv/dvr/recorder/DvrStartRecordingReceiver.java
@@ -21,16 +21,15 @@ import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.support.annotation.RequiresApi;
-import com.android.tv.Starter;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
/** Signals the DVR to start recording shows <i>soon</i>. */
@RequiresApi(Build.VERSION_CODES.N)
public class DvrStartRecordingReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- Starter.start(context);
- RecordingScheduler scheduler = TvSingletons.getSingletons(context).getRecordingScheduler();
+ TvApplication.setCurrentRunningProcess(context, true);
+ RecordingScheduler scheduler = TvApplication.getSingletons(context).getRecordingScheduler();
if (scheduler != null) {
scheduler.updateAndStartServiceIfNeeded();
}
diff --git a/src/com/android/tv/dvr/recorder/InputTaskScheduler.java b/src/com/android/tv/dvr/recorder/InputTaskScheduler.java
index 722e75fc..ff46c7c3 100644
--- a/src/com/android/tv/dvr/recorder/InputTaskScheduler.java
+++ b/src/com/android/tv/dvr/recorder/InputTaskScheduler.java
@@ -26,13 +26,13 @@ import android.util.ArrayMap;
import android.util.Log;
import android.util.LongSparseArray;
import com.android.tv.InputSessionManager;
-import com.android.tv.common.util.Clock;
import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.DvrManager;
import com.android.tv.dvr.WritableDvrDataManager;
import com.android.tv.dvr.data.ScheduledRecording;
+import com.android.tv.util.Clock;
import com.android.tv.util.CompositeComparator;
import java.util.ArrayList;
import java.util.Collections;
@@ -443,7 +443,6 @@ public class InputTaskScheduler {
break;
case MSG_UPDATE_SCHEDULED_RECORDING:
handleUpdateSchedule((ScheduledRecording) msg.obj);
- break;
case MSG_BUILD_SCHEDULE:
handleBuildSchedule();
break;
diff --git a/src/com/android/tv/dvr/recorder/RecordingScheduler.java b/src/com/android/tv/dvr/recorder/RecordingScheduler.java
index d631d84f..ea54f8c3 100644
--- a/src/com/android/tv/dvr/recorder/RecordingScheduler.java
+++ b/src/com/android/tv/dvr/recorder/RecordingScheduler.java
@@ -31,10 +31,10 @@ import android.support.annotation.VisibleForTesting;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Range;
+import com.android.tv.ApplicationSingletons;
import com.android.tv.InputSessionManager;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.common.util.Clock;
import com.android.tv.data.ChannelDataManager;
import com.android.tv.data.ChannelDataManager.Listener;
import com.android.tv.dvr.DvrDataManager;
@@ -43,6 +43,7 @@ import com.android.tv.dvr.DvrDataManager.ScheduledRecordingListener;
import com.android.tv.dvr.DvrManager;
import com.android.tv.dvr.WritableDvrDataManager;
import com.android.tv.dvr.data.ScheduledRecording;
+import com.android.tv.util.Clock;
import com.android.tv.util.TvInputManagerHelper;
import com.android.tv.util.Utils;
import java.util.Arrays;
@@ -119,10 +120,10 @@ public class RecordingScheduler extends TvInputCallback implements ScheduledReco
*/
public static RecordingScheduler createScheduler(Context context) {
SoftPreconditions.checkState(
- TvSingletons.getSingletons(context).getRecordingScheduler() == null);
+ TvApplication.getSingletons(context).getRecordingScheduler() == null);
HandlerThread handlerThread = new HandlerThread(HANDLER_THREAD_NAME);
handlerThread.start();
- TvSingletons singletons = TvSingletons.getSingletons(context);
+ ApplicationSingletons singletons = TvApplication.getSingletons(context);
return new RecordingScheduler(
handlerThread.getLooper(),
singletons.getDvrManager(),
diff --git a/src/com/android/tv/dvr/recorder/RecordingTask.java b/src/com/android/tv/dvr/recorder/RecordingTask.java
index 4bd73e8a..85c6a0d5 100644
--- a/src/com/android/tv/dvr/recorder/RecordingTask.java
+++ b/src/com/android/tv/dvr/recorder/RecordingTask.java
@@ -33,15 +33,14 @@ import android.widget.Toast;
import com.android.tv.InputSessionManager;
import com.android.tv.InputSessionManager.RecordingSession;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.common.util.Clock;
-import com.android.tv.common.util.CommonUtils;
import com.android.tv.data.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.HandlerWrapper;
+import com.android.tv.util.Clock;
import com.android.tv.util.Utils;
import java.util.Comparator;
import java.util.concurrent.TimeUnit;
@@ -179,7 +178,7 @@ public class RecordingTask extends RecordingCallback
release();
return false;
default:
- SoftPreconditions.checkArgument(false, TAG, "unexpected message type %s", msg);
+ SoftPreconditions.checkArgument(false, TAG, "unexpected message type " + msg);
break;
}
return true;
@@ -254,7 +253,7 @@ public class RecordingTask extends RecordingCallback
new Runnable() {
@Override
public void run() {
- if (TvSingletons.getSingletons(mContext)
+ if (TvApplication.getSingletons(mContext)
.getMainActivityWrapper()
.isResumed()) {
ScheduledRecording scheduledRecording =
@@ -282,7 +281,7 @@ public class RecordingTask extends RecordingCallback
}
}
});
- // fall through
+ // Pass through
default:
failAndQuit();
break;
@@ -427,7 +426,7 @@ public class RecordingTask extends RecordingCallback
+ " with a delay of "
+ delay / 1000
+ " seconds to arrive at "
- + CommonUtils.toIsoDateTimeString(when));
+ + Utils.toIsoDateTimeString(when));
}
return mHandler.sendEmptyMessageDelayed(what, delay);
}
diff --git a/src/com/android/tv/dvr/recorder/ScheduledProgramReaper.java b/src/com/android/tv/dvr/recorder/ScheduledProgramReaper.java
index f30308f3..c59d4a93 100644
--- a/src/com/android/tv/dvr/recorder/ScheduledProgramReaper.java
+++ b/src/com/android/tv/dvr/recorder/ScheduledProgramReaper.java
@@ -18,10 +18,10 @@ package com.android.tv.dvr.recorder;
import android.support.annotation.MainThread;
import android.support.annotation.VisibleForTesting;
-import com.android.tv.common.util.Clock;
import com.android.tv.dvr.WritableDvrDataManager;
import com.android.tv.dvr.data.ScheduledRecording;
import com.android.tv.dvr.data.SeriesRecording;
+import com.android.tv.util.Clock;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
diff --git a/src/com/android/tv/dvr/recorder/SeriesRecordingScheduler.java b/src/com/android/tv/dvr/recorder/SeriesRecordingScheduler.java
index 4f7a789b..05f876ad 100644
--- a/src/com/android/tv/dvr/recorder/SeriesRecordingScheduler.java
+++ b/src/com/android/tv/dvr/recorder/SeriesRecordingScheduler.java
@@ -27,13 +27,13 @@ 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.ApplicationSingletons;
+import com.android.tv.TvApplication;
+import com.android.tv.common.CollectionUtils;
+import com.android.tv.common.SharedPreferencesUtils;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.common.experiments.Experiments;
-import com.android.tv.common.util.CollectionUtils;
-import com.android.tv.common.util.SharedPreferencesUtils;
import com.android.tv.data.Program;
-import com.android.tv.data.epg.EpgReader;
+import com.android.tv.data.epg.EpgFetcher;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.DvrDataManager.ScheduledRecordingListener;
import com.android.tv.dvr.DvrDataManager.SeriesRecordingListener;
@@ -44,6 +44,8 @@ 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 com.android.tv.experiments.Experiments;
+import com.android.tv.util.LocationUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -56,7 +58,6 @@ 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
@@ -207,9 +208,9 @@ public class SeriesRecordingScheduler {
private SeriesRecordingScheduler(Context context) {
mContext = context.getApplicationContext();
- TvSingletons tvSingletons = TvSingletons.getSingletons(context);
- mDvrManager = tvSingletons.getDvrManager();
- mDataManager = (WritableDvrDataManager) tvSingletons.getDvrDataManager();
+ ApplicationSingletons appSingletons = TvApplication.getSingletons(context);
+ mDvrManager = appSingletons.getDvrManager();
+ mDataManager = (WritableDvrDataManager) appSingletons.getDvrDataManager();
mSharedPreferences =
context.getSharedPreferences(
SharedPreferencesUtils.SHARED_PREF_SERIES_RECORDINGS, Context.MODE_PRIVATE);
@@ -262,10 +263,7 @@ public class SeriesRecordingScheduler {
private void executeFetchSeriesInfoTask(SeriesRecording seriesRecording) {
if (Experiments.CLOUD_EPG.get()) {
- FetchSeriesInfoTask task =
- new FetchSeriesInfoTask(
- seriesRecording,
- TvSingletons.getSingletons(mContext).providesEpgReader());
+ FetchSeriesInfoTask task = new FetchSeriesInfoTask(seriesRecording);
task.execute();
mFetchSeriesInfoTasks.put(seriesRecording.getId(), task);
}
@@ -536,18 +534,16 @@ public class SeriesRecordingScheduler {
}
private class FetchSeriesInfoTask extends AsyncTask<Void, Void, SeriesInfo> {
- private final SeriesRecording mSeriesRecording;
- private final Provider<EpgReader> mEpgReaderProvider;
+ private SeriesRecording mSeriesRecording;
- FetchSeriesInfoTask(
- SeriesRecording seriesRecording, Provider<EpgReader> epgReaderProvider) {
+ FetchSeriesInfoTask(SeriesRecording seriesRecording) {
mSeriesRecording = seriesRecording;
- mEpgReaderProvider = epgReaderProvider;
}
@Override
protected SeriesInfo doInBackground(Void... voids) {
- return mEpgReaderProvider.get().getSeriesInfo(mSeriesRecording.getSeriesId());
+ return EpgFetcher.createEpgReader(mContext, LocationUtils.getCurrentCountry(mContext))
+ .getSeriesInfo(mSeriesRecording.getSeriesId());
}
@Override
diff --git a/src/com/android/tv/dvr/ui/DvrAlreadyRecordedFragment.java b/src/com/android/tv/dvr/ui/DvrAlreadyRecordedFragment.java
index fce94230..f4077e44 100644
--- a/src/com/android/tv/dvr/ui/DvrAlreadyRecordedFragment.java
+++ b/src/com/android/tv/dvr/ui/DvrAlreadyRecordedFragment.java
@@ -25,7 +25,7 @@ import android.support.annotation.NonNull;
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.TvApplication;
import com.android.tv.data.Program;
import com.android.tv.dvr.DvrManager;
import com.android.tv.dvr.data.RecordedProgram;
@@ -49,7 +49,7 @@ public class DvrAlreadyRecordedFragment extends DvrGuidedStepFragment {
public void onAttach(Context context) {
super.onAttach(context);
mProgram = getArguments().getParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM);
- DvrManager dvrManager = TvSingletons.getSingletons(context).getDvrManager();
+ DvrManager dvrManager = TvApplication.getSingletons(context).getDvrManager();
mDuplicate =
dvrManager.getRecordedProgram(
mProgram.getTitle(),
diff --git a/src/com/android/tv/dvr/ui/DvrAlreadyScheduledFragment.java b/src/com/android/tv/dvr/ui/DvrAlreadyScheduledFragment.java
index 456ad830..f27ec5c5 100644
--- a/src/com/android/tv/dvr/ui/DvrAlreadyScheduledFragment.java
+++ b/src/com/android/tv/dvr/ui/DvrAlreadyScheduledFragment.java
@@ -26,7 +26,7 @@ import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
import android.support.v17.leanback.widget.GuidedAction;
import android.text.format.DateUtils;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.data.Program;
import com.android.tv.dvr.DvrManager;
import com.android.tv.dvr.data.ScheduledRecording;
@@ -50,7 +50,7 @@ public class DvrAlreadyScheduledFragment extends DvrGuidedStepFragment {
public void onAttach(Context context) {
super.onAttach(context);
mProgram = getArguments().getParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM);
- DvrManager dvrManager = TvSingletons.getSingletons(context).getDvrManager();
+ DvrManager dvrManager = TvApplication.getSingletons(context).getDvrManager();
mDuplicate =
dvrManager.getScheduledRecording(
mProgram.getTitle(),
diff --git a/src/com/android/tv/dvr/ui/DvrChannelRecordDurationOptionFragment.java b/src/com/android/tv/dvr/ui/DvrChannelRecordDurationOptionFragment.java
index 24a6fcd3..e247b82b 100644
--- a/src/com/android/tv/dvr/ui/DvrChannelRecordDurationOptionFragment.java
+++ b/src/com/android/tv/dvr/ui/DvrChannelRecordDurationOptionFragment.java
@@ -22,7 +22,7 @@ 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.TvApplication;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.data.Channel;
import com.android.tv.dvr.DvrManager;
@@ -42,7 +42,7 @@ public class DvrChannelRecordDurationOptionFragment extends DvrGuidedStepFragmen
if (args != null) {
long channelId = args.getLong(DvrHalfSizedDialogFragment.KEY_CHANNEL_ID);
mChannel =
- TvSingletons.getSingletons(getContext())
+ TvApplication.getSingletons(getContext())
.getChannelDataManager()
.getChannel(channelId);
}
@@ -90,7 +90,7 @@ public class DvrChannelRecordDurationOptionFragment extends DvrGuidedStepFragmen
@Override
public void onTrackedGuidedActionClicked(GuidedAction action) {
- DvrManager dvrManager = TvSingletons.getSingletons(getContext()).getDvrManager();
+ DvrManager dvrManager = TvApplication.getSingletons(getContext()).getDvrManager();
long duration = mDurations.get((int) action.getId());
long startTimeMs = System.currentTimeMillis();
long endTimeMs = System.currentTimeMillis() + duration;
diff --git a/src/com/android/tv/dvr/ui/DvrConflictFragment.java b/src/com/android/tv/dvr/ui/DvrConflictFragment.java
index 641f86c1..80011acd 100644
--- a/src/com/android/tv/dvr/ui/DvrConflictFragment.java
+++ b/src/com/android/tv/dvr/ui/DvrConflictFragment.java
@@ -29,7 +29,7 @@ import android.view.View;
import android.view.ViewGroup;
import com.android.tv.MainActivity;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.data.Channel;
import com.android.tv.data.Program;
@@ -149,7 +149,7 @@ public abstract class DvrConflictFragment extends DvrGuidedStepFragment {
private String getScheduleTitle(ScheduledRecording schedule) {
if (schedule.getType() == ScheduledRecording.TYPE_TIMED) {
Channel channel =
- TvSingletons.getSingletons(getContext())
+ TvApplication.getSingletons(getContext())
.getChannelDataManager()
.getChannel(schedule.getChannelId());
if (channel != null) {
@@ -179,7 +179,7 @@ public abstract class DvrConflictFragment extends DvrGuidedStepFragment {
List<ScheduledRecording> conflicts = null;
if (input != null) {
conflicts =
- TvSingletons.getSingletons(getContext())
+ TvApplication.getSingletons(getContext())
.getDvrManager()
.getConflictingSchedules(mProgram);
}
@@ -227,7 +227,7 @@ public abstract class DvrConflictFragment extends DvrGuidedStepFragment {
Bundle args = getArguments();
long channelId = args.getLong(DvrHalfSizedDialogFragment.KEY_CHANNEL_ID);
mChannel =
- TvSingletons.getSingletons(getContext())
+ TvApplication.getSingletons(getContext())
.getChannelDataManager()
.getChannel(channelId);
SoftPreconditions.checkArgument(mChannel != null);
@@ -238,7 +238,7 @@ public abstract class DvrConflictFragment extends DvrGuidedStepFragment {
mStartTimeMs = args.getLong(DvrHalfSizedDialogFragment.KEY_START_TIME_MS);
mEndTimeMs = args.getLong(DvrHalfSizedDialogFragment.KEY_END_TIME_MS);
conflicts =
- TvSingletons.getSingletons(getContext())
+ TvApplication.getSingletons(getContext())
.getDvrManager()
.getConflictingSchedules(
mChannel.getId(), mStartTimeMs, mEndTimeMs);
diff --git a/src/com/android/tv/dvr/ui/DvrGuidedStepFragment.java b/src/com/android/tv/dvr/ui/DvrGuidedStepFragment.java
index 793bd01b..8524e1ea 100644
--- a/src/com/android/tv/dvr/ui/DvrGuidedStepFragment.java
+++ b/src/com/android/tv/dvr/ui/DvrGuidedStepFragment.java
@@ -26,13 +26,14 @@ import android.support.v17.leanback.widget.VerticalGridView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import com.android.tv.ApplicationSingletons;
import com.android.tv.MainActivity;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
-import com.android.tv.common.recording.RecordingStorageStatusManager;
+import com.android.tv.TvApplication;
import com.android.tv.dialog.HalfSizedDialogFragment.OnActionClickListener;
import com.android.tv.dialog.SafeDismissDialogFragment;
import com.android.tv.dvr.DvrManager;
+import com.android.tv.dvr.DvrStorageStatusManager;
import java.util.List;
public abstract class DvrGuidedStepFragment extends TrackedGuidedStepFragment {
@@ -55,7 +56,7 @@ public abstract class DvrGuidedStepFragment extends TrackedGuidedStepFragment {
@Override
public void onAttach(Context context) {
super.onAttach(context);
- TvSingletons singletons = TvSingletons.getSingletons(context);
+ ApplicationSingletons singletons = TvApplication.getSingletons(context);
mDvrManager = singletons.getDvrManager();
}
@@ -114,8 +115,8 @@ public abstract class DvrGuidedStepFragment extends TrackedGuidedStepFragment {
}
/**
- * The inner guided step fragment for {@link
- * com.android.tv.dvr.ui.DvrHalfSizedDialogFragment .DvrNoFreeSpaceErrorDialogFragment}.
+ * The inner guided step fragment for {@link com.android.tv.dvr.ui.DvrHalfSizedDialogFragment
+ * .DvrNoFreeSpaceErrorDialogFragment}.
*/
public static class DvrNoFreeSpaceErrorFragment extends DvrGuidedStepFragment {
@Override
@@ -154,8 +155,7 @@ public abstract class DvrGuidedStepFragment extends TrackedGuidedStepFragment {
}
/**
- * The inner guided step fragment for {@link
- * com.android.tv.dvr.ui.DvrHalfSizedDialogFragment
+ * The inner guided step fragment for {@link com.android.tv.dvr.ui.DvrHalfSizedDialogFragment
* .DvrSmallSizedStorageErrorDialogFragment}.
*/
public static class DvrSmallSizedStorageErrorFragment extends DvrGuidedStepFragment {
@@ -166,7 +166,7 @@ public abstract class DvrGuidedStepFragment extends TrackedGuidedStepFragment {
getResources()
.getString(
R.string.dvr_error_small_sized_storage_description,
- RecordingStorageStatusManager.MIN_STORAGE_SIZE_FOR_DVR_IN_BYTES
+ DvrStorageStatusManager.MIN_STORAGE_SIZE_FOR_DVR_IN_BYTES
/ 1024
/ 1024
/ 1024);
diff --git a/src/com/android/tv/dvr/ui/DvrInsufficientSpaceErrorFragment.java b/src/com/android/tv/dvr/ui/DvrInsufficientSpaceErrorFragment.java
index 6fba4d98..ad26a5c2 100644
--- a/src/com/android/tv/dvr/ui/DvrInsufficientSpaceErrorFragment.java
+++ b/src/com/android/tv/dvr/ui/DvrInsufficientSpaceErrorFragment.java
@@ -23,7 +23,7 @@ import android.os.Bundle;
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.TvApplication;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.dvr.ui.browse.DvrBrowseActivity;
import java.util.ArrayList;
@@ -102,7 +102,7 @@ public class DvrInsufficientSpaceErrorFragment extends DvrGuidedStepFragment {
Activity activity = getActivity();
actions.add(
new GuidedAction.Builder(activity).clickAction(GuidedAction.ACTION_ID_OK).build());
- if (TvSingletons.getSingletons(getContext()).getDvrManager().hasValidItems()) {
+ if (TvApplication.getSingletons(getContext()).getDvrManager().hasValidItems()) {
actions.add(
new GuidedAction.Builder(activity)
.id(ACTION_VIEW_RECENT_RECORDINGS)
diff --git a/src/com/android/tv/dvr/ui/DvrPrioritySettingsFragment.java b/src/com/android/tv/dvr/ui/DvrPrioritySettingsFragment.java
index 5bb97e90..03124260 100644
--- a/src/com/android/tv/dvr/ui/DvrPrioritySettingsFragment.java
+++ b/src/com/android/tv/dvr/ui/DvrPrioritySettingsFragment.java
@@ -16,11 +16,9 @@
package com.android.tv.dvr.ui;
-import android.annotation.TargetApi;
import android.app.FragmentManager;
import android.content.Context;
import android.graphics.Typeface;
-import android.os.Build;
import android.os.Bundle;
import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
import android.support.v17.leanback.widget.GuidedAction;
@@ -29,7 +27,7 @@ import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.DvrManager;
import com.android.tv.dvr.DvrScheduleManager;
@@ -38,8 +36,6 @@ import java.util.ArrayList;
import java.util.List;
/** Fragment for DVR series recording settings. */
-@TargetApi(Build.VERSION_CODES.N)
-@SuppressWarnings("AndroidApiChecker") // TODO(b/32513850) remove when error prone is updated
public class DvrPrioritySettingsFragment extends TrackedGuidedStepFragment {
/** Name of series recording id starting the fragment. Type: Long */
public static final String COME_FROM_SERIES_RECORDING_ID = "series_recording_id";
@@ -66,7 +62,7 @@ public class DvrPrioritySettingsFragment extends TrackedGuidedStepFragment {
.setPriority(Long.MAX_VALUE)
.setId(ONE_TIME_RECORDING_ID)
.build());
- DvrDataManager dvrDataManager = TvSingletons.getSingletons(context).getDvrDataManager();
+ DvrDataManager dvrDataManager = TvApplication.getSingletons(context).getDvrDataManager();
long comeFromSeriesRecordingId = getArguments().getLong(COME_FROM_SERIES_RECORDING_ID, -1);
for (SeriesRecording series : dvrDataManager.getSeriesRecordings()) {
if (series.getState() == SeriesRecording.STATE_SERIES_NORMAL
@@ -131,7 +127,7 @@ public class DvrPrioritySettingsFragment extends TrackedGuidedStepFragment {
public void onTrackedGuidedActionClicked(GuidedAction action) {
long actionId = action.getId();
if (actionId == ACTION_ID_SAVE) {
- DvrManager dvrManager = TvSingletons.getSingletons(getContext()).getDvrManager();
+ DvrManager dvrManager = TvApplication.getSingletons(getContext()).getDvrManager();
int size = mSeriesRecordings.size();
for (int i = 1; i < size; ++i) {
long priority = DvrScheduleManager.suggestSeriesPriority(size - i);
diff --git a/src/com/android/tv/dvr/ui/DvrScheduleFragment.java b/src/com/android/tv/dvr/ui/DvrScheduleFragment.java
index 5251e140..854fea56 100644
--- a/src/com/android/tv/dvr/ui/DvrScheduleFragment.java
+++ b/src/com/android/tv/dvr/ui/DvrScheduleFragment.java
@@ -27,7 +27,7 @@ import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
import android.support.v17.leanback.widget.GuidedAction;
import android.text.format.DateUtils;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.data.Program;
import com.android.tv.dvr.DvrManager;
@@ -63,18 +63,16 @@ public class DvrScheduleFragment extends DvrGuidedStepFragment {
mProgram = args.getParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM);
mAddCurrentProgramToSeries = args.getBoolean(KEY_ADD_CURRENT_PROGRAM_TO_SERIES, false);
}
- DvrManager dvrManager = TvSingletons.getSingletons(getContext()).getDvrManager();
+ DvrManager dvrManager = TvApplication.getSingletons(getContext()).getDvrManager();
SoftPreconditions.checkArgument(
mProgram != null && mProgram.isEpisodic(),
TAG,
- "The program should be episodic: %s ",
- mProgram);
+ "The program should be episodic: " + mProgram);
SeriesRecording seriesRecording = dvrManager.getSeriesRecording(mProgram);
SoftPreconditions.checkArgument(
seriesRecording == null || seriesRecording.isStopped(),
TAG,
- "The series recording should be stopped or null: %s",
- seriesRecording);
+ "The series recording should be stopped or null: " + seriesRecording);
super.onCreate(savedInstanceState);
}
@@ -146,7 +144,7 @@ public class DvrScheduleFragment extends DvrGuidedStepFragment {
}
} else if (action.getId() == ACTION_RECORD_SERIES) {
SeriesRecording seriesRecording =
- TvSingletons.getSingletons(getContext())
+ TvApplication.getSingletons(getContext())
.getDvrDataManager()
.getSeriesRecording(mProgram.getSeriesId());
if (seriesRecording == null) {
@@ -161,7 +159,7 @@ public class DvrScheduleFragment extends DvrGuidedStepFragment {
seriesRecording =
SeriesRecording.buildFrom(seriesRecording)
.setPriority(
- TvSingletons.getSingletons(getContext())
+ TvApplication.getSingletons(getContext())
.getDvrScheduleManager()
.suggestNewSeriesPriority())
.build();
diff --git a/src/com/android/tv/dvr/ui/DvrSeriesDeletionActivity.java b/src/com/android/tv/dvr/ui/DvrSeriesDeletionActivity.java
index a2ae1f97..8b05cf1c 100644
--- a/src/com/android/tv/dvr/ui/DvrSeriesDeletionActivity.java
+++ b/src/com/android/tv/dvr/ui/DvrSeriesDeletionActivity.java
@@ -20,7 +20,7 @@ import android.app.Activity;
import android.os.Bundle;
import android.support.v17.leanback.app.GuidedStepFragment;
import com.android.tv.R;
-import com.android.tv.Starter;
+import com.android.tv.TvApplication;
/** Activity to show details view in DVR. */
public class DvrSeriesDeletionActivity extends Activity {
@@ -29,7 +29,7 @@ public class DvrSeriesDeletionActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
- Starter.start(this);
+ TvApplication.setCurrentRunningProcess(this, true);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dvr_series_settings);
// Check savedInstanceState to prevent that activity is being showed with animation.
diff --git a/src/com/android/tv/dvr/ui/DvrSeriesDeletionFragment.java b/src/com/android/tv/dvr/ui/DvrSeriesDeletionFragment.java
index 685f0a58..5f2c3582 100644
--- a/src/com/android/tv/dvr/ui/DvrSeriesDeletionFragment.java
+++ b/src/com/android/tv/dvr/ui/DvrSeriesDeletionFragment.java
@@ -27,7 +27,7 @@ import android.text.TextUtils;
import android.view.ViewGroup.LayoutParams;
import android.widget.Toast;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.DvrManager;
@@ -67,9 +67,9 @@ public class DvrSeriesDeletionFragment extends GuidedStepFragment {
mSeriesRecordingId =
getArguments().getLong(DvrSeriesDeletionActivity.SERIES_RECORDING_ID, -1);
SoftPreconditions.checkArgument(mSeriesRecordingId != -1);
- mDvrDataManager = TvSingletons.getSingletons(context).getDvrDataManager();
+ mDvrDataManager = TvApplication.getSingletons(context).getDvrDataManager();
mDvrWatchedPositionManager =
- TvSingletons.getSingletons(context).getDvrWatchedPositionManager();
+ TvApplication.getSingletons(context).getDvrWatchedPositionManager();
mRecordings = mDvrDataManager.getRecordedPrograms(mSeriesRecordingId);
mOneLineActionHeight =
getResources()
@@ -166,7 +166,7 @@ public class DvrSeriesDeletionFragment extends GuidedStepFragment {
}
}
if (!idsToDelete.isEmpty()) {
- DvrManager dvrManager = TvSingletons.getSingletons(getActivity()).getDvrManager();
+ DvrManager dvrManager = TvApplication.getSingletons(getActivity()).getDvrManager();
dvrManager.removeRecordedPrograms(idsToDelete);
}
Toast.makeText(
diff --git a/src/com/android/tv/dvr/ui/DvrSeriesScheduledFragment.java b/src/com/android/tv/dvr/ui/DvrSeriesScheduledFragment.java
index edb62c96..d600b54d 100644
--- a/src/com/android/tv/dvr/ui/DvrSeriesScheduledFragment.java
+++ b/src/com/android/tv/dvr/ui/DvrSeriesScheduledFragment.java
@@ -23,7 +23,7 @@ import android.os.Bundle;
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.TvApplication;
import com.android.tv.data.Program;
import com.android.tv.dvr.DvrScheduleManager;
import com.android.tv.dvr.data.ScheduledRecording;
@@ -68,7 +68,7 @@ public class DvrSeriesScheduledFragment extends DvrGuidedStepFragment {
getArguments()
.getBoolean(DvrSeriesScheduledDialogActivity.SHOW_VIEW_SCHEDULE_OPTION);
mSeriesRecording =
- TvSingletons.getSingletons(context)
+ TvApplication.getSingletons(context)
.getDvrDataManager()
.getSeriesRecording(seriesRecordingId);
if (mSeriesRecording == null) {
@@ -78,12 +78,12 @@ public class DvrSeriesScheduledFragment extends DvrGuidedStepFragment {
mPrograms = (List<Program>) BigArguments.getArgument(SERIES_SCHEDULED_KEY_PROGRAMS);
BigArguments.reset();
mSchedulesAddedCount =
- TvSingletons.getSingletons(getContext())
+ TvApplication.getSingletons(getContext())
.getDvrManager()
.getAvailableScheduledRecording(mSeriesRecording.getId())
.size();
DvrScheduleManager dvrScheduleManager =
- TvSingletons.getSingletons(context).getDvrScheduleManager();
+ TvApplication.getSingletons(context).getDvrScheduleManager();
List<ScheduledRecording> conflictingRecordings =
dvrScheduleManager.getConflictingSchedules(mSeriesRecording);
mHasConflict = !conflictingRecordings.isEmpty();
diff --git a/src/com/android/tv/dvr/ui/DvrSeriesSettingsActivity.java b/src/com/android/tv/dvr/ui/DvrSeriesSettingsActivity.java
index 1a51cf46..117f72d8 100644
--- a/src/com/android/tv/dvr/ui/DvrSeriesSettingsActivity.java
+++ b/src/com/android/tv/dvr/ui/DvrSeriesSettingsActivity.java
@@ -21,7 +21,7 @@ import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.support.v17.leanback.app.GuidedStepFragment;
import com.android.tv.R;
-import com.android.tv.Starter;
+import com.android.tv.TvApplication;
import com.android.tv.common.SoftPreconditions;
/** Activity to show details view in DVR. */
@@ -60,7 +60,7 @@ public class DvrSeriesSettingsActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
- Starter.start(this);
+ TvApplication.setCurrentRunningProcess(this, true);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dvr_series_settings);
long seriesRecordingId = getIntent().getLongExtra(SERIES_RECORDING_ID, -1);
diff --git a/src/com/android/tv/dvr/ui/DvrSeriesSettingsFragment.java b/src/com/android/tv/dvr/ui/DvrSeriesSettingsFragment.java
index 9383058a..c44e44a3 100644
--- a/src/com/android/tv/dvr/ui/DvrSeriesSettingsFragment.java
+++ b/src/com/android/tv/dvr/ui/DvrSeriesSettingsFragment.java
@@ -16,10 +16,8 @@
package com.android.tv.dvr.ui;
-import android.annotation.TargetApi;
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;
@@ -27,7 +25,7 @@ import android.support.v17.leanback.widget.GuidedAction;
import android.support.v17.leanback.widget.GuidedActionsStylist;
import android.util.LongSparseArray;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
import com.android.tv.data.Program;
@@ -45,8 +43,6 @@ import java.util.List;
import java.util.Set;
/** Fragment for DVR series recording settings. */
-@TargetApi(Build.VERSION_CODES.N)
-@SuppressWarnings("AndroidApiChecker") // TODO(b/32513850) remove when error prone is updated
public class DvrSeriesSettingsFragment extends GuidedStepFragment
implements DvrDataManager.SeriesRecordingListener {
private static final String TAG = "SeriesSettingsFragment";
@@ -85,7 +81,7 @@ public class DvrSeriesSettingsFragment extends GuidedStepFragment
public void onAttach(Context context) {
super.onAttach(context);
mBackStackCount = getFragmentManager().getBackStackEntryCount();
- mDvrDataManager = TvSingletons.getSingletons(context).getDvrDataManager();
+ mDvrDataManager = TvApplication.getSingletons(context).getDvrDataManager();
mSeriesRecordingId = getArguments().getLong(DvrSeriesSettingsActivity.SERIES_RECORDING_ID);
mSeriesRecording = mDvrDataManager.getSeriesRecording(mSeriesRecordingId);
if (mSeriesRecording == null) {
@@ -106,7 +102,7 @@ public class DvrSeriesSettingsFragment extends GuidedStepFragment
}
Set<Long> channelIds = new HashSet<>();
ChannelDataManager channelDataManager =
- TvSingletons.getSingletons(context).getChannelDataManager();
+ TvApplication.getSingletons(context).getChannelDataManager();
for (Program program : mPrograms) {
long channelId = program.getChannelId();
if (channelIds.add(channelId)) {
@@ -212,7 +208,7 @@ public class DvrSeriesSettingsFragment extends GuidedStepFragment
if (mSelectedChannelId != Channel.INVALID_ID) {
builder.setChannelId(mSelectedChannelId);
}
- DvrManager dvrManager = TvSingletons.getSingletons(getContext()).getDvrManager();
+ DvrManager dvrManager = TvApplication.getSingletons(getContext()).getDvrManager();
dvrManager.updateSeriesRecording(builder.build());
if (mCurrentProgram != null
&& (mChannelOption == SeriesRecording.OPTION_CHANNEL_ALL
@@ -332,7 +328,7 @@ public class DvrSeriesSettingsFragment extends GuidedStepFragment
recordingCandidates)
.get(mSeriesRecordingId);
if (!programsToSchedule.isEmpty()) {
- TvSingletons.getSingletons(getContext())
+ TvApplication.getSingletons(getContext())
.getDvrManager()
.addScheduleToSeriesRecording(mSeriesRecording, programsToSchedule);
}
diff --git a/src/com/android/tv/dvr/ui/DvrStopRecordingFragment.java b/src/com/android/tv/dvr/ui/DvrStopRecordingFragment.java
index e93387ab..6f34e8a0 100644
--- a/src/com/android/tv/dvr/ui/DvrStopRecordingFragment.java
+++ b/src/com/android/tv/dvr/ui/DvrStopRecordingFragment.java
@@ -26,7 +26,7 @@ import android.support.annotation.NonNull;
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.TvApplication;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.DvrDataManager.ScheduledRecordingListener;
import com.android.tv.dvr.data.ScheduledRecording;
@@ -100,7 +100,7 @@ public class DvrStopRecordingFragment extends DvrGuidedStepFragment {
dismissDialog();
return;
}
- mDvrDataManager = TvSingletons.getSingletons(context).getDvrDataManager();
+ mDvrDataManager = TvApplication.getSingletons(context).getDvrDataManager();
mDvrDataManager.addScheduledRecordingListener(mScheduledRecordingListener);
mStopReason = args.getInt(KEY_REASON);
}
diff --git a/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingFragment.java b/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingFragment.java
index 99211fdb..3d84f48f 100644
--- a/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingFragment.java
+++ b/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingFragment.java
@@ -25,8 +25,9 @@ import android.support.v17.leanback.widget.GuidedAction;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import com.android.tv.ApplicationSingletons;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.DvrManager;
import com.android.tv.dvr.data.ScheduledRecording;
@@ -76,7 +77,7 @@ public class DvrStopSeriesRecordingFragment extends DvrGuidedStepFragment {
@Override
public void onTrackedGuidedActionClicked(GuidedAction action) {
if (action.getId() == ACTION_STOP_SERIES_RECORDING) {
- TvSingletons singletons = TvSingletons.getSingletons(getContext());
+ ApplicationSingletons singletons = TvApplication.getSingletons(getContext());
DvrManager dvrManager = singletons.getDvrManager();
DvrDataManager dataManager = singletons.getDvrDataManager();
List<ScheduledRecording> toDelete = new ArrayList<>();
diff --git a/src/com/android/tv/dvr/ui/DvrUiHelper.java b/src/com/android/tv/dvr/ui/DvrUiHelper.java
index 6373b30f..ae60f4a4 100644
--- a/src/com/android/tv/dvr/ui/DvrUiHelper.java
+++ b/src/com/android/tv/dvr/ui/DvrUiHelper.java
@@ -39,15 +39,14 @@ import android.widget.ImageView;
import android.widget.Toast;
import com.android.tv.MainActivity;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
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.BaseProgram;
import com.android.tv.data.Channel;
import com.android.tv.data.Program;
import com.android.tv.dialog.HalfSizedDialogFragment;
import com.android.tv.dvr.DvrManager;
+import com.android.tv.dvr.DvrStorageStatusManager;
import com.android.tv.dvr.data.RecordedProgram;
import com.android.tv.dvr.data.ScheduledRecording;
import com.android.tv.dvr.data.SeriesRecording;
@@ -92,17 +91,17 @@ public class DvrUiHelper {
*/
public static void checkStorageStatusAndShowErrorMessage(
Activity activity, String inputId, Runnable recordingRequestRunnable) {
- if (CommonUtils.isBundledInput(inputId)) {
- switch (TvSingletons.getSingletons(activity)
- .getRecordingStorageStatusManager()
+ if (Utils.isBundledInput(inputId)) {
+ switch (TvApplication.getSingletons(activity)
+ .getDvrStorageStatusManager()
.getDvrStorageStatus()) {
- case RecordingStorageStatusManager.STORAGE_STATUS_TOTAL_CAPACITY_TOO_SMALL:
+ case DvrStorageStatusManager.STORAGE_STATUS_TOTAL_CAPACITY_TOO_SMALL:
showDvrSmallSizedStorageErrorDialog(activity);
return;
- case RecordingStorageStatusManager.STORAGE_STATUS_MISSING:
+ case DvrStorageStatusManager.STORAGE_STATUS_MISSING:
showDvrMissingStorageErrorDialog(activity);
return;
- case RecordingStorageStatusManager.STORAGE_STATUS_FREE_SPACE_INSUFFICIENT:
+ case DvrStorageStatusManager.STORAGE_STATUS_FREE_SPACE_INSUFFICIENT:
showDvrNoFreeSpaceErrorDialog(activity, recordingRequestRunnable);
return;
}
@@ -282,7 +281,7 @@ public class DvrUiHelper {
if (program == null) {
return false;
}
- DvrManager dvrManager = TvSingletons.getSingletons(activity).getDvrManager();
+ DvrManager dvrManager = TvApplication.getSingletons(activity).getDvrManager();
if (!program.isEpisodic()) {
// One time recording.
dvrManager.addSchedule(program);
@@ -393,7 +392,7 @@ public class DvrUiHelper {
return;
}
List<ScheduledRecording> conflicts =
- TvSingletons.getSingletons(context)
+ TvApplication.getSingletons(context)
.getDvrManager()
.getConflictingSchedulesForTune(channel.getId());
startSchedulesActivity(context, getEarliestScheduledRecording(conflicts));
@@ -444,7 +443,7 @@ public class DvrUiHelper {
boolean showViewScheduleOptionInDialog,
Program currentProgram) {
SeriesRecording series =
- TvSingletons.getSingletons(context)
+ TvApplication.getSingletons(context)
.getDvrDataManager()
.getSeriesRecording(seriesRecordingId);
if (series == null) {
diff --git a/src/com/android/tv/dvr/ui/TrackedGuidedStepFragment.java b/src/com/android/tv/dvr/ui/TrackedGuidedStepFragment.java
index 0172f76f..0a24187a 100644
--- a/src/com/android/tv/dvr/ui/TrackedGuidedStepFragment.java
+++ b/src/com/android/tv/dvr/ui/TrackedGuidedStepFragment.java
@@ -19,7 +19,7 @@ package com.android.tv.dvr.ui;
import android.content.Context;
import android.support.v17.leanback.app.GuidedStepFragment;
import android.support.v17.leanback.widget.GuidedAction;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.analytics.Tracker;
/** A {@link GuidedStepFragment} with {@link Tracker} for analytics. */
@@ -29,7 +29,7 @@ public abstract class TrackedGuidedStepFragment extends GuidedStepFragment {
@Override
public void onAttach(Context context) {
super.onAttach(context);
- mTracker = TvSingletons.getSingletons(context).getAnalytics().getDefaultTracker();
+ mTracker = TvApplication.getSingletons(context).getAnalytics().getDefaultTracker();
}
@Override
diff --git a/src/com/android/tv/dvr/ui/browse/CurrentRecordingDetailsFragment.java b/src/com/android/tv/dvr/ui/browse/CurrentRecordingDetailsFragment.java
index 7e7e1f75..22246e5a 100644
--- a/src/com/android/tv/dvr/ui/browse/CurrentRecordingDetailsFragment.java
+++ b/src/com/android/tv/dvr/ui/browse/CurrentRecordingDetailsFragment.java
@@ -22,7 +22,7 @@ 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.TvApplication;
import com.android.tv.dialog.HalfSizedDialogFragment;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.DvrManager;
@@ -66,7 +66,7 @@ public class CurrentRecordingDetailsFragment extends RecordingDetailsFragment {
@Override
public void onAttach(Context context) {
super.onAttach(context);
- mDvrDataManger = TvSingletons.getSingletons(context).getDvrDataManager();
+ mDvrDataManger = TvApplication.getSingletons(context).getDvrDataManager();
mDvrDataManger.addScheduledRecordingListener(mScheduledRecordingListener);
}
@@ -100,7 +100,7 @@ public class CurrentRecordingDetailsFragment extends RecordingDetailsFragment {
public void onActionClick(long actionId) {
if (actionId == DvrStopRecordingFragment.ACTION_STOP) {
DvrManager dvrManager =
- TvSingletons.getSingletons(getContext())
+ TvApplication.getSingletons(getContext())
.getDvrManager();
dvrManager.stopRecording(getRecording());
getActivity().finish();
diff --git a/src/com/android/tv/dvr/ui/browse/DetailsContent.java b/src/com/android/tv/dvr/ui/browse/DetailsContent.java
index 70903373..9f588aa3 100644
--- a/src/com/android/tv/dvr/ui/browse/DetailsContent.java
+++ b/src/com/android/tv/dvr/ui/browse/DetailsContent.java
@@ -21,7 +21,7 @@ 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.TvApplication;
import com.android.tv.data.Channel;
import com.android.tv.dvr.data.RecordedProgram;
import com.android.tv.dvr.data.ScheduledRecording;
@@ -76,7 +76,7 @@ class DetailsContent {
static DetailsContent createFromScheduledRecording(
Context context, ScheduledRecording scheduledRecording) {
Channel channel =
- TvSingletons.getSingletons(context)
+ TvApplication.getSingletons(context)
.getChannelDataManager()
.getChannel(scheduledRecording.getChannelId());
String description =
@@ -278,7 +278,7 @@ class DetailsContent {
/** Builds details content. */
public DetailsContent build(Context context) {
Channel channel =
- TvSingletons.getSingletons(context)
+ TvApplication.getSingletons(context)
.getChannelDataManager()
.getChannel(mChannelId);
if (mDetailsContent.mTitle == null) {
diff --git a/src/com/android/tv/dvr/ui/browse/DetailsViewBackgroundHelper.java b/src/com/android/tv/dvr/ui/browse/DetailsViewBackgroundHelper.java
index 849360b8..5a058454 100644
--- a/src/com/android/tv/dvr/ui/browse/DetailsViewBackgroundHelper.java
+++ b/src/com/android/tv/dvr/ui/browse/DetailsViewBackgroundHelper.java
@@ -57,7 +57,6 @@ class DetailsViewBackgroundHelper {
public DetailsViewBackgroundHelper(Activity activity) {
mBackgroundManager = BackgroundManager.getInstance(activity);
mBackgroundManager.attach(activity.getWindow());
- mBackgroundManager.setAutoReleaseOnStop(false);
}
/** Sets the given image to background. */
diff --git a/src/com/android/tv/dvr/ui/browse/DvrBrowseActivity.java b/src/com/android/tv/dvr/ui/browse/DvrBrowseActivity.java
index 6cc1c7a1..f208b5e8 100644
--- a/src/com/android/tv/dvr/ui/browse/DvrBrowseActivity.java
+++ b/src/com/android/tv/dvr/ui/browse/DvrBrowseActivity.java
@@ -21,7 +21,7 @@ import android.content.Intent;
import android.media.tv.TvInputManager;
import android.os.Bundle;
import com.android.tv.R;
-import com.android.tv.Starter;
+import com.android.tv.TvApplication;
/** {@link android.app.Activity} for DVR UI. */
public class DvrBrowseActivity extends Activity {
@@ -29,7 +29,7 @@ public class DvrBrowseActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
- Starter.start(this);
+ TvApplication.setCurrentRunningProcess(this, true);
super.onCreate(savedInstanceState);
setContentView(R.layout.dvr_main);
mFragment = (DvrBrowseFragment) getFragmentManager().findFragmentById(R.id.dvr_frame);
diff --git a/src/com/android/tv/dvr/ui/browse/DvrBrowseFragment.java b/src/com/android/tv/dvr/ui/browse/DvrBrowseFragment.java
index 90326a8b..f8a54ef0 100644
--- a/src/com/android/tv/dvr/ui/browse/DvrBrowseFragment.java
+++ b/src/com/android/tv/dvr/ui/browse/DvrBrowseFragment.java
@@ -16,9 +16,7 @@
package com.android.tv.dvr.ui.browse;
-import android.annotation.TargetApi;
import android.content.Context;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.v17.leanback.app.BrowseFragment;
@@ -31,8 +29,9 @@ import android.support.v17.leanback.widget.TitleViewAdapter;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalFocusChangeListener;
+import com.android.tv.ApplicationSingletons;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.data.GenreItems;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.DvrDataManager.OnDvrScheduleLoadFinishedListener;
@@ -52,8 +51,6 @@ import java.util.HashMap;
import java.util.List;
/** {@link BrowseFragment} for DVR functions. */
-@TargetApi(Build.VERSION_CODES.N)
-@SuppressWarnings("AndroidApiChecker") // TODO(b/32513850) remove when error prone is updated
public class DvrBrowseFragment extends BrowseFragment
implements RecordedProgramListener,
ScheduledRecordingListener,
@@ -171,7 +168,7 @@ public class DvrBrowseFragment extends BrowseFragment
if (DEBUG) Log.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
Context context = getContext();
- TvSingletons singletons = TvSingletons.getSingletons(context);
+ ApplicationSingletons singletons = TvApplication.getSingletons(context);
mDvrDataManager = singletons.getDvrDataManager();
mDvrScheudleManager = singletons.getDvrScheduleManager();
mPresenterSelector =
diff --git a/src/com/android/tv/dvr/ui/browse/DvrDetailsActivity.java b/src/com/android/tv/dvr/ui/browse/DvrDetailsActivity.java
index 2659c3f3..a953f1d2 100644
--- a/src/com/android/tv/dvr/ui/browse/DvrDetailsActivity.java
+++ b/src/com/android/tv/dvr/ui/browse/DvrDetailsActivity.java
@@ -23,7 +23,7 @@ import android.transition.Transition;
import android.transition.Transition.TransitionListener;
import android.view.View;
import com.android.tv.R;
-import com.android.tv.Starter;
+import com.android.tv.TvApplication;
import com.android.tv.dialog.PinDialogFragment;
/** Activity to show details view in DVR. */
@@ -59,7 +59,7 @@ public class DvrDetailsActivity extends Activity implements PinDialogFragment.On
@Override
public void onCreate(Bundle savedInstanceState) {
- Starter.start(this);
+ TvApplication.setCurrentRunningProcess(this, true);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dvr_details);
long recordId = getIntent().getLongExtra(RECORDING_ID, -1);
diff --git a/src/com/android/tv/dvr/ui/browse/DvrDetailsFragment.java b/src/com/android/tv/dvr/ui/browse/DvrDetailsFragment.java
index 209fc6e1..f03f3f58 100644
--- a/src/com/android/tv/dvr/ui/browse/DvrDetailsFragment.java
+++ b/src/com/android/tv/dvr/ui/browse/DvrDetailsFragment.java
@@ -37,9 +37,8 @@ import android.support.v17.leanback.widget.VerticalGridView;
import android.text.TextUtils;
import android.widget.Toast;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.common.util.CommonUtils;
import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
import com.android.tv.dialog.PinDialogFragment;
@@ -49,6 +48,7 @@ import com.android.tv.dvr.ui.DvrUiHelper;
import com.android.tv.parental.ParentalControlSettings;
import com.android.tv.util.ImageLoader;
import com.android.tv.util.ToastUtils;
+import com.android.tv.util.Utils;
import java.io.File;
abstract class DvrDetailsFragment extends DetailsFragment {
@@ -195,7 +195,7 @@ abstract class DvrDetailsFragment extends DetailsFragment {
}
protected void startPlayback(RecordedProgram recordedProgram, long seekTimeMs) {
- if (CommonUtils.isInBundledPackageSet(recordedProgram.getPackageName())
+ if (Utils.isInBundledPackageSet(recordedProgram.getPackageName())
&& !isDataUriAccessible(recordedProgram.getDataUri())) {
// Since cleaning RecordedProgram from forgotten storage will take some time,
// ignore playback until cleaning is finished.
@@ -207,7 +207,7 @@ abstract class DvrDetailsFragment extends DetailsFragment {
}
long programId = recordedProgram.getId();
ParentalControlSettings parental =
- TvSingletons.getSingletons(getActivity())
+ TvApplication.getSingletons(getActivity())
.getTvInputManagerHelper()
.getParentalControlSettings();
if (!parental.isParentalControlsEnabled()) {
@@ -215,7 +215,7 @@ abstract class DvrDetailsFragment extends DetailsFragment {
return;
}
ChannelDataManager channelDataManager =
- TvSingletons.getSingletons(getActivity()).getChannelDataManager();
+ TvApplication.getSingletons(getActivity()).getChannelDataManager();
Channel channel = channelDataManager.getChannel(recordedProgram.getChannelId());
if (channel != null && channel.isLocked()) {
checkPinToPlay(recordedProgram, seekTimeMs);
diff --git a/src/com/android/tv/dvr/ui/browse/DvrItemPresenter.java b/src/com/android/tv/dvr/ui/browse/DvrItemPresenter.java
index 1e5f6935..4298d86a 100644
--- a/src/com/android/tv/dvr/ui/browse/DvrItemPresenter.java
+++ b/src/com/android/tv/dvr/ui/browse/DvrItemPresenter.java
@@ -31,9 +31,8 @@ import java.util.Set;
/**
* An abstract class to present DVR items in {@link RecordingCardView}, which is mainly used in
* {@link DvrBrowseFragment}. DVR items might include: {@link
- * com.android.tv.dvr.data.ScheduledRecording}, {@link
- * com.android.tv.dvr.data.RecordedProgram}, and {@link
- * com.android.tv.dvr.data.SeriesRecording}.
+ * com.android.tv.dvr.data.ScheduledRecording}, {@link com.android.tv.dvr.data.RecordedProgram}, and
+ * {@link com.android.tv.dvr.data.SeriesRecording}.
*/
public abstract class DvrItemPresenter<T> extends Presenter {
protected final Context mContext;
diff --git a/src/com/android/tv/dvr/ui/browse/FullSchedulesCardPresenter.java b/src/com/android/tv/dvr/ui/browse/FullSchedulesCardPresenter.java
index af0f24c0..88133331 100644
--- a/src/com/android/tv/dvr/ui/browse/FullSchedulesCardPresenter.java
+++ b/src/com/android/tv/dvr/ui/browse/FullSchedulesCardPresenter.java
@@ -20,7 +20,7 @@ import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.View;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.dvr.data.ScheduledRecording;
import com.android.tv.dvr.ui.DvrUiHelper;
import com.android.tv.util.Utils;
@@ -50,7 +50,7 @@ class FullSchedulesCardPresenter extends DvrItemPresenter<Object> {
cardView.setTitle(mCardTitleText);
cardView.setImage(mIconDrawable);
List<ScheduledRecording> scheduledRecordings =
- TvSingletons.getSingletons(mContext)
+ TvApplication.getSingletons(mContext)
.getDvrDataManager()
.getAvailableScheduledRecordings();
int fullDays = 0;
diff --git a/src/com/android/tv/dvr/ui/browse/RecordedProgramDetailsFragment.java b/src/com/android/tv/dvr/ui/browse/RecordedProgramDetailsFragment.java
index 47b1a198..3b3401b2 100644
--- a/src/com/android/tv/dvr/ui/browse/RecordedProgramDetailsFragment.java
+++ b/src/com/android/tv/dvr/ui/browse/RecordedProgramDetailsFragment.java
@@ -23,7 +23,7 @@ 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.TvApplication;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.DvrManager;
import com.android.tv.dvr.DvrWatchedPositionManager;
@@ -44,7 +44,7 @@ public class RecordedProgramDetailsFragment extends DvrDetailsFragment
@Override
public void onCreate(Bundle savedInstanceState) {
- mDvrDataManager = TvSingletons.getSingletons(getContext()).getDvrDataManager();
+ mDvrDataManager = TvApplication.getSingletons(getContext()).getDvrDataManager();
mDvrDataManager.addRecordedProgramListener(this);
super.onCreate(savedInstanceState);
}
@@ -52,7 +52,7 @@ public class RecordedProgramDetailsFragment extends DvrDetailsFragment
@Override
public void onCreateInternal() {
mDvrWatchedPositionManager =
- TvSingletons.getSingletons(getActivity()).getDvrWatchedPositionManager();
+ TvApplication.getSingletons(getActivity()).getDvrWatchedPositionManager();
setDetailsOverviewRow(
DetailsContent.createFromRecordedProgram(getContext(), mRecordedProgram));
}
@@ -139,7 +139,7 @@ public class RecordedProgramDetailsFragment extends DvrDetailsFragment
mRecordedProgram.getId()));
} else if (action.getId() == ACTION_DELETE_RECORDING) {
DvrManager dvrManager =
- TvSingletons.getSingletons(getActivity()).getDvrManager();
+ TvApplication.getSingletons(getActivity()).getDvrManager();
dvrManager.removeRecordedProgram(mRecordedProgram);
getActivity().finish();
}
diff --git a/src/com/android/tv/dvr/ui/browse/RecordedProgramPresenter.java b/src/com/android/tv/dvr/ui/browse/RecordedProgramPresenter.java
index e2db3ac4..aad1cc6a 100644
--- a/src/com/android/tv/dvr/ui/browse/RecordedProgramPresenter.java
+++ b/src/com/android/tv/dvr/ui/browse/RecordedProgramPresenter.java
@@ -19,7 +19,7 @@ package com.android.tv.dvr.ui.browse;
import android.content.Context;
import android.media.tv.TvInputManager;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.dvr.DvrWatchedPositionManager;
import com.android.tv.dvr.DvrWatchedPositionManager.WatchedPositionChangedListener;
import com.android.tv.dvr.data.RecordedProgram;
@@ -95,7 +95,7 @@ public class RecordedProgramPresenter extends DvrItemPresenter<RecordedProgram>
mTodayString = mContext.getString(R.string.dvr_date_today);
mYesterdayString = mContext.getString(R.string.dvr_date_yesterday);
mDvrWatchedPositionManager =
- TvSingletons.getSingletons(mContext).getDvrWatchedPositionManager();
+ TvApplication.getSingletons(mContext).getDvrWatchedPositionManager();
mProgressBarColor =
mContext.getResources().getColor(R.color.play_controls_progress_bar_watched);
mShowEpisodeTitle = showEpisodeTitle;
diff --git a/src/com/android/tv/dvr/ui/browse/RecordingCardView.java b/src/com/android/tv/dvr/ui/browse/RecordingCardView.java
index 0a204c14..edee5d3a 100644
--- a/src/com/android/tv/dvr/ui/browse/RecordingCardView.java
+++ b/src/com/android/tv/dvr/ui/browse/RecordingCardView.java
@@ -37,8 +37,8 @@ import com.android.tv.ui.ViewUtils;
import com.android.tv.util.ImageLoader;
/**
- * A CardView for displaying info about a {@link com.android.tv.dvr.data.ScheduledRecording}
- * or {@link RecordedProgram} or {@link com.android.tv.dvr.data.SeriesRecording}.
+ * A CardView for displaying info about a {@link com.android.tv.dvr.data.ScheduledRecording} or
+ * {@link RecordedProgram} or {@link com.android.tv.dvr.data.SeriesRecording}.
*/
public class RecordingCardView extends BaseCardView {
// This value should be the same with
diff --git a/src/com/android/tv/dvr/ui/browse/RecordingDetailsFragment.java b/src/com/android/tv/dvr/ui/browse/RecordingDetailsFragment.java
index e4d95630..c8f1c785 100644
--- a/src/com/android/tv/dvr/ui/browse/RecordingDetailsFragment.java
+++ b/src/com/android/tv/dvr/ui/browse/RecordingDetailsFragment.java
@@ -18,7 +18,7 @@ package com.android.tv.dvr.ui.browse;
import android.os.Bundle;
import android.support.v17.leanback.app.DetailsFragment;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.dvr.data.ScheduledRecording;
/** {@link DetailsFragment} for recordings in DVR. */
@@ -35,7 +35,7 @@ abstract class RecordingDetailsFragment extends DvrDetailsFragment {
protected boolean onLoadRecordingDetails(Bundle args) {
long scheduledRecordingId = args.getLong(DvrDetailsActivity.RECORDING_ID);
mRecording =
- TvSingletons.getSingletons(getContext())
+ TvApplication.getSingletons(getContext())
.getDvrDataManager()
.getScheduledRecording(scheduledRecordingId);
return mRecording != null;
diff --git a/src/com/android/tv/dvr/ui/browse/ScheduledRecordingDetailsFragment.java b/src/com/android/tv/dvr/ui/browse/ScheduledRecordingDetailsFragment.java
index 0765117d..b3e6ebb3 100644
--- a/src/com/android/tv/dvr/ui/browse/ScheduledRecordingDetailsFragment.java
+++ b/src/com/android/tv/dvr/ui/browse/ScheduledRecordingDetailsFragment.java
@@ -22,7 +22,7 @@ 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.TvApplication;
import com.android.tv.dvr.DvrManager;
import com.android.tv.dvr.ui.DvrUiHelper;
@@ -37,7 +37,7 @@ public class ScheduledRecordingDetailsFragment extends RecordingDetailsFragment
@Override
public void onCreate(Bundle savedInstance) {
- mDvrManager = TvSingletons.getSingletons(getContext()).getDvrManager();
+ mDvrManager = TvApplication.getSingletons(getContext()).getDvrManager();
mHideViewSchedule = getArguments().getBoolean(DvrDetailsActivity.HIDE_VIEW_SCHEDULE);
super.onCreate(savedInstance);
}
diff --git a/src/com/android/tv/dvr/ui/browse/ScheduledRecordingPresenter.java b/src/com/android/tv/dvr/ui/browse/ScheduledRecordingPresenter.java
index f1ed52c8..fa948447 100644
--- a/src/com/android/tv/dvr/ui/browse/ScheduledRecordingPresenter.java
+++ b/src/com/android/tv/dvr/ui/browse/ScheduledRecordingPresenter.java
@@ -19,7 +19,7 @@ package com.android.tv.dvr.ui.browse;
import android.content.Context;
import android.os.Handler;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.dvr.DvrManager;
import com.android.tv.dvr.data.ScheduledRecording;
import com.android.tv.util.Utils;
@@ -100,7 +100,7 @@ class ScheduledRecordingPresenter extends DvrItemPresenter<ScheduledRecording> {
public ScheduledRecordingPresenter(Context context) {
super(context);
- mDvrManager = TvSingletons.getSingletons(mContext).getDvrManager();
+ mDvrManager = TvApplication.getSingletons(mContext).getDvrManager();
mProgressBarColor =
mContext.getResources()
.getColor(R.color.play_controls_recording_icon_color_on_focus);
diff --git a/src/com/android/tv/dvr/ui/browse/SeriesRecordingDetailsFragment.java b/src/com/android/tv/dvr/ui/browse/SeriesRecordingDetailsFragment.java
index 2cd191a7..48bc9cbd 100644
--- a/src/com/android/tv/dvr/ui/browse/SeriesRecordingDetailsFragment.java
+++ b/src/com/android/tv/dvr/ui/browse/SeriesRecordingDetailsFragment.java
@@ -33,7 +33,7 @@ import android.support.v17.leanback.widget.PresenterSelector;
import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
import android.text.TextUtils;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.data.BaseProgram;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.DvrWatchedPositionManager;
@@ -73,7 +73,7 @@ public class SeriesRecordingDetailsFragment extends DvrDetailsFragment
@Override
public void onCreate(Bundle savedInstanceState) {
- mDvrDataManager = TvSingletons.getSingletons(getActivity()).getDvrDataManager();
+ mDvrDataManager = TvApplication.getSingletons(getActivity()).getDvrDataManager();
mWatchLabel = getString(R.string.dvr_detail_watch);
mResumeLabel = getString(R.string.dvr_detail_series_resume);
mWatchDrawable = getResources().getDrawable(R.drawable.lb_ic_play, null);
@@ -84,7 +84,7 @@ public class SeriesRecordingDetailsFragment extends DvrDetailsFragment
@Override
protected void onCreateInternal() {
mDvrWatchedPositionManager =
- TvSingletons.getSingletons(getActivity()).getDvrWatchedPositionManager();
+ TvApplication.getSingletons(getActivity()).getDvrWatchedPositionManager();
setDetailsOverviewRow(DetailsContent.createFromSeriesRecording(getContext(), mSeries));
setupRecordedProgramsRow();
mDvrDataManager.addSeriesRecordingListener(this);
@@ -137,7 +137,7 @@ public class SeriesRecordingDetailsFragment extends DvrDetailsFragment
protected boolean onLoadRecordingDetails(Bundle args) {
long recordId = args.getLong(DvrDetailsActivity.RECORDING_ID);
mSeries =
- TvSingletons.getSingletons(getActivity())
+ TvApplication.getSingletons(getActivity())
.getDvrDataManager()
.getSeriesRecording(recordId);
if (mSeries == null) {
diff --git a/src/com/android/tv/dvr/ui/browse/SeriesRecordingPresenter.java b/src/com/android/tv/dvr/ui/browse/SeriesRecordingPresenter.java
index 14f9dceb..02ce24ef 100644
--- a/src/com/android/tv/dvr/ui/browse/SeriesRecordingPresenter.java
+++ b/src/com/android/tv/dvr/ui/browse/SeriesRecordingPresenter.java
@@ -19,8 +19,9 @@ package com.android.tv.dvr.ui.browse;
import android.content.Context;
import android.media.tv.TvInputManager;
import android.text.TextUtils;
+import com.android.tv.ApplicationSingletons;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.DvrDataManager.RecordedProgramListener;
import com.android.tv.dvr.DvrDataManager.ScheduledRecordingListener;
@@ -185,7 +186,7 @@ class SeriesRecordingPresenter extends DvrItemPresenter<SeriesRecording> {
public SeriesRecordingPresenter(Context context) {
super(context);
- TvSingletons singletons = TvSingletons.getSingletons(context);
+ ApplicationSingletons singletons = TvApplication.getSingletons(context);
mDvrDataManager = singletons.getDvrDataManager();
mDvrManager = singletons.getDvrManager();
mWatchedPositionManager = singletons.getDvrWatchedPositionManager();
diff --git a/src/com/android/tv/dvr/ui/list/BaseDvrSchedulesFragment.java b/src/com/android/tv/dvr/ui/list/BaseDvrSchedulesFragment.java
index 84298bdf..42c7086a 100644
--- a/src/com/android/tv/dvr/ui/list/BaseDvrSchedulesFragment.java
+++ b/src/com/android/tv/dvr/ui/list/BaseDvrSchedulesFragment.java
@@ -23,8 +23,9 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
+import com.android.tv.ApplicationSingletons;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.DvrScheduleManager;
import com.android.tv.dvr.data.ScheduledRecording;
@@ -49,7 +50,7 @@ public abstract class BaseDvrSchedulesFragment extends DetailsFragment
mRowsAdapter = onCreateRowsAdapter(presenterSelector);
setAdapter(mRowsAdapter);
mRowsAdapter.start();
- TvSingletons singletons = TvSingletons.getSingletons(getContext());
+ ApplicationSingletons singletons = TvApplication.getSingletons(getContext());
singletons.getDvrDataManager().addScheduledRecordingListener(this);
singletons.getDvrScheduleManager().addOnConflictStateChangeListener(this);
mEmptyInfoScreenView = (TextView) getActivity().findViewById(R.id.empty_info_screen);
@@ -95,7 +96,7 @@ public abstract class BaseDvrSchedulesFragment extends DetailsFragment
@Override
public void onDestroy() {
- TvSingletons singletons = TvSingletons.getSingletons(getContext());
+ ApplicationSingletons singletons = TvApplication.getSingletons(getContext());
singletons.getDvrScheduleManager().removeOnConflictStateChangeListener(this);
singletons.getDvrDataManager().removeScheduledRecordingListener(this);
mRowsAdapter.stop();
diff --git a/src/com/android/tv/dvr/ui/list/DvrSchedulesActivity.java b/src/com/android/tv/dvr/ui/list/DvrSchedulesActivity.java
index 82b85630..11df780c 100644
--- a/src/com/android/tv/dvr/ui/list/DvrSchedulesActivity.java
+++ b/src/com/android/tv/dvr/ui/list/DvrSchedulesActivity.java
@@ -21,7 +21,7 @@ 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.TvApplication;
import com.android.tv.data.Program;
import com.android.tv.dvr.data.SeriesRecording;
import com.android.tv.dvr.provider.EpisodicProgramLoadTask;
@@ -53,7 +53,7 @@ public class DvrSchedulesActivity extends Activity {
@Override
public void onCreate(final Bundle savedInstanceState) {
- Starter.start(this);
+ TvApplication.setCurrentRunningProcess(this, true);
// Pass null to prevent automatically re-creating fragments
super.onCreate(null);
setContentView(R.layout.activity_dvr_schedules);
diff --git a/src/com/android/tv/dvr/ui/list/DvrSeriesSchedulesFragment.java b/src/com/android/tv/dvr/ui/list/DvrSeriesSchedulesFragment.java
index d376e358..6ec2e152 100644
--- a/src/com/android/tv/dvr/ui/list/DvrSeriesSchedulesFragment.java
+++ b/src/com/android/tv/dvr/ui/list/DvrSeriesSchedulesFragment.java
@@ -30,8 +30,9 @@ import android.transition.Fade;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import com.android.tv.ApplicationSingletons;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.data.ChannelDataManager;
import com.android.tv.data.Program;
import com.android.tv.dvr.DvrDataManager;
@@ -140,7 +141,7 @@ public class DvrSeriesSchedulesFragment extends BaseDvrSchedulesFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- TvSingletons singletons = TvSingletons.getSingletons(getContext());
+ ApplicationSingletons singletons = TvApplication.getSingletons(getContext());
mChannelDataManager = singletons.getChannelDataManager();
mChannelDataManager.addListener(mChannelListener);
mDvrDataManager = singletons.getDvrDataManager();
diff --git a/src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java b/src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java
index 1215c19a..8dd6c322 100644
--- a/src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java
+++ b/src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java
@@ -26,7 +26,7 @@ import android.text.format.DateUtils;
import android.util.ArraySet;
import android.util.Log;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.dvr.DvrManager;
import com.android.tv.dvr.data.ScheduledRecording;
@@ -79,11 +79,11 @@ class ScheduleRowAdapter extends ArrayObjectAdapter {
public void start() {
clear();
List<ScheduledRecording> recordingList =
- TvSingletons.getSingletons(mContext)
+ TvApplication.getSingletons(mContext)
.getDvrDataManager()
.getNonStartedScheduledRecordings();
recordingList.addAll(
- TvSingletons.getSingletons(mContext).getDvrDataManager().getStartedRecordings());
+ TvApplication.getSingletons(mContext).getDvrDataManager().getStartedRecordings());
Collections.sort(
recordingList, ScheduledRecording.START_TIME_THEN_PRIORITY_THEN_ID_COMPARATOR);
long deadLine = Utils.getLastMillisecondOfDay(System.currentTimeMillis());
@@ -136,7 +136,7 @@ class ScheduleRowAdapter extends ArrayObjectAdapter {
/** Stops schedules row adapter. */
public void stop() {
mHandler.removeCallbacksAndMessages(null);
- DvrManager dvrManager = TvSingletons.getSingletons(getContext()).getDvrManager();
+ DvrManager dvrManager = TvApplication.getSingletons(getContext()).getDvrManager();
for (int i = 0; i < size(); i++) {
if (get(i) instanceof ScheduleRow) {
ScheduleRow row = (ScheduleRow) get(i);
diff --git a/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java b/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java
index 5cab607a..67096e3b 100644
--- a/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java
+++ b/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java
@@ -38,7 +38,7 @@ import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.data.Channel;
import com.android.tv.dialog.HalfSizedDialogFragment;
@@ -344,8 +344,8 @@ class ScheduleRowPresenter extends RowPresenter {
setHeaderPresenter(null);
setSelectEffectEnabled(false);
mContext = context;
- mDvrManager = TvSingletons.getSingletons(context).getDvrManager();
- mDvrScheduleManager = TvSingletons.getSingletons(context).getDvrScheduleManager();
+ mDvrManager = TvApplication.getSingletons(context).getDvrManager();
+ mDvrScheduleManager = TvApplication.getSingletons(context).getDvrScheduleManager();
mTunerConflictWillNotBeRecordedInfo =
mContext.getString(R.string.dvr_schedules_tuner_conflict_will_not_be_recorded_info);
mTunerConflictWillBePartiallyRecordedInfo =
@@ -426,7 +426,7 @@ class ScheduleRowPresenter extends RowPresenter {
switch (actions.length) {
case 2:
viewHolder.mSecondActionView.setImageResource(getImageForAction(actions[1]));
- // fall through
+ // pass through
case 1:
viewHolder.mFirstActionView.setImageResource(getImageForAction(actions[0]));
break;
@@ -486,7 +486,7 @@ class ScheduleRowPresenter extends RowPresenter {
private String getChannelNameText(ScheduleRow row) {
Channel channel =
- TvSingletons.getSingletons(mContext)
+ TvApplication.getSingletons(mContext)
.getChannelDataManager()
.getChannel(row.getChannelId());
return channel == null
diff --git a/src/com/android/tv/dvr/ui/list/SchedulesHeaderRowPresenter.java b/src/com/android/tv/dvr/ui/list/SchedulesHeaderRowPresenter.java
index eb01aba2..03cc0a79 100644
--- a/src/com/android/tv/dvr/ui/list/SchedulesHeaderRowPresenter.java
+++ b/src/com/android/tv/dvr/ui/list/SchedulesHeaderRowPresenter.java
@@ -28,7 +28,7 @@ import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.widget.TextView;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.dvr.data.SeriesRecording;
import com.android.tv.dvr.ui.DvrUiHelper;
import com.android.tv.dvr.ui.list.SchedulesHeaderRow.SeriesRecordingHeaderRow;
@@ -158,11 +158,11 @@ abstract class SchedulesHeaderRowPresenter extends RowPresenter {
SeriesRecording seriesRecording =
SeriesRecording.buildFrom(header.getSeriesRecording())
.setPriority(
- TvSingletons.getSingletons(getContext())
+ TvApplication.getSingletons(getContext())
.getDvrScheduleManager()
.suggestNewSeriesPriority())
.build();
- TvSingletons.getSingletons(getContext())
+ TvApplication.getSingletons(getContext())
.getDvrManager()
.updateSeriesRecording(seriesRecording);
DvrUiHelper.startSeriesSettingsActivity(
diff --git a/src/com/android/tv/dvr/ui/list/SeriesScheduleRowAdapter.java b/src/com/android/tv/dvr/ui/list/SeriesScheduleRowAdapter.java
index 9a9c94ea..692c0f99 100644
--- a/src/com/android/tv/dvr/ui/list/SeriesScheduleRowAdapter.java
+++ b/src/com/android/tv/dvr/ui/list/SeriesScheduleRowAdapter.java
@@ -23,8 +23,9 @@ import android.os.Build;
import android.support.v17.leanback.widget.ClassPresenterSelector;
import android.util.ArrayMap;
import android.util.Log;
+import com.android.tv.ApplicationSingletons;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.data.Program;
import com.android.tv.dvr.DvrDataManager;
@@ -64,7 +65,7 @@ class SeriesScheduleRowAdapter extends ScheduleRowAdapter {
} else {
mInputId = null;
}
- TvSingletons singletons = TvSingletons.getSingletons(context);
+ ApplicationSingletons singletons = TvApplication.getSingletons(context);
mDvrManager = singletons.getDvrManager();
mDataManager = singletons.getDvrDataManager();
setHasStableIds(true);
diff --git a/src/com/android/tv/dvr/ui/playback/DvrPlaybackActivity.java b/src/com/android/tv/dvr/ui/playback/DvrPlaybackActivity.java
index b8b19adc..29f2734d 100644
--- a/src/com/android/tv/dvr/ui/playback/DvrPlaybackActivity.java
+++ b/src/com/android/tv/dvr/ui/playback/DvrPlaybackActivity.java
@@ -24,7 +24,7 @@ import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import com.android.tv.R;
-import com.android.tv.Starter;
+import com.android.tv.TvApplication;
import com.android.tv.dialog.PinDialogFragment.OnPinCheckedListener;
import com.android.tv.dvr.data.RecordedProgram;
import com.android.tv.util.Utils;
@@ -39,7 +39,7 @@ public class DvrPlaybackActivity extends Activity implements OnPinCheckedListene
@Override
public void onCreate(Bundle savedInstanceState) {
- Starter.start(this);
+ TvApplication.setCurrentRunningProcess(this, true);
if (DEBUG) Log.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
setIntent(createProgramIntent(getIntent()));
diff --git a/src/com/android/tv/dvr/ui/playback/DvrPlaybackMediaSessionHelper.java b/src/com/android/tv/dvr/ui/playback/DvrPlaybackMediaSessionHelper.java
index dd17b22d..3ff90aa4 100644
--- a/src/com/android/tv/dvr/ui/playback/DvrPlaybackMediaSessionHelper.java
+++ b/src/com/android/tv/dvr/ui/playback/DvrPlaybackMediaSessionHelper.java
@@ -29,7 +29,7 @@ import android.os.AsyncTask;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
import com.android.tv.dvr.DvrWatchedPositionManager;
@@ -61,8 +61,8 @@ class DvrPlaybackMediaSessionHelper {
mActivity = activity;
mDvrPlayer = dvrPlayer;
mDvrWatchedPositionManager =
- TvSingletons.getSingletons(activity).getDvrWatchedPositionManager();
- mChannelDataManager = TvSingletons.getSingletons(activity).getChannelDataManager();
+ TvApplication.getSingletons(activity).getDvrWatchedPositionManager();
+ mChannelDataManager = TvApplication.getSingletons(activity).getChannelDataManager();
mDvrPlayer.setCallback(
new DvrPlayer.DvrPlayerCallback() {
@Override
diff --git a/src/com/android/tv/dvr/ui/playback/DvrPlaybackOverlayFragment.java b/src/com/android/tv/dvr/ui/playback/DvrPlaybackOverlayFragment.java
index d3374cfa..c5fccda2 100644
--- a/src/com/android/tv/dvr/ui/playback/DvrPlaybackOverlayFragment.java
+++ b/src/com/android/tv/dvr/ui/playback/DvrPlaybackOverlayFragment.java
@@ -43,7 +43,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.data.BaseProgram;
import com.android.tv.dialog.PinDialogFragment;
import com.android.tv.dvr.DvrDataManager;
@@ -116,9 +116,9 @@ public class DvrPlaybackOverlayFragment extends PlaybackFragment {
.getResources()
.getDimensionPixelOffset(
R.dimen.dvr_playback_overlay_padding_top_no_secondary_row);
- mDvrDataManager = TvSingletons.getSingletons(getActivity()).getDvrDataManager();
+ mDvrDataManager = TvApplication.getSingletons(getActivity()).getDvrDataManager();
mContentRatingsManager =
- TvSingletons.getSingletons(getContext())
+ TvApplication.getSingletons(getContext())
.getTvInputManagerHelper()
.getContentRatingsManager();
if (!mDvrDataManager.isRecordedProgramLoadFinished()) {
diff --git a/common/src/com/android/tv/common/experiments/ExperimentFlag.java b/src/com/android/tv/experiments/ExperimentFlag.java
index 42f7afca..2963482e 100644
--- a/common/src/com/android/tv/common/experiments/ExperimentFlag.java
+++ b/src/com/android/tv/experiments/ExperimentFlag.java
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package com.android.tv.common.experiments;
+package com.android.tv.experiments;
import android.support.annotation.VisibleForTesting;
-
/** Experiments return values based on user, device and other criteria. */
public final class ExperimentFlag<T> {
@@ -30,10 +29,8 @@ public final class ExperimentFlag<T> {
}
/** Returns a boolean experiment */
- public static ExperimentFlag<Boolean> createFlag(
- boolean defaultValue) {
- return new ExperimentFlag<>(
- defaultValue);
+ public static ExperimentFlag<Boolean> createFlag(boolean defaultValue) {
+ return new ExperimentFlag<>(defaultValue);
}
private final T mDefaultValue;
@@ -41,8 +38,7 @@ public final class ExperimentFlag<T> {
private T mOverrideValue = null;
private boolean mOverridden = false;
- private ExperimentFlag(
- T defaultValue) {
+ private ExperimentFlag(T defaultValue) {
mDefaultValue = defaultValue;
}
diff --git a/common/src/com/android/tv/common/experiments/Experiments.java b/src/com/android/tv/experiments/Experiments.java
index 96b15e53..0bff384e 100644
--- a/common/src/com/android/tv/common/experiments/Experiments.java
+++ b/src/com/android/tv/experiments/Experiments.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.tv.common.experiments;
+package com.android.tv.experiments;
-import static com.android.tv.common.experiments.ExperimentFlag.createFlag;
+import static com.android.tv.experiments.ExperimentFlag.createFlag;
import com.android.tv.common.BuildConfig;
@@ -26,18 +26,9 @@ import com.android.tv.common.BuildConfig;
* <p>This file is maintained by hand.
*/
public final class Experiments {
- public static final ExperimentFlag<Boolean> CLOUD_EPG =
- ExperimentFlag.createFlag(
- true);
+ public static final ExperimentFlag<Boolean> CLOUD_EPG = createFlag(true);
- public static final ExperimentFlag<Boolean> ENABLE_UNRATED_CONTENT_SETTINGS =
- ExperimentFlag.createFlag(
- false);
-
- /** Turn analytics on or off based on the System Checkbox for logging. */
- public static final ExperimentFlag<Boolean> ENABLE_ANALYTICS_VIA_CHECKBOX =
- createFlag(
- false);
+ public static final ExperimentFlag<Boolean> ENABLE_UNRATED_CONTENT_SETTINGS = createFlag(false);
/**
* Allow developer features such as the dev menu and other aids.
@@ -45,19 +36,7 @@ public final class Experiments {
* <p>These features are available to select users(aka fishfooders) on production builds.
*/
public static final ExperimentFlag<Boolean> ENABLE_DEVELOPER_FEATURES =
- ExperimentFlag.createFlag(
- 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(
- false);
+ createFlag(BuildConfig.ENG);
private Experiments() {}
}
diff --git a/src/com/android/tv/guide/ProgramGuide.java b/src/com/android/tv/guide/ProgramGuide.java
index 33ab9ad7..20c3ccdf 100644
--- a/src/com/android/tv/guide/ProgramGuide.java
+++ b/src/com/android/tv/guide/ProgramGuide.java
@@ -44,12 +44,11 @@ import android.view.ViewGroup.LayoutParams;
import android.view.ViewTreeObserver;
import android.view.accessibility.AccessibilityManager;
import com.android.tv.ChannelTuner;
+import com.android.tv.Features;
import com.android.tv.MainActivity;
import com.android.tv.R;
-import com.android.tv.TvFeatures;
import com.android.tv.analytics.Tracker;
import com.android.tv.common.WeakHandler;
-import com.android.tv.common.util.DurationTimer;
import com.android.tv.data.ChannelDataManager;
import com.android.tv.data.GenreItems;
import com.android.tv.data.ProgramDataManager;
@@ -57,6 +56,7 @@ import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.DvrScheduleManager;
import com.android.tv.ui.HardwareLayerAnimatorListenerAdapter;
import com.android.tv.ui.ViewUtils;
+import com.android.tv.util.DurationTimer;
import com.android.tv.util.TvInputManagerHelper;
import com.android.tv.util.Utils;
import java.util.ArrayList;
@@ -165,7 +165,6 @@ public class ProgramGuide implements ProgramGrid.ChildFocusListener {
}
};
- @SuppressWarnings("RestrictTo")
public ProgramGuide(
MainActivity activity,
ChannelTuner channelTuner,
@@ -237,7 +236,7 @@ public class ProgramGuide implements ProgramGrid.ChildFocusListener {
mSidePanelGridView.setWindowAlignmentOffsetPercent(
VerticalGridView.WINDOW_ALIGN_OFFSET_PERCENT_DISABLED);
- if (TvFeatures.EPG_SEARCH.isEnabled(mActivity)) {
+ if (Features.EPG_SEARCH.isEnabled(mActivity)) {
mSearchOrb =
(SearchOrbView)
mContainer.findViewById(R.id.program_guide_side_panel_search_orb);
diff --git a/src/com/android/tv/guide/ProgramItemView.java b/src/com/android/tv/guide/ProgramItemView.java
index 9daa9f2f..c8c7ff2d 100644
--- a/src/com/android/tv/guide/ProgramItemView.java
+++ b/src/com/android/tv/guide/ProgramItemView.java
@@ -35,9 +35,10 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
+import com.android.tv.ApplicationSingletons;
import com.android.tv.MainActivity;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.analytics.Tracker;
import com.android.tv.common.feature.CommonFeatures;
import com.android.tv.data.Channel;
@@ -90,7 +91,8 @@ public class ProgramItemView extends TextView {
// do nothing
return;
}
- TvSingletons singletons = TvSingletons.getSingletons(view.getContext());
+ ApplicationSingletons singletons =
+ TvApplication.getSingletons(view.getContext());
Tracker tracker = singletons.getTracker();
tracker.sendEpgItemClicked();
final MainActivity tvActivity = (MainActivity) view.getContext();
@@ -206,7 +208,7 @@ public class ProgramItemView extends TextView {
super(context, attrs, defStyle);
setOnClickListener(ON_CLICKED);
setOnFocusChangeListener(ON_FOCUS_CHANGED);
- mDvrManager = TvSingletons.getSingletons(getContext()).getDvrManager();
+ mDvrManager = TvApplication.getSingletons(getContext()).getDvrManager();
}
private void initIfNeeded() {
diff --git a/src/com/android/tv/guide/ProgramTableAdapter.java b/src/com/android/tv/guide/ProgramTableAdapter.java
index c77673a2..8dd14ca3 100644
--- a/src/com/android/tv/guide/ProgramTableAdapter.java
+++ b/src/com/android/tv/guide/ProgramTableAdapter.java
@@ -16,6 +16,8 @@
package com.android.tv.guide;
+import static com.android.tv.util.ImageLoader.ImageLoaderCallback;
+
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
@@ -40,7 +42,6 @@ import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewParent;
import android.view.ViewTreeObserver;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
@@ -48,9 +49,9 @@ 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.TvApplication;
+import com.android.tv.common.TvCommonUtils;
import com.android.tv.common.feature.CommonFeatures;
-import com.android.tv.common.util.CommonUtils;
import com.android.tv.data.Channel;
import com.android.tv.data.Program;
import com.android.tv.data.Program.CriticScore;
@@ -58,12 +59,10 @@ import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.DvrManager;
import com.android.tv.dvr.data.ScheduledRecording;
import com.android.tv.guide.ProgramManager.TableEntriesUpdatedListener;
-
import com.android.tv.parental.ParentalControlSettings;
import com.android.tv.ui.HardwareLayerAnimatorListenerAdapter;
import com.android.tv.util.ImageCache;
import com.android.tv.util.ImageLoader;
-import com.android.tv.util.ImageLoader.ImageLoaderCallback;
import com.android.tv.util.ImageLoader.LoadTvInputLogoTask;
import com.android.tv.util.TvInputManagerHelper;
import com.android.tv.util.Utils;
@@ -114,10 +113,10 @@ class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapter.Progr
mContext = context;
mAccessibilityManager =
(AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
- mTvInputManagerHelper = TvSingletons.getSingletons(context).getTvInputManagerHelper();
+ mTvInputManagerHelper = TvApplication.getSingletons(context).getTvInputManagerHelper();
if (CommonFeatures.DVR.isEnabled(context)) {
- mDvrManager = TvSingletons.getSingletons(context).getDvrManager();
- mDvrDataManager = TvSingletons.getSingletons(context).getDvrDataManager();
+ mDvrManager = TvApplication.getSingletons(context).getDvrManager();
+ mDvrDataManager = TvApplication.getSingletons(context).getDvrDataManager();
} else {
mDvrManager = null;
mDvrDataManager = null;
@@ -315,7 +314,7 @@ class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapter.Progr
new AccessibilityManager.AccessibilityStateChangeListener() {
@Override
public void onAccessibilityStateChanged(boolean enable) {
- enable &= !CommonUtils.isRunningInTest();
+ enable &= !TvCommonUtils.isRunningInTest();
mDetailView.setFocusable(enable);
mChannelHeaderView.setFocusable(enable);
}
@@ -369,7 +368,7 @@ class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapter.Progr
mInputLogoView = (ImageView) mContainer.findViewById(R.id.input_logo);
boolean accessibilityEnabled =
- mAccessibilityManager.isEnabled() && !CommonUtils.isRunningInTest();
+ mAccessibilityManager.isEnabled() && !TvCommonUtils.isRunningInTest();
mDetailView.setFocusable(accessibilityEnabled);
mChannelHeaderView.setFocusable(accessibilityEnabled);
}
@@ -449,7 +448,7 @@ class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapter.Progr
if (newFocus == null) {
return;
} // When the accessibility service is enabled, focus might be put on channel's header
- // or
+ // or
// detail view, besides program items.
if (newFocus == mChannelHeaderView) {
mSelectedEntry = ((ProgramItemView) mProgramRow.getChildAt(0)).getTableEntry();
diff --git a/src/com/android/tv/license/LicenseUtils.java b/src/com/android/tv/license/LicenseUtils.java
index ea774caa..1bae0c6a 100644
--- a/src/com/android/tv/license/LicenseUtils.java
+++ b/src/com/android/tv/license/LicenseUtils.java
@@ -21,7 +21,6 @@ import java.io.IOException;
import java.io.InputStream;
/** Utilities for showing open source licenses. */
-@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed
public final class LicenseUtils {
public static final String RATING_SOURCE_FILE = "file:///android_asset/rating_sources.html";
diff --git a/src/com/android/tv/menu/ChannelsRowAdapter.java b/src/com/android/tv/menu/ChannelsRowAdapter.java
index 2d86ec75..73ff6f3b 100644
--- a/src/com/android/tv/menu/ChannelsRowAdapter.java
+++ b/src/com/android/tv/menu/ChannelsRowAdapter.java
@@ -20,13 +20,15 @@ import android.content.Context;
import android.content.Intent;
import android.media.tv.TvInputInfo;
import android.view.View;
+import com.android.tv.ApplicationSingletons;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.analytics.Tracker;
import com.android.tv.common.feature.CommonFeatures;
import com.android.tv.data.Channel;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.recommendation.Recommender;
+import com.android.tv.util.SetupUtils;
import com.android.tv.util.TvInputManagerHelper;
import java.util.ArrayDeque;
import java.util.ArrayList;
@@ -100,10 +102,10 @@ public class ChannelsRowAdapter extends ItemListRowView.ItemListAdapter<Channels
Context context, Recommender recommender, int minCount, int maxCount) {
super(context);
mContext = context;
- TvSingletons tvSingletons = TvSingletons.getSingletons(context);
- mTracker = tvSingletons.getTracker();
+ ApplicationSingletons appSingletons = TvApplication.getSingletons(context);
+ mTracker = appSingletons.getTracker();
if (CommonFeatures.DVR.isEnabled(context)) {
- mDvrDataManager = tvSingletons.getDvrDataManager();
+ mDvrDataManager = appSingletons.getDvrDataManager();
} else {
mDvrDataManager = null;
}
@@ -229,14 +231,14 @@ public class ChannelsRowAdapter extends ItemListRowView.ItemListAdapter<Channels
}
private boolean needToShowSetupItem() {
- TvSingletons singletons = TvSingletons.getSingletons(mContext);
- TvInputManagerHelper inputManager = singletons.getTvInputManagerHelper();
- return singletons.getSetupUtils().hasNewInput(inputManager);
+ TvInputManagerHelper inputManager =
+ TvApplication.getSingletons(mContext).getTvInputManagerHelper();
+ return SetupUtils.getInstance(mContext).hasNewInput(inputManager);
}
private boolean needToShowDvrItem() {
TvInputManagerHelper inputManager =
- TvSingletons.getSingletons(mContext).getTvInputManagerHelper();
+ TvApplication.getSingletons(mContext).getTvInputManagerHelper();
if (mDvrDataManager != null) {
for (TvInputInfo info : inputManager.getTvInputInfos(true, true)) {
if (info.canRecord()) {
@@ -249,7 +251,7 @@ public class ChannelsRowAdapter extends ItemListRowView.ItemListAdapter<Channels
private boolean needToShowAppLinkItem() {
TvInputManagerHelper inputManager =
- TvSingletons.getSingletons(mContext).getTvInputManagerHelper();
+ TvApplication.getSingletons(mContext).getTvInputManagerHelper();
Channel currentChannel = getMainActivity().getCurrentChannel();
return currentChannel != null
&& currentChannel.getAppLinkType(mContext) != Channel.APP_LINK_TYPE_NONE
diff --git a/src/com/android/tv/menu/CustomizableOptionsRowAdapter.java b/src/com/android/tv/menu/CustomizableOptionsRowAdapter.java
index 7da26916..9ec70d09 100644
--- a/src/com/android/tv/menu/CustomizableOptionsRowAdapter.java
+++ b/src/com/android/tv/menu/CustomizableOptionsRowAdapter.java
@@ -17,7 +17,7 @@
package com.android.tv.menu;
import android.content.Context;
-import com.android.tv.common.customization.CustomAction;
+import com.android.tv.customization.CustomAction;
import java.util.ArrayList;
import java.util.List;
diff --git a/src/com/android/tv/menu/Menu.java b/src/com/android/tv/menu/Menu.java
index 0e081ba8..2b8a1fa6 100644
--- a/src/com/android/tv/menu/Menu.java
+++ b/src/com/android/tv/menu/Menu.java
@@ -30,15 +30,15 @@ import android.support.v17.leanback.widget.HorizontalGridView;
import android.util.Log;
import com.android.tv.ChannelTuner;
import com.android.tv.R;
+import com.android.tv.TvApplication;
import com.android.tv.TvOptionsManager;
-import com.android.tv.TvSingletons;
import com.android.tv.analytics.Tracker;
+import com.android.tv.common.TvCommonUtils;
import com.android.tv.common.WeakHandler;
-import com.android.tv.common.util.CommonUtils;
-import com.android.tv.common.util.DurationTimer;
import com.android.tv.menu.MenuRowFactory.PartnerRow;
import com.android.tv.menu.MenuRowFactory.TvOptionsRow;
import com.android.tv.ui.TunableTvView;
+import com.android.tv.util.DurationTimer;
import com.android.tv.util.ViewCache;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -139,7 +139,7 @@ public class Menu {
OnMenuVisibilityChangeListener onMenuVisibilityChangeListener) {
mContext = context;
mMenuView = menuView;
- mTracker = TvSingletons.getSingletons(context).getTracker();
+ mTracker = TvApplication.getSingletons(context).getTracker();
mMenuUpdater = new MenuUpdater(this, tvView, optionsManager);
Resources res = context.getResources();
mShowDurationMillis = res.getInteger(R.integer.menu_show_duration);
@@ -328,7 +328,7 @@ public class Menu {
@VisibleForTesting
void disableAnimationForTest() {
- if (!CommonUtils.isRunningInTest()) {
+ if (!TvCommonUtils.isRunningInTest()) {
throw new RuntimeException("Animation may only be enabled/disabled during tests.");
}
mAnimationDisabledForTest = true;
diff --git a/src/com/android/tv/menu/MenuLayoutManager.java b/src/com/android/tv/menu/MenuLayoutManager.java
index a600f704..e652463e 100644
--- a/src/com/android/tv/menu/MenuLayoutManager.java
+++ b/src/com/android/tv/menu/MenuLayoutManager.java
@@ -366,7 +366,7 @@ public class MenuLayoutManager {
return;
}
boolean indexValid = Utils.isIndexValid(mMenuRowViews, position);
- SoftPreconditions.checkArgument(indexValid, TAG, "position %s ", position);
+ SoftPreconditions.checkArgument(indexValid, TAG, "position " + position);
if (!indexValid) {
return;
}
@@ -419,7 +419,7 @@ public class MenuLayoutManager {
return;
}
boolean newIndexValid = Utils.isIndexValid(mMenuRowViews, position);
- SoftPreconditions.checkArgument(newIndexValid, TAG, "position %s", position);
+ SoftPreconditions.checkArgument(newIndexValid, TAG, "position " + position);
if (!newIndexValid) {
return;
}
diff --git a/src/com/android/tv/menu/MenuRowFactory.java b/src/com/android/tv/menu/MenuRowFactory.java
index 048d725d..5424e6f6 100644
--- a/src/com/android/tv/menu/MenuRowFactory.java
+++ b/src/com/android/tv/menu/MenuRowFactory.java
@@ -21,8 +21,8 @@ import android.support.annotation.Nullable;
import android.text.TextUtils;
import com.android.tv.MainActivity;
import com.android.tv.R;
-import com.android.tv.common.customization.CustomAction;
-import com.android.tv.common.customization.CustomizationManager;
+import com.android.tv.customization.CustomAction;
+import com.android.tv.customization.TvCustomizationManager;
import com.android.tv.ui.TunableTvView;
import java.util.List;
@@ -30,14 +30,14 @@ import java.util.List;
public class MenuRowFactory {
private final MainActivity mMainActivity;
private final TunableTvView mTvView;
- private final CustomizationManager mCustomizationManager;
+ private final TvCustomizationManager mTvCustomizationManager;
/** A constructor. */
public MenuRowFactory(MainActivity mainActivity, TunableTvView tvView) {
mMainActivity = mainActivity;
mTvView = tvView;
- mCustomizationManager = new CustomizationManager(mainActivity);
- mCustomizationManager.initialize();
+ mTvCustomizationManager = new TvCustomizationManager(mainActivity);
+ mTvCustomizationManager.initialize();
}
/** Creates an object corresponding to the given {@code key}. */
@@ -50,8 +50,8 @@ public class MenuRowFactory {
return new ChannelsRow(mMainActivity, menu, mMainActivity.getProgramDataManager());
} else if (PartnerRow.class.equals(key)) {
List<CustomAction> customActions =
- mCustomizationManager.getCustomActions(CustomizationManager.ID_PARTNER_ROW);
- String title = mCustomizationManager.getPartnerRowTitle();
+ mTvCustomizationManager.getCustomActions(TvCustomizationManager.ID_PARTNER_ROW);
+ String title = mTvCustomizationManager.getPartnerRowTitle();
if (customActions != null && !TextUtils.isEmpty(title)) {
return new PartnerRow(mMainActivity, menu, title, customActions);
}
@@ -60,7 +60,8 @@ public class MenuRowFactory {
return new TvOptionsRow(
mMainActivity,
menu,
- mCustomizationManager.getCustomActions(CustomizationManager.ID_OPTIONS_ROW));
+ mTvCustomizationManager.getCustomActions(
+ TvCustomizationManager.ID_OPTIONS_ROW));
}
return null;
}
diff --git a/src/com/android/tv/menu/OptionsRowAdapter.java b/src/com/android/tv/menu/OptionsRowAdapter.java
index ceffe861..593bede7 100644
--- a/src/com/android/tv/menu/OptionsRowAdapter.java
+++ b/src/com/android/tv/menu/OptionsRowAdapter.java
@@ -19,7 +19,7 @@ package com.android.tv.menu;
import android.content.Context;
import android.view.View;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.analytics.Tracker;
import java.util.List;
@@ -54,7 +54,7 @@ public abstract class OptionsRowAdapter extends ItemListRowView.ItemListAdapter<
public OptionsRowAdapter(Context context) {
super(context);
- mTracker = TvSingletons.getSingletons(context).getTracker();
+ mTracker = TvApplication.getSingletons(context).getTracker();
}
/** Update action list and its content. */
diff --git a/src/com/android/tv/menu/PartnerOptionsRowAdapter.java b/src/com/android/tv/menu/PartnerOptionsRowAdapter.java
index 9676fe4d..1a962640 100644
--- a/src/com/android/tv/menu/PartnerOptionsRowAdapter.java
+++ b/src/com/android/tv/menu/PartnerOptionsRowAdapter.java
@@ -17,7 +17,7 @@
package com.android.tv.menu;
import android.content.Context;
-import com.android.tv.common.customization.CustomAction;
+import com.android.tv.customization.CustomAction;
import java.util.Collections;
import java.util.List;
diff --git a/src/com/android/tv/menu/PlayControlsRowView.java b/src/com/android/tv/menu/PlayControlsRowView.java
index 35f1d503..d9879e18 100644
--- a/src/com/android/tv/menu/PlayControlsRowView.java
+++ b/src/com/android/tv/menu/PlayControlsRowView.java
@@ -28,7 +28,7 @@ import com.android.tv.MainActivity;
import com.android.tv.R;
import com.android.tv.TimeShiftManager;
import com.android.tv.TimeShiftManager.TimeShiftActionId;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.feature.CommonFeatures;
import com.android.tv.data.Channel;
@@ -127,8 +127,8 @@ public class PlayControlsRowView extends MenuRowView {
mCompactButtonMargin =
res.getDimensionPixelSize(R.dimen.play_controls_button_compact_margin);
if (CommonFeatures.DVR.isEnabled(context)) {
- mDvrDataManager = TvSingletons.getSingletons(context).getDvrDataManager();
- mDvrManager = TvSingletons.getSingletons(context).getDvrManager();
+ mDvrDataManager = TvApplication.getSingletons(context).getDvrDataManager();
+ mDvrManager = TvApplication.getSingletons(context).getDvrManager();
} else {
mDvrDataManager = null;
mDvrManager = null;
@@ -275,7 +275,7 @@ public class PlayControlsRowView extends MenuRowView {
private void onRecordButtonClicked() {
boolean isRecording = isCurrentChannelRecording();
Channel currentChannel = mMainActivity.getCurrentChannel();
- TvSingletons.getSingletons(getContext())
+ TvApplication.getSingletons(getContext())
.getTracker()
.sendMenuClicked(
isRecording
@@ -290,7 +290,7 @@ public class PlayControlsRowView extends MenuRowView {
.show();
} else {
Program program =
- TvSingletons.getSingletons(mMainActivity)
+ TvApplication.getSingletons(mMainActivity)
.getProgramDataManager()
.getCurrentProgram(currentChannel.getId());
DvrUiHelper.checkStorageStatusAndShowErrorMessage(
diff --git a/src/com/android/tv/menu/TvOptionsRowAdapter.java b/src/com/android/tv/menu/TvOptionsRowAdapter.java
index 55affb59..d340d309 100644
--- a/src/com/android/tv/menu/TvOptionsRowAdapter.java
+++ b/src/com/android/tv/menu/TvOptionsRowAdapter.java
@@ -19,16 +19,16 @@ package com.android.tv.menu;
import android.content.Context;
import android.media.tv.TvTrackInfo;
import android.support.annotation.VisibleForTesting;
-import com.android.tv.TvFeatures;
+import com.android.tv.Features;
import com.android.tv.TvOptionsManager;
-import com.android.tv.common.customization.CustomAction;
-import com.android.tv.common.util.CommonUtils;
+import com.android.tv.customization.CustomAction;
import com.android.tv.data.DisplayMode;
import com.android.tv.ui.TvViewUiManager;
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.util.Utils;
import java.util.ArrayList;
import java.util.List;
@@ -45,12 +45,12 @@ public class TvOptionsRowAdapter extends CustomizableOptionsRowAdapter {
List<MenuAction> actionList = new ArrayList<>();
actionList.add(MenuAction.SELECT_CLOSED_CAPTION_ACTION);
actionList.add(MenuAction.SELECT_DISPLAY_MODE_ACTION);
- if (TvFeatures.PICTURE_IN_PICTURE.isEnabled(getMainActivity())) {
+ if (Features.PICTURE_IN_PICTURE.isEnabled(getMainActivity())) {
actionList.add(MenuAction.SYSTEMWIDE_PIP_ACTION);
}
actionList.add(MenuAction.SELECT_AUDIO_LANGUAGE_ACTION);
actionList.add(MenuAction.MORE_CHANNELS_ACTION);
- if (CommonUtils.isDeveloper()) {
+ if (Utils.isDeveloper()) {
actionList.add(MenuAction.DEV_ACTION);
}
actionList.add(MenuAction.SETTINGS_ACTION);
diff --git a/src/com/android/tv/onboarding/NewSourcesFragment.java b/src/com/android/tv/onboarding/NewSourcesFragment.java
index e6b247a0..eaf06990 100644
--- a/src/com/android/tv/onboarding/NewSourcesFragment.java
+++ b/src/com/android/tv/onboarding/NewSourcesFragment.java
@@ -24,14 +24,14 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.common.ui.setup.SetupActionHelper;
+import com.android.tv.util.SetupUtils;
/** A fragment for new channel source info/setup. */
public class NewSourcesFragment extends Fragment {
/** The action category. */
- public static final String ACTION_CATEOGRY =
- "com.android.tv.onboarding.NewSourcesFragment";
+ public static final String ACTION_CATEOGRY = "com.android.tv.onboarding.NewSourcesFragment";
/** An action to show the setup screen. */
public static final int ACTION_SETUP = 1;
/** An action to close this fragment. */
@@ -52,8 +52,9 @@ public class NewSourcesFragment extends Fragment {
View view = inflater.inflate(R.layout.fragment_new_sources, container, false);
initializeButton(view.findViewById(R.id.setup), ACTION_SETUP);
initializeButton(view.findViewById(R.id.skip), ACTION_SKIP);
- TvSingletons singletons = TvSingletons.getSingletons(getActivity());
- singletons.getSetupUtils().markAllInputsRecognized(singletons.getTvInputManagerHelper());
+ SetupUtils.getInstance(getActivity())
+ .markAllInputsRecognized(
+ TvApplication.getSingletons(getActivity()).getTvInputManagerHelper());
view.requestFocus();
return view;
}
diff --git a/src/com/android/tv/onboarding/OnboardingActivity.java b/src/com/android/tv/onboarding/OnboardingActivity.java
index a1cf9de1..8d429a1d 100644
--- a/src/com/android/tv/onboarding/OnboardingActivity.java
+++ b/src/com/android/tv/onboarding/OnboardingActivity.java
@@ -26,15 +26,16 @@ import android.media.tv.TvInputInfo;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.widget.Toast;
+import com.android.tv.ApplicationSingletons;
import com.android.tv.R;
import com.android.tv.SetupPassthroughActivity;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
+import com.android.tv.common.TvCommonUtils;
import com.android.tv.common.ui.setup.SetupActivity;
import com.android.tv.common.ui.setup.SetupMultiPaneFragment;
-import com.android.tv.common.util.CommonUtils;
-import com.android.tv.common.util.PermissionUtils;
import com.android.tv.data.ChannelDataManager;
import com.android.tv.util.OnboardingUtils;
+import com.android.tv.util.PermissionUtils;
import com.android.tv.util.SetupUtils;
import com.android.tv.util.TvInputManagerHelper;
@@ -49,13 +50,12 @@ public class OnboardingActivity extends SetupActivity {
private ChannelDataManager mChannelDataManager;
private TvInputManagerHelper mInputManager;
- private SetupUtils mSetupUtils;
private final ChannelDataManager.Listener mChannelListener =
new ChannelDataManager.Listener() {
@Override
public void onLoadFinished() {
mChannelDataManager.removeListener(this);
- mSetupUtils.markNewChannelsBrowsable();
+ SetupUtils.getInstance(OnboardingActivity.this).markNewChannelsBrowsable();
}
@Override
@@ -81,15 +81,14 @@ public class OnboardingActivity extends SetupActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- TvSingletons singletons = TvSingletons.getSingletons(this);
+ ApplicationSingletons singletons = TvApplication.getSingletons(this);
mInputManager = singletons.getTvInputManagerHelper();
- mSetupUtils = singletons.getSetupUtils();
if (PermissionUtils.hasAccessAllEpg(this) || PermissionUtils.hasReadTvListings(this)) {
mChannelDataManager = singletons.getChannelDataManager();
// Make the channels of the new inputs which have been setup outside Live TV
// browsable.
if (mChannelDataManager.isDbLoadFinished()) {
- mSetupUtils.markNewChannelsBrowsable();
+ SetupUtils.getInstance(this).markNewChannelsBrowsable();
} else {
mChannelDataManager.addListener(mChannelListener);
}
@@ -180,7 +179,7 @@ public class OnboardingActivity extends SetupActivity {
params.getString(
SetupSourcesFragment.ACTION_PARAM_KEY_INPUT_ID);
TvInputInfo input = mInputManager.getTvInputInfo(inputId);
- Intent intent = CommonUtils.createSetupIntent(input);
+ Intent intent = TvCommonUtils.createSetupIntent(input);
if (intent == null) {
Toast.makeText(
this,
@@ -214,7 +213,7 @@ public class OnboardingActivity extends SetupActivity {
case SetupMultiPaneFragment.ACTION_DONE:
{
ChannelDataManager manager =
- TvSingletons.getSingletons(OnboardingActivity.this)
+ TvApplication.getSingletons(OnboardingActivity.this)
.getChannelDataManager();
if (manager.getChannelCount() == 0) {
finish();
diff --git a/src/com/android/tv/onboarding/SetupSourcesFragment.java b/src/com/android/tv/onboarding/SetupSourcesFragment.java
index 3025538b..1ac6b27e 100644
--- a/src/com/android/tv/onboarding/SetupSourcesFragment.java
+++ b/src/com/android/tv/onboarding/SetupSourcesFragment.java
@@ -30,12 +30,14 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
+import com.android.tv.ApplicationSingletons;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
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.tuner.TunerInputController;
import com.android.tv.ui.GuidedActionsStylistWithDivider;
import com.android.tv.util.SetupUtils;
import com.android.tv.util.TvInputManagerHelper;
@@ -46,8 +48,7 @@ import java.util.List;
/** A fragment for channel source info/setup. */
public class SetupSourcesFragment extends SetupMultiPaneFragment {
/** The action category for the actions which is fired from this fragment. */
- public static final String ACTION_CATEGORY =
- "com.android.tv.onboarding.SetupSourcesFragment";
+ public static final String ACTION_CATEGORY = "com.android.tv.onboarding.SetupSourcesFragment";
/** An action to open the merchant collection. */
public static final int ACTION_ONLINE_STORE = 1;
/**
@@ -70,7 +71,7 @@ public class SetupSourcesFragment extends SetupMultiPaneFragment {
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = super.onCreateView(inflater, container, savedInstanceState);
- TvSingletons.getSingletons(getActivity()).getTracker().sendScreenView(SETUP_TRACKER_LABEL);
+ TvApplication.getSingletons(getActivity()).getTracker().sendScreenView(SETUP_TRACKER_LABEL);
return view;
}
@@ -189,18 +190,16 @@ public class SetupSourcesFragment extends SetupMultiPaneFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
Context context = getActivity();
- TvSingletons singletons = TvSingletons.getSingletons(context);
- mInputManager = singletons.getTvInputManagerHelper();
- mChannelDataManager = singletons.getChannelDataManager();
- mSetupUtils = singletons.getSetupUtils();
+ ApplicationSingletons app = TvApplication.getSingletons(context);
+ mInputManager = app.getTvInputManagerHelper();
+ mChannelDataManager = app.getChannelDataManager();
+ mSetupUtils = SetupUtils.getInstance(context);
buildInputs();
mInputManager.addCallback(mInputCallback);
mChannelDataManager.addListener(mChannelDataManagerListener);
super.onCreate(savedInstanceState);
mParentFragment = (SetupSourcesFragment) getParentFragment();
- singletons
- .getTunerInputController()
- .executeNetworkTunerDiscoveryAsyncTask(getContext());
+ TunerInputController.executeNetworkTunerDiscoveryAsyncTask(getContext());
}
@Override
diff --git a/src/com/android/tv/onboarding/WelcomeFragment.java b/src/com/android/tv/onboarding/WelcomeFragment.java
index 92b56e8d..d139314e 100644
--- a/src/com/android/tv/onboarding/WelcomeFragment.java
+++ b/src/com/android/tv/onboarding/WelcomeFragment.java
@@ -16,8 +16,6 @@
package com.android.tv.onboarding;
-import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS;
-
import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.animation.AnimatorListenerAdapter;
@@ -26,18 +24,11 @@ import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v17.leanback.app.OnboardingFragment;
-import android.text.Editable;
-import android.text.TextWatcher;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.View.AccessibilityDelegate;
import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.widget.Button;
import android.widget.ImageView;
-import android.widget.TextView;
import com.android.tv.R;
import com.android.tv.common.ui.setup.SetupActionHelper;
import com.android.tv.common.ui.setup.animation.SetupAnimationHelper;
@@ -46,7 +37,7 @@ import java.util.List;
/** A fragment for the onboarding welcome screen. */
public class WelcomeFragment extends OnboardingFragment {
- public static final String ACTION_CATEGORY = "com.android.tv.onboarding.WelcomeFragment";
+ public static final String ACTION_CATEGORY = "comgoogle.android.tv.onboarding.WelcomeFragment";
public static final int ACTION_NEXT = 1;
private static final long START_DELAY_CLOUD_MS = 33;
@@ -585,15 +576,8 @@ public class WelcomeFragment extends OnboardingFragment {
private ImageView mTvContentView;
private ImageView mArrowView;
- private TextView mTitleView;
- private Button mStartButton;
- private View mPagingIndicator;
-
private Animator mAnimator;
- private boolean mLogoAnimationFinished;
- private boolean mTitleChanged;
-
public WelcomeFragment() {
setExitTransition(
new SetupAnimationHelper.TransitionBuilder()
@@ -614,91 +598,14 @@ public class WelcomeFragment extends OnboardingFragment {
mPageDescriptions = getResources().getStringArray(R.array.welcome_page_descriptions);
}
}
+
@Nullable
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = super.onCreateView(inflater, container, savedInstanceState);
setLogoResourceId(R.drawable.splash_logo);
- 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() {
- @Override
- public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
- int type = event.getEventType();
- if (type == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED
- || type == AccessibilityEvent.TYPE_VIEW_FOCUSED) {
- if (!mTitleChanged || mTitleView.isAccessibilityFocused()) {
- // Skip the event before the title is accessibility focused to avoid race
- // conditions
- return;
- }
- }
- super.onInitializeAccessibilityEvent(host, event);
- }
- });
-
- mPagingIndicator.setAccessibilityDelegate(new AccessibilityDelegate() {
- @Override
- public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
- int type = event.getEventType();
- if (type == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED
- || type == AccessibilityEvent.TYPE_VIEW_FOCUSED) {
- if (!mTitleChanged || mTitleView.isAccessibilityFocused()) {
- // Skip the event before the title is accessibility focused to avoid race
- // conditions
- return;
- }
- }
- super.onInitializeAccessibilityEvent(host, event);
- }
- });
-
- mTitleView.setAccessibilityDelegate(new AccessibilityDelegate() {
- @Override
- public boolean performAccessibilityAction(View host, int action, Bundle args) {
- if (action == ACTION_CLEAR_ACCESSIBILITY_FOCUS) {
- if (!mTitleChanged || mTitleView.isAccessibilityFocused()) {
- // Skip the event before the title is accessibility focused to avoid race
- // conditions
- return false;
- }
- }
- return super.performAccessibilityAction(host, action, args);
- }
- });
-
- mTitleView.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- mTitleChanged = false;
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- if (!mTitleView.isAccessibilityFocused()) {
- mTitleView.performAccessibilityAction(
- AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
- } else {
- mTitleView.sendAccessibilityEvent(
- AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
- }
- mTitleChanged = true;
- }
- });
- return view;
- }
-
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
- if (savedInstanceState != null && mLogoAnimationFinished) {
+ if (savedInstanceState != null) {
switch (getCurrentPageIndex()) {
case 0:
mTvContentView.setImageResource(
@@ -720,6 +627,7 @@ public class WelcomeFragment extends OnboardingFragment {
break;
}
}
+ return view;
}
@Override
@@ -728,12 +636,6 @@ public class WelcomeFragment extends OnboardingFragment {
}
@Override
- protected void onLogoAnimationFinished() {
- super.onLogoAnimationFinished();
- mLogoAnimationFinished = true;
- }
-
- @Override
protected Animator onCreateEnterAnimation() {
List<Animator> animators = new ArrayList<>();
// Cloud 1
@@ -831,7 +733,6 @@ public class WelcomeFragment extends OnboardingFragment {
if (mAnimator != null) {
mAnimator.cancel();
}
- mTitleChanged = false;
mArrowView.setVisibility(View.GONE);
// TV screen hiding animator.
Animator hideAnimator =
diff --git a/src/com/android/tv/parental/ContentRatingsManager.java b/src/com/android/tv/parental/ContentRatingsManager.java
index 32a1325b..a9c947c6 100644
--- a/src/com/android/tv/parental/ContentRatingsManager.java
+++ b/src/com/android/tv/parental/ContentRatingsManager.java
@@ -19,12 +19,12 @@ package com.android.tv.parental;
import android.content.Context;
import android.media.tv.TvContentRating;
import android.media.tv.TvContentRatingSystemInfo;
+import android.media.tv.TvInputManager;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import com.android.tv.R;
import com.android.tv.parental.ContentRatingSystem.Rating;
import com.android.tv.parental.ContentRatingSystem.SubRating;
-import com.android.tv.util.TvInputManagerHelper;
import java.util.ArrayList;
import java.util.List;
@@ -32,19 +32,19 @@ public class ContentRatingsManager {
private final List<ContentRatingSystem> mContentRatingSystems = new ArrayList<>();
private final Context mContext;
- private final TvInputManagerHelper.TvInputManagerInterface mTvInputManager;
- public ContentRatingsManager(
- Context context, TvInputManagerHelper.TvInputManagerInterface tvInputManager) {
+ public ContentRatingsManager(Context context) {
mContext = context;
- this.mTvInputManager = tvInputManager;
}
public void update() {
mContentRatingSystems.clear();
+
+ TvInputManager manager =
+ (TvInputManager) mContext.getSystemService(Context.TV_INPUT_SERVICE);
ContentRatingsParser parser = new ContentRatingsParser(mContext);
- List<TvContentRatingSystemInfo> infos = mTvInputManager.getTvContentRatingSystemList();
+ List<TvContentRatingSystemInfo> infos = manager.getTvContentRatingSystemList();
for (TvContentRatingSystemInfo info : infos) {
List<ContentRatingSystem> list = parser.parse(info);
if (list != null) {
diff --git a/src/com/android/tv/parental/ContentRatingsParser.java b/src/com/android/tv/parental/ContentRatingsParser.java
index 294e9463..3e645ce9 100644
--- a/src/com/android/tv/parental/ContentRatingsParser.java
+++ b/src/com/android/tv/parental/ContentRatingsParser.java
@@ -33,7 +33,6 @@ import java.util.List;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed
public class ContentRatingsParser {
private static final String TAG = "ContentRatingsParser";
private static final boolean DEBUG = false;
diff --git a/src/com/android/tv/parental/ParentalControlSettings.java b/src/com/android/tv/parental/ParentalControlSettings.java
index db1f0a4d..b9cf45b2 100644
--- a/src/com/android/tv/parental/ParentalControlSettings.java
+++ b/src/com/android/tv/parental/ParentalControlSettings.java
@@ -19,7 +19,7 @@ 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.experiments.Experiments;
import com.android.tv.parental.ContentRatingSystem.Rating;
import com.android.tv.parental.ContentRatingSystem.SubRating;
import com.android.tv.util.TvSettings;
diff --git a/src/com/android/tv/perf/EventNames.java b/src/com/android/tv/perf/EventNames.java
index 54745f3b..12488ddb 100644
--- a/src/com/android/tv/perf/EventNames.java
+++ b/src/com/android/tv/perf/EventNames.java
@@ -25,7 +25,6 @@ import java.lang.annotation.Retention;
* Constants for performance event names.
*
* <p>Only constants are used to insure no PII is sent.
- *
*/
public final class EventNames {
diff --git a/src/com/android/tv/receiver/AudioCapabilitiesReceiver.java b/src/com/android/tv/receiver/AudioCapabilitiesReceiver.java
index 3fb66245..90e087f0 100644
--- a/src/com/android/tv/receiver/AudioCapabilitiesReceiver.java
+++ b/src/com/android/tv/receiver/AudioCapabilitiesReceiver.java
@@ -24,10 +24,11 @@ import android.media.AudioFormat;
import android.media.AudioManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import com.android.tv.TvSingletons;
+import com.android.tv.ApplicationSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.analytics.Analytics;
import com.android.tv.analytics.Tracker;
-import com.android.tv.common.util.SharedPreferencesUtils;
+import com.android.tv.common.SharedPreferencesUtils;
/**
* Creates HDMI plug broadcast receiver, and reports AC3 passthrough capabilities to Google
@@ -60,9 +61,9 @@ public final class AudioCapabilitiesReceiver {
public AudioCapabilitiesReceiver(
@NonNull Context context, @Nullable OnAc3PassthroughCapabilityChangeListener listener) {
mContext = context;
- TvSingletons tvSingletons = TvSingletons.getSingletons(context);
- mAnalytics = tvSingletons.getAnalytics();
- mTracker = tvSingletons.getTracker();
+ ApplicationSingletons appSingletons = TvApplication.getSingletons(context);
+ mAnalytics = appSingletons.getAnalytics();
+ mTracker = appSingletons.getTracker();
mListener = listener;
}
diff --git a/src/com/android/tv/receiver/BootCompletedReceiver.java b/src/com/android/tv/receiver/BootCompletedReceiver.java
index d8528bb5..b3ecb8e6 100644
--- a/src/com/android/tv/receiver/BootCompletedReceiver.java
+++ b/src/com/android/tv/receiver/BootCompletedReceiver.java
@@ -23,10 +23,9 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.util.Log;
-import com.android.tv.Starter;
+import com.android.tv.Features;
import com.android.tv.TvActivity;
-import com.android.tv.TvFeatures;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.dvr.recorder.DvrRecordingService;
import com.android.tv.dvr.recorder.RecordingScheduler;
import com.android.tv.recommendation.ChannelPreviewUpdater;
@@ -52,12 +51,12 @@ public class BootCompletedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- if (!TvSingletons.getSingletons(context).getTvInputManagerHelper().hasTvInputManager()) {
+ if (!TvApplication.getSingletons(context).getTvInputManagerHelper().hasTvInputManager()) {
Log.wtf(TAG, "Stopping because device does not have a TvInputManager");
return;
}
if (DEBUG) Log.d(TAG, "boot completed " + intent);
- Starter.start(context);
+ TvApplication.setCurrentRunningProcess(context, true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ChannelPreviewUpdater.getInstance(context).updatePreviewDataForChannelsImmediately();
@@ -70,7 +69,7 @@ public class BootCompletedReceiver extends BroadcastReceiver {
// Grant permission to already set up packages after the system has finished booting.
SetupUtils.grantEpgPermissionToSetUpPackages(context);
- if (TvFeatures.UNHIDE.isEnabled(context)) {
+ if (Features.UNHIDE.isEnabled(context)) {
if (OnboardingUtils.isFirstBoot(context)) {
// Enable the application if this is the first "unhide" feature is enabled just in
// case when the app has been disabled before.
@@ -85,7 +84,7 @@ public class BootCompletedReceiver extends BroadcastReceiver {
}
}
- RecordingScheduler scheduler = TvSingletons.getSingletons(context).getRecordingScheduler();
+ RecordingScheduler scheduler = TvApplication.getSingletons(context).getRecordingScheduler();
if (scheduler != null) {
scheduler.updateAndStartServiceIfNeeded();
}
diff --git a/src/com/android/tv/receiver/GlobalKeyReceiver.java b/src/com/android/tv/receiver/GlobalKeyReceiver.java
index 0133d8ee..7c4117d4 100644
--- a/src/com/android/tv/receiver/GlobalKeyReceiver.java
+++ b/src/com/android/tv/receiver/GlobalKeyReceiver.java
@@ -23,9 +23,7 @@ import android.os.AsyncTask;
import android.provider.Settings;
import android.util.Log;
import android.view.KeyEvent;
-import com.android.tv.Starter;
import com.android.tv.TvApplication;
-import com.android.tv.TvSingletons;
/** Handles global keys. */
public class GlobalKeyReceiver extends BroadcastReceiver {
@@ -41,11 +39,11 @@ public class GlobalKeyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- if (!TvSingletons.getSingletons(context).getTvInputManagerHelper().hasTvInputManager()) {
+ if (!TvApplication.getSingletons(context).getTvInputManagerHelper().hasTvInputManager()) {
Log.wtf(TAG, "Stopping because device does not have a TvInputManager");
return;
}
- Starter.start(context);
+ TvApplication.setCurrentRunningProcess(context, true);
Context appContext = context.getApplicationContext();
if (DEBUG) Log.d(TAG, "onReceive: " + intent);
if (sUserSetupComplete) {
diff --git a/src/com/android/tv/receiver/PackageIntentsReceiver.java b/src/com/android/tv/receiver/PackageIntentsReceiver.java
index 3958f6bf..bd26c7b3 100644
--- a/src/com/android/tv/receiver/PackageIntentsReceiver.java
+++ b/src/com/android/tv/receiver/PackageIntentsReceiver.java
@@ -21,10 +21,7 @@ import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;
-import com.android.tv.Starter;
-import com.android.tv.TvFeatures;
-import com.android.tv.TvSingletons;
-
+import com.android.tv.TvApplication;
import com.android.tv.util.Partner;
/** A class for handling the broadcast intents from PackageManager. */
@@ -33,12 +30,12 @@ public class PackageIntentsReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- if (!TvSingletons.getSingletons(context).getTvInputManagerHelper().hasTvInputManager()) {
+ if (!TvApplication.getSingletons(context).getTvInputManagerHelper().hasTvInputManager()) {
Log.wtf(TAG, "Stopping because device does not have a TvInputManager");
return;
}
- Starter.start(context);
- ((TvSingletons) context.getApplicationContext()).handleInputCountChanged();
+ TvApplication.setCurrentRunningProcess(context, true);
+ ((TvApplication) context.getApplicationContext()).handleInputCountChanged();
Uri uri = intent.getData();
final String packageName = (uri != null ? uri.getSchemeSpecificPart() : null);
diff --git a/src/com/android/tv/recommendation/ChannelPreviewUpdater.java b/src/com/android/tv/recommendation/ChannelPreviewUpdater.java
index 5da802c4..d332e18a 100644
--- a/src/com/android/tv/recommendation/ChannelPreviewUpdater.java
+++ b/src/com/android/tv/recommendation/ChannelPreviewUpdater.java
@@ -28,8 +28,8 @@ import android.support.annotation.RequiresApi;
import android.support.media.tv.TvContractCompat;
import android.text.TextUtils;
import android.util.Log;
-import com.android.tv.Starter;
-import com.android.tv.TvSingletons;
+import com.android.tv.ApplicationSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.data.Channel;
import com.android.tv.data.PreviewDataManager;
import com.android.tv.data.PreviewProgramContent;
@@ -46,7 +46,8 @@ import java.util.concurrent.TimeUnit;
@RequiresApi(Build.VERSION_CODES.O)
public class ChannelPreviewUpdater {
private static final String TAG = "ChannelPreviewUpdater";
- private static final boolean DEBUG = false;
+ // STOPSHIP: set it to false.
+ private static final boolean DEBUG = true;
private static final int UPATE_PREVIEW_PROGRAMS_JOB_ID = 1000001;
private static final long ROUTINE_INTERVAL_MS = TimeUnit.MINUTES.toMillis(10);
@@ -99,10 +100,10 @@ public class ChannelPreviewUpdater {
mRecommender.registerEvaluator(new RandomEvaluator(), 0.1, 0.1);
mRecommender.registerEvaluator(new FavoriteChannelEvaluator(), 0.5, 0.5);
mRecommender.registerEvaluator(new RoutineWatchEvaluator(), 1.0, 1.0);
- TvSingletons tvSingleton = TvSingletons.getSingletons(context);
- mPreviewDataManager = tvSingleton.getPreviewDataManager();
+ ApplicationSingletons appSingleton = TvApplication.getSingletons(context);
+ mPreviewDataManager = appSingleton.getPreviewDataManager();
mParentalControlSettings =
- tvSingleton.getTvInputManagerHelper().getParentalControlSettings();
+ appSingleton.getTvInputManagerHelper().getParentalControlSettings();
}
/** Starts the routine service for updating the preview programs. */
@@ -293,7 +294,7 @@ public class ChannelPreviewUpdater {
@Override
public void onCreate() {
- Starter.start(this);
+ TvApplication.setCurrentRunningProcess(this, true);
if (DEBUG) Log.d(TAG, "ChannelPreviewUpdateService.onCreate");
mChannelPreviewUpdater = ChannelPreviewUpdater.getInstance(this);
}
diff --git a/src/com/android/tv/recommendation/ChannelRecord.java b/src/com/android/tv/recommendation/ChannelRecord.java
index 34679452..812b9d3f 100644
--- a/src/com/android/tv/recommendation/ChannelRecord.java
+++ b/src/com/android/tv/recommendation/ChannelRecord.java
@@ -17,9 +17,8 @@
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.TvApplication;
import com.android.tv.data.Channel;
import com.android.tv.data.Program;
import com.android.tv.data.ProgramDataManager;
@@ -30,10 +29,7 @@ public class ChannelRecord {
// TODO: decide the value for max history size.
@VisibleForTesting static final int MAX_HISTORY_SIZE = 100;
private final Context mContext;
-
- @GuardedBy("this")
private final Deque<WatchedProgram> mWatchHistory;
-
private Program mCurrentProgram;
private Channel mChannel;
private long mTotalWatchDurationMs;
@@ -63,7 +59,7 @@ public class ChannelRecord {
mInputRemoved = removed;
}
- public synchronized long getLastWatchEndTimeMs() {
+ public long getLastWatchEndTimeMs() {
WatchedProgram p = mWatchHistory.peekLast();
return (p == null) ? 0 : p.getWatchEndTimeMs();
}
@@ -72,7 +68,7 @@ public class ChannelRecord {
long time = System.currentTimeMillis();
if (mCurrentProgram == null || mCurrentProgram.getEndTimeUtcMillis() < time) {
ProgramDataManager manager =
- TvSingletons.getSingletons(mContext).getProgramDataManager();
+ TvApplication.getSingletons(mContext).getProgramDataManager();
mCurrentProgram = manager.getCurrentProgram(mChannel.getId());
}
return mCurrentProgram;
@@ -82,11 +78,11 @@ public class ChannelRecord {
return mTotalWatchDurationMs;
}
- public final synchronized WatchedProgram[] getWatchHistory() {
+ public final WatchedProgram[] getWatchHistory() {
return mWatchHistory.toArray(new WatchedProgram[mWatchHistory.size()]);
}
- public synchronized void logWatchHistory(WatchedProgram p) {
+ public void logWatchHistory(WatchedProgram p) {
mWatchHistory.offer(p);
mTotalWatchDurationMs += p.getWatchedDurationMs();
if (mWatchHistory.size() > MAX_HISTORY_SIZE) {
diff --git a/src/com/android/tv/recommendation/NotificationService.java b/src/com/android/tv/recommendation/NotificationService.java
index 201bb103..c4b321e1 100644
--- a/src/com/android/tv/recommendation/NotificationService.java
+++ b/src/com/android/tv/recommendation/NotificationService.java
@@ -40,10 +40,10 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.SparseLongArray;
import android.view.View;
+import com.android.tv.ApplicationSingletons;
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.TvApplication;
import com.android.tv.common.WeakHandler;
import com.android.tv.data.Channel;
import com.android.tv.data.Program;
@@ -122,7 +122,7 @@ public class NotificationService extends Service
@Override
public void onCreate() {
if (DEBUG) Log.d(TAG, "onCreate");
- Starter.start(this);
+ TvApplication.setCurrentRunningProcess(this, true);
super.onCreate();
mCurrentNotificationCount = 0;
mNotificationChannels = new long[NOTIFICATION_COUNT];
@@ -146,17 +146,17 @@ public class NotificationService extends Service
getResources().getDimensionPixelOffset(R.dimen.notif_ch_logo_padding_bottom);
mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- TvSingletons tvSingletons = TvSingletons.getSingletons(this);
- mTvInputManagerHelper = tvSingletons.getTvInputManagerHelper();
+ ApplicationSingletons appSingletons = TvApplication.getSingletons(this);
+ mTvInputManagerHelper = appSingletons.getTvInputManagerHelper();
mHandlerThread = new HandlerThread("tv notification");
mHandlerThread.start();
mHandler = new NotificationHandler(mHandlerThread.getLooper(), this);
mHandler.sendEmptyMessage(MSG_INITIALIZE_RECOMMENDER);
// Just called for early initialization.
- tvSingletons.getChannelDataManager();
- tvSingletons.getProgramDataManager();
- tvSingletons.getMainActivityWrapper().addOnCurrentChannelChangeListener(this);
+ appSingletons.getChannelDataManager();
+ appSingletons.getProgramDataManager();
+ appSingletons.getMainActivityWrapper().addOnCurrentChannelChangeListener(this);
}
@UiThread
@@ -209,7 +209,7 @@ public class NotificationService extends Service
@Override
public void onDestroy() {
- TvSingletons.getSingletons(this)
+ TvApplication.getSingletons(this)
.getMainActivityWrapper()
.removeOnCurrentChannelChangeListener(this);
if (mRecommender != null) {
diff --git a/src/com/android/tv/recommendation/RecommendationDataManager.java b/src/com/android/tv/recommendation/RecommendationDataManager.java
index 8e8455fa..794ca7e2 100644
--- a/src/com/android/tv/recommendation/RecommendationDataManager.java
+++ b/src/com/android/tv/recommendation/RecommendationDataManager.java
@@ -33,13 +33,13 @@ import android.support.annotation.MainThread;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.WorkerThread;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.common.WeakHandler;
-import com.android.tv.common.util.PermissionUtils;
import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
import com.android.tv.data.Program;
import com.android.tv.data.WatchedHistoryManager;
+import com.android.tv.util.PermissionUtils;
import com.android.tv.util.TvUriMatcher;
import java.util.ArrayList;
import java.util.Collection;
@@ -50,7 +50,6 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
-@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed
public class RecommendationDataManager implements WatchedHistoryManager.Listener {
private static final int MSG_START = 1000;
private static final int MSG_STOP = 1001;
@@ -186,7 +185,7 @@ public class RecommendationDataManager implements WatchedHistoryManager.Listener
mHandler = new RecommendationHandler(mHandlerThread.getLooper(), this);
mMainHandler = new RecommendationMainHandler(Looper.getMainLooper(), this);
mContentObserver = new RecommendationContentObserver(mHandler);
- mChannelDataManager = TvSingletons.getSingletons(mContext).getChannelDataManager();
+ mChannelDataManager = TvApplication.getSingletons(mContext).getChannelDataManager();
runOnMainThread(
new Runnable() {
@Override
diff --git a/src/com/android/tv/recommendation/RecordedProgramPreviewUpdater.java b/src/com/android/tv/recommendation/RecordedProgramPreviewUpdater.java
index edc23c53..2b17c510 100644
--- a/src/com/android/tv/recommendation/RecordedProgramPreviewUpdater.java
+++ b/src/com/android/tv/recommendation/RecordedProgramPreviewUpdater.java
@@ -21,7 +21,8 @@ import android.os.Build;
import android.support.annotation.RequiresApi;
import android.text.TextUtils;
import android.util.Log;
-import com.android.tv.TvSingletons;
+import com.android.tv.ApplicationSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.data.PreviewDataManager;
import com.android.tv.data.PreviewProgramContent;
import com.android.tv.dvr.DvrDataManager;
@@ -33,10 +34,10 @@ import java.util.Set;
/** Class to update the preview data for {@link RecordedProgram} */
@RequiresApi(Build.VERSION_CODES.O)
-@SuppressWarnings("AndroidApiChecker") // TODO(b/32513850) remove when error prone is updated
public class RecordedProgramPreviewUpdater {
private static final String TAG = "RecordedProgramPreviewUpdater";
- private static final boolean DEBUG = false;
+ // STOPSHIP: set it to false.
+ private static final boolean DEBUG = true;
private static final int RECOMMENDATION_COUNT = 6;
@@ -57,9 +58,9 @@ public class RecordedProgramPreviewUpdater {
private RecordedProgramPreviewUpdater(Context context) {
mContext = context.getApplicationContext();
- TvSingletons tvSingletons = TvSingletons.getSingletons(mContext);
- mPreviewDataManager = tvSingletons.getPreviewDataManager();
- mDvrDataManager = tvSingletons.getDvrDataManager();
+ ApplicationSingletons applicationSingletons = TvApplication.getSingletons(mContext);
+ mPreviewDataManager = applicationSingletons.getPreviewDataManager();
+ mDvrDataManager = applicationSingletons.getDvrDataManager();
mDvrDataManager.addRecordedProgramListener(
new DvrDataManager.RecordedProgramListener() {
@Override
diff --git a/src/com/android/tv/search/DataManagerSearch.java b/src/com/android/tv/search/DataManagerSearch.java
index 0d4a9dbc..a60355f4 100644
--- a/src/com/android/tv/search/DataManagerSearch.java
+++ b/src/com/android/tv/search/DataManagerSearch.java
@@ -26,7 +26,8 @@ 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.ApplicationSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
import com.android.tv.data.Program;
@@ -59,9 +60,9 @@ public class DataManagerSearch implements SearchInterface {
DataManagerSearch(Context context) {
mContext = context;
mTvInputManager = (TvInputManager) context.getSystemService(Context.TV_INPUT_SERVICE);
- TvSingletons tvSingletons = TvSingletons.getSingletons(context);
- mChannelDataManager = tvSingletons.getChannelDataManager();
- mProgramDataManager = tvSingletons.getProgramDataManager();
+ ApplicationSingletons appSingletons = TvApplication.getSingletons(context);
+ mChannelDataManager = appSingletons.getChannelDataManager();
+ mProgramDataManager = appSingletons.getProgramDataManager();
}
@Override
diff --git a/src/com/android/tv/search/LocalSearchProvider.java b/src/com/android/tv/search/LocalSearchProvider.java
index 579811e7..dfd585c3 100644
--- a/src/com/android/tv/search/LocalSearchProvider.java
+++ b/src/com/android/tv/search/LocalSearchProvider.java
@@ -27,13 +27,13 @@ import android.support.annotation.NonNull;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.Log;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.common.util.CommonUtils;
-import com.android.tv.common.util.PermissionUtils;
+import com.android.tv.common.TvCommonUtils;
import com.android.tv.perf.EventNames;
import com.android.tv.perf.PerformanceMonitor;
import com.android.tv.perf.TimerEvent;
+import com.android.tv.util.PermissionUtils;
import com.android.tv.util.TvUriMatcher;
import java.util.ArrayList;
import java.util.Arrays;
@@ -84,13 +84,13 @@ public class LocalSearchProvider extends ContentProvider {
@Override
public boolean onCreate() {
- mPerformanceMonitor = TvSingletons.getSingletons(getContext()).getPerformanceMonitor();
+ mPerformanceMonitor = TvApplication.getSingletons(getContext()).getPerformanceMonitor();
return true;
}
@VisibleForTesting
void setSearchInterface(SearchInterface searchInterface) {
- SoftPreconditions.checkState(CommonUtils.isRunningInTest());
+ SoftPreconditions.checkState(TvCommonUtils.isRunningInTest());
mSearchInterface = searchInterface;
}
diff --git a/src/com/android/tv/search/ProgramGuideSearchFragment.java b/src/com/android/tv/search/ProgramGuideSearchFragment.java
index d3fe1554..1ca86d22 100644
--- a/src/com/android/tv/search/ProgramGuideSearchFragment.java
+++ b/src/com/android/tv/search/ProgramGuideSearchFragment.java
@@ -40,8 +40,8 @@ import android.view.View;
import android.view.ViewGroup;
import com.android.tv.MainActivity;
import com.android.tv.R;
-import com.android.tv.common.util.PermissionUtils;
import com.android.tv.util.ImageLoader;
+import com.android.tv.util.PermissionUtils;
import java.util.List;
public class ProgramGuideSearchFragment extends SearchFragment {
@@ -83,8 +83,7 @@ public class ProgramGuideSearchFragment extends SearchFragment {
mMainCardHeight,
createImageLoaderCallback(cardView));
} else {
- cardView.setMainImage(
- mMainActivity.getDrawable(R.drawable.ic_live_channels_96x96));
+ cardView.setMainImage(mMainActivity.getDrawable(R.drawable.ic_launcher));
}
}
@@ -169,7 +168,7 @@ public class ProgramGuideSearchFragment extends SearchFragment {
View v = super.onCreateView(inflater, container, savedInstanceState);
v.setBackgroundResource(R.color.program_guide_scrim);
- setBadgeDrawable(mMainActivity.getDrawable(R.drawable.ic_live_channels_96x96));
+ setBadgeDrawable(mMainActivity.getDrawable(R.drawable.ic_launcher));
setSearchResultProvider(mSearchResultProvider);
setOnItemViewClickedListener(mItemClickedListener);
return v;
diff --git a/src/com/android/tv/search/TvProviderSearch.java b/src/com/android/tv/search/TvProviderSearch.java
index a8640538..d6cf9cc9 100644
--- a/src/com/android/tv/search/TvProviderSearch.java
+++ b/src/com/android/tv/search/TvProviderSearch.java
@@ -33,8 +33,8 @@ import android.support.annotation.WorkerThread;
import android.text.TextUtils;
import android.util.Log;
import com.android.tv.common.TvContentRatingCache;
-import com.android.tv.common.util.PermissionUtils;
import com.android.tv.search.LocalSearchProvider.SearchResult;
+import com.android.tv.util.PermissionUtils;
import com.android.tv.util.Utils;
import java.util.ArrayList;
import java.util.Collections;
@@ -48,7 +48,6 @@ import java.util.Objects;
import java.util.Set;
/** An implementation of {@link SearchInterface} to search query from TvProvider directly. */
-@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed
public class TvProviderSearch implements SearchInterface {
private static final String TAG = "TvProviderSearch";
private static final boolean DEBUG = false;
diff --git a/src/com/android/tv/setup/SystemSetupActivity.java b/src/com/android/tv/setup/SystemSetupActivity.java
index 3fefc0c8..df25afa6 100644
--- a/src/com/android/tv/setup/SystemSetupActivity.java
+++ b/src/com/android/tv/setup/SystemSetupActivity.java
@@ -24,12 +24,13 @@ import android.content.Intent;
import android.media.tv.TvInputInfo;
import android.os.Bundle;
import android.widget.Toast;
+import com.android.tv.ApplicationSingletons;
import com.android.tv.R;
import com.android.tv.SetupPassthroughActivity;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
+import com.android.tv.common.TvCommonUtils;
import com.android.tv.common.ui.setup.SetupActivity;
import com.android.tv.common.ui.setup.SetupMultiPaneFragment;
-import com.android.tv.common.util.CommonUtils;
import com.android.tv.onboarding.SetupSourcesFragment;
import com.android.tv.util.OnboardingUtils;
import com.android.tv.util.SetupUtils;
@@ -51,7 +52,7 @@ public class SystemSetupActivity extends SetupActivity {
finish();
return;
}
- TvSingletons singletons = TvSingletons.getSingletons(this);
+ ApplicationSingletons singletons = TvApplication.getSingletons(this);
mInputManager = singletons.getTvInputManagerHelper();
}
@@ -85,7 +86,7 @@ public class SystemSetupActivity extends SetupActivity {
params.getString(
SetupSourcesFragment.ACTION_PARAM_KEY_INPUT_ID);
TvInputInfo input = mInputManager.getTvInputInfo(inputId);
- Intent intent = CommonUtils.createSetupIntent(input);
+ Intent intent = TvCommonUtils.createSetupIntent(input);
if (intent == null) {
Toast.makeText(
this,
diff --git a/tuner/src/com/android/tv/tuner/ChannelScanFileParser.java b/src/com/android/tv/tuner/ChannelScanFileParser.java
index d2ed6c38..50153f89 100644
--- a/tuner/src/com/android/tv/tuner/ChannelScanFileParser.java
+++ b/src/com/android/tv/tuner/ChannelScanFileParser.java
@@ -44,15 +44,11 @@ public class ChannelScanFileParser {
public static ScanChannel forTuner(
int frequency, String modulation, Integer radioFrequencyNumber) {
return new ScanChannel(
- Channel.TunerType.TYPE_TUNER,
- frequency,
- modulation,
- null,
- radioFrequencyNumber);
+ Channel.TYPE_TUNER, frequency, modulation, null, radioFrequencyNumber);
}
public static ScanChannel forFile(int frequency, String filename) {
- return new ScanChannel(Channel.TunerType.TYPE_FILE, frequency, "file:", filename, null);
+ return new ScanChannel(Channel.TYPE_FILE, frequency, "file:", filename, null);
}
private ScanChannel(
diff --git a/tuner/src/com/android/tv/tuner/DvbDeviceAccessor.java b/src/com/android/tv/tuner/DvbDeviceAccessor.java
index 217433d2..217433d2 100644
--- a/tuner/src/com/android/tv/tuner/DvbDeviceAccessor.java
+++ b/src/com/android/tv/tuner/DvbDeviceAccessor.java
diff --git a/tuner/src/com/android/tv/tuner/DvbTunerHal.java b/src/com/android/tv/tuner/DvbTunerHal.java
index 8397400f..8397400f 100644
--- a/tuner/src/com/android/tv/tuner/DvbTunerHal.java
+++ b/src/com/android/tv/tuner/DvbTunerHal.java
diff --git a/tuner/src/com/android/tv/tuner/TunerHal.java b/src/com/android/tv/tuner/TunerHal.java
index 367ca929..c8db73c3 100644
--- a/tuner/src/com/android/tv/tuner/TunerHal.java
+++ b/src/com/android/tv/tuner/TunerHal.java
@@ -22,10 +22,7 @@ import android.support.annotation.StringDef;
import android.support.annotation.WorkerThread;
import android.util.Log;
import android.util.Pair;
-import com.android.tv.common.annotation.UsedByNative;
-import com.android.tv.common.BuildConfig;
-import com.android.tv.common.customization.CustomizationManager;
-
+import com.android.tv.customization.TvCustomizationManager;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
@@ -86,9 +83,7 @@ public abstract class TunerHal implements AutoCloseable {
protected static final int DEFAULT_VSB_TUNE_TIMEOUT_MS = 2000;
protected static final int DEFAULT_QAM_TUNE_TIMEOUT_MS = 4000; // Some device takes time for
// QAM256 tuning.
- @IntDef({
- BUILT_IN_TUNER_TYPE_LINUX_DVB
- })
+ @IntDef({BUILT_IN_TUNER_TYPE_LINUX_DVB})
@Retention(RetentionPolicy.SOURCE)
private @interface BuiltInTunerType {}
@@ -102,9 +97,7 @@ public abstract class TunerHal implements AutoCloseable {
private String mModulation;
static {
- if (!BuildConfig.NO_JNI_TEST) {
- System.loadLibrary("tunertvinput_jni");
- }
+ System.loadLibrary("tunertvinput_jni");
}
/**
@@ -159,7 +152,7 @@ public abstract class TunerHal implements AutoCloseable {
private static @BuiltInTunerType int getBuiltInTunerType(Context context) {
if (sBuiltInTunerType == null) {
sBuiltInTunerType = 0;
- if (CustomizationManager.hasLinuxDvbBuiltInTuner(context)
+ if (TvCustomizationManager.hasLinuxDvbBuiltInTuner(context)
&& DvbTunerHal.getNumberOfDevices(context) > 0) {
sBuiltInTunerType = BUILT_IN_TUNER_TYPE_LINUX_DVB;
}
@@ -343,7 +336,6 @@ public abstract class TunerHal implements AutoCloseable {
* Opens Linux DVB frontend device. This method is called from native JNI and used only for
* DvbTunerHal.
*/
- @UsedByNative("DvbManager.cpp")
protected int openDvbFrontEndFd() {
return -1;
}
@@ -352,7 +344,6 @@ public abstract class TunerHal implements AutoCloseable {
* Opens Linux DVB demux device. This method is called from native JNI and used only for
* DvbTunerHal.
*/
- @UsedByNative("DvbManager.cpp")
protected int openDvbDemuxFd() {
return -1;
}
@@ -361,7 +352,6 @@ public abstract class TunerHal implements AutoCloseable {
* Opens Linux DVB dvr device. This method is called from native JNI and used only for
* DvbTunerHal.
*/
- @UsedByNative("DvbManager.cpp")
protected int openDvbDvrFd() {
return -1;
}
diff --git a/src/com/android/tv/tuner/TunerInputController.java b/src/com/android/tv/tuner/TunerInputController.java
index 02611bbf..829bec1c 100644
--- a/src/com/android/tv/tuner/TunerInputController.java
+++ b/src/com/android/tv/tuner/TunerInputController.java
@@ -17,9 +17,6 @@
package com.android.tv.tuner;
import android.app.AlarmManager;
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -27,14 +24,10 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
-import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
@@ -45,94 +38,72 @@ import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
+import com.android.tv.Features;
import com.android.tv.R;
-import com.android.tv.Starter;
import com.android.tv.TvApplication;
-import com.android.tv.TvSingletons;
-import com.android.tv.common.BuildConfig;
-import com.android.tv.common.util.SystemPropertiesProxy;
-
-
-import com.android.tv.tuner.setup.BaseTunerSetupActivity;
+import com.android.tv.common.SoftPreconditions;
+import com.android.tv.tuner.setup.TunerSetupActivity;
+import com.android.tv.tuner.tvinput.TunerTvInputService;
+import com.android.tv.tuner.util.SystemPropertiesProxy;
import com.android.tv.tuner.util.TunerInputInfoUtils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
import java.util.Map;
-import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
- * Controls the package visibility of {@link BaseTunerTvInputService}.
+ * Controls the package visibility of {@link TunerTvInputService}.
*
* <p>Listens to broadcast intent for {@link Intent#ACTION_BOOT_COMPLETED}, {@code
* UsbManager.ACTION_USB_DEVICE_ATTACHED}, and {@code UsbManager.ACTION_USB_DEVICE_ATTACHED} to
* update the connection status of the supported USB TV tuners.
*/
public class TunerInputController {
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = true;
private static final String TAG = "TunerInputController";
private static final String PREFERENCE_IS_NETWORK_TUNER_ATTACHED = "network_tuner";
private static final String SECURITY_PATCH_LEVEL_KEY = "ro.build.version.security_patch";
private static final String SECURITY_PATCH_LEVEL_FORMAT = "yyyy-MM-dd";
- private static final String PLAY_STORE_LINK_TEMPLATE = "market://details?id=%s";
/** Action of {@link Intent} to check network connection repeatedly when it is necessary. */
- private static final String CHECKING_NETWORK_TUNER_STATUS =
- "com.android.tv.action.CHECKING_NETWORK_TUNER_STATUS";
+ private static final String CHECKING_NETWORK_CONNECTION =
+ "com.android.tv.action.CHECKING_NETWORK_CONNECTION";
private static final String EXTRA_CHECKING_DURATION =
"com.android.tv.action.extra.CHECKING_DURATION";
- private static final String EXTRA_DEVICE_IP = "com.android.tv.action.extra.DEVICE_IP";
private static final long INITIAL_CHECKING_DURATION_MS = TimeUnit.SECONDS.toMillis(10);
private static final long MAXIMUM_CHECKING_DURATION_MS = TimeUnit.MINUTES.toMillis(10);
- private static final String NOTIFICATION_CHANNEL_ID = "tuner_discovery_notification";
- // TODO: Load settings from XML file
private static final TunerDevice[] TUNER_DEVICES = {
new TunerDevice(0x2040, 0xb123, null), // WinTV-HVR-955Q
new TunerDevice(0x07ca, 0x0837, null), // AverTV Volar Hybrid Q
// WinTV-dualHD (bulk) will be supported after 2017 April security patch.
new TunerDevice(0x2040, 0x826d, "2017-04-01"), // WinTV-dualHD (bulk)
+ // STOPSHIP: Add WinTV-soloHD (Isoc) temporary for test. Remove this after test complete.
new TunerDevice(0x2040, 0x0264, null),
};
private static final int MSG_ENABLE_INPUT_SERVICE = 1000;
private static final long DVB_DRIVER_CHECK_DELAY_MS = 300;
- private final ComponentName usbTunerComponent;
- private final ComponentName networkTunerComponent;
- private final ComponentName builtInTunerComponent;
- private final Map<TunerDevice, ComponentName> mTunerServiceMapping = new HashMap<>();
-
- private final Map<ComponentName, String> mTunerApplicationNames = new HashMap<>();
- private final Map<ComponentName, String> mNotificationMessages = new HashMap<>();
- private final Map<ComponentName, Bitmap> mNotificationLargeIcons = new HashMap<>();
-
- private final CheckDvbDeviceHandler mHandler = new CheckDvbDeviceHandler(this);
-
- public TunerInputController(ComponentName embeddedTuner) {
- usbTunerComponent = embeddedTuner;
- networkTunerComponent = usbTunerComponent;
- builtInTunerComponent = usbTunerComponent;
- for (TunerDevice device : TUNER_DEVICES) {
- mTunerServiceMapping.put(device, usbTunerComponent);
- }
- }
-
/** Checks status of USB devices to see if there are available USB tuners connected. */
- public void onCheckingUsbTunerStatus(Context context, String action) {
- onCheckingUsbTunerStatus(context, action, mHandler);
+ public static void onCheckingUsbTunerStatus(Context context, String action) {
+ onCheckingUsbTunerStatus(context, action, new CheckDvbDeviceHandler());
}
- private void onCheckingUsbTunerStatus(
+ private static void onCheckingUsbTunerStatus(
Context context, String action, @NonNull CheckDvbDeviceHandler handler) {
- Set<TunerDevice> connectedUsbTuners = getConnectedUsbTuners(context);
+ SharedPreferences sharedPreferences =
+ PreferenceManager.getDefaultSharedPreferences(context);
+ if (TunerHal.useBuiltInTuner(context)) {
+ enableTunerTvInputService(context, true, false, TunerHal.TUNER_TYPE_BUILT_IN);
+ return;
+ }
+ // Falls back to the below to check USB tuner devices.
+ boolean enabled = isUsbTunerConnected(context);
handler.removeMessages(MSG_ENABLE_INPUT_SERVICE);
- if (!connectedUsbTuners.isEmpty()) {
+ if (enabled) {
// Need to check if DVB driver is accessible. Since the driver creation
// could be happen after the USB event, delay the checking by
// DVB_DRIVER_CHECK_DELAY_MS.
@@ -140,37 +111,45 @@ public class TunerInputController {
handler.obtainMessage(MSG_ENABLE_INPUT_SERVICE, context),
DVB_DRIVER_CHECK_DELAY_MS);
} else {
- handleTunerStatusChanged(
+ if (sharedPreferences.getBoolean(PREFERENCE_IS_NETWORK_TUNER_ATTACHED, false)) {
+ // Since network tuner is attached, do not disable TunerTvInput,
+ // just updates the TvInputInfo.
+ TunerInputInfoUtils.updateTunerInputInfo(context);
+ return;
+ }
+ enableTunerTvInputService(
context,
false,
- connectedUsbTuners,
+ false,
TextUtils.equals(action, UsbManager.ACTION_USB_DEVICE_DETACHED)
? TunerHal.TUNER_TYPE_USB
: null);
}
}
- private void onNetworkTunerChanged(Context context, boolean enabled) {
+ private static void onNetworkTunerChanged(Context context, boolean enabled) {
SharedPreferences sharedPreferences =
PreferenceManager.getDefaultSharedPreferences(context);
- if (sharedPreferences.contains(PREFERENCE_IS_NETWORK_TUNER_ATTACHED)
- && sharedPreferences.getBoolean(PREFERENCE_IS_NETWORK_TUNER_ATTACHED, false)
- == enabled) {
- // the status is not changed
- return;
- }
if (enabled) {
+ // Network tuner detection is initiated by UI. So the app should not
+ // be killed.
sharedPreferences.edit().putBoolean(PREFERENCE_IS_NETWORK_TUNER_ATTACHED, true).apply();
+ enableTunerTvInputService(context, true, true, TunerHal.TUNER_TYPE_NETWORK);
} else {
sharedPreferences
.edit()
.putBoolean(PREFERENCE_IS_NETWORK_TUNER_ATTACHED, false)
.apply();
+ if (!isUsbTunerConnected(context) && !TunerHal.useBuiltInTuner(context)) {
+ // Network tuner detection is initiated by UI. So the app should not
+ // be killed.
+ enableTunerTvInputService(context, false, true, TunerHal.TUNER_TYPE_NETWORK);
+ } else {
+ // Since USB tuner is attached, do not disable TunerTvInput,
+ // just updates the TvInputInfo.
+ TunerInputInfoUtils.updateTunerInputInfo(context);
+ }
}
- // Network tuner detection is initiated by UI. So the app should not
- // be killed.
- handleTunerStatusChanged(
- context, true, getConnectedUsbTuners(context), TunerHal.TUNER_TYPE_NETWORK);
}
/**
@@ -179,131 +158,75 @@ public class TunerInputController {
* @param context {@link Context} instance
* @return {@code true} if any tuner device we support is plugged in
*/
- private Set<TunerDevice> getConnectedUsbTuners(Context context) {
+ private static boolean isUsbTunerConnected(Context context) {
UsbManager manager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
Map<String, UsbDevice> deviceList = manager.getDeviceList();
String currentSecurityLevel =
SystemPropertiesProxy.getString(SECURITY_PATCH_LEVEL_KEY, null);
- Set<TunerDevice> devices = new HashSet<>();
for (UsbDevice device : deviceList.values()) {
if (DEBUG) {
Log.d(TAG, "Device: " + device);
}
for (TunerDevice tuner : TUNER_DEVICES) {
- if (tuner.equalsTo(device) && tuner.isSupported(currentSecurityLevel)) {
+ if (tuner.equals(device) && tuner.isSupported(currentSecurityLevel)) {
Log.i(TAG, "Tuner found");
- devices.add(tuner);
+ return true;
}
}
}
- return devices;
- }
-
- private void handleTunerStatusChanged(
- Context context,
- boolean forceDontKillApp,
- Set<TunerDevice> connectedUsbTuners,
- Integer triggerType) {
- Map<ComponentName, Integer> serviceToEnable = new HashMap<>();
- Set<ComponentName> serviceToDisable = new HashSet<>();
- serviceToDisable.add(builtInTunerComponent);
- serviceToDisable.add(networkTunerComponent);
- if (TunerFeatures.TUNER.isEnabled(context)) {
- // TODO: support both built-in tuner and other tuners at the same time?
- if (TunerHal.useBuiltInTuner(context)) {
- enableTunerTvInputService(
- context, true, false, TunerHal.TUNER_TYPE_BUILT_IN, builtInTunerComponent);
- return;
- }
- SharedPreferences sharedPreferences =
- PreferenceManager.getDefaultSharedPreferences(context);
- if (sharedPreferences.getBoolean(PREFERENCE_IS_NETWORK_TUNER_ATTACHED, false)) {
- serviceToEnable.put(networkTunerComponent, TunerHal.TUNER_TYPE_NETWORK);
- }
- }
- for (TunerDevice device : TUNER_DEVICES) {
- if (TunerFeatures.TUNER.isEnabled(context) && connectedUsbTuners.contains(device)) {
- serviceToEnable.put(mTunerServiceMapping.get(device), TunerHal.TUNER_TYPE_USB);
- } else {
- serviceToDisable.add(mTunerServiceMapping.get(device));
- }
- }
- serviceToDisable.removeAll(serviceToEnable.keySet());
- for (ComponentName serviceComponent : serviceToEnable.keySet()) {
- if (isTunerPackageInstalled(context, serviceComponent)) {
- enableTunerTvInputService(
- context,
- true,
- forceDontKillApp,
- serviceToEnable.get(serviceComponent),
- serviceComponent);
- } else {
- sendNotificationToInstallPackage(context, serviceComponent);
- }
- }
- for (ComponentName serviceComponent : serviceToDisable) {
- if (isTunerPackageInstalled(context, serviceComponent)) {
- enableTunerTvInputService(
- context, false, forceDontKillApp, triggerType, serviceComponent);
- } else {
- cancelNotificationToInstallPackage(context, serviceComponent);
- }
- }
+ return false;
}
/**
- * Enable/disable the component {@link BaseTunerTvInputService}.
+ * Enable/disable the component {@link TunerTvInputService}.
*
* @param context {@link Context} instance
* @param enabled {@code true} to enable the service; otherwise {@code false}
*/
private static void enableTunerTvInputService(
- Context context,
- boolean enabled,
- boolean forceDontKillApp,
- Integer tunerType,
- ComponentName serviceComponent) {
+ Context context, boolean enabled, boolean forceDontKillApp, Integer tunerType) {
if (DEBUG) Log.d(TAG, "enableTunerTvInputService: " + enabled);
PackageManager pm = context.getPackageManager();
+ ComponentName componentName = new ComponentName(context, TunerTvInputService.class);
+
+ // Don't kill app by enabling/disabling TvActivity. If LC is killed by enabling/disabling
+ // TvActivity, the following pm.setComponentEnabledSetting doesn't work.
+ ((TvApplication) context.getApplicationContext())
+ .handleInputCountChanged(true, enabled, true);
+ // Since PackageManager.DONT_KILL_APP delays the operation by 10 seconds
+ // (PackageManagerService.BROADCAST_DELAY), we'd better avoid using it. It is used only
+ // when the LiveChannels app is active since we don't want to kill the running app.
+ int flags =
+ forceDontKillApp
+ || TvApplication.getSingletons(context)
+ .getMainActivityWrapper()
+ .isCreated()
+ ? PackageManager.DONT_KILL_APP
+ : 0;
int newState =
enabled
? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
: PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
- if (newState != pm.getComponentEnabledSetting(serviceComponent)) {
- int flags = forceDontKillApp ? PackageManager.DONT_KILL_APP : 0;
- if (serviceComponent.getPackageName().equals(context.getPackageName())) {
- // Don't kill APP when handling input count changing. Or the following
- // setComponentEnabledSetting() call won't work.
- ((TvApplication) context.getApplicationContext())
- .handleInputCountChanged(true, enabled, true);
- // Bundled input. Don't kill app if LiveChannels app is active since we don't want
- // to kill the running app.
- if (TvSingletons.getSingletons(context).getMainActivityWrapper().isCreated()) {
- flags |= PackageManager.DONT_KILL_APP;
- }
- // Send/cancel the USB tuner TV input setup notification.
- BaseTunerSetupActivity.onTvInputEnabled(context, enabled, tunerType);
- if (!enabled && tunerType != null) {
- if (tunerType == TunerHal.TUNER_TYPE_USB) {
- Toast.makeText(
- context,
- R.string.msg_usb_tuner_disconnected,
- Toast.LENGTH_SHORT)
- .show();
- } else if (tunerType == TunerHal.TUNER_TYPE_NETWORK) {
- Toast.makeText(
- context,
- R.string.msg_network_tuner_disconnected,
- Toast.LENGTH_SHORT)
- .show();
- }
+ if (newState != pm.getComponentEnabledSetting(componentName)) {
+ // Send/cancel the USB tuner TV input setup notification.
+ TunerSetupActivity.onTvInputEnabled(context, enabled, tunerType);
+ // Enable/disable the USB tuner TV input.
+ pm.setComponentEnabledSetting(componentName, newState, flags);
+ if (!enabled && tunerType != null) {
+ if (tunerType == TunerHal.TUNER_TYPE_USB) {
+ Toast.makeText(context, R.string.msg_usb_tuner_disconnected, Toast.LENGTH_SHORT)
+ .show();
+ } else if (tunerType == TunerHal.TUNER_TYPE_NETWORK) {
+ Toast.makeText(
+ context,
+ R.string.msg_network_tuner_disconnected,
+ Toast.LENGTH_SHORT)
+ .show();
}
}
- // Enable/disable the USB tuner TV input.
- pm.setComponentEnabledSetting(serviceComponent, newState, flags);
if (DEBUG) Log.d(TAG, "Status updated:" + enabled);
- } else if (enabled && serviceComponent.getPackageName().equals(context.getPackageName())) {
+ } else if (enabled) {
// When # of tuners is changed or the tuner input service is switching from/to using
// network tuners or the device just boots.
TunerInputInfoUtils.updateTunerInputInfo(context);
@@ -313,50 +236,62 @@ public class TunerInputController {
/**
* Discovers a network tuner. If the network connection is down, it won't repeatedly checking.
*/
- public void executeNetworkTunerDiscoveryAsyncTask(final Context context) {
- executeNetworkTunerDiscoveryAsyncTask(context, 0, 0);
+ public static void executeNetworkTunerDiscoveryAsyncTask(final Context context) {
+ boolean runningInMainProcess =
+ TvApplication.getSingletons(context).isRunningInMainProcess();
+ SoftPreconditions.checkState(runningInMainProcess);
+ if (!runningInMainProcess) {
+ return;
+ }
+ executeNetworkTunerDiscoveryAsyncTask(context, 0);
}
/**
* Discovers a network tuner.
*
* @param context {@link Context}
- * @param repeatedDurationMs The time length to wait to repeatedly check network status to start
+ * @param repeatedDurationMs the time length to wait to repeatedly check network status to start
* finding network tuner when the network connection is not available. {@code 0} to disable
* repeatedly checking.
- * @param deviceIp The previous discovered device IP, 0 if none.
*/
- private void executeNetworkTunerDiscoveryAsyncTask(
- final Context context, final long repeatedDurationMs, final int deviceIp) {
- if (!TunerFeatures.NETWORK_TUNER.isEnabled(context)) {
+ private static void executeNetworkTunerDiscoveryAsyncTask(
+ final Context context, final long repeatedDurationMs) {
+ if (!Features.NETWORK_TUNER.isEnabled(context)) {
return;
}
- final Intent networkCheckingIntent = new Intent(context, IntentReceiver.class);
- networkCheckingIntent.setAction(CHECKING_NETWORK_TUNER_STATUS);
- if (!isNetworkConnected(context) && repeatedDurationMs > 0) {
- sendCheckingAlarm(context, networkCheckingIntent, repeatedDurationMs);
- } else {
- new AsyncTask<Void, Void, Boolean>() {
- @Override
- protected Boolean doInBackground(Void... params) {
- Boolean result = null;
+ new AsyncTask<Void, Void, Boolean>() {
+ @Override
+ protected Boolean doInBackground(Void... params) {
+ if (isNetworkConnected(context)) {
// Implement and execute network tuner discovery AsyncTask here.
- return result;
+ } else if (repeatedDurationMs > 0) {
+ AlarmManager alarmManager =
+ (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ Intent networkCheckingIntent = new Intent(context, IntentReceiver.class);
+ networkCheckingIntent.setAction(CHECKING_NETWORK_CONNECTION);
+ networkCheckingIntent.putExtra(EXTRA_CHECKING_DURATION, repeatedDurationMs);
+ PendingIntent alarmIntent =
+ PendingIntent.getBroadcast(
+ context,
+ 0,
+ networkCheckingIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ alarmManager.set(
+ AlarmManager.ELAPSED_REALTIME,
+ SystemClock.elapsedRealtime() + repeatedDurationMs,
+ alarmIntent);
}
+ return null;
+ }
- @Override
- protected void onPostExecute(Boolean foundNetworkTuner) {
- if (foundNetworkTuner == null) {
- return;
- }
- sendCheckingAlarm(
- context,
- networkCheckingIntent,
- foundNetworkTuner ? INITIAL_CHECKING_DURATION_MS : repeatedDurationMs);
- onNetworkTunerChanged(context, foundNetworkTuner);
+ @Override
+ protected void onPostExecute(Boolean result) {
+ if (result == null) {
+ return;
}
- }.execute();
- }
+ onNetworkTunerChanged(context, result);
+ }
+ }.execute();
}
private static boolean isNetworkConnected(Context context) {
@@ -366,119 +301,33 @@ public class TunerInputController {
return networkInfo != null && networkInfo.isConnected();
}
- private static void sendCheckingAlarm(Context context, Intent intent, long delayMs) {
- AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
- intent.putExtra(EXTRA_CHECKING_DURATION, delayMs);
- PendingIntent alarmIntent =
- PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
- alarmManager.set(
- AlarmManager.ELAPSED_REALTIME,
- SystemClock.elapsedRealtime() + delayMs,
- alarmIntent);
- }
-
- private static boolean isTunerPackageInstalled(
- Context context, ComponentName serviceComponent) {
- try {
- context.getPackageManager().getPackageInfo(serviceComponent.getPackageName(), 0);
- return true;
- } catch (NameNotFoundException e) {
- return false;
- }
- }
-
- private void sendNotificationToInstallPackage(Context context, ComponentName serviceComponent) {
- if (!BuildConfig.ENG) {
- return;
- }
- String applicationName = mTunerApplicationNames.get(serviceComponent);
- if (applicationName == null) {
- applicationName = context.getString(R.string.tuner_install_default_application_name);
- }
- String contentTitle =
- context.getString(
- R.string.tuner_install_notification_content_title, applicationName);
- String contentText = mNotificationMessages.get(serviceComponent);
- if (contentText == null) {
- contentText = context.getString(R.string.tuner_install_notification_content_text);
- }
- Bitmap largeIcon = mNotificationLargeIcons.get(serviceComponent);
- if (largeIcon == null) {
- // TODO: Make a better default image.
- largeIcon = BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_store);
- }
- NotificationManager notificationManager =
- (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
- if (notificationManager.getNotificationChannel(NOTIFICATION_CHANNEL_ID) == null) {
- createNotificationChannel(context, notificationManager);
- }
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(
- Uri.parse(
- String.format(
- PLAY_STORE_LINK_TEMPLATE, serviceComponent.getPackageName())));
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- Notification.Builder builder = new Notification.Builder(context, NOTIFICATION_CHANNEL_ID);
- builder.setAutoCancel(true)
- .setSmallIcon(R.drawable.ic_launcher_s)
- .setLargeIcon(largeIcon)
- .setContentTitle(contentTitle)
- .setContentText(contentText)
- .setCategory(Notification.CATEGORY_RECOMMENDATION)
- .setContentIntent(PendingIntent.getActivity(context, 0, intent, 0));
- notificationManager.notify(serviceComponent.getPackageName(), 0, builder.build());
- }
-
- private static void cancelNotificationToInstallPackage(
- Context context, ComponentName serviceComponent) {
- NotificationManager notificationManager =
- (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
- notificationManager.cancel(serviceComponent.getPackageName(), 0);
- }
-
- private static void createNotificationChannel(
- Context context, NotificationManager notificationManager) {
- notificationManager.createNotificationChannel(
- new NotificationChannel(
- NOTIFICATION_CHANNEL_ID,
- context.getResources()
- .getString(R.string.ut_setup_notification_channel_name),
- NotificationManager.IMPORTANCE_HIGH));
- }
-
public static class IntentReceiver extends BroadcastReceiver {
+ private final CheckDvbDeviceHandler mHandler = new CheckDvbDeviceHandler();
@Override
public void onReceive(Context context, Intent intent) {
if (DEBUG) Log.d(TAG, "Broadcast intent received:" + intent);
- Starter.start(context);
- TunerInputController tunerInputController =
- TvSingletons.getSingletons(context).getTunerInputController();
- if (!TunerFeatures.TUNER.isEnabled(context)) {
- tunerInputController.handleTunerStatusChanged(
- context, false, Collections.emptySet(), null);
+ TvApplication.setCurrentRunningProcess(context, true);
+ if (!Features.TUNER.isEnabled(context)) {
+ enableTunerTvInputService(context, false, false, null);
return;
}
switch (intent.getAction()) {
case Intent.ACTION_BOOT_COMPLETED:
- tunerInputController.executeNetworkTunerDiscoveryAsyncTask(
- context, INITIAL_CHECKING_DURATION_MS, 0);
- // fall through
+ executeNetworkTunerDiscoveryAsyncTask(context, INITIAL_CHECKING_DURATION_MS);
case TvApplication.ACTION_APPLICATION_FIRST_LAUNCHED:
case UsbManager.ACTION_USB_DEVICE_ATTACHED:
case UsbManager.ACTION_USB_DEVICE_DETACHED:
- tunerInputController.onCheckingUsbTunerStatus(context, intent.getAction());
+ onCheckingUsbTunerStatus(context, intent.getAction(), mHandler);
break;
- case CHECKING_NETWORK_TUNER_STATUS:
+ case CHECKING_NETWORK_CONNECTION:
long repeatedDurationMs =
intent.getLongExtra(
EXTRA_CHECKING_DURATION, INITIAL_CHECKING_DURATION_MS);
- tunerInputController.executeNetworkTunerDiscoveryAsyncTask(
+ executeNetworkTunerDiscoveryAsyncTask(
context,
- Math.min(repeatedDurationMs * 2, MAXIMUM_CHECKING_DURATION_MS),
- intent.getIntExtra(EXTRA_DEVICE_IP, 0));
+ Math.min(repeatedDurationMs * 2, MAXIMUM_CHECKING_DURATION_MS));
break;
- default: // fall out
}
}
}
@@ -500,7 +349,7 @@ public class TunerInputController {
this.minSecurityLevel = minSecurityLevel;
}
- private boolean equalsTo(UsbDevice device) {
+ private boolean equals(UsbDevice device) {
return device.getVendorId() == vendorId && device.getProductId() == productId;
}
@@ -523,13 +372,10 @@ public class TunerInputController {
}
private static class CheckDvbDeviceHandler extends Handler {
-
- private final TunerInputController mTunerInputController;
private DvbDeviceAccessor mDvbDeviceAccessor;
- CheckDvbDeviceHandler(TunerInputController tunerInputController) {
+ CheckDvbDeviceHandler() {
super(Looper.getMainLooper());
- this.mTunerInputController = tunerInputController;
}
@Override
@@ -541,15 +387,9 @@ public class TunerInputController {
mDvbDeviceAccessor = new DvbDeviceAccessor(context);
}
boolean enabled = mDvbDeviceAccessor.isDvbDeviceAvailable();
- mTunerInputController.handleTunerStatusChanged(
- context,
- false,
- enabled
- ? mTunerInputController.getConnectedUsbTuners(context)
- : Collections.emptySet(),
- TunerHal.TUNER_TYPE_USB);
+ enableTunerTvInputService(
+ context, enabled, false, enabled ? TunerHal.TUNER_TYPE_USB : null);
break;
- default: // fall out
}
}
}
diff --git a/common/src/com/android/tv/common/CommonPreferenceProvider.java b/src/com/android/tv/tuner/TunerPreferenceProvider.java
index 05eb2e7e..425c30ac 100644
--- a/common/src/com/android/tv/common/CommonPreferenceProvider.java
+++ b/src/com/android/tv/tuner/TunerPreferenceProvider.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.tv.common;
+package com.android.tv.tuner;
import android.content.ContentProvider;
import android.content.ContentValues;
@@ -27,11 +27,11 @@ import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
/**
- * A content provider for storing common preferences. It's used across TV app and tuner TV inputs.
+ * A content provider for storing the preferences. It's used across TV app and USB tuner TV input.
*/
-public class CommonPreferenceProvider extends ContentProvider {
+public class TunerPreferenceProvider extends ContentProvider {
/** The authority of the provider */
- public static final String AUTHORITY = "com.android.tv.common.preferences";
+ public static final String AUTHORITY = "com.android.tv.tuner.preferences";
private static final String PATH_PREFERENCES = "preferences";
diff --git a/common/src/com/android/tv/common/CommonPreferences.java b/src/com/android/tv/tuner/TunerPreferences.java
index 8023d739..62a4ce99 100644
--- a/common/src/com/android/tv/common/CommonPreferences.java
+++ b/src/com/android/tv/tuner/TunerPreferences.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.tv.common;
+
+package com.android.tv.tuner;
import android.content.ContentResolver;
import android.content.ContentValues;
@@ -27,34 +28,28 @@ import android.os.Handler;
import android.support.annotation.GuardedBy;
import android.support.annotation.IntDef;
import android.support.annotation.MainThread;
-import android.util.Log;
-import com.android.tv.common.CommonPreferenceProvider.Preferences;
-import com.android.tv.common.util.CommonUtils;
+import com.android.tv.common.SoftPreconditions;
+import com.android.tv.tuner.TunerPreferenceProvider.Preferences;
+import com.android.tv.tuner.util.TisConfiguration;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.HashMap;
-import java.util.Map;
-/** A helper class for setting/getting common preferences across applications. */
-@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed
-public class CommonPreferences {
- private static final String TAG = "CommonPreferences";
+/** A helper class for the USB tuner preferences. */
+public class TunerPreferences {
+ private static final String TAG = "TunerPreferences";
+ private static final String PREFS_KEY_CHANNEL_DATA_VERSION = "channel_data_version";
+ private static final String PREFS_KEY_SCANNED_CHANNEL_COUNT = "scanned_channel_count";
+ private static final String PREFS_KEY_LAST_POSTAL_CODE = "last_postal_code";
+ private static final String PREFS_KEY_SCAN_DONE = "scan_done";
private static final String PREFS_KEY_LAUNCH_SETUP = "launch_setup";
private static final String PREFS_KEY_STORE_TS_STREAM = "store_ts_stream";
private static final String PREFS_KEY_TRICKPLAY_SETTING = "trickplay_setting";
- private static final String PREFS_KEY_LAST_POSTAL_CODE = "last_postal_code";
+ private static final String PREFS_KEY_TRICKPLAY_EXPIRED_MS = "trickplay_expired_ms";
- private static final Map<String, Class> sPref2TypeMapping = new HashMap<>();
+ private static final String SHARED_PREFS_NAME = "com.android.tv.tuner.preferences";
- static {
- sPref2TypeMapping.put(PREFS_KEY_TRICKPLAY_SETTING, int.class);
- sPref2TypeMapping.put(PREFS_KEY_STORE_TS_STREAM, boolean.class);
- sPref2TypeMapping.put(PREFS_KEY_LAUNCH_SETUP, boolean.class);
- sPref2TypeMapping.put(PREFS_KEY_LAST_POSTAL_CODE, String.class);
- }
-
- private static final String SHARED_PREFS_NAME = "com.android.tv.common.preferences";
+ public static final int CHANNEL_DATA_VERSION_NOT_SET = -1;
@IntDef({TRICKPLAY_SETTING_NOT_SET, TRICKPLAY_SETTING_DISABLED, TRICKPLAY_SETTING_ENABLED})
@Retention(RetentionPolicy.SOURCE)
@@ -69,21 +64,21 @@ public class CommonPreferences {
/** Trickplay setting is enabled. */
public static final int TRICKPLAY_SETTING_ENABLED = 1;
- @GuardedBy("CommonPreferences.class")
+ @GuardedBy("TunerPreferences.class")
private static final Bundle sPreferenceValues = new Bundle();
private static LoadPreferencesTask sLoadPreferencesTask;
private static ContentObserver sContentObserver;
- private static CommonPreferencesChangedListener sPreferencesChangedListener = null;
+ private static TunerPreferencesChangedListener sPreferencesChangedListener = null;
- protected static boolean sInitialized;
+ private static boolean sInitialized;
- /** Listeners for CommonPreferences change. */
- public interface CommonPreferencesChangedListener {
- void onCommonPreferencesChanged();
+ /** Listeners for TunerPreferences change. */
+ public interface TunerPreferencesChangedListener {
+ void onTunerPreferencesChanged();
}
- /** Initializes the common preferences. */
+ /** Initializes the USB tuner preferences. */
@MainThread
public static void initialize(final Context context) {
if (sInitialized) {
@@ -100,7 +95,10 @@ public class CommonPreferences {
}
};
context.getContentResolver()
- .registerContentObserver(Preferences.CONTENT_URI, true, sContentObserver);
+ .registerContentObserver(
+ TunerPreferenceProvider.Preferences.CONTENT_URI,
+ true,
+ sContentObserver);
} else {
new AsyncTask<Void, Void, Void>() {
@Override
@@ -117,12 +115,12 @@ public class CommonPreferences {
if (useContentProvider(context) && sContentObserver != null) {
context.getContentResolver().unregisterContentObserver(sContentObserver);
}
- setCommonPreferencesChangedListener(null);
+ setTunerPreferencesChangedListener(null);
}
- /** Sets the listener for CommonPreferences change. */
- public static void setCommonPreferencesChangedListener(
- CommonPreferencesChangedListener listener) {
+ /** Sets the listener for TunerPreferences change. */
+ public static void setTunerPreferencesChangedListener(
+ TunerPreferencesChangedListener listener) {
sPreferencesChangedListener = listener;
}
@@ -144,7 +142,93 @@ public class CommonPreferences {
private static boolean useContentProvider(Context context) {
// If TIS is a part of LC, it should use ContentProvider to resolve multiple process access.
- return CommonUtils.isPackagedWithLiveChannels(context);
+ return TisConfiguration.isPackagedWithLiveChannels(context);
+ }
+
+ public static synchronized int getChannelDataVersion(Context context) {
+ SoftPreconditions.checkState(sInitialized);
+ if (useContentProvider(context)) {
+ return sPreferenceValues.getInt(
+ PREFS_KEY_CHANNEL_DATA_VERSION, CHANNEL_DATA_VERSION_NOT_SET);
+ } else {
+ return getSharedPreferences(context)
+ .getInt(
+ TunerPreferences.PREFS_KEY_CHANNEL_DATA_VERSION,
+ CHANNEL_DATA_VERSION_NOT_SET);
+ }
+ }
+
+ public static synchronized void setChannelDataVersion(Context context, int version) {
+ if (useContentProvider(context)) {
+ setPreference(context, PREFS_KEY_CHANNEL_DATA_VERSION, version);
+ } else {
+ getSharedPreferences(context)
+ .edit()
+ .putInt(TunerPreferences.PREFS_KEY_CHANNEL_DATA_VERSION, version)
+ .apply();
+ }
+ }
+
+ public static synchronized int getScannedChannelCount(Context context) {
+ SoftPreconditions.checkState(sInitialized);
+ if (useContentProvider(context)) {
+ return sPreferenceValues.getInt(PREFS_KEY_SCANNED_CHANNEL_COUNT);
+ } else {
+ return getSharedPreferences(context)
+ .getInt(TunerPreferences.PREFS_KEY_SCANNED_CHANNEL_COUNT, 0);
+ }
+ }
+
+ public static synchronized void setScannedChannelCount(Context context, int channelCount) {
+ if (useContentProvider(context)) {
+ setPreference(context, PREFS_KEY_SCANNED_CHANNEL_COUNT, channelCount);
+ } else {
+ getSharedPreferences(context)
+ .edit()
+ .putInt(TunerPreferences.PREFS_KEY_SCANNED_CHANNEL_COUNT, channelCount)
+ .apply();
+ }
+ }
+
+ public static synchronized String getLastPostalCode(Context context) {
+ SoftPreconditions.checkState(sInitialized);
+ if (useContentProvider(context)) {
+ return sPreferenceValues.getString(PREFS_KEY_LAST_POSTAL_CODE);
+ } else {
+ return getSharedPreferences(context).getString(PREFS_KEY_LAST_POSTAL_CODE, null);
+ }
+ }
+
+ public static synchronized void setLastPostalCode(Context context, String postalCode) {
+ if (useContentProvider(context)) {
+ setPreference(context, PREFS_KEY_LAST_POSTAL_CODE, postalCode);
+ } else {
+ getSharedPreferences(context)
+ .edit()
+ .putString(PREFS_KEY_LAST_POSTAL_CODE, postalCode)
+ .apply();
+ }
+ }
+
+ public static synchronized boolean isScanDone(Context context) {
+ SoftPreconditions.checkState(sInitialized);
+ if (useContentProvider(context)) {
+ return sPreferenceValues.getBoolean(PREFS_KEY_SCAN_DONE);
+ } else {
+ return getSharedPreferences(context)
+ .getBoolean(TunerPreferences.PREFS_KEY_SCAN_DONE, false);
+ }
+ }
+
+ public static synchronized void setScanDone(Context context) {
+ if (useContentProvider(context)) {
+ setPreference(context, PREFS_KEY_SCAN_DONE, true);
+ } else {
+ getSharedPreferences(context)
+ .edit()
+ .putBoolean(TunerPreferences.PREFS_KEY_SCAN_DONE, true)
+ .apply();
+ }
}
public static synchronized boolean shouldShowSetupActivity(Context context) {
@@ -152,7 +236,8 @@ public class CommonPreferences {
if (useContentProvider(context)) {
return sPreferenceValues.getBoolean(PREFS_KEY_LAUNCH_SETUP);
} else {
- return getSharedPreferences(context).getBoolean(PREFS_KEY_LAUNCH_SETUP, false);
+ return getSharedPreferences(context)
+ .getBoolean(TunerPreferences.PREFS_KEY_LAUNCH_SETUP, false);
}
}
@@ -160,75 +245,82 @@ public class CommonPreferences {
if (useContentProvider(context)) {
setPreference(context, PREFS_KEY_LAUNCH_SETUP, need);
} else {
- getSharedPreferences(context).edit().putBoolean(PREFS_KEY_LAUNCH_SETUP, need).apply();
+ getSharedPreferences(context)
+ .edit()
+ .putBoolean(TunerPreferences.PREFS_KEY_LAUNCH_SETUP, need)
+ .apply();
}
}
- public static synchronized @TrickplaySetting int getTrickplaySetting(Context context) {
+ public static synchronized long getTrickplayExpiredMs(Context context) {
SoftPreconditions.checkState(sInitialized);
if (useContentProvider(context)) {
- return sPreferenceValues.getInt(PREFS_KEY_TRICKPLAY_SETTING, TRICKPLAY_SETTING_NOT_SET);
+ return sPreferenceValues.getLong(PREFS_KEY_TRICKPLAY_EXPIRED_MS, 0);
} else {
return getSharedPreferences(context)
- .getInt(PREFS_KEY_TRICKPLAY_SETTING, TRICKPLAY_SETTING_NOT_SET);
+ .getLong(TunerPreferences.PREFS_KEY_TRICKPLAY_EXPIRED_MS, 0);
}
}
- public static synchronized void setTrickplaySetting(
- Context context, @TrickplaySetting int trickplaySetting) {
- SoftPreconditions.checkState(sInitialized);
- SoftPreconditions.checkArgument(trickplaySetting != TRICKPLAY_SETTING_NOT_SET);
+ public static synchronized void setTrickplayExpiredMs(Context context, long timeMs) {
if (useContentProvider(context)) {
- setPreference(context, PREFS_KEY_TRICKPLAY_SETTING, trickplaySetting);
+ setPreference(context, PREFS_KEY_TRICKPLAY_EXPIRED_MS, timeMs);
} else {
getSharedPreferences(context)
.edit()
- .putInt(PREFS_KEY_TRICKPLAY_SETTING, trickplaySetting)
+ .putLong(TunerPreferences.PREFS_KEY_TRICKPLAY_EXPIRED_MS, timeMs)
.apply();
}
}
- public static synchronized boolean getStoreTsStream(Context context) {
+ public static synchronized @TrickplaySetting int getTrickplaySetting(Context context) {
SoftPreconditions.checkState(sInitialized);
if (useContentProvider(context)) {
- return sPreferenceValues.getBoolean(PREFS_KEY_STORE_TS_STREAM, false);
+ return sPreferenceValues.getInt(PREFS_KEY_TRICKPLAY_SETTING, TRICKPLAY_SETTING_NOT_SET);
} else {
- return getSharedPreferences(context).getBoolean(PREFS_KEY_STORE_TS_STREAM, false);
+ return getSharedPreferences(context)
+ .getInt(
+ TunerPreferences.PREFS_KEY_TRICKPLAY_SETTING,
+ TRICKPLAY_SETTING_NOT_SET);
}
}
- public static synchronized void setStoreTsStream(Context context, boolean shouldStore) {
+ public static synchronized void setTrickplaySetting(
+ Context context, @TrickplaySetting int trickplaySetting) {
+ SoftPreconditions.checkState(sInitialized);
+ SoftPreconditions.checkArgument(trickplaySetting != TRICKPLAY_SETTING_NOT_SET);
if (useContentProvider(context)) {
- setPreference(context, PREFS_KEY_STORE_TS_STREAM, shouldStore);
+ setPreference(context, PREFS_KEY_TRICKPLAY_SETTING, trickplaySetting);
} else {
getSharedPreferences(context)
.edit()
- .putBoolean(PREFS_KEY_STORE_TS_STREAM, shouldStore)
+ .putInt(TunerPreferences.PREFS_KEY_TRICKPLAY_SETTING, trickplaySetting)
.apply();
}
}
- public static synchronized String getLastPostalCode(Context context) {
+ public static synchronized boolean getStoreTsStream(Context context) {
SoftPreconditions.checkState(sInitialized);
if (useContentProvider(context)) {
- return sPreferenceValues.getString(PREFS_KEY_LAST_POSTAL_CODE);
+ return sPreferenceValues.getBoolean(PREFS_KEY_STORE_TS_STREAM, false);
} else {
- return getSharedPreferences(context).getString(PREFS_KEY_LAST_POSTAL_CODE, null);
+ return getSharedPreferences(context)
+ .getBoolean(TunerPreferences.PREFS_KEY_STORE_TS_STREAM, false);
}
}
- public static synchronized void setLastPostalCode(Context context, String postalCode) {
+ public static synchronized void setStoreTsStream(Context context, boolean shouldStore) {
if (useContentProvider(context)) {
- setPreference(context, PREFS_KEY_LAST_POSTAL_CODE, postalCode);
+ setPreference(context, PREFS_KEY_STORE_TS_STREAM, shouldStore);
} else {
getSharedPreferences(context)
.edit()
- .putString(PREFS_KEY_LAST_POSTAL_CODE, postalCode)
+ .putBoolean(TunerPreferences.PREFS_KEY_STORE_TS_STREAM, shouldStore)
.apply();
}
}
- protected static SharedPreferences getSharedPreferences(Context context) {
+ private static SharedPreferences getSharedPreferences(Context context) {
return context.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE);
}
@@ -265,7 +357,7 @@ public class CommonPreferences {
resolver.insert(Preferences.CONTENT_URI, values);
} catch (Exception e) {
SoftPreconditions.warn(
- TAG, "setPreference", e, "Error writing preference values");
+ TAG, "setPreference", "Error writing preference values", e);
}
return null;
}
@@ -290,28 +382,32 @@ public class CommonPreferences {
while (!isCancelled() && cursor.moveToNext()) {
String key = cursor.getString(0);
String value = cursor.getString(1);
- Class prefClass = sPref2TypeMapping.get(key);
- if (prefClass == int.class) {
- try {
- bundle.putInt(key, Integer.parseInt(value));
- } catch (NumberFormatException e) {
- Log.w(TAG, "Invalid format, key=" + key + ", value=" + value);
- }
- } else if (prefClass == long.class) {
- try {
+ switch (key) {
+ case PREFS_KEY_TRICKPLAY_EXPIRED_MS:
bundle.putLong(key, Long.parseLong(value));
- } catch (NumberFormatException e) {
- Log.w(TAG, "Invalid format, key=" + key + ", value=" + value);
- }
- } else if (prefClass == boolean.class) {
- bundle.putBoolean(key, Boolean.parseBoolean(value));
- } else {
- bundle.putString(key, value);
+ break;
+ case PREFS_KEY_CHANNEL_DATA_VERSION:
+ case PREFS_KEY_SCANNED_CHANNEL_COUNT:
+ case PREFS_KEY_TRICKPLAY_SETTING:
+ try {
+ bundle.putInt(key, Integer.parseInt(value));
+ } catch (NumberFormatException e) {
+ // Does nothing.
+ }
+ break;
+ case PREFS_KEY_SCAN_DONE:
+ case PREFS_KEY_LAUNCH_SETUP:
+ case PREFS_KEY_STORE_TS_STREAM:
+ bundle.putBoolean(key, Boolean.parseBoolean(value));
+ break;
+ case PREFS_KEY_LAST_POSTAL_CODE:
+ bundle.putString(key, value);
+ break;
}
}
}
} catch (Exception e) {
- SoftPreconditions.warn(TAG, "getPreference", e, "Error querying preference values");
+ SoftPreconditions.warn(TAG, "getPreference", "Error querying preference values", e);
return null;
}
return bundle;
@@ -319,13 +415,13 @@ public class CommonPreferences {
@Override
protected void onPostExecute(Bundle bundle) {
- synchronized (CommonPreferences.class) {
+ synchronized (TunerPreferences.class) {
if (bundle != null) {
sPreferenceValues.putAll(bundle);
}
}
if (sPreferencesChangedListener != null) {
- sPreferencesChangedListener.onCommonPreferencesChanged();
+ sPreferencesChangedListener.onTunerPreferencesChanged();
}
}
}
diff --git a/tuner/src/com/android/tv/tuner/cc/CaptionLayout.java b/src/com/android/tv/tuner/cc/CaptionLayout.java
index eb9ad463..eb9ad463 100644
--- a/tuner/src/com/android/tv/tuner/cc/CaptionLayout.java
+++ b/src/com/android/tv/tuner/cc/CaptionLayout.java
diff --git a/tuner/src/com/android/tv/tuner/cc/CaptionTrackRenderer.java b/src/com/android/tv/tuner/cc/CaptionTrackRenderer.java
index bcb8e1c0..bcb8e1c0 100644
--- a/tuner/src/com/android/tv/tuner/cc/CaptionTrackRenderer.java
+++ b/src/com/android/tv/tuner/cc/CaptionTrackRenderer.java
diff --git a/tuner/src/com/android/tv/tuner/cc/CaptionWindowLayout.java b/src/com/android/tv/tuner/cc/CaptionWindowLayout.java
index 89c7b66b..e9371f94 100644
--- a/tuner/src/com/android/tv/tuner/cc/CaptionWindowLayout.java
+++ b/src/com/android/tv/tuner/cc/CaptionWindowLayout.java
@@ -39,13 +39,13 @@ import android.view.accessibility.CaptioningManager;
import android.view.accessibility.CaptioningManager.CaptionStyle;
import android.view.accessibility.CaptioningManager.CaptioningChangeListener;
import android.widget.RelativeLayout;
-import com.google.android.exoplayer.text.CaptionStyleCompat;
import com.android.tv.tuner.data.Cea708Data.CaptionPenAttr;
import com.android.tv.tuner.data.Cea708Data.CaptionPenColor;
import com.android.tv.tuner.data.Cea708Data.CaptionWindow;
import com.android.tv.tuner.data.Cea708Data.CaptionWindowAttr;
-import com.android.tv.tuner.exoplayer.text.SubtitleView;
import com.android.tv.tuner.layout.ScaledLayout;
+import com.google.android.exoplayer.text.CaptionStyleCompat;
+import com.google.android.exoplayer.text.SubtitleView;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
diff --git a/tuner/src/com/android/tv/tuner/cc/Cea708Parser.java b/src/com/android/tv/tuner/cc/Cea708Parser.java
index 4e080276..4e080276 100644
--- a/tuner/src/com/android/tv/tuner/cc/Cea708Parser.java
+++ b/src/com/android/tv/tuner/cc/Cea708Parser.java
diff --git a/tuner/src/com/android/tv/tuner/data/Cea708Data.java b/src/com/android/tv/tuner/data/Cea708Data.java
index 73a90181..73a90181 100644
--- a/tuner/src/com/android/tv/tuner/data/Cea708Data.java
+++ b/src/com/android/tv/tuner/data/Cea708Data.java
diff --git a/tuner/src/com/android/tv/tuner/data/PsiData.java b/src/com/android/tv/tuner/data/PsiData.java
index 9b7c2e2c..9b7c2e2c 100644
--- a/tuner/src/com/android/tv/tuner/data/PsiData.java
+++ b/src/com/android/tv/tuner/data/PsiData.java
diff --git a/tuner/src/com/android/tv/tuner/data/PsipData.java b/src/com/android/tv/tuner/data/PsipData.java
index 239009dc..6459004c 100644
--- a/tuner/src/com/android/tv/tuner/data/PsipData.java
+++ b/src/com/android/tv/tuner/data/PsipData.java
@@ -19,11 +19,11 @@ package com.android.tv.tuner.data;
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.nano.Track.AtscAudioTrack;
import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack;
import com.android.tv.tuner.ts.SectionParser;
import com.android.tv.tuner.util.ConvertUtils;
+import com.android.tv.util.StringUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
diff --git a/tuner/src/com/android/tv/tuner/data/TunerChannel.java b/src/com/android/tv/tuner/data/TunerChannel.java
index d20c343b..52356c2e 100644
--- a/tuner/src/com/android/tv/tuner/data/TunerChannel.java
+++ b/src/com/android/tv/tuner/data/TunerChannel.java
@@ -16,15 +16,14 @@
package com.android.tv.tuner.data;
-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.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.android.tv.util.StringUtils;
import com.google.protobuf.nano.MessageNano;
import java.io.IOException;
import java.util.ArrayList;
@@ -55,7 +54,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];
+ ATSC_SERVICE_TYPE_NAMES[Channel.SERVICE_TYPE_ATSC_RESERVED];
public static final int INVALID_FREQUENCY = -1;
@@ -105,22 +104,22 @@ public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracks
for (PsiData.PmtItem pmt : pmtItems) {
switch (pmt.getStreamType()) {
// MPEG ES stream video types
- case Channel.VideoStreamType.MPEG1:
- case Channel.VideoStreamType.MPEG2:
- case Channel.VideoStreamType.H263:
- case Channel.VideoStreamType.H264:
- case Channel.VideoStreamType.H265:
+ case Channel.MPEG1:
+ case Channel.MPEG2:
+ case Channel.H263:
+ case Channel.H264:
+ case Channel.H265:
mProto.videoPid = pmt.getEsPid();
mProto.videoStreamType = pmt.getStreamType();
break;
// MPEG ES stream audio types
- case Channel.AudioStreamType.MPEG1AUDIO:
- case Channel.AudioStreamType.MPEG2AUDIO:
- case Channel.AudioStreamType.MPEG2AACAUDIO:
- case Channel.AudioStreamType.MPEG4LATMAACAUDIO:
- case Channel.AudioStreamType.A52AC3AUDIO:
- case Channel.AudioStreamType.EAC3AUDIO:
+ case Channel.MPEG1AUDIO:
+ case Channel.MPEG2AUDIO:
+ case Channel.MPEG2AACAUDIO:
+ case Channel.MPEG4LATMAACAUDIO:
+ case Channel.A52AC3AUDIO:
+ case Channel.EAC3AUDIO:
audioPids.add(pmt.getEsPid());
audioStreamTypes.add(pmt.getStreamType());
break;
@@ -129,8 +128,6 @@ public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracks
case 0x100: // PmtItem.ES_PID_PCR:
mProto.pcrPid = pmt.getEsPid();
break;
- default:
- // fall out
}
}
mProto.audioPids = Ints.toArray(audioPids);
@@ -157,17 +154,17 @@ public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracks
/** Initialize tuner channel with VCT items and PMT items. */
public TunerChannel(PsipData.VctItem channel, List<PsiData.PmtItem> pmtItems) {
- this(channel, 0, pmtItems, Channel.TunerType.TYPE_TUNER);
+ this(channel, 0, pmtItems, Channel.TYPE_TUNER);
}
/** Initialize tuner channel with program number and PMT items. */
public TunerChannel(int programNumber, List<PsiData.PmtItem> pmtItems) {
- this(null, programNumber, pmtItems, Channel.TunerType.TYPE_TUNER);
+ this(null, programNumber, pmtItems, Channel.TYPE_TUNER);
}
/** Initialize tuner channel with SDT items and PMT items. */
public TunerChannel(PsipData.SdtItem channel, List<PsiData.PmtItem> pmtItems) {
- this(0, Channel.TunerType.TYPE_TUNER, channel, pmtItems);
+ this(0, Channel.TYPE_TUNER, channel, pmtItems);
}
private TunerChannel(TunerChannelProto tunerChannelProto) {
@@ -175,12 +172,12 @@ public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracks
}
public static TunerChannel forFile(PsipData.VctItem channel, List<PsiData.PmtItem> pmtItems) {
- return new TunerChannel(channel, 0, pmtItems, Channel.TunerType.TYPE_FILE);
+ return new TunerChannel(channel, 0, pmtItems, Channel.TYPE_FILE);
}
public static TunerChannel forDvbFile(
PsipData.SdtItem channel, List<PsiData.PmtItem> pmtItems) {
- return new TunerChannel(0, Channel.TunerType.TYPE_FILE, channel, pmtItems);
+ return new TunerChannel(0, Channel.TYPE_FILE, channel, pmtItems);
}
/**
@@ -213,11 +210,7 @@ public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracks
boolean recordingProhibited,
String videoFormat) {
TunerChannel tunerChannel =
- new TunerChannel(
- null,
- programNumber,
- Collections.EMPTY_LIST,
- Channel.TunerType.TYPE_NETWORK);
+ new TunerChannel(null, programNumber, Collections.EMPTY_LIST, Channel.TYPE_NETWORK);
tunerChannel.setVirtualMajor(major);
tunerChannel.setVirtualMinor(minor);
tunerChannel.setShortName(shortName);
@@ -370,22 +363,6 @@ public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracks
mProto.channelId = channelId;
}
- /**
- * 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>
- */
- public boolean isLocked() {
- return mProto.locked;
- }
-
- public synchronized void setLocked(boolean locked) {
- mProto.locked = locked;
- }
-
public String getDisplayNumber() {
return getDisplayNumber(true);
}
@@ -460,7 +437,7 @@ public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracks
@Override
public String toString() {
switch (mProto.type) {
- case Channel.TunerType.TYPE_FILE:
+ case Channel.TYPE_FILE:
return String.format(
"{%d-%d %s} Filepath: %s, ProgramNumber %d",
mProto.virtualMajor,
@@ -468,7 +445,7 @@ public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracks
mProto.shortName,
mProto.filepath,
mProto.programNumber);
- // case Channel.TunerType.TYPE_TUNER:
+ // case Channel.TYPE_TUNER:
default:
return String.format(
"{%d-%d %s} Frequency: %d, ProgramNumber %d",
@@ -537,16 +514,4 @@ public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracks
return null;
}
}
-
- public static TunerChannel fromCursor(Cursor cursor) {
- long channelId = cursor.getLong(0);
- boolean locked = cursor.getInt(1) > 0;
- byte[] data = cursor.getBlob(2);
- TunerChannel channel = TunerChannel.parseFrom(data);
- if (channel != null) {
- channel.setChannelId(channelId);
- channel.setLocked(locked);
- }
- return channel;
- }
}
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/Cea708TextTrackRenderer.java b/src/com/android/tv/tuner/exoplayer/Cea708TextTrackRenderer.java
index 21e650a2..1f48c45b 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/Cea708TextTrackRenderer.java
+++ b/src/com/android/tv/tuner/exoplayer/Cea708TextTrackRenderer.java
@@ -17,6 +17,8 @@
package com.android.tv.tuner.exoplayer;
import android.util.Log;
+import com.android.tv.tuner.cc.Cea708Parser;
+import com.android.tv.tuner.data.Cea708Data.CaptionEvent;
import com.google.android.exoplayer.ExoPlaybackException;
import com.google.android.exoplayer.MediaClock;
import com.google.android.exoplayer.MediaFormat;
@@ -25,8 +27,6 @@ import com.google.android.exoplayer.SampleHolder;
import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.util.Assertions;
-import com.android.tv.tuner.cc.Cea708Parser;
-import com.android.tv.tuner.data.Cea708Data.CaptionEvent;
import java.io.IOException;
/** A {@link TrackRenderer} for CEA-708 textual subtitles. */
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/ExoPlayerExtractorsFactory.java b/src/com/android/tv/tuner/exoplayer/ExoPlayerExtractorsFactory.java
index dc08c072..b5369d69 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/ExoPlayerExtractorsFactory.java
+++ b/src/com/android/tv/tuner/exoplayer/ExoPlayerExtractorsFactory.java
@@ -17,9 +17,9 @@ package com.android.tv.tuner.exoplayer;
import com.google.android.exoplayer2.extractor.Extractor;
import com.google.android.exoplayer2.extractor.ExtractorsFactory;
+import com.google.android.exoplayer2.extractor.TimestampAdjuster;
import com.google.android.exoplayer2.extractor.ts.DefaultTsPayloadReaderFactory;
import com.google.android.exoplayer2.extractor.ts.TsExtractor;
-import com.google.android.exoplayer2.util.TimestampAdjuster;
/**
* Extractor factory, mainly aim at create TsExtractor with FLAG_ALLOW_NON_IDR_KEYFRAMES flags for
@@ -31,10 +31,10 @@ public final class ExoPlayerExtractorsFactory implements ExtractorsFactory {
// Only create TsExtractor since we only target MPEG2TS stream.
Extractor[] extractors = {
new TsExtractor(
- TsExtractor.MODE_SINGLE_PMT,
new TimestampAdjuster(0),
new DefaultTsPayloadReaderFactory(
- DefaultTsPayloadReaderFactory.FLAG_ALLOW_NON_IDR_KEYFRAMES))
+ DefaultTsPayloadReaderFactory.FLAG_ALLOW_NON_IDR_KEYFRAMES),
+ false)
};
return extractors;
}
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/ExoPlayerSampleExtractor.java b/src/com/android/tv/tuner/exoplayer/ExoPlayerSampleExtractor.java
index 6fcdeb40..df520900 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/ExoPlayerSampleExtractor.java
+++ b/src/com/android/tv/tuner/exoplayer/ExoPlayerSampleExtractor.java
@@ -24,6 +24,11 @@ import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
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.RecordingSampleBuffer;
+import com.android.tv.tuner.exoplayer.buffer.SimpleSampleBuffer;
+import com.android.tv.tuner.tvinput.PlaybackBufferListener;
import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.MediaFormatHolder;
import com.google.android.exoplayer.SampleHolder;
@@ -43,14 +48,10 @@ import com.google.android.exoplayer2.trackselection.FixedTrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.DefaultAllocator;
-import com.android.tv.tuner.exoplayer.audio.MpegTsDefaultAudioTrackRenderer;
-import com.android.tv.tuner.exoplayer.buffer.BufferManager;
-import com.android.tv.tuner.exoplayer.buffer.RecordingSampleBuffer;
-import com.android.tv.tuner.exoplayer.buffer.SimpleSampleBuffer;
-import com.android.tv.tuner.tvinput.PlaybackBufferListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -79,7 +80,7 @@ public class ExoPlayerSampleExtractor implements SampleExtractor {
private boolean mVideoTrackMet;
private long mBaseSamplePts = Long.MIN_VALUE;
private HashMap<Integer, Long> mLastExtractedPositionUsMap = new HashMap<>();
- private final List<Pair<Integer, SampleHolder>> mPendingSamples = new ArrayList<>();
+ private final List<Pair<Integer, SampleHolder>> mPendingSamples = new LinkedList<>();
private OnCompletionListener mOnCompletionListener;
private Handler mOnCompletionListenerHandler;
private IOException mError;
@@ -201,8 +202,7 @@ public class ExoPlayerSampleExtractor implements SampleExtractor {
false,
new MediaSource.Listener() {
@Override
- public void onSourceInfoRefreshed(
- MediaSource source, Timeline timeline, Object manifest) {
+ public void onSourceInfoRefreshed(Timeline timeline, Object manifest) {
// Dynamic stream change is not supported yet. b/28169263
// For now, this will cause EOS and playback reset.
}
@@ -238,9 +238,7 @@ public class ExoPlayerSampleExtractor implements SampleExtractor {
format.rotationDegrees,
format.pixelWidthHeightRatio,
format.projectionData,
- format.stereoMode,
- null // colorInfo
- );
+ format.stereoMode);
} else if (format.sampleMimeType.endsWith("/cea-608")
|| format.sampleMimeType.startsWith("text/")) {
return MediaFormat.createTextFormat(
@@ -270,8 +268,8 @@ public class ExoPlayerSampleExtractor implements SampleExtractor {
for (int i = 0; i < selections.length; ++i) {
selections[i] = selectionFactory.createTrackSelection(trackGroupArray.get(i), 0);
}
- boolean[] retain = new boolean[trackGroupArray.length];
- boolean[] reset = new boolean[trackGroupArray.length];
+ boolean retain[] = new boolean[trackGroupArray.length];
+ boolean reset[] = new boolean[trackGroupArray.length];
mStreams = new SampleStream[trackGroupArray.length];
mMediaPeriod.selectTracks(selections, retain, mStreams, reset, 0);
if (mTrackFormats == null) {
@@ -323,9 +321,10 @@ public class ExoPlayerSampleExtractor implements SampleExtractor {
mPrepareRequested = true;
mMediaPeriod =
mSampleSource.createPeriod(
- new MediaSource.MediaPeriodId(0),
- new DefaultAllocator(true, C.DEFAULT_BUFFER_SEGMENT_SIZE));
- mMediaPeriod.prepare(this, 0);
+ 0,
+ new DefaultAllocator(true, C.DEFAULT_BUFFER_SEGMENT_SIZE),
+ 0);
+ mMediaPeriod.prepare(this);
try {
mMediaPeriod.maybeThrowPrepareError();
} catch (IOException e) {
@@ -339,7 +338,8 @@ public class ExoPlayerSampleExtractor implements SampleExtractor {
int trackCount = mStreams.length;
for (int i = 0; i < trackCount; ++i) {
if (!mTrackMetEos[i]
- && C.RESULT_NOTHING_READ != fetchSample(i, conditionVariable)) {
+ && C.RESULT_NOTHING_READ
+ != fetchSample(i, mSampleHolder, conditionVariable)) {
if (mMetEos) {
// If mMetEos was on during fetchSample() due to an error,
// fetching from other tracks is not necessary.
@@ -369,24 +369,21 @@ public class ExoPlayerSampleExtractor implements SampleExtractor {
cleanUp();
mSourceReaderHandler.removeCallbacksAndMessages(null);
return true;
- default: // fall out
}
return false;
}
- private int fetchSample(int track, ConditionVariable conditionVariable) {
+ private int fetchSample(
+ int track, SampleHolder sample, ConditionVariable conditionVariable) {
FormatHolder dummyFormatHolder = new FormatHolder();
mDecoderInputBuffer.clear();
- int ret = mStreams[track].readData(dummyFormatHolder, mDecoderInputBuffer, false);
+ int ret = mStreams[track].readData(dummyFormatHolder, mDecoderInputBuffer);
if (ret == C.RESULT_BUFFER_READ
// Double-check if the extractor provided the data to prevent NPE. b/33758354
&& mDecoderInputBuffer.data != null) {
if (mCurrentPosition < mDecoderInputBuffer.timeUs) {
mCurrentPosition = mDecoderInputBuffer.timeUs;
}
- if (mMediaPeriod != null) {
- mMediaPeriod.discardBuffer(mCurrentPosition, false);
- }
try {
Long lastExtractedPositionUs = mLastExtractedPositionUsMap.get(track);
if (lastExtractedPositionUs == null) {
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/FileSampleExtractor.java b/src/com/android/tv/tuner/exoplayer/FileSampleExtractor.java
index f9cdb2fb..e7224422 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/FileSampleExtractor.java
+++ b/src/com/android/tv/tuner/exoplayer/FileSampleExtractor.java
@@ -17,13 +17,13 @@
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.RecordingSampleBuffer;
+import com.android.tv.tuner.tvinput.PlaybackBufferListener;
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.android.tv.tuner.exoplayer.buffer.BufferManager;
-import com.android.tv.tuner.exoplayer.buffer.RecordingSampleBuffer;
-import com.android.tv.tuner.tvinput.PlaybackBufferListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/MpegTsPlayer.java b/src/com/android/tv/tuner/exoplayer/MpegTsPlayer.java
index a8a96123..a49cbfaf 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/MpegTsPlayer.java
+++ b/src/com/android/tv/tuner/exoplayer/MpegTsPlayer.java
@@ -23,6 +23,16 @@ import android.media.PlaybackParams;
import android.os.Handler;
import android.support.annotation.IntDef;
import android.view.Surface;
+import com.android.tv.common.SoftPreconditions;
+import com.android.tv.tuner.data.Cea708Data;
+import com.android.tv.tuner.data.Cea708Data.CaptionEvent;
+import com.android.tv.tuner.data.TunerChannel;
+import com.android.tv.tuner.exoplayer.audio.MpegTsDefaultAudioTrackRenderer;
+import com.android.tv.tuner.exoplayer.audio.MpegTsMediaCodecAudioTrackRenderer;
+import com.android.tv.tuner.source.TsDataSource;
+import com.android.tv.tuner.source.TsDataSourceManager;
+import com.android.tv.tuner.tvinput.EventDetector;
+import com.android.tv.tuner.tvinput.TunerDebug;
import com.google.android.exoplayer.DummyTrackRenderer;
import com.google.android.exoplayer.ExoPlaybackException;
import com.google.android.exoplayer.ExoPlayer;
@@ -34,16 +44,6 @@ import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.audio.AudioCapabilities;
import com.google.android.exoplayer.audio.AudioTrack;
import com.google.android.exoplayer.upstream.DataSource;
-import com.android.tv.common.SoftPreconditions;
-import com.android.tv.tuner.data.Cea708Data;
-import com.android.tv.tuner.data.Cea708Data.CaptionEvent;
-import com.android.tv.tuner.data.TunerChannel;
-import com.android.tv.tuner.exoplayer.audio.MpegTsDefaultAudioTrackRenderer;
-import com.android.tv.tuner.exoplayer.audio.MpegTsMediaCodecAudioTrackRenderer;
-import com.android.tv.tuner.source.TsDataSource;
-import com.android.tv.tuner.source.TsDataSourceManager;
-import com.android.tv.tuner.tvinput.EventDetector;
-import com.android.tv.tuner.tvinput.TunerDebug;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/MpegTsRendererBuilder.java b/src/com/android/tv/tuner/exoplayer/MpegTsRendererBuilder.java
index f429505f..c7f5b333 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/MpegTsRendererBuilder.java
+++ b/src/com/android/tv/tuner/exoplayer/MpegTsRendererBuilder.java
@@ -17,16 +17,16 @@
package com.android.tv.tuner.exoplayer;
import android.content.Context;
-import com.google.android.exoplayer.MediaCodecSelector;
-import com.google.android.exoplayer.SampleSource;
-import com.google.android.exoplayer.TrackRenderer;
-import com.google.android.exoplayer.upstream.DataSource;
-import com.android.tv.tuner.TunerFeatures;
+import com.android.tv.Features;
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.tvinput.PlaybackBufferListener;
+import com.google.android.exoplayer.MediaCodecSelector;
+import com.google.android.exoplayer.SampleSource;
+import com.google.android.exoplayer.TrackRenderer;
+import com.google.android.exoplayer.upstream.DataSource;
/** Builder for renderer objects for {@link MpegTsPlayer}. */
public class MpegTsRendererBuilder implements RendererBuilder {
@@ -65,7 +65,7 @@ public class MpegTsRendererBuilder implements RendererBuilder {
mpegTsPlayer.getMainHandler(),
mpegTsPlayer,
mHasSoftwareAudioDecoder,
- !TunerFeatures.AC3_SOFTWARE_DECODE.isEnabled(mContext));
+ !Features.AC3_SOFTWARE_DECODE.isEnabled(mContext));
Cea708TextTrackRenderer textRenderer = new Cea708TextTrackRenderer(sampleSource);
TrackRenderer[] renderers = new TrackRenderer[MpegTsPlayer.RENDERER_COUNT];
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/MpegTsSampleExtractor.java b/src/com/android/tv/tuner/exoplayer/MpegTsSampleExtractor.java
index a8dd3d37..593b576e 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/MpegTsSampleExtractor.java
+++ b/src/com/android/tv/tuner/exoplayer/MpegTsSampleExtractor.java
@@ -18,15 +18,15 @@ package com.android.tv.tuner.exoplayer;
import android.net.Uri;
import android.os.Handler;
+import com.android.tv.tuner.exoplayer.buffer.BufferManager;
+import com.android.tv.tuner.exoplayer.buffer.SamplePool;
+import com.android.tv.tuner.tvinput.PlaybackBufferListener;
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.android.tv.tuner.exoplayer.buffer.BufferManager;
-import com.android.tv.tuner.exoplayer.buffer.SamplePool;
-import com.android.tv.tuner.tvinput.PlaybackBufferListener;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/MpegTsSampleSource.java b/src/com/android/tv/tuner/exoplayer/MpegTsSampleSource.java
index 3b5d1011..3b5d1011 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/MpegTsSampleSource.java
+++ b/src/com/android/tv/tuner/exoplayer/MpegTsSampleSource.java
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/MpegTsVideoTrackRenderer.java b/src/com/android/tv/tuner/exoplayer/MpegTsVideoTrackRenderer.java
index 63d72c5f..c4400b47 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/MpegTsVideoTrackRenderer.java
+++ b/src/com/android/tv/tuner/exoplayer/MpegTsVideoTrackRenderer.java
@@ -1,24 +1,10 @@
-/*
- * 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;
import android.content.Context;
import android.media.MediaCodec;
import android.os.Handler;
import android.util.Log;
+import com.android.tv.common.feature.CommonFeatures;
import com.google.android.exoplayer.DecoderInfo;
import com.google.android.exoplayer.ExoPlaybackException;
import com.google.android.exoplayer.MediaCodecSelector;
@@ -27,7 +13,6 @@ import com.google.android.exoplayer.MediaCodecVideoTrackRenderer;
import com.google.android.exoplayer.MediaFormatHolder;
import com.google.android.exoplayer.MediaSoftwareCodecUtil;
import com.google.android.exoplayer.SampleSource;
-import com.android.tv.tuner.TunerFeatures;
import java.lang.reflect.Field;
/** MPEG-2 TS video track renderer */
@@ -70,7 +55,7 @@ public class MpegTsVideoTrackRenderer extends MediaCodecVideoTrackRenderer {
handler,
listener,
DROPPED_FRAMES_NOTIFICATION_THRESHOLD);
- mIsSwCodecEnabled = TunerFeatures.USE_SW_CODEC_FOR_SD.isEnabled(context);
+ mIsSwCodecEnabled = CommonFeatures.USE_SW_CODEC_FOR_SD.isEnabled(context);
}
@Override
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/SampleExtractor.java b/src/com/android/tv/tuner/exoplayer/SampleExtractor.java
index 256aea92..256aea92 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/SampleExtractor.java
+++ b/src/com/android/tv/tuner/exoplayer/SampleExtractor.java
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/audio/AudioClock.java b/src/com/android/tv/tuner/exoplayer/audio/AudioClock.java
index 13eabc3a..13eabc3a 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/audio/AudioClock.java
+++ b/src/com/android/tv/tuner/exoplayer/audio/AudioClock.java
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/audio/AudioDecoder.java b/src/com/android/tv/tuner/exoplayer/audio/AudioDecoder.java
index fa489883..fa489883 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/audio/AudioDecoder.java
+++ b/src/com/android/tv/tuner/exoplayer/audio/AudioDecoder.java
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/audio/AudioTrackMonitor.java b/src/com/android/tv/tuner/exoplayer/audio/AudioTrackMonitor.java
index 28389017..28389017 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/audio/AudioTrackMonitor.java
+++ b/src/com/android/tv/tuner/exoplayer/audio/AudioTrackMonitor.java
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/audio/AudioTrackWrapper.java b/src/com/android/tv/tuner/exoplayer/audio/AudioTrackWrapper.java
index 7446c923..7446c923 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/audio/AudioTrackWrapper.java
+++ b/src/com/android/tv/tuner/exoplayer/audio/AudioTrackWrapper.java
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/audio/MediaCodecAudioDecoder.java b/src/com/android/tv/tuner/exoplayer/audio/MediaCodecAudioDecoder.java
index 80f91ebd..80f91ebd 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/audio/MediaCodecAudioDecoder.java
+++ b/src/com/android/tv/tuner/exoplayer/audio/MediaCodecAudioDecoder.java
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/audio/MpegTsDefaultAudioTrackRenderer.java b/src/com/android/tv/tuner/exoplayer/audio/MpegTsDefaultAudioTrackRenderer.java
index fd9299c2..ae18e05d 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/audio/MpegTsDefaultAudioTrackRenderer.java
+++ b/src/com/android/tv/tuner/exoplayer/audio/MpegTsDefaultAudioTrackRenderer.java
@@ -21,6 +21,8 @@ import android.os.Build;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
+import com.android.tv.tuner.exoplayer.ffmpeg.FfmpegDecoderClient;
+import com.android.tv.tuner.tvinput.TunerDebug;
import com.google.android.exoplayer.CodecCounters;
import com.google.android.exoplayer.ExoPlaybackException;
import com.google.android.exoplayer.MediaClock;
@@ -33,7 +35,6 @@ import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.audio.AudioTrack;
import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.MimeTypes;
-import com.android.tv.tuner.tvinput.TunerDebug;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
@@ -153,8 +154,7 @@ public class MpegTsDefaultAudioTrackRenderer extends TrackRenderer implements Me
mAudioClock = new AudioClock();
mTracksIndex = new ArrayList<>();
mAc3Passthrough = usePassthrough;
- // TODO reimplement ffmpeg decoder check for google3
- mSoftwareDecoderAvailable = false;
+ mSoftwareDecoderAvailable = hasSoftwareAudioDecoder && FfmpegDecoderClient.isAvailable();
}
@Override
@@ -400,11 +400,15 @@ public class MpegTsDefaultAudioTrackRenderer extends TrackRenderer implements Me
mFormat = formatHolder.format;
mAudioDecoder.maybeInitDecoder(mFormat);
mSampleHolder = new SampleHolder(SampleHolder.BUFFER_REPLACEMENT_MODE_DISABLED);
- // TODO reimplement ffmeg for google3
- // Here use else if
- // (MimeTypes.AUDIO_MPEG_L2.equalsIgnoreCase(mimeType)
- // || MimeTypes.AUDIO_AC3.equalsIgnoreCase(mimeType) && !mAc3Passthrough
- // then set the audio decoder to ffmpeg
+ } else if (mSoftwareDecoderAvailable
+ && (MimeTypes.AUDIO_MPEG_L2.equalsIgnoreCase(mimeType)
+ || MimeTypes.AUDIO_AC3.equalsIgnoreCase(mimeType) && !mAc3Passthrough)) {
+ releaseDecoder();
+ mSampleHolder = new SampleHolder(SampleHolder.BUFFER_REPLACEMENT_MODE_DIRECT);
+ mSampleHolder.ensureSpaceForWrite(DEFAULT_INPUT_BUFFER_SIZE);
+ mAudioDecoder = FfmpegDecoderClient.getInstance();
+ mDecodingMime = mimeType;
+ mFormat = convertMediaFormatToRaw(formatHolder.format);
} else {
mSampleHolder = new SampleHolder(SampleHolder.BUFFER_REPLACEMENT_MODE_DIRECT);
mSampleHolder.ensureSpaceForWrite(DEFAULT_INPUT_BUFFER_SIZE);
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/audio/MpegTsMediaCodecAudioTrackRenderer.java b/src/com/android/tv/tuner/exoplayer/audio/MpegTsMediaCodecAudioTrackRenderer.java
index b382545f..b382545f 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/audio/MpegTsMediaCodecAudioTrackRenderer.java
+++ b/src/com/android/tv/tuner/exoplayer/audio/MpegTsMediaCodecAudioTrackRenderer.java
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/buffer/BufferManager.java b/src/com/android/tv/tuner/exoplayer/buffer/BufferManager.java
index 8f30b729..206e2098 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/buffer/BufferManager.java
+++ b/src/com/android/tv/tuner/exoplayer/buffer/BufferManager.java
@@ -23,10 +23,10 @@ import android.support.annotation.VisibleForTesting;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
-import com.google.android.exoplayer.SampleHolder;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.common.util.CommonUtils;
import com.android.tv.tuner.exoplayer.SampleExtractor;
+import com.android.tv.util.Utils;
+import com.google.android.exoplayer.SampleHolder;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
@@ -515,7 +515,7 @@ public class BufferManager {
earliestChunk.getSize(),
earliestChunkId,
earliestChunk.getStartPositionUs(),
- CommonUtils.toIsoDateTimeString(earliestChunk.getCreatedTimeMs())));
+ Utils.toIsoDateTimeString(earliestChunk.getCreatedTimeMs())));
}
ChunkEvictedListener listener = mEvictListeners.get(earliestChunkId);
if (listener != null) {
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/buffer/DvrStorageManager.java b/src/com/android/tv/tuner/exoplayer/buffer/DvrStorageManager.java
index 54899ede..2a58ffcf 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/buffer/DvrStorageManager.java
+++ b/src/com/android/tv/tuner/exoplayer/buffer/DvrStorageManager.java
@@ -35,7 +35,6 @@ import java.util.Map;
import java.util.SortedMap;
/** Manages DVR storage. */
-@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed
public class DvrStorageManager implements BufferManager.StorageManager {
private static final String TAG = "DvrStorageManager";
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/buffer/RecordingSampleBuffer.java b/src/com/android/tv/tuner/exoplayer/buffer/RecordingSampleBuffer.java
index 5598b815..ebf00f59 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/buffer/RecordingSampleBuffer.java
+++ b/src/com/android/tv/tuner/exoplayer/buffer/RecordingSampleBuffer.java
@@ -20,14 +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.android.tv.tuner.tvinput.PlaybackBufferListener;
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.android.tv.tuner.exoplayer.MpegTsPlayer;
-import com.android.tv.tuner.exoplayer.SampleExtractor;
-import com.android.tv.tuner.tvinput.PlaybackBufferListener;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/buffer/SampleChunk.java b/src/com/android/tv/tuner/exoplayer/buffer/SampleChunk.java
index 294912e1..023d3295 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/buffer/SampleChunk.java
+++ b/src/com/android/tv/tuner/exoplayer/buffer/SampleChunk.java
@@ -214,11 +214,8 @@ public class SampleChunk {
* @throws IOException
*/
void write(SampleHolder sample, SampleChunk nextChunk) throws IOException {
- if (mChunk == null) {
- throw new IOException("mChunk should not be null");
- }
if (nextChunk != null) {
- if (mChunk.mNextChunk != null) {
+ if (mChunk == null || mChunk.mNextChunk != null) {
throw new IllegalStateException("Requested write for wrong SampleChunk");
}
mChunk.closeWrite(nextChunk);
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/buffer/SampleChunkIoHelper.java b/src/com/android/tv/tuner/exoplayer/buffer/SampleChunkIoHelper.java
index 01989766..06fd6558 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/buffer/SampleChunkIoHelper.java
+++ b/src/com/android/tv/tuner/exoplayer/buffer/SampleChunkIoHelper.java
@@ -24,11 +24,11 @@ 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.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.android.tv.common.SoftPreconditions;
-import com.android.tv.tuner.exoplayer.buffer.RecordingSampleBuffer.BufferReason;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/buffer/SamplePool.java b/src/com/android/tv/tuner/exoplayer/buffer/SamplePool.java
index b89a14db..b89a14db 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/buffer/SamplePool.java
+++ b/src/com/android/tv/tuner/exoplayer/buffer/SamplePool.java
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/buffer/SampleQueue.java b/src/com/android/tv/tuner/exoplayer/buffer/SampleQueue.java
index e208f2c2..e208f2c2 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/buffer/SampleQueue.java
+++ b/src/com/android/tv/tuner/exoplayer/buffer/SampleQueue.java
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/buffer/SimpleSampleBuffer.java b/src/com/android/tv/tuner/exoplayer/buffer/SimpleSampleBuffer.java
index 5517e2ad..4c6260bf 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/buffer/SimpleSampleBuffer.java
+++ b/src/com/android/tv/tuner/exoplayer/buffer/SimpleSampleBuffer.java
@@ -18,13 +18,13 @@ package com.android.tv.tuner.exoplayer.buffer;
import android.os.ConditionVariable;
import android.support.annotation.NonNull;
+import com.android.tv.common.SoftPreconditions;
+import com.android.tv.tuner.exoplayer.SampleExtractor;
+import com.android.tv.tuner.tvinput.PlaybackBufferListener;
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.android.tv.common.SoftPreconditions;
-import com.android.tv.tuner.exoplayer.SampleExtractor;
-import com.android.tv.tuner.tvinput.PlaybackBufferListener;
import java.io.IOException;
import java.util.List;
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/buffer/TrickplayStorageManager.java b/src/com/android/tv/tuner/exoplayer/buffer/TrickplayStorageManager.java
index b22b8af1..b22b8af1 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/buffer/TrickplayStorageManager.java
+++ b/src/com/android/tv/tuner/exoplayer/buffer/TrickplayStorageManager.java
diff --git a/src/com/android/tv/tuner/exoplayer/ffmpeg/FfmpegDecoderClient.java b/src/com/android/tv/tuner/exoplayer/ffmpeg/FfmpegDecoderClient.java
new file mode 100644
index 00000000..421192f1
--- /dev/null
+++ b/src/com/android/tv/tuner/exoplayer/ffmpeg/FfmpegDecoderClient.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.tuner.exoplayer.ffmpeg;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.support.annotation.MainThread;
+import android.support.annotation.VisibleForTesting;
+import android.support.annotation.WorkerThread;
+import com.android.tv.Features;
+import com.android.tv.tuner.exoplayer.audio.AudioDecoder;
+import com.google.android.exoplayer.SampleHolder;
+import java.nio.ByteBuffer;
+
+/**
+ * The class connects {@link FfmpegDecoderService} to decode audio samples. In order to sandbox
+ * ffmpeg based decoder, {@link FfmpegDecoderService} is an isolated process without any permission
+ * and connected by binder.
+ */
+public class FfmpegDecoderClient extends AudioDecoder {
+ private static FfmpegDecoderClient sInstance;
+
+ private IFfmpegDecoder mService;
+ private Boolean mIsAvailable;
+
+ private static final String FFMPEG_DECODER_SERVICE_FILTER =
+ "com.android.tv.tuner.exoplayer.ffmpeg.IFfmpegDecoder";
+ private static final long FFMPEG_SERVICE_CONNECT_TIMEOUT_MS = 500;
+
+ private final ServiceConnection mConnection =
+ new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ mService = IFfmpegDecoder.Stub.asInterface(service);
+ synchronized (FfmpegDecoderClient.this) {
+ try {
+ mIsAvailable = mService.isAvailable();
+ } catch (RemoteException e) {
+ }
+ FfmpegDecoderClient.this.notify();
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName className) {
+ synchronized (FfmpegDecoderClient.this) {
+ sInstance.releaseLocked();
+ mIsAvailable = false;
+ mService = null;
+ }
+ }
+ };
+
+ /**
+ * Connects to the decoder service for future uses.
+ *
+ * @param context
+ * @return {@code true} when decoder service is connected.
+ */
+ @MainThread
+ public static synchronized boolean connect(Context context) {
+ if (Features.AC3_SOFTWARE_DECODE.isEnabled(context)) {
+ if (sInstance == null) {
+ sInstance = new FfmpegDecoderClient();
+ Intent intent =
+ new Intent(FFMPEG_DECODER_SERVICE_FILTER)
+ .setComponent(
+ new ComponentName(context, FfmpegDecoderService.class));
+ if (context.bindService(intent, sInstance.mConnection, Context.BIND_AUTO_CREATE)) {
+ return true;
+ } else {
+ sInstance = null;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Disconnects from the decoder service and release resources.
+ *
+ * @param context
+ */
+ @MainThread
+ public static synchronized void disconnect(Context context) {
+ if (sInstance != null) {
+ synchronized (sInstance) {
+ sInstance.releaseLocked();
+ if (sInstance.mIsAvailable != null && sInstance.mIsAvailable) {
+ context.unbindService(sInstance.mConnection);
+ }
+ sInstance.mIsAvailable = false;
+ sInstance.mService = null;
+ }
+ sInstance = null;
+ }
+ }
+
+ /**
+ * Returns whether service is available or not. Before using client, this should be used to
+ * check availability.
+ */
+ @WorkerThread
+ public static synchronized boolean isAvailable() {
+ if (sInstance != null) {
+ return sInstance.available();
+ }
+ return false;
+ }
+
+ /** Returns an client instance. */
+ public static synchronized FfmpegDecoderClient getInstance() {
+ if (sInstance != null) {
+ sInstance.createDecoder();
+ }
+ return sInstance;
+ }
+
+ private FfmpegDecoderClient() {}
+
+ private synchronized boolean available() {
+ if (mIsAvailable == null) {
+ try {
+ this.wait(FFMPEG_SERVICE_CONNECT_TIMEOUT_MS);
+ } catch (InterruptedException e) {
+ }
+ }
+ return mIsAvailable != null && mIsAvailable == true;
+ }
+
+ private synchronized void createDecoder() {
+ if (mIsAvailable == null || mIsAvailable == false) {
+ return;
+ }
+ try {
+ mService.create();
+ } catch (RemoteException e) {
+ }
+ }
+
+ private void releaseLocked() {
+ if (mIsAvailable == null || mIsAvailable == false) {
+ return;
+ }
+ try {
+ mService.release();
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
+ public synchronized void release() {
+ releaseLocked();
+ }
+
+ @Override
+ public synchronized void decode(SampleHolder sampleHolder) {
+ if (mIsAvailable == null || mIsAvailable == false) {
+ return;
+ }
+ byte[] sampleBytes = new byte[sampleHolder.data.limit()];
+ sampleHolder.data.get(sampleBytes, 0, sampleBytes.length);
+ try {
+ mService.decode(sampleHolder.timeUs, sampleBytes);
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
+ public synchronized void resetDecoderState(String mimeType) {
+ if (mIsAvailable == null || mIsAvailable == false) {
+ return;
+ }
+ try {
+ mService.resetDecoderState(mimeType);
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
+ public synchronized ByteBuffer getDecodedSample() {
+ if (mIsAvailable == null || mIsAvailable == false) {
+ return null;
+ }
+ try {
+ byte[] outputBytes = mService.getDecodedSample();
+ if (outputBytes != null && outputBytes.length > 0) {
+ return ByteBuffer.wrap(outputBytes);
+ }
+ } catch (RemoteException e) {
+ }
+ return null;
+ }
+
+ @Override
+ public synchronized long getDecodedTimeUs() {
+ if (mIsAvailable == null || mIsAvailable == false) {
+ return 0;
+ }
+ try {
+ return mService.getDecodedTimeUs();
+ } catch (RemoteException e) {
+ }
+ return 0;
+ }
+
+ @VisibleForTesting
+ public boolean testSandboxIsolatedProcess() {
+ // When testing isolated process, we will check the permission in FfmpegDecoderService.
+ // If the service have any permission, an exception will be thrown.
+ try {
+ mService.testSandboxIsolatedProcess();
+ } catch (RemoteException e) {
+ return false;
+ }
+ return true;
+ }
+
+ @VisibleForTesting
+ public void testSandboxMinijail() {
+ // When testing minijail, we will call a system call which is blocked by minijail. In that
+ // case, the FfmpegDecoderService will be disconnected, we can check the connection status
+ // to make sure if the minijail works or not.
+ try {
+ mService.testSandboxMinijail();
+ } catch (RemoteException e) {
+ }
+ }
+}
diff --git a/src/com/android/tv/tuner/exoplayer/ffmpeg/FfmpegDecoderService.java b/src/com/android/tv/tuner/exoplayer/ffmpeg/FfmpegDecoderService.java
new file mode 100644
index 00000000..0172d817
--- /dev/null
+++ b/src/com/android/tv/tuner/exoplayer/ffmpeg/FfmpegDecoderService.java
@@ -0,0 +1,202 @@
+/*
+ * 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.ffmpeg;
+
+import android.app.Service;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.res.AssetFileDescriptor;
+import android.os.AsyncTask;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+import com.google.android.exoplayer2.ext.ffmpeg.FfmpegAudioDecoder;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/** Ffmpeg based audio decoder service. It should be isolatedProcess due to security reason. */
+public class FfmpegDecoderService extends Service {
+ private static final String TAG = "FfmpegDecoderService";
+ private static final boolean DEBUG = false;
+
+ private static final String POLICY_FILE = "whitelist.policy";
+
+ private static final long MINIJAIL_SETUP_WAIT_TIMEOUT_MS = 5000;
+
+ private static boolean sLibraryLoaded = true;
+
+ static {
+ try {
+ System.loadLibrary("minijail_jni");
+ } catch (Exception | Error e) {
+ Log.e(TAG, "Load minijail failed:", e);
+ sLibraryLoaded = false;
+ }
+ }
+
+ private FfmpegDecoder mBinder = new FfmpegDecoder();
+ private volatile Object mMinijailSetupMonitor = new Object();
+ // @GuardedBy("mMinijailSetupMonitor")
+ private volatile Boolean mMinijailSetup;
+
+ @Override
+ public void onCreate() {
+ if (sLibraryLoaded) {
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ synchronized (mMinijailSetupMonitor) {
+ int pipeFd = getPolicyPipeFd();
+ if (pipeFd <= 0) {
+ Log.e(TAG, "fail to open policy file");
+ mMinijailSetup = false;
+ } else {
+ nativeSetupMinijail(pipeFd);
+ mMinijailSetup = true;
+ if (DEBUG) Log.d(TAG, "Minijail setup successfully");
+ }
+ mMinijailSetupMonitor.notify();
+ }
+ return null;
+ }
+ }.execute();
+ } else {
+ synchronized (mMinijailSetupMonitor) {
+ mMinijailSetup = false;
+ mMinijailSetupMonitor.notify();
+ }
+ }
+ super.onCreate();
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+ private int getPolicyPipeFd() {
+ try {
+ ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
+ final ParcelFileDescriptor.AutoCloseOutputStream outputStream =
+ new ParcelFileDescriptor.AutoCloseOutputStream(pipe[1]);
+ final AssetFileDescriptor policyFile = getAssets().openFd("whitelist.policy");
+ final byte[] buffer = new byte[2048];
+ final FileInputStream policyStream = policyFile.createInputStream();
+ while (true) {
+ int bytesRead = policyStream.read(buffer);
+ if (bytesRead == -1) break;
+ outputStream.write(buffer, 0, bytesRead);
+ }
+ policyStream.close();
+ outputStream.close();
+ return pipe[0].detachFd();
+ } catch (IOException e) {
+ Log.e(TAG, "Policy file not found:" + e);
+ }
+ return -1;
+ }
+
+ private final class FfmpegDecoder extends IFfmpegDecoder.Stub {
+ FfmpegAudioDecoder mDecoder;
+
+ @Override
+ public boolean isAvailable() {
+ return isMinijailSetupDone() && FfmpegAudioDecoder.isAvailable();
+ }
+
+ @Override
+ public void create() {
+ mDecoder = new FfmpegAudioDecoder(FfmpegDecoderService.this);
+ }
+
+ @Override
+ public void release() {
+ if (mDecoder != null) {
+ mDecoder.release();
+ mDecoder = null;
+ }
+ }
+
+ @Override
+ public void decode(long timeUs, byte[] sample) {
+ if (!isMinijailSetupDone()) {
+ // If minijail is not setup, we don't run decode for better security.
+ return;
+ }
+ mDecoder.decode(timeUs, sample);
+ }
+
+ @Override
+ public void resetDecoderState(String mimetype) {
+ mDecoder.resetDecoderState(mimetype);
+ }
+
+ @Override
+ public byte[] getDecodedSample() {
+ ByteBuffer decodedBuffer = mDecoder.getDecodedSample();
+ byte[] ret = new byte[decodedBuffer.limit()];
+ decodedBuffer.get(ret, 0, ret.length);
+ return ret;
+ }
+
+ @Override
+ public long getDecodedTimeUs() {
+ return mDecoder.getDecodedTimeUs();
+ }
+
+ private boolean isMinijailSetupDone() {
+ synchronized (mMinijailSetupMonitor) {
+ if (DEBUG) Log.d(TAG, "mMinijailSetup in isAvailable(): " + mMinijailSetup);
+ if (mMinijailSetup == null) {
+ try {
+ if (DEBUG) Log.d(TAG, "Wait till Minijail setup is done");
+ mMinijailSetupMonitor.wait(MINIJAIL_SETUP_WAIT_TIMEOUT_MS);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ return mMinijailSetup != null && mMinijailSetup;
+ }
+ }
+
+ @Override
+ public void testSandboxIsolatedProcess() {
+ if (!isMinijailSetupDone()) {
+ // If minijail is not setup, we return directly to make the test fail.
+ return;
+ }
+ if (FfmpegDecoderService.this.checkSelfPermission("android.permission.INTERNET")
+ == PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Shouldn't have the permission of internet");
+ }
+ }
+
+ @Override
+ public void testSandboxMinijail() {
+ if (!isMinijailSetupDone()) {
+ // If minijail is not setup, we return directly to make the test fail.
+ return;
+ }
+ nativeTestMinijail();
+ }
+ }
+
+ private native void nativeSetupMinijail(int policyFd);
+
+ private native void nativeTestMinijail();
+}
diff --git a/tuner/src/com/mediatek/tunerservice/IMtkTuner.aidl b/src/com/android/tv/tuner/exoplayer/ffmpeg/IFfmpegDecoder.aidl
index b15c736a..ed053790 100644
--- a/tuner/src/com/mediatek/tunerservice/IMtkTuner.aidl
+++ b/src/com/android/tv/tuner/exoplayer/ffmpeg/IFfmpegDecoder.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 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.
@@ -14,14 +14,16 @@
* limitations under the License.
*/
-package com.mediatek.tunerservice;
+package com.android.tv.tuner.exoplayer.ffmpeg;
-interface IMtkTuner {
- boolean tune(int frequency, String modulation, int timeOutMs);
- void addPidFilter(int pid, int filterType);
- void closeAllPidFilters();
- void stopTune();
- byte[] getTsData(int maxDataSize, int timeOutMs);
- void setHasPendingTune(boolean hasPendingTune);
+interface IFfmpegDecoder {
+ boolean isAvailable();
+ void create();
void release();
-}
+ void resetDecoderState(String mimetype);
+ void decode(long timeUs, in byte[] sample);
+ byte[] getDecodedSample();
+ long getDecodedTimeUs();
+ void testSandboxIsolatedProcess();
+ void testSandboxMinijail();
+} \ No newline at end of file
diff --git a/tuner/src/com/android/tv/tuner/layout/ScaledLayout.java b/src/com/android/tv/tuner/layout/ScaledLayout.java
index dd92b641..dd92b641 100644
--- a/tuner/src/com/android/tv/tuner/layout/ScaledLayout.java
+++ b/src/com/android/tv/tuner/layout/ScaledLayout.java
diff --git a/tuner/src/com/android/tv/tuner/setup/ConnectionTypeFragment.java b/src/com/android/tv/tuner/setup/ConnectionTypeFragment.java
index ebe4e41e..75d1c34c 100644
--- a/tuner/src/com/android/tv/tuner/setup/ConnectionTypeFragment.java
+++ b/src/com/android/tv/tuner/setup/ConnectionTypeFragment.java
@@ -20,12 +20,10 @@ 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 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 {
@@ -34,19 +32,19 @@ public class ConnectionTypeFragment extends SetupMultiPaneFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
- ((BaseTunerSetupActivity) getActivity()).generateTunerHal();
+ ((TunerSetupActivity) getActivity()).generateTunerHal();
super.onCreate(savedInstanceState);
}
@Override
public void onResume() {
- ((BaseTunerSetupActivity) getActivity()).generateTunerHal();
+ ((TunerSetupActivity) getActivity()).generateTunerHal();
super.onResume();
}
@Override
public void onDestroy() {
- ((BaseTunerSetupActivity) getActivity()).clearTunerHal();
+ ((TunerSetupActivity) getActivity()).clearTunerHal();
super.onDestroy();
}
@@ -65,7 +63,6 @@ public class ConnectionTypeFragment extends SetupMultiPaneFragment {
return false;
}
- /** The content fragment of {@link ConnectionTypeFragment}. */
public static class ContentFragment extends SetupGuidedStepFragment {
@NonNull
diff --git a/tuner/src/com/android/tv/tuner/setup/PostalCodeFragment.java b/src/com/android/tv/tuner/setup/PostalCodeFragment.java
index 2ef59836..fbf03909 100644
--- a/tuner/src/com/android/tv/tuner/setup/PostalCodeFragment.java
+++ b/src/com/android/tv/tuner/setup/PostalCodeFragment.java
@@ -25,18 +25,16 @@ import android.text.InputFilter;
import android.text.InputFilter.AllCaps;
import android.view.View;
import android.widget.TextView;
+import com.android.tv.R;
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.common.util.PostalCodeUtils;
-import com.android.tv.tuner.R;
+import com.android.tv.tuner.util.PostalCodeUtils;
+import com.android.tv.util.LocationUtils;
import java.util.List;
/** A fragment for initial screen. */
public class PostalCodeFragment extends SetupMultiPaneFragment {
- public static final String ACTION_CATEGORY =
- "com.android.tv.tuner.setup.PostalCodeFragment";
- public static final String KEY_POSTAL_CODE = "postal_code";
+ public static final String ACTION_CATEGORY = "com.android.tv.tuner.setup.PostalCodeFragment";
private static final int VIEW_TYPE_EDITABLE = 1;
@Override
@@ -71,15 +69,12 @@ public class PostalCodeFragment extends SetupMultiPaneFragment {
@Override
public void onClick(View view) {
CharSequence postalCode =
- ((ContentFragment) getContentFragment())
- .mEditedActionTitleView.getText();
+ ((ContentFragment) getContentFragment()).mEditAction.getTitle();
String region = LocationUtils.getCurrentCountry(getContext());
if (postalCode != null && PostalCodeUtils.matches(postalCode, region)) {
- String postalCodeString = postalCode.toString();
- PostalCodeUtils.setLastPostalCode(getContext(), postalCodeString);
- Bundle params = new Bundle();
- params.putString(KEY_POSTAL_CODE, postalCodeString);
- onActionClick(category, actionId, params);
+ PostalCodeUtils.setLastPostalCode(
+ getContext(), postalCode.toString());
+ onActionClick(category, actionId);
} else {
ContentFragment contentFragment =
(ContentFragment) getContentFragment();
@@ -95,11 +90,9 @@ public class PostalCodeFragment extends SetupMultiPaneFragment {
}
}
- /** The content fragment of {@link PostalCodeFragment}. */
public static class ContentFragment extends SetupGuidedStepFragment {
private GuidedAction mEditAction;
private View mEditedActionView;
- private TextView mEditedActionTitleView;
private View mDoneActionView;
private boolean mProceed;
@@ -109,7 +102,7 @@ public class PostalCodeFragment extends SetupMultiPaneFragment {
if (mProceed) {
// "NEXT" in IME was just clicked, moves focus to Done button.
if (mDoneActionView == null) {
- mDoneActionView = getDoneButton();
+ mDoneActionView = getActivity().findViewById(R.id.button_done);
}
mDoneActionView.requestFocus();
mProceed = false;
@@ -118,12 +111,11 @@ public class PostalCodeFragment extends SetupMultiPaneFragment {
if (mEditedActionView == null) {
int maxLength = PostalCodeUtils.getRegionMaxLength(getContext());
mEditedActionView = getView().findViewById(R.id.guidedactions_editable);
- mEditedActionTitleView =
- mEditedActionView.findViewById(R.id.guidedactions_item_title);
- mEditedActionTitleView.setFilters(
- new InputFilter[] {
- new InputFilter.LengthFilter(maxLength), new AllCaps()
- });
+ ((TextView) mEditedActionView.findViewById(R.id.guidedactions_item_title))
+ .setFilters(
+ new InputFilter[] {
+ new InputFilter.LengthFilter(maxLength), new AllCaps()
+ });
}
mEditedActionView.performClick();
}
diff --git a/tuner/src/com/android/tv/tuner/setup/ScanFragment.java b/src/com/android/tv/tuner/setup/ScanFragment.java
index 3ac86e19..044b0d26 100644
--- a/tuner/src/com/android/tv/tuner/setup/ScanFragment.java
+++ b/src/com/android/tv/tuner/setup/ScanFragment.java
@@ -44,8 +44,6 @@ import com.android.tv.tuner.TunerPreferences;
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.source.FileTsStreamer;
import com.android.tv.tuner.source.TsDataSource;
import com.android.tv.tuner.source.TsStreamer;
@@ -74,7 +72,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 KEY_CHANNEL_NUMBERS = "channel_numbers";
+
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;
@@ -91,14 +89,11 @@ public class ScanFragment extends SetupFragment {
private volatile boolean mChannelListVisible;
private Button mCancelButton;
- private ArrayList<String> mChannelNumbers;
-
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (DEBUG) Log.d(TAG, "onCreateView");
View view = super.onCreateView(inflater, container, savedInstanceState);
- mChannelNumbers = new ArrayList<>();
mChannelDataManager = new ChannelDataManager(getActivity());
mChannelDataManager.checkDataVersion(getActivity());
mAdapter = new ChannelAdapter();
@@ -121,7 +116,7 @@ public class ScanFragment extends SetupFragment {
}
});
Bundle args = getArguments();
- int tunerType = (args == null ? 0 : args.getInt(BaseTunerSetupActivity.KEY_TUNER_TYPE, 0));
+ int tunerType = (args == null ? 0 : args.getInt(TunerSetupActivity.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);
@@ -191,7 +186,7 @@ public class ScanFragment extends SetupFragment {
}
}
- private static class ChannelAdapter extends BaseAdapter {
+ private class ChannelAdapter extends BaseAdapter {
private final ArrayList<TunerChannel> mChannels;
public ChannelAdapter() {
@@ -269,7 +264,7 @@ public class ScanFragment extends SetupFragment {
if (FAKE_MODE) {
mScanTsStreamer = new FakeTsStreamer(this);
} else {
- TunerHal hal = ((BaseTunerSetupActivity) mActivity).getTunerHal();
+ TunerHal hal = ((TunerSetupActivity) mActivity).getTunerHal();
if (hal == null) {
throw new RuntimeException("Failed to open a DVB device");
}
@@ -385,6 +380,7 @@ public class ScanFragment extends SetupFragment {
e);
}
streamer.stopStream();
+
addChannelsWithoutVct(scanChannel);
if (System.currentTimeMillis() > startMs + CHANNEL_SCAN_SHOW_DELAY_MS
&& !mChannelListVisible) {
@@ -429,9 +425,9 @@ public class ScanFragment extends SetupFragment {
private TsStreamer getStreamer(int type) {
switch (type) {
- case Channel.TunerType.TYPE_TUNER:
+ case Channel.TYPE_TUNER:
return mScanTsStreamer;
- case Channel.TunerType.TYPE_FILE:
+ case Channel.TYPE_FILE:
return mFileTsStreamer;
default:
return null;
@@ -460,7 +456,6 @@ public class ScanFragment extends SetupFragment {
// No video-only channel has been found.
addChannel(channel);
mChannelDataManager.notifyChannelDetected(channel, channelArrivedAtFirstTime);
- mChannelNumbers.add(channel.getDisplayNumber());
}
}
@@ -482,7 +477,7 @@ public class ScanFragment extends SetupFragment {
mActivity.getApplicationContext(),
mChannelDataManager.getScannedChannelCount());
// Cancel a previously shown notification.
- BaseTunerSetupActivity.cancelNotification(mActivity.getApplicationContext());
+ TunerSetupActivity.cancelNotification(mActivity.getApplicationContext());
// Mark scan as done
TunerPreferences.setScanDone(mActivity.getApplicationContext());
// finishing will be done manually.
@@ -492,13 +487,7 @@ public class ScanFragment extends SetupFragment {
// If the fragment is not resumed, the next fragment (scan result page) can't be
// displayed. In that case, just close the activity.
if (isResumed()) {
- if (mIsCanceled) {
- onActionClick(ACTION_CATEGORY, ACTION_CANCEL);
- } else {
- Bundle params = new Bundle();
- params.putStringArrayList(KEY_CHANNEL_NUMBERS, mChannelNumbers);
- onActionClick(ACTION_CATEGORY, ACTION_FINISH, params);
- }
+ onActionClick(ACTION_CATEGORY, mIsCanceled ? ACTION_CANCEL : ACTION_FINISH);
} else if (getActivity() != null) {
getActivity().finish();
}
diff --git a/tuner/src/com/android/tv/tuner/setup/ScanResultFragment.java b/src/com/android/tv/tuner/setup/ScanResultFragment.java
index d29311b9..a6160ef1 100644
--- a/tuner/src/com/android/tv/tuner/setup/ScanResultFragment.java
+++ b/src/com/android/tv/tuner/setup/ScanResultFragment.java
@@ -31,15 +31,11 @@ import java.util.List;
/** A fragment for initial screen. */
public class ScanResultFragment extends SetupMultiPaneFragment {
- public static final String ACTION_CATEGORY =
- "com.android.tv.tuner.setup.ScanResultFragment";
+ public static final String ACTION_CATEGORY = "com.android.tv.tuner.setup.ScanResultFragment";
@Override
protected SetupGuidedStepFragment onCreateContentFragment() {
- Bundle args = new Bundle();
- ContentFragment fragment = new ContentFragment();
- fragment.setArguments(args);
- return fragment;
+ return new ContentFragment();
}
@Override
@@ -52,7 +48,6 @@ public class ScanResultFragment extends SetupMultiPaneFragment {
return false;
}
- /** The content fragment of {@link ScanResultFragment}. */
public static class ContentFragment extends SetupGuidedStepFragment {
private int mChannelCountOnPreference;
@@ -75,13 +70,16 @@ public class ScanResultFragment extends SetupMultiPaneFragment {
R.plurals.ut_result_found_title,
mChannelCountOnPreference,
mChannelCountOnPreference);
- description = res.getString(R.string.ut_result_found_description);
-
+ description =
+ res.getQuantityString(
+ R.plurals.ut_result_found_description,
+ mChannelCountOnPreference,
+ mChannelCountOnPreference);
breadcrumb = null;
} else {
Bundle args = getArguments();
int tunerType =
- (args == null ? 0 : args.getInt(BaseTunerSetupActivity.KEY_TUNER_TYPE, 0));
+ (args == null ? 0 : args.getInt(TunerSetupActivity.KEY_TUNER_TYPE, 0));
title = getString(R.string.ut_result_not_found_title);
switch (tunerType) {
case TunerHal.TUNER_TYPE_USB:
diff --git a/tuner/src/com/android/tv/tuner/setup/BaseTunerSetupActivity.java b/src/com/android/tv/tuner/setup/TunerSetupActivity.java
index 8356af0a..58cfc927 100644
--- a/tuner/src/com/android/tv/tuner/setup/BaseTunerSetupActivity.java
+++ b/src/com/android/tv/tuner/setup/TunerSetupActivity.java
@@ -17,15 +17,19 @@
package com.android.tv.tuner.setup;
import android.app.Fragment;
+import android.app.FragmentManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.media.tv.TvContract;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
@@ -36,38 +40,43 @@ import android.support.annotation.WorkerThread;
import android.support.v4.app.NotificationCompat;
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.Features;
+import com.android.tv.TvApplication;
+import com.android.tv.common.AutoCloseableUtils;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.common.experiments.Experiments;
-import com.android.tv.common.feature.CommonFeatures;
+import com.android.tv.common.TvCommonConstants;
+import com.android.tv.common.TvCommonUtils;
import com.android.tv.common.ui.setup.SetupActivity;
import com.android.tv.common.ui.setup.SetupFragment;
import com.android.tv.common.ui.setup.SetupMultiPaneFragment;
-import com.android.tv.common.util.AutoCloseableUtils;
-import com.android.tv.common.util.PostalCodeUtils;
+import com.android.tv.experiments.Experiments;
import com.android.tv.tuner.R;
import com.android.tv.tuner.TunerHal;
import com.android.tv.tuner.TunerPreferences;
+import com.android.tv.tuner.tvinput.TunerTvInputService;
+import com.android.tv.tuner.util.PostalCodeUtils;
import java.util.concurrent.Executor;
-/** The base setup activity class for tuner. */
-public class BaseTunerSetupActivity extends SetupActivity {
- private static final String TAG = "BaseTunerSetupActivity";
+/** An activity that serves tuner setup process. */
+public class TunerSetupActivity extends SetupActivity {
+ private static final String TAG = "TunerSetupActivity";
private static final boolean DEBUG = false;
/** Key for passing tuner type to sub-fragments. */
public static final String KEY_TUNER_TYPE = "TunerSetupActivity.tunerType";
// For the notification.
- protected static final String TUNER_SET_UP_NOTIFICATION_CHANNEL_ID = "tuner_setup_channel";
- protected static final String NOTIFY_TAG = "TunerSetup";
- protected static final int NOTIFY_ID = 1000;
- protected static final String TAG_DRAWABLE = "drawable";
- protected static final String TAG_ICON = "ic_launcher_s";
- protected static final int PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION = 1;
-
- protected static final int[] CHANNEL_MAP_SCAN_FILE = {
+ private static final String TV_ACTIVITY_CLASS_NAME = "com.android.tv.TvActivity";
+ private static final String TUNER_SET_UP_NOTIFICATION_CHANNEL_ID = "tuner_setup_channel";
+ private static final String NOTIFY_TAG = "TunerSetup";
+ private static final int NOTIFY_ID = 1000;
+ private static final String TAG_DRAWABLE = "drawable";
+ private static final String TAG_ICON = "ic_launcher_s";
+ private static final int PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION = 1;
+
+ private static final int CHANNEL_MAP_SCAN_FILE[] = {
R.raw.ut_us_atsc_center_frequencies_8vsb,
R.raw.ut_us_cable_standard_center_frequencies_qam256,
R.raw.ut_us_all,
@@ -80,24 +89,34 @@ public class BaseTunerSetupActivity extends SetupActivity {
R.raw.ut_euro_dvbt_all
};
- protected ScanFragment mLastScanFragment;
- protected Integer mTunerType;
- protected boolean mNeedToShowPostalCodeFragment;
- protected String mPreviousPostalCode;
- protected boolean mActivityStopped;
- protected boolean mPendingShowInitialFragment;
-
+ private ScanFragment mLastScanFragment;
+ private Integer mTunerType;
private TunerHalFactory mTunerHalFactory;
+ private boolean mNeedToShowPostalCodeFragment;
+ private String mPreviousPostalCode;
@Override
protected void onCreate(Bundle savedInstanceState) {
- if (DEBUG) {
- Log.d(TAG, "onCreate");
- }
- mActivityStopped = false;
- executeGetTunerTypeAndCountAsyncTask();
- mTunerHalFactory =
- new TunerHalFactory(getApplicationContext(), AsyncTask.THREAD_POOL_EXECUTOR);
+ if (DEBUG) Log.d(TAG, "onCreate");
+ new AsyncTask<Void, Void, Integer>() {
+ @Override
+ protected Integer doInBackground(Void... arg0) {
+ return TunerHal.getTunerTypeAndCount(TunerSetupActivity.this).first;
+ }
+
+ @Override
+ protected void onPostExecute(Integer result) {
+ if (!TunerSetupActivity.this.isDestroyed()) {
+ mTunerType = result;
+ if (result == null) {
+ finish();
+ } else {
+ showInitialFragment();
+ }
+ }
+ }
+ }.execute();
+ TvApplication.setCurrentRunningProcess(this, false);
super.onCreate(savedInstanceState);
// TODO: check {@link shouldShowRequestPermissionRationale}.
if (checkSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
@@ -107,6 +126,7 @@ public class BaseTunerSetupActivity extends SetupActivity {
new String[] {android.Manifest.permission.ACCESS_COARSE_LOCATION},
PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION);
}
+ mTunerHalFactory = new TunerHalFactory(getApplicationContext());
try {
// Updating postal code takes time, therefore we called it here for "warm-up".
mPreviousPostalCode = PostalCodeUtils.getLastPostalCode(this);
@@ -119,24 +139,6 @@ public class BaseTunerSetupActivity extends SetupActivity {
}
}
- protected void executeGetTunerTypeAndCountAsyncTask() {}
-
- @Override
- protected void onStop() {
- mActivityStopped = true;
- super.onStop();
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- mActivityStopped = false;
- if (mPendingShowInitialFragment) {
- showInitialFragment();
- mPendingShowInitialFragment = false;
- }
- }
-
@Override
public void onRequestPermissionsResult(
int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
@@ -183,11 +185,11 @@ public class BaseTunerSetupActivity extends SetupActivity {
finish();
break;
default:
- String postalCode = PostalCodeUtils.getLastPostalCode(this);
if (mNeedToShowPostalCodeFragment
- || (CommonFeatures.ENABLE_CLOUD_EPG_REGION.isEnabled(
+ || Features.ENABLE_CLOUD_EPG_REGION.isEnabled(
getApplicationContext())
- && TextUtils.isEmpty(postalCode))) {
+ && TextUtils.isEmpty(
+ PostalCodeUtils.getLastPostalCode(this))) {
// We cannot get postal code automatically. Postal code input fragment
// should always be shown even if users have input some valid postal
// code in this activity before.
@@ -200,13 +202,9 @@ public class BaseTunerSetupActivity extends SetupActivity {
}
return true;
case PostalCodeFragment.ACTION_CATEGORY:
- switch (actionId) {
- case SetupMultiPaneFragment.ACTION_DONE:
- // fall through
- case SetupMultiPaneFragment.ACTION_SKIP:
- showConnectionTypeFragment();
- break;
- default: // fall out
+ if (actionId == SetupMultiPaneFragment.ACTION_DONE
+ || actionId == SetupMultiPaneFragment.ACTION_SKIP) {
+ showConnectionTypeFragment();
}
return true;
case ConnectionTypeFragment.ACTION_CATEGORY:
@@ -234,9 +232,15 @@ public class BaseTunerSetupActivity extends SetupActivity {
return true;
case ScanFragment.ACTION_FINISH:
mTunerHalFactory.clear();
- showScanResultFragment();
+ SetupFragment fragment = new ScanResultFragment();
+ Bundle args2 = new Bundle();
+ args2.putInt(KEY_TUNER_TYPE, mTunerType);
+ fragment.setArguments(args2);
+ fragment.setShortDistance(
+ SetupFragment.FRAGMENT_EXIT_TRANSITION
+ | SetupFragment.FRAGMENT_REENTER_TRANSITION);
+ showFragment(fragment, true);
return true;
- default: // fall out
}
break;
case ScanResultFragment.ACTION_CATEGORY:
@@ -246,7 +250,6 @@ public class BaseTunerSetupActivity extends SetupActivity {
finish();
break;
default:
- // scan again
SetupFragment fragment = new ConnectionTypeFragment();
fragment.setShortDistance(
SetupFragment.FRAGMENT_ENTER_TRANSITION
@@ -255,12 +258,33 @@ public class BaseTunerSetupActivity extends SetupActivity {
break;
}
return true;
- default: // fall out
}
return false;
}
@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) {
+ // Pops fragment including ScanFragment.
+ manager.popBackStack(
+ manager.getBackStackEntryAt(count - 2).getName(),
+ 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 onDestroy() {
if (mPreviousPostalCode != null && PostalCodeUtils.getLastPostalCode(this) == null) {
PostalCodeUtils.setLastPostalCode(this, mPreviousPostalCode);
@@ -268,6 +292,49 @@ public class BaseTunerSetupActivity extends SetupActivity {
super.onDestroy();
}
+ /**
+ * A callback to be invoked when the TvInputService is enabled or disabled.
+ *
+ * @param context a {@link Context} instance
+ * @param enabled {@code true} for the {@link TunerTvInputService} to be enabled; otherwise
+ * {@code false}
+ */
+ public static void onTvInputEnabled(Context context, boolean enabled, Integer tunerType) {
+ // Send a notification for tuner setup if there's no channels and the tuner TV input
+ // setup has been not done.
+ boolean channelScanDoneOnPreference = TunerPreferences.isScanDone(context);
+ int channelCountOnPreference = TunerPreferences.getScannedChannelCount(context);
+ if (enabled && !channelScanDoneOnPreference && channelCountOnPreference == 0) {
+ TunerPreferences.setShouldShowSetupActivity(context, true);
+ sendNotification(context, tunerType);
+ } else {
+ TunerPreferences.setShouldShowSetupActivity(context, false);
+ cancelNotification(context);
+ }
+ }
+
+ /**
+ * Returns a {@link Intent} to launch the tuner TV input service.
+ *
+ * @param context a {@link Context} instance
+ */
+ public static Intent createSetupActivity(Context context) {
+ String inputId =
+ TvContract.buildInputId(
+ new ComponentName(
+ context.getPackageName(), TunerTvInputService.class.getName()));
+
+ // Make an intent to launch the setup activity of TV tuner input.
+ Intent intent =
+ TvCommonUtils.createSetupIntent(
+ new Intent(context, TunerSetupActivity.class), inputId);
+ intent.putExtra(TvCommonConstants.EXTRA_INPUT_ID, inputId);
+ Intent tvActivityIntent = new Intent();
+ tvActivityIntent.setComponent(new ComponentName(context, TV_ACTIVITY_CLASS_NAME));
+ intent.putExtra(TvCommonConstants.EXTRA_ACTIVITY_AFTER_COMPLETION, tvActivityIntent);
+ return intent;
+ }
+
/** Gets the currently used tuner HAL. */
TunerHal getTunerHal() {
return mTunerHalFactory.getOrCreate();
@@ -279,63 +346,18 @@ public class BaseTunerSetupActivity extends SetupActivity {
}
/** Clears the currently used tuner HAL. */
- protected void clearTunerHal() {
+ void clearTunerHal() {
mTunerHalFactory.clear();
}
- protected void showPostalCodeFragment() {
- SetupFragment fragment = new PostalCodeFragment();
- fragment.setShortDistance(
- SetupFragment.FRAGMENT_ENTER_TRANSITION | SetupFragment.FRAGMENT_RETURN_TRANSITION);
- showFragment(fragment, true);
- }
-
- protected void showConnectionTypeFragment() {
- SetupFragment fragment = new ConnectionTypeFragment();
- fragment.setShortDistance(
- SetupFragment.FRAGMENT_ENTER_TRANSITION | SetupFragment.FRAGMENT_RETURN_TRANSITION);
- showFragment(fragment, true);
- }
-
- protected void showScanResultFragment() {
- SetupFragment scanResultFragment = new ScanResultFragment();
- Bundle args2 = new Bundle();
- args2.putInt(KEY_TUNER_TYPE, mTunerType);
- scanResultFragment.setShortDistance(
- SetupFragment.FRAGMENT_EXIT_TRANSITION | SetupFragment.FRAGMENT_REENTER_TRANSITION);
- showFragment(scanResultFragment, true);
- }
-
- /**
- * Cancels the previously shown notification.
- *
- * @param context a {@link Context} instance
- */
- public static void cancelNotification(Context context) {
- NotificationManager notificationManager =
- (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
- notificationManager.cancel(NOTIFY_TAG, NOTIFY_ID);
- }
-
/**
- * A callback to be invoked when the TvInputService is enabled or disabled.
+ * Returns a {@link PendingIntent} to launch the tuner TV input service.
*
* @param context a {@link Context} instance
- * @param enabled {@code true} for the {@link TunerTvInputService} to be enabled;
- * otherwise {@code false}
*/
- public static void onTvInputEnabled(Context context, boolean enabled, Integer tunerType) {
- // Send a notification for tuner setup if there's no channels and the tuner TV input
- // setup has been not done.
- boolean channelScanDoneOnPreference = TunerPreferences.isScanDone(context);
- int channelCountOnPreference = TunerPreferences.getScannedChannelCount(context);
- if (enabled && !channelScanDoneOnPreference && channelCountOnPreference == 0) {
- TunerPreferences.setShouldShowSetupActivity(context, true);
- sendNotification(context, tunerType);
- } else {
- TunerPreferences.setShouldShowSetupActivity(context, false);
- cancelNotification(context);
- }
+ private static PendingIntent createPendingIntentForSetupActivity(Context context) {
+ return PendingIntent.getActivity(
+ context, 0, createSetupActivity(context), PendingIntent.FLAG_UPDATE_CURRENT);
}
private static void sendNotification(Context context, Integer tunerType) {
@@ -357,7 +379,6 @@ public class BaseTunerSetupActivity extends SetupActivity {
case TunerHal.TUNER_TYPE_NETWORK:
contentTextId = R.string.nt_setup_notification_content_text;
break;
- default: // fall out
}
String contentText = resources.getString(contentTextId);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -369,6 +390,37 @@ public class BaseTunerSetupActivity extends SetupActivity {
}
}
+ /**
+ * Sends the recommendation card to start the tuner TV input setup activity.
+ *
+ * @param context a {@link Context} instance
+ */
+ private static void sendRecommendationCard(
+ Context context, String contentTitle, String contentText, Bitmap largeIcon) {
+ // Build and send the notification.
+ Notification notification =
+ new NotificationCompat.BigPictureStyle(
+ new NotificationCompat.Builder(context)
+ .setAutoCancel(false)
+ .setContentTitle(contentTitle)
+ .setContentText(contentText)
+ .setContentInfo(contentText)
+ .setCategory(Notification.CATEGORY_RECOMMENDATION)
+ .setLargeIcon(largeIcon)
+ .setSmallIcon(
+ context.getResources()
+ .getIdentifier(
+ TAG_ICON,
+ TAG_DRAWABLE,
+ context.getPackageName()))
+ .setContentIntent(
+ createPendingIntentForSetupActivity(context)))
+ .build();
+ NotificationManager notificationManager =
+ (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ notificationManager.notify(NOTIFY_TAG, NOTIFY_ID, notification);
+ }
+
private static void sendNotificationInternal(
Context context, String contentTitle, String contentText) {
NotificationManager notificationManager =
@@ -394,55 +446,36 @@ public class BaseTunerSetupActivity extends SetupActivity {
notificationManager.notify(NOTIFY_TAG, NOTIFY_ID, notification);
}
- /**
- * Sends the recommendation card to start the tuner TV input setup activity.
- *
- * @param context a {@link Context} instance
- */
- private static void sendRecommendationCard(
- Context context, String contentTitle, String contentText, Bitmap largeIcon) {
- // Build and send the notification.
- Notification notification =
- new NotificationCompat.BigPictureStyle(
- new NotificationCompat.Builder(context)
- .setAutoCancel(false)
- .setContentTitle(contentTitle)
- .setContentText(contentText)
- .setContentInfo(contentText)
- .setCategory(Notification.CATEGORY_RECOMMENDATION)
- .setLargeIcon(largeIcon)
- .setSmallIcon(
- context.getResources()
- .getIdentifier(
- TAG_ICON,
- TAG_DRAWABLE,
- context.getPackageName()))
- .setContentIntent(
- createPendingIntentForSetupActivity(context)))
- .build();
- NotificationManager notificationManager =
- (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
- notificationManager.notify(NOTIFY_TAG, NOTIFY_ID, notification);
+ private void showPostalCodeFragment() {
+ SetupFragment fragment = new PostalCodeFragment();
+ fragment.setShortDistance(
+ SetupFragment.FRAGMENT_ENTER_TRANSITION | SetupFragment.FRAGMENT_RETURN_TRANSITION);
+ showFragment(fragment, true);
+ }
+
+ private void showConnectionTypeFragment() {
+ SetupFragment fragment = new ConnectionTypeFragment();
+ fragment.setShortDistance(
+ SetupFragment.FRAGMENT_ENTER_TRANSITION | SetupFragment.FRAGMENT_RETURN_TRANSITION);
+ showFragment(fragment, true);
}
/**
- * Returns a {@link PendingIntent} to launch the tuner TV input service.
+ * Cancels the previously shown notification.
*
* @param context a {@link Context} instance
*/
- private static PendingIntent createPendingIntentForSetupActivity(Context context) {
- return PendingIntent.getActivity(
- context, 0,
- BaseApplication.getSingletons(context).getTunerSetupIntent(context),
- PendingIntent.FLAG_UPDATE_CURRENT);
+ public static void cancelNotification(Context context) {
+ NotificationManager notificationManager =
+ (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ notificationManager.cancel(NOTIFY_TAG, NOTIFY_ID);
}
- /** A static factory for {@link TunerHal} instances **/
@VisibleForTesting
- protected static class TunerHalFactory {
+ static class TunerHalFactory {
private Context mContext;
@VisibleForTesting TunerHal mTunerHal;
- private TunerHalFactory.GenerateTunerHalTask mGenerateTunerHalTask;
+ private GenerateTunerHalTask mGenerateTunerHalTask;
private final Executor mExecutor;
TunerHalFactory(Context context) {
@@ -477,7 +510,7 @@ public class BaseTunerSetupActivity extends SetupActivity {
@MainThread
void generate() {
if (mGenerateTunerHalTask == null && mTunerHal == null) {
- mGenerateTunerHalTask = new TunerHalFactory.GenerateTunerHalTask();
+ mGenerateTunerHalTask = new GenerateTunerHalTask();
mGenerateTunerHalTask.executeOnExecutor(mExecutor);
}
}
diff --git a/tuner/src/com/android/tv/tuner/setup/WelcomeFragment.java b/src/com/android/tv/tuner/setup/WelcomeFragment.java
index 8fc9f2a0..326fe126 100644
--- a/tuner/src/com/android/tv/tuner/setup/WelcomeFragment.java
+++ b/src/com/android/tv/tuner/setup/WelcomeFragment.java
@@ -30,8 +30,7 @@ import java.util.List;
/** A fragment for initial screen. */
public class WelcomeFragment extends SetupMultiPaneFragment {
- public static final String ACTION_CATEGORY =
- "com.android.tv.tuner.setup.WelcomeFragment";
+ public static final String ACTION_CATEGORY = "com.android.tv.tuner.setup.WelcomeFragment";
@Override
protected SetupGuidedStepFragment onCreateContentFragment() {
@@ -50,7 +49,6 @@ public class WelcomeFragment extends SetupMultiPaneFragment {
return false;
}
- /** The content fragment of {@link WelcomeFragment}. */
public static class ContentFragment extends SetupGuidedStepFragment {
private int mChannelCountOnPreference;
@@ -69,7 +67,7 @@ public class WelcomeFragment extends SetupMultiPaneFragment {
int tunerType =
getArguments()
.getInt(
- BaseTunerSetupActivity.KEY_TUNER_TYPE,
+ TunerSetupActivity.KEY_TUNER_TYPE,
TunerHal.TUNER_TYPE_BUILT_IN);
if (mChannelCountOnPreference == 0) {
switch (tunerType) {
diff --git a/tuner/src/com/android/tv/tuner/source/FileTsStreamer.java b/src/com/android/tv/tuner/source/FileTsStreamer.java
index 2bdac238..f74274f4 100644
--- a/tuner/src/com/android/tv/tuner/source/FileTsStreamer.java
+++ b/src/com/android/tv/tuner/source/FileTsStreamer.java
@@ -20,15 +20,15 @@ import android.content.Context;
import android.os.Environment;
import android.util.Log;
import android.util.SparseBooleanArray;
-import com.google.android.exoplayer.C;
-import com.google.android.exoplayer.upstream.DataSpec;
+import com.android.tv.Features;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.tuner.ChannelScanFileParser.ScanChannel;
-import com.android.tv.tuner.TunerFeatures;
import com.android.tv.tuner.data.TunerChannel;
import com.android.tv.tuner.ts.TsParser;
import com.android.tv.tuner.tvinput.EventDetector;
import com.android.tv.tuner.tvinput.FileSourceEventDetector;
+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;
@@ -128,7 +128,7 @@ public class FileTsStreamer implements TsStreamer {
public FileTsStreamer(EventDetector.EventListener eventListener, Context context) {
mEventDetector =
new FileSourceEventDetector(
- eventListener, TunerFeatures.ENABLE_FILE_DVB.isEnabled(context));
+ eventListener, Features.ENABLE_FILE_DVB.isEnabled(context));
mContext = context;
}
@@ -142,7 +142,7 @@ public class FileTsStreamer implements TsStreamer {
mEventDetector.start(mSource, FileSourceEventDetector.ALL_PROGRAM_NUMBERS);
mSource.addPidFilter(TsParser.PAT_PID);
mSource.addPidFilter(TsParser.ATSC_SI_BASE_PID);
- if (TunerFeatures.ENABLE_FILE_DVB.isEnabled(mContext)) {
+ if (Features.ENABLE_FILE_DVB.isEnabled(mContext)) {
mSource.addPidFilter(TsParser.DVB_EIT_PID);
mSource.addPidFilter(TsParser.DVB_SDT_PID);
}
@@ -174,7 +174,7 @@ public class FileTsStreamer implements TsStreamer {
mSource.addPidFilter(channel.getPcrPid());
mSource.addPidFilter(TsParser.PAT_PID);
mSource.addPidFilter(TsParser.ATSC_SI_BASE_PID);
- if (TunerFeatures.ENABLE_FILE_DVB.isEnabled(mContext)) {
+ if (Features.ENABLE_FILE_DVB.isEnabled(mContext)) {
mSource.addPidFilter(TsParser.DVB_EIT_PID);
mSource.addPidFilter(TsParser.DVB_SDT_PID);
}
diff --git a/tuner/src/com/android/tv/tuner/source/TsDataSource.java b/src/com/android/tv/tuner/source/TsDataSource.java
index be902944..be902944 100644
--- a/tuner/src/com/android/tv/tuner/source/TsDataSource.java
+++ b/src/com/android/tv/tuner/source/TsDataSource.java
diff --git a/tuner/src/com/android/tv/tuner/source/TsDataSourceManager.java b/src/com/android/tv/tuner/source/TsDataSourceManager.java
index 08acbc88..fc8a8327 100644
--- a/tuner/src/com/android/tv/tuner/source/TsDataSourceManager.java
+++ b/src/com/android/tv/tuner/source/TsDataSourceManager.java
@@ -74,7 +74,7 @@ public class TsDataSourceManager {
*/
public TsDataSource createDataSource(
Context context, TunerChannel channel, EventDetector.EventListener eventListener) {
- if (channel.getType() == Channel.TunerType.TYPE_FILE) {
+ if (channel.getType() == Channel.TYPE_FILE) {
// MPEG2 TS captured stream file recording is not supported.
if (mIsRecording) {
return null;
diff --git a/tuner/src/com/android/tv/tuner/source/TsStreamWriter.java b/src/com/android/tv/tuner/source/TsStreamWriter.java
index f90136bf..f90136bf 100644
--- a/tuner/src/com/android/tv/tuner/source/TsStreamWriter.java
+++ b/src/com/android/tv/tuner/source/TsStreamWriter.java
diff --git a/tuner/src/com/android/tv/tuner/source/TsStreamer.java b/src/com/android/tv/tuner/source/TsStreamer.java
index 3dbba7e7..3dbba7e7 100644
--- a/tuner/src/com/android/tv/tuner/source/TsStreamer.java
+++ b/src/com/android/tv/tuner/source/TsStreamer.java
diff --git a/tuner/src/com/android/tv/tuner/source/TunerTsStreamer.java b/src/com/android/tv/tuner/source/TunerTsStreamer.java
index 580538c8..21b7a1f8 100644
--- a/tuner/src/com/android/tv/tuner/source/TunerTsStreamer.java
+++ b/src/com/android/tv/tuner/source/TunerTsStreamer.java
@@ -19,8 +19,6 @@ package com.android.tv.tuner.source;
import android.content.Context;
import android.util.Log;
import android.util.Pair;
-import com.google.android.exoplayer.C;
-import com.google.android.exoplayer.upstream.DataSpec;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.tuner.ChannelScanFileParser;
import com.android.tv.tuner.TunerHal;
@@ -28,6 +26,8 @@ import com.android.tv.tuner.TunerPreferences;
import com.android.tv.tuner.data.TunerChannel;
import com.android.tv.tuner.tvinput.EventDetector;
import com.android.tv.tuner.tvinput.EventDetector.EventListener;
+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;
diff --git a/tuner/src/com/android/tv/tuner/source/TunerTsStreamerManager.java b/src/com/android/tv/tuner/source/TunerTsStreamerManager.java
index 11ebb6cc..e94bd56c 100644
--- a/tuner/src/com/android/tv/tuner/source/TunerTsStreamerManager.java
+++ b/src/com/android/tv/tuner/source/TunerTsStreamerManager.java
@@ -17,8 +17,8 @@
package com.android.tv.tuner.source;
import android.content.Context;
+import com.android.tv.common.AutoCloseableUtils;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.common.util.AutoCloseableUtils;
import com.android.tv.tuner.TunerHal;
import com.android.tv.tuner.data.TunerChannel;
import com.android.tv.tuner.tvinput.EventDetector;
diff --git a/tuner/src/com/android/tv/tuner/ts/SectionParser.java b/src/com/android/tv/tuner/ts/SectionParser.java
index 2270c0f1..6d0eb90f 100644
--- a/tuner/src/com/android/tv/tuner/ts/SectionParser.java
+++ b/src/com/android/tv/tuner/ts/SectionParser.java
@@ -18,7 +18,6 @@ package com.android.tv.tuner.ts;
import android.media.tv.TvContentRating;
import android.media.tv.TvContract.Programs.Genres;
-import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.ArraySet;
@@ -49,9 +48,9 @@ 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 com.ibm.icu.text.UnicodeDecompressor;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
@@ -615,10 +614,6 @@ public class SectionParser {
ISO_LANGUAGE_CODE_MAP.put("esl", "spa"); // Special entry for channel 9-1 KQED in bay area.
}
- @Nullable
- private static final Charset SCSU_CHARSET =
- Charset.isSupported("SCSU") ? Charset.forName("SCSU") : null;
-
// Containers to store the last version numbers of the PSIP sections.
private final HashMap<PsipSection, Integer> mSectionVersionMap = new HashMap<>();
private final SparseArray<List<EttItem>> mParsedEttItems = new SparseArray<>();
@@ -930,12 +925,10 @@ public class SectionParser {
}
if (!accessControlled
&& !hidden
- && (serviceType == Channel.AtscServiceType.SERVICE_TYPE_ATSC_AUDIO
- || serviceType
- == Channel.AtscServiceType.SERVICE_TYPE_ATSC_DIGITAL_TELEVISION
+ && (serviceType == Channel.SERVICE_TYPE_ATSC_AUDIO
+ || serviceType == Channel.SERVICE_TYPE_ATSC_DIGITAL_TELEVISION
|| serviceType
- == Channel.AtscServiceType
- .SERVICE_TYPE_UNASSOCIATED_SMALL_SCREEN_SERVICE)) {
+ == Channel.SERVICE_TYPE_UNASSOCIATED_SMALL_SCREEN_SERVICE)) {
// Hide hidden, encrypted, or unsupported ATSC service type channels
results.add(
new VctItem(
@@ -1218,7 +1211,7 @@ public class SectionParser {
if (audioTrack.language == null) {
audioTrack.language = "";
}
- audioTrack.audioType = AtscAudioTrack.AudioType.AUDIOTYPE_UNDEFINED;
+ audioTrack.audioType = AtscAudioTrack.AUDIOTYPE_UNDEFINED;
audioTrack.channelCount = audioDescriptor.getNumChannels();
audioTrack.sampleRate = audioDescriptor.getSampleRate();
ac3Tracks.add(audioTrack);
@@ -2000,22 +1993,19 @@ public class SectionParser {
Log.e(TAG, "Broken text.");
return null;
}
+ byte[] bytes = Arrays.copyOfRange(data, pos + 3, pos + 3 + numBytes);
if (compressionType == COMPRESSION_TYPE_NO_COMPRESSION) {
- switch (mode) {
- case MODE_SELECTED_UNICODE_RANGE_1:
- return new String(data, pos + 3, numBytes, StandardCharsets.ISO_8859_1);
- case MODE_SCSU:
- if (SCSU_CHARSET != null) {
- return new String(data, pos + 3, numBytes, SCSU_CHARSET);
- } else {
- Log.w(TAG, "SCSU not supported");
- return null;
- }
- case MODE_UTF16:
- return new String(data, pos + 3, numBytes, StandardCharsets.UTF_16);
- default:
- Log.w(TAG, "Unsupported text mode " + mode);
- return null;
+ try {
+ switch (mode) {
+ case MODE_SELECTED_UNICODE_RANGE_1:
+ return new String(bytes, "ISO-8859-1");
+ case MODE_SCSU:
+ return UnicodeDecompressor.decompress(bytes);
+ case MODE_UTF16:
+ return new String(bytes, "UTF-16");
+ }
+ } catch (UnsupportedEncodingException e) {
+ Log.e(TAG, "Unsupported text format.", e);
}
}
pos += 3 + numBytes;
diff --git a/tuner/src/com/android/tv/tuner/ts/TsParser.java b/src/com/android/tv/tuner/ts/TsParser.java
index fbedc2c3..fbedc2c3 100644
--- a/tuner/src/com/android/tv/tuner/ts/TsParser.java
+++ b/src/com/android/tv/tuner/ts/TsParser.java
diff --git a/tuner/src/com/android/tv/tuner/tvinput/ChannelDataManager.java b/src/com/android/tv/tuner/tvinput/ChannelDataManager.java
index b4a23ea0..49fc0ca1 100644
--- a/tuner/src/com/android/tv/tuner/tvinput/ChannelDataManager.java
+++ b/src/com/android/tv/tuner/tvinput/ChannelDataManager.java
@@ -16,6 +16,7 @@
package com.android.tv.tuner.tvinput;
+import android.content.ComponentName;
import android.content.ContentProviderOperation;
import android.content.ContentUris;
import android.content.ContentValues;
@@ -32,12 +33,11 @@ import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.text.format.DateUtils;
import android.util.Log;
-import com.android.tv.common.BaseApplication;
-import com.android.tv.common.util.PermissionUtils;
import com.android.tv.tuner.TunerPreferences;
import com.android.tv.tuner.data.PsipData.EitItem;
import com.android.tv.tuner.data.TunerChannel;
import com.android.tv.tuner.util.ConvertUtils;
+import com.android.tv.util.PermissionUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -52,7 +52,6 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
/** Manages the channel info and EPG data through {@link TvInputManager}. */
-@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed
public class ChannelDataManager implements Handler.Callback {
private static final String TAG = "ChannelDataManager";
@@ -71,7 +70,6 @@ public class ChannelDataManager implements Handler.Callback {
private static final String[] CHANNEL_DATA_SELECTION_ARGS =
new String[] {
TvContract.Channels._ID,
- TvContract.Channels.COLUMN_LOCKED,
TvContract.Channels.COLUMN_INTERNAL_PROVIDER_DATA,
TvContract.Channels.COLUMN_INTERNAL_PROVIDER_FLAG1
};
@@ -148,7 +146,10 @@ public class ChannelDataManager implements Handler.Callback {
public ChannelDataManager(Context context) {
mContext = context;
- mInputId = BaseApplication.getSingletons(context).getEmbeddedTunerInputId();
+ mInputId =
+ TvContract.buildInputId(
+ new ComponentName(
+ mContext.getPackageName(), TunerTvInputService.class.getName()));
mChannelsUri = TvContract.buildChannelsUriForInput(mInputId);
mTunerChannelMap = new ConcurrentHashMap<>();
mTunerChannelIdMap = new ConcurrentSkipListMap<>();
@@ -210,7 +211,6 @@ public class ChannelDataManager implements Handler.Callback {
}
mHandler.sendEmptyMessage(MSG_BUILD_CHANNEL_MAP);
byte[] data = null;
- boolean locked = false;
try (Cursor cursor =
mContext.getContentResolver()
.query(
@@ -220,8 +220,7 @@ public class ChannelDataManager implements Handler.Callback {
null,
null)) {
if (cursor != null && cursor.moveToFirst()) {
- locked = cursor.getInt(1) > 0;
- data = cursor.getBlob(2);
+ data = cursor.getBlob(1);
}
}
if (data == null) {
@@ -231,7 +230,6 @@ public class ChannelDataManager implements Handler.Callback {
if (channel == null) {
return null;
}
- channel.setLocked(locked);
channel.setChannelId(channelId);
return channel;
}
@@ -268,8 +266,11 @@ public class ChannelDataManager implements Handler.Callback {
.query(mChannelsUri, CHANNEL_DATA_SELECTION_ARGS, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
do {
- TunerChannel channel = TunerChannel.fromCursor(cursor);
+ long channelId = cursor.getLong(0);
+ byte[] data = cursor.getBlob(1);
+ TunerChannel channel = TunerChannel.parseFrom(data);
if (channel != null) {
+ channel.setChannelId(channelId);
mPreviousScannedChannels.add(channel);
}
} while (cursor.moveToNext());
@@ -382,8 +383,6 @@ public class ChannelDataManager implements Handler.Callback {
checkVersion();
return true;
}
- default: // fall out
- Log.w(TAG, "unexpected case in handleMessage ( " + msg.what + " )");
}
return false;
}
@@ -699,11 +698,14 @@ public class ChannelDataManager implements Handler.Callback {
.query(mChannelsUri, CHANNEL_DATA_SELECTION_ARGS, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
do {
- TunerChannel tunerChannel = TunerChannel.fromCursor(cursor);
+ channelId = cursor.getLong(0);
+ byte[] providerData = cursor.getBlob(1);
+ TunerChannel tunerChannel = TunerChannel.parseFrom(providerData);
if (tunerChannel != null && tunerChannel.compareTo(channel) == 0) {
- mTunerChannelIdMap.put(channel, tunerChannel.getChannelId());
- mTunerChannelMap.put(tunerChannel.getChannelId(), channel);
- return tunerChannel.getChannelId();
+ channel.setChannelId(channelId);
+ mTunerChannelIdMap.put(channel, channelId);
+ mTunerChannelMap.put(channelId, channel);
+ return channelId;
}
} while (cursor.moveToNext());
}
@@ -769,8 +771,11 @@ public class ChannelDataManager implements Handler.Callback {
.query(mChannelsUri, CHANNEL_DATA_SELECTION_ARGS, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
do {
- TunerChannel channel = TunerChannel.fromCursor(cursor);
+ long channelId = cursor.getLong(0);
+ byte[] data = cursor.getBlob(1);
+ TunerChannel channel = TunerChannel.parseFrom(data);
if (channel != null) {
+ channel.setChannelId(channelId);
channels.add(channel);
}
} while (cursor.moveToNext());
diff --git a/tuner/src/com/android/tv/tuner/tvinput/EventDetector.java b/src/com/android/tv/tuner/tvinput/EventDetector.java
index c529c6db..c529c6db 100644
--- a/tuner/src/com/android/tv/tuner/tvinput/EventDetector.java
+++ b/src/com/android/tv/tuner/tvinput/EventDetector.java
diff --git a/tuner/src/com/android/tv/tuner/tvinput/FileSourceEventDetector.java b/src/com/android/tv/tuner/tvinput/FileSourceEventDetector.java
index ab05aa02..f2ed72f1 100644
--- a/tuner/src/com/android/tv/tuner/tvinput/FileSourceEventDetector.java
+++ b/src/com/android/tv/tuner/tvinput/FileSourceEventDetector.java
@@ -43,7 +43,7 @@ import java.util.Set;
*/
public class FileSourceEventDetector {
private static final String TAG = "FileSourceEventDetector";
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = true;
public static final int ALL_PROGRAM_NUMBERS = 0;
private TsParser mTsParser;
diff --git a/tuner/src/com/android/tv/tuner/tvinput/PlaybackBufferListener.java b/src/com/android/tv/tuner/tvinput/PlaybackBufferListener.java
index 1628bcfb..1628bcfb 100644
--- a/tuner/src/com/android/tv/tuner/tvinput/PlaybackBufferListener.java
+++ b/src/com/android/tv/tuner/tvinput/PlaybackBufferListener.java
diff --git a/tuner/src/com/android/tv/tuner/tvinput/TunerDebug.java b/src/com/android/tv/tuner/tvinput/TunerDebug.java
index 1df0b5c3..1df0b5c3 100644
--- a/tuner/src/com/android/tv/tuner/tvinput/TunerDebug.java
+++ b/src/com/android/tv/tuner/tvinput/TunerDebug.java
diff --git a/tuner/src/com/android/tv/tuner/tvinput/TunerRecordingSession.java b/src/com/android/tv/tuner/tvinput/TunerRecordingSession.java
index a1f0c773..a1f0c773 100644
--- a/tuner/src/com/android/tv/tuner/tvinput/TunerRecordingSession.java
+++ b/src/com/android/tv/tuner/tvinput/TunerRecordingSession.java
diff --git a/tuner/src/com/android/tv/tuner/tvinput/TunerRecordingSessionWorker.java b/src/com/android/tv/tuner/tvinput/TunerRecordingSessionWorker.java
index 9843d41d..1bc4e295 100644
--- a/tuner/src/com/android/tv/tuner/tvinput/TunerRecordingSessionWorker.java
+++ b/src/com/android/tv/tuner/tvinput/TunerRecordingSessionWorker.java
@@ -22,7 +22,6 @@ import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.media.tv.TvContract;
-import android.media.tv.TvContract.RecordedPrograms;
import android.media.tv.TvInputManager;
import android.net.Uri;
import android.os.AsyncTask;
@@ -32,14 +31,13 @@ import android.os.Message;
import android.support.annotation.IntDef;
import android.support.annotation.MainThread;
import android.support.annotation.Nullable;
-import android.support.media.tv.Program;
import android.util.Log;
import android.util.Pair;
-import com.google.android.exoplayer.C;
-import com.android.tv.common.BaseApplication;
+import com.android.tv.TvApplication;
+import com.android.tv.common.SoftPreconditions;
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.dvr.DvrStorageStatusManager;
+import com.android.tv.dvr.data.RecordedProgram;
import com.android.tv.tuner.DvbDeviceAccessor;
import com.android.tv.tuner.data.PsipData;
import com.android.tv.tuner.data.PsipData.EitItem;
@@ -51,6 +49,8 @@ import com.android.tv.tuner.exoplayer.buffer.BufferManager;
import com.android.tv.tuner.exoplayer.buffer.DvrStorageManager;
import com.android.tv.tuner.source.TsDataSource;
import com.android.tv.tuner.source.TsDataSourceManager;
+import com.android.tv.util.Utils;
+import com.google.android.exoplayer.C;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Retention;
@@ -62,7 +62,6 @@ import java.util.Random;
import java.util.concurrent.TimeUnit;
/** Implements a DVR feature. */
-@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed
public class TunerRecordingSessionWorker
implements PlaybackBufferListener,
EventDetector.EventListener,
@@ -90,24 +89,9 @@ public class TunerRecordingSessionWorker
private static final int MSG_UPDATE_CC_INFO = 7;
private final RecordingCapability mCapabilities;
- private static final String[] PROGRAM_PROJECTION = {
- TvContract.Programs.COLUMN_CHANNEL_ID,
- TvContract.Programs.COLUMN_TITLE,
- TvContract.Programs.COLUMN_SEASON_TITLE,
- TvContract.Programs.COLUMN_EPISODE_TITLE,
- TvContract.Programs.COLUMN_SEASON_DISPLAY_NUMBER,
- TvContract.Programs.COLUMN_EPISODE_DISPLAY_NUMBER,
- TvContract.Programs.COLUMN_SHORT_DESCRIPTION,
- TvContract.Programs.COLUMN_POSTER_ART_URI,
- TvContract.Programs.COLUMN_THUMBNAIL_URI,
- TvContract.Programs.COLUMN_CANONICAL_GENRE,
- TvContract.Programs.COLUMN_CONTENT_RATING,
- TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS,
- TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS,
- TvContract.Programs.COLUMN_VIDEO_WIDTH,
- TvContract.Programs.COLUMN_VIDEO_HEIGHT,
- TvContract.Programs.COLUMN_INTERNAL_PROVIDER_DATA
- };
+ public RecordingCapability getCapabilities() {
+ return mCapabilities;
+ }
@IntDef({STATE_IDLE, STATE_TUNING, STATE_TUNED, STATE_RECORDING})
@Retention(RetentionPolicy.SOURCE)
@@ -123,7 +107,7 @@ public class TunerRecordingSessionWorker
private final Context mContext;
private final ChannelDataManager mChannelDataManager;
- private final RecordingStorageStatusManager mRecordingStorageStatusManager;
+ private final DvrStorageStatusManager mDvrStorageStatusManager;
private final Handler mHandler;
private final TsDataSourceManager mSourceManager;
private final Random mRandom = new Random();
@@ -154,8 +138,8 @@ public class TunerRecordingSessionWorker
HandlerThread handlerThread = new HandlerThread(TAG);
handlerThread.start();
mHandler = new Handler(handlerThread.getLooper(), this);
- mRecordingStorageStatusManager =
- BaseApplication.getSingletons(context).getRecordingStorageStatusManager();
+ mDvrStorageStatusManager =
+ TvApplication.getSingletons(context).getDvrStorageStatusManager();
mChannelDataManager = dataManager;
mChannelDataManager.checkDataVersion(context);
mSourceManager = TsDataSourceManager.createSourceManager(true);
@@ -301,7 +285,7 @@ public class TunerRecordingSessionWorker
if (mSessionState != STATE_RECORDING) {
return true;
}
- if (!mRecordingStorageStatusManager.isStorageSufficient()) {
+ if (!mDvrStorageStatusManager.isStorageSufficient()) {
if (mRecorderRunning) {
stopRecorder();
}
@@ -385,7 +369,7 @@ public class TunerRecordingSessionWorker
Log.w(TAG, "Failed to start recording. Not a recordable channel: " + mChannel);
return false;
}
- if (!mRecordingStorageStatusManager.isStorageSufficient()) {
+ if (!mDvrStorageStatusManager.isStorageSufficient()) {
mSession.onError(TvInputManager.RECORDING_ERROR_INSUFFICIENT_SPACE);
Log.w(TAG, "Tuning failed due to insufficient storage.");
return false;
@@ -407,9 +391,9 @@ public class TunerRecordingSessionWorker
return false;
}
mStorageDir =
- mRecordingStorageStatusManager.isStorageSufficient()
+ mDvrStorageStatusManager.isStorageSufficient()
? new File(
- mRecordingStorageStatusManager.getRecordingRootDataDirectory(),
+ mDvrStorageStatusManager.getRecordingRootDataDirectory(),
getStorageKey())
: null;
if (mStorageDir == null) {
@@ -479,6 +463,116 @@ public class TunerRecordingSessionWorker
return null;
}
+ private static class Program {
+ private final long mChannelId;
+ private final String mTitle;
+ private String mSeriesId;
+ private final String mSeasonTitle;
+ private final String mEpisodeTitle;
+ private final String mSeasonNumber;
+ private final String mEpisodeNumber;
+ private final String mDescription;
+ private final String mPosterArtUri;
+ private final String mThumbnailUri;
+ private final String mCanonicalGenres;
+ private final String mContentRatings;
+ private final long mStartTimeUtcMillis;
+ private final long mEndTimeUtcMillis;
+ private final int mVideoWidth;
+ private final int mVideoHeight;
+ private final byte[] mInternalProviderData;
+
+ private static final String[] PROJECTION = {
+ TvContract.Programs.COLUMN_CHANNEL_ID,
+ TvContract.Programs.COLUMN_TITLE,
+ TvContract.Programs.COLUMN_SEASON_TITLE,
+ TvContract.Programs.COLUMN_EPISODE_TITLE,
+ TvContract.Programs.COLUMN_SEASON_DISPLAY_NUMBER,
+ TvContract.Programs.COLUMN_EPISODE_DISPLAY_NUMBER,
+ TvContract.Programs.COLUMN_SHORT_DESCRIPTION,
+ TvContract.Programs.COLUMN_POSTER_ART_URI,
+ TvContract.Programs.COLUMN_THUMBNAIL_URI,
+ TvContract.Programs.COLUMN_CANONICAL_GENRE,
+ TvContract.Programs.COLUMN_CONTENT_RATING,
+ TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS,
+ TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS,
+ TvContract.Programs.COLUMN_VIDEO_WIDTH,
+ TvContract.Programs.COLUMN_VIDEO_HEIGHT,
+ TvContract.Programs.COLUMN_INTERNAL_PROVIDER_DATA
+ };
+
+ public Program(Cursor cursor) {
+ int index = 0;
+ mChannelId = cursor.getLong(index++);
+ mTitle = cursor.getString(index++);
+ mSeasonTitle = cursor.getString(index++);
+ mEpisodeTitle = cursor.getString(index++);
+ mSeasonNumber = cursor.getString(index++);
+ mEpisodeNumber = cursor.getString(index++);
+ mDescription = cursor.getString(index++);
+ mPosterArtUri = cursor.getString(index++);
+ mThumbnailUri = cursor.getString(index++);
+ mCanonicalGenres = cursor.getString(index++);
+ mContentRatings = cursor.getString(index++);
+ mStartTimeUtcMillis = cursor.getLong(index++);
+ mEndTimeUtcMillis = cursor.getLong(index++);
+ mVideoWidth = cursor.getInt(index++);
+ mVideoHeight = cursor.getInt(index++);
+ mInternalProviderData = cursor.getBlob(index++);
+ SoftPreconditions.checkArgument(index == PROJECTION.length);
+ }
+
+ public Program(long channelId) {
+ mChannelId = channelId;
+ mTitle = "Unknown";
+ mSeasonTitle = "";
+ mEpisodeTitle = "";
+ mSeasonNumber = "";
+ mEpisodeNumber = "";
+ mDescription = "Unknown";
+ mPosterArtUri = null;
+ mThumbnailUri = null;
+ mCanonicalGenres = null;
+ mContentRatings = null;
+ mStartTimeUtcMillis = 0;
+ mEndTimeUtcMillis = 0;
+ mVideoWidth = 0;
+ mVideoHeight = 0;
+ mInternalProviderData = null;
+ }
+
+ public static Program onQuery(Cursor c) {
+ Program program = null;
+ if (c != null && c.moveToNext()) {
+ program = new Program(c);
+ }
+ return program;
+ }
+
+ public ContentValues buildValues() {
+ ContentValues values = new ContentValues();
+ int index = 0;
+ values.put(PROJECTION[index++], mChannelId);
+ values.put(PROJECTION[index++], mTitle);
+ values.put(PROJECTION[index++], mSeasonTitle);
+ values.put(PROJECTION[index++], mEpisodeTitle);
+ values.put(PROJECTION[index++], mSeasonNumber);
+ values.put(PROJECTION[index++], mEpisodeNumber);
+ values.put(PROJECTION[index++], mDescription);
+ values.put(PROJECTION[index++], mPosterArtUri);
+ values.put(PROJECTION[index++], mThumbnailUri);
+ values.put(PROJECTION[index++], mCanonicalGenres);
+ values.put(PROJECTION[index++], mContentRatings);
+ values.put(PROJECTION[index++], mStartTimeUtcMillis);
+ values.put(PROJECTION[index++], mEndTimeUtcMillis);
+ values.put(PROJECTION[index++], mVideoWidth);
+ values.put(PROJECTION[index++], mVideoHeight);
+ values.put(PROJECTION[index++], mInternalProviderData);
+ SoftPreconditions.checkArgument(index == PROJECTION.length);
+ return values;
+ }
+ }
+
private Program getRecordedProgram() {
ContentResolver resolver = mContext.getContentResolver();
Uri programUri = mProgramUri;
@@ -486,9 +580,9 @@ public class TunerRecordingSessionWorker
long avg = mRecordStartTime / 2 + mRecordEndTime / 2;
programUri = TvContract.buildProgramsUriForChannel(mChannel.getChannelId(), avg, avg);
}
- try (Cursor c = resolver.query(programUri, PROGRAM_PROJECTION, null, null, SORT_BY_TIME)) {
- if (c != null && c.moveToNext()) {
- Program result = Program.fromCursor(c);
+ try (Cursor c = resolver.query(programUri, Program.PROJECTION, null, null, SORT_BY_TIME)) {
+ if (c != null) {
+ Program result = Program.onQuery(c);
if (DEBUG) {
Log.v(TAG, "Finished query for " + this);
}
@@ -497,7 +591,7 @@ public class TunerRecordingSessionWorker
if (c == null) {
Log.e(TAG, "Unknown query error for " + this);
} else {
- if (DEBUG) Log.d(TAG, "Can not find program:" + programUri);
+ if (DEBUG) Log.d(TAG, "Canceled query for " + this);
}
return null;
}
@@ -511,17 +605,22 @@ public class TunerRecordingSessionWorker
long totalBytes,
long startTime,
long endTime) {
- ContentValues values = new ContentValues();
- values.put(RecordedPrograms.COLUMN_INPUT_ID, mInputId);
- values.put(RecordedPrograms.COLUMN_CHANNEL_ID, channelId);
- values.put(RecordedPrograms.COLUMN_RECORDING_DATA_URI, storageUri);
- values.put(RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS, endTime - startTime);
- values.put(RecordedPrograms.COLUMN_RECORDING_DATA_BYTES, totalBytes);
- // startTime and endTime could be overridden by program's start and end value.
- values.put(RecordedPrograms.COLUMN_START_TIME_UTC_MILLIS, startTime);
- values.put(RecordedPrograms.COLUMN_END_TIME_UTC_MILLIS, endTime);
+ // TODO: Set title even though program is null.
+ RecordedProgram recordedProgram =
+ RecordedProgram.builder()
+ .setInputId(mInputId)
+ .setChannelId(channelId)
+ .setDataUri(storageUri)
+ .setDurationMillis(endTime - startTime)
+ .setDataBytes(totalBytes)
+ // startTime and endTime could be overridden by program's start and end
+ // value.
+ .setStartTimeUtcMillis(startTime)
+ .setEndTimeUtcMillis(endTime)
+ .build();
+ ContentValues values = RecordedProgram.toValues(recordedProgram);
if (program != null) {
- values.putAll(program.toContentValues());
+ values.putAll(program.buildValues());
}
return mContext.getContentResolver()
.insert(TvContract.RecordedPrograms.CONTENT_URI, values);
@@ -576,7 +675,7 @@ public class TunerRecordingSessionWorker
return null;
}
for (File file : files) {
- CommonUtils.deleteDirOrFile(file);
+ Utils.deleteDirOrFile(file);
}
return null;
}
diff --git a/tuner/src/com/android/tv/tuner/tvinput/TunerSession.java b/src/com/android/tv/tuner/tvinput/TunerSession.java
index 0efc6472..eec5da1f 100644
--- a/tuner/src/com/android/tv/tuner/tvinput/TunerSession.java
+++ b/src/com/android/tv/tuner/tvinput/TunerSession.java
@@ -35,24 +35,24 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
-import com.google.android.exoplayer.audio.AudioCapabilities;
-import com.android.tv.common.CommonPreferences.CommonPreferencesChangedListener;
-import com.android.tv.common.util.SystemPropertiesProxy;
import com.android.tv.tuner.R;
import com.android.tv.tuner.TunerPreferences;
+import com.android.tv.tuner.TunerPreferences.TunerPreferencesChangedListener;
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.nano.Track.AtscCaptionTrack;
import com.android.tv.tuner.util.GlobalSettingsUtils;
import com.android.tv.tuner.util.StatusTextUtils;
+import com.android.tv.tuner.util.SystemPropertiesProxy;
+import com.google.android.exoplayer.audio.AudioCapabilities;
/**
* Provides a tuner TV input session. It handles Overlay UI works. Main tuner input functions are
* implemented in {@link TunerSessionWorker}.
*/
public class TunerSession extends TvInputService.Session
- implements Handler.Callback, CommonPreferencesChangedListener {
+ implements Handler.Callback, TunerPreferencesChangedListener {
private static final String TAG = "TunerSession";
private static final boolean DEBUG = false;
private static final String USBTUNER_SHOW_DEBUG = "persist.tv.tuner.show_debug";
@@ -100,7 +100,7 @@ public class TunerSession extends TvInputService.Session
CaptionLayout captionLayout = (CaptionLayout) mOverlayView.findViewById(R.id.caption);
mCaptionTrackRenderer = new CaptionTrackRenderer(captionLayout);
mSessionWorker = new TunerSessionWorker(context, channelDataManager, this);
- TunerPreferences.setCommonPreferencesChangedListener(this);
+ TunerPreferences.setTunerPreferencesChangedListener(this);
}
public boolean isReleased() {
@@ -210,7 +210,7 @@ public class TunerSession extends TvInputService.Session
mReleased = true;
mSessionWorker.release();
mUiHandler.removeCallbacksAndMessages(null);
- TunerPreferences.setCommonPreferencesChangedListener(null);
+ TunerPreferences.setTunerPreferencesChangedListener(null);
}
/** Sets {@link AudioCapabilities}. */
@@ -335,7 +335,7 @@ public class TunerSession extends TvInputService.Session
}
@Override
- public void onCommonPreferencesChanged() {
+ public void onTunerPreferencesChanged() {
mSessionWorker.sendMessage(TunerSessionWorker.MSG_TUNER_PREFERENCES_CHANGED);
}
}
diff --git a/tuner/src/com/android/tv/tuner/tvinput/TunerSessionWorker.java b/src/com/android/tv/tuner/tvinput/TunerSessionWorker.java
index 2b86283a..7a0897e2 100644
--- a/tuner/src/com/android/tv/tuner/tvinput/TunerSessionWorker.java
+++ b/src/com/android/tv/tuner/tvinput/TunerSessionWorker.java
@@ -42,15 +42,12 @@ import android.util.Pair;
import android.util.SparseArray;
import android.view.Surface;
import android.view.accessibility.CaptioningManager;
-import com.google.android.exoplayer.ExoPlayer;
-import com.google.android.exoplayer.audio.AudioCapabilities;
-import com.android.tv.common.CommonPreferences.TrickplaySetting;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.TvContentRatingCache;
-import com.android.tv.common.customization.CustomizationManager;
-import com.android.tv.common.customization.CustomizationManager.TRICKPLAY_MODE;
-import com.android.tv.common.util.SystemPropertiesProxy;
+import com.android.tv.customization.TvCustomizationManager;
+import com.android.tv.customization.TvCustomizationManager.TRICKPLAY_MODE;
import com.android.tv.tuner.TunerPreferences;
+import com.android.tv.tuner.TunerPreferences.TrickplaySetting;
import com.android.tv.tuner.data.Cea708Data;
import com.android.tv.tuner.data.PsipData.EitItem;
import com.android.tv.tuner.data.PsipData.TvTracksInterface;
@@ -64,9 +61,13 @@ import com.android.tv.tuner.exoplayer.buffer.BufferManager;
import com.android.tv.tuner.exoplayer.buffer.BufferManager.StorageManager;
import com.android.tv.tuner.exoplayer.buffer.DvrStorageManager;
import com.android.tv.tuner.exoplayer.buffer.TrickplayStorageManager;
+import com.android.tv.tuner.exoplayer.ffmpeg.FfmpegDecoderClient;
import com.android.tv.tuner.source.TsDataSource;
import com.android.tv.tuner.source.TsDataSourceManager;
import com.android.tv.tuner.util.StatusTextUtils;
+import com.android.tv.tuner.util.SystemPropertiesProxy;
+import com.google.android.exoplayer.ExoPlayer;
+import com.google.android.exoplayer.audio.AudioCapabilities;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
@@ -80,7 +81,6 @@ import java.util.concurrent.TimeUnit;
* handling {@link ExoPlayer}, managing a tuner device, trickplay, and so on.
*/
@WorkerThread
-@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed
public class TunerSessionWorker
implements PlaybackBufferListener,
MpegTsPlayer.VideoEventListener,
@@ -241,14 +241,14 @@ public class TunerSessionWorker
mPlaybackParams.setSpeed(1.0f);
mMaxTrickplayBufferSizeMb =
SystemPropertiesProxy.getInt(MAX_BUFFER_SIZE_KEY, MAX_BUFFER_SIZE_DEF);
- mTrickplayModeCustomization = CustomizationManager.getTrickplayMode(context);
+ mTrickplayModeCustomization = TvCustomizationManager.getTrickplayMode(context);
if (mTrickplayModeCustomization
- == CustomizationManager.TRICKPLAY_MODE_USE_EXTERNAL_STORAGE) {
+ == TvCustomizationManager.TRICKPLAY_MODE_USE_EXTERNAL_STORAGE) {
boolean useExternalStorage =
Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
&& Environment.isExternalStorageRemovable();
mTrickplayBufferDir = useExternalStorage ? context.getExternalCacheDir() : null;
- } else if (mTrickplayModeCustomization == CustomizationManager.TRICKPLAY_MODE_ENABLED) {
+ } else if (mTrickplayModeCustomization == TvCustomizationManager.TRICKPLAY_MODE_ENABLED) {
mTrickplayBufferDir = context.getCacheDir();
} else {
mTrickplayBufferDir = null;
@@ -257,7 +257,7 @@ public class TunerSessionWorker
mTrickplaySetting = TunerPreferences.getTrickplaySetting(context);
if (mTrickplaySetting != TunerPreferences.TRICKPLAY_SETTING_NOT_SET
&& mTrickplayModeCustomization
- == CustomizationManager.TRICKPLAY_MODE_USE_EXTERNAL_STORAGE) {
+ == TvCustomizationManager.TRICKPLAY_MODE_USE_EXTERNAL_STORAGE) {
// Consider the case of Customization package updates the value of trickplay mode
// to TRICKPLAY_MODE_USE_EXTERNAL_STORAGE after install.
mTrickplaySetting = TunerPreferences.TRICKPLAY_SETTING_NOT_SET;
@@ -271,8 +271,7 @@ public class TunerSessionWorker
// NOTE: We assume that TunerSessionWorker instance will be at most one.
// Only one TunerSessionWorker can be connected to FfmpegDecoderClient at any given time.
// connect() will return false, if there is a connected TunerSessionWorker already.
- mHasSoftwareAudioDecoder = false; // TODO reimplement ffmpeg for google3
- // TODO connect the ffmpeg client and report if available.
+ mHasSoftwareAudioDecoder = FfmpegDecoderClient.connect(context);
}
// Public methods
@@ -399,8 +398,7 @@ public class TunerSessionWorker
mReleaseRequested = true;
}
if (mHasSoftwareAudioDecoder) {
- // TODO reimplement for google3
- // Here disconnect ffmpeg
+ FfmpegDecoderClient.disconnect(mContext);
}
mChannelDataManager.setListener(null);
mHandler.removeCallbacksAndMessages(null);
@@ -595,7 +593,7 @@ public class TunerSessionWorker
}
private static class RecordedProgram {
- // private final long mChannelId;
+ private final long mChannelId;
private final String mDataUri;
private static final String[] PROJECTION = {
@@ -605,13 +603,12 @@ public class TunerSessionWorker
public RecordedProgram(Cursor cursor) {
int index = 0;
- // mChannelId = cursor.getLong(index++);
- index++;
+ mChannelId = cursor.getLong(index++);
mDataUri = cursor.getString(index++);
}
public RecordedProgram(long channelId, String dataUri) {
- // mChannelId = channelId;
+ mChannelId = channelId;
mDataUri = dataUri;
}
@@ -709,11 +706,6 @@ public class TunerSessionWorker
clearCallbacksAndMessagesSafely();
mChannelDataManager.removeAllCallbacksAndMessages();
if (channel != null) {
- if (mTvInputManager.isParentalControlsEnabled() && channel.isLocked()) {
- Log.i(TAG, "onTune() is failed. Channel is blocked" + channel);
- mSession.notifyContentBlocked(TvContentRating.UNRATED);
- return true;
- }
mChannelDataManager.requestProgramsData(channel);
}
prepareTune(channel, recording);
@@ -948,10 +940,6 @@ public class TunerSessionWorker
}
case MSG_SELECT_TRACK:
{
- if (mPlayer == null) {
- Log.w(TAG, "mPlayer is null when doselectTrack is called");
- return false;
- }
if (mChannel != null || mRecordingId != null) {
doSelectTrack(msg.arg1, (String) msg.obj);
}
@@ -1070,82 +1058,84 @@ public class TunerSessionWorker
return true;
}
case MSG_CHECK_SIGNAL:
- if (mChannel == null || mPlayer == null) {
- return true;
- }
- TsDataSource source = mPlayer.getDataSource();
- long limitInBytes = source != null ? source.getBufferedPosition() : 0L;
- if (TunerDebug.ENABLED) {
- TunerDebug.calculateDiff();
- mSession.sendUiMessage(
- TunerSession.MSG_UI_SET_STATUS_TEXT,
- Html.fromHtml(
- StatusTextUtils.getStatusWarningInHTML(
- (limitInBytes - mLastLimitInBytes) / TS_PACKET_SIZE,
- TunerDebug.getVideoFrameDrop(),
- TunerDebug.getBytesInQueue(),
- TunerDebug.getAudioPositionUs(),
- TunerDebug.getAudioPositionUsRate(),
- TunerDebug.getAudioPtsUs(),
- TunerDebug.getAudioPtsUsRate(),
- TunerDebug.getVideoPtsUs(),
- TunerDebug.getVideoPtsUsRate())));
- }
- mSession.sendUiMessage(TunerSession.MSG_UI_HIDE_MESSAGE);
- long currentTime = SystemClock.elapsedRealtime();
- long bufferingTimeMs =
- mBufferingStartTimeMs != INVALID_TIME
- ? currentTime - mBufferingStartTimeMs
- : mBufferingStartTimeMs;
- long preparingTimeMs =
- mPreparingStartTimeMs != INVALID_TIME
- ? currentTime - mPreparingStartTimeMs
- : mPreparingStartTimeMs;
- boolean isBufferingTooLong =
- bufferingTimeMs > PLAYBACK_STATE_CHANGED_WAITING_THRESHOLD_MS;
- boolean isPreparingTooLong =
- preparingTimeMs > PLAYBACK_STATE_CHANGED_WAITING_THRESHOLD_MS;
- boolean isWeakSignal =
- source != null
- && mChannel.getType() != Channel.TunerType.TYPE_FILE
- && (isBufferingTooLong || isPreparingTooLong);
- if (isWeakSignal && !mReportedWeakSignal) {
- if (!mHandler.hasMessages(MSG_RETRY_PLAYBACK)) {
- mHandler.sendMessageDelayed(
- mHandler.obtainMessage(
- MSG_RETRY_PLAYBACK, System.identityHashCode(mPlayer)),
- PLAYBACK_RETRY_DELAY_MS);
+ {
+ if (mChannel == null || mPlayer == null) {
+ return true;
}
- if (mPlayer != null) {
- mPlayer.setAudioTrackAndClosedCaption(false);
+ TsDataSource source = mPlayer.getDataSource();
+ long limitInBytes = source != null ? source.getBufferedPosition() : 0L;
+ if (TunerDebug.ENABLED) {
+ TunerDebug.calculateDiff();
+ mSession.sendUiMessage(
+ TunerSession.MSG_UI_SET_STATUS_TEXT,
+ Html.fromHtml(
+ StatusTextUtils.getStatusWarningInHTML(
+ (limitInBytes - mLastLimitInBytes) / TS_PACKET_SIZE,
+ TunerDebug.getVideoFrameDrop(),
+ TunerDebug.getBytesInQueue(),
+ TunerDebug.getAudioPositionUs(),
+ TunerDebug.getAudioPositionUsRate(),
+ TunerDebug.getAudioPtsUs(),
+ TunerDebug.getAudioPtsUsRate(),
+ TunerDebug.getVideoPtsUs(),
+ TunerDebug.getVideoPtsUsRate())));
}
- notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL);
- Log.i(
- TAG,
- "Notify weak signal due to signal check, "
- + String.format(
- "packetsPerSec:%d, bufferingTimeMs:%d, preparingTimeMs:%d, "
- + "videoFrameDrop:%d",
- (limitInBytes - mLastLimitInBytes) / TS_PACKET_SIZE,
- bufferingTimeMs,
- preparingTimeMs,
- TunerDebug.getVideoFrameDrop()));
- } else if (!isWeakSignal && mReportedWeakSignal) {
- boolean isPlaybackStable =
- mReadyStartTimeMs != INVALID_TIME
- && currentTime - mReadyStartTimeMs
- > PLAYBACK_STATE_CHANGED_WAITING_THRESHOLD_MS;
- if (!isPlaybackStable) {
- // Wait until playback becomes stable.
- } else if (mReportedDrawnToSurface) {
- mHandler.removeMessages(MSG_RETRY_PLAYBACK);
- notifyVideoAvailable();
- mPlayer.setAudioTrackAndClosedCaption(true);
+ mSession.sendUiMessage(TunerSession.MSG_UI_HIDE_MESSAGE);
+ long currentTime = SystemClock.elapsedRealtime();
+ long bufferingTimeMs =
+ mBufferingStartTimeMs != INVALID_TIME
+ ? currentTime - mBufferingStartTimeMs
+ : mBufferingStartTimeMs;
+ long preparingTimeMs =
+ mPreparingStartTimeMs != INVALID_TIME
+ ? currentTime - mPreparingStartTimeMs
+ : mPreparingStartTimeMs;
+ boolean isBufferingTooLong =
+ bufferingTimeMs > PLAYBACK_STATE_CHANGED_WAITING_THRESHOLD_MS;
+ boolean isPreparingTooLong =
+ preparingTimeMs > PLAYBACK_STATE_CHANGED_WAITING_THRESHOLD_MS;
+ boolean isWeakSignal =
+ source != null
+ && mChannel.getType() != Channel.TYPE_FILE
+ && (isBufferingTooLong || isPreparingTooLong);
+ if (isWeakSignal && !mReportedWeakSignal) {
+ if (!mHandler.hasMessages(MSG_RETRY_PLAYBACK)) {
+ mHandler.sendMessageDelayed(
+ mHandler.obtainMessage(
+ MSG_RETRY_PLAYBACK, System.identityHashCode(mPlayer)),
+ PLAYBACK_RETRY_DELAY_MS);
+ }
+ if (mPlayer != null) {
+ mPlayer.setAudioTrackAndClosedCaption(false);
+ }
+ notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL);
+ Log.i(
+ TAG,
+ "Notify weak signal due to signal check, "
+ + String.format(
+ "packetsPerSec:%d, bufferingTimeMs:%d, preparingTimeMs:%d, "
+ + "videoFrameDrop:%d",
+ (limitInBytes - mLastLimitInBytes) / TS_PACKET_SIZE,
+ bufferingTimeMs,
+ preparingTimeMs,
+ TunerDebug.getVideoFrameDrop()));
+ } else if (!isWeakSignal && mReportedWeakSignal) {
+ boolean isPlaybackStable =
+ mReadyStartTimeMs != INVALID_TIME
+ && currentTime - mReadyStartTimeMs
+ > PLAYBACK_STATE_CHANGED_WAITING_THRESHOLD_MS;
+ if (!isPlaybackStable) {
+ // Wait until playback becomes stable.
+ } else if (mReportedDrawnToSurface) {
+ mHandler.removeMessages(MSG_RETRY_PLAYBACK);
+ notifyVideoAvailable();
+ mPlayer.setAudioTrackAndClosedCaption(true);
+ }
}
+ mLastLimitInBytes = limitInBytes;
+ mHandler.sendEmptyMessageDelayed(MSG_CHECK_SIGNAL, CHECK_NO_SIGNAL_PERIOD_MS);
+ return true;
}
- mLastLimitInBytes = limitInBytes;
- mHandler.sendEmptyMessageDelayed(MSG_CHECK_SIGNAL, CHECK_NO_SIGNAL_PERIOD_MS);
- return true;
case MSG_SET_SURFACE:
{
if (mPlayer != null) {
@@ -1204,7 +1194,7 @@ public class TunerSessionWorker
private void setTrickplayEnabledIfNeeded() {
if (mChannel == null
- || mTrickplayModeCustomization != CustomizationManager.TRICKPLAY_MODE_ENABLED) {
+ || mTrickplayModeCustomization != TvCustomizationManager.TRICKPLAY_MODE_ENABLED) {
return;
}
if (mTrickplaySetting == TunerPreferences.TRICKPLAY_SETTING_NOT_SET) {
@@ -1218,7 +1208,7 @@ public class TunerSessionWorker
Log.w(TAG, "No Audio Capabilities");
}
long now = System.currentTimeMillis();
- if (mTrickplayModeCustomization == CustomizationManager.TRICKPLAY_MODE_ENABLED
+ if (mTrickplayModeCustomization == TvCustomizationManager.TRICKPLAY_MODE_ENABLED
&& mTrickplaySetting == TunerPreferences.TRICKPLAY_SETTING_NOT_SET) {
if (mTrickplayExpiredMs == 0) {
mTrickplayExpiredMs = now + TRICKPLAY_OFF_DURATION_MS;
@@ -1499,7 +1489,7 @@ public class TunerSessionWorker
if (mChannel != null
&& ((mChannel.hasAudio() && !mPlayer.hasAudio())
|| (mChannel.hasVideo() && !mPlayer.hasVideo()))
- && mChannel.getType() != Channel.TunerType.TYPE_NETWORK) {
+ && mChannel.getType() != Channel.TYPE_NETWORK) {
// If the channel is from network, skip this part since the video and audio tracks
// information for channels from network are more reliable in the extractor. Otherwise,
// tracks haven't been detected in the extractor. Try again.
@@ -1559,8 +1549,7 @@ public class TunerSessionWorker
}
private void resetPlayback() {
- long timestamp;
- long oldTimestamp;
+ long timestamp, oldTimestamp;
timestamp = SystemClock.elapsedRealtime();
stopPlayback(false);
stopCaptionTrack();
@@ -1627,7 +1616,6 @@ public class TunerSessionWorker
MIN_TRICKPLAY_SEEK_INTERVAL_MS);
}
- @SuppressWarnings("NarrowingCompoundAssignment")
private void doTrickplayBySeek(int seekPositionMs) {
mHandler.removeMessages(MSG_TRICKPLAY_BY_SEEK);
if (mPlaybackParams.getSpeed() == 1.0f || !mPlayer.isPrepared()) {
@@ -1729,7 +1717,7 @@ public class TunerSessionWorker
if (mPrograms == null || mPrograms.isEmpty()) {
return null;
}
- if (mChannel.getType() == Channel.TunerType.TYPE_FILE) {
+ if (mChannel.getType() == Channel.TYPE_FILE) {
// For the playback from the local file, we use the first one from the given program.
EitItem first = mPrograms.get(0);
if (first != null
diff --git a/tuner/src/com/android/tv/tuner/tvinput/TunerStorageCleanUpService.java b/src/com/android/tv/tuner/tvinput/TunerStorageCleanUpService.java
index d7f98383..f014d568 100644
--- a/tuner/src/com/android/tv/tuner/tvinput/TunerStorageCleanUpService.java
+++ b/src/com/android/tv/tuner/tvinput/TunerStorageCleanUpService.java
@@ -25,9 +25,9 @@ import android.media.tv.TvContract;
import android.net.Uri;
import android.os.AsyncTask;
import android.util.Log;
-import com.android.tv.common.BaseApplication;
-import com.android.tv.common.recording.RecordingStorageStatusManager;
-import com.android.tv.common.util.CommonUtils;
+import com.android.tv.TvApplication;
+import com.android.tv.dvr.DvrStorageStatusManager;
+import com.android.tv.util.Utils;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
@@ -38,7 +38,6 @@ import java.util.concurrent.TimeUnit;
* Creates {@link JobService} to clean up recorded program files which are not referenced from
* database.
*/
-@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed
public class TunerStorageCleanUpService extends JobService {
private static final String TAG = "TunerStorageCleanUpService";
@@ -46,11 +45,12 @@ public class TunerStorageCleanUpService extends JobService {
@Override
public void onCreate() {
- if (getApplicationContext().getSystemService(Context.TV_INPUT_SERVICE) == null) {
+ if (!TvApplication.getSingletons(this).getTvInputManagerHelper().hasTvInputManager()) {
Log.wtf(TAG, "Stopping because device does not have a TvInputManager");
this.stopSelf();
return;
}
+ TvApplication.setCurrentRunningProcess(this, false);
super.onCreate();
mTask = new CleanUpStorageTask(this, this);
}
@@ -78,7 +78,7 @@ public class TunerStorageCleanUpService extends JobService {
private static final long ELAPSED_MILLIS_TO_DELETE = TimeUnit.DAYS.toMillis(1);
private final Context mContext;
- private final RecordingStorageStatusManager mDvrStorageStatusManager;
+ private final DvrStorageStatusManager mDvrStorageStatusManager;
private final JobService mJobService;
private final ContentResolver mContentResolver;
@@ -91,7 +91,7 @@ public class TunerStorageCleanUpService extends JobService {
public CleanUpStorageTask(Context context, JobService jobService) {
mContext = context;
mDvrStorageStatusManager =
- BaseApplication.getSingletons(context).getRecordingStorageStatusManager();
+ TvApplication.getSingletons(mContext).getDvrStorageStatusManager();
mJobService = jobService;
mContentResolver = mContext.getContentResolver();
}
@@ -115,7 +115,7 @@ public class TunerStorageCleanUpService extends JobService {
continue;
}
Uri dataUri = Uri.parse(dataUriString);
- if (!CommonUtils.isInBundledPackageSet(packageName)
+ if (!Utils.isInBundledPackageSet(packageName)
|| dataUri == null
|| dataUri.getPath() == null
|| !ContentResolver.SCHEME_FILE.equals(dataUri.getScheme())) {
@@ -134,7 +134,7 @@ public class TunerStorageCleanUpService extends JobService {
@Override
protected JobParameters[] doInBackground(JobParameters... params) {
if (mDvrStorageStatusManager.getDvrStorageStatus()
- == RecordingStorageStatusManager.STORAGE_STATUS_MISSING) {
+ == DvrStorageStatusManager.STORAGE_STATUS_MISSING) {
return params;
}
File dvrRecordingDir = mDvrStorageStatusManager.getRecordingRootDataDirectory();
@@ -157,7 +157,7 @@ public class TunerStorageCleanUpService extends JobService {
if (lastModified != 0 && lastModified < now - ELAPSED_MILLIS_TO_DELETE) {
// To prevent current recordings from being deleted,
// deletes recordings which was not modified for long enough time.
- CommonUtils.deleteDirOrFile(recordingDir);
+ Utils.deleteDirOrFile(recordingDir);
}
}
} catch (IOException | SecurityException e) {
diff --git a/tuner/src/com/android/tv/tuner/tvinput/BaseTunerTvInputService.java b/src/com/android/tv/tuner/tvinput/TunerTvInputService.java
index 21895b61..a1596e3b 100644
--- a/tuner/src/com/android/tv/tuner/tvinput/BaseTunerTvInputService.java
+++ b/src/com/android/tv/tuner/tvinput/TunerTvInputService.java
@@ -20,20 +20,22 @@ import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.content.Context;
+import android.media.tv.TvContract;
import android.media.tv.TvInputService;
import android.util.Log;
+import com.android.tv.TvApplication;
+import com.android.tv.common.feature.CommonFeatures;
import com.google.android.exoplayer.audio.AudioCapabilities;
import com.google.android.exoplayer.audio.AudioCapabilitiesReceiver;
-import com.android.tv.common.feature.CommonFeatures;
import java.util.Collections;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.TimeUnit;
-/** {@link BaseTunerTvInputService} serves TV channels coming from a tuner device. */
-public class BaseTunerTvInputService extends TvInputService
+/** {@link TunerTvInputService} serves TV channels coming from a tuner device. */
+public class TunerTvInputService extends TvInputService
implements AudioCapabilitiesReceiver.Listener {
- private static final String TAG = "BaseTunerTvInputService";
+ private static final String TAG = "TunerTvInputService";
private static final boolean DEBUG = false;
private static final int DVR_STORAGE_CLEANUP_JOB_ID = 100;
@@ -46,11 +48,12 @@ public class BaseTunerTvInputService extends TvInputService
@Override
public void onCreate() {
- if (getApplicationContext().getSystemService(Context.TV_INPUT_SERVICE) == null) {
+ if (!TvApplication.getSingletons(this).getTvInputManagerHelper().hasTvInputManager()) {
Log.wtf(TAG, "Stopping because device does not have a TvInputManager");
this.stopSelf();
return;
}
+ TvApplication.setCurrentRunningProcess(this, false);
super.onCreate();
if (DEBUG) Log.d(TAG, "onCreate");
mChannelDataManager = new ChannelDataManager(getApplicationContext());
@@ -92,11 +95,6 @@ public class BaseTunerTvInputService extends TvInputService
public Session onCreateSession(String inputId) {
if (DEBUG) Log.d(TAG, "onCreateSession");
try {
- // TODO(b/65445352): Support multiple TunerSessions for multiple tuners
- if (!allSessionsReleased()) {
- Log.d(TAG, "abort creating an session");
- return null;
- }
final TunerSession session = new TunerSession(this, mChannelDataManager);
mTunerSessions.add(session);
session.setAudioCapabilities(mAudioCapabilities);
@@ -119,12 +117,7 @@ public class BaseTunerTvInputService extends TvInputService
}
}
- private boolean allSessionsReleased() {
- for (TunerSession session : mTunerSessions) {
- if (!session.isReleased()) {
- return false;
- }
- }
- return true;
+ public static String getInputId(Context context) {
+ return TvContract.buildInputId(new ComponentName(context, TunerTvInputService.class));
}
}
diff --git a/tuner/src/com/android/tv/tuner/util/ByteArrayBuffer.java b/src/com/android/tv/tuner/util/ByteArrayBuffer.java
index 00ba039a..c3e38443 100644
--- a/tuner/src/com/android/tv/tuner/util/ByteArrayBuffer.java
+++ b/src/com/android/tv/tuner/util/ByteArrayBuffer.java
@@ -27,9 +27,6 @@
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
- * For the license checker
- * Licensed under the Apache License, Version 2.0
- *
*/
package com.android.tv.tuner.util;
diff --git a/tuner/src/com/android/tv/tuner/util/ConvertUtils.java b/src/com/android/tv/tuner/util/ConvertUtils.java
index 4b7fbdae..4b7fbdae 100644
--- a/tuner/src/com/android/tv/tuner/util/ConvertUtils.java
+++ b/src/com/android/tv/tuner/util/ConvertUtils.java
diff --git a/tuner/src/com/android/tv/tuner/util/GlobalSettingsUtils.java b/src/com/android/tv/tuner/util/GlobalSettingsUtils.java
index 98463f3b..98463f3b 100644
--- a/tuner/src/com/android/tv/tuner/util/GlobalSettingsUtils.java
+++ b/src/com/android/tv/tuner/util/GlobalSettingsUtils.java
diff --git a/tuner/src/com/android/tv/tuner/util/Ints.java b/src/com/android/tv/tuner/util/Ints.java
index 22c6bbb9..74e0ca8d 100644
--- a/tuner/src/com/android/tv/tuner/util/Ints.java
+++ b/src/com/android/tv/tuner/util/Ints.java
@@ -1,18 +1,3 @@
-/*
- * 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 java.util.ArrayList;
diff --git a/common/src/com/android/tv/common/util/PostalCodeUtils.java b/src/com/android/tv/tuner/util/PostalCodeUtils.java
index c0917af2..502c5648 100644
--- a/common/src/com/android/tv/common/util/PostalCodeUtils.java
+++ b/src/com/android/tv/tuner/util/PostalCodeUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.tv.common.util;
+package com.android.tv.tuner.util;
import android.content.Context;
import android.location.Address;
@@ -22,7 +22,8 @@ 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 com.android.tv.tuner.TunerPreferences;
+import com.android.tv.util.LocationUtils;
import java.io.IOException;
import java.util.HashMap;
import java.util.Locale;
@@ -80,7 +81,7 @@ public class PostalCodeUtils {
* input by users.
*/
public static String getLastPostalCode(Context context) {
- return CommonPreferences.getLastPostalCode(context);
+ return TunerPreferences.getLastPostalCode(context);
}
/**
@@ -89,7 +90,7 @@ public class PostalCodeUtils {
*/
public static void setLastPostalCode(Context context, String postalCode) {
Log.i(TAG, "Set Postal Code:" + postalCode);
- CommonPreferences.setLastPostalCode(context, postalCode);
+ TunerPreferences.setLastPostalCode(context, postalCode);
}
@Nullable
diff --git a/tuner/src/com/android/tv/tuner/util/StatusTextUtils.java b/src/com/android/tv/tuner/util/StatusTextUtils.java
index 84e2fc5a..84e2fc5a 100644
--- a/tuner/src/com/android/tv/tuner/util/StatusTextUtils.java
+++ b/src/com/android/tv/tuner/util/StatusTextUtils.java
diff --git a/common/src/com/android/tv/common/util/SystemPropertiesProxy.java b/src/com/android/tv/tuner/util/SystemPropertiesProxy.java
index a3ffd0fa..5c23c797 100644
--- a/common/src/com/android/tv/common/util/SystemPropertiesProxy.java
+++ b/src/com/android/tv/tuner/util/SystemPropertiesProxy.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.tv.common.util;
+package com.android.tv.tuner.util;
import android.util.Log;
import java.lang.reflect.InvocationTargetException;
diff --git a/src/com/android/tv/tuner/util/TisConfiguration.java b/src/com/android/tv/tuner/util/TisConfiguration.java
new file mode 100644
index 00000000..8f1326ce
--- /dev/null
+++ b/src/com/android/tv/tuner/util/TisConfiguration.java
@@ -0,0 +1,20 @@
+package com.android.tv.tuner.util;
+
+import android.content.Context;
+
+/** A helper class of tuner configuration. */
+public class TisConfiguration {
+ private static final String LC_PACKAGE_NAME = "com.android.tv";
+
+ public static boolean isPackagedWithLiveChannels(Context context) {
+ return (LC_PACKAGE_NAME.equals(context.getPackageName()));
+ }
+
+ public static boolean isInternalTunerTvInput(Context context) {
+ return (!LC_PACKAGE_NAME.equals(context.getPackageName()));
+ }
+
+ public static int getTunerHwDeviceId(Context context) {
+ return 0; // FIXME: Make it OEM configurable
+ }
+}
diff --git a/tuner/src/com/android/tv/tuner/util/TunerInputInfoUtils.java b/src/com/android/tv/tuner/util/TunerInputInfoUtils.java
index fad71335..9a3eec2b 100644
--- a/tuner/src/com/android/tv/tuner/util/TunerInputInfoUtils.java
+++ b/src/com/android/tv/tuner/util/TunerInputInfoUtils.java
@@ -26,11 +26,10 @@ import android.os.Build;
import android.support.annotation.Nullable;
import android.util.Log;
import android.util.Pair;
-import com.android.tv.common.BaseApplication;
-import com.android.tv.common.BuildConfig;
import com.android.tv.common.feature.CommonFeatures;
import com.android.tv.tuner.R;
import com.android.tv.tuner.TunerHal;
+import com.android.tv.tuner.tvinput.TunerTvInputService;
/** Utility class for providing tuner input info. */
public class TunerInputInfoUtils {
@@ -58,15 +57,15 @@ public class TunerInputInfoUtils {
break;
}
try {
- String inputId = BaseApplication.getSingletons(context).getEmbeddedTunerInputId();
TvInputInfo.Builder builder =
- new TvInputInfo.Builder(context, ComponentName.unflattenFromString(inputId));
+ new TvInputInfo.Builder(
+ context, new ComponentName(context, TunerTvInputService.class));
return builder.setLabel(inputLabelId)
.setCanRecord(CommonFeatures.DVR.isEnabled(context))
.setTunerCount(tunerTypeAndCount.second)
.build();
} catch (IllegalArgumentException | NullPointerException e) {
- // BaseTunerTvInputService is not enabled.
+ // TunerTvInputService is not enabled.
return null;
}
}
@@ -78,7 +77,7 @@ public class TunerInputInfoUtils {
*/
public static void updateTunerInputInfo(Context context) {
final Context appContext = context.getApplicationContext();
- if (!BuildConfig.NO_JNI_TEST && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
new AsyncTask<Void, Void, TvInputInfo>() {
@Override
protected TvInputInfo doInBackground(Void... params) {
diff --git a/src/com/android/tv/ui/AppLayerTvView.java b/src/com/android/tv/ui/AppLayerTvView.java
index b2be9f02..5454132a 100644
--- a/src/com/android/tv/ui/AppLayerTvView.java
+++ b/src/com/android/tv/ui/AppLayerTvView.java
@@ -21,8 +21,8 @@ import android.media.tv.TvView;
import android.util.AttributeSet;
import android.view.SurfaceView;
import android.view.View;
-import com.android.tv.common.util.CommonUtils;
-import com.android.tv.common.util.Debug;
+import com.android.tv.util.Debug;
+import com.android.tv.util.Utils;
/**
* A TvView class for application layer when multiple windows are being used in the app.
@@ -53,7 +53,7 @@ public class AppLayerTvView extends TvView {
public void onViewAdded(View child) {
if (child instanceof SurfaceView) {
// Note: See b/29118070 for detail.
- ((SurfaceView) child).setSecure(!CommonUtils.isDeveloper());
+ ((SurfaceView) child).setSecure(!Utils.isDeveloper());
}
super.onViewAdded(child);
}
diff --git a/src/com/android/tv/ui/ChannelBannerView.java b/src/com/android/tv/ui/ChannelBannerView.java
index df487bb5..c8c3dc86 100644
--- a/src/com/android/tv/ui/ChannelBannerView.java
+++ b/src/com/android/tv/ui/ChannelBannerView.java
@@ -47,7 +47,7 @@ import android.widget.RelativeLayout;
import android.widget.TextView;
import com.android.tv.MainActivity;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.feature.CommonFeatures;
import com.android.tv.data.Channel;
@@ -213,12 +213,12 @@ public class ChannelBannerView extends FrameLayout implements TvTransitionManage
mMainActivity, R.animator.channel_banner_program_description_fade_out);
if (CommonFeatures.DVR.isEnabled(mMainActivity)) {
- mDvrManager = TvSingletons.getSingletons(mMainActivity).getDvrManager();
+ mDvrManager = TvApplication.getSingletons(mMainActivity).getDvrManager();
} else {
mDvrManager = null;
}
mContentRatingsManager =
- TvSingletons.getSingletons(getContext())
+ TvApplication.getSingletons(getContext())
.getTvInputManagerHelper()
.getContentRatingsManager();
diff --git a/src/com/android/tv/ui/KeypadChannelSwitchView.java b/src/com/android/tv/ui/KeypadChannelSwitchView.java
index 5919dbf1..0c3613f6 100644
--- a/src/com/android/tv/ui/KeypadChannelSwitchView.java
+++ b/src/com/android/tv/ui/KeypadChannelSwitchView.java
@@ -37,12 +37,12 @@ import android.widget.ListView;
import android.widget.TextView;
import com.android.tv.MainActivity;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.analytics.Tracker;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.common.util.DurationTimer;
import com.android.tv.data.Channel;
import com.android.tv.data.ChannelNumber;
+import com.android.tv.util.DurationTimer;
import java.util.ArrayList;
import java.util.List;
@@ -116,7 +116,7 @@ public class KeypadChannelSwitchView extends LinearLayout
super(context, attrs, defStyleAttr);
mMainActivity = (MainActivity) context;
- mTracker = TvSingletons.getSingletons(context).getTracker();
+ mTracker = TvApplication.getSingletons(context).getTracker();
Resources resources = getResources();
mLayoutInflater = LayoutInflater.from(context);
mShowDurationMillis = resources.getInteger(R.integer.keypad_channel_switch_show_duration);
diff --git a/src/com/android/tv/ui/SelectInputView.java b/src/com/android/tv/ui/SelectInputView.java
index 2ec498a8..aa91aa50 100644
--- a/src/com/android/tv/ui/SelectInputView.java
+++ b/src/com/android/tv/ui/SelectInputView.java
@@ -32,11 +32,12 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
+import com.android.tv.ApplicationSingletons;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.analytics.Tracker;
-import com.android.tv.common.util.DurationTimer;
import com.android.tv.data.Channel;
+import com.android.tv.util.DurationTimer;
import com.android.tv.util.TvInputManagerHelper;
import java.util.ArrayList;
import java.util.Collections;
@@ -143,9 +144,9 @@ public class SelectInputView extends VerticalGridView
super(context, attrs, defStyleAttr);
setAdapter(new InputListAdapter());
- TvSingletons tvSingletons = TvSingletons.getSingletons(context);
- mTracker = tvSingletons.getTracker();
- mTvInputManagerHelper = tvSingletons.getTvInputManagerHelper();
+ ApplicationSingletons appSingletons = TvApplication.getSingletons(context);
+ mTracker = appSingletons.getTracker();
+ mTvInputManagerHelper = appSingletons.getTvInputManagerHelper();
mComparator =
new TvInputManagerHelper.HardwareInputComparator(context, mTvInputManagerHelper);
diff --git a/src/com/android/tv/ui/TunableTvView.java b/src/com/android/tv/ui/TunableTvView.java
index 36de790f..97f7c65c 100644
--- a/src/com/android/tv/ui/TunableTvView.java
+++ b/src/com/android/tv/ui/TunableTvView.java
@@ -57,18 +57,15 @@ import android.view.SurfaceView;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
+import com.android.tv.ApplicationSingletons;
+import com.android.tv.Features;
import com.android.tv.InputSessionManager;
import com.android.tv.InputSessionManager.TvViewSession;
import com.android.tv.R;
-import com.android.tv.TvFeatures;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.analytics.Tracker;
import com.android.tv.common.BuildConfig;
import com.android.tv.common.feature.CommonFeatures;
-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.Channel;
import com.android.tv.data.Program;
import com.android.tv.data.ProgramDataManager;
@@ -77,8 +74,11 @@ import com.android.tv.data.WatchedHistoryManager;
import com.android.tv.parental.ContentRatingsManager;
import com.android.tv.parental.ParentalControlSettings;
import com.android.tv.recommendation.NotificationService;
+import com.android.tv.util.Debug;
+import com.android.tv.util.DurationTimer;
import com.android.tv.util.ImageLoader;
import com.android.tv.util.NetworkUtils;
+import com.android.tv.util.PermissionUtils;
import com.android.tv.util.TvInputManagerHelper;
import com.android.tv.util.Utils;
import java.lang.annotation.Retention;
@@ -362,7 +362,7 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
getContext().startActivity(intent);
}
})
- .setNegativeButton(android.R.string.cancel, null)
+ .setNegativeButton(android.R.string.no, null)
.show();
}
@@ -393,7 +393,6 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
case TvInputManager.VIDEO_UNAVAILABLE_REASON_BUFFERING:
case TvInputManager.VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL:
mTracker.sendChannelVideoUnavailable(mCurrentChannel, reason);
- break;
default:
// do nothing
}
@@ -455,17 +454,17 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
super(context, attrs, defStyleAttr, defStyleRes);
inflate(getContext(), R.layout.tunable_tv_view, this);
- TvSingletons tvSingletons = TvSingletons.getSingletons(context);
+ ApplicationSingletons appSingletons = TvApplication.getSingletons(context);
if (CommonFeatures.DVR.isEnabled(context)) {
- mInputSessionManager = tvSingletons.getInputSessionManager();
+ mInputSessionManager = appSingletons.getInputSessionManager();
} else {
mInputSessionManager = null;
}
- mInputManager = tvSingletons.getTvInputManagerHelper();
+ mInputManager = appSingletons.getTvInputManagerHelper();
mConnectivityManager =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
mCanModifyParentalControls = PermissionUtils.hasModifyParentalControls(context);
- mTracker = tvSingletons.getTracker();
+ mTracker = appSingletons.getTracker();
mBlockScreenType = BLOCK_SCREEN_TYPE_NORMAL;
mBlockScreenView = (BlockScreenView) findViewById(R.id.block_screen);
mBlockScreenView.addInfoFadeInAnimationListener(
@@ -1082,7 +1081,7 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
}
private boolean closePipIfNeeded() {
- if (TvFeatures.PICTURE_IN_PICTURE.isEnabled(getContext())
+ if (Features.PICTURE_IN_PICTURE.isEnabled(getContext())
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
&& ((Activity) getContext()).isInPictureInPictureMode()
&& (mScreenBlocked
@@ -1153,7 +1152,7 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
}
private void updateMuteStatus() {
- // Workaround: BaseTunerTvInputService uses AC3 pass-through implementation, which disables
+ // Workaround: TunerTvInputService uses AC3 pass-through implementation, which disables
// audio tracks to enforce the mute request. We don't want to send mute request if we are
// not going to block the screen to prevent the video jankiness resulted by disabling audio
// track before the playback is started. In other way, we should send unmute request before
@@ -1184,7 +1183,7 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
private boolean isBundledInput() {
return mInputInfo != null
&& mInputInfo.getType() == TvInputInfo.TYPE_TUNER
- && CommonUtils.isBundledInput(mInputInfo.getId());
+ && Utils.isBundledInput(mInputInfo.getId());
}
/** Returns true if this view is faded out. */
diff --git a/src/com/android/tv/ui/TvOverlayManager.java b/src/com/android/tv/ui/TvOverlayManager.java
index 5daa525a..58ff8c2f 100644
--- a/src/com/android/tv/ui/TvOverlayManager.java
+++ b/src/com/android/tv/ui/TvOverlayManager.java
@@ -32,13 +32,14 @@ import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.ViewGroup;
+import com.android.tv.ApplicationSingletons;
import com.android.tv.ChannelTuner;
import com.android.tv.MainActivity;
import com.android.tv.MainActivity.KeyHandlerResultType;
import com.android.tv.R;
import com.android.tv.TimeShiftManager;
+import com.android.tv.TvApplication;
import com.android.tv.TvOptionsManager;
-import com.android.tv.TvSingletons;
import com.android.tv.analytics.Tracker;
import com.android.tv.common.WeakHandler;
import com.android.tv.common.feature.CommonFeatures;
@@ -231,7 +232,7 @@ public class TvOverlayManager {
ProgramGuideSearchFragment searchFragment) {
mMainActivity = mainActivity;
mChannelTuner = channelTuner;
- TvSingletons singletons = TvSingletons.getSingletons(mainActivity);
+ ApplicationSingletons singletons = TvApplication.getSingletons(mainActivity);
mChannelDataManager = singletons.getChannelDataManager();
mInputManager = singletons.getTvInputManagerHelper();
mTvView = tvView;
@@ -708,10 +709,6 @@ public class TvOverlayManager {
}
}
- public boolean isOverlayOpened() {
- return mOpenedOverlays != OVERLAY_TYPE_NONE;
- }
-
/** Hides all the opened overlays according to the flags. */
// TODO: Add test for this method.
public void hideOverlays(@HideOverlayFlag int flags) {
@@ -1018,10 +1015,6 @@ public class TvOverlayManager {
// Do not handle media key when any pop-ups which can handle keys are active.
return MainActivity.KEY_EVENT_HANDLER_RESULT_HANDLED;
}
- if (mTvView.isScreenBlocked()) {
- // Do not handle media key when screen is blocked.
- return MainActivity.KEY_EVENT_HANDLER_RESULT_HANDLED;
- }
TimeShiftManager timeShiftManager = mMainActivity.getTimeShiftManager();
if (!timeShiftManager.isAvailable()) {
return MainActivity.KEY_EVENT_HANDLER_RESULT_HANDLED;
diff --git a/src/com/android/tv/ui/TvViewUiManager.java b/src/com/android/tv/ui/TvViewUiManager.java
index 7e354db3..23cd9718 100644
--- a/src/com/android/tv/ui/TvViewUiManager.java
+++ b/src/com/android/tv/ui/TvViewUiManager.java
@@ -42,8 +42,8 @@ import android.view.ViewGroup.LayoutParams;
import android.view.ViewGroup.MarginLayoutParams;
import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
+import com.android.tv.Features;
import com.android.tv.R;
-import com.android.tv.TvFeatures;
import com.android.tv.TvOptionsManager;
import com.android.tv.data.DisplayMode;
import com.android.tv.util.TvSettings;
@@ -93,7 +93,7 @@ public class TvViewUiManager {
mTvView.setLayoutParams(mTvViewFrame);
// Smooth PIP size change, we don't change surface size when
// isInPictureInPictureMode is true.
- if (!TvFeatures.PICTURE_IN_PICTURE.isEnabled(mContext)
+ if (!Features.PICTURE_IN_PICTURE.isEnabled(mContext)
|| (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
&& !((Activity) mContext).isInPictureInPictureMode())) {
mTvView.setFixedSurfaceSize(
diff --git a/src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java b/src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java
index 8660c830..ad2f13f1 100644
--- a/src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java
+++ b/src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java
@@ -28,7 +28,7 @@ import android.view.ViewGroup;
import android.widget.TextView;
import com.android.tv.MainActivity;
import com.android.tv.R;
-import com.android.tv.common.util.SharedPreferencesUtils;
+import com.android.tv.common.SharedPreferencesUtils;
import com.android.tv.data.Channel;
import com.android.tv.data.ChannelNumber;
import com.android.tv.ui.OnRepeatedKeyInterceptListener;
diff --git a/src/com/android/tv/ui/sidepanel/DeveloperOptionFragment.java b/src/com/android/tv/ui/sidepanel/DeveloperOptionFragment.java
index dd42a728..766e206f 100644
--- a/src/com/android/tv/ui/sidepanel/DeveloperOptionFragment.java
+++ b/src/com/android/tv/ui/sidepanel/DeveloperOptionFragment.java
@@ -16,21 +16,11 @@
package com.android.tv.ui.sidepanel;
-import android.accounts.Account;
-import android.app.Activity;
-import android.support.annotation.NonNull;
-import android.util.Log;
-import android.widget.Toast;
-
-
-
-
import com.android.tv.R;
-import com.android.tv.TvSingletons;
-import com.android.tv.common.CommonPreferences;
+import com.android.tv.TvApplication;
import com.android.tv.common.feature.CommonFeatures;
-import com.android.tv.common.util.CommonUtils;
-
+import com.android.tv.tuner.TunerPreferences;
+import com.android.tv.util.Utils;
import java.util.ArrayList;
import java.util.List;
@@ -61,7 +51,7 @@ public class DeveloperOptionFragment extends SideFragment {
}
});
}
- if (CommonUtils.isDeveloper()) {
+ if (Utils.isDeveloper()) {
items.add(
new ActionItem(getString(R.string.dev_item_watch_history)) {
@Override
@@ -78,21 +68,21 @@ public class DeveloperOptionFragment extends SideFragment {
@Override
protected void onUpdate() {
super.onUpdate();
- setChecked(CommonPreferences.getStoreTsStream(getContext()));
+ setChecked(TunerPreferences.getStoreTsStream(getContext()));
}
@Override
protected void onSelected() {
super.onSelected();
- CommonPreferences.setStoreTsStream(getContext(), isChecked());
+ TunerPreferences.setStoreTsStream(getContext(), isChecked());
}
});
- if (CommonUtils.isDeveloper()) {
+ if (Utils.isDeveloper()) {
items.add(
new ActionItem(getString(R.string.dev_item_show_performance_monitor_log)) {
@Override
protected void onSelected() {
- TvSingletons.getSingletons(getContext())
+ TvApplication.getSingletons(getContext())
.getPerformanceMonitor()
.startPerformanceMonitorEventDebugActivity(getContext());
}
diff --git a/src/com/android/tv/ui/sidepanel/SettingsFragment.java b/src/com/android/tv/ui/sidepanel/SettingsFragment.java
index 31d00fa6..2552b5dd 100644
--- a/src/com/android/tv/ui/sidepanel/SettingsFragment.java
+++ b/src/com/android/tv/ui/sidepanel/SettingsFragment.java
@@ -16,7 +16,7 @@
package com.android.tv.ui.sidepanel;
-import static com.android.tv.TvFeatures.TUNER;
+import static com.android.tv.Features.TUNER;
import android.app.ApplicationErrorReport;
import android.content.Intent;
@@ -26,13 +26,13 @@ import android.widget.Toast;
import com.android.tv.MainActivity;
import com.android.tv.R;
import com.android.tv.TvApplication;
-import com.android.tv.TvSingletons;
-import com.android.tv.common.CommonPreferences;
-import com.android.tv.common.customization.CustomizationManager;
-import com.android.tv.common.util.PermissionUtils;
+import com.android.tv.customization.TvCustomizationManager;
import com.android.tv.dialog.PinDialogFragment;
import com.android.tv.license.LicenseSideFragment;
import com.android.tv.license.Licenses;
+import com.android.tv.tuner.TunerPreferences;
+import com.android.tv.util.PermissionUtils;
+import com.android.tv.util.SetupUtils;
import com.android.tv.util.Utils;
import java.util.ArrayList;
import java.util.List;
@@ -82,9 +82,7 @@ public class SettingsFragment extends SideFragment {
items.add(customizeChannelListItem);
final MainActivity activity = getMainActivity();
boolean hasNewInput =
- TvSingletons.getSingletons(getContext())
- .getSetupUtils()
- .hasNewInput(activity.getTvInputManagerHelper());
+ SetupUtils.getInstance(activity).hasNewInput(activity.getTvInputManagerHelper());
items.add(
new ActionItem(
getString(R.string.settings_channel_source_item_setup),
@@ -129,7 +127,7 @@ public class SettingsFragment extends SideFragment {
boolean showTrickplaySetting = false;
if (TUNER.isEnabled(getContext())) {
for (TvInputInfo inputInfo :
- TvSingletons.getSingletons(getContext())
+ TvApplication.getSingletons(getContext())
.getTvInputManagerHelper()
.getTvInputInfos(true, true)) {
if (Utils.isInternalTvInput(getContext(), inputInfo.getId())) {
@@ -139,8 +137,8 @@ public class SettingsFragment extends SideFragment {
}
if (showTrickplaySetting) {
showTrickplaySetting =
- CustomizationManager.getTrickplayMode(getContext())
- == CustomizationManager.TRICKPLAY_MODE_ENABLED;
+ TvCustomizationManager.getTrickplayMode(getContext())
+ == TvCustomizationManager.TRICKPLAY_MODE_ENABLED;
}
}
if (showTrickplaySetting) {
@@ -154,20 +152,20 @@ public class SettingsFragment extends SideFragment {
protected void onUpdate() {
super.onUpdate();
boolean enabled =
- CommonPreferences.getTrickplaySetting(getContext())
- != CommonPreferences.TRICKPLAY_SETTING_DISABLED;
+ TunerPreferences.getTrickplaySetting(getContext())
+ != TunerPreferences.TRICKPLAY_SETTING_DISABLED;
setChecked(enabled);
}
@Override
protected void onSelected() {
super.onSelected();
- @CommonPreferences.TrickplaySetting
+ @TunerPreferences.TrickplaySetting
int setting =
isChecked()
- ? CommonPreferences.TRICKPLAY_SETTING_ENABLED
- : CommonPreferences.TRICKPLAY_SETTING_DISABLED;
- CommonPreferences.setTrickplaySetting(getContext(), setting);
+ ? TunerPreferences.TRICKPLAY_SETTING_ENABLED
+ : TunerPreferences.TRICKPLAY_SETTING_DISABLED;
+ TunerPreferences.setTrickplaySetting(getContext(), setting);
}
});
}
diff --git a/src/com/android/tv/ui/sidepanel/SideFragment.java b/src/com/android/tv/ui/sidepanel/SideFragment.java
index 2902ea7f..0660a6f9 100644
--- a/src/com/android/tv/ui/sidepanel/SideFragment.java
+++ b/src/com/android/tv/ui/sidepanel/SideFragment.java
@@ -30,13 +30,13 @@ import android.widget.FrameLayout;
import android.widget.TextView;
import com.android.tv.MainActivity;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.analytics.HasTrackerLabel;
import com.android.tv.analytics.Tracker;
-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.DurationTimer;
+import com.android.tv.util.SystemProperties;
import com.android.tv.util.ViewCache;
import java.util.List;
@@ -85,7 +85,7 @@ public abstract class SideFragment<T extends Item> extends Fragment implements H
super.onAttach(context);
mChannelDataManager = getMainActivity().getChannelDataManager();
mProgramDataManager = getMainActivity().getProgramDataManager();
- mTracker = TvSingletons.getSingletons(context).getTracker();
+ mTracker = TvApplication.getSingletons(context).getTracker();
}
@Override
diff --git a/src/com/android/tv/ui/sidepanel/parentalcontrols/ChannelsBlockedFragment.java b/src/com/android/tv/ui/sidepanel/parentalcontrols/ChannelsBlockedFragment.java
index d70cf97a..f0396bfe 100644
--- a/src/com/android/tv/ui/sidepanel/parentalcontrols/ChannelsBlockedFragment.java
+++ b/src/com/android/tv/ui/sidepanel/parentalcontrols/ChannelsBlockedFragment.java
@@ -19,8 +19,6 @@ package com.android.tv.ui.sidepanel.parentalcontrols;
import android.database.ContentObserver;
import android.media.tv.TvContract;
import android.net.Uri;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.Handler;
import android.support.v17.leanback.widget.VerticalGridView;
@@ -32,7 +30,6 @@ import android.widget.TextView;
import com.android.tv.R;
import com.android.tv.data.Channel;
import com.android.tv.data.ChannelNumber;
-import com.android.tv.recommendation.ChannelPreviewUpdater;
import com.android.tv.ui.OnRepeatedKeyInterceptListener;
import com.android.tv.ui.sidepanel.ActionItem;
import com.android.tv.ui.sidepanel.ChannelCheckItem;
@@ -50,7 +47,6 @@ public class ChannelsBlockedFragment extends SideFragment {
private final List<Channel> mChannels = new ArrayList<>();
private long mLastFocusedChannelId = Channel.INVALID_ID;
private int mSelectedPosition = INVALID_POSITION;
- private boolean mUpdated;
private final ContentObserver mProgramUpdateObserver =
new ContentObserver(new Handler()) {
@Override
@@ -98,7 +94,6 @@ public class ChannelsBlockedFragment extends SideFragment {
.registerContentObserver(
TvContract.Programs.CONTENT_URI, true, mProgramUpdateObserver);
getMainActivity().startShrunkenTvView(true, true);
- mUpdated = false;
return view;
}
@@ -107,10 +102,6 @@ public class ChannelsBlockedFragment extends SideFragment {
getActivity().getContentResolver().unregisterContentObserver(mProgramUpdateObserver);
getChannelDataManager().applyUpdatedValuesToDb();
getMainActivity().endShrunkenTvView();
- if (VERSION.SDK_INT >= VERSION_CODES.O && mUpdated) {
- ChannelPreviewUpdater.getInstance(getMainActivity())
- .updatePreviewDataForChannelsImmediately();
- }
super.onDestroyView();
}
@@ -194,7 +185,6 @@ public class ChannelsBlockedFragment extends SideFragment {
}
mBlockedChannelCount = lock ? mChannels.size() : 0;
notifyItemsChanged();
- mUpdated = true;
}
@Override
@@ -238,7 +228,6 @@ public class ChannelsBlockedFragment extends SideFragment {
getChannelDataManager().updateLocked(getChannel().getId(), isChecked());
mBlockedChannelCount += isChecked() ? 1 : -1;
notifyItemChanged(mLockAllItem);
- mUpdated = true;
}
@Override
diff --git a/src/com/android/tv/ui/sidepanel/parentalcontrols/RatingsFragment.java b/src/com/android/tv/ui/sidepanel/parentalcontrols/RatingsFragment.java
index 128fcd1a..882843c2 100644
--- a/src/com/android/tv/ui/sidepanel/parentalcontrols/RatingsFragment.java
+++ b/src/com/android/tv/ui/sidepanel/parentalcontrols/RatingsFragment.java
@@ -26,8 +26,8 @@ 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.experiments.Experiments;
import com.android.tv.license.LicenseUtils;
import com.android.tv.parental.ContentRatingSystem;
import com.android.tv.parental.ContentRatingSystem.Rating;
diff --git a/src/com/android/tv/util/account/AccountHelperImpl.java b/src/com/android/tv/util/AccountHelper.java
index 58fbd27e..a3e6ad58 100644
--- a/src/com/android/tv/util/account/AccountHelperImpl.java
+++ b/src/com/android/tv/util/AccountHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.tv.util.account;
+package com.android.tv.util;
import android.accounts.Account;
import android.content.Context;
@@ -23,23 +23,24 @@ import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
/** Helper methods for getting and selecting a user account. */
-public class AccountHelperImpl implements com.android.tv.util.account.AccountHelper {
+public class AccountHelper {
+ private static final String TAG = "AccountHelper";
+ private static final boolean DEBUG = false;
private static final String SELECTED_ACCOUNT = "android.tv.livechannels.selected_account";
- protected final Context mContext;
+ private final Context mContext;
private final SharedPreferences mDefaultPreferences;
@Nullable private Account mSelectedAccount;
- public AccountHelperImpl(Context context) {
+ public AccountHelper(Context context) {
mContext = context.getApplicationContext();
mDefaultPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
}
/** Returns the currently selected account or {@code null} if none is selected. */
- @Override
@Nullable
- public final Account getSelectedAccount() {
+ public Account getSelectedAccount() {
String accountId = mDefaultPreferences.getString(SELECTED_ACCOUNT, null);
if (accountId == null) {
return null;
@@ -56,12 +57,8 @@ public class AccountHelperImpl implements com.android.tv.util.account.AccountHel
return mSelectedAccount;
}
- /**
- * Returns all eligible accounts.
- *
- * <p>Override this method to return the accounts needed.
- */
- protected Account[] getEligibleAccounts() {
+ /** Returns all eligible accounts . */
+ private Account[] getEligibleAccounts() {
return new Account[0];
}
@@ -70,9 +67,8 @@ public class AccountHelperImpl implements com.android.tv.util.account.AccountHel
*
* @return selected account or {@code null} if none is selected.
*/
- @Override
@Nullable
- public final Account selectFirstAccount() {
+ public Account selectFirstAccount() {
Account account = getFirstEligibleAccount();
if (account != null) {
selectAccount(account);
@@ -85,9 +81,8 @@ public class AccountHelperImpl implements com.android.tv.util.account.AccountHel
*
* @return first account or {@code null} if none is eligible.
*/
- @Override
@Nullable
- public final Account getFirstEligibleAccount() {
+ public Account getFirstEligibleAccount() {
Account[] accounts = getEligibleAccounts();
return accounts.length == 0 ? null : accounts[0];
}
diff --git a/src/com/android/tv/util/AsyncDbTask.java b/src/com/android/tv/util/AsyncDbTask.java
index b575df53..376fcc70 100644
--- a/src/com/android/tv/util/AsyncDbTask.java
+++ b/src/com/android/tv/util/AsyncDbTask.java
@@ -28,7 +28,6 @@ import android.support.annotation.WorkerThread;
import android.util.Log;
import android.util.Range;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.common.concurrent.NamedThreadFactory;
import com.android.tv.data.Channel;
import com.android.tv.data.Program;
import com.android.tv.dvr.data.RecordedProgram;
@@ -48,7 +47,6 @@ import java.util.concurrent.RejectedExecutionException;
* @param <Progress> the type of the progress units published during the background computation.
* @param <Result> the type of the result of the background computation.
*/
-@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed
public abstract class AsyncDbTask<Params, Progress, Result>
extends AsyncTask<Params, Progress, Result> {
private static final String TAG = "AsyncDbTask";
@@ -151,7 +149,7 @@ public abstract class AsyncDbTask<Params, Progress, Result>
return null;
}
} catch (Exception e) {
- SoftPreconditions.warn(TAG, null, e, "Error querying " + this);
+ SoftPreconditions.warn(TAG, null, "Error querying " + this, e);
return null;
}
}
diff --git a/src/com/android/tv/util/BitmapUtils.java b/src/com/android/tv/util/BitmapUtils.java
index 4c67d934..6902a6fe 100644
--- a/src/com/android/tv/util/BitmapUtils.java
+++ b/src/com/android/tv/util/BitmapUtils.java
@@ -29,7 +29,6 @@ import android.net.Uri;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
-import com.android.tv.common.util.NetworkTrafficTags;
import java.io.BufferedInputStream;
import java.io.Closeable;
import java.io.IOException;
diff --git a/common/src/com/android/tv/common/util/Clock.java b/src/com/android/tv/util/Clock.java
index a8c4366c..0004a669 100644
--- a/common/src/com/android/tv/common/util/Clock.java
+++ b/src/com/android/tv/util/Clock.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.tv.common.util;
+package com.android.tv.util;
import android.os.SystemClock;
diff --git a/common/src/com/android/tv/common/util/Debug.java b/src/com/android/tv/util/Debug.java
index ab908741..422a61e3 100644
--- a/common/src/com/android/tv/common/util/Debug.java
+++ b/src/com/android/tv/util/Debug.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.tv.common.util;
+package com.android.tv.util;
import java.util.HashMap;
import java.util.Map;
@@ -23,8 +23,8 @@ 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 Live TV 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 Live TV. */
diff --git a/common/src/com/android/tv/common/util/DurationTimer.java b/src/com/android/tv/util/DurationTimer.java
index 91581ad5..6aabf37b 100644
--- a/common/src/com/android/tv/common/util/DurationTimer.java
+++ b/src/com/android/tv/util/DurationTimer.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.tv.common.util;
+package com.android.tv.util;
import android.os.SystemClock;
import android.util.Log;
diff --git a/src/com/android/tv/util/ImageLoader.java b/src/com/android/tv/util/ImageLoader.java
index 32ac89f0..9b4d2a70 100644
--- a/src/com/android/tv/util/ImageLoader.java
+++ b/src/com/android/tv/util/ImageLoader.java
@@ -31,7 +31,6 @@ import android.support.annotation.WorkerThread;
import android.util.ArraySet;
import android.util.Log;
import com.android.tv.R;
-import com.android.tv.common.concurrent.NamedThreadFactory;
import com.android.tv.util.BitmapUtils.ScaledBitmapInfo;
import java.lang.ref.WeakReference;
import java.util.HashMap;
diff --git a/common/src/com/android/tv/common/util/LocationUtils.java b/src/com/android/tv/util/LocationUtils.java
index e11e17a9..a960c616 100644
--- a/common/src/com/android/tv/common/util/LocationUtils.java
+++ b/src/com/android/tv/util/LocationUtils.java
@@ -14,11 +14,9 @@
* limitations under the License.
*/
-package com.android.tv.common.util;
+package com.android.tv.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;
@@ -28,10 +26,7 @@ import android.os.Bundle;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
-
-
-
-
+import com.android.tv.tuner.util.PostalCodeUtils;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
diff --git a/common/src/com/android/tv/common/concurrent/NamedThreadFactory.java b/src/com/android/tv/util/NamedThreadFactory.java
index 4c8371f3..264b8b3f 100644
--- a/common/src/com/android/tv/common/concurrent/NamedThreadFactory.java
+++ b/src/com/android/tv/util/NamedThreadFactory.java
@@ -14,22 +14,22 @@
* limitations under the License
*/
-package com.android.tv.common.concurrent;
+package com.android.tv.util;
import android.support.annotation.NonNull;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
-/** A thread factory that creates threads with named <code>prefix-##</code>. */
+/** A thread factory that creates threads with a suffix. */
public class NamedThreadFactory implements ThreadFactory {
private final AtomicInteger mCount = new AtomicInteger(0);
private final ThreadFactory mDefaultThreadFactory;
private final String mPrefix;
- public NamedThreadFactory(final String prefix) {
+ public NamedThreadFactory(final String baseName) {
mDefaultThreadFactory = Executors.defaultThreadFactory();
- mPrefix = prefix + "-";
+ mPrefix = baseName + "-";
}
@Override
diff --git a/common/src/com/android/tv/common/util/NetworkTrafficTags.java b/src/com/android/tv/util/NetworkTrafficTags.java
index 91f2bcd1..85ecde5b 100644
--- a/common/src/com/android/tv/common/util/NetworkTrafficTags.java
+++ b/src/com/android/tv/util/NetworkTrafficTags.java
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.tv.common.util;
+package com.android.tv.util;
import android.net.TrafficStats;
import android.support.annotation.NonNull;
diff --git a/src/com/android/tv/util/OnboardingUtils.java b/src/com/android/tv/util/OnboardingUtils.java
index 63383aab..3b72e091 100644
--- a/src/com/android/tv/util/OnboardingUtils.java
+++ b/src/com/android/tv/util/OnboardingUtils.java
@@ -48,8 +48,8 @@ public final class OnboardingUtils {
}
/**
- * Checks if this is the first run of {@link com.android.tv.MainActivity} with the
- * current onboarding version.
+ * Checks if this is the first run of {@link com.android.tv.MainActivity} with the current
+ * onboarding version.
*/
public static boolean isFirstRunWithCurrentVersion(Context context) {
int versionCode =
@@ -59,8 +59,8 @@ public final class OnboardingUtils {
}
/**
- * Marks that the first run of {@link com.android.tv.MainActivity} with the current
- * onboarding version has been completed.
+ * Marks that the first run of {@link com.android.tv.MainActivity} with the current onboarding
+ * version has been completed.
*/
public static void setFirstRunWithCurrentVersionCompleted(Context context) {
PreferenceManager.getDefaultSharedPreferences(context)
diff --git a/common/src/com/android/tv/common/util/PermissionUtils.java b/src/com/android/tv/util/PermissionUtils.java
index 8d409e50..b3e4e3a2 100644
--- a/common/src/com/android/tv/common/util/PermissionUtils.java
+++ b/src/com/android/tv/util/PermissionUtils.java
@@ -1,19 +1,4 @@
-/*
- * 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.util;
+package com.android.tv.util;
import android.content.Context;
import android.content.pm.PackageManager;
diff --git a/src/com/android/tv/util/RecurringRunner.java b/src/com/android/tv/util/RecurringRunner.java
index 764689c2..c1b724a2 100644
--- a/src/com/android/tv/util/RecurringRunner.java
+++ b/src/com/android/tv/util/RecurringRunner.java
@@ -22,8 +22,8 @@ import android.os.AsyncTask;
import android.os.Handler;
import android.support.annotation.WorkerThread;
import android.util.Log;
+import com.android.tv.common.SharedPreferencesUtils;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.common.util.SharedPreferencesUtils;
import java.util.Date;
/**
diff --git a/src/com/android/tv/util/SetupUtils.java b/src/com/android/tv/util/SetupUtils.java
index ad5d5024..a1ff192b 100644
--- a/src/com/android/tv/util/SetupUtils.java
+++ b/src/com/android/tv/util/SetupUtils.java
@@ -28,15 +28,15 @@ import android.media.tv.TvInputManager;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
-import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
-import com.android.tv.TvSingletons;
-import com.android.tv.common.BaseApplication;
+import com.android.tv.ApplicationSingletons;
+import com.android.tv.TvApplication;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
+import com.android.tv.tuner.tvinput.TunerTvInputService;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
@@ -54,8 +54,9 @@ public class SetupUtils {
// Recognized inputs means that the user already knows the inputs are installed.
private static final String PREF_KEY_RECOGNIZED_INPUTS = "recognized_inputs";
private static final String PREF_KEY_IS_FIRST_TUNE = "is_first_tune";
+ private static SetupUtils sSetupUtils;
- private final Context mContext;
+ private final TvApplication mTvApplication;
private final SharedPreferences mSharedPreferences;
private final Set<String> mKnownInputs;
private final Set<String> mSetUpInputs;
@@ -63,10 +64,9 @@ public class SetupUtils {
private boolean mIsFirstTune;
private final String mTunerInputId;
- @VisibleForTesting
- protected SetupUtils(Context context) {
- mContext = context;
- mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
+ private SetupUtils(TvApplication tvApplication) {
+ mTvApplication = tvApplication;
+ mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(tvApplication);
mSetUpInputs = new ArraySet<>();
mSetUpInputs.addAll(
mSharedPreferences.getStringSet(PREF_KEY_SET_UP_INPUTS, Collections.emptySet()));
@@ -77,16 +77,18 @@ public class SetupUtils {
mRecognizedInputs.addAll(
mSharedPreferences.getStringSet(PREF_KEY_RECOGNIZED_INPUTS, mKnownInputs));
mIsFirstTune = mSharedPreferences.getBoolean(PREF_KEY_IS_FIRST_TUNE, true);
- mTunerInputId = BaseApplication.getSingletons(context).getEmbeddedTunerInputId();
+ mTunerInputId =
+ TvContract.buildInputId(
+ new ComponentName(tvApplication, TunerTvInputService.class));
}
- /**
- * Creates an instance of {@link SetupUtils}.
- *
- * <p><b>WARNING</b> this should only be called by the top level application.
- */
- public static SetupUtils createForTvSingletons(Context context) {
- return new SetupUtils(context.getApplicationContext());
+ /** Gets an instance of {@link SetupUtils}. */
+ public static SetupUtils getInstance(Context context) {
+ if (sSetupUtils != null) {
+ return sSetupUtils;
+ }
+ sSetupUtils = new SetupUtils((TvApplication) context.getApplicationContext());
+ return sSetupUtils;
}
/** Additional work after the setup of TV input. */
@@ -97,15 +99,14 @@ public class SetupUtils {
// which one is the last callback. To reduce error prune, we update channel
// list again and make all channels of {@code inputId} browsable.
onSetupDone(inputId);
- final ChannelDataManager manager =
- TvSingletons.getSingletons(mContext).getChannelDataManager();
+ final ChannelDataManager manager = mTvApplication.getChannelDataManager();
if (!manager.isDbLoadFinished()) {
manager.addListener(
new ChannelDataManager.Listener() {
@Override
public void onLoadFinished() {
manager.removeListener(this);
- updateChannelsAfterSetup(mContext, inputId, postRunnable);
+ updateChannelsAfterSetup(mTvApplication, inputId, postRunnable);
}
@Override
@@ -115,14 +116,14 @@ public class SetupUtils {
public void onChannelBrowsableChanged() {}
});
} else {
- updateChannelsAfterSetup(mContext, inputId, postRunnable);
+ updateChannelsAfterSetup(mTvApplication, inputId, postRunnable);
}
}
private static void updateChannelsAfterSetup(
Context context, final String inputId, final Runnable postRunnable) {
- TvSingletons tvSingletons = TvSingletons.getSingletons(context);
- final ChannelDataManager manager = tvSingletons.getChannelDataManager();
+ ApplicationSingletons appSingletons = TvApplication.getSingletons(context);
+ final ChannelDataManager manager = appSingletons.getChannelDataManager();
manager.updateChannels(
new Runnable() {
@Override
@@ -158,9 +159,8 @@ public class SetupUtils {
@UiThread
public void markNewChannelsBrowsable() {
Set<String> newInputsWithChannels = new HashSet<>();
- TvSingletons singletons = TvSingletons.getSingletons(mContext);
- TvInputManagerHelper tvInputManagerHelper = singletons.getTvInputManagerHelper();
- ChannelDataManager channelDataManager = singletons.getChannelDataManager();
+ TvInputManagerHelper tvInputManagerHelper = mTvApplication.getTvInputManagerHelper();
+ ChannelDataManager channelDataManager = mTvApplication.getChannelDataManager();
SoftPreconditions.checkState(channelDataManager.isDbLoadFinished());
for (TvInputInfo input : tvInputManagerHelper.getTvInputInfos(true, true)) {
String inputId = input.getId();
@@ -340,7 +340,8 @@ public class SetupUtils {
try {
// Just after booting, input list from TvInputManager are not reliable.
// So we need to double-check package existence. b/29034900
- mContext.getPackageManager()
+ mTvApplication
+ .getPackageManager()
.getPackageInfo(
ComponentName.unflattenFromString(input).getPackageName(),
PackageManager.GET_ACTIVITIES);
diff --git a/src/com/android/tv/util/SqlParams.java b/src/com/android/tv/util/SqlParams.java
deleted file mode 100644
index c4b803b6..00000000
--- a/src/com/android/tv/util/SqlParams.java
+++ /dev/null
@@ -1,74 +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 android.database.DatabaseUtils;
-import java.util.Arrays;
-
-/** Convenience class for SQL operations. */
-public class SqlParams {
- private String mTables;
- private String mSelection;
- private String[] mSelectionArgs;
-
- public SqlParams(String tables, String selection, String... selectionArgs) {
- setTables(tables);
- setWhere(selection, selectionArgs);
- }
-
- public String getTables() {
- return mTables;
- }
-
- public String getSelection() {
- return mSelection;
- }
-
- public String[] getSelectionArgs() {
- return mSelectionArgs;
- }
-
- public void setTables(String tables) {
- mTables = tables;
- }
-
- public void setWhere(String selection, String... selectionArgs) {
- mSelection = selection;
- mSelectionArgs = selectionArgs;
- }
-
- public void appendWhere(String selection, String... selectionArgs) {
- mSelection = DatabaseUtils.concatenateWhere(mSelection, selection);
- if (selectionArgs != null) {
- mSelectionArgs = DatabaseUtils.appendSelectionArgs(mSelectionArgs, selectionArgs);
- }
- }
-
- public void appendWhereEquals(String name, String value) {
- appendWhere(name + "=?", value);
- }
-
- @Override
- public String toString() {
- return "tables "
- + getTables()
- + " where "
- + getSelection()
- + " with "
- + Arrays.toString(getSelectionArgs());
- }
-}
diff --git a/common/src/com/android/tv/common/util/StringUtils.java b/src/com/android/tv/util/StringUtils.java
index b9461426..eeaf33a6 100644
--- a/common/src/com/android/tv/common/util/StringUtils.java
+++ b/src/com/android/tv/util/StringUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.tv.common.util;
+package com.android.tv.util;
/** Utility class for handling {@link String}. */
public final class StringUtils {
diff --git a/common/src/com/android/tv/common/util/SystemProperties.java b/src/com/android/tv/util/SystemProperties.java
index 02bf5791..e1b8a398 100644
--- a/common/src/com/android/tv/common/util/SystemProperties.java
+++ b/src/com/android/tv/util/SystemProperties.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.tv.common.util;
+package com.android.tv.util;
import com.android.tv.common.BooleanSystemProperty;
@@ -36,9 +36,7 @@ public final class SystemProperties {
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}.
- */
+ /** Send {@link com.android.tv.analytics.Tracker} information. Defaults to {@code true}. */
public static final BooleanSystemProperty USE_TRACKER =
new BooleanSystemProperty("tv_use_tracker", true);
diff --git a/src/com/android/tv/util/TvInputManagerHelper.java b/src/com/android/tv/util/TvInputManagerHelper.java
index c4feafb7..e97bc4f9 100644
--- a/src/com/android/tv/util/TvInputManagerHelper.java
+++ b/src/com/android/tv/util/TvInputManagerHelper.java
@@ -21,19 +21,17 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.hardware.hdmi.HdmiDeviceInfo;
-import android.media.tv.TvContentRatingSystemInfo;
import android.media.tv.TvInputInfo;
import android.media.tv.TvInputManager;
import android.media.tv.TvInputManager.TvInputCallback;
import android.os.Handler;
-import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
-import com.android.tv.TvFeatures;
+import com.android.tv.Features;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.common.util.CommonUtils;
+import com.android.tv.common.TvCommonUtils;
import com.android.tv.parental.ContentRatingsManager;
import com.android.tv.parental.ParentalControlSettings;
import java.util.ArrayList;
@@ -49,58 +47,6 @@ public class TvInputManagerHelper {
private static final String TAG = "TvInputManagerHelper";
private static final boolean DEBUG = false;
- public interface TvInputManagerInterface {
- TvInputInfo getTvInputInfo(String inputId);
-
- Integer getInputState(String inputId);
-
- void registerCallback(TvInputCallback internalCallback, Handler handler);
-
- void unregisterCallback(TvInputCallback internalCallback);
-
- List<TvInputInfo> getTvInputList();
-
- List<TvContentRatingSystemInfo> getTvContentRatingSystemList();
- }
-
- private static final class TvInputManagerImpl implements TvInputManagerInterface {
- private final TvInputManager delegate;
-
- private TvInputManagerImpl(TvInputManager delegate) {
- this.delegate = delegate;
- }
-
- @Override
- public TvInputInfo getTvInputInfo(String inputId) {
- return delegate.getTvInputInfo(inputId);
- }
-
- @Override
- public Integer getInputState(String inputId) {
- return delegate.getInputState(inputId);
- }
-
- @Override
- public void registerCallback(TvInputCallback internalCallback, Handler handler) {
- delegate.registerCallback(internalCallback, handler);
- }
-
- @Override
- public void unregisterCallback(TvInputCallback internalCallback) {
- delegate.unregisterCallback(internalCallback);
- }
-
- @Override
- public List<TvInputInfo> getTvInputList() {
- return delegate.getTvInputList();
- }
-
- @Override
- public List<TvContentRatingSystemInfo> getTvContentRatingSystemList() {
- return delegate.getTvContentRatingSystemList();
- }
- }
-
/** Types of HDMI device and bundled tuner. */
public static final int TYPE_CEC_DEVICE = -2;
@@ -111,8 +57,7 @@ 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 = {
- };
+ private static final String[] mPhysicalTunerBlackList = {};
private static final String META_LABEL_SORT_KEY = "input_sort_key";
/** The default tv input priority to show. */
@@ -136,8 +81,7 @@ public class TvInputManagerHelper {
DEFAULT_TV_INPUT_PRIORITY.add(TvInputInfo.TYPE_OTHER);
}
- private static final String[] PARTNER_TUNER_INPUT_PREFIX_BLACKLIST = {
- };
+ private static final String[] PARTNER_TUNER_INPUT_PREFIX_BLACKLIST = {};
private static final String[] TESTABLE_INPUTS = {
"com.android.tv.testinput/.TestTvInputService"
@@ -145,7 +89,7 @@ public class TvInputManagerHelper {
private final Context mContext;
private final PackageManager mPackageManager;
- protected final TvInputManagerInterface mTvInputManager;
+ private final TvInputManager mTvInputManager;
private final Map<String, Integer> mInputStateMap = new HashMap<>();
private final Map<String, TvInputInfo> mInputMap = new HashMap<>();
private final Map<String, String> mTvInputLabels = new ArrayMap<>();
@@ -262,23 +206,10 @@ public class TvInputManagerHelper {
private final Comparator<TvInputInfo> mTvInputInfoComparator;
public TvInputManagerHelper(Context context) {
- this(context, createTvInputManagerWrapper(context));
- }
-
- @Nullable
- protected static TvInputManagerImpl createTvInputManagerWrapper(Context context) {
- TvInputManager tvInputManager =
- (TvInputManager) context.getSystemService(Context.TV_INPUT_SERVICE);
- return tvInputManager == null ? null : new TvInputManagerImpl(tvInputManager);
- }
-
- @VisibleForTesting
- protected TvInputManagerHelper(
- Context context, @Nullable TvInputManagerInterface tvInputManager) {
mContext = context.getApplicationContext();
mPackageManager = context.getPackageManager();
- mTvInputManager = tvInputManager;
- mContentRatingsManager = new ContentRatingsManager(context, tvInputManager);
+ mTvInputManager = (TvInputManager) context.getSystemService(Context.TV_INPUT_SERVICE);
+ mContentRatingsManager = new ContentRatingsManager(context);
mParentalControlSettings = new ParentalControlSettings(context);
mTvInputInfoComparator = new InputComparatorInternal(this);
}
@@ -389,7 +320,7 @@ public class TvInputManagerHelper {
/** Is the input one known bundled inputs not written by OEM/SOCs. */
public boolean isBundledInput(TvInputInfo inputInfo) {
return inputInfo != null
- && CommonUtils.isInBundledPackageSet(
+ && Utils.isInBundledPackageSet(
inputInfo.getServiceInfo().applicationInfo.packageName);
}
@@ -497,17 +428,9 @@ public class TvInputManagerHelper {
}
return size;
}
- /**
- * Returns TvInputInfo's input state.
- *
- * @param inputInfo
- * @return An Integer which stands for the input state {@link
- * TvInputManager.INPUT_STATE_DISCONNECTED} if inputInfo is null
- */
- public int getInputState(@Nullable TvInputInfo inputInfo) {
- return inputInfo == null
- ? TvInputManager.INPUT_STATE_DISCONNECTED
- : getInputState(inputInfo.getId());
+
+ public int getInputState(TvInputInfo inputInfo) {
+ return getInputState(inputInfo.getId());
}
public int getInputState(String inputId) {
@@ -578,15 +501,14 @@ public class TvInputManagerHelper {
}
private boolean isInBlackList(String inputId) {
- if (TvFeatures.USE_PARTNER_INPUT_BLACKLIST.isEnabled(mContext)) {
+ if (Features.USE_PARTNER_INPUT_BLACKLIST.isEnabled(mContext)) {
for (String disabledTunerInputPrefix : PARTNER_TUNER_INPUT_PREFIX_BLACKLIST) {
if (inputId.contains(disabledTunerInputPrefix)) {
return true;
}
}
}
- if (CommonUtils.isRoboTest()) return false;
- if (CommonUtils.isRunningInTest()) {
+ if (TvCommonUtils.isRunningInTest()) {
for (String testableInput : TESTABLE_INPUTS) {
if (testableInput.equals(inputId)) {
return false;
diff --git a/src/com/android/tv/util/Utils.java b/src/com/android/tv/util/Utils.java
index 1c8ccd5b..ac3be643 100644
--- a/src/com/android/tv/util/Utils.java
+++ b/src/com/android/tv/util/Utils.java
@@ -38,15 +38,20 @@ import android.support.annotation.VisibleForTesting;
import android.support.annotation.WorkerThread;
import android.text.TextUtils;
import android.text.format.DateUtils;
+import android.util.ArraySet;
import android.util.Log;
import android.view.View;
+import com.android.tv.ApplicationSingletons;
import com.android.tv.R;
-import com.android.tv.TvSingletons;
+import com.android.tv.TvApplication;
+import com.android.tv.common.BuildConfig;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.data.Channel;
import com.android.tv.data.GenreItems;
import com.android.tv.data.Program;
import com.android.tv.data.StreamInfo;
+import com.android.tv.experiments.Experiments;
+import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
@@ -63,11 +68,13 @@ import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
/** A class that includes convenience methods for accessing TvProvider database. */
-@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed
public class Utils {
private static final String TAG = "Utils";
private static final boolean DEBUG = false;
+ private static final SimpleDateFormat ISO_8601 =
+ new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US);
+
public static final String EXTRA_KEY_ACTION = "action";
public static final String EXTRA_ACTION_SHOW_TV_INPUT = "show_tv_input";
public static final String EXTRA_KEY_FROM_LAUNCHER = "from_launcher";
@@ -109,6 +116,15 @@ public class Utils {
private static final long HALF_MINUTE_MS = TimeUnit.SECONDS.toMillis(30);
private static final long ONE_DAY_MS = TimeUnit.DAYS.toMillis(1);
+ // Hardcoded list for known bundled inputs not written by OEM/SOCs.
+ // Bundled (system) inputs not in the list will get the high priority
+ // so they and their channels come first in the UI.
+ private static final Set<String> BUNDLED_PACKAGE_SET = new ArraySet<>();
+
+ static {
+ BUNDLED_PACKAGE_SET.add("com.android.tv");
+ }
+
private enum AspectRatio {
ASPECT_RATIO_4_3(4, 3),
ASPECT_RATIO_16_9(16, 9),
@@ -645,7 +661,7 @@ public class Utils {
return null;
}
TvInputManagerHelper inputManager =
- TvSingletons.getSingletons(context).getTvInputManagerHelper();
+ TvApplication.getSingletons(context).getTvInputManagerHelper();
CharSequence customLabel = inputManager.loadCustomLabel(input);
String label = (customLabel == null) ? null : customLabel.toString();
if (TextUtils.isEmpty(label)) {
@@ -688,6 +704,11 @@ public class Utils {
return toTimeString(timeMillis, true);
}
+ /** Converts time in milliseconds to a ISO 8061 string. */
+ public static String toIsoDateTimeString(long timeMillis) {
+ return ISO_8601.format(new Date(timeMillis));
+ }
+
/**
* Returns a {@link String} object which contains the layout information of the {@code view}.
*/
@@ -754,7 +775,7 @@ public class Utils {
/** Checks where there is any internal TV input. */
public static boolean hasInternalTvInputs(Context context, boolean tunerInputOnly) {
for (TvInputInfo input :
- TvSingletons.getSingletons(context)
+ TvApplication.getSingletons(context)
.getTvInputManagerHelper()
.getTvInputInfos(true, tunerInputOnly)) {
if (isInternalTvInput(context, input.getId())) {
@@ -768,7 +789,7 @@ public class Utils {
public static List<TvInputInfo> getInternalTvInputs(Context context, boolean tunerInputOnly) {
List<TvInputInfo> inputs = new ArrayList<>();
for (TvInputInfo input :
- TvSingletons.getSingletons(context)
+ TvApplication.getSingletons(context)
.getTvInputManagerHelper()
.getTvInputInfos(true, tunerInputOnly)) {
if (isInternalTvInput(context, input.getId())) {
@@ -796,22 +817,47 @@ public class Utils {
/** Returns the TV input for the given channel ID. */
@Nullable
public static TvInputInfo getTvInputInfoForChannelId(Context context, long channelId) {
- TvSingletons tvSingletons = TvSingletons.getSingletons(context);
- Channel channel = tvSingletons.getChannelDataManager().getChannel(channelId);
+ ApplicationSingletons appSingletons = TvApplication.getSingletons(context);
+ Channel channel = appSingletons.getChannelDataManager().getChannel(channelId);
if (channel == null) {
return null;
}
- return tvSingletons.getTvInputManagerHelper().getTvInputInfo(channel.getInputId());
+ return appSingletons.getTvInputManagerHelper().getTvInputInfo(channel.getInputId());
}
/** Returns the {@link TvInputInfo} for the given input ID. */
@Nullable
public static TvInputInfo getTvInputInfoForInputId(Context context, String inputId) {
- return TvSingletons.getSingletons(context)
+ return TvApplication.getSingletons(context)
.getTvInputManagerHelper()
.getTvInputInfo(inputId);
}
+ /** Deletes a file or a directory. */
+ public static void deleteDirOrFile(File fileOrDirectory) {
+ if (fileOrDirectory.isDirectory()) {
+ for (File child : fileOrDirectory.listFiles()) {
+ deleteDirOrFile(child);
+ }
+ }
+ fileOrDirectory.delete();
+ }
+
+ /** Checks whether a given package is in our bundled package set. */
+ public static boolean isInBundledPackageSet(String packageName) {
+ return BUNDLED_PACKAGE_SET.contains(packageName);
+ }
+
+ /** Checks whether a given input is a bundled input. */
+ public static boolean isBundledInput(String inputId) {
+ for (String prefix : BUNDLED_PACKAGE_SET) {
+ if (inputId.startsWith(prefix + "/")) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/** Returns the canonical genre ID's from the {@code genres}. */
public static int[] getCanonicalGenreIds(String genres) {
if (TextUtils.isEmpty(genres)) {
@@ -853,6 +899,11 @@ public class Utils {
return Genres.encode(genres);
}
+ /** Returns true if the current user is a developer. */
+ public static boolean isDeveloper() {
+ return BuildConfig.ENG || Experiments.ENABLE_DEVELOPER_FEATURES.get();
+ }
+
/**
* Runs the method in main thread. If the current thread is not main thread, block it util the
* method is finished.
diff --git a/src/com/android/tv/util/ViewCache.java b/src/com/android/tv/util/ViewCache.java
index b8bdb6b8..2d5ecfe6 100644
--- a/src/com/android/tv/util/ViewCache.java
+++ b/src/com/android/tv/util/ViewCache.java
@@ -1,18 +1,3 @@
-/*
- * 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 android.content.Context;
diff --git a/src/com/android/tv/util/account/AccountHelper.java b/src/com/android/tv/util/account/AccountHelper.java
deleted file mode 100644
index e98b42ec..00000000
--- a/src/com/android/tv/util/account/AccountHelper.java
+++ /dev/null
@@ -1,38 +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.util.account;
-
-import android.accounts.Account;
-import android.support.annotation.Nullable;
-
-/** Helper methods for getting and selecting a user account. */
-public interface AccountHelper {
- /** Returns the currently selected account or {@code null} if none is selected. */
- @Nullable
- Account getSelectedAccount();
- /**
- * Selects the first account available.
- *
- * @return selected account or {@code null} if none is selected.
- */
- @Nullable
- Account selectFirstAccount();
-
- /** Returns all eligible accounts . */
- @Nullable
- Account getFirstEligibleAccount();
-}
diff --git a/tests/common/Android.mk b/tests/common/Android.mk
index 4ead78bf..27c9f031 100644
--- a/tests/common/Android.mk
+++ b/tests/common/Android.mk
@@ -8,13 +8,8 @@ LOCAL_SRC_FILES := \
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-annotations \
- android-support-test \
- guava-22-0-jar \
- javax-annotations-jar \
mockito-target \
- platform-robolectric-3.4.2-prebuilt \
- truth-0-36-prebuilt-jar \
- ub-uiautomator \
+ ub-uiautomator
# Link tv-common as shared library to avoid the problem of initialization of the constants
LOCAL_JAVA_LIBRARIES := tv-common
@@ -22,7 +17,7 @@ LOCAL_JAVA_LIBRARIES := tv-common
LOCAL_INSTRUMENTATION_FOR := LiveTv
LOCAL_MODULE := tv-test-common
LOCAL_MODULE_TAGS := optional
-LOCAL_SDK_VERSION := system_current
+LOCAL_SDK_VERSION := current
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_AIDL_INCLUDES += $(LOCAL_PATH)/src
diff --git a/tests/common/src/com/android/tv/testing/data/ChannelInfo.java b/tests/common/src/com/android/tv/testing/ChannelInfo.java
index e39c057d..b28ac9fb 100644
--- a/tests/common/src/com/android/tv/testing/data/ChannelInfo.java
+++ b/tests/common/src/com/android/tv/testing/ChannelInfo.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.tv.testing.data;
+package com.android.tv.testing;
import android.content.ContentResolver;
import android.content.Context;
diff --git a/tests/common/src/com/android/tv/testing/ChannelNumberSubject.java b/tests/common/src/com/android/tv/testing/ChannelNumberSubject.java
deleted file mode 100644
index ba4662ee..00000000
--- a/tests/common/src/com/android/tv/testing/ChannelNumberSubject.java
+++ /dev/null
@@ -1,66 +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 android.support.annotation.Nullable;
-import com.android.tv.data.ChannelNumber;
-import com.google.common.truth.ComparableSubject;
-import com.google.common.truth.FailureMetadata;
-import com.google.common.truth.Subject;
-import com.google.common.truth.Truth;
-
-/** Propositions for {@link ChannelNumber} subjects. */
-public final class ChannelNumberSubject
- extends ComparableSubject<ChannelNumberSubject, ChannelNumber> {
- private static final Subject.Factory<ChannelNumberSubject, ChannelNumber> FACTORY =
- ChannelNumberSubject::new;
-
- public static Subject.Factory<ChannelNumberSubject, ChannelNumber> channelNumbers() {
- return FACTORY;
- }
-
- public static ChannelNumberSubject assertThat(@Nullable ChannelNumber actual) {
- return Truth.assertAbout(channelNumbers()).that(actual);
- }
-
- public ChannelNumberSubject(FailureMetadata failureMetadata, @Nullable ChannelNumber subject) {
- super(failureMetadata, subject);
- }
-
- public void displaysAs(int major) {
- if (!getSubject().majorNumber.equals(Integer.toString(major))
- || getSubject().hasDelimiter) {
- fail("displaysAs", major);
- }
- }
-
- public void displaysAs(int major, int minor) {
- if (!getSubject().majorNumber.equals(Integer.toString(major))
- || !getSubject().minorNumber.equals(Integer.toString(minor))
- || !getSubject().hasDelimiter) {
- fail("displaysAs", major + "-" + minor);
- }
- }
-
- public void isEmpty() {
- if (!getSubject().majorNumber.isEmpty()
- || !getSubject().minorNumber.isEmpty()
- || getSubject().hasDelimiter) {
- fail("isEmpty");
- }
- }
-}
diff --git a/tests/common/src/com/android/tv/testing/data/ChannelUtils.java b/tests/common/src/com/android/tv/testing/ChannelUtils.java
index c95c4d2a..b9c48f37 100644
--- a/tests/common/src/com/android/tv/testing/data/ChannelUtils.java
+++ b/tests/common/src/com/android/tv/testing/ChannelUtils.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.tv.testing.data;
+package com.android.tv.testing;
import android.content.ContentResolver;
import android.content.ContentValues;
@@ -35,14 +35,13 @@ import java.util.List;
import java.util.Map;
/** Static helper methods for working with {@link android.media.tv.TvContract}. */
-@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed
public class ChannelUtils {
private static final String TAG = "ChannelUtils";
private static final boolean DEBUG = false;
/**
* Query and return the map of (channel_id, ChannelInfo). See: {@link
- * com.android.tv.testing.data.ChannelInfo#fromCursor(Cursor)}.
+ * ChannelInfo#fromCursor(Cursor)}.
*/
@WorkerThread
public static Map<Long, ChannelInfo> queryChannelInfoMapForTvInput(
@@ -111,14 +110,10 @@ public class ChannelUtils {
Long rowId = existingChannelsMap.get(channel.originalNetworkId);
Uri uri;
if (rowId == null) {
- if (DEBUG) {
- Log.d(TAG, "Inserting " + channel);
- }
+ if (DEBUG) Log.d(TAG, "Inserting " + channel);
uri = resolver.insert(TvContract.Channels.CONTENT_URI, values);
} else {
- if (DEBUG) {
- Log.d(TAG, "Updating " + channel);
- }
+ if (DEBUG) Log.d(TAG, "Updating " + channel);
uri = TvContract.buildChannelUri(rowId);
resolver.update(uri, values, null, null);
existingChannelsMap.remove(channel.originalNetworkId);
diff --git a/tests/common/src/com/android/tv/testing/constants/Constants.java b/tests/common/src/com/android/tv/testing/Constants.java
index 09e1ada1..879a88b4 100644
--- a/tests/common/src/com/android/tv/testing/constants/Constants.java
+++ b/tests/common/src/com/android/tv/testing/Constants.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.tv.testing.constants;
+package com.android.tv.testing;
import android.media.tv.TvTrackInfo;
diff --git a/tests/common/src/com/android/tv/testing/DbTestingUtils.java b/tests/common/src/com/android/tv/testing/DbTestingUtils.java
deleted file mode 100644
index 53e26ca7..00000000
--- a/tests/common/src/com/android/tv/testing/DbTestingUtils.java
+++ /dev/null
@@ -1,40 +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 android.database.Cursor;
-import java.util.ArrayList;
-import java.util.List;
-
-/** Static utilities for testing using databases. */
-public final class DbTestingUtils {
-
- public static List<List<String>> toList(Cursor cursor) {
- ArrayList<List<String>> result = new ArrayList<>();
- int colCount = cursor.getColumnCount();
- while (cursor.moveToNext()) {
- List<String> row = new ArrayList<>(colCount);
- for (int i = 0; i < colCount; i++) {
- row.add(cursor.getString(i));
- }
- result.add(row);
- }
- return result;
- }
-
- private DbTestingUtils() {}
-}
diff --git a/tests/common/src/com/android/tv/testing/EpgTestData.java b/tests/common/src/com/android/tv/testing/EpgTestData.java
deleted file mode 100644
index 87bfb4ed..00000000
--- a/tests/common/src/com/android/tv/testing/EpgTestData.java
+++ /dev/null
@@ -1,197 +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 com.android.tv.data.Channel;
-import com.android.tv.data.Lineup;
-import com.android.tv.data.Program;
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableListMultimap;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.ListMultimap;
-import java.util.concurrent.TimeUnit;
-
-/** EPG data for use in tests. */
-public abstract class EpgTestData {
-
- public static final android.support.media.tv.Channel CHANNEL_10 =
- new android.support.media.tv.Channel.Builder()
- .setDisplayName("Channel TEN")
- .setDisplayNumber("10")
- .build();
- public static final android.support.media.tv.Channel CHANNEL_11 =
- new android.support.media.tv.Channel.Builder()
- .setDisplayName("Channel Eleven")
- .setDisplayNumber("11")
- .build();
- public static final android.support.media.tv.Channel CHANNEL_90_2 =
- new android.support.media.tv.Channel.Builder()
- .setDisplayName("Channel Ninety dot Two")
- .setDisplayNumber("90.2")
- .build();
-
- public static final Lineup LINEUP_1 =
- new Lineup(
- "lineup1",
- Lineup.LINEUP_SATELLITE,
- "Lineup one",
- "Location one",
- ImmutableList.of("1", "2.2"));
- public static final Lineup LINEUP_2 =
- new Lineup(
- "lineup2",
- Lineup.LINEUP_SATELLITE,
- "Lineup two",
- "Location two",
- ImmutableList.of("1", "2.3"));
-
- public static final Lineup LINEUP_90210 =
- new Lineup(
- "test90210",
- Lineup.LINEUP_BROADCAST_DIGITAL,
- "Test 90210",
- "Beverly Hills",
- ImmutableList.of("90.2", "10"));
-
- // Programs start and end times are set relative to 0.
- // Then when loaded they are offset by the {@link #getStartTimeMs}.
- // Start and end time may be negative meaning they happen before "now".
-
- public static final Program PROGRAM_1 =
- new Program.Builder()
- .setTitle("Program 1")
- .setStartTimeUtcMillis(0)
- .setEndTimeUtcMillis(TimeUnit.MINUTES.toMillis(30))
- .build();
-
- public static final Program PROGRAM_2 =
- new Program.Builder()
- .setTitle("Program 2")
- .setStartTimeUtcMillis(TimeUnit.MINUTES.toMillis(30))
- .setEndTimeUtcMillis(TimeUnit.MINUTES.toMillis(60))
- .build();
-
- public static final EpgTestData DATA_90210 =
- new EpgTestData() {
-
- // Thursday, June 1, 2017 4:00:00 PM GMT-07:00
- private final long testStartTimeMs = 1496358000000L;
-
- @Override
- public ListMultimap<String, Lineup> getLineups() {
- ImmutableListMultimap.Builder<String, Lineup> builder =
- ImmutableListMultimap.builder();
- return builder.putAll("90210", LINEUP_1, LINEUP_2, LINEUP_90210).build();
- }
-
- @Override
- public ListMultimap<String, Channel> getLineupChannels() {
- ImmutableListMultimap.Builder<String, Channel> builder =
- ImmutableListMultimap.builder();
- return builder.putAll(
- LINEUP_90210.getId(), toTvChannels(CHANNEL_90_2, CHANNEL_10))
- .putAll(LINEUP_1.getId(), toTvChannels(CHANNEL_10, CHANNEL_11))
- .build();
- }
-
- @Override
- public ListMultimap<String, Program> getEpgPrograms() {
- ImmutableListMultimap.Builder<String, Program> builder =
- ImmutableListMultimap.builder();
- return builder.putAll(
- CHANNEL_10.getDisplayNumber(),
- EpgTestData.updateTime(getStartTimeMs(), PROGRAM_1))
- .putAll(
- CHANNEL_11.getDisplayNumber(),
- EpgTestData.updateTime(getStartTimeMs(), PROGRAM_2))
- .build();
- }
-
- @Override
- public long getStartTimeMs() {
- return testStartTimeMs;
- }
- };
-
- public abstract ListMultimap<String, Lineup> getLineups();
-
- public abstract ListMultimap<String, Channel> getLineupChannels();
-
- public abstract ListMultimap<String, Program> getEpgPrograms();
-
- /** The starting time for this test data */
- public abstract long getStartTimeMs();
-
- /**
- * Loads test data
- *
- * <p>
- *
- * <ul>
- * <li>Sets clock to {@link #getStartTimeMs()} and boot time to 12 hours before that
- * <li>Loads lineups
- * <li>Loads lineupChannels
- * <li>Loads epgPrograms
- * </ul>
- */
- public final void loadData(FakeClock clock, FakeEpgReader epgReader) {
- clock.setBootTimeMillis(getStartTimeMs() + TimeUnit.HOURS.toMillis(-12));
- clock.setCurrentTimeMillis(getStartTimeMs());
- epgReader.zip2lineups.putAll(getLineups());
- epgReader.lineup2Channels.putAll(getLineupChannels());
- epgReader.epgChannelId2Programs.putAll(getEpgPrograms());
- }
-
- public final void loadData(TestSingletonApp testSingletonApp) {
- loadData(testSingletonApp.fakeClock, testSingletonApp.epgReader);
- }
-
- private static Iterable<Channel> toTvChannels(android.support.media.tv.Channel... channels) {
- return Iterables.transform(
- ImmutableList.copyOf(channels),
- new Function<android.support.media.tv.Channel, Channel>() {
- @Override
- public Channel apply(android.support.media.tv.Channel original) {
- return toTvChannel(original);
- }
- });
- }
-
- public static Channel toTvChannel(android.support.media.tv.Channel original) {
- return new Channel.Builder()
- .setDisplayName(original.getDisplayName())
- .setDisplayNumber(original.getDisplayNumber())
- // TODO implement the reset
- .build();
- }
-
- /** Add time to the startTime and stopTime of each program */
- private static Iterable<Program> updateTime(long time, Program... programs) {
- return Iterables.transform(
- ImmutableList.copyOf(programs),
- new Function<Program, Program>() {
- @Override
- public Program apply(Program p) {
- return new Program.Builder(p)
- .setStartTimeUtcMillis(p.getStartTimeUtcMillis() + time)
- .setEndTimeUtcMillis(p.getEndTimeUtcMillis() + time)
- .build();
- }
- });
- }
-}
diff --git a/tests/common/src/com/android/tv/testing/FakeClock.java b/tests/common/src/com/android/tv/testing/FakeClock.java
index 66978a3d..fd6165cf 100644
--- a/tests/common/src/com/android/tv/testing/FakeClock.java
+++ b/tests/common/src/com/android/tv/testing/FakeClock.java
@@ -16,7 +16,7 @@
package com.android.tv.testing;
-import com.android.tv.common.util.Clock;
+import com.android.tv.util.Clock;
import java.util.concurrent.TimeUnit;
/**
diff --git a/tests/common/src/com/android/tv/testing/FakeEpgFetcher.java b/tests/common/src/com/android/tv/testing/FakeEpgFetcher.java
deleted file mode 100644
index d1018a5c..00000000
--- a/tests/common/src/com/android/tv/testing/FakeEpgFetcher.java
+++ /dev/null
@@ -1,57 +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 android.app.job.JobParameters;
-import android.app.job.JobService;
-import com.android.tv.data.epg.EpgFetcher;
-
-/** Fake {@link EpgFetcher} for testing. */
-public class FakeEpgFetcher implements EpgFetcher {
- public boolean fetchStarted = false;
-
- @Override
- public void startRoutineService() {}
-
- @Override
- public void fetchImmediatelyIfNeeded() {}
-
- @Override
- public void fetchImmediately() {
- fetchStarted = true;
- }
-
- @Override
- public void onChannelScanStarted() {}
-
- @Override
- public void onChannelScanFinished() {}
-
- @Override
- public boolean executeFetchTaskIfPossible(JobService jobService, JobParameters params) {
- return false;
- }
-
- @Override
- public void stopFetchingJob() {
- fetchStarted = false;
- }
-
- public void reset() {
- fetchStarted = false;
- }
-}
diff --git a/tests/common/src/com/android/tv/testing/FakeEpgReader.java b/tests/common/src/com/android/tv/testing/FakeEpgReader.java
deleted file mode 100644
index a3505279..00000000
--- a/tests/common/src/com/android/tv/testing/FakeEpgReader.java
+++ /dev/null
@@ -1,163 +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 android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.util.Range;
-import com.android.tv.data.Channel;
-import com.android.tv.data.ChannelNumber;
-import com.android.tv.data.Lineup;
-import com.android.tv.data.Program;
-import com.android.tv.data.epg.EpgReader;
-import com.android.tv.dvr.data.SeriesInfo;
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.LinkedListMultimap;
-import com.google.common.collect.ListMultimap;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/** Fake {@link EpgReader} for testing. */
-public final class FakeEpgReader implements EpgReader {
- public final ListMultimap<String, Lineup> zip2lineups = LinkedListMultimap.create(2);
- public final ListMultimap<String, Channel> lineup2Channels = LinkedListMultimap.create(2);
- public final ListMultimap<String, Program> epgChannelId2Programs = LinkedListMultimap.create(2);
- public final FakeClock fakeClock;
-
- public FakeEpgReader(FakeClock fakeClock) {
- this.fakeClock = fakeClock;
- }
-
- @Override
- public boolean isAvailable() {
- return true;
- }
-
- @Override
- public long getEpgTimestamp() {
- return fakeClock.currentTimeMillis();
- }
-
- @Override
- public void setRegionCode(String regionCode) {}
-
- @Override
- public List<Lineup> getLineups(@NonNull String postalCode) {
- return zip2lineups.get(postalCode);
- }
-
- @Override
- public List<String> getChannelNumbers(@NonNull String lineupId) {
- return null;
- }
-
- @Override
- public Set<EpgChannel> getChannels(Set<Channel> inputChannels, @NonNull String lineupId) {
- Set<EpgChannel> result = new HashSet<>();
- List<Channel> lineupChannels = lineup2Channels.get(lineupId);
- for (Channel channel : lineupChannels) {
- Channel match =
- Iterables.find(
- inputChannels,
- new Predicate<Channel>() {
- @Override
- public boolean apply(@Nullable Channel inputChannel) {
- return ChannelNumber.equivalent(
- inputChannel.getDisplayNumber(),
- channel.getDisplayNumber());
- }
- },
- null);
- if (match != null) {
- Channel updatedChannel = new Channel.Builder(match).build();
- updatedChannel.setLogoUri(channel.getLogoUri());
- result.add(EpgChannel.createEpgChannel(updatedChannel, channel.getDisplayNumber()));
- }
- }
- return result;
- }
-
- @Override
- public void preloadChannels(@NonNull String lineupId) {}
-
- @Override
- public void clearCachedChannels(@NonNull String lineupId) {}
-
- @Override
- public List<Program> getPrograms(EpgChannel epgChannel) {
- return ImmutableList.copyOf(
- Iterables.transform(
- epgChannelId2Programs.get(epgChannel.getEpgChannelId()),
- updateWith(epgChannel)));
- }
-
- @Override
- public Map<EpgChannel, Collection<Program>> getPrograms(
- @NonNull Set<EpgChannel> epgChannels, long duration) {
- Range<Long> validRange =
- Range.create(
- fakeClock.currentTimeMillis(), fakeClock.currentTimeMillis() + duration);
- ImmutableMap.Builder<EpgChannel, Collection<Program>> mapBuilder = ImmutableMap.builder();
- for (EpgChannel epgChannel : epgChannels) {
- Iterable<Program> programs = getPrograms(epgChannel);
-
- mapBuilder.put(
- epgChannel,
- ImmutableList.copyOf(Iterables.filter(programs, isProgramDuring(validRange))));
- }
- return mapBuilder.build();
- }
-
- protected Function<Program, Program> updateWith(final EpgChannel channel) {
- return new Function<Program, Program>() {
- @Nullable
- @Override
- public Program apply(@Nullable Program program) {
- return new Program.Builder(program)
- .setChannelId(channel.getChannel().getId())
- .setPackageName(channel.getChannel().getPackageName())
- .build();
- }
- };
- }
-
- /**
- * True if the start time or the end time is {@link Range#contains contained (inclusive)} in the
- * range
- */
- protected Predicate<Program> isProgramDuring(final Range<Long> validRange) {
- return new Predicate<Program>() {
- @Override
- public boolean apply(@Nullable Program program) {
- return validRange.contains(program.getStartTimeUtcMillis())
- || validRange.contains(program.getEndTimeUtcMillis());
- }
- };
- }
-
- @Override
- public SeriesInfo getSeriesInfo(@NonNull String seriesId) {
- return null;
- }
-}
diff --git a/tests/common/src/com/android/tv/testing/FakeRemoteConfig.java b/tests/common/src/com/android/tv/testing/FakeRemoteConfig.java
deleted file mode 100644
index d8951d08..00000000
--- a/tests/common/src/com/android/tv/testing/FakeRemoteConfig.java
+++ /dev/null
@@ -1,47 +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 android.text.TextUtils;
-import com.android.tv.common.config.api.RemoteConfig;
-import java.util.HashMap;
-import java.util.Map;
-
-/** Fake {@link RemoteConfig} suitable for testing. */
-public class FakeRemoteConfig implements RemoteConfig {
- public final Map<String, String> values = new HashMap();
-
- @Override
- public void fetch(OnRemoteConfigUpdatedListener listener) {}
-
- @Override
- public String getString(String key) {
- return values.get(key);
- }
-
- @Override
- public boolean getBoolean(String key) {
- String value = values.get(key);
- return TextUtils.isEmpty(value) ? false : Boolean.valueOf(key);
- }
-
- @Override
- public long getLong(String key) {
- String value = values.get(key);
- return TextUtils.isEmpty(value) ? 0 : Long.valueOf(key);
- }
-}
diff --git a/tests/common/src/com/android/tv/testing/FakeTvInputManager.java b/tests/common/src/com/android/tv/testing/FakeTvInputManager.java
deleted file mode 100644
index 397b4052..00000000
--- a/tests/common/src/com/android/tv/testing/FakeTvInputManager.java
+++ /dev/null
@@ -1,117 +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 android.media.tv.TvContentRatingSystemInfo;
-import android.media.tv.TvInputInfo;
-import android.media.tv.TvInputManager;
-import android.os.Handler;
-import com.android.tv.util.TvInputManagerHelper;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/** Fake implementation for testing. */
-public class FakeTvInputManager implements TvInputManagerHelper.TvInputManagerInterface {
-
- private final Map<String, Integer> mInputStateMap = new HashMap<>();
- private final Map<String, TvInputInfo> mInputMap = new HashMap<>();
- private final Map<TvInputManager.TvInputCallback, Handler> mCallbacks = new HashMap<>();
-
- public void add(TvInputInfo inputInfo, int state) {
- final String inputId = inputInfo.getId();
- if (mInputStateMap.containsKey(inputId)) {
- throw new IllegalArgumentException("inputId " + inputId);
- }
- mInputMap.put(inputId, inputInfo);
- mInputStateMap.put(inputId, state);
- for (final Map.Entry<TvInputManager.TvInputCallback, Handler> e : mCallbacks.entrySet()) {
- e.getValue()
- .post(
- new Runnable() {
- @Override
- public void run() {
- e.getKey().onInputAdded(inputId);
- }
- });
- }
- }
-
- public void setInputState(final String inputId, final int state) {
- if (!mInputStateMap.containsKey(inputId)) {
- throw new IllegalArgumentException("inputId " + inputId);
- }
- mInputStateMap.put(inputId, state);
- for (final Map.Entry<TvInputManager.TvInputCallback, Handler> e : mCallbacks.entrySet()) {
- e.getValue()
- .post(
- new Runnable() {
- @Override
- public void run() {
- e.getKey().onInputStateChanged(inputId, state);
- }
- });
- }
- }
-
- public void remove(final String inputId) {
- mInputMap.remove(inputId);
- mInputStateMap.remove(inputId);
- for (final Map.Entry<TvInputManager.TvInputCallback, Handler> e : mCallbacks.entrySet()) {
- e.getValue()
- .post(
- new Runnable() {
- @Override
- public void run() {
- e.getKey().onInputRemoved(inputId);
- }
- });
- }
- }
-
- @Override
- public TvInputInfo getTvInputInfo(String inputId) {
- return mInputMap.get(inputId);
- }
-
- @Override
- public Integer getInputState(String inputId) {
- return mInputStateMap.get(inputId);
- }
-
- @Override
- public void registerCallback(TvInputManager.TvInputCallback internalCallback, Handler handler) {
- mCallbacks.put(internalCallback, handler);
- }
-
- @Override
- public void unregisterCallback(TvInputManager.TvInputCallback internalCallback) {
- mCallbacks.remove(internalCallback);
- }
-
- @Override
- public List<TvInputInfo> getTvInputList() {
- return new ArrayList(mInputMap.values());
- }
-
- @Override
- public List<TvContentRatingSystemInfo> getTvContentRatingSystemList() {
- // TODO implement
- return new ArrayList<>();
- }
-}
diff --git a/tests/common/src/com/android/tv/testing/FakeTvInputManagerHelper.java b/tests/common/src/com/android/tv/testing/FakeTvInputManagerHelper.java
deleted file mode 100644
index 85bdcf04..00000000
--- a/tests/common/src/com/android/tv/testing/FakeTvInputManagerHelper.java
+++ /dev/null
@@ -1,32 +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 android.content.Context;
-import com.android.tv.util.TvInputManagerHelper;
-
-/** Fake TvInputManagerHelper. */
-public class FakeTvInputManagerHelper extends TvInputManagerHelper {
-
- public FakeTvInputManagerHelper(Context context) {
- super(context, new FakeTvInputManager());
- }
-
- public FakeTvInputManager getFakeTvInputManager() {
- return (FakeTvInputManager) mTvInputManager;
- }
-}
diff --git a/tests/common/src/com/android/tv/testing/FakeTvProvider.java b/tests/common/src/com/android/tv/testing/FakeTvProvider.java
deleted file mode 100644
index 24c26f39..00000000
--- a/tests/common/src/com/android/tv/testing/FakeTvProvider.java
+++ /dev/null
@@ -1,2605 +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 android.annotation.SuppressLint;
-import android.content.ContentProvider;
-import android.content.ContentProviderOperation;
-import android.content.ContentProviderResult;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.OperationApplicationException;
-import android.content.SharedPreferences;
-import android.content.UriMatcher;
-import android.content.pm.PackageManager;
-import android.database.Cursor;
-import android.database.DatabaseUtils;
-import android.database.SQLException;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.database.sqlite.SQLiteQueryBuilder;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.media.tv.TvContract;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.ParcelFileDescriptor;
-import android.os.ParcelFileDescriptor.AutoCloseInputStream;
-import android.preference.PreferenceManager;
-import android.provider.BaseColumns;
-import android.support.annotation.VisibleForTesting;
-import android.support.media.tv.TvContractCompat;
-import android.support.media.tv.TvContractCompat.BaseTvColumns;
-import android.support.media.tv.TvContractCompat.Channels;
-import android.support.media.tv.TvContractCompat.PreviewPrograms;
-import android.support.media.tv.TvContractCompat.Programs;
-import android.support.media.tv.TvContractCompat.Programs.Genres;
-import android.support.media.tv.TvContractCompat.RecordedPrograms;
-import android.support.media.tv.TvContractCompat.WatchNextPrograms;
-import android.text.TextUtils;
-import android.util.Log;
-import com.android.tv.util.SqlParams;
-import java.io.ByteArrayOutputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * Fake TV content provider suitable for unit tests. The contract between this provider and
- * applications is defined in {@link TvContractCompat}.
- */
-// TODO(b/62143348): remove when error prone check fixed
-@SuppressWarnings({"AndroidApiChecker", "TryWithResources"})
-public class FakeTvProvider extends ContentProvider {
- // TODO either make this a shadow or move it to the support library
-
- private static final boolean DEBUG = false;
- private static final String TAG = "TvProvider";
-
- static final int DATABASE_VERSION = 34;
- static final String SHARED_PREF_BLOCKED_PACKAGES_KEY = "blocked_packages";
- static final String CHANNELS_TABLE = "channels";
- static final String PROGRAMS_TABLE = "programs";
- static final String RECORDED_PROGRAMS_TABLE = "recorded_programs";
- static final String PREVIEW_PROGRAMS_TABLE = "preview_programs";
- static final String WATCH_NEXT_PROGRAMS_TABLE = "watch_next_programs";
- static final String WATCHED_PROGRAMS_TABLE = "watched_programs";
- static final String PROGRAMS_TABLE_PACKAGE_NAME_INDEX = "programs_package_name_index";
- static final String PROGRAMS_TABLE_CHANNEL_ID_INDEX = "programs_channel_id_index";
- static final String PROGRAMS_TABLE_START_TIME_INDEX = "programs_start_time_index";
- static final String PROGRAMS_TABLE_END_TIME_INDEX = "programs_end_time_index";
- static final String WATCHED_PROGRAMS_TABLE_CHANNEL_ID_INDEX =
- "watched_programs_channel_id_index";
- // The internal column in the watched programs table to indicate whether the current log entry
- // is consolidated or not. Unconsolidated entries may have columns with missing data.
- static final String WATCHED_PROGRAMS_COLUMN_CONSOLIDATED = "consolidated";
- static final String CHANNELS_COLUMN_LOGO = "logo";
- private static final String DATABASE_NAME = "tv.db";
- private static final String DELETED_CHANNELS_TABLE = "deleted_channels"; // Deprecated
- private static final String DEFAULT_PROGRAMS_SORT_ORDER =
- Programs.COLUMN_START_TIME_UTC_MILLIS + " ASC";
- private static final String DEFAULT_WATCHED_PROGRAMS_SORT_ORDER =
- WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS + " DESC";
- private static final String CHANNELS_TABLE_INNER_JOIN_PROGRAMS_TABLE =
- CHANNELS_TABLE
- + " INNER JOIN "
- + PROGRAMS_TABLE
- + " ON ("
- + CHANNELS_TABLE
- + "."
- + Channels._ID
- + "="
- + PROGRAMS_TABLE
- + "."
- + Programs.COLUMN_CHANNEL_ID
- + ")";
-
- // Operation names for createSqlParams().
- private static final String OP_QUERY = "query";
- private static final String OP_UPDATE = "update";
- private static final String OP_DELETE = "delete";
-
- private static final UriMatcher sUriMatcher;
- private static final int MATCH_CHANNEL = 1;
- private static final int MATCH_CHANNEL_ID = 2;
- private static final int MATCH_CHANNEL_ID_LOGO = 3;
- private static final int MATCH_PASSTHROUGH_ID = 4;
- private static final int MATCH_PROGRAM = 5;
- private static final int MATCH_PROGRAM_ID = 6;
- private static final int MATCH_WATCHED_PROGRAM = 7;
- private static final int MATCH_WATCHED_PROGRAM_ID = 8;
- private static final int MATCH_RECORDED_PROGRAM = 9;
- private static final int MATCH_RECORDED_PROGRAM_ID = 10;
- private static final int MATCH_PREVIEW_PROGRAM = 11;
- private static final int MATCH_PREVIEW_PROGRAM_ID = 12;
- private static final int MATCH_WATCH_NEXT_PROGRAM = 13;
- private static final int MATCH_WATCH_NEXT_PROGRAM_ID = 14;
-
- private static final int MAX_LOGO_IMAGE_SIZE = 256;
-
- private static final String EMPTY_STRING = "";
-
- private static final Map<String, String> sChannelProjectionMap;
- private static final Map<String, String> sProgramProjectionMap;
- private static final Map<String, String> sWatchedProgramProjectionMap;
- private static final Map<String, String> sRecordedProgramProjectionMap;
- private static final Map<String, String> sPreviewProgramProjectionMap;
- private static final Map<String, String> sWatchNextProgramProjectionMap;
-
- // TvContract hidden
- private static final String PARAM_PACKAGE = "package";
- private static final String PARAM_PREVIEW = "preview";
-
- private static boolean sInitialized;
-
- static {
- sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
- sUriMatcher.addURI(TvContractCompat.AUTHORITY, "channel", MATCH_CHANNEL);
- sUriMatcher.addURI(TvContractCompat.AUTHORITY, "channel/#", MATCH_CHANNEL_ID);
- sUriMatcher.addURI(TvContractCompat.AUTHORITY, "channel/#/logo", MATCH_CHANNEL_ID_LOGO);
- sUriMatcher.addURI(TvContractCompat.AUTHORITY, "passthrough/*", MATCH_PASSTHROUGH_ID);
- sUriMatcher.addURI(TvContractCompat.AUTHORITY, "program", MATCH_PROGRAM);
- sUriMatcher.addURI(TvContractCompat.AUTHORITY, "program/#", MATCH_PROGRAM_ID);
- sUriMatcher.addURI(TvContractCompat.AUTHORITY, "watched_program", MATCH_WATCHED_PROGRAM);
- sUriMatcher.addURI(
- TvContractCompat.AUTHORITY, "watched_program/#", MATCH_WATCHED_PROGRAM_ID);
- sUriMatcher.addURI(TvContractCompat.AUTHORITY, "recorded_program", MATCH_RECORDED_PROGRAM);
- sUriMatcher.addURI(
- TvContractCompat.AUTHORITY, "recorded_program/#", MATCH_RECORDED_PROGRAM_ID);
- sUriMatcher.addURI(TvContractCompat.AUTHORITY, "preview_program", MATCH_PREVIEW_PROGRAM);
- sUriMatcher.addURI(
- TvContractCompat.AUTHORITY, "preview_program/#", MATCH_PREVIEW_PROGRAM_ID);
- sUriMatcher.addURI(
- TvContractCompat.AUTHORITY, "watch_next_program", MATCH_WATCH_NEXT_PROGRAM);
- sUriMatcher.addURI(
- TvContractCompat.AUTHORITY, "watch_next_program/#", MATCH_WATCH_NEXT_PROGRAM_ID);
-
- sChannelProjectionMap = new HashMap<>();
- sChannelProjectionMap.put(Channels._ID, CHANNELS_TABLE + "." + Channels._ID);
- sChannelProjectionMap.put(
- Channels.COLUMN_PACKAGE_NAME, CHANNELS_TABLE + "." + Channels.COLUMN_PACKAGE_NAME);
- sChannelProjectionMap.put(
- Channels.COLUMN_INPUT_ID, CHANNELS_TABLE + "." + Channels.COLUMN_INPUT_ID);
- sChannelProjectionMap.put(
- Channels.COLUMN_TYPE, CHANNELS_TABLE + "." + Channels.COLUMN_TYPE);
- sChannelProjectionMap.put(
- Channels.COLUMN_SERVICE_TYPE, CHANNELS_TABLE + "." + Channels.COLUMN_SERVICE_TYPE);
- sChannelProjectionMap.put(
- Channels.COLUMN_ORIGINAL_NETWORK_ID,
- CHANNELS_TABLE + "." + Channels.COLUMN_ORIGINAL_NETWORK_ID);
- sChannelProjectionMap.put(
- Channels.COLUMN_TRANSPORT_STREAM_ID,
- CHANNELS_TABLE + "." + Channels.COLUMN_TRANSPORT_STREAM_ID);
- sChannelProjectionMap.put(
- Channels.COLUMN_SERVICE_ID, CHANNELS_TABLE + "." + Channels.COLUMN_SERVICE_ID);
- sChannelProjectionMap.put(
- Channels.COLUMN_DISPLAY_NUMBER,
- CHANNELS_TABLE + "." + Channels.COLUMN_DISPLAY_NUMBER);
- sChannelProjectionMap.put(
- Channels.COLUMN_DISPLAY_NAME, CHANNELS_TABLE + "." + Channels.COLUMN_DISPLAY_NAME);
- sChannelProjectionMap.put(
- Channels.COLUMN_NETWORK_AFFILIATION,
- CHANNELS_TABLE + "." + Channels.COLUMN_NETWORK_AFFILIATION);
- sChannelProjectionMap.put(
- Channels.COLUMN_DESCRIPTION, CHANNELS_TABLE + "." + Channels.COLUMN_DESCRIPTION);
- sChannelProjectionMap.put(
- Channels.COLUMN_VIDEO_FORMAT, CHANNELS_TABLE + "." + Channels.COLUMN_VIDEO_FORMAT);
- sChannelProjectionMap.put(
- Channels.COLUMN_BROWSABLE, CHANNELS_TABLE + "." + Channels.COLUMN_BROWSABLE);
- sChannelProjectionMap.put(
- Channels.COLUMN_SEARCHABLE, CHANNELS_TABLE + "." + Channels.COLUMN_SEARCHABLE);
- sChannelProjectionMap.put(
- Channels.COLUMN_LOCKED, CHANNELS_TABLE + "." + Channels.COLUMN_LOCKED);
- sChannelProjectionMap.put(
- Channels.COLUMN_APP_LINK_ICON_URI,
- CHANNELS_TABLE + "." + Channels.COLUMN_APP_LINK_ICON_URI);
- sChannelProjectionMap.put(
- Channels.COLUMN_APP_LINK_POSTER_ART_URI,
- CHANNELS_TABLE + "." + Channels.COLUMN_APP_LINK_POSTER_ART_URI);
- sChannelProjectionMap.put(
- Channels.COLUMN_APP_LINK_TEXT,
- CHANNELS_TABLE + "." + Channels.COLUMN_APP_LINK_TEXT);
- sChannelProjectionMap.put(
- Channels.COLUMN_APP_LINK_COLOR,
- CHANNELS_TABLE + "." + Channels.COLUMN_APP_LINK_COLOR);
- sChannelProjectionMap.put(
- Channels.COLUMN_APP_LINK_INTENT_URI,
- CHANNELS_TABLE + "." + Channels.COLUMN_APP_LINK_INTENT_URI);
- sChannelProjectionMap.put(
- Channels.COLUMN_INTERNAL_PROVIDER_DATA,
- CHANNELS_TABLE + "." + Channels.COLUMN_INTERNAL_PROVIDER_DATA);
- sChannelProjectionMap.put(
- Channels.COLUMN_INTERNAL_PROVIDER_FLAG1,
- CHANNELS_TABLE + "." + Channels.COLUMN_INTERNAL_PROVIDER_FLAG1);
- sChannelProjectionMap.put(
- Channels.COLUMN_INTERNAL_PROVIDER_FLAG2,
- CHANNELS_TABLE + "." + Channels.COLUMN_INTERNAL_PROVIDER_FLAG2);
- sChannelProjectionMap.put(
- Channels.COLUMN_INTERNAL_PROVIDER_FLAG3,
- CHANNELS_TABLE + "." + Channels.COLUMN_INTERNAL_PROVIDER_FLAG3);
- sChannelProjectionMap.put(
- Channels.COLUMN_INTERNAL_PROVIDER_FLAG4,
- CHANNELS_TABLE + "." + Channels.COLUMN_INTERNAL_PROVIDER_FLAG4);
- sChannelProjectionMap.put(
- Channels.COLUMN_VERSION_NUMBER,
- CHANNELS_TABLE + "." + Channels.COLUMN_VERSION_NUMBER);
- sChannelProjectionMap.put(
- Channels.COLUMN_TRANSIENT, CHANNELS_TABLE + "." + Channels.COLUMN_TRANSIENT);
- sChannelProjectionMap.put(
- Channels.COLUMN_INTERNAL_PROVIDER_ID,
- CHANNELS_TABLE + "." + Channels.COLUMN_INTERNAL_PROVIDER_ID);
-
- sProgramProjectionMap = new HashMap<>();
- sProgramProjectionMap.put(Programs._ID, Programs._ID);
- sProgramProjectionMap.put(Programs.COLUMN_PACKAGE_NAME, Programs.COLUMN_PACKAGE_NAME);
- sProgramProjectionMap.put(Programs.COLUMN_CHANNEL_ID, Programs.COLUMN_CHANNEL_ID);
- sProgramProjectionMap.put(Programs.COLUMN_TITLE, Programs.COLUMN_TITLE);
- // COLUMN_SEASON_NUMBER is deprecated. Return COLUMN_SEASON_DISPLAY_NUMBER instead.
- sProgramProjectionMap.put(
- Programs.COLUMN_SEASON_NUMBER,
- Programs.COLUMN_SEASON_DISPLAY_NUMBER + " AS " + Programs.COLUMN_SEASON_NUMBER);
- sProgramProjectionMap.put(
- Programs.COLUMN_SEASON_DISPLAY_NUMBER, Programs.COLUMN_SEASON_DISPLAY_NUMBER);
- sProgramProjectionMap.put(Programs.COLUMN_SEASON_TITLE, Programs.COLUMN_SEASON_TITLE);
- // COLUMN_EPISODE_NUMBER is deprecated. Return COLUMN_EPISODE_DISPLAY_NUMBER instead.
- sProgramProjectionMap.put(
- Programs.COLUMN_EPISODE_NUMBER,
- Programs.COLUMN_EPISODE_DISPLAY_NUMBER + " AS " + Programs.COLUMN_EPISODE_NUMBER);
- sProgramProjectionMap.put(
- Programs.COLUMN_EPISODE_DISPLAY_NUMBER, Programs.COLUMN_EPISODE_DISPLAY_NUMBER);
- sProgramProjectionMap.put(Programs.COLUMN_EPISODE_TITLE, Programs.COLUMN_EPISODE_TITLE);
- sProgramProjectionMap.put(
- Programs.COLUMN_START_TIME_UTC_MILLIS, Programs.COLUMN_START_TIME_UTC_MILLIS);
- sProgramProjectionMap.put(
- Programs.COLUMN_END_TIME_UTC_MILLIS, Programs.COLUMN_END_TIME_UTC_MILLIS);
- sProgramProjectionMap.put(Programs.COLUMN_BROADCAST_GENRE, Programs.COLUMN_BROADCAST_GENRE);
- sProgramProjectionMap.put(Programs.COLUMN_CANONICAL_GENRE, Programs.COLUMN_CANONICAL_GENRE);
- sProgramProjectionMap.put(
- Programs.COLUMN_SHORT_DESCRIPTION, Programs.COLUMN_SHORT_DESCRIPTION);
- sProgramProjectionMap.put(
- Programs.COLUMN_LONG_DESCRIPTION, Programs.COLUMN_LONG_DESCRIPTION);
- sProgramProjectionMap.put(Programs.COLUMN_VIDEO_WIDTH, Programs.COLUMN_VIDEO_WIDTH);
- sProgramProjectionMap.put(Programs.COLUMN_VIDEO_HEIGHT, Programs.COLUMN_VIDEO_HEIGHT);
- sProgramProjectionMap.put(Programs.COLUMN_AUDIO_LANGUAGE, Programs.COLUMN_AUDIO_LANGUAGE);
- sProgramProjectionMap.put(Programs.COLUMN_CONTENT_RATING, Programs.COLUMN_CONTENT_RATING);
- sProgramProjectionMap.put(Programs.COLUMN_POSTER_ART_URI, Programs.COLUMN_POSTER_ART_URI);
- sProgramProjectionMap.put(Programs.COLUMN_THUMBNAIL_URI, Programs.COLUMN_THUMBNAIL_URI);
- sProgramProjectionMap.put(Programs.COLUMN_SEARCHABLE, Programs.COLUMN_SEARCHABLE);
- sProgramProjectionMap.put(
- Programs.COLUMN_RECORDING_PROHIBITED, Programs.COLUMN_RECORDING_PROHIBITED);
- sProgramProjectionMap.put(
- Programs.COLUMN_INTERNAL_PROVIDER_DATA, Programs.COLUMN_INTERNAL_PROVIDER_DATA);
- sProgramProjectionMap.put(
- Programs.COLUMN_INTERNAL_PROVIDER_FLAG1, Programs.COLUMN_INTERNAL_PROVIDER_FLAG1);
- sProgramProjectionMap.put(
- Programs.COLUMN_INTERNAL_PROVIDER_FLAG2, Programs.COLUMN_INTERNAL_PROVIDER_FLAG2);
- sProgramProjectionMap.put(
- Programs.COLUMN_INTERNAL_PROVIDER_FLAG3, Programs.COLUMN_INTERNAL_PROVIDER_FLAG3);
- sProgramProjectionMap.put(
- Programs.COLUMN_INTERNAL_PROVIDER_FLAG4, Programs.COLUMN_INTERNAL_PROVIDER_FLAG4);
- sProgramProjectionMap.put(Programs.COLUMN_VERSION_NUMBER, Programs.COLUMN_VERSION_NUMBER);
- sProgramProjectionMap.put(
- Programs.COLUMN_REVIEW_RATING_STYLE, Programs.COLUMN_REVIEW_RATING_STYLE);
- sProgramProjectionMap.put(Programs.COLUMN_REVIEW_RATING, Programs.COLUMN_REVIEW_RATING);
-
- sWatchedProgramProjectionMap = new HashMap<>();
- sWatchedProgramProjectionMap.put(WatchedPrograms._ID, WatchedPrograms._ID);
- sWatchedProgramProjectionMap.put(
- WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS,
- WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS);
- sWatchedProgramProjectionMap.put(
- WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS,
- WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS);
- sWatchedProgramProjectionMap.put(
- WatchedPrograms.COLUMN_CHANNEL_ID, WatchedPrograms.COLUMN_CHANNEL_ID);
- sWatchedProgramProjectionMap.put(
- WatchedPrograms.COLUMN_TITLE, WatchedPrograms.COLUMN_TITLE);
- sWatchedProgramProjectionMap.put(
- WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS,
- WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS);
- sWatchedProgramProjectionMap.put(
- WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS,
- WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS);
- sWatchedProgramProjectionMap.put(
- WatchedPrograms.COLUMN_DESCRIPTION, WatchedPrograms.COLUMN_DESCRIPTION);
- sWatchedProgramProjectionMap.put(
- WatchedPrograms.COLUMN_INTERNAL_TUNE_PARAMS,
- WatchedPrograms.COLUMN_INTERNAL_TUNE_PARAMS);
- sWatchedProgramProjectionMap.put(
- WatchedPrograms.COLUMN_INTERNAL_SESSION_TOKEN,
- WatchedPrograms.COLUMN_INTERNAL_SESSION_TOKEN);
- sWatchedProgramProjectionMap.put(
- WATCHED_PROGRAMS_COLUMN_CONSOLIDATED, WATCHED_PROGRAMS_COLUMN_CONSOLIDATED);
-
- sRecordedProgramProjectionMap = new HashMap<>();
- sRecordedProgramProjectionMap.put(RecordedPrograms._ID, RecordedPrograms._ID);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_PACKAGE_NAME, RecordedPrograms.COLUMN_PACKAGE_NAME);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_INPUT_ID, RecordedPrograms.COLUMN_INPUT_ID);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_CHANNEL_ID, RecordedPrograms.COLUMN_CHANNEL_ID);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_TITLE, RecordedPrograms.COLUMN_TITLE);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_SEASON_DISPLAY_NUMBER,
- RecordedPrograms.COLUMN_SEASON_DISPLAY_NUMBER);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_SEASON_TITLE, RecordedPrograms.COLUMN_SEASON_TITLE);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_EPISODE_DISPLAY_NUMBER,
- RecordedPrograms.COLUMN_EPISODE_DISPLAY_NUMBER);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_EPISODE_TITLE, RecordedPrograms.COLUMN_EPISODE_TITLE);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_START_TIME_UTC_MILLIS,
- RecordedPrograms.COLUMN_START_TIME_UTC_MILLIS);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_END_TIME_UTC_MILLIS,
- RecordedPrograms.COLUMN_END_TIME_UTC_MILLIS);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_BROADCAST_GENRE, RecordedPrograms.COLUMN_BROADCAST_GENRE);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_CANONICAL_GENRE, RecordedPrograms.COLUMN_CANONICAL_GENRE);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_SHORT_DESCRIPTION,
- RecordedPrograms.COLUMN_SHORT_DESCRIPTION);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_LONG_DESCRIPTION, RecordedPrograms.COLUMN_LONG_DESCRIPTION);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_VIDEO_WIDTH, RecordedPrograms.COLUMN_VIDEO_WIDTH);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_VIDEO_HEIGHT, RecordedPrograms.COLUMN_VIDEO_HEIGHT);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_AUDIO_LANGUAGE, RecordedPrograms.COLUMN_AUDIO_LANGUAGE);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_CONTENT_RATING, RecordedPrograms.COLUMN_CONTENT_RATING);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_POSTER_ART_URI, RecordedPrograms.COLUMN_POSTER_ART_URI);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_THUMBNAIL_URI, RecordedPrograms.COLUMN_THUMBNAIL_URI);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_SEARCHABLE, RecordedPrograms.COLUMN_SEARCHABLE);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_RECORDING_DATA_URI,
- RecordedPrograms.COLUMN_RECORDING_DATA_URI);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_RECORDING_DATA_BYTES,
- RecordedPrograms.COLUMN_RECORDING_DATA_BYTES);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS,
- RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS,
- RecordedPrograms.COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_INTERNAL_PROVIDER_DATA,
- RecordedPrograms.COLUMN_INTERNAL_PROVIDER_DATA);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1,
- RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2,
- RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3,
- RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4,
- RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_VERSION_NUMBER, RecordedPrograms.COLUMN_VERSION_NUMBER);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_REVIEW_RATING_STYLE,
- RecordedPrograms.COLUMN_REVIEW_RATING_STYLE);
- sRecordedProgramProjectionMap.put(
- RecordedPrograms.COLUMN_REVIEW_RATING, RecordedPrograms.COLUMN_REVIEW_RATING);
-
- sPreviewProgramProjectionMap = new HashMap<>();
- sPreviewProgramProjectionMap.put(PreviewPrograms._ID, PreviewPrograms._ID);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_PACKAGE_NAME, PreviewPrograms.COLUMN_PACKAGE_NAME);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_CHANNEL_ID, PreviewPrograms.COLUMN_CHANNEL_ID);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_TITLE, PreviewPrograms.COLUMN_TITLE);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_SEASON_DISPLAY_NUMBER,
- PreviewPrograms.COLUMN_SEASON_DISPLAY_NUMBER);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_SEASON_TITLE, PreviewPrograms.COLUMN_SEASON_TITLE);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_EPISODE_DISPLAY_NUMBER,
- PreviewPrograms.COLUMN_EPISODE_DISPLAY_NUMBER);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_EPISODE_TITLE, PreviewPrograms.COLUMN_EPISODE_TITLE);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_CANONICAL_GENRE, PreviewPrograms.COLUMN_CANONICAL_GENRE);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_SHORT_DESCRIPTION, PreviewPrograms.COLUMN_SHORT_DESCRIPTION);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_LONG_DESCRIPTION, PreviewPrograms.COLUMN_LONG_DESCRIPTION);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_VIDEO_WIDTH, PreviewPrograms.COLUMN_VIDEO_WIDTH);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_VIDEO_HEIGHT, PreviewPrograms.COLUMN_VIDEO_HEIGHT);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_AUDIO_LANGUAGE, PreviewPrograms.COLUMN_AUDIO_LANGUAGE);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_CONTENT_RATING, PreviewPrograms.COLUMN_CONTENT_RATING);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_POSTER_ART_URI, PreviewPrograms.COLUMN_POSTER_ART_URI);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_THUMBNAIL_URI, PreviewPrograms.COLUMN_THUMBNAIL_URI);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_SEARCHABLE, PreviewPrograms.COLUMN_SEARCHABLE);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_INTERNAL_PROVIDER_DATA,
- PreviewPrograms.COLUMN_INTERNAL_PROVIDER_DATA);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1,
- PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2,
- PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3,
- PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4,
- PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_VERSION_NUMBER, PreviewPrograms.COLUMN_VERSION_NUMBER);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_INTERNAL_PROVIDER_ID,
- PreviewPrograms.COLUMN_INTERNAL_PROVIDER_ID);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_PREVIEW_VIDEO_URI, PreviewPrograms.COLUMN_PREVIEW_VIDEO_URI);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS,
- PreviewPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_DURATION_MILLIS, PreviewPrograms.COLUMN_DURATION_MILLIS);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_INTENT_URI, PreviewPrograms.COLUMN_INTENT_URI);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_WEIGHT, PreviewPrograms.COLUMN_WEIGHT);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_TRANSIENT, PreviewPrograms.COLUMN_TRANSIENT);
- sPreviewProgramProjectionMap.put(PreviewPrograms.COLUMN_TYPE, PreviewPrograms.COLUMN_TYPE);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_POSTER_ART_ASPECT_RATIO,
- PreviewPrograms.COLUMN_POSTER_ART_ASPECT_RATIO);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO,
- PreviewPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_LOGO_URI, PreviewPrograms.COLUMN_LOGO_URI);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_AVAILABILITY, PreviewPrograms.COLUMN_AVAILABILITY);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_STARTING_PRICE, PreviewPrograms.COLUMN_STARTING_PRICE);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_OFFER_PRICE, PreviewPrograms.COLUMN_OFFER_PRICE);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_RELEASE_DATE, PreviewPrograms.COLUMN_RELEASE_DATE);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_ITEM_COUNT, PreviewPrograms.COLUMN_ITEM_COUNT);
- sPreviewProgramProjectionMap.put(PreviewPrograms.COLUMN_LIVE, PreviewPrograms.COLUMN_LIVE);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_INTERACTION_TYPE, PreviewPrograms.COLUMN_INTERACTION_TYPE);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_INTERACTION_COUNT, PreviewPrograms.COLUMN_INTERACTION_COUNT);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_AUTHOR, PreviewPrograms.COLUMN_AUTHOR);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_REVIEW_RATING_STYLE,
- PreviewPrograms.COLUMN_REVIEW_RATING_STYLE);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_REVIEW_RATING, PreviewPrograms.COLUMN_REVIEW_RATING);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_BROWSABLE, PreviewPrograms.COLUMN_BROWSABLE);
- sPreviewProgramProjectionMap.put(
- PreviewPrograms.COLUMN_CONTENT_ID, PreviewPrograms.COLUMN_CONTENT_ID);
-
- sWatchNextProgramProjectionMap = new HashMap<>();
- sWatchNextProgramProjectionMap.put(WatchNextPrograms._ID, WatchNextPrograms._ID);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_PACKAGE_NAME, WatchNextPrograms.COLUMN_PACKAGE_NAME);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_TITLE, WatchNextPrograms.COLUMN_TITLE);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_SEASON_DISPLAY_NUMBER,
- WatchNextPrograms.COLUMN_SEASON_DISPLAY_NUMBER);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_SEASON_TITLE, WatchNextPrograms.COLUMN_SEASON_TITLE);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_EPISODE_DISPLAY_NUMBER,
- WatchNextPrograms.COLUMN_EPISODE_DISPLAY_NUMBER);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_EPISODE_TITLE, WatchNextPrograms.COLUMN_EPISODE_TITLE);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_CANONICAL_GENRE, WatchNextPrograms.COLUMN_CANONICAL_GENRE);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_SHORT_DESCRIPTION,
- WatchNextPrograms.COLUMN_SHORT_DESCRIPTION);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_LONG_DESCRIPTION,
- WatchNextPrograms.COLUMN_LONG_DESCRIPTION);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_VIDEO_WIDTH, WatchNextPrograms.COLUMN_VIDEO_WIDTH);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_VIDEO_HEIGHT, WatchNextPrograms.COLUMN_VIDEO_HEIGHT);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_AUDIO_LANGUAGE, WatchNextPrograms.COLUMN_AUDIO_LANGUAGE);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_CONTENT_RATING, WatchNextPrograms.COLUMN_CONTENT_RATING);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_POSTER_ART_URI, WatchNextPrograms.COLUMN_POSTER_ART_URI);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_THUMBNAIL_URI, WatchNextPrograms.COLUMN_THUMBNAIL_URI);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_SEARCHABLE, WatchNextPrograms.COLUMN_SEARCHABLE);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_DATA,
- WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_DATA);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1,
- WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2,
- WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3,
- WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4,
- WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_VERSION_NUMBER, WatchNextPrograms.COLUMN_VERSION_NUMBER);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_ID,
- WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_ID);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_PREVIEW_VIDEO_URI,
- WatchNextPrograms.COLUMN_PREVIEW_VIDEO_URI);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS,
- WatchNextPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_DURATION_MILLIS, WatchNextPrograms.COLUMN_DURATION_MILLIS);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_INTENT_URI, WatchNextPrograms.COLUMN_INTENT_URI);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_TRANSIENT, WatchNextPrograms.COLUMN_TRANSIENT);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_TYPE, WatchNextPrograms.COLUMN_TYPE);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_WATCH_NEXT_TYPE, WatchNextPrograms.COLUMN_WATCH_NEXT_TYPE);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_POSTER_ART_ASPECT_RATIO,
- WatchNextPrograms.COLUMN_POSTER_ART_ASPECT_RATIO);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO,
- WatchNextPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_LOGO_URI, WatchNextPrograms.COLUMN_LOGO_URI);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_AVAILABILITY, WatchNextPrograms.COLUMN_AVAILABILITY);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_STARTING_PRICE, WatchNextPrograms.COLUMN_STARTING_PRICE);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_OFFER_PRICE, WatchNextPrograms.COLUMN_OFFER_PRICE);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_RELEASE_DATE, WatchNextPrograms.COLUMN_RELEASE_DATE);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_ITEM_COUNT, WatchNextPrograms.COLUMN_ITEM_COUNT);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_LIVE, WatchNextPrograms.COLUMN_LIVE);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_INTERACTION_TYPE,
- WatchNextPrograms.COLUMN_INTERACTION_TYPE);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_INTERACTION_COUNT,
- WatchNextPrograms.COLUMN_INTERACTION_COUNT);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_AUTHOR, WatchNextPrograms.COLUMN_AUTHOR);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_REVIEW_RATING_STYLE,
- WatchNextPrograms.COLUMN_REVIEW_RATING_STYLE);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_REVIEW_RATING, WatchNextPrograms.COLUMN_REVIEW_RATING);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_BROWSABLE, WatchNextPrograms.COLUMN_BROWSABLE);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_CONTENT_ID, WatchNextPrograms.COLUMN_CONTENT_ID);
- sWatchNextProgramProjectionMap.put(
- WatchNextPrograms.COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS,
- WatchNextPrograms.COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS);
- }
-
- // Mapping from broadcast genre to canonical genre.
- private static Map<String, String> sGenreMap;
-
- private static final String PERMISSION_READ_TV_LISTINGS = "android.permission.READ_TV_LISTINGS";
-
- private static final String PERMISSION_ACCESS_ALL_EPG_DATA =
- "com.android.providers.tv.permission.ACCESS_ALL_EPG_DATA";
-
- private static final String PERMISSION_ACCESS_WATCHED_PROGRAMS =
- "com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS";
-
- private static final String CREATE_RECORDED_PROGRAMS_TABLE_SQL =
- "CREATE TABLE "
- + RECORDED_PROGRAMS_TABLE
- + " ("
- + RecordedPrograms._ID
- + " INTEGER PRIMARY KEY AUTOINCREMENT,"
- + RecordedPrograms.COLUMN_PACKAGE_NAME
- + " TEXT NOT NULL,"
- + RecordedPrograms.COLUMN_INPUT_ID
- + " TEXT NOT NULL,"
- + RecordedPrograms.COLUMN_CHANNEL_ID
- + " INTEGER,"
- + RecordedPrograms.COLUMN_TITLE
- + " TEXT,"
- + RecordedPrograms.COLUMN_SEASON_DISPLAY_NUMBER
- + " TEXT,"
- + RecordedPrograms.COLUMN_SEASON_TITLE
- + " TEXT,"
- + RecordedPrograms.COLUMN_EPISODE_DISPLAY_NUMBER
- + " TEXT,"
- + RecordedPrograms.COLUMN_EPISODE_TITLE
- + " TEXT,"
- + RecordedPrograms.COLUMN_START_TIME_UTC_MILLIS
- + " INTEGER,"
- + RecordedPrograms.COLUMN_END_TIME_UTC_MILLIS
- + " INTEGER,"
- + RecordedPrograms.COLUMN_BROADCAST_GENRE
- + " TEXT,"
- + RecordedPrograms.COLUMN_CANONICAL_GENRE
- + " TEXT,"
- + RecordedPrograms.COLUMN_SHORT_DESCRIPTION
- + " TEXT,"
- + RecordedPrograms.COLUMN_LONG_DESCRIPTION
- + " TEXT,"
- + RecordedPrograms.COLUMN_VIDEO_WIDTH
- + " INTEGER,"
- + RecordedPrograms.COLUMN_VIDEO_HEIGHT
- + " INTEGER,"
- + RecordedPrograms.COLUMN_AUDIO_LANGUAGE
- + " TEXT,"
- + RecordedPrograms.COLUMN_CONTENT_RATING
- + " TEXT,"
- + RecordedPrograms.COLUMN_POSTER_ART_URI
- + " TEXT,"
- + RecordedPrograms.COLUMN_THUMBNAIL_URI
- + " TEXT,"
- + RecordedPrograms.COLUMN_SEARCHABLE
- + " INTEGER NOT NULL DEFAULT 1,"
- + RecordedPrograms.COLUMN_RECORDING_DATA_URI
- + " TEXT,"
- + RecordedPrograms.COLUMN_RECORDING_DATA_BYTES
- + " INTEGER,"
- + RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS
- + " INTEGER,"
- + RecordedPrograms.COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS
- + " INTEGER,"
- + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_DATA
- + " BLOB,"
- + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1
- + " INTEGER,"
- + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2
- + " INTEGER,"
- + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3
- + " INTEGER,"
- + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4
- + " INTEGER,"
- + RecordedPrograms.COLUMN_VERSION_NUMBER
- + " INTEGER,"
- + RecordedPrograms.COLUMN_REVIEW_RATING_STYLE
- + " INTEGER,"
- + RecordedPrograms.COLUMN_REVIEW_RATING
- + " TEXT,"
- + "FOREIGN KEY("
- + RecordedPrograms.COLUMN_CHANNEL_ID
- + ") "
- + "REFERENCES "
- + CHANNELS_TABLE
- + "("
- + Channels._ID
- + ") "
- + "ON UPDATE CASCADE ON DELETE SET NULL);";
-
- private static final String CREATE_PREVIEW_PROGRAMS_TABLE_SQL =
- "CREATE TABLE "
- + PREVIEW_PROGRAMS_TABLE
- + " ("
- + PreviewPrograms._ID
- + " INTEGER PRIMARY KEY AUTOINCREMENT,"
- + PreviewPrograms.COLUMN_PACKAGE_NAME
- + " TEXT NOT NULL,"
- + PreviewPrograms.COLUMN_CHANNEL_ID
- + " INTEGER,"
- + PreviewPrograms.COLUMN_TITLE
- + " TEXT,"
- + PreviewPrograms.COLUMN_SEASON_DISPLAY_NUMBER
- + " TEXT,"
- + PreviewPrograms.COLUMN_SEASON_TITLE
- + " TEXT,"
- + PreviewPrograms.COLUMN_EPISODE_DISPLAY_NUMBER
- + " TEXT,"
- + PreviewPrograms.COLUMN_EPISODE_TITLE
- + " TEXT,"
- + PreviewPrograms.COLUMN_CANONICAL_GENRE
- + " TEXT,"
- + PreviewPrograms.COLUMN_SHORT_DESCRIPTION
- + " TEXT,"
- + PreviewPrograms.COLUMN_LONG_DESCRIPTION
- + " TEXT,"
- + PreviewPrograms.COLUMN_VIDEO_WIDTH
- + " INTEGER,"
- + PreviewPrograms.COLUMN_VIDEO_HEIGHT
- + " INTEGER,"
- + PreviewPrograms.COLUMN_AUDIO_LANGUAGE
- + " TEXT,"
- + PreviewPrograms.COLUMN_CONTENT_RATING
- + " TEXT,"
- + PreviewPrograms.COLUMN_POSTER_ART_URI
- + " TEXT,"
- + PreviewPrograms.COLUMN_THUMBNAIL_URI
- + " TEXT,"
- + PreviewPrograms.COLUMN_SEARCHABLE
- + " INTEGER NOT NULL DEFAULT 1,"
- + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_DATA
- + " BLOB,"
- + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1
- + " INTEGER,"
- + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2
- + " INTEGER,"
- + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3
- + " INTEGER,"
- + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4
- + " INTEGER,"
- + PreviewPrograms.COLUMN_VERSION_NUMBER
- + " INTEGER,"
- + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_ID
- + " TEXT,"
- + PreviewPrograms.COLUMN_PREVIEW_VIDEO_URI
- + " TEXT,"
- + PreviewPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS
- + " INTEGER,"
- + PreviewPrograms.COLUMN_DURATION_MILLIS
- + " INTEGER,"
- + PreviewPrograms.COLUMN_INTENT_URI
- + " TEXT,"
- + PreviewPrograms.COLUMN_WEIGHT
- + " INTEGER,"
- + PreviewPrograms.COLUMN_TRANSIENT
- + " INTEGER NOT NULL DEFAULT 0,"
- + PreviewPrograms.COLUMN_TYPE
- + " INTEGER NOT NULL,"
- + PreviewPrograms.COLUMN_POSTER_ART_ASPECT_RATIO
- + " INTEGER,"
- + PreviewPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO
- + " INTEGER,"
- + PreviewPrograms.COLUMN_LOGO_URI
- + " TEXT,"
- + PreviewPrograms.COLUMN_AVAILABILITY
- + " INTERGER,"
- + PreviewPrograms.COLUMN_STARTING_PRICE
- + " TEXT,"
- + PreviewPrograms.COLUMN_OFFER_PRICE
- + " TEXT,"
- + PreviewPrograms.COLUMN_RELEASE_DATE
- + " TEXT,"
- + PreviewPrograms.COLUMN_ITEM_COUNT
- + " INTEGER,"
- + PreviewPrograms.COLUMN_LIVE
- + " INTEGER NOT NULL DEFAULT 0,"
- + PreviewPrograms.COLUMN_INTERACTION_TYPE
- + " INTEGER,"
- + PreviewPrograms.COLUMN_INTERACTION_COUNT
- + " INTEGER,"
- + PreviewPrograms.COLUMN_AUTHOR
- + " TEXT,"
- + PreviewPrograms.COLUMN_REVIEW_RATING_STYLE
- + " INTEGER,"
- + PreviewPrograms.COLUMN_REVIEW_RATING
- + " TEXT,"
- + PreviewPrograms.COLUMN_BROWSABLE
- + " INTEGER NOT NULL DEFAULT 1,"
- + PreviewPrograms.COLUMN_CONTENT_ID
- + " TEXT,"
- + "FOREIGN KEY("
- + PreviewPrograms.COLUMN_CHANNEL_ID
- + ","
- + PreviewPrograms.COLUMN_PACKAGE_NAME
- + ") REFERENCES "
- + CHANNELS_TABLE
- + "("
- + Channels._ID
- + ","
- + Channels.COLUMN_PACKAGE_NAME
- + ") ON UPDATE CASCADE ON DELETE CASCADE"
- + ");";
- private static final String CREATE_PREVIEW_PROGRAMS_PACKAGE_NAME_INDEX_SQL =
- "CREATE INDEX preview_programs_package_name_index ON "
- + PREVIEW_PROGRAMS_TABLE
- + "("
- + PreviewPrograms.COLUMN_PACKAGE_NAME
- + ");";
- private static final String CREATE_PREVIEW_PROGRAMS_CHANNEL_ID_INDEX_SQL =
- "CREATE INDEX preview_programs_id_index ON "
- + PREVIEW_PROGRAMS_TABLE
- + "("
- + PreviewPrograms.COLUMN_CHANNEL_ID
- + ");";
- private static final String CREATE_WATCH_NEXT_PROGRAMS_TABLE_SQL =
- "CREATE TABLE "
- + WATCH_NEXT_PROGRAMS_TABLE
- + " ("
- + WatchNextPrograms._ID
- + " INTEGER PRIMARY KEY AUTOINCREMENT,"
- + WatchNextPrograms.COLUMN_PACKAGE_NAME
- + " TEXT NOT NULL,"
- + WatchNextPrograms.COLUMN_TITLE
- + " TEXT,"
- + WatchNextPrograms.COLUMN_SEASON_DISPLAY_NUMBER
- + " TEXT,"
- + WatchNextPrograms.COLUMN_SEASON_TITLE
- + " TEXT,"
- + WatchNextPrograms.COLUMN_EPISODE_DISPLAY_NUMBER
- + " TEXT,"
- + WatchNextPrograms.COLUMN_EPISODE_TITLE
- + " TEXT,"
- + WatchNextPrograms.COLUMN_CANONICAL_GENRE
- + " TEXT,"
- + WatchNextPrograms.COLUMN_SHORT_DESCRIPTION
- + " TEXT,"
- + WatchNextPrograms.COLUMN_LONG_DESCRIPTION
- + " TEXT,"
- + WatchNextPrograms.COLUMN_VIDEO_WIDTH
- + " INTEGER,"
- + WatchNextPrograms.COLUMN_VIDEO_HEIGHT
- + " INTEGER,"
- + WatchNextPrograms.COLUMN_AUDIO_LANGUAGE
- + " TEXT,"
- + WatchNextPrograms.COLUMN_CONTENT_RATING
- + " TEXT,"
- + WatchNextPrograms.COLUMN_POSTER_ART_URI
- + " TEXT,"
- + WatchNextPrograms.COLUMN_THUMBNAIL_URI
- + " TEXT,"
- + WatchNextPrograms.COLUMN_SEARCHABLE
- + " INTEGER NOT NULL DEFAULT 1,"
- + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_DATA
- + " BLOB,"
- + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1
- + " INTEGER,"
- + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2
- + " INTEGER,"
- + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3
- + " INTEGER,"
- + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4
- + " INTEGER,"
- + WatchNextPrograms.COLUMN_VERSION_NUMBER
- + " INTEGER,"
- + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_ID
- + " TEXT,"
- + WatchNextPrograms.COLUMN_PREVIEW_VIDEO_URI
- + " TEXT,"
- + WatchNextPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS
- + " INTEGER,"
- + WatchNextPrograms.COLUMN_DURATION_MILLIS
- + " INTEGER,"
- + WatchNextPrograms.COLUMN_INTENT_URI
- + " TEXT,"
- + WatchNextPrograms.COLUMN_TRANSIENT
- + " INTEGER NOT NULL DEFAULT 0,"
- + WatchNextPrograms.COLUMN_TYPE
- + " INTEGER NOT NULL,"
- + WatchNextPrograms.COLUMN_WATCH_NEXT_TYPE
- + " INTEGER,"
- + WatchNextPrograms.COLUMN_POSTER_ART_ASPECT_RATIO
- + " INTEGER,"
- + WatchNextPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO
- + " INTEGER,"
- + WatchNextPrograms.COLUMN_LOGO_URI
- + " TEXT,"
- + WatchNextPrograms.COLUMN_AVAILABILITY
- + " INTEGER,"
- + WatchNextPrograms.COLUMN_STARTING_PRICE
- + " TEXT,"
- + WatchNextPrograms.COLUMN_OFFER_PRICE
- + " TEXT,"
- + WatchNextPrograms.COLUMN_RELEASE_DATE
- + " TEXT,"
- + WatchNextPrograms.COLUMN_ITEM_COUNT
- + " INTEGER,"
- + WatchNextPrograms.COLUMN_LIVE
- + " INTEGER NOT NULL DEFAULT 0,"
- + WatchNextPrograms.COLUMN_INTERACTION_TYPE
- + " INTEGER,"
- + WatchNextPrograms.COLUMN_INTERACTION_COUNT
- + " INTEGER,"
- + WatchNextPrograms.COLUMN_AUTHOR
- + " TEXT,"
- + WatchNextPrograms.COLUMN_REVIEW_RATING_STYLE
- + " INTEGER,"
- + WatchNextPrograms.COLUMN_REVIEW_RATING
- + " TEXT,"
- + WatchNextPrograms.COLUMN_BROWSABLE
- + " INTEGER NOT NULL DEFAULT 1,"
- + WatchNextPrograms.COLUMN_CONTENT_ID
- + " TEXT,"
- + WatchNextPrograms.COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS
- + " INTEGER"
- + ");";
- private static final String CREATE_WATCH_NEXT_PROGRAMS_PACKAGE_NAME_INDEX_SQL =
- "CREATE INDEX watch_next_programs_package_name_index ON "
- + WATCH_NEXT_PROGRAMS_TABLE
- + "("
- + WatchNextPrograms.COLUMN_PACKAGE_NAME
- + ");";
-
- private String mCallingPackage = "com.android.tv";
-
- static class DatabaseHelper extends SQLiteOpenHelper {
- private Context mContext;
-
- public static synchronized DatabaseHelper createInstance(Context context) {
- return new DatabaseHelper(context);
- }
-
- private DatabaseHelper(Context context) {
- this(context, DATABASE_NAME, DATABASE_VERSION);
- }
-
- @VisibleForTesting
- DatabaseHelper(Context context, String databaseName, int databaseVersion) {
- super(context, databaseName, null, databaseVersion);
- mContext = context;
- }
-
- @Override
- public void onConfigure(SQLiteDatabase db) {
- db.setForeignKeyConstraintsEnabled(true);
- }
-
- @Override
- public void onCreate(SQLiteDatabase db) {
- if (DEBUG) {
- Log.d(TAG, "Creating database");
- }
- // Set up the database schema.
- db.execSQL(
- "CREATE TABLE "
- + CHANNELS_TABLE
- + " ("
- + Channels._ID
- + " INTEGER PRIMARY KEY AUTOINCREMENT,"
- + Channels.COLUMN_PACKAGE_NAME
- + " TEXT NOT NULL,"
- + Channels.COLUMN_INPUT_ID
- + " TEXT NOT NULL,"
- + Channels.COLUMN_TYPE
- + " TEXT NOT NULL DEFAULT '"
- + Channels.TYPE_OTHER
- + "',"
- + Channels.COLUMN_SERVICE_TYPE
- + " TEXT NOT NULL DEFAULT '"
- + Channels.SERVICE_TYPE_AUDIO_VIDEO
- + "',"
- + Channels.COLUMN_ORIGINAL_NETWORK_ID
- + " INTEGER NOT NULL DEFAULT 0,"
- + Channels.COLUMN_TRANSPORT_STREAM_ID
- + " INTEGER NOT NULL DEFAULT 0,"
- + Channels.COLUMN_SERVICE_ID
- + " INTEGER NOT NULL DEFAULT 0,"
- + Channels.COLUMN_DISPLAY_NUMBER
- + " TEXT,"
- + Channels.COLUMN_DISPLAY_NAME
- + " TEXT,"
- + Channels.COLUMN_NETWORK_AFFILIATION
- + " TEXT,"
- + Channels.COLUMN_DESCRIPTION
- + " TEXT,"
- + Channels.COLUMN_VIDEO_FORMAT
- + " TEXT,"
- + Channels.COLUMN_BROWSABLE
- + " INTEGER NOT NULL DEFAULT 0,"
- + Channels.COLUMN_SEARCHABLE
- + " INTEGER NOT NULL DEFAULT 1,"
- + Channels.COLUMN_LOCKED
- + " INTEGER NOT NULL DEFAULT 0,"
- + Channels.COLUMN_APP_LINK_ICON_URI
- + " TEXT,"
- + Channels.COLUMN_APP_LINK_POSTER_ART_URI
- + " TEXT,"
- + Channels.COLUMN_APP_LINK_TEXT
- + " TEXT,"
- + Channels.COLUMN_APP_LINK_COLOR
- + " INTEGER,"
- + Channels.COLUMN_APP_LINK_INTENT_URI
- + " TEXT,"
- + Channels.COLUMN_INTERNAL_PROVIDER_DATA
- + " BLOB,"
- + Channels.COLUMN_INTERNAL_PROVIDER_FLAG1
- + " INTEGER,"
- + Channels.COLUMN_INTERNAL_PROVIDER_FLAG2
- + " INTEGER,"
- + Channels.COLUMN_INTERNAL_PROVIDER_FLAG3
- + " INTEGER,"
- + Channels.COLUMN_INTERNAL_PROVIDER_FLAG4
- + " INTEGER,"
- + CHANNELS_COLUMN_LOGO
- + " BLOB,"
- + Channels.COLUMN_VERSION_NUMBER
- + " INTEGER,"
- + Channels.COLUMN_TRANSIENT
- + " INTEGER NOT NULL DEFAULT 0,"
- + Channels.COLUMN_INTERNAL_PROVIDER_ID
- + " TEXT,"
- // Needed for foreign keys in other tables.
- + "UNIQUE("
- + Channels._ID
- + ","
- + Channels.COLUMN_PACKAGE_NAME
- + ")"
- + ");");
- db.execSQL(
- "CREATE TABLE "
- + PROGRAMS_TABLE
- + " ("
- + Programs._ID
- + " INTEGER PRIMARY KEY AUTOINCREMENT,"
- + Programs.COLUMN_PACKAGE_NAME
- + " TEXT NOT NULL,"
- + Programs.COLUMN_CHANNEL_ID
- + " INTEGER,"
- + Programs.COLUMN_TITLE
- + " TEXT,"
- + Programs.COLUMN_SEASON_DISPLAY_NUMBER
- + " TEXT,"
- + Programs.COLUMN_SEASON_TITLE
- + " TEXT,"
- + Programs.COLUMN_EPISODE_DISPLAY_NUMBER
- + " TEXT,"
- + Programs.COLUMN_EPISODE_TITLE
- + " TEXT,"
- + Programs.COLUMN_START_TIME_UTC_MILLIS
- + " INTEGER,"
- + Programs.COLUMN_END_TIME_UTC_MILLIS
- + " INTEGER,"
- + Programs.COLUMN_BROADCAST_GENRE
- + " TEXT,"
- + Programs.COLUMN_CANONICAL_GENRE
- + " TEXT,"
- + Programs.COLUMN_SHORT_DESCRIPTION
- + " TEXT,"
- + Programs.COLUMN_LONG_DESCRIPTION
- + " TEXT,"
- + Programs.COLUMN_VIDEO_WIDTH
- + " INTEGER,"
- + Programs.COLUMN_VIDEO_HEIGHT
- + " INTEGER,"
- + Programs.COLUMN_AUDIO_LANGUAGE
- + " TEXT,"
- + Programs.COLUMN_CONTENT_RATING
- + " TEXT,"
- + Programs.COLUMN_POSTER_ART_URI
- + " TEXT,"
- + Programs.COLUMN_THUMBNAIL_URI
- + " TEXT,"
- + Programs.COLUMN_SEARCHABLE
- + " INTEGER NOT NULL DEFAULT 1,"
- + Programs.COLUMN_RECORDING_PROHIBITED
- + " INTEGER NOT NULL DEFAULT 0,"
- + Programs.COLUMN_INTERNAL_PROVIDER_DATA
- + " BLOB,"
- + Programs.COLUMN_INTERNAL_PROVIDER_FLAG1
- + " INTEGER,"
- + Programs.COLUMN_INTERNAL_PROVIDER_FLAG2
- + " INTEGER,"
- + Programs.COLUMN_INTERNAL_PROVIDER_FLAG3
- + " INTEGER,"
- + Programs.COLUMN_INTERNAL_PROVIDER_FLAG4
- + " INTEGER,"
- + Programs.COLUMN_REVIEW_RATING_STYLE
- + " INTEGER,"
- + Programs.COLUMN_REVIEW_RATING
- + " TEXT,"
- + Programs.COLUMN_VERSION_NUMBER
- + " INTEGER,"
- + "FOREIGN KEY("
- + Programs.COLUMN_CHANNEL_ID
- + ","
- + Programs.COLUMN_PACKAGE_NAME
- + ") REFERENCES "
- + CHANNELS_TABLE
- + "("
- + Channels._ID
- + ","
- + Channels.COLUMN_PACKAGE_NAME
- + ") ON UPDATE CASCADE ON DELETE CASCADE"
- + ");");
- db.execSQL(
- "CREATE INDEX "
- + PROGRAMS_TABLE_PACKAGE_NAME_INDEX
- + " ON "
- + PROGRAMS_TABLE
- + "("
- + Programs.COLUMN_PACKAGE_NAME
- + ");");
- db.execSQL(
- "CREATE INDEX "
- + PROGRAMS_TABLE_CHANNEL_ID_INDEX
- + " ON "
- + PROGRAMS_TABLE
- + "("
- + Programs.COLUMN_CHANNEL_ID
- + ");");
- db.execSQL(
- "CREATE INDEX "
- + PROGRAMS_TABLE_START_TIME_INDEX
- + " ON "
- + PROGRAMS_TABLE
- + "("
- + Programs.COLUMN_START_TIME_UTC_MILLIS
- + ");");
- db.execSQL(
- "CREATE INDEX "
- + PROGRAMS_TABLE_END_TIME_INDEX
- + " ON "
- + PROGRAMS_TABLE
- + "("
- + Programs.COLUMN_END_TIME_UTC_MILLIS
- + ");");
- db.execSQL(
- "CREATE TABLE "
- + WATCHED_PROGRAMS_TABLE
- + " ("
- + WatchedPrograms._ID
- + " INTEGER PRIMARY KEY AUTOINCREMENT,"
- + WatchedPrograms.COLUMN_PACKAGE_NAME
- + " TEXT NOT NULL,"
- + WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS
- + " INTEGER NOT NULL DEFAULT 0,"
- + WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS
- + " INTEGER NOT NULL DEFAULT 0,"
- + WatchedPrograms.COLUMN_CHANNEL_ID
- + " INTEGER,"
- + WatchedPrograms.COLUMN_TITLE
- + " TEXT,"
- + WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS
- + " INTEGER,"
- + WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS
- + " INTEGER,"
- + WatchedPrograms.COLUMN_DESCRIPTION
- + " TEXT,"
- + WatchedPrograms.COLUMN_INTERNAL_TUNE_PARAMS
- + " TEXT,"
- + WatchedPrograms.COLUMN_INTERNAL_SESSION_TOKEN
- + " TEXT NOT NULL,"
- + WATCHED_PROGRAMS_COLUMN_CONSOLIDATED
- + " INTEGER NOT NULL DEFAULT 0,"
- + "FOREIGN KEY("
- + WatchedPrograms.COLUMN_CHANNEL_ID
- + ","
- + WatchedPrograms.COLUMN_PACKAGE_NAME
- + ") REFERENCES "
- + CHANNELS_TABLE
- + "("
- + Channels._ID
- + ","
- + Channels.COLUMN_PACKAGE_NAME
- + ") ON UPDATE CASCADE ON DELETE CASCADE"
- + ");");
- db.execSQL(
- "CREATE INDEX "
- + WATCHED_PROGRAMS_TABLE_CHANNEL_ID_INDEX
- + " ON "
- + WATCHED_PROGRAMS_TABLE
- + "("
- + WatchedPrograms.COLUMN_CHANNEL_ID
- + ");");
- db.execSQL(CREATE_RECORDED_PROGRAMS_TABLE_SQL);
- db.execSQL(CREATE_PREVIEW_PROGRAMS_TABLE_SQL);
- db.execSQL(CREATE_PREVIEW_PROGRAMS_PACKAGE_NAME_INDEX_SQL);
- db.execSQL(CREATE_PREVIEW_PROGRAMS_CHANNEL_ID_INDEX_SQL);
- db.execSQL(CREATE_WATCH_NEXT_PROGRAMS_TABLE_SQL);
- db.execSQL(CREATE_WATCH_NEXT_PROGRAMS_PACKAGE_NAME_INDEX_SQL);
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- if (oldVersion < 23) {
- Log.i(
- TAG,
- "Upgrading from version "
- + oldVersion
- + " to "
- + newVersion
- + ", data will be lost!");
- db.execSQL("DROP TABLE IF EXISTS " + DELETED_CHANNELS_TABLE);
- db.execSQL("DROP TABLE IF EXISTS " + WATCHED_PROGRAMS_TABLE);
- db.execSQL("DROP TABLE IF EXISTS " + PROGRAMS_TABLE);
- db.execSQL("DROP TABLE IF EXISTS " + CHANNELS_TABLE);
-
- onCreate(db);
- return;
- }
-
- Log.i(TAG, "Upgrading from version " + oldVersion + " to " + newVersion + ".");
- if (oldVersion <= 23) {
- db.execSQL(
- "ALTER TABLE "
- + CHANNELS_TABLE
- + " ADD "
- + Channels.COLUMN_INTERNAL_PROVIDER_FLAG1
- + " INTEGER;");
- db.execSQL(
- "ALTER TABLE "
- + CHANNELS_TABLE
- + " ADD "
- + Channels.COLUMN_INTERNAL_PROVIDER_FLAG2
- + " INTEGER;");
- db.execSQL(
- "ALTER TABLE "
- + CHANNELS_TABLE
- + " ADD "
- + Channels.COLUMN_INTERNAL_PROVIDER_FLAG3
- + " INTEGER;");
- db.execSQL(
- "ALTER TABLE "
- + CHANNELS_TABLE
- + " ADD "
- + Channels.COLUMN_INTERNAL_PROVIDER_FLAG4
- + " INTEGER;");
- }
- if (oldVersion <= 24) {
- db.execSQL(
- "ALTER TABLE "
- + PROGRAMS_TABLE
- + " ADD "
- + Programs.COLUMN_INTERNAL_PROVIDER_FLAG1
- + " INTEGER;");
- db.execSQL(
- "ALTER TABLE "
- + PROGRAMS_TABLE
- + " ADD "
- + Programs.COLUMN_INTERNAL_PROVIDER_FLAG2
- + " INTEGER;");
- db.execSQL(
- "ALTER TABLE "
- + PROGRAMS_TABLE
- + " ADD "
- + Programs.COLUMN_INTERNAL_PROVIDER_FLAG3
- + " INTEGER;");
- db.execSQL(
- "ALTER TABLE "
- + PROGRAMS_TABLE
- + " ADD "
- + Programs.COLUMN_INTERNAL_PROVIDER_FLAG4
- + " INTEGER;");
- }
- if (oldVersion <= 25) {
- db.execSQL(
- "ALTER TABLE "
- + CHANNELS_TABLE
- + " ADD "
- + Channels.COLUMN_APP_LINK_ICON_URI
- + " TEXT;");
- db.execSQL(
- "ALTER TABLE "
- + CHANNELS_TABLE
- + " ADD "
- + Channels.COLUMN_APP_LINK_POSTER_ART_URI
- + " TEXT;");
- db.execSQL(
- "ALTER TABLE "
- + CHANNELS_TABLE
- + " ADD "
- + Channels.COLUMN_APP_LINK_TEXT
- + " TEXT;");
- db.execSQL(
- "ALTER TABLE "
- + CHANNELS_TABLE
- + " ADD "
- + Channels.COLUMN_APP_LINK_COLOR
- + " INTEGER;");
- db.execSQL(
- "ALTER TABLE "
- + CHANNELS_TABLE
- + " ADD "
- + Channels.COLUMN_APP_LINK_INTENT_URI
- + " TEXT;");
- db.execSQL(
- "ALTER TABLE "
- + PROGRAMS_TABLE
- + " ADD "
- + Programs.COLUMN_SEARCHABLE
- + " INTEGER NOT NULL DEFAULT 1;");
- }
- if (oldVersion <= 28) {
- db.execSQL(
- "ALTER TABLE "
- + PROGRAMS_TABLE
- + " ADD "
- + Programs.COLUMN_SEASON_TITLE
- + " TEXT;");
- migrateIntegerColumnToTextColumn(
- db,
- PROGRAMS_TABLE,
- Programs.COLUMN_SEASON_NUMBER,
- Programs.COLUMN_SEASON_DISPLAY_NUMBER);
- migrateIntegerColumnToTextColumn(
- db,
- PROGRAMS_TABLE,
- Programs.COLUMN_EPISODE_NUMBER,
- Programs.COLUMN_EPISODE_DISPLAY_NUMBER);
- }
- if (oldVersion <= 29) {
- db.execSQL("DROP TABLE IF EXISTS " + RECORDED_PROGRAMS_TABLE);
- db.execSQL(CREATE_RECORDED_PROGRAMS_TABLE_SQL);
- }
- if (oldVersion <= 30) {
- db.execSQL(
- "ALTER TABLE "
- + PROGRAMS_TABLE
- + " ADD "
- + Programs.COLUMN_RECORDING_PROHIBITED
- + " INTEGER NOT NULL DEFAULT 0;");
- }
- if (oldVersion <= 32) {
- db.execSQL(
- "ALTER TABLE "
- + CHANNELS_TABLE
- + " ADD "
- + Channels.COLUMN_TRANSIENT
- + " INTEGER NOT NULL DEFAULT 0;");
- db.execSQL(
- "ALTER TABLE "
- + CHANNELS_TABLE
- + " ADD "
- + Channels.COLUMN_INTERNAL_PROVIDER_ID
- + " TEXT;");
- db.execSQL(
- "ALTER TABLE "
- + PROGRAMS_TABLE
- + " ADD "
- + Programs.COLUMN_REVIEW_RATING_STYLE
- + " INTEGER;");
- db.execSQL(
- "ALTER TABLE "
- + PROGRAMS_TABLE
- + " ADD "
- + Programs.COLUMN_REVIEW_RATING
- + " TEXT;");
- if (oldVersion > 29) {
- db.execSQL(
- "ALTER TABLE "
- + RECORDED_PROGRAMS_TABLE
- + " ADD "
- + RecordedPrograms.COLUMN_REVIEW_RATING_STYLE
- + " INTEGER;");
- db.execSQL(
- "ALTER TABLE "
- + RECORDED_PROGRAMS_TABLE
- + " ADD "
- + RecordedPrograms.COLUMN_REVIEW_RATING
- + " TEXT;");
- }
- }
- if (oldVersion <= 33) {
- db.execSQL("DROP TABLE IF EXISTS " + PREVIEW_PROGRAMS_TABLE);
- db.execSQL("DROP TABLE IF EXISTS " + WATCH_NEXT_PROGRAMS_TABLE);
- db.execSQL(CREATE_PREVIEW_PROGRAMS_TABLE_SQL);
- db.execSQL(CREATE_PREVIEW_PROGRAMS_PACKAGE_NAME_INDEX_SQL);
- db.execSQL(CREATE_PREVIEW_PROGRAMS_CHANNEL_ID_INDEX_SQL);
- db.execSQL(CREATE_WATCH_NEXT_PROGRAMS_TABLE_SQL);
- db.execSQL(CREATE_WATCH_NEXT_PROGRAMS_PACKAGE_NAME_INDEX_SQL);
- }
- Log.i(TAG, "Upgrading from version " + oldVersion + " to " + newVersion + " is done.");
- }
-
- @Override
- public void onOpen(SQLiteDatabase db) {
- // Call a static method on the TvProvider because changes to sInitialized must
- // be guarded by a lock on the class.
- initOnOpenIfNeeded(mContext, db);
- }
-
- private static void migrateIntegerColumnToTextColumn(
- SQLiteDatabase db, String table, String integerColumn, String textColumn) {
- db.execSQL("ALTER TABLE " + table + " ADD " + textColumn + " TEXT;");
- db.execSQL(
- "UPDATE "
- + table
- + " SET "
- + textColumn
- + " = CAST("
- + integerColumn
- + " AS TEXT);");
- }
- }
-
- private DatabaseHelper mOpenHelper;
- private static SharedPreferences sBlockedPackagesSharedPreference;
- private static Map<String, Boolean> sBlockedPackages;
-
- @Override
- public boolean onCreate() {
- if (DEBUG) {
- Log.d(TAG, "Creating TvProvider");
- }
- mOpenHelper = DatabaseHelper.createInstance(getContext());
- return true;
- }
-
- @VisibleForTesting
- String getCallingPackage_() {
- return mCallingPackage;
- }
-
- public void setCallingPackage(String packageName) {
- mCallingPackage = packageName;
- }
-
- void setOpenHelper(DatabaseHelper helper) {
- mOpenHelper = helper;
- }
-
- @Override
- public String getType(Uri uri) {
- switch (sUriMatcher.match(uri)) {
- case MATCH_CHANNEL:
- return Channels.CONTENT_TYPE;
- case MATCH_CHANNEL_ID:
- return Channels.CONTENT_ITEM_TYPE;
- case MATCH_CHANNEL_ID_LOGO:
- return "image/png";
- case MATCH_PASSTHROUGH_ID:
- return Channels.CONTENT_ITEM_TYPE;
- case MATCH_PROGRAM:
- return Programs.CONTENT_TYPE;
- case MATCH_PROGRAM_ID:
- return Programs.CONTENT_ITEM_TYPE;
- case MATCH_WATCHED_PROGRAM:
- return WatchedPrograms.CONTENT_TYPE;
- case MATCH_WATCHED_PROGRAM_ID:
- return WatchedPrograms.CONTENT_ITEM_TYPE;
- case MATCH_RECORDED_PROGRAM:
- return RecordedPrograms.CONTENT_TYPE;
- case MATCH_RECORDED_PROGRAM_ID:
- return RecordedPrograms.CONTENT_ITEM_TYPE;
- case MATCH_PREVIEW_PROGRAM:
- return PreviewPrograms.CONTENT_TYPE;
- case MATCH_PREVIEW_PROGRAM_ID:
- return PreviewPrograms.CONTENT_ITEM_TYPE;
- case MATCH_WATCH_NEXT_PROGRAM:
- return WatchNextPrograms.CONTENT_TYPE;
- case MATCH_WATCH_NEXT_PROGRAM_ID:
- return WatchNextPrograms.CONTENT_ITEM_TYPE;
- default:
- throw new IllegalArgumentException("Unknown URI " + uri);
- }
- }
-
- @Override
- public Bundle call(String method, String arg, Bundle extras) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Cursor query(
- Uri uri,
- String[] projection,
- String selection,
- String[] selectionArgs,
- String sortOrder) {
- ensureInitialized();
- boolean needsToValidateSortOrder = !callerHasAccessAllEpgDataPermission();
- SqlParams params = createSqlParams(OP_QUERY, uri, selection, selectionArgs);
-
- SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
- queryBuilder.setStrict(needsToValidateSortOrder);
- queryBuilder.setTables(params.getTables());
- String orderBy = null;
- Map<String, String> projectionMap;
- switch (params.getTables()) {
- case PROGRAMS_TABLE:
- projectionMap = sProgramProjectionMap;
- orderBy = DEFAULT_PROGRAMS_SORT_ORDER;
- break;
- case WATCHED_PROGRAMS_TABLE:
- projectionMap = sWatchedProgramProjectionMap;
- orderBy = DEFAULT_WATCHED_PROGRAMS_SORT_ORDER;
- break;
- case RECORDED_PROGRAMS_TABLE:
- projectionMap = sRecordedProgramProjectionMap;
- break;
- case PREVIEW_PROGRAMS_TABLE:
- projectionMap = sPreviewProgramProjectionMap;
- break;
- case WATCH_NEXT_PROGRAMS_TABLE:
- projectionMap = sWatchNextProgramProjectionMap;
- break;
- default:
- projectionMap = sChannelProjectionMap;
- break;
- }
- queryBuilder.setProjectionMap(createProjectionMapForQuery(projection, projectionMap));
- if (needsToValidateSortOrder) {
- validateSortOrder(sortOrder, projectionMap.keySet());
- }
-
- // Use the default sort order only if no sort order is specified.
- if (!TextUtils.isEmpty(sortOrder)) {
- orderBy = sortOrder;
- }
-
- // Get the database and run the query.
- SQLiteDatabase db = mOpenHelper.getReadableDatabase();
- Cursor c =
- queryBuilder.query(
- db,
- projection,
- params.getSelection(),
- params.getSelectionArgs(),
- null,
- null,
- orderBy);
-
- // Tell the cursor what URI to watch, so it knows when its source data changes.
- c.setNotificationUri(getContext().getContentResolver(), uri);
- return c;
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- ensureInitialized();
- switch (sUriMatcher.match(uri)) {
- case MATCH_CHANNEL:
- // Preview channels are not necessarily associated with TV input service.
- // Therefore, we fill a fake ID to meet not null restriction for preview channels.
- if (values.get(Channels.COLUMN_INPUT_ID) == null
- && TvContractCompat.PARAM_CHANNEL.equals(
- values.get(Channels.COLUMN_TYPE))) {
- values.put(Channels.COLUMN_INPUT_ID, EMPTY_STRING);
- }
- filterContentValues(values, sChannelProjectionMap);
- return insertChannel(uri, values);
- case MATCH_PROGRAM:
- filterContentValues(values, sProgramProjectionMap);
- return insertProgram(uri, values);
- case MATCH_WATCHED_PROGRAM:
- return insertWatchedProgram(uri, values);
- case MATCH_RECORDED_PROGRAM:
- filterContentValues(values, sRecordedProgramProjectionMap);
- return insertRecordedProgram(uri, values);
- case MATCH_PREVIEW_PROGRAM:
- filterContentValues(values, sPreviewProgramProjectionMap);
- return insertPreviewProgram(uri, values);
- case MATCH_WATCH_NEXT_PROGRAM:
- filterContentValues(values, sWatchNextProgramProjectionMap);
- return insertWatchNextProgram(uri, values);
- case MATCH_CHANNEL_ID:
- case MATCH_CHANNEL_ID_LOGO:
- case MATCH_PASSTHROUGH_ID:
- case MATCH_PROGRAM_ID:
- case MATCH_WATCHED_PROGRAM_ID:
- case MATCH_RECORDED_PROGRAM_ID:
- case MATCH_PREVIEW_PROGRAM_ID:
- throw new UnsupportedOperationException("Cannot insert into that URI: " + uri);
- default:
- throw new IllegalArgumentException("Unknown URI " + uri);
- }
- }
-
- private Uri insertChannel(Uri uri, ContentValues values) {
- if (TextUtils.equals(
- values.getAsString(Channels.COLUMN_TYPE), TvContractCompat.Channels.TYPE_PREVIEW)) {
- blockIllegalAccessFromBlockedPackage();
- }
- // Mark the owner package of this channel.
- values.put(Channels.COLUMN_PACKAGE_NAME, getCallingPackage_());
- blockIllegalAccessToChannelsSystemColumns(values);
-
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- long rowId = db.insert(CHANNELS_TABLE, null, values);
- if (rowId > 0) {
- Uri channelUri = TvContractCompat.buildChannelUri(rowId);
- notifyChange(channelUri);
- return channelUri;
- }
-
- throw new SQLException("Failed to insert row into " + uri);
- }
-
- private Uri insertProgram(Uri uri, ContentValues values) {
- if (!callerHasAccessAllEpgDataPermission()
- || !values.containsKey(Programs.COLUMN_PACKAGE_NAME)) {
- // Mark the owner package of this program. System app with a proper permission may
- // change the owner of the program.
- values.put(Programs.COLUMN_PACKAGE_NAME, getCallingPackage_());
- }
-
- checkAndConvertGenre(values);
- checkAndConvertDeprecatedColumns(values);
-
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- long rowId = db.insert(PROGRAMS_TABLE, null, values);
- if (rowId > 0) {
- Uri programUri = TvContractCompat.buildProgramUri(rowId);
- notifyChange(programUri);
- return programUri;
- }
-
- throw new SQLException("Failed to insert row into " + uri);
- }
-
- private Uri insertWatchedProgram(Uri uri, ContentValues values) {
- if (DEBUG) {
- Log.d(TAG, "insertWatchedProgram(uri=" + uri + ", values={" + values + "})");
- }
- Long watchStartTime = values.getAsLong(WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS);
- Long watchEndTime = values.getAsLong(WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS);
- // The system sends only two kinds of watch events:
- // 1. The user tunes to a new channel. (COLUMN_WATCH_START_TIME_UTC_MILLIS)
- // 2. The user stops watching. (COLUMN_WATCH_END_TIME_UTC_MILLIS)
- if (watchStartTime != null && watchEndTime == null) {
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- long rowId = db.insert(WATCHED_PROGRAMS_TABLE, null, values);
- if (rowId > 0) {
- return ContentUris.withAppendedId(WatchedPrograms.CONTENT_URI, rowId);
- }
- Log.w(TAG, "Failed to insert row for " + values + ". Channel does not exist.");
- return null;
- } else if (watchStartTime == null && watchEndTime != null) {
- return null;
- }
- // All the other cases are invalid.
- throw new IllegalArgumentException(
- "Only one of COLUMN_WATCH_START_TIME_UTC_MILLIS and"
- + " COLUMN_WATCH_END_TIME_UTC_MILLIS should be specified");
- }
-
- private Uri insertRecordedProgram(Uri uri, ContentValues values) {
- // Mark the owner package of this program.
- values.put(Programs.COLUMN_PACKAGE_NAME, getCallingPackage_());
-
- checkAndConvertGenre(values);
-
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- long rowId = db.insert(RECORDED_PROGRAMS_TABLE, null, values);
- if (rowId > 0) {
- Uri recordedProgramUri = TvContractCompat.buildRecordedProgramUri(rowId);
- notifyChange(recordedProgramUri);
- return recordedProgramUri;
- }
-
- throw new SQLException("Failed to insert row into " + uri);
- }
-
- private Uri insertPreviewProgram(Uri uri, ContentValues values) {
- if (!values.containsKey(PreviewPrograms.COLUMN_TYPE)) {
- throw new IllegalArgumentException(
- "Missing the required column: " + PreviewPrograms.COLUMN_TYPE);
- }
- blockIllegalAccessFromBlockedPackage();
- // Mark the owner package of this program.
- values.put(Programs.COLUMN_PACKAGE_NAME, getCallingPackage_());
- blockIllegalAccessToPreviewProgramsSystemColumns(values);
-
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- long rowId = db.insert(PREVIEW_PROGRAMS_TABLE, null, values);
- if (rowId > 0) {
- Uri previewProgramUri = TvContractCompat.buildPreviewProgramUri(rowId);
- notifyChange(previewProgramUri);
- return previewProgramUri;
- }
-
- throw new SQLException("Failed to insert row into " + uri);
- }
-
- private Uri insertWatchNextProgram(Uri uri, ContentValues values) {
- if (!values.containsKey(WatchNextPrograms.COLUMN_TYPE)) {
- throw new IllegalArgumentException(
- "Missing the required column: " + WatchNextPrograms.COLUMN_TYPE);
- }
- blockIllegalAccessFromBlockedPackage();
- if (!callerHasAccessAllEpgDataPermission()
- || !values.containsKey(Programs.COLUMN_PACKAGE_NAME)) {
- // Mark the owner package of this program. System app with a proper permission may
- // change the owner of the program.
- values.put(Programs.COLUMN_PACKAGE_NAME, getCallingPackage_());
- }
- blockIllegalAccessToPreviewProgramsSystemColumns(values);
-
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- long rowId = db.insert(WATCH_NEXT_PROGRAMS_TABLE, null, values);
- if (rowId > 0) {
- Uri watchNextProgramUri = TvContractCompat.buildWatchNextProgramUri(rowId);
- notifyChange(watchNextProgramUri);
- return watchNextProgramUri;
- }
-
- throw new SQLException("Failed to insert row into " + uri);
- }
-
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- SqlParams params = createSqlParams(OP_DELETE, uri, selection, selectionArgs);
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- int count;
- switch (sUriMatcher.match(uri)) {
- case MATCH_CHANNEL_ID_LOGO:
- ContentValues values = new ContentValues();
- values.putNull(CHANNELS_COLUMN_LOGO);
- count =
- db.update(
- params.getTables(),
- values,
- params.getSelection(),
- params.getSelectionArgs());
- break;
- case MATCH_CHANNEL:
- case MATCH_PROGRAM:
- case MATCH_WATCHED_PROGRAM:
- case MATCH_RECORDED_PROGRAM:
- case MATCH_PREVIEW_PROGRAM:
- case MATCH_WATCH_NEXT_PROGRAM:
- case MATCH_CHANNEL_ID:
- case MATCH_PASSTHROUGH_ID:
- case MATCH_PROGRAM_ID:
- case MATCH_WATCHED_PROGRAM_ID:
- case MATCH_RECORDED_PROGRAM_ID:
- case MATCH_PREVIEW_PROGRAM_ID:
- case MATCH_WATCH_NEXT_PROGRAM_ID:
- count =
- db.delete(
- params.getTables(),
- params.getSelection(),
- params.getSelectionArgs());
- break;
- default:
- throw new IllegalArgumentException("Unknown URI " + uri);
- }
- if (count > 0) {
- notifyChange(uri);
- }
- return count;
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- SqlParams params = createSqlParams(OP_UPDATE, uri, selection, selectionArgs);
- blockIllegalAccessToIdAndPackageName(uri, values);
- boolean containImmutableColumn = false;
- if (params.getTables().equals(CHANNELS_TABLE)) {
- filterContentValues(values, sChannelProjectionMap);
- containImmutableColumn = disallowModifyChannelType(values, params);
- if (containImmutableColumn && sUriMatcher.match(uri) != MATCH_CHANNEL_ID) {
- Log.i(TAG, "Updating failed. Attempt to change immutable column for channels.");
- return 0;
- }
- blockIllegalAccessToChannelsSystemColumns(values);
- } else if (params.getTables().equals(PROGRAMS_TABLE)) {
- filterContentValues(values, sProgramProjectionMap);
- checkAndConvertGenre(values);
- checkAndConvertDeprecatedColumns(values);
- } else if (params.getTables().equals(RECORDED_PROGRAMS_TABLE)) {
- filterContentValues(values, sRecordedProgramProjectionMap);
- checkAndConvertGenre(values);
- } else if (params.getTables().equals(PREVIEW_PROGRAMS_TABLE)) {
- filterContentValues(values, sPreviewProgramProjectionMap);
- containImmutableColumn = disallowModifyChannelId(values, params);
- if (containImmutableColumn && PreviewPrograms.CONTENT_URI.equals(uri)) {
- Log.i(
- TAG,
- "Updating failed. Attempt to change unmodifiable column for "
- + "preview programs.");
- return 0;
- }
- blockIllegalAccessToPreviewProgramsSystemColumns(values);
- } else if (params.getTables().equals(WATCH_NEXT_PROGRAMS_TABLE)) {
- filterContentValues(values, sWatchNextProgramProjectionMap);
- blockIllegalAccessToPreviewProgramsSystemColumns(values);
- }
- if (values.size() == 0) {
- // All values may be filtered out, no need to update
- return 0;
- }
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- int count =
- db.update(
- params.getTables(),
- values,
- params.getSelection(),
- params.getSelectionArgs());
- if (count > 0) {
- notifyChange(uri);
- } else if (containImmutableColumn) {
- Log.i(
- TAG,
- "Updating failed. The item may not exist or attempt to change "
- + "immutable column.");
- }
- return count;
- }
-
- private synchronized void ensureInitialized() {
- if (!sInitialized) {
- // Database is not accessed before and the projection maps and the blocked package list
- // are not updated yet. Gets database here to make it initialized.
- mOpenHelper.getReadableDatabase();
- }
- }
-
- private static synchronized void initOnOpenIfNeeded(Context context, SQLiteDatabase db) {
- if (!sInitialized) {
- updateProjectionMap(db, CHANNELS_TABLE, sChannelProjectionMap);
- updateProjectionMap(db, PROGRAMS_TABLE, sProgramProjectionMap);
- updateProjectionMap(db, WATCHED_PROGRAMS_TABLE, sWatchedProgramProjectionMap);
- updateProjectionMap(db, RECORDED_PROGRAMS_TABLE, sRecordedProgramProjectionMap);
- updateProjectionMap(db, PREVIEW_PROGRAMS_TABLE, sPreviewProgramProjectionMap);
- updateProjectionMap(db, WATCH_NEXT_PROGRAMS_TABLE, sWatchNextProgramProjectionMap);
- sBlockedPackagesSharedPreference =
- PreferenceManager.getDefaultSharedPreferences(context);
- sBlockedPackages = new ConcurrentHashMap<>();
- for (String packageName :
- sBlockedPackagesSharedPreference.getStringSet(
- SHARED_PREF_BLOCKED_PACKAGES_KEY, new HashSet<>())) {
- sBlockedPackages.put(packageName, true);
- }
- sInitialized = true;
- }
- }
-
- private static void updateProjectionMap(
- SQLiteDatabase db, String tableName, Map<String, String> projectionMap) {
- try (Cursor cursor = db.rawQuery("SELECT * FROM " + tableName + " LIMIT 0", null)) {
- for (String columnName : cursor.getColumnNames()) {
- if (!projectionMap.containsKey(columnName)) {
- projectionMap.put(columnName, tableName + '.' + columnName);
- }
- }
- }
- }
-
- private Map<String, String> createProjectionMapForQuery(
- String[] projection, Map<String, String> projectionMap) {
- if (projection == null) {
- return projectionMap;
- }
- Map<String, String> columnProjectionMap = new HashMap<>();
- for (String columnName : projection) {
- // Value NULL will be provided if the requested column does not exist in the database.
- columnProjectionMap.put(
- columnName, projectionMap.getOrDefault(columnName, "NULL as " + columnName));
- }
- return columnProjectionMap;
- }
-
- private void filterContentValues(ContentValues values, Map<String, String> projectionMap) {
- Iterator<String> iter = values.keySet().iterator();
- while (iter.hasNext()) {
- String columnName = iter.next();
- if (!projectionMap.containsKey(columnName)) {
- iter.remove();
- }
- }
- }
-
- private SqlParams createSqlParams(
- String operation, Uri uri, String selection, String[] selectionArgs) {
- int match = sUriMatcher.match(uri);
- SqlParams params = new SqlParams(null, selection, selectionArgs);
-
- // Control access to EPG data (excluding watched programs) when the caller doesn't have all
- // access.
- String prefix = match == MATCH_CHANNEL ? CHANNELS_TABLE + "." : "";
- if (!callerHasAccessAllEpgDataPermission()
- && match != MATCH_WATCHED_PROGRAM
- && match != MATCH_WATCHED_PROGRAM_ID) {
- if (!TextUtils.isEmpty(selection)) {
- throw new SecurityException("Selection not allowed for " + uri);
- }
- // Limit the operation only to the data that the calling package owns except for when
- // the caller tries to read TV listings and has the appropriate permission.
- if (operation.equals(OP_QUERY) && callerHasReadTvListingsPermission()) {
- params.setWhere(
- prefix
- + BaseTvColumns.COLUMN_PACKAGE_NAME
- + "=? OR "
- + Channels.COLUMN_SEARCHABLE
- + "=?",
- getCallingPackage_(),
- "1");
- } else {
- params.setWhere(
- prefix + BaseTvColumns.COLUMN_PACKAGE_NAME + "=?", getCallingPackage_());
- }
- }
- String packageName = uri.getQueryParameter(PARAM_PACKAGE);
- if (packageName != null) {
- params.appendWhere(prefix + BaseTvColumns.COLUMN_PACKAGE_NAME + "=?", packageName);
- }
-
- switch (match) {
- case MATCH_CHANNEL:
- String genre = uri.getQueryParameter(TvContractCompat.PARAM_CANONICAL_GENRE);
- if (genre == null) {
- params.setTables(CHANNELS_TABLE);
- } else {
- if (!operation.equals(OP_QUERY)) {
- throw new SecurityException(
- capitalize(operation) + " not allowed for " + uri);
- }
- if (!Genres.isCanonical(genre)) {
- throw new IllegalArgumentException("Not a canonical genre : " + genre);
- }
- params.setTables(CHANNELS_TABLE_INNER_JOIN_PROGRAMS_TABLE);
- String curTime = String.valueOf(System.currentTimeMillis());
- params.appendWhere(
- "LIKE(?, "
- + Programs.COLUMN_CANONICAL_GENRE
- + ") AND "
- + Programs.COLUMN_START_TIME_UTC_MILLIS
- + "<=? AND "
- + Programs.COLUMN_END_TIME_UTC_MILLIS
- + ">=?",
- "%" + genre + "%",
- curTime,
- curTime);
- }
- String inputId = uri.getQueryParameter(TvContractCompat.PARAM_INPUT);
- if (inputId != null) {
- params.appendWhere(Channels.COLUMN_INPUT_ID + "=?", inputId);
- }
- boolean browsableOnly =
- uri.getBooleanQueryParameter(TvContractCompat.PARAM_BROWSABLE_ONLY, false);
- if (browsableOnly) {
- params.appendWhere(Channels.COLUMN_BROWSABLE + "=1");
- }
- String preview = uri.getQueryParameter(PARAM_PREVIEW);
- if (preview != null) {
- String previewSelection =
- Channels.COLUMN_TYPE
- + (preview.equals(String.valueOf(true)) ? "=?" : "!=?");
- params.appendWhere(previewSelection, Channels.TYPE_PREVIEW);
- }
- break;
- case MATCH_CHANNEL_ID:
- params.setTables(CHANNELS_TABLE);
- params.appendWhere(Channels._ID + "=?", uri.getLastPathSegment());
- break;
- case MATCH_PROGRAM:
- params.setTables(PROGRAMS_TABLE);
- String paramChannelId = uri.getQueryParameter(TvContractCompat.PARAM_CHANNEL);
- if (paramChannelId != null) {
- String channelId = String.valueOf(Long.parseLong(paramChannelId));
- params.appendWhere(Programs.COLUMN_CHANNEL_ID + "=?", channelId);
- }
- String paramStartTime = uri.getQueryParameter(TvContractCompat.PARAM_START_TIME);
- String paramEndTime = uri.getQueryParameter(TvContractCompat.PARAM_END_TIME);
- if (paramStartTime != null && paramEndTime != null) {
- String startTime = String.valueOf(Long.parseLong(paramStartTime));
- String endTime = String.valueOf(Long.parseLong(paramEndTime));
- params.appendWhere(
- Programs.COLUMN_START_TIME_UTC_MILLIS
- + "<=? AND "
- + Programs.COLUMN_END_TIME_UTC_MILLIS
- + ">=? AND ?<=?",
- endTime,
- startTime,
- startTime,
- endTime);
- }
- break;
- case MATCH_PROGRAM_ID:
- params.setTables(PROGRAMS_TABLE);
- params.appendWhere(Programs._ID + "=?", uri.getLastPathSegment());
- break;
- case MATCH_WATCHED_PROGRAM:
- if (!callerHasAccessWatchedProgramsPermission()) {
- throw new SecurityException("Access not allowed for " + uri);
- }
- params.setTables(WATCHED_PROGRAMS_TABLE);
- params.appendWhere(WATCHED_PROGRAMS_COLUMN_CONSOLIDATED + "=?", "1");
- break;
- case MATCH_WATCHED_PROGRAM_ID:
- if (!callerHasAccessWatchedProgramsPermission()) {
- throw new SecurityException("Access not allowed for " + uri);
- }
- params.setTables(WATCHED_PROGRAMS_TABLE);
- params.appendWhere(WatchedPrograms._ID + "=?", uri.getLastPathSegment());
- params.appendWhere(WATCHED_PROGRAMS_COLUMN_CONSOLIDATED + "=?", "1");
- break;
- case MATCH_RECORDED_PROGRAM_ID:
- params.appendWhere(RecordedPrograms._ID + "=?", uri.getLastPathSegment());
- // fall-through
- case MATCH_RECORDED_PROGRAM:
- params.setTables(RECORDED_PROGRAMS_TABLE);
- paramChannelId = uri.getQueryParameter(TvContractCompat.PARAM_CHANNEL);
- if (paramChannelId != null) {
- String channelId = String.valueOf(Long.parseLong(paramChannelId));
- params.appendWhere(Programs.COLUMN_CHANNEL_ID + "=?", channelId);
- }
- break;
- case MATCH_PREVIEW_PROGRAM_ID:
- params.appendWhere(PreviewPrograms._ID + "=?", uri.getLastPathSegment());
- // fall-through
- case MATCH_PREVIEW_PROGRAM:
- params.setTables(PREVIEW_PROGRAMS_TABLE);
- paramChannelId = uri.getQueryParameter(TvContractCompat.PARAM_CHANNEL);
- if (paramChannelId != null) {
- String channelId = String.valueOf(Long.parseLong(paramChannelId));
- params.appendWhere(PreviewPrograms.COLUMN_CHANNEL_ID + "=?", channelId);
- }
- break;
- case MATCH_WATCH_NEXT_PROGRAM_ID:
- params.appendWhere(WatchNextPrograms._ID + "=?", uri.getLastPathSegment());
- // fall-through
- case MATCH_WATCH_NEXT_PROGRAM:
- params.setTables(WATCH_NEXT_PROGRAMS_TABLE);
- break;
- case MATCH_CHANNEL_ID_LOGO:
- if (operation.equals(OP_DELETE)) {
- params.setTables(CHANNELS_TABLE);
- params.appendWhere(Channels._ID + "=?", uri.getPathSegments().get(1));
- break;
- }
- // fall-through
- case MATCH_PASSTHROUGH_ID:
- throw new UnsupportedOperationException(operation + " not permmitted on " + uri);
- default:
- throw new IllegalArgumentException("Unknown URI " + uri);
- }
- return params;
- }
-
- private static String capitalize(String str) {
- return Character.toUpperCase(str.charAt(0)) + str.substring(1);
- }
-
- @SuppressLint("DefaultLocale")
- private void checkAndConvertGenre(ContentValues values) {
- String canonicalGenres = values.getAsString(Programs.COLUMN_CANONICAL_GENRE);
-
- if (!TextUtils.isEmpty(canonicalGenres)) {
- // Check if the canonical genres are valid. If not, clear them.
- String[] genres = Genres.decode(canonicalGenres);
- for (String genre : genres) {
- if (!Genres.isCanonical(genre)) {
- values.putNull(Programs.COLUMN_CANONICAL_GENRE);
- canonicalGenres = null;
- break;
- }
- }
- }
-
- if (TextUtils.isEmpty(canonicalGenres)) {
- // If the canonical genre is not set, try to map the broadcast genre to the canonical
- // genre.
- String broadcastGenres = values.getAsString(Programs.COLUMN_BROADCAST_GENRE);
- if (!TextUtils.isEmpty(broadcastGenres)) {
- Set<String> genreSet = new HashSet<>();
- String[] genres = Genres.decode(broadcastGenres);
- for (String genre : genres) {
- String canonicalGenre = sGenreMap.get(genre.toUpperCase());
- if (Genres.isCanonical(canonicalGenre)) {
- genreSet.add(canonicalGenre);
- }
- }
- if (genreSet.size() > 0) {
- values.put(
- Programs.COLUMN_CANONICAL_GENRE,
- Genres.encode(genreSet.toArray(new String[genreSet.size()])));
- }
- }
- }
- }
-
- private void checkAndConvertDeprecatedColumns(ContentValues values) {
- if (values.containsKey(Programs.COLUMN_SEASON_NUMBER)) {
- if (!values.containsKey(Programs.COLUMN_SEASON_DISPLAY_NUMBER)) {
- values.put(
- Programs.COLUMN_SEASON_DISPLAY_NUMBER,
- values.getAsInteger(Programs.COLUMN_SEASON_NUMBER));
- }
- values.remove(Programs.COLUMN_SEASON_NUMBER);
- }
- if (values.containsKey(Programs.COLUMN_EPISODE_NUMBER)) {
- if (!values.containsKey(Programs.COLUMN_EPISODE_DISPLAY_NUMBER)) {
- values.put(
- Programs.COLUMN_EPISODE_DISPLAY_NUMBER,
- values.getAsInteger(Programs.COLUMN_EPISODE_NUMBER));
- }
- values.remove(Programs.COLUMN_EPISODE_NUMBER);
- }
- }
-
- // We might have more than one thread trying to make its way through applyBatch() so the
- // notification coalescing needs to be thread-local to work correctly.
- private final ThreadLocal<Set<Uri>> mTLBatchNotifications = new ThreadLocal<>();
-
- private Set<Uri> getBatchNotificationsSet() {
- return mTLBatchNotifications.get();
- }
-
- private void setBatchNotificationsSet(Set<Uri> batchNotifications) {
- mTLBatchNotifications.set(batchNotifications);
- }
-
- @Override
- public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
- throws OperationApplicationException {
- setBatchNotificationsSet(new HashSet<Uri>());
- Context context = getContext();
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- db.beginTransaction();
- try {
- ContentProviderResult[] results = super.applyBatch(operations);
- db.setTransactionSuccessful();
- return results;
- } finally {
- db.endTransaction();
- final Set<Uri> notifications = getBatchNotificationsSet();
- setBatchNotificationsSet(null);
- for (final Uri uri : notifications) {
- context.getContentResolver().notifyChange(uri, null);
- }
- }
- }
-
- @Override
- public int bulkInsert(Uri uri, ContentValues[] values) {
- setBatchNotificationsSet(new HashSet<Uri>());
- Context context = getContext();
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- db.beginTransaction();
- try {
- int result = super.bulkInsert(uri, values);
- db.setTransactionSuccessful();
- return result;
- } finally {
- db.endTransaction();
- final Set<Uri> notifications = getBatchNotificationsSet();
- setBatchNotificationsSet(null);
- for (final Uri notificationUri : notifications) {
- context.getContentResolver().notifyChange(notificationUri, null);
- }
- }
- }
-
- private void notifyChange(Uri uri) {
- final Set<Uri> batchNotifications = getBatchNotificationsSet();
- if (batchNotifications != null) {
- batchNotifications.add(uri);
- } else {
- getContext().getContentResolver().notifyChange(uri, null);
- }
- }
-
- private boolean callerHasReadTvListingsPermission() {
- return getContext().checkCallingOrSelfPermission(PERMISSION_READ_TV_LISTINGS)
- == PackageManager.PERMISSION_GRANTED;
- }
-
- private boolean callerHasAccessAllEpgDataPermission() {
- return getContext().checkCallingOrSelfPermission(PERMISSION_ACCESS_ALL_EPG_DATA)
- == PackageManager.PERMISSION_GRANTED;
- }
-
- private boolean callerHasAccessWatchedProgramsPermission() {
- return getContext().checkCallingOrSelfPermission(PERMISSION_ACCESS_WATCHED_PROGRAMS)
- == PackageManager.PERMISSION_GRANTED;
- }
-
- private boolean callerHasModifyParentalControlsPermission() {
- return getContext()
- .checkCallingOrSelfPermission(
- android.Manifest.permission.MODIFY_PARENTAL_CONTROLS)
- == PackageManager.PERMISSION_GRANTED;
- }
-
- private void blockIllegalAccessToIdAndPackageName(Uri uri, ContentValues values) {
- if (values.containsKey(BaseColumns._ID)) {
- int match = sUriMatcher.match(uri);
- switch (match) {
- case MATCH_CHANNEL_ID:
- case MATCH_PROGRAM_ID:
- case MATCH_PREVIEW_PROGRAM_ID:
- case MATCH_RECORDED_PROGRAM_ID:
- case MATCH_WATCH_NEXT_PROGRAM_ID:
- case MATCH_WATCHED_PROGRAM_ID:
- if (TextUtils.equals(
- values.getAsString(BaseColumns._ID), uri.getLastPathSegment())) {
- break;
- }
- // fall through
- default:
- throw new IllegalArgumentException("Not allowed to change ID.");
- }
- }
- if (values.containsKey(BaseTvColumns.COLUMN_PACKAGE_NAME)
- && !callerHasAccessAllEpgDataPermission()
- && !TextUtils.equals(
- values.getAsString(BaseTvColumns.COLUMN_PACKAGE_NAME),
- getCallingPackage_())) {
- throw new SecurityException("Not allowed to change package name.");
- }
- }
-
- private void blockIllegalAccessToChannelsSystemColumns(ContentValues values) {
- if (values.containsKey(Channels.COLUMN_LOCKED)
- && !callerHasModifyParentalControlsPermission()) {
- throw new SecurityException("Not allowed to access Channels.COLUMN_LOCKED");
- }
- Boolean hasAccessAllEpgDataPermission = null;
- if (values.containsKey(Channels.COLUMN_BROWSABLE)) {
- hasAccessAllEpgDataPermission = callerHasAccessAllEpgDataPermission();
- if (!hasAccessAllEpgDataPermission) {
- throw new SecurityException("Not allowed to access Channels.COLUMN_BROWSABLE");
- }
- }
- }
-
- private void blockIllegalAccessToPreviewProgramsSystemColumns(ContentValues values) {
- if (values.containsKey(PreviewPrograms.COLUMN_BROWSABLE)
- && !callerHasAccessAllEpgDataPermission()) {
- throw new SecurityException("Not allowed to access Programs.COLUMN_BROWSABLE");
- }
- }
-
- private void blockIllegalAccessFromBlockedPackage() {
- String callingPackageName = getCallingPackage_();
- if (sBlockedPackages.containsKey(callingPackageName)) {
- throw new SecurityException(
- "Not allowed to access "
- + TvContractCompat.AUTHORITY
- + ", "
- + callingPackageName
- + " is blocked");
- }
- }
-
- private boolean disallowModifyChannelType(ContentValues values, SqlParams params) {
- if (values.containsKey(Channels.COLUMN_TYPE)) {
- params.appendWhere(
- Channels.COLUMN_TYPE + "=?", values.getAsString(Channels.COLUMN_TYPE));
- return true;
- }
- return false;
- }
-
- private boolean disallowModifyChannelId(ContentValues values, SqlParams params) {
- if (values.containsKey(PreviewPrograms.COLUMN_CHANNEL_ID)) {
- params.appendWhere(
- PreviewPrograms.COLUMN_CHANNEL_ID + "=?",
- values.getAsString(PreviewPrograms.COLUMN_CHANNEL_ID));
- return true;
- }
- return false;
- }
-
- @Override
- public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
- switch (sUriMatcher.match(uri)) {
- case MATCH_CHANNEL_ID_LOGO:
- return openLogoFile(uri, mode);
- default:
- throw new FileNotFoundException(uri.toString());
- }
- }
-
- private ParcelFileDescriptor openLogoFile(Uri uri, String mode) throws FileNotFoundException {
- long channelId = Long.parseLong(uri.getPathSegments().get(1));
-
- SqlParams params =
- new SqlParams(CHANNELS_TABLE, Channels._ID + "=?", String.valueOf(channelId));
- if (!callerHasAccessAllEpgDataPermission()) {
- if (callerHasReadTvListingsPermission()) {
- params.appendWhere(
- Channels.COLUMN_PACKAGE_NAME + "=? OR " + Channels.COLUMN_SEARCHABLE + "=?",
- getCallingPackage_(),
- "1");
- } else {
- params.appendWhere(Channels.COLUMN_PACKAGE_NAME + "=?", getCallingPackage_());
- }
- }
-
- SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
- queryBuilder.setTables(params.getTables());
-
- // We don't write the database here.
- SQLiteDatabase db = mOpenHelper.getReadableDatabase();
- if (mode.equals("r")) {
- String sql =
- queryBuilder.buildQuery(
- new String[] {CHANNELS_COLUMN_LOGO},
- params.getSelection(),
- null,
- null,
- null,
- null);
- ParcelFileDescriptor fd =
- DatabaseUtils.blobFileDescriptorForQuery(db, sql, params.getSelectionArgs());
- if (fd == null) {
- throw new FileNotFoundException(uri.toString());
- }
- return fd;
- } else {
- try (Cursor cursor =
- queryBuilder.query(
- db,
- new String[] {Channels._ID},
- params.getSelection(),
- params.getSelectionArgs(),
- null,
- null,
- null)) {
- if (cursor.getCount() < 1) {
- // Fails early if corresponding channel does not exist.
- // PipeMonitor may still fail to update DB later.
- throw new FileNotFoundException(uri.toString());
- }
- }
-
- try {
- ParcelFileDescriptor[] pipeFds = ParcelFileDescriptor.createPipe();
- PipeMonitor pipeMonitor = new PipeMonitor(pipeFds[0], channelId, params);
- pipeMonitor.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- return pipeFds[1];
- } catch (IOException ioe) {
- FileNotFoundException fne = new FileNotFoundException(uri.toString());
- fne.initCause(ioe);
- throw fne;
- }
- }
- }
-
- /**
- * Validates the sort order based on the given field set.
- *
- * @throws IllegalArgumentException if there is any unknown field.
- */
- @SuppressLint("DefaultLocale")
- private static void validateSortOrder(String sortOrder, Set<String> possibleFields) {
- if (TextUtils.isEmpty(sortOrder) || possibleFields.isEmpty()) {
- return;
- }
- String[] orders = sortOrder.split(",");
- for (String order : orders) {
- String field =
- order.replaceAll("\\s+", " ")
- .trim()
- .toLowerCase()
- .replace(" asc", "")
- .replace(" desc", "");
- if (!possibleFields.contains(field)) {
- throw new IllegalArgumentException("Illegal field in sort order " + order);
- }
- }
- }
-
- private class PipeMonitor extends AsyncTask<Void, Void, Void> {
- private final ParcelFileDescriptor mPfd;
- private final long mChannelId;
- private final SqlParams mParams;
-
- private PipeMonitor(ParcelFileDescriptor pfd, long channelId, SqlParams params) {
- mPfd = pfd;
- mChannelId = channelId;
- mParams = params;
- }
-
- @Override
- protected Void doInBackground(Void... params) {
- int count = 0;
- try (AutoCloseInputStream is = new AutoCloseInputStream(mPfd);
- ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
- Bitmap bitmap = BitmapFactory.decodeStream(is);
- if (bitmap == null) {
- Log.e(TAG, "Failed to decode logo image for channel ID " + mChannelId);
- return null;
- }
-
- float scaleFactor =
- Math.min(
- 1f,
- ((float) MAX_LOGO_IMAGE_SIZE)
- / Math.max(bitmap.getWidth(), bitmap.getHeight()));
- if (scaleFactor < 1f) {
- bitmap =
- Bitmap.createScaledBitmap(
- bitmap,
- (int) (bitmap.getWidth() * scaleFactor),
- (int) (bitmap.getHeight() * scaleFactor),
- false);
- }
- bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
- byte[] bytes = baos.toByteArray();
-
- ContentValues values = new ContentValues();
- values.put(CHANNELS_COLUMN_LOGO, bytes);
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- count =
- db.update(
- mParams.getTables(),
- values,
- mParams.getSelection(),
- mParams.getSelectionArgs());
- if (count > 0) {
- Uri uri = TvContractCompat.buildChannelLogoUri(mChannelId);
- notifyChange(uri);
- }
- } catch (IOException e) {
- Log.e(TAG, "Failed to write logo for channel ID " + mChannelId, e);
-
- } finally {
- if (count == 0) {
- try {
- mPfd.closeWithError("Failed to write logo for channel ID " + mChannelId);
- } catch (IOException ioe) {
- Log.e(TAG, "Failed to close pipe", ioe);
- }
- }
- }
- return null;
- }
- }
-
- /**
- * Column definitions for the TV programs that the user watched. Applications do not have access
- * to this table.
- *
- * <p>
- *
- * <p>By default, the query results will be sorted by {@link
- * WatchedPrograms#COLUMN_WATCH_START_TIME_UTC_MILLIS} in descending order.
- *
- * @hide
- */
- public static final class WatchedPrograms implements BaseTvColumns {
-
- /** The content:// style URI for this table. */
- public static final Uri CONTENT_URI =
- Uri.parse("content://" + TvContract.AUTHORITY + "/watched_program");
-
- /** The MIME type of a directory of watched programs. */
- public static final String CONTENT_TYPE = "vnd.android.cursor.dir/watched_program";
-
- /** The MIME type of a single item in this table. */
- public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watched_program";
-
- /**
- * The UTC time that the user started watching this TV program, in milliseconds since the
- * epoch.
- *
- * <p>
- *
- * <p>Type: INTEGER (long)
- */
- public static final String COLUMN_WATCH_START_TIME_UTC_MILLIS =
- "watch_start_time_utc_millis";
-
- /**
- * The UTC time that the user stopped watching this TV program, in milliseconds since the
- * epoch.
- *
- * <p>
- *
- * <p>Type: INTEGER (long)
- */
- public static final String COLUMN_WATCH_END_TIME_UTC_MILLIS = "watch_end_time_utc_millis";
-
- /**
- * The ID of the TV channel that provides this TV program.
- *
- * <p>
- *
- * <p>This is a required field.
- *
- * <p>
- *
- * <p>Type: INTEGER (long)
- */
- public static final String COLUMN_CHANNEL_ID = "channel_id";
-
- /**
- * The title of this TV program.
- *
- * <p>
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_TITLE = "title";
-
- /**
- * The start time of this TV program, in milliseconds since the epoch.
- *
- * <p>
- *
- * <p>Type: INTEGER (long)
- */
- public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
-
- /**
- * The end time of this TV program, in milliseconds since the epoch.
- *
- * <p>
- *
- * <p>Type: INTEGER (long)
- */
- public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
-
- /**
- * The description of this TV program.
- *
- * <p>
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_DESCRIPTION = "description";
-
- /**
- * Extra parameters given to {@link TvInputService.Session#tune(Uri, android.os.Bundle)
- * TvInputService.Session.tune(Uri, android.os.Bundle)} when tuning to the channel that
- * provides this TV program. (Used internally.)
- *
- * <p>
- *
- * <p>This column contains an encoded string that represents comma-separated key-value pairs
- * of the tune parameters. (Ex. "[key1]=[value1], [key2]=[value2]"). '%' is used as an
- * escape character for '%', '=', and ','.
- *
- * <p>
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_INTERNAL_TUNE_PARAMS = "tune_params";
-
- /**
- * The session token of this TV program. (Used internally.)
- *
- * <p>
- *
- * <p>This contains a String representation of {@link IBinder} for {@link
- * TvInputService.Session} that provides the current TV program. It is used internally to
- * distinguish watched programs entries from different TV input sessions.
- *
- * <p>
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_INTERNAL_SESSION_TOKEN = "session_token";
-
- private WatchedPrograms() {}
- }
-}
diff --git a/tests/common/src/com/android/tv/testing/data/ProgramInfo.java b/tests/common/src/com/android/tv/testing/ProgramInfo.java
index 6d801425..08742aed 100644
--- a/tests/common/src/com/android/tv/testing/data/ProgramInfo.java
+++ b/tests/common/src/com/android/tv/testing/ProgramInfo.java
@@ -14,15 +14,12 @@
* limitations under the License.
*/
-package com.android.tv.testing.data;
+package com.android.tv.testing;
import android.content.Context;
import android.database.Cursor;
import android.media.tv.TvContentRating;
import android.media.tv.TvContract;
-import com.android.tv.testing.R;
-import com.android.tv.testing.utils.Utils;
-import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
@@ -71,12 +68,12 @@ public final class ProgramInfo {
TimeUnit.MINUTES.toMillis(90),
TimeUnit.HOURS.toMillis(5)
};
- private static long durationsSumMs;
+ private static long DURATIONS_SUM_MS;
static {
- durationsSumMs = 0;
+ DURATIONS_SUM_MS = 0;
for (long duration : DURATIONS_MS) {
- durationsSumMs += duration;
+ DURATIONS_SUM_MS += duration;
}
}
@@ -163,8 +160,8 @@ public final class ProgramInfo {
return Math.max((int) (timeMs / durationMs), 0);
}
long startTimeMs = channelId * DURATIONS_MS[((int) (channelId % DURATIONS_MS.length))];
- int index = (int) ((timeMs - startTimeMs) / durationsSumMs) * DURATIONS_MS.length;
- startTimeMs += (index / DURATIONS_MS.length) * durationsSumMs;
+ int index = (int) ((timeMs - startTimeMs) / DURATIONS_SUM_MS) * DURATIONS_MS.length;
+ startTimeMs += (index / DURATIONS_MS.length) * DURATIONS_SUM_MS;
while (startTimeMs + DURATIONS_MS[index % DURATIONS_MS.length] < timeMs) {
startTimeMs += DURATIONS_MS[index % DURATIONS_MS.length];
index++;
@@ -183,7 +180,7 @@ public final class ProgramInfo {
}
long startTimeMs =
channelId * DURATIONS_MS[((int) (channelId % DURATIONS_MS.length))]
- + (index / DURATIONS_MS.length) * durationsSumMs;
+ + (index / DURATIONS_MS.length) * DURATIONS_SUM_MS;
for (int i = 0; i < index % DURATIONS_MS.length; i++) {
startTimeMs += DURATIONS_MS[i];
}
@@ -248,7 +245,7 @@ public final class ProgramInfo {
&& Objects.equals(posterArtUri, that.posterArtUri)
&& Objects.equals(description, that.description)
&& Objects.equals(genre, that.genre)
- && Arrays.equals(contentRatings, that.contentRatings)
+ && Objects.equals(contentRatings, that.contentRatings)
&& Objects.equals(resourceUri, that.resourceUri);
}
diff --git a/tests/common/src/com/android/tv/testing/data/ProgramUtils.java b/tests/common/src/com/android/tv/testing/ProgramUtils.java
index 21fd371f..3be9d10c 100644
--- a/tests/common/src/com/android/tv/testing/data/ProgramUtils.java
+++ b/tests/common/src/com/android/tv/testing/ProgramUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.tv.testing.data;
+package com.android.tv.testing;
import android.content.ContentUris;
import android.content.ContentValues;
@@ -29,7 +29,6 @@ import com.android.tv.common.TvContentRatingCache;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
-@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed
public class ProgramUtils {
private static final String TAG = "ProgramUtils";
private static final boolean DEBUG = false;
diff --git a/tests/common/src/com/android/tv/testing/SingletonProvider.java b/tests/common/src/com/android/tv/testing/SingletonProvider.java
deleted file mode 100644
index d9c2d409..00000000
--- a/tests/common/src/com/android/tv/testing/SingletonProvider.java
+++ /dev/null
@@ -1,37 +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 javax.inject.Provider;
-
-/** A Provider that always returns the same instance. */
-public class SingletonProvider<T> implements Provider<T> {
- private final T t;
-
- private SingletonProvider(T t) {
- this.t = t;
- }
-
- @Override
- public T get() {
- return t;
- }
-
- public static <S, T extends S> Provider<S> create(T t) {
- return new SingletonProvider<S>(t);
- }
-}
diff --git a/tests/common/src/com/android/tv/testing/TestSingletonApp.java b/tests/common/src/com/android/tv/testing/TestSingletonApp.java
deleted file mode 100644
index a4a39c18..00000000
--- a/tests/common/src/com/android/tv/testing/TestSingletonApp.java
+++ /dev/null
@@ -1,219 +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 android.app.Application;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import com.android.tv.InputSessionManager;
-import com.android.tv.MainActivityWrapper;
-import com.android.tv.TvSingletons;
-import com.android.tv.analytics.Analytics;
-import com.android.tv.analytics.Tracker;
-import com.android.tv.common.BaseApplication;
-import com.android.tv.common.config.api.RemoteConfig;
-import com.android.tv.common.experiments.ExperimentLoader;
-import com.android.tv.common.recording.RecordingStorageStatusManager;
-import com.android.tv.common.util.Clock;
-import com.android.tv.data.ChannelDataManager;
-import com.android.tv.data.PreviewDataManager;
-import com.android.tv.data.ProgramDataManager;
-import com.android.tv.data.epg.EpgFetcher;
-import com.android.tv.data.epg.EpgReader;
-import com.android.tv.dvr.DvrDataManager;
-import com.android.tv.dvr.DvrManager;
-import com.android.tv.dvr.DvrScheduleManager;
-import com.android.tv.dvr.DvrWatchedPositionManager;
-import com.android.tv.dvr.recorder.RecordingScheduler;
-import com.android.tv.perf.PerformanceMonitor;
-import com.android.tv.tuner.TunerInputController;
-import com.android.tv.util.SetupUtils;
-import com.android.tv.util.TvInputManagerHelper;
-import com.android.tv.util.account.AccountHelper;
-import javax.inject.Provider;
-
-/** Test application for Live TV. */
-public class TestSingletonApp extends Application implements TvSingletons {
- public final FakeClock fakeClock = FakeClock.createWithCurrentTime();
- public final FakeEpgReader epgReader = new FakeEpgReader(fakeClock);
- public final FakeRemoteConfig remoteConfig = new FakeRemoteConfig();
- public final FakeEpgFetcher epgFetcher = new FakeEpgFetcher();
-
- public FakeTvInputManagerHelper tvInputManagerHelper;
- public SetupUtils setupUtils;
-
- private final Provider<EpgReader> mEpgReaderProvider = SingletonProvider.create(epgReader);
- private TunerInputController mTunerInputController;
-
- @Override
- public void onCreate() {
- super.onCreate();
- mTunerInputController =
- new TunerInputController(
- ComponentName.unflattenFromString(getEmbeddedTunerInputId()));
-
- tvInputManagerHelper = new FakeTvInputManagerHelper(this);
- setupUtils = SetupUtils.createForTvSingletons(this);
- tvInputManagerHelper.start();
- // HACK reset the singleton for tests
- BaseApplication.sSingletons = this;
- }
-
- @Override
- public Analytics getAnalytics() {
- return null;
- }
-
- @Override
- public void handleInputCountChanged() {}
-
- @Override
- public ChannelDataManager getChannelDataManager() {
- return new ChannelDataManager(this, tvInputManagerHelper);
- }
-
- @Override
- public boolean isChannelDataManagerLoadFinished() {
- return false;
- }
-
- @Override
- public ProgramDataManager getProgramDataManager() {
- return null;
- }
-
- @Override
- public boolean isProgramDataManagerCurrentProgramsLoadFinished() {
- return false;
- }
-
- @Override
- public PreviewDataManager getPreviewDataManager() {
- return null;
- }
-
- @Override
- public DvrDataManager getDvrDataManager() {
- return null;
- }
-
- @Override
- public DvrScheduleManager getDvrScheduleManager() {
- return null;
- }
-
- @Override
- public DvrManager getDvrManager() {
- return null;
- }
-
- @Override
- public RecordingScheduler getRecordingScheduler() {
- return null;
- }
-
- @Override
- public DvrWatchedPositionManager getDvrWatchedPositionManager() {
- return null;
- }
-
- @Override
- public InputSessionManager getInputSessionManager() {
- return null;
- }
-
- @Override
- public Tracker getTracker() {
- return null;
- }
-
- @Override
- public TvInputManagerHelper getTvInputManagerHelper() {
- return tvInputManagerHelper;
- }
-
- @Override
- public Provider<EpgReader> providesEpgReader() {
- return mEpgReaderProvider;
- }
-
- @Override
- public EpgFetcher getEpgFetcher() {
- return epgFetcher;
- }
-
- @Override
- public SetupUtils getSetupUtils() {
- return setupUtils;
- }
-
- @Override
- public TunerInputController getTunerInputController() {
- return mTunerInputController;
- }
-
- @Override
- public ExperimentLoader getExperimentLoader() {
- return new ExperimentLoader();
- }
-
- @Override
- public MainActivityWrapper getMainActivityWrapper() {
- return null;
- }
-
- @Override
- public AccountHelper getAccountHelper() {
- return null;
- }
-
- @Override
- public Clock getClock() {
- return fakeClock;
- }
-
- @Override
- public RecordingStorageStatusManager getRecordingStorageStatusManager() {
- return null;
- }
-
- @Override
- public RemoteConfig getRemoteConfig() {
- return remoteConfig;
- }
-
- @Override
- public Intent getTunerSetupIntent(Context context) {
- return null;
- }
-
- @Override
- public boolean isRunningInMainProcess() {
- return false;
- }
-
- @Override
- public PerformanceMonitor getPerformanceMonitor() {
- return null;
- }
-
- @Override
- public String getEmbeddedTunerInputId() {
- return "com.android.tv/.tuner.tvinput.TunerTvInputService";
- }
-}
diff --git a/tests/common/src/com/android/tv/testing/constants/TvContentRatingConstants.java b/tests/common/src/com/android/tv/testing/TvContentRatingConstants.java
index e1a3d906..30382209 100644
--- a/tests/common/src/com/android/tv/testing/constants/TvContentRatingConstants.java
+++ b/tests/common/src/com/android/tv/testing/TvContentRatingConstants.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.tv.testing.constants;
+package com.android.tv.testing;
import android.media.tv.TvContentRating;
diff --git a/tests/common/src/com/android/tv/testing/utils/Utils.java b/tests/common/src/com/android/tv/testing/Utils.java
index 09a6c09c..a250995a 100644
--- a/tests/common/src/com/android/tv/testing/utils/Utils.java
+++ b/tests/common/src/com/android/tv/testing/Utils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.tv.testing.utils;
+package com.android.tv.testing;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -26,7 +26,7 @@ import android.media.tv.TvInputInfo;
import android.media.tv.TvInputManager;
import android.net.Uri;
import android.util.Log;
-import com.android.tv.common.util.CommonUtils;
+import com.android.tv.common.TvCommonUtils;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -38,7 +38,9 @@ import java.util.Random;
/**
* An utility class for testing.
*
- * @see CommonUtils#isRunningInTest
+ * <p>This class is also used to check whether TV app is running in tests or not.
+ *
+ * @see TvCommonUtils#isRunningInTest
*/
public final class Utils {
private static final String TAG = "Utils";
@@ -104,15 +106,14 @@ public final class Utils {
return Long.valueOf(today);
}
+ private Utils() {}
+
/** Checks whether TvActivity is enabled or not. */
public static boolean isTvActivityEnabled(Context context) {
PackageManager pm = context.getPackageManager();
- ComponentName name =
- new ComponentName("com.android.tv", "com.android.tv.TvActivity");
+ ComponentName name = new ComponentName("com.android.tv", "com.android.tv.TvActivity");
int enabled = pm.getComponentEnabledSetting(name);
return enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
|| enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
}
-
- private Utils() {}
}
diff --git a/tests/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/testinput/ChannelState.java b/tests/common/src/com/android/tv/testing/testinput/ChannelState.java
index 3e8bab33..c6f67b0b 100644
--- a/tests/common/src/com/android/tv/testing/testinput/ChannelState.java
+++ b/tests/common/src/com/android/tv/testing/testinput/ChannelState.java
@@ -16,7 +16,7 @@
package com.android.tv.testing.testinput;
import android.media.tv.TvTrackInfo;
-import com.android.tv.testing.constants.Constants;
+import com.android.tv.testing.Constants;
import java.util.Collections;
import java.util.List;
diff --git a/tests/common/src/com/android/tv/testing/testinput/TestInputControlConnection.java b/tests/common/src/com/android/tv/testing/testinput/TestInputControlConnection.java
index 071b1d3c..82b4614e 100644
--- a/tests/common/src/com/android/tv/testing/testinput/TestInputControlConnection.java
+++ b/tests/common/src/com/android/tv/testing/testinput/TestInputControlConnection.java
@@ -21,7 +21,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Log;
-import com.android.tv.testing.data.ChannelInfo;
+import com.android.tv.testing.ChannelInfo;
/**
* Connection for controlling the Test TV Input Service.
diff --git a/tests/common/src/com/android/tv/testing/testinput/TvTestInputConstants.java b/tests/common/src/com/android/tv/testing/testinput/TvTestInputConstants.java
index 27d3036c..0c768b21 100644
--- a/tests/common/src/com/android/tv/testing/testinput/TvTestInputConstants.java
+++ b/tests/common/src/com/android/tv/testing/testinput/TvTestInputConstants.java
@@ -15,7 +15,7 @@
*/
package com.android.tv.testing.testinput;
-import com.android.tv.testing.data.ChannelInfo;
+import com.android.tv.testing.ChannelInfo;
/** Constants for interacting with TvTestInput. */
public final class TvTestInputConstants {
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 1af1119f..8c4e6e4b 100644
--- a/tests/common/src/com/android/tv/testing/uihelper/LiveChannelsUiDeviceHelper.java
+++ b/tests/common/src/com/android/tv/testing/uihelper/LiveChannelsUiDeviceHelper.java
@@ -1,18 +1,3 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
package com.android.tv.testing.uihelper;
import static com.android.tv.testing.uihelper.UiDeviceAsserts.waitForCondition;
@@ -26,7 +11,7 @@ import android.support.test.uiautomator.BySelector;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.Until;
import android.util.Log;
-import com.android.tv.testing.utils.Utils;
+import com.android.tv.testing.Utils;
import junit.framework.Assert;
/** Helper for testing the Live TV Application. */
diff --git a/tests/func/src/com/android/tv/tests/ui/LiveChannelsAppTest.java b/tests/func/src/com/android/tv/tests/ui/LiveChannelsAppTest.java
index 916ef8f1..36a3b07b 100644
--- a/tests/func/src/com/android/tv/tests/ui/LiveChannelsAppTest.java
+++ b/tests/func/src/com/android/tv/tests/ui/LiveChannelsAppTest.java
@@ -66,9 +66,8 @@ public class LiveChannelsAppTest extends LiveChannelsTestCase {
public void testDisplayModeCancel() {
ChannelStateData data = new ChannelStateData();
- data.mTvTrackInfos.add(com.android.tv.testing.constants.Constants.SVGA_VIDEO_TRACK);
- data.mSelectedVideoTrackId =
- com.android.tv.testing.constants.Constants.SVGA_VIDEO_TRACK.getId();
+ data.mTvTrackInfos.add(com.android.tv.testing.Constants.SVGA_VIDEO_TRACK);
+ data.mSelectedVideoTrackId = com.android.tv.testing.Constants.SVGA_VIDEO_TRACK.getId();
updateThenTune(data, TvTestInputConstants.CH_2);
mMenuHelper.assertPressOptionsDisplayMode();
@@ -89,8 +88,7 @@ public class LiveChannelsAppTest extends LiveChannelsTestCase {
public void testMultiAudioCancel() {
ChannelStateData data = new ChannelStateData();
- data.mTvTrackInfos.add(
- com.android.tv.testing.constants.Constants.GENERIC_AUDIO_TRACK);
+ data.mTvTrackInfos.add(com.android.tv.testing.Constants.GENERIC_AUDIO_TRACK);
updateThenTune(data, TvTestInputConstants.CH_2);
mMenuHelper.assertPressOptionsMultiAudio();
diff --git a/tests/func/src/com/android/tv/tests/ui/LiveChannelsTestCase.java b/tests/func/src/com/android/tv/tests/ui/LiveChannelsTestCase.java
index 38d8ce1a..9a1bc043 100644
--- a/tests/func/src/com/android/tv/tests/ui/LiveChannelsTestCase.java
+++ b/tests/func/src/com/android/tv/tests/ui/LiveChannelsTestCase.java
@@ -23,7 +23,7 @@ import android.content.res.Resources;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.Until;
import android.test.InstrumentationTestCase;
-import com.android.tv.testing.data.ChannelInfo;
+import com.android.tv.testing.ChannelInfo;
import com.android.tv.testing.testinput.ChannelStateData;
import com.android.tv.testing.testinput.TestInputControlConnection;
import com.android.tv.testing.testinput.TestInputControlUtils;
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 9b824a63..265e85e4 100644
--- a/tests/func/src/com/android/tv/tests/ui/PlayControlsRowViewTest.java
+++ b/tests/func/src/com/android/tv/tests/ui/PlayControlsRowViewTest.java
@@ -111,8 +111,7 @@ public class PlayControlsRowViewTest extends LiveChannelsTestCase {
assertButtonHasFocus(BUTTON_ID_PLAY_PAUSE);
}
- // TODO("b/70727167"): fix tests
- public void notestKeepPausedAfterVisitingHome() {
+ public void testKeepPausedAfterVisitingHome() {
// Pause the playback.
mDevice.pressKeyCode(KeyEvent.KEYCODE_MEDIA_PAUSE);
mMenuHelper.assertWaitForMenu();
diff --git a/tests/input/func.sh b/tests/input/func.sh
deleted file mode 100644
index 3b2af4da..00000000
--- a/tests/input/func.sh
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/system/bin/sh
-#
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# text fixture setup for unit tests
-
-
-echo "text fixture setup for func tests"
-
-am instrument \
- -e testSetupMode func \
- -w com.android.tv.testinput/.instrument.TestSetupInstrumentation \ No newline at end of file
diff --git a/tests/input/src/com/android/tv/testinput/TestInputControl.java b/tests/input/src/com/android/tv/testinput/TestInputControl.java
index 5e5ec32a..54845b80 100644
--- a/tests/input/src/com/android/tv/testinput/TestInputControl.java
+++ b/tests/input/src/com/android/tv/testinput/TestInputControl.java
@@ -21,8 +21,8 @@ import android.net.Uri;
import android.os.RemoteException;
import android.util.Log;
import android.util.LongSparseArray;
-import com.android.tv.testing.data.ChannelInfo;
-import com.android.tv.testing.data.ChannelUtils;
+import com.android.tv.testing.ChannelInfo;
+import com.android.tv.testing.ChannelUtils;
import com.android.tv.testing.testinput.ChannelState;
import com.android.tv.testing.testinput.ChannelStateData;
import com.android.tv.testing.testinput.ITestInputControl;
diff --git a/tests/input/src/com/android/tv/testinput/TestTvInputService.java b/tests/input/src/com/android/tv/testinput/TestTvInputService.java
index 5cefdc72..6e9405d8 100644
--- a/tests/input/src/com/android/tv/testinput/TestTvInputService.java
+++ b/tests/input/src/com/android/tv/testinput/TestTvInputService.java
@@ -42,13 +42,12 @@ import android.util.Log;
import android.view.KeyEvent;
import android.view.Surface;
import com.android.tv.input.TunerHelper;
-import com.android.tv.testing.data.ChannelInfo;
+import com.android.tv.testing.ChannelInfo;
import com.android.tv.testing.testinput.ChannelState;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/** Simple TV input service which provides test channels. */
-@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed
public class TestTvInputService extends TvInputService {
private static final String TAG = "TestTvInputService";
private static final int REFRESH_DELAY_MS = 1000 / 5;
diff --git a/tests/input/src/com/android/tv/testinput/TestTvInputSetupActivity.java b/tests/input/src/com/android/tv/testinput/TestTvInputSetupActivity.java
index b315785d..ce18ff81 100644
--- a/tests/input/src/com/android/tv/testinput/TestTvInputSetupActivity.java
+++ b/tests/input/src/com/android/tv/testinput/TestTvInputSetupActivity.java
@@ -26,11 +26,11 @@ import android.media.tv.TvContract;
import android.media.tv.TvInputInfo;
import android.os.Bundle;
import android.util.Log;
-import com.android.tv.testing.constants.Constants;
-import com.android.tv.testing.data.ChannelInfo;
-import com.android.tv.testing.data.ChannelUtils;
-import com.android.tv.testing.data.ProgramInfo;
-import com.android.tv.testing.data.ProgramUtils;
+import com.android.tv.testing.ChannelInfo;
+import com.android.tv.testing.ChannelUtils;
+import com.android.tv.testing.Constants;
+import com.android.tv.testing.ProgramInfo;
+import com.android.tv.testing.ProgramUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
diff --git a/tests/input/src/com/android/tv/testinput/instrument/TestSetupInstrumentation.java b/tests/input/src/com/android/tv/testinput/instrument/TestSetupInstrumentation.java
index a4bd45c0..498e25dc 100644
--- a/tests/input/src/com/android/tv/testinput/instrument/TestSetupInstrumentation.java
+++ b/tests/input/src/com/android/tv/testinput/instrument/TestSetupInstrumentation.java
@@ -21,7 +21,7 @@ import android.app.Instrumentation;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
-import com.android.tv.testing.constants.Constants;
+import com.android.tv.testing.Constants;
import com.android.tv.testinput.TestTvInputService;
import com.android.tv.testinput.TestTvInputSetupActivity;
diff --git a/tests/input/tools/get_test_logos.sh b/tests/input/tools/get_test_logos.sh
deleted file mode 100755
index 4dd87a3a..00000000
--- a/tests/input/tools/get_test_logos.sh
+++ /dev/null
@@ -1,57 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-BASE="http://www.google.com/chart?chs=32&chst=d_simple_text_icon_above"
-
-# From http://developers.google.com/chart/image/docs/gallery/dynamic_icons#basic-icons
-icons=(
- academy activities airport amusement aquarium
- art-gallery atm baby bank-dollar bank-euro
- bank-intl bank-pound bank-yen bar barber
- beach beer bicycle books bowling
- bus cafe camping car-dealer car-rental
- car-repair casino caution cemetery-grave cemetery-tomb
- cinema civic-building computer corporate courthouse
- fire flag floral helicopter home
- info landslide legal location locomotive
- medical mobile motorcycle music parking
- pet petrol phone picnic postal
- repair restaurant sail school scissors
- ship shoppingbag shoppingcart ski snack
- snow sport star swim taxi train
- truck wc-female wc-male wc
- wheelchair
- )
-
-# The 500s from https://spec.googleplex.com/quantumpalette#
-colors=(
- DB4437 E91E63 9C27B0 673AB7 3F51B5
- 4285F4 03A9F4 00BCD4 009688 0F9D58
- 8BC34A CDDC39 FFEB3B F4B400 FF9800
- FF5722 795548 9E9E9E 607D8B
-)
-
-
-# See https://developers.google.com/chart/image/docs/gallery/dynamic_icons
-for n in `seq 1 80`;
-do
- i=n%76
- c=$(($RANDOM%19))
- # <font_size>|<font_fill_color>|<icon_name>|<icon_size>|<icon_fill_color>|<icon_and_text_border_color>
- url=${BASE}"&chld=Ch+"${n}"|7|00F|${icons[${i}]}|24|${colors[${c}]}|FFF"
- echo ${url}
- curl ${url} -o tests/input/res/drawable-xhdpi/ch_${n}_logo.png
-done; \ No newline at end of file
diff --git a/tests/input/unit.sh b/tests/input/unit.sh
deleted file mode 100644
index a14d3292..00000000
--- a/tests/input/unit.sh
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/system/bin/sh
-#
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# text fixture setup for unit tests
-
-
-echo "text fixture setup for unit tests"
-
-am instrument \
- -e testSetupMode unit \
- -w com.android.tv.testinput/.instrument.TestSetupInstrumentation \ No newline at end of file
diff --git a/tests/tunerscripts/measure-tuning-time.awk b/tests/tunerscripts/measure-tuning-time.awk
deleted file mode 100644
index e7febcf1..00000000
--- a/tests/tunerscripts/measure-tuning-time.awk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Awk script to measure tuning time statistics from logcat dump
-
-BEGIN {
- n = 0;
- sum = 0;
-}
-
-# Collect tuning time with "Video available in <time> ms" message
-/Video available in/ {
- n++;
- tune_time = $11;
- sum += tune_time;
- if (n == 1) {
- min = tune_time;
- max = tune_time;
- } else {
- if (tune_time < min) {
- min = tune_time
- }
- if (tune_time > max) {
- max = tune_time
- }
- }
-}
-
-END {
- average = sum / n;
- print "Average tune time", average, "ms";
- print "Minimum tune time", min, "ms";
- print "Maximum tune time", max, "ms";
-}
-
diff --git a/tests/tunerscripts/usbtuner-test.sh b/tests/tunerscripts/usbtuner-test.sh
deleted file mode 100755
index b8c15841..00000000
--- a/tests/tunerscripts/usbtuner-test.sh
+++ /dev/null
@@ -1,159 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# usage: usbtuner-test.sh <test_case> [channel]
-#
-# To test repeated channel change, run:
-#
-# ./usbtuner-test.sh <1 or 3>
-#
-# To test watching a fixed channel, run:
-#
-# ./usbtuner-test.sh 2
-#
-# Case 2 uses the last-viewed channel by TV app. Give a channel number
-# as a 2nd parameter if you want to use the channel for testing, like below:
-#
-# ./usbtuner-test.sh 2 6-1
-#
-# The script assumes that:
-# 1) Browsing by keydown event circulates among the USB input channels only
-# 2) When started, TV app should tune to one of the channels provided by the USB input
-#
-# The test result is logged in the doc: https://goo.gl/MsPBf7
-
-function start_tv {
- disable_analytics_report
- adb shell am force-stop com.android.tv
- adb shell am start -n com.android.tv/.MainActivity > /dev/null
- sleep 5
-}
-
-function log_begin {
- adb shell dumpsys meminfo -d --package com.android.tv.tuner > meminfo-begin.txt
-}
-
-function tune {
- adb shell input text $1
- adb shell input keyevent KEYCODE_DPAD_CENTER
- sleep 5 # Wait enough for tuning
-}
-
-function browse {
- for i in {1..50}; do
- adb shell input keyevent DPAD_DOWN
- sleep 10 # Tune and watch the channel for a while
- done;
-}
-
-function browse_heavily {
- for i in {1..60}; do
- echo "$(date '+%x %X') ======== Test #$i of 60 ========"
- clear_logcat
- for j in {1..60}; do
- adb shell input keyevent DPAD_DOWN
- sleep $(( $RANDOM % 3 )) # Sleep for 0 - 2 seconds
- done;
- measure_tuning_time
- done;
-}
-
-function clear_logcat {
- adb logcat -c
-}
-
-function measure_tuning_time {
- timeout 1 adb logcat -s TvInputSessionImpl | awk -f $(dirname $0)/measure-tuning-time.awk
-}
-
-function log_end {
- adb shell dumpsys meminfo -d --package com.android.tv.tuner > meminfo-end.txt
-}
-
-function stop_tv {
- # Stop TV by running other app (Settings)
- adb shell am start com.android.tv.settings/com.android.tv.settings.MainSettings
- restore_analytics_setting
-}
-
-function output {
- echo "Cut and paste this"
- sed -n 33,46p meminfo-begin.txt | cut -f 2 -d ":" -s | awk '{print $1}'
- sed -n 33,46p meminfo-end.txt | cut -f 2 -d ":" -s | awk '{print $1}'
-}
-
-function disable_analytics_report {
- tracker=$(adb shell getprop tv_use_tracker | tr -d '[[:space:]]')
- adb shell setprop tv_use_tracker false
-}
-
-function restore_analytics_setting {
- if [ "${tracker}" == "" ]; then
- adb shell setprop tv_use_tracker ""
- else
- adb shell setprop tv_use_tracker ${tracker}
- fi
-}
-
-function control_c {
- restore_analytics_setting
- echo "Exiting..."
- exit 1
-}
-
-# Entry point
-
-trap control_c SIGINT
-
-case "$1" in
- 1)
- echo "Runing test 1"
- start_tv
- log_begin
- clear_logcat
- browse # Repeat channel change for about 10 minutes
- measure_tuning_time
- log_end
- stop_tv
- output
- ;;
- 2)
- echo "Runing test 2"
- start_tv
- log_begin
- if [ "$2" != "" ]; then
- tune $2
- fi
- sleep 600 # 10 minutes
- log_end
- stop_tv
- output
- ;;
- 3)
- echo "Runing test 3"
- start_tv
- log_begin
- browse_heavily # Repeat channel change for about 3 hours
- log_end
- stop_tv
- output
- ;;
- *)
- echo "usage: usbtuner-test.sh <1|2|3> [channel]"
- exit 1
- ;;
-esac
-
diff --git a/tests/tunerunit/Android.mk b/tests/tunerunit/Android.mk
deleted file mode 100644
index 5c861641..00000000
--- a/tests/tunerunit/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-# Include all test java files.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := UsbTunerTvInputTests
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- android-support-test \
- tv-test-common \
-
-LOCAL_JAVA_LIBRARIES := \
- android.test.runner.stubs \
- android.test.base.stubs \
- android.test.mock.stubs \
-
-LOCAL_INSTRUMENTATION_FOR := LiveTv
-
-LOCAL_SDK_VERSION := current
-LOCAL_MIN_SDK_VERSION := 23 # M
-
-include $(BUILD_PACKAGE)
diff --git a/tests/tunerunit/AndroidManifest.xml b/tests/tunerunit/AndroidManifest.xml
deleted file mode 100644
index 0340121f..00000000
--- a/tests/tunerunit/AndroidManifest.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tv.tests" >
-
- <uses-sdk android:targetSdkVersion="23" android:minSdkVersion="23" />
-
- <instrumentation
- android:name="android.support.test.runner.AndroidJUnitRunner"
- android:label="Live Channel Unit Tests"
- android:targetPackage="com.android.tv.tuner" />
-
- <application android:label="TunerTest" >
- <uses-library android:name="android.test.runner" />
- </application>
-
-</manifest> \ No newline at end of file
diff --git a/tests/tunerunit/src/com/android/tv/tuner/exoplayer/buffer/VerySlowSampleChunk.java b/tests/tunerunit/src/com/android/tv/tuner/exoplayer/buffer/VerySlowSampleChunk.java
deleted file mode 100644
index ecfbb643..00000000
--- a/tests/tunerunit/src/com/android/tv/tuner/exoplayer/buffer/VerySlowSampleChunk.java
+++ /dev/null
@@ -1,51 +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.exoplayer.buffer;
-
-import android.os.SystemClock;
-import com.google.android.exoplayer.SampleHolder;
-import java.io.File;
-import java.io.IOException;
-
-public class VerySlowSampleChunk extends SampleChunk {
-
- public static class VerySlowSampleChunkCreator extends SampleChunkCreator {
- @Override
- public SampleChunk createSampleChunk(
- SamplePool samplePool,
- File file,
- long startPositionUs,
- ChunkCallback chunkCallback) {
- return new VerySlowSampleChunk(
- samplePool, file, startPositionUs, System.currentTimeMillis(), chunkCallback);
- }
- }
-
- private VerySlowSampleChunk(
- SamplePool samplePool,
- File file,
- long startPositionUs,
- long createdTimeMs,
- ChunkCallback chunkCallback) {
- super(samplePool, file, startPositionUs, createdTimeMs, chunkCallback);
- }
-
- @Override
- protected void write(SampleHolder sample, IoState state) throws IOException {
- SystemClock.sleep(10);
- super.write(sample, state);
- }
-}
diff --git a/tests/tunerunit/src/com/android/tv/tuner/exoplayer/tests/AssetDataSource.java b/tests/tunerunit/src/com/android/tv/tuner/exoplayer/tests/AssetDataSource.java
deleted file mode 100644
index b3defc55..00000000
--- a/tests/tunerunit/src/com/android/tv/tuner/exoplayer/tests/AssetDataSource.java
+++ /dev/null
@@ -1,124 +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 com.google.android.exoplayer.C;
-import com.google.android.exoplayer.upstream.DataSource;
-import com.google.android.exoplayer.upstream.DataSpec;
-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 boolean mOpened;
-
- /** 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);
- }
-
- mOpened = true;
- 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 {
- if (mInputStream != null) {
- try {
- mInputStream.close();
- } catch (IOException e) {
- throw new AssetDataSourceException(e);
- } finally {
- mInputStream = null;
- if (mOpened) {
- mOpened = false;
- }
- }
- }
- }
-}
diff --git a/tests/tunerunit/src/com/android/tv/tuner/exoplayer/tests/SampleSourceExtractorTest.java b/tests/tunerunit/src/com/android/tv/tuner/exoplayer/tests/SampleSourceExtractorTest.java
deleted file mode 100644
index a71366c7..00000000
--- a/tests/tunerunit/src/com/android/tv/tuner/exoplayer/tests/SampleSourceExtractorTest.java
+++ /dev/null
@@ -1,246 +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 android.content.Context;
-import android.net.Uri;
-import android.os.SystemClock;
-import android.support.test.filters.LargeTest;
-import android.test.InstrumentationTestCase;
-import android.util.Pair;
-import com.google.android.exoplayer.MediaFormat;
-import com.google.android.exoplayer.SampleHolder;
-import com.google.android.exoplayer.SampleSource;
-import com.google.android.exoplayer.upstream.DataSource;
-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.SampleChunk;
-import com.android.tv.tuner.exoplayer.buffer.VerySlowSampleChunk;
-import com.android.tv.tuner.tvinput.PlaybackBufferListener;
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.SortedMap;
-
-@LargeTest
-public class SampleSourceExtractorTest extends InstrumentationTestCase {
- // 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 static final int PREPARE_POLL_DELAY_MILLIS = 100;
- private static final String TEST_TS_ASSET_PATH = "asset:///capture_stream.ts";
-
- public void testTrickplayDisabled() throws Throwable {
- DataSource source = new AssetDataSource(getInstrumentation().getContext());
- MockPlaybackBufferListener listener = new MockPlaybackBufferListener();
- ExoPlayerSampleExtractor extractor =
- new ExoPlayerSampleExtractor(
- Uri.parse(TEST_TS_ASSET_PATH), source, null, listener, false);
-
- assertEquals("Trickplay should be disabled", listener.getLastState(), Boolean.FALSE);
-
- // Prepares the extractor.
- try {
- while (!extractor.prepare()) {
- Thread.sleep(PREPARE_POLL_DELAY_MILLIS);
- }
- } catch (IOException | InterruptedException 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);
- 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;
- }
- }
- Thread.yield();
- }
- }
-
- extractor.release();
- }
-
- public void testDiskTooSlowTrickplayDisabled() throws Throwable {
- StorageManager storageManager =
- new StubStorageManager(getInstrumentation().getTargetContext());
- BufferManager bufferManager =
- new BufferManager(
- storageManager, new VerySlowSampleChunk.VerySlowSampleChunkCreator());
- bufferManager.setMinimumSampleSizeForSpeedCheck(0);
- DataSource source = new AssetDataSource(getInstrumentation().getContext());
- MockPlaybackBufferListener listener = new MockPlaybackBufferListener();
- ExoPlayerSampleExtractor extractor =
- new ExoPlayerSampleExtractor(
- Uri.parse(TEST_TS_ASSET_PATH), source, bufferManager, listener, false);
-
- assertEquals(
- "Trickplay should be enabled at the first", listener.getLastState(), Boolean.TRUE);
-
- // Prepares the extractor.
- try {
- while (!extractor.prepare()) {
- Thread.sleep(PREPARE_POLL_DELAY_MILLIS);
- }
- } catch (IOException | InterruptedException 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;
- }
- }
- Thread.yield();
- }
- }
-
- extractor.release();
-
- // Sleep for synchronization.
- SystemClock.sleep(1000);
-
- assertEquals(
- "Disk too slow event should be reported", listener.isReportedDiskTooSlow(), true);
- }
-
- 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.
- }
- }
-
- public 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/tests/unit/src/com/android/tv/BaseMainActivityTestCase.java b/tests/unit/src/com/android/tv/BaseMainActivityTestCase.java
index 84283d90..4e280d1a 100644
--- a/tests/unit/src/com/android/tv/BaseMainActivityTestCase.java
+++ b/tests/unit/src/com/android/tv/BaseMainActivityTestCase.java
@@ -23,7 +23,7 @@ import android.support.test.rule.ActivityTestRule;
import android.text.TextUtils;
import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
-import com.android.tv.testing.data.ChannelInfo;
+import com.android.tv.testing.ChannelInfo;
import com.android.tv.testing.testinput.ChannelStateData;
import com.android.tv.testing.testinput.TestInputControlConnection;
import com.android.tv.testing.testinput.TestInputControlUtils;
diff --git a/tests/unit/src/com/android/tv/CurrentPositionMediatorTest.java b/tests/unit/src/com/android/tv/CurrentPositionMediatorTest.java
index 1c6a0e3b..6a48e635 100644
--- a/tests/unit/src/com/android/tv/CurrentPositionMediatorTest.java
+++ b/tests/unit/src/com/android/tv/CurrentPositionMediatorTest.java
@@ -18,17 +18,15 @@ package com.android.tv;
import static com.android.tv.TimeShiftManager.INVALID_TIME;
import static com.android.tv.TimeShiftManager.REQUEST_TIMEOUT_MS;
-import static com.google.common.truth.Truth.assertWithMessage;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.MediumTest;
-import android.support.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
@MediumTest
-@RunWith(AndroidJUnit4.class)
public class CurrentPositionMediatorTest extends BaseMainActivityTestCase {
private TimeShiftManager.CurrentPositionMediator mMediator;
@@ -52,12 +50,8 @@ 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)
- .isNotSameAs(INVALID_TIME);
- assertWithMessage("Current position")
- .that(mMediator.mCurrentPositionMs)
- .isEqualTo(seekToTimeMs);
+ assertNotSame("Seek request time", INVALID_TIME, mMediator.mSeekRequestTimeMs);
+ assertEquals("Current position", seekToTimeMs, mMediator.mCurrentPositionMs);
}
@UiThreadTest
@@ -67,15 +61,9 @@ public class CurrentPositionMediatorTest extends BaseMainActivityTestCase {
long newCurrentTimeMs = seekToTimeMs + REQUEST_TIMEOUT_MS;
mMediator.onSeekRequested(seekToTimeMs);
mMediator.onCurrentPositionChanged(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);
+ assertNotSame("Seek request time", INVALID_TIME, mMediator.mSeekRequestTimeMs);
+ assertNotSame("Current position", seekToTimeMs, mMediator.mCurrentPositionMs);
+ assertNotSame("Current position", newCurrentTimeMs, mMediator.mCurrentPositionMs);
}
@UiThreadTest
@@ -90,11 +78,7 @@ public class CurrentPositionMediatorTest extends BaseMainActivityTestCase {
private void assertCurrentPositionMediator(
long expectedSeekRequestTimeMs, long expectedCurrentPositionMs) {
- assertWithMessage("Seek request time")
- .that(mMediator.mSeekRequestTimeMs)
- .isEqualTo(expectedSeekRequestTimeMs);
- assertWithMessage("Current position")
- .that(mMediator.mCurrentPositionMs)
- .isEqualTo(expectedCurrentPositionMs);
+ assertEquals("Seek request time", expectedSeekRequestTimeMs, mMediator.mSeekRequestTimeMs);
+ assertEquals("Current position", expectedCurrentPositionMs, mMediator.mCurrentPositionMs);
}
}
diff --git a/tests/unit/src/com/android/tv/FeaturesTest.java b/tests/unit/src/com/android/tv/FeaturesTest.java
index e19f4b7c..b6be6866 100644
--- a/tests/unit/src/com/android/tv/FeaturesTest.java
+++ b/tests/unit/src/com/android/tv/FeaturesTest.java
@@ -16,21 +16,18 @@
package com.android.tv;
-import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertFalse;
import android.support.test.filters.SmallTest;
-import android.support.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();
+ assertFalse(Features.TEST_FEATURE.isEnabled(null));
}
}
diff --git a/tests/unit/src/com/android/tv/MainActivityTest.java b/tests/unit/src/com/android/tv/MainActivityTest.java
index d28a8cd2..00aa79d8 100644
--- a/tests/unit/src/com/android/tv/MainActivityTest.java
+++ b/tests/unit/src/com/android/tv/MainActivityTest.java
@@ -16,11 +16,10 @@
package com.android.tv;
import static android.support.test.InstrumentationRegistry.getInstrumentation;
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import android.support.test.filters.MediumTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.View;
import android.widget.TextView;
import com.android.tv.data.Channel;
@@ -28,17 +27,15 @@ import com.android.tv.testing.testinput.TvTestInputConstants;
import com.android.tv.ui.ChannelBannerView;
import java.util.List;
import org.junit.Test;
-import org.junit.runner.RunWith;
/** Tests for {@link MainActivity}. */
@MediumTest
-@RunWith(AndroidJUnit4.class)
public class MainActivityTest extends BaseMainActivityTestCase {
@Test
public void testInitialConditions() {
waitUntilChannelLoadingFinish();
List<Channel> channelList = mActivity.getChannelDataManager().getChannelList();
- assertWithMessage("Expected at least one channel").that(channelList.size() > 0).isTrue();
+ assertTrue("Expected at least one channel", channelList.size() > 0);
}
@Test
@@ -71,7 +68,7 @@ public class MainActivityTest extends BaseMainActivityTestCase {
private void assertChannelName(String displayName) {
TextView channelNameView = (TextView) mActivity.findViewById(R.id.channel_name);
- assertWithMessage("Channel Name").that(channelNameView.getText()).isEqualTo(displayName);
+ assertEquals("Channel Name", displayName, channelNameView.getText());
}
private void assertProgramGuide(boolean isShown) {
@@ -89,7 +86,7 @@ public class MainActivityTest extends BaseMainActivityTestCase {
assertViewIsShown(
expectedClass.getSimpleName(), R.id.scene_transition_common, expectedShown);
if (v != null) {
- assertThat(v.getClass()).isEqualTo(expectedClass);
+ assertEquals(expectedClass, v.getClass());
}
return v;
}
@@ -103,7 +100,7 @@ public class MainActivityTest extends BaseMainActivityTestCase {
return null;
}
}
- assertWithMessage(viewName + " shown").that(view.isShown()).isEqualTo(expected);
+ assertEquals(viewName + " shown", expected, view.isShown());
return view;
}
}
diff --git a/tests/unit/src/com/android/tv/TimeShiftManagerTest.java b/tests/unit/src/com/android/tv/TimeShiftManagerTest.java
index e30a9226..7ad6bdbf 100644
--- a/tests/unit/src/com/android/tv/TimeShiftManagerTest.java
+++ b/tests/unit/src/com/android/tv/TimeShiftManagerTest.java
@@ -22,16 +22,13 @@ import static com.android.tv.TimeShiftManager.TIME_SHIFT_ACTION_ID_JUMP_TO_PREVI
import static com.android.tv.TimeShiftManager.TIME_SHIFT_ACTION_ID_PAUSE;
import static com.android.tv.TimeShiftManager.TIME_SHIFT_ACTION_ID_PLAY;
import static com.android.tv.TimeShiftManager.TIME_SHIFT_ACTION_ID_REWIND;
-import static com.google.common.truth.Truth.assertWithMessage;
+import static org.junit.Assert.assertEquals;
import android.support.test.filters.MediumTest;
-import android.support.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
@MediumTest
-@RunWith(AndroidJUnit4.class)
public class TimeShiftManagerTest extends BaseMainActivityTestCase {
private TimeShiftManager mTimeShiftManager;
@@ -94,23 +91,29 @@ public class TimeShiftManagerTest extends BaseMainActivityTestCase {
boolean fastForwardEnabled,
boolean jumpToPreviousEnabled,
boolean jumpToNextEnabled) {
- assertWithMessage("Play Action")
- .that(mTimeShiftManager.isActionEnabled(TIME_SHIFT_ACTION_ID_PLAY))
- .isEqualTo(playEnabled);
- assertWithMessage("Pause Action")
- .that(mTimeShiftManager.isActionEnabled(TIME_SHIFT_ACTION_ID_PAUSE))
- .isEqualTo(pauseEnabled);
- assertWithMessage("Rewind Action")
- .that(mTimeShiftManager.isActionEnabled(TIME_SHIFT_ACTION_ID_REWIND))
- .isEqualTo(rewindEnabled);
- assertWithMessage("Fast Forward Action")
- .that(mTimeShiftManager.isActionEnabled(TIME_SHIFT_ACTION_ID_FAST_FORWARD))
- .isEqualTo(fastForwardEnabled);
- assertWithMessage("Jump To Previous Action")
- .that(mTimeShiftManager.isActionEnabled(TIME_SHIFT_ACTION_ID_JUMP_TO_PREVIOUS))
- .isEqualTo(jumpToPreviousEnabled);
- assertWithMessage("Jump To Next Action")
- .that(mTimeShiftManager.isActionEnabled(TIME_SHIFT_ACTION_ID_JUMP_TO_NEXT))
- .isEqualTo(jumpToNextEnabled);
+ assertEquals(
+ "Play Action",
+ playEnabled,
+ mTimeShiftManager.isActionEnabled(TIME_SHIFT_ACTION_ID_PLAY));
+ assertEquals(
+ "Pause Action",
+ pauseEnabled,
+ mTimeShiftManager.isActionEnabled(TIME_SHIFT_ACTION_ID_PAUSE));
+ assertEquals(
+ "Rewind Action",
+ rewindEnabled,
+ mTimeShiftManager.isActionEnabled(TIME_SHIFT_ACTION_ID_REWIND));
+ assertEquals(
+ "Fast Forward Action",
+ fastForwardEnabled,
+ mTimeShiftManager.isActionEnabled(TIME_SHIFT_ACTION_ID_FAST_FORWARD));
+ assertEquals(
+ "Jump To Previous Action",
+ jumpToPreviousEnabled,
+ mTimeShiftManager.isActionEnabled(TIME_SHIFT_ACTION_ID_JUMP_TO_PREVIOUS));
+ assertEquals(
+ "Jump To Next Action",
+ jumpToNextEnabled,
+ mTimeShiftManager.isActionEnabled(TIME_SHIFT_ACTION_ID_JUMP_TO_NEXT));
}
}
diff --git a/tests/unit/src/com/android/tv/data/ChannelDataManagerTest.java b/tests/unit/src/com/android/tv/data/ChannelDataManagerTest.java
index 9b81f5d5..0adfd1be 100644
--- a/tests/unit/src/com/android/tv/data/ChannelDataManagerTest.java
+++ b/tests/unit/src/com/android/tv/data/ChannelDataManagerTest.java
@@ -18,8 +18,9 @@ package com.android.tv.data;
import static android.support.test.InstrumentationRegistry.getInstrumentation;
import static android.support.test.InstrumentationRegistry.getTargetContext;
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import android.content.ContentProvider;
import android.content.ContentUris;
@@ -31,7 +32,6 @@ import android.media.tv.TvContract;
import android.media.tv.TvContract.Channels;
import android.net.Uri;
import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.test.MoreAsserts;
import android.test.mock.MockContentProvider;
import android.test.mock.MockContentResolver;
@@ -39,8 +39,8 @@ import android.test.mock.MockCursor;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
-import com.android.tv.testing.constants.Constants;
-import com.android.tv.testing.data.ChannelInfo;
+import com.android.tv.testing.ChannelInfo;
+import com.android.tv.testing.Constants;
import com.android.tv.util.TvInputManagerHelper;
import java.util.ArrayList;
import java.util.Arrays;
@@ -50,7 +50,6 @@ import java.util.concurrent.TimeUnit;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.mockito.Mockito;
@@ -61,7 +60,6 @@ import org.mockito.Mockito;
* the methods of {@link ChannelDataManager} should be called from the UI thread.
*/
@SmallTest
-@RunWith(AndroidJUnit4.class)
public class ChannelDataManagerTest {
private static final boolean DEBUG = false;
private static final String TAG = "ChannelDataManagerTest";
@@ -79,9 +77,7 @@ public class ChannelDataManagerTest {
@Before
public void setUp() {
- assertWithMessage("More than 2 channels to test")
- .that(Constants.UNIT_TEST_CHANNEL_COUNT > 2)
- .isTrue();
+ assertTrue("More than 2 channels to test", Constants.UNIT_TEST_CHANNEL_COUNT > 2);
mContentProvider = new FakeContentProvider(getTargetContext());
mContentResolver = new FakeContentResolver();
@@ -125,8 +121,7 @@ public class ChannelDataManagerTest {
mChannelDataManager.start();
}
});
- assertThat(mListener.loadFinishedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS))
- .isTrue();
+ assertTrue(mListener.loadFinishedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS));
}
private void restart() throws InterruptedException {
@@ -145,7 +140,7 @@ public class ChannelDataManagerTest {
@Test
public void testIsDbLoadFinished() throws InterruptedException {
startAndWaitForComplete();
- assertThat(mChannelDataManager.isDbLoadFinished()).isTrue();
+ assertTrue(mChannelDataManager.isDbLoadFinished());
}
/**
@@ -157,8 +152,7 @@ public class ChannelDataManagerTest {
startAndWaitForComplete();
// Test {@link ChannelDataManager#getChannelCount}
- assertThat(mChannelDataManager.getChannelCount())
- .isEqualTo(Constants.UNIT_TEST_CHANNEL_COUNT);
+ assertEquals(Constants.UNIT_TEST_CHANNEL_COUNT, mChannelDataManager.getChannelCount());
// Test {@link ChannelDataManager#getChannelList}
List<ChannelInfo> channelInfoList = new ArrayList<>();
@@ -169,18 +163,19 @@ public class ChannelDataManagerTest {
for (Channel channel : channelList) {
boolean found = false;
for (ChannelInfo channelInfo : channelInfoList) {
- if (TextUtils.equals(channelInfo.name, channel.getDisplayName())) {
+ if (TextUtils.equals(channelInfo.name, channel.getDisplayName())
+ && TextUtils.equals(channelInfo.name, channel.getDisplayName())) {
found = true;
channelInfoList.remove(channelInfo);
break;
}
}
- assertWithMessage("Cannot find (" + channel + ")").that(found).isTrue();
+ assertTrue("Cannot find (" + channel + ")", found);
}
// Test {@link ChannelDataManager#getChannelIndex()}
for (Channel channel : channelList) {
- assertThat(mChannelDataManager.getChannel(channel.getId())).isEqualTo(channel);
+ assertEquals(channel, mChannelDataManager.getChannel(channel.getId()));
}
}
@@ -189,7 +184,7 @@ public class ChannelDataManagerTest {
public void testGetChannels_noChannels() throws InterruptedException {
mContentProvider.clear();
startAndWaitForComplete();
- assertThat(mChannelDataManager.getChannelCount()).isEqualTo(0);
+ assertEquals(0, mChannelDataManager.getChannelCount());
}
/**
@@ -205,9 +200,9 @@ public class ChannelDataManagerTest {
List<Channel> browsableChannelList = mChannelDataManager.getBrowsableChannelList();
for (Channel browsableChannel : browsableChannelList) {
boolean found = channelList.remove(browsableChannel);
- assertWithMessage("Cannot find (" + browsableChannel + ")").that(found).isTrue();
+ assertTrue("Cannot find (" + browsableChannel + ")", found);
}
- assertThat(channelList).isEmpty();
+ assertEquals(0, channelList.size());
// Prepare for next tests.
channelList = mChannelDataManager.getChannelList();
@@ -218,8 +213,8 @@ public class ChannelDataManagerTest {
// Test {@link ChannelDataManager#updateBrowsable} & notification.
mChannelDataManager.updateBrowsable(channel1.getId(), false, false);
- assertThat(mListener.channelBrowsableChangedCalled).isTrue();
- assertThat(mChannelDataManager.getBrowsableChannelList()).doesNotContain(channel1);
+ assertTrue(mListener.channelBrowsableChangedCalled);
+ assertFalse(mChannelDataManager.getBrowsableChannelList().contains(channel1));
MoreAsserts.assertContentsInAnyOrder(channelListener.updatedChannels, channel1);
channelListener.reset();
@@ -229,8 +224,8 @@ public class ChannelDataManagerTest {
mChannelDataManager.applyUpdatedValuesToDb();
restart();
browsableChannelList = mChannelDataManager.getBrowsableChannelList();
- assertThat(browsableChannelList).hasSize(Constants.UNIT_TEST_CHANNEL_COUNT - 1);
- assertThat(browsableChannelList).doesNotContain(channel1);
+ assertEquals(Constants.UNIT_TEST_CHANNEL_COUNT - 1, browsableChannelList.size());
+ assertFalse(browsableChannelList.contains(channel1));
}
/**
@@ -254,10 +249,10 @@ public class ChannelDataManagerTest {
mChannelDataManager.updateBrowsable(channel1.getId(), false, true);
mChannelDataManager.updateBrowsable(channel2.getId(), false, true);
mChannelDataManager.updateBrowsable(channel1.getId(), true, true);
- assertThat(mListener.channelBrowsableChangedCalled).isFalse();
+ assertFalse(mListener.channelBrowsableChangedCalled);
List<Channel> browsableChannelList = mChannelDataManager.getBrowsableChannelList();
- assertThat(browsableChannelList).contains(channel1);
- assertThat(browsableChannelList).doesNotContain(channel2);
+ assertTrue(browsableChannelList.contains(channel1));
+ assertFalse(browsableChannelList.contains(channel2));
// Test {@link ChannelDataManager#applyUpdatedValuesToDb}
// Disable the update notification to avoid the unwanted call of "onLoadFinished".
@@ -265,8 +260,8 @@ public class ChannelDataManagerTest {
mChannelDataManager.applyUpdatedValuesToDb();
restart();
browsableChannelList = mChannelDataManager.getBrowsableChannelList();
- assertThat(browsableChannelList).hasSize(Constants.UNIT_TEST_CHANNEL_COUNT - 1);
- assertThat(browsableChannelList).doesNotContain(channel2);
+ assertEquals(Constants.UNIT_TEST_CHANNEL_COUNT - 1, browsableChannelList.size());
+ assertFalse(browsableChannelList.contains(channel2));
}
/**
@@ -280,7 +275,7 @@ public class ChannelDataManagerTest {
// Test if all channels aren't locked at the first time.
List<Channel> channelList = mChannelDataManager.getChannelList();
for (Channel channel : channelList) {
- assertWithMessage(channel + " is locked").that(channel.isLocked()).isFalse();
+ assertFalse(channel + " is locked", channel.isLocked());
}
// Prepare for next tests.
@@ -288,14 +283,14 @@ public class ChannelDataManagerTest {
// Test {@link ChannelDataManager#updateLocked}
mChannelDataManager.updateLocked(channel.getId(), true);
- assertThat(mChannelDataManager.getChannel(channel.getId()).isLocked()).isTrue();
+ assertTrue(mChannelDataManager.getChannel(channel.getId()).isLocked());
// Test {@link ChannelDataManager#applyUpdatedValuesToDb}.
// Disable the update notification to avoid the unwanted call of "onLoadFinished".
mContentResolver.mNotifyDisabled = true;
mChannelDataManager.applyUpdatedValuesToDb();
restart();
- assertThat(mChannelDataManager.getChannel(channel.getId()).isLocked()).isTrue();
+ assertTrue(mChannelDataManager.getChannel(channel.getId()).isLocked());
// Cleanup
mChannelDataManager.updateLocked(channel.getId(), false);
@@ -312,10 +307,9 @@ public class ChannelDataManagerTest {
ChannelInfo testChannelInfo = ChannelInfo.create(getTargetContext(), (int) testChannelId);
testChannelId = Constants.UNIT_TEST_CHANNEL_COUNT + 1;
mContentProvider.simulateInsert(testChannelInfo);
- assertThat(mListener.channelListUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS))
- .isTrue();
- assertThat(mChannelDataManager.getChannelCount())
- .isEqualTo(Constants.UNIT_TEST_CHANNEL_COUNT + 1);
+ assertTrue(
+ mListener.channelListUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS));
+ assertEquals(Constants.UNIT_TEST_CHANNEL_COUNT + 1, mChannelDataManager.getChannelCount());
// Test channel update
mListener.reset();
@@ -324,41 +318,35 @@ public class ChannelDataManagerTest {
mChannelDataManager.addChannelListener(testChannelId, channelListener);
String newName = testChannelInfo.name + "_test";
mContentProvider.simulateUpdate(testChannelId, newName);
- assertThat(mListener.channelListUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS))
- .isTrue();
- assertThat(
- channelListener.channelChangedLatch.await(
- WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS))
- .isTrue();
- assertThat(channelListener.removedChannels).isEmpty();
- assertThat(channelListener.updatedChannels).hasSize(1);
+ assertTrue(
+ mListener.channelListUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS));
+ assertTrue(
+ channelListener.channelChangedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS));
+ assertEquals(0, channelListener.removedChannels.size());
+ assertEquals(1, channelListener.updatedChannels.size());
Channel updatedChannel = channelListener.updatedChannels.get(0);
- assertThat(updatedChannel.getId()).isEqualTo(testChannelId);
- assertThat(updatedChannel.getDisplayNumber()).isEqualTo(testChannelInfo.number);
- assertThat(updatedChannel.getDisplayName()).isEqualTo(newName);
- assertThat(mChannelDataManager.getChannelCount())
- .isEqualTo(Constants.UNIT_TEST_CHANNEL_COUNT + 1);
+ assertEquals(testChannelId, updatedChannel.getId());
+ assertEquals(testChannelInfo.number, updatedChannel.getDisplayNumber());
+ assertEquals(newName, updatedChannel.getDisplayName());
+ assertEquals(Constants.UNIT_TEST_CHANNEL_COUNT + 1, mChannelDataManager.getChannelCount());
// Test channel remove.
mListener.reset();
channelListener.reset();
mContentProvider.simulateDelete(testChannelId);
- assertThat(mListener.channelListUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS))
- .isTrue();
- assertThat(
- channelListener.channelChangedLatch.await(
- WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS))
- .isTrue();
- assertThat(channelListener.removedChannels).hasSize(1);
- assertThat(channelListener.updatedChannels).isEmpty();
+ assertTrue(
+ mListener.channelListUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS));
+ assertTrue(
+ channelListener.channelChangedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS));
+ assertEquals(1, channelListener.removedChannels.size());
+ assertEquals(0, channelListener.updatedChannels.size());
Channel removedChannel = channelListener.removedChannels.get(0);
- assertThat(removedChannel.getDisplayName()).isEqualTo(newName);
- assertThat(removedChannel.getDisplayNumber()).isEqualTo(testChannelInfo.number);
- assertThat(mChannelDataManager.getChannelCount())
- .isEqualTo(Constants.UNIT_TEST_CHANNEL_COUNT);
+ assertEquals(newName, removedChannel.getDisplayName());
+ assertEquals(testChannelInfo.number, removedChannel.getDisplayNumber());
+ assertEquals(Constants.UNIT_TEST_CHANNEL_COUNT, mChannelDataManager.getChannelCount());
}
- private static class ChannelInfoWrapper {
+ private class ChannelInfoWrapper {
public ChannelInfo channelInfo;
public boolean browsable;
public boolean locked;
@@ -525,9 +513,9 @@ public class ChannelDataManagerTest {
}
private void assertChannelUri(Uri uri) {
- assertWithMessage("Uri(" + uri + ") isn't channel uri")
- .that(uri.toString().startsWith(Channels.CONTENT_URI.toString()))
- .isTrue();
+ assertTrue(
+ "Uri(" + uri + ") isn't channel uri",
+ uri.toString().startsWith(Channels.CONTENT_URI.toString()));
}
public void clear() {
@@ -548,7 +536,7 @@ public class ChannelDataManagerTest {
}
private class FakeCursor extends MockCursor {
- private final String[] allColumns = {
+ private final String[] ALL_COLUMNS = {
Channels._ID,
Channels.COLUMN_DISPLAY_NAME,
Channels.COLUMN_DISPLAY_NUMBER,
@@ -562,7 +550,7 @@ public class ChannelDataManagerTest {
private int mPosition;
public FakeCursor(String[] columns) {
- mColumns = (columns == null) ? allColumns : columns;
+ mColumns = (columns == null) ? ALL_COLUMNS : columns;
mPosition = -1;
}
@@ -587,7 +575,6 @@ public class ChannelDataManagerTest {
switch (columnName) {
case Channels._ID:
return mContentProvider.keyAt(mPosition);
- default: // fall out
}
if (DEBUG) {
Log.d(TAG, "Column (" + columnName + ") is ignored in getLong()");
@@ -608,7 +595,6 @@ public class ChannelDataManagerTest {
return DUMMY_INPUT_ID;
case Channels.COLUMN_VIDEO_FORMAT:
return channel.channelInfo.getVideoFormat();
- default: // fall out
}
if (DEBUG) {
Log.d(TAG, "Column (" + columnName + ") is ignored in getString()");
@@ -627,7 +613,6 @@ public class ChannelDataManagerTest {
return channel.browsable ? 1 : 0;
case COLUMN_LOCKED:
return channel.locked ? 1 : 0;
- default: // fall out
}
if (DEBUG) {
Log.d(TAG, "Column (" + columnName + ") is ignored in getInt()");
@@ -651,7 +636,7 @@ public class ChannelDataManagerTest {
}
}
- private static class TestChannelDataManagerListener implements ChannelDataManager.Listener {
+ private class TestChannelDataManagerListener implements ChannelDataManager.Listener {
public CountDownLatch loadFinishedLatch = new CountDownLatch(1);
public CountDownLatch channelListUpdatedLatch = new CountDownLatch(1);
public boolean channelBrowsableChangedCalled;
@@ -678,7 +663,7 @@ public class ChannelDataManagerTest {
}
}
- private static class TestChannelDataManagerChannelListener
+ private class TestChannelDataManagerChannelListener
implements ChannelDataManager.ChannelListener {
public CountDownLatch channelChangedLatch = new CountDownLatch(1);
public final List<Channel> removedChannels = new ArrayList<>();
diff --git a/tests/unit/src/com/android/tv/data/ChannelNumberTest.java b/tests/unit/src/com/android/tv/data/ChannelNumberTest.java
new file mode 100644
index 00000000..86d27efa
--- /dev/null
+++ b/tests/unit/src/com/android/tv/data/ChannelNumberTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.tv.data;
+
+import static com.android.tv.data.ChannelNumber.parseChannelNumber;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import android.support.test.filters.SmallTest;
+import com.android.tv.testing.ComparableTester;
+import org.junit.Test;
+
+/** Tests for {@link ChannelNumber}. */
+@SmallTest
+public class ChannelNumberTest {
+ /** Test method for {@link ChannelNumber#ChannelNumber()}. */
+ @Test
+ public void testChannelNumber() {
+ assertChannelEquals(new ChannelNumber(), "", false, "");
+ }
+
+ /**
+ * Test method for {@link
+ * com.android.tv.data.ChannelNumber#parseChannelNumber(java.lang.String)}.
+ */
+ @Test
+ public void testParseChannelNumber() {
+ assertNull(parseChannelNumber(""));
+ assertNull(parseChannelNumber("-"));
+ assertNull(parseChannelNumber("abcd12"));
+ assertNull(parseChannelNumber("12abcd"));
+ assertNull(parseChannelNumber("-12"));
+ assertChannelEquals(parseChannelNumber("1"), "1", false, "");
+ assertChannelEquals(parseChannelNumber("1234-4321"), "1234", true, "4321");
+ assertChannelEquals(parseChannelNumber("3-4"), "3", true, "4");
+ assertChannelEquals(parseChannelNumber("5-6"), "5", true, "6");
+ }
+
+ /** Test method for {@link ChannelNumber#compareTo(com.android.tv.data.ChannelNumber)}. */
+ @Test
+ public void testCompareTo() {
+ new ComparableTester<ChannelNumber>()
+ .addEquivalentGroup(parseChannelNumber("1"), parseChannelNumber("1"))
+ .addEquivalentGroup(parseChannelNumber("2"))
+ .addEquivalentGroup(parseChannelNumber("2-1"))
+ .addEquivalentGroup(parseChannelNumber("2-2"))
+ .addEquivalentGroup(parseChannelNumber("2-10"))
+ .addEquivalentGroup(parseChannelNumber("3"))
+ .addEquivalentGroup(parseChannelNumber("4"), parseChannelNumber("4-0"))
+ .addEquivalentGroup(parseChannelNumber("10"))
+ .addEquivalentGroup(parseChannelNumber("100"))
+ .test();
+ }
+
+ /** Test method for {@link ChannelNumber#compare(java.lang.String, java.lang.String)}. */
+ @Test
+ public void testCompare() {
+ // Only need to test nulls, the reset is tested by testCompareTo
+ assertEquals("compareTo(null,null)", 0, ChannelNumber.compare(null, null));
+ assertEquals("compareTo(1,1)", 0, ChannelNumber.compare("1", "1"));
+ assertEquals("compareTo(null,1)<0", true, ChannelNumber.compare(null, "1") < 0);
+ assertEquals("compareTo(mal-formatted,1)<0", true, ChannelNumber.compare("abcd", "1") < 0);
+ assertEquals("compareTo(mal-formatted,1)<0", true, ChannelNumber.compare(".4", "1") < 0);
+ assertEquals("compareTo(1,null)>0", true, ChannelNumber.compare("1", null) > 0);
+ }
+
+ private void assertChannelEquals(
+ ChannelNumber actual,
+ String expectedMajor,
+ boolean expectedHasDelimiter,
+ String expectedMinor) {
+ assertEquals(actual + " major", actual.majorNumber, expectedMajor);
+ assertEquals(actual + " hasDelimiter", actual.hasDelimiter, expectedHasDelimiter);
+ assertEquals(actual + " minor", actual.minorNumber, expectedMinor);
+ }
+}
diff --git a/tests/unit/src/com/android/tv/data/ChannelTest.java b/tests/unit/src/com/android/tv/data/ChannelTest.java
index 1f30a819..a7bac9fb 100644
--- a/tests/unit/src/com/android/tv/data/ChannelTest.java
+++ b/tests/unit/src/com/android/tv/data/ChannelTest.java
@@ -16,8 +16,7 @@
package com.android.tv.data;
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
+import static org.junit.Assert.assertEquals;
import android.content.ComponentName;
import android.content.Context;
@@ -26,13 +25,11 @@ import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import com.android.tv.testing.ComparatorTester;
import com.android.tv.util.TvInputManagerHelper;
import java.util.Comparator;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
@@ -40,20 +37,17 @@ import org.mockito.stubbing.Answer;
/** Tests for {@link Channel}. */
@SmallTest
-@RunWith(AndroidJUnit4.class)
public class ChannelTest {
// Used for testing TV inputs with invalid input package. This could happen when a TV input is
// uninstalled while drawing an app link card.
- private static final String INVALID_TV_INPUT_PACKAGE_NAME =
- "com.android.tv.invalid_tv_input";
+ private static final String INVALID_TV_INPUT_PACKAGE_NAME = "com.android.tv.invalid_tv_input";
// Used for testing TV inputs defined inside of Live TV.
private static final String LIVE_CHANNELS_PACKAGE_NAME = "com.android.tv";
// Used for testing a TV input which doesn't have its leanback launcher activity.
private static final String NONE_LEANBACK_TV_INPUT_PACKAGE_NAME =
"com.android.tv.none_leanback_tv_input";
// Used for testing a TV input which has its leanback launcher activity.
- private static final String LEANBACK_TV_INPUT_PACKAGE_NAME =
- "com.android.tv.leanback_tv_input";
+ private static final String LEANBACK_TV_INPUT_PACKAGE_NAME = "com.android.tv.leanback_tv_input";
private static final String TEST_APP_LINK_TEXT = "test_app_link_text";
private static final String PARTNER_INPUT_ID = "partner";
private static final ActivityInfo TEST_ACTIVITY_INFO = new ActivityInfo();
@@ -133,7 +127,6 @@ public class ChannelTest {
assertAppLinkType(Channel.APP_LINK_TYPE_APP, LEANBACK_TV_INPUT_PACKAGE_NAME, null, null);
}
- @Test
public void testGetAppLinkType_NoText_InvalidIntent() {
assertAppLinkType(
Channel.APP_LINK_TYPE_NONE, INVALID_TV_INPUT_PACKAGE_NAME, null, mInvalidIntent);
@@ -148,7 +141,6 @@ public class ChannelTest {
Channel.APP_LINK_TYPE_APP, LEANBACK_TV_INPUT_PACKAGE_NAME, null, mInvalidIntent);
}
- @Test
public void testGetAppLinkType_NoText_ValidIntent() {
assertAppLinkType(
Channel.APP_LINK_TYPE_NONE, INVALID_TV_INPUT_PACKAGE_NAME, null, mValidIntent);
@@ -163,7 +155,6 @@ public class ChannelTest {
Channel.APP_LINK_TYPE_APP, LEANBACK_TV_INPUT_PACKAGE_NAME, null, mValidIntent);
}
- @Test
public void testGetAppLinkType_HasText_NoIntent() {
assertAppLinkType(
Channel.APP_LINK_TYPE_NONE,
@@ -184,7 +175,6 @@ public class ChannelTest {
null);
}
- @Test
public void testGetAppLinkType_HasText_InvalidIntent() {
assertAppLinkType(
Channel.APP_LINK_TYPE_NONE,
@@ -208,7 +198,6 @@ public class ChannelTest {
mInvalidIntent);
}
- @Test
public void testGetAppLinkType_HasText_ValidIntent() {
assertAppLinkType(
Channel.APP_LINK_TYPE_CHANNEL,
@@ -245,13 +234,14 @@ public class ChannelTest {
? null
: appLinkIntent.toUri(Intent.URI_INTENT_SCHEME))
.build();
- assertWithMessage("Unexpected app-link type for for " + testChannel)
- .that(testChannel.getAppLinkType(mMockContext))
- .isEqualTo(expectedType);
+ assertEquals(
+ "Unexpected app-link type for for " + testChannel,
+ expectedType,
+ testChannel.getAppLinkType(mMockContext));
}
- @Test
public void testComparator() {
+
TvInputManagerHelper manager = Mockito.mock(TvInputManagerHelper.class);
Mockito.when(manager.isPartnerInput(Matchers.anyString()))
.thenAnswer(
@@ -303,7 +293,6 @@ public class ChannelTest {
* <p>Sort partner inputs first, then sort by input label, then by input id. See <a
* href="http://b/23031603">b/23031603</a>.
*/
- @Test
public void testComparatorLabel() {
TvInputManagerHelper manager = Mockito.mock(TvInputManagerHelper.class);
Mockito.when(manager.isPartnerInput(Matchers.anyString()))
@@ -332,7 +321,6 @@ public class ChannelTest {
comparatorTester.test();
}
- @Test
public void testNormalizeChannelNumber() {
assertNormalizedDisplayNumber(null, null);
assertNormalizedDisplayNumber("", "");
@@ -353,10 +341,10 @@ public class ChannelTest {
}
private void assertNormalizedDisplayNumber(String displayNumber, String normalized) {
- assertThat(Channel.normalizeDisplayNumber(displayNumber)).isEqualTo(normalized);
+ assertEquals(normalized, Channel.normalizeDisplayNumber(displayNumber));
}
- private static final class TestChannelComparator extends Channel.DefaultComparator {
+ private class TestChannelComparator extends Channel.DefaultComparator {
public TestChannelComparator(TvInputManagerHelper manager) {
super(null, manager);
}
@@ -367,8 +355,7 @@ public class ChannelTest {
}
}
- private static final class ChannelComparatorWithDescriptionAsLabel
- extends Channel.DefaultComparator {
+ private static class ChannelComparatorWithDescriptionAsLabel extends Channel.DefaultComparator {
public ChannelComparatorWithDescriptionAsLabel(TvInputManagerHelper manager) {
super(null, manager);
}
diff --git a/tests/unit/src/com/android/tv/data/GenreItemTest.java b/tests/unit/src/com/android/tv/data/GenreItemTest.java
index 02bf4b30..dbf99eac 100644
--- a/tests/unit/src/com/android/tv/data/GenreItemTest.java
+++ b/tests/unit/src/com/android/tv/data/GenreItemTest.java
@@ -17,18 +17,18 @@
package com.android.tv.data;
import static android.support.test.InstrumentationRegistry.getTargetContext;
-import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import android.media.tv.TvContract.Programs.Genres;
import android.os.Build;
import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
-import org.junit.runner.RunWith;
/** Tests for {@link Channel}. */
@SmallTest
-@RunWith(AndroidJUnit4.class)
public class GenreItemTest {
private static final String INVALID_GENRE = "INVALID GENRE";
@@ -41,17 +41,17 @@ public class GenreItemTest {
@Test
public void testGetCanonicalGenre() {
int count = GenreItems.getGenreCount();
- assertThat(GenreItems.getCanonicalGenre(GenreItems.ID_ALL_CHANNELS)).isNull();
+ assertNull(GenreItems.getCanonicalGenre(GenreItems.ID_ALL_CHANNELS));
for (int i = 1; i < count; ++i) {
- assertThat(GenreItems.getCanonicalGenre(i)).isNotNull();
+ assertNotNull(GenreItems.getCanonicalGenre(i));
}
}
@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);
+ assertEquals(GenreItems.ID_ALL_CHANNELS, GenreItems.getId(null));
+ assertEquals(GenreItems.ID_ALL_CHANNELS, GenreItems.getId(INVALID_GENRE));
assertInRange(GenreItems.getId(Genres.FAMILY_KIDS), 1, count - 1);
assertInRange(GenreItems.getId(Genres.SPORTS), 1, count - 1);
assertInRange(GenreItems.getId(Genres.SHOPPING), 1, count - 1);
@@ -68,13 +68,12 @@ public class GenreItemTest {
@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);
+ assertEquals(GenreItems.ID_ALL_CHANNELS, GenreItems.getId(Genres.ARTS));
+ assertEquals(GenreItems.ID_ALL_CHANNELS, GenreItems.getId(Genres.ENTERTAINMENT));
+ assertEquals(GenreItems.ID_ALL_CHANNELS, GenreItems.getId(Genres.LIFE_STYLE));
+ assertEquals(GenreItems.ID_ALL_CHANNELS, GenreItems.getId(Genres.MUSIC));
+ assertEquals(GenreItems.ID_ALL_CHANNELS, GenreItems.getId(Genres.PREMIER));
+ assertEquals(GenreItems.ID_ALL_CHANNELS, GenreItems.getId(Genres.TECH_SCIENCE));
} else {
int count = GenreItems.getGenreCount();
assertInRange(GenreItems.getId(Genres.ARTS), 1, count - 1);
@@ -87,6 +86,6 @@ public class GenreItemTest {
}
private void assertInRange(int value, int lower, int upper) {
- assertThat(value >= lower && value <= upper).isTrue();
+ assertTrue(value >= lower && value <= upper);
}
}
diff --git a/tests/unit/src/com/android/tv/data/ProgramDataManagerTest.java b/tests/unit/src/com/android/tv/data/ProgramDataManagerTest.java
index c1d670fe..2b75ee4b 100644
--- a/tests/unit/src/com/android/tv/data/ProgramDataManagerTest.java
+++ b/tests/unit/src/com/android/tv/data/ProgramDataManagerTest.java
@@ -17,8 +17,10 @@
package com.android.tv.data;
import static android.support.test.InstrumentationRegistry.getTargetContext;
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.database.ContentObserver;
@@ -28,15 +30,14 @@ import android.net.Uri;
import android.os.HandlerThread;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.test.mock.MockContentProvider;
import android.test.mock.MockContentResolver;
import android.test.mock.MockCursor;
import android.util.Log;
import android.util.SparseArray;
+import com.android.tv.testing.Constants;
import com.android.tv.testing.FakeClock;
-import com.android.tv.testing.constants.Constants;
-import com.android.tv.testing.data.ProgramInfo;
+import com.android.tv.testing.ProgramInfo;
import com.android.tv.util.Utils;
import java.util.ArrayList;
import java.util.Arrays;
@@ -45,14 +46,10 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
-import org.junit.runner.RunWith;
/** Test for {@link com.android.tv.data.ProgramDataManager} */
@SmallTest
-@RunWith(AndroidJUnit4.class)
-@Ignore("b/69836704")
public class ProgramDataManagerTest {
private static final boolean DEBUG = false;
private static final String TAG = "ProgramDataManagerTest";
@@ -97,8 +94,7 @@ public class ProgramDataManagerTest {
private void startAndWaitForComplete() throws InterruptedException {
mProgramDataManager.start();
- assertThat(mListener.programUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS))
- .isTrue();
+ assertTrue(mListener.programUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS));
}
/** Test for {@link ProgramInfo#getIndex} and {@link ProgramInfo#getStartTimeMs}. */
@@ -109,8 +105,8 @@ public class ProgramDataManagerTest {
int index = stub.getIndex(mClock.currentTimeMillis(), channelId);
long startTimeMs = stub.getStartTimeMs(index, channelId);
ProgramInfo programAt = stub.build(InstrumentationRegistry.getContext(), index);
- assertThat(startTimeMs).isAtMost(mClock.currentTimeMillis());
- assertThat(mClock.currentTimeMillis()).isLessThan(startTimeMs + programAt.durationMs);
+ assertTrue(startTimeMs <= mClock.currentTimeMillis());
+ assertTrue(mClock.currentTimeMillis() < startTimeMs + programAt.durationMs);
}
}
@@ -134,11 +130,9 @@ public class ProgramDataManagerTest {
for (long channelId = 1; channelId <= Constants.UNIT_TEST_CHANNEL_COUNT; channelId++) {
Program currentProgram = mProgramDataManager.getCurrentProgram(channelId);
// Test {@link ProgramDataManager#getCurrentProgram(long)}.
- assertThat(
- currentProgram.getStartTimeUtcMillis() <= mClock.currentTimeMillis()
- && mClock.currentTimeMillis()
- <= currentProgram.getEndTimeUtcMillis())
- .isTrue();
+ assertTrue(
+ currentProgram.getStartTimeUtcMillis() <= mClock.currentTimeMillis()
+ && mClock.currentTimeMillis() <= currentProgram.getEndTimeUtcMillis());
// Test {@link ProgramDataManager#getPrograms(long)}.
// Case #1: Normal case
@@ -155,14 +149,14 @@ public class ProgramDataManagerTest {
// 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);
+ assertEquals(startTimeMs, programs.get(0).getStartTimeUtcMillis());
// Test {@link ProgramDataManager#setPrefetchTimeRange(long)}.
programs =
mProgramDataManager.getPrograms(
channelId, prefetchTimeRangeStartMs - TimeUnit.HOURS.toMillis(1));
for (Program program : programs) {
- assertThat(program.getEndTimeUtcMillis()).isAtLeast(prefetchTimeRangeStartMs);
+ assertTrue(program.getEndTimeUtcMillis() >= prefetchTimeRangeStartMs);
}
}
}
@@ -192,14 +186,12 @@ public class ProgramDataManagerTest {
TestProgramDataManagerOnCurrentProgramUpdatedListener listener =
new TestProgramDataManagerOnCurrentProgramUpdatedListener();
mProgramDataManager.addOnCurrentProgramUpdatedListener(testChannelId, listener);
- assertThat(
- listener.currentProgramUpdatedLatch.await(
- WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS))
- .isTrue();
- assertThat(listener.updatedChannelId).isEqualTo(testChannelId);
+ assertTrue(
+ listener.currentProgramUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS));
+ assertEquals(testChannelId, listener.updatedChannelId);
Program currentProgram = mProgramDataManager.getCurrentProgram(testChannelId);
assertProgramEquals(nextProgramStartTimeMs, nextProgramInfo, currentProgram);
- assertThat(currentProgram).isEqualTo(listener.updatedProgram);
+ assertEquals(listener.updatedProgram, currentProgram);
}
/** Test if program data is refreshed after the program insertion. */
@@ -212,15 +204,14 @@ public class ProgramDataManagerTest {
mListener.reset();
List<Program> programList =
mProgramDataManager.getPrograms(testChannelId, mClock.currentTimeMillis());
- assertThat(programList).isNotNull();
+ assertNotNull(programList);
long lastProgramEndTime = programList.get(programList.size() - 1).getEndTimeUtcMillis();
// Make change in content provider
mContentProvider.simulateAppend(testChannelId);
- assertThat(mListener.programUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS))
- .isTrue();
+ assertTrue(mListener.programUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS));
programList = mProgramDataManager.getPrograms(testChannelId, mClock.currentTimeMillis());
- assertThat(lastProgramEndTime)
- .isLessThan(programList.get(programList.size() - 1).getEndTimeUtcMillis());
+ assertTrue(
+ lastProgramEndTime < programList.get(programList.size() - 1).getEndTimeUtcMillis());
}
/** Test for {@link ProgramDataManager#setPauseProgramUpdate(boolean)}. */
@@ -233,28 +224,23 @@ public class ProgramDataManagerTest {
mListener.reset();
mProgramDataManager.setPauseProgramUpdate(true);
mContentProvider.simulateAppend(testChannelId);
- assertThat(mListener.programUpdatedLatch.await(FAILURE_TIME_OUT_MS, TimeUnit.MILLISECONDS))
- .isFalse();
+ assertFalse(
+ mListener.programUpdatedLatch.await(FAILURE_TIME_OUT_MS, TimeUnit.MILLISECONDS));
}
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);
+ assertEquals("title", expectedInfo.title, actualProgram.getTitle());
+ assertEquals("episode", expectedInfo.episode, actualProgram.getEpisodeTitle());
+ assertEquals("description", expectedInfo.description, actualProgram.getDescription());
+ assertEquals("startTime", expectedStartTime, actualProgram.getStartTimeUtcMillis());
+ assertEquals(
+ "endTime",
+ expectedStartTime + expectedInfo.durationMs,
+ actualProgram.getEndTimeUtcMillis());
}
- private final class FakeContentResolver extends MockContentResolver {
+ private class FakeContentResolver extends MockContentResolver {
@Override
public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
super.notifyChange(uri, observer, syncToNetwork);
@@ -269,7 +255,7 @@ public class ProgramDataManagerTest {
}
}
- private static final class ProgramInfoWrapper {
+ private static class ProgramInfoWrapper {
private final int index;
private final long startTimeMs;
private final ProgramInfo programInfo;
@@ -283,7 +269,7 @@ public class ProgramDataManagerTest {
// This implements the minimal methods in content resolver
// and detailed assumptions are written in each method.
- private final class FakeContentProvider extends MockContentProvider {
+ private class FakeContentProvider extends MockContentProvider {
private final SparseArray<List<ProgramInfoWrapper>> mProgramInfoList = new SparseArray<>();
/**
@@ -374,9 +360,9 @@ public class ProgramDataManagerTest {
}
private void assertProgramUri(Uri uri) {
- assertWithMessage("Uri(" + uri + ") isn't channel uri")
- .that(uri.toString().startsWith(TvContract.Programs.CONTENT_URI.toString()))
- .isTrue();
+ assertTrue(
+ "Uri(" + uri + ") isn't channel uri",
+ uri.toString().startsWith(TvContract.Programs.CONTENT_URI.toString()));
}
public ProgramInfoWrapper get(long channelId, int position) {
@@ -388,8 +374,8 @@ public class ProgramDataManagerTest {
}
}
- private final class FakeCursor extends MockCursor {
- private final String[] allColumns = {
+ private class FakeCursor extends MockCursor {
+ private final String[] ALL_COLUMNS = {
TvContract.Programs.COLUMN_CHANNEL_ID,
TvContract.Programs.COLUMN_TITLE,
TvContract.Programs.COLUMN_SHORT_DESCRIPTION,
@@ -417,7 +403,7 @@ public class ProgramDataManagerTest {
* @param endTimeMs end of the time range to query programs.
*/
public FakeCursor(String[] columns, long channelId, long startTimeMs, long endTimeMs) {
- mColumns = (columns == null) ? allColumns : columns;
+ mColumns = (columns == null) ? ALL_COLUMNS : columns;
mIsQueryForSingleChannel = (channelId > 0);
mChannelId = channelId;
mProgramPosition = -1;
@@ -480,12 +466,11 @@ public class ProgramDataManagerTest {
return mCurrentProgram.startTimeMs;
case TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS:
return mCurrentProgram.startTimeMs + mCurrentProgram.programInfo.durationMs;
- default:
- if (DEBUG) {
- Log.d(TAG, "Column (" + columnName + ") is ignored in getLong()");
- }
- return 0;
}
+ if (DEBUG) {
+ Log.d(TAG, "Column (" + columnName + ") is ignored in getLong()");
+ }
+ return 0;
}
@Override
@@ -498,12 +483,11 @@ public class ProgramDataManagerTest {
return mCurrentProgram.programInfo.description;
case TvContract.Programs.COLUMN_EPISODE_TITLE:
return mCurrentProgram.programInfo.episode;
- default:
- if (DEBUG) {
- Log.d(TAG, "Column (" + columnName + ") is ignored in getString()");
- }
- return null;
}
+ if (DEBUG) {
+ Log.d(TAG, "Column (" + columnName + ") is ignored in getString()");
+ }
+ return null;
}
@Override
diff --git a/tests/unit/src/com/android/tv/data/ProgramTest.java b/tests/unit/src/com/android/tv/data/ProgramTest.java
index 3f2a9f26..a69688d2 100644
--- a/tests/unit/src/com/android/tv/data/ProgramTest.java
+++ b/tests/unit/src/com/android/tv/data/ProgramTest.java
@@ -17,24 +17,22 @@ 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import android.media.tv.TvContentRating;
import android.media.tv.TvContract.Programs.Genres;
import android.os.Parcel;
import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import com.android.tv.data.Program.CriticScore;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
-import org.junit.runner.RunWith;
/** Tests for {@link Program}. */
@SmallTest
-@RunWith(AndroidJUnit4.class)
public class ProgramTest {
private static final int NOT_FOUND_GENRE = 987;
@@ -45,7 +43,7 @@ public class ProgramTest {
@Test
public void testBuild() {
Program program = new Program.Builder().build();
- assertWithMessage("isValid").that(program.isValid()).isFalse();
+ assertEquals("isValid", false, program.isValid());
}
@Test
@@ -129,7 +127,7 @@ public class ProgramTest {
p2.unmarshall(bytes, 0, bytes.length);
p2.setDataPosition(0);
Program r2 = Program.fromParcel(p2);
- assertThat(r2).isEqualTo(p);
+ assertEquals(p, r2);
} finally {
p1.recycle();
p2.recycle();
@@ -143,36 +141,34 @@ public class ProgramTest {
.setTitle("MyTitle")
.addCriticScore(
new CriticScore(
- "default source", "5/10", "http://testurl/testimage.jpg"))
+ "default source", "5/10", "https://testurl/testimage.jpg"))
.build();
Parcel parcel = Parcel.obtain();
program.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
Program programFromParcel = Program.CREATOR.createFromParcel(parcel);
- 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");
+ assertNotNull(programFromParcel.getCriticScores());
+ assertEquals(programFromParcel.getCriticScores().get(0).source, "default source");
+ assertEquals(programFromParcel.getCriticScores().get(0).score, "5/10");
+ assertEquals(
+ programFromParcel.getCriticScores().get(0).logoUrl,
+ "https://testurl/testimage.jpg");
}
private static void assertNullCanonicalGenres(Program program) {
String[] actual = program.getCanonicalGenres();
- assertWithMessage("Expected null canonical genres but was " + Arrays.toString(actual))
- .that(actual)
- .isNull();
+ assertNull("Expected null canonical genres but was " + Arrays.toString(actual), actual);
}
private static void assertCanonicalGenres(Program program, String... expected) {
- assertWithMessage("canonical genres")
- .that(Arrays.asList(program.getCanonicalGenres()))
- .isEqualTo(Arrays.asList(expected));
+ assertEquals(
+ "canonical genres",
+ Arrays.asList(expected),
+ Arrays.asList(program.getCanonicalGenres()));
}
private static void assertHasGenre(Program program, int genreId, boolean expected) {
- assertWithMessage("hasGenre(" + genreId + ")")
- .that(program.hasGenre(genreId))
- .isEqualTo(expected);
+ assertEquals("hasGenre(" + genreId + ")", expected, program.hasGenre(genreId));
}
}
diff --git a/tests/unit/src/com/android/tv/data/TvInputNewComparatorTest.java b/tests/unit/src/com/android/tv/data/TvInputNewComparatorTest.java
index 8bf3efbc..496d1018 100644
--- a/tests/unit/src/com/android/tv/data/TvInputNewComparatorTest.java
+++ b/tests/unit/src/com/android/tv/data/TvInputNewComparatorTest.java
@@ -19,7 +19,6 @@ package com.android.tv.data;
import android.content.pm.ResolveInfo;
import android.media.tv.TvInputInfo;
import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.util.Pair;
import com.android.tv.testing.ComparatorTester;
import com.android.tv.util.SetupUtils;
@@ -28,7 +27,6 @@ import com.android.tv.util.TvInputManagerHelper;
import java.util.Comparator;
import java.util.LinkedHashMap;
import org.junit.Test;
-import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
@@ -36,7 +34,6 @@ import org.mockito.stubbing.Answer;
/** Test for {@link TvInputNewComparator} */
@SmallTest
-@RunWith(AndroidJUnit4.class)
public class TvInputNewComparatorTest {
@Test
public void testComparator() throws Exception {
diff --git a/tests/unit/src/com/android/tv/data/WatchedHistoryManagerTest.java b/tests/unit/src/com/android/tv/data/WatchedHistoryManagerTest.java
index 539698bf..e65a71fb 100644
--- a/tests/unit/src/com/android/tv/data/WatchedHistoryManagerTest.java
+++ b/tests/unit/src/com/android/tv/data/WatchedHistoryManagerTest.java
@@ -17,16 +17,16 @@
package com.android.tv.data;
import static android.support.test.InstrumentationRegistry.getTargetContext;
-import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import android.os.Looper;
import android.support.test.filters.MediumTest;
-import android.support.test.runner.AndroidJUnit4;
import com.android.tv.data.WatchedHistoryManager.WatchedRecord;
import java.util.concurrent.TimeUnit;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
/**
* Test for {@link com.android.tv.data.WatchedHistoryManagerTest}
@@ -34,7 +34,6 @@ import org.junit.runner.RunWith;
* <p>This is a medium test because it load files which accessing SharedPreferences.
*/
@MediumTest
-@RunWith(AndroidJUnit4.class)
public class WatchedHistoryManagerTest {
// Wait time for expected success.
private static final int MAX_HISTORY_SIZE = 100;
@@ -54,13 +53,13 @@ public class WatchedHistoryManagerTest {
private void startAndWaitForComplete() throws InterruptedException {
mWatchedHistoryManager.start();
- assertThat(mListener.mLoadFinished).isTrue();
+ assertTrue(mListener.mLoadFinished);
}
@Test
public void testIsLoaded() throws InterruptedException {
startAndWaitForComplete();
- assertThat(mWatchedHistoryManager.isLoaded()).isTrue();
+ assertTrue(mWatchedHistoryManager.isLoaded());
}
@Test
@@ -75,10 +74,10 @@ public class WatchedHistoryManagerTest {
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);
+ assertEquals(record.channelId, fakeId);
+ assertEquals(record.watchedStartTime, time - duration);
+ assertEquals(record.duration, duration);
+ assertEquals(record, recordFromSharedPreferences);
}
@Test
@@ -97,21 +96,22 @@ public class WatchedHistoryManagerTest {
WatchedRecord record = mWatchedHistoryManager.getRecord(i);
WatchedRecord recordFromSharedPreferences =
mWatchedHistoryManager.getRecordFromSharedPreferences(i);
- assertThat(recordFromSharedPreferences).isEqualTo(record);
- assertThat(startChannelId + size - 1 - i).isEqualTo(record.channelId);
+ assertEquals(record, recordFromSharedPreferences);
+ assertEquals(record.channelId, startChannelId + size - 1 - i);
}
// 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));
+ assertEquals(
+ mWatchedHistoryManager.getRecordFromSharedPreferences(0),
+ mWatchedHistoryManager.getRecordFromSharedPreferences(MAX_HISTORY_SIZE));
}
@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();
+ assertTrue(new WatchedRecord(1, 2, 3).equals(new WatchedRecord(1, 2, 3)));
+ assertFalse(new WatchedRecord(1, 2, 3).equals(new WatchedRecord(1, 2, 4)));
+ assertFalse(new WatchedRecord(1, 2, 3).equals(new WatchedRecord(1, 4, 3)));
+ assertFalse(new WatchedRecord(1, 2, 3).equals(new WatchedRecord(4, 2, 3)));
}
@Test
@@ -122,11 +122,10 @@ public class WatchedHistoryManagerTest {
WatchedRecord record = new WatchedRecord(fakeId, time, duration);
WatchedRecord sameRecord =
mWatchedHistoryManager.decode(mWatchedHistoryManager.encode(record));
- assertThat(sameRecord).isEqualTo(record);
+ assertEquals(record, sameRecord);
}
- private static final class TestWatchedHistoryManagerListener
- implements WatchedHistoryManager.Listener {
+ private class TestWatchedHistoryManagerListener implements WatchedHistoryManager.Listener {
boolean mLoadFinished;
@Override
diff --git a/tests/unit/src/com/android/tv/dvr/BaseDvrDataManagerTest.java b/tests/unit/src/com/android/tv/dvr/BaseDvrDataManagerTest.java
new file mode 100644
index 00000000..c9c76a5a
--- /dev/null
+++ b/tests/unit/src/com/android/tv/dvr/BaseDvrDataManagerTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.dvr;
+
+import static android.support.test.InstrumentationRegistry.getContext;
+
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+import android.test.MoreAsserts;
+import com.android.tv.common.feature.CommonFeatures;
+import com.android.tv.common.feature.TestableFeature;
+import com.android.tv.dvr.data.ScheduledRecording;
+import com.android.tv.testing.FakeClock;
+import com.android.tv.testing.dvr.RecordingTestUtils;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/** Tests for {@link BaseDvrDataManager} using {@link DvrDataManagerInMemoryImpl}. */
+@SmallTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+public class BaseDvrDataManagerTest {
+ private static final String INPUT_ID = "input_id";
+ private static final int CHANNEL_ID = 273;
+
+ private final TestableFeature mDvrFeature = CommonFeatures.DVR;
+ private DvrDataManagerInMemoryImpl mDvrDataManager;
+ private FakeClock mFakeClock;
+
+ @Before
+ public void setUp() {
+ mDvrFeature.enableForTest();
+ mFakeClock = FakeClock.createWithCurrentTime();
+ mDvrDataManager = new DvrDataManagerInMemoryImpl(getContext(), mFakeClock);
+ }
+
+ @After
+ public void tearDown() {
+ mDvrFeature.resetForTests();
+ }
+
+ @Test
+ public void testGetNonStartedScheduledRecordings() {
+ ScheduledRecording recording =
+ mDvrDataManager.addScheduledRecordingInternal(
+ createNewScheduledRecordingStartingNow());
+ List<ScheduledRecording> result = mDvrDataManager.getNonStartedScheduledRecordings();
+ MoreAsserts.assertContentsInAnyOrder(result, recording);
+ }
+
+ @Test
+ public void testGetNonStartedScheduledRecordings_past() {
+ mDvrDataManager.addScheduledRecordingInternal(createNewScheduledRecordingStartingNow());
+ mFakeClock.increment(TimeUnit.MINUTES, 6);
+ List<ScheduledRecording> result = mDvrDataManager.getNonStartedScheduledRecordings();
+ MoreAsserts.assertContentsInAnyOrder(result);
+ }
+
+ @NonNull
+ private ScheduledRecording createNewScheduledRecordingStartingNow() {
+ return ScheduledRecording.buildFrom(
+ RecordingTestUtils.createTestRecordingWithIdAndPeriod(
+ ScheduledRecording.ID_NOT_SET,
+ INPUT_ID,
+ CHANNEL_ID,
+ mFakeClock.currentTimeMillis(),
+ mFakeClock.currentTimeMillis() + TimeUnit.MINUTES.toMillis(5)))
+ .setState(ScheduledRecording.STATE_RECORDING_NOT_STARTED)
+ .build();
+ }
+}
diff --git a/tests/unit/src/com/android/tv/dvr/DvrDataManagerImplTest.java b/tests/unit/src/com/android/tv/dvr/DvrDataManagerImplTest.java
new file mode 100644
index 00000000..8a5dfabd
--- /dev/null
+++ b/tests/unit/src/com/android/tv/dvr/DvrDataManagerImplTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.tv.dvr;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.Build;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+import com.android.tv.dvr.data.ScheduledRecording;
+import com.android.tv.testing.dvr.RecordingTestUtils;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Test;
+
+/** Tests for {@link DvrDataManagerImpl} */
+@SmallTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+public class DvrDataManagerImplTest {
+ private static final String INPUT_ID = "input_id";
+ private static final int CHANNEL_ID = 273;
+
+ @Test
+ public void testGetNextScheduledStartTimeAfter() {
+ long id = 1;
+ List<ScheduledRecording> scheduledRecordings = new ArrayList<>();
+ assertNextStartTime(scheduledRecordings, 0L, DvrDataManager.NEXT_START_TIME_NOT_FOUND);
+ scheduledRecordings.add(
+ RecordingTestUtils.createTestRecordingWithIdAndPeriod(
+ id++, INPUT_ID, CHANNEL_ID, 10L, 20L));
+ assertNextStartTime(scheduledRecordings, 9L, 10L);
+ assertNextStartTime(scheduledRecordings, 10L, DvrDataManager.NEXT_START_TIME_NOT_FOUND);
+ scheduledRecordings.add(
+ RecordingTestUtils.createTestRecordingWithIdAndPeriod(
+ id++, INPUT_ID, CHANNEL_ID, 20L, 30L));
+ assertNextStartTime(scheduledRecordings, 9L, 10L);
+ assertNextStartTime(scheduledRecordings, 10L, 20L);
+ assertNextStartTime(scheduledRecordings, 20L, DvrDataManager.NEXT_START_TIME_NOT_FOUND);
+ scheduledRecordings.add(
+ RecordingTestUtils.createTestRecordingWithIdAndPeriod(
+ id++, INPUT_ID, CHANNEL_ID, 30L, 40L));
+ assertNextStartTime(scheduledRecordings, 9L, 10L);
+ assertNextStartTime(scheduledRecordings, 10L, 20L);
+ assertNextStartTime(scheduledRecordings, 20L, 30L);
+ assertNextStartTime(scheduledRecordings, 30L, DvrDataManager.NEXT_START_TIME_NOT_FOUND);
+ scheduledRecordings.clear();
+ scheduledRecordings.add(
+ RecordingTestUtils.createTestRecordingWithIdAndPeriod(
+ id++, INPUT_ID, CHANNEL_ID, 10L, 20L));
+ scheduledRecordings.add(
+ RecordingTestUtils.createTestRecordingWithIdAndPeriod(
+ id++, INPUT_ID, CHANNEL_ID, 10L, 20L));
+ scheduledRecordings.add(
+ RecordingTestUtils.createTestRecordingWithIdAndPeriod(
+ id++, INPUT_ID, CHANNEL_ID, 10L, 20L));
+ assertNextStartTime(scheduledRecordings, 9L, 10L);
+ assertNextStartTime(scheduledRecordings, 10L, DvrDataManager.NEXT_START_TIME_NOT_FOUND);
+ }
+
+ private void assertNextStartTime(
+ List<ScheduledRecording> scheduledRecordings, long startTime, long expected) {
+ assertEquals(
+ "getNextScheduledStartTimeAfter()",
+ expected,
+ DvrDataManagerImpl.getNextStartTimeAfter(scheduledRecordings, startTime));
+ }
+}
diff --git a/tests/unit/src/com/android/tv/dvr/DvrDataManagerInMemoryImpl.java b/tests/unit/src/com/android/tv/dvr/DvrDataManagerInMemoryImpl.java
new file mode 100644
index 00000000..a16f7acc
--- /dev/null
+++ b/tests/unit/src/com/android/tv/dvr/DvrDataManagerInMemoryImpl.java
@@ -0,0 +1,310 @@
+/*
+ * 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 android.content.Context;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.test.filters.SdkSuppress;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Range;
+import com.android.tv.common.SoftPreconditions;
+import com.android.tv.dvr.data.RecordedProgram;
+import com.android.tv.dvr.data.ScheduledRecording;
+import com.android.tv.dvr.data.ScheduledRecording.RecordingState;
+import com.android.tv.dvr.data.SeriesRecording;
+import com.android.tv.util.Clock;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
+
+/** A DVR Data manager that stores values in memory suitable for testing. */
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+public final class DvrDataManagerInMemoryImpl extends BaseDvrDataManager {
+ private static final String TAG = "DvrDataManagerInMemory";
+ private final AtomicLong mNextId = new AtomicLong(1);
+ private final Map<Long, ScheduledRecording> mScheduledRecordings = new HashMap<>();
+ private final Map<Long, RecordedProgram> mRecordedPrograms = new HashMap<>();
+ private final Map<Long, SeriesRecording> mSeriesRecordings = new HashMap<>();
+
+ public DvrDataManagerInMemoryImpl(Context context, Clock clock) {
+ super(context, clock);
+ }
+
+ @Override
+ public boolean isInitialized() {
+ return true;
+ }
+
+ @Override
+ public boolean isDvrScheduleLoadFinished() {
+ return true;
+ }
+
+ @Override
+ public boolean isRecordedProgramLoadFinished() {
+ return true;
+ }
+
+ private List<ScheduledRecording> getScheduledRecordingsPrograms() {
+ return new ArrayList<>(mScheduledRecordings.values());
+ }
+
+ @Override
+ public List<RecordedProgram> getRecordedPrograms() {
+ return new ArrayList<>(mRecordedPrograms.values());
+ }
+
+ @Override
+ public List<ScheduledRecording> getAllScheduledRecordings() {
+ return new ArrayList<>(mScheduledRecordings.values());
+ }
+
+ public List<SeriesRecording> getSeriesRecordings() {
+ return new ArrayList<>(mSeriesRecordings.values());
+ }
+
+ @Override
+ public List<SeriesRecording> getSeriesRecordings(String inputId) {
+ List<SeriesRecording> result = new ArrayList<>();
+ for (SeriesRecording r : mSeriesRecordings.values()) {
+ if (TextUtils.equals(r.getInputId(), inputId)) {
+ result.add(r);
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public long getNextScheduledStartTimeAfter(long startTime) {
+
+ List<ScheduledRecording> temp = getNonStartedScheduledRecordings();
+ Collections.sort(temp, ScheduledRecording.START_TIME_COMPARATOR);
+ for (ScheduledRecording r : temp) {
+ if (r.getStartTimeMs() > startTime) {
+ return r.getStartTimeMs();
+ }
+ }
+ return DvrDataManager.NEXT_START_TIME_NOT_FOUND;
+ }
+
+ @Override
+ public List<ScheduledRecording> getScheduledRecordings(
+ Range<Long> period, @RecordingState int state) {
+ List<ScheduledRecording> temp = getScheduledRecordingsPrograms();
+ List<ScheduledRecording> result = new ArrayList<>();
+ for (ScheduledRecording r : temp) {
+ if (r.isOverLapping(period) && r.getState() == state) {
+ result.add(r);
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public List<ScheduledRecording> getScheduledRecordings(long seriesRecordingId) {
+ List<ScheduledRecording> result = new ArrayList<>();
+ for (ScheduledRecording r : mScheduledRecordings.values()) {
+ if (r.getSeriesRecordingId() == seriesRecordingId) {
+ result.add(r);
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public List<ScheduledRecording> getScheduledRecordings(String inputId) {
+ List<ScheduledRecording> result = new ArrayList<>();
+ for (ScheduledRecording r : mScheduledRecordings.values()) {
+ if (TextUtils.equals(r.getInputId(), inputId)) {
+ result.add(r);
+ }
+ }
+ return result;
+ }
+
+ /** Add a new scheduled recording. */
+ @Override
+ public void addScheduledRecording(ScheduledRecording... scheduledRecordings) {
+ for (ScheduledRecording r : scheduledRecordings) {
+ addScheduledRecordingInternal(r);
+ }
+ }
+
+ public void addRecordedProgram(RecordedProgram recordedProgram) {
+ addRecordedProgramInternal(recordedProgram);
+ }
+
+ public void updateRecordedProgram(RecordedProgram r) {
+ long id = r.getId();
+ if (mRecordedPrograms.containsKey(id)) {
+ mRecordedPrograms.put(id, r);
+ notifyRecordedProgramsChanged(r);
+ } else {
+ throw new IllegalArgumentException("Recording not found:" + r);
+ }
+ }
+
+ public void removeRecordedProgram(RecordedProgram scheduledRecording) {
+ mRecordedPrograms.remove(scheduledRecording.getId());
+ notifyRecordedProgramsRemoved(scheduledRecording);
+ }
+
+ public ScheduledRecording addScheduledRecordingInternal(ScheduledRecording scheduledRecording) {
+ SoftPreconditions.checkState(
+ scheduledRecording.getId() == ScheduledRecording.ID_NOT_SET,
+ TAG,
+ "expected id of "
+ + ScheduledRecording.ID_NOT_SET
+ + " but was "
+ + scheduledRecording);
+ scheduledRecording =
+ ScheduledRecording.buildFrom(scheduledRecording)
+ .setId(mNextId.incrementAndGet())
+ .build();
+ mScheduledRecordings.put(scheduledRecording.getId(), scheduledRecording);
+ notifyScheduledRecordingAdded(scheduledRecording);
+ return scheduledRecording;
+ }
+
+ public RecordedProgram addRecordedProgramInternal(RecordedProgram recordedProgram) {
+ SoftPreconditions.checkState(
+ recordedProgram.getId() == RecordedProgram.ID_NOT_SET,
+ TAG,
+ "expected id of " + RecordedProgram.ID_NOT_SET + " but was " + recordedProgram);
+ recordedProgram =
+ RecordedProgram.buildFrom(recordedProgram).setId(mNextId.incrementAndGet()).build();
+ mRecordedPrograms.put(recordedProgram.getId(), recordedProgram);
+ notifyRecordedProgramsAdded(recordedProgram);
+ return recordedProgram;
+ }
+
+ @Override
+ public void addSeriesRecording(SeriesRecording... seriesRecordings) {
+ for (SeriesRecording r : seriesRecordings) {
+ mSeriesRecordings.put(r.getId(), r);
+ }
+ notifySeriesRecordingAdded(seriesRecordings);
+ }
+
+ @Override
+ public void removeScheduledRecording(ScheduledRecording... scheduledRecordings) {
+ for (ScheduledRecording r : scheduledRecordings) {
+ mScheduledRecordings.remove(r.getId());
+ }
+ notifyScheduledRecordingRemoved(scheduledRecordings);
+ }
+
+ @Override
+ public void removeScheduledRecording(boolean forceRemove, ScheduledRecording... schedule) {
+ removeScheduledRecording(schedule);
+ }
+
+ @Override
+ public void removeSeriesRecording(SeriesRecording... seriesRecordings) {
+ for (SeriesRecording r : seriesRecordings) {
+ mSeriesRecordings.remove(r.getId());
+ }
+ notifySeriesRecordingRemoved(seriesRecordings);
+ }
+
+ @Override
+ public void updateScheduledRecording(ScheduledRecording... scheduledRecordings) {
+ for (ScheduledRecording r : scheduledRecordings) {
+ long id = r.getId();
+ if (mScheduledRecordings.containsKey(id)) {
+ mScheduledRecordings.put(id, r);
+ } else {
+ Log.d(TAG, "Recording not found:" + r);
+ }
+ }
+ notifyScheduledRecordingStatusChanged(scheduledRecordings);
+ }
+
+ @Override
+ public void updateSeriesRecording(SeriesRecording... seriesRecordings) {
+ for (SeriesRecording r : seriesRecordings) {
+ long id = r.getId();
+ if (mSeriesRecordings.containsKey(id)) {
+ mSeriesRecordings.put(id, r);
+ } else {
+ throw new IllegalArgumentException("Recording not found:" + r);
+ }
+ }
+ notifySeriesRecordingChanged(seriesRecordings);
+ }
+
+ @Nullable
+ @Override
+ public ScheduledRecording getScheduledRecording(long id) {
+ return mScheduledRecordings.get(id);
+ }
+
+ @Nullable
+ @Override
+ public ScheduledRecording getScheduledRecordingForProgramId(long programId) {
+ for (ScheduledRecording r : mScheduledRecordings.values()) {
+ if (r.getProgramId() == programId) {
+ return r;
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public SeriesRecording getSeriesRecording(long seriesRecordingId) {
+ return mSeriesRecordings.get(seriesRecordingId);
+ }
+
+ @Nullable
+ @Override
+ public SeriesRecording getSeriesRecording(String seriesId) {
+ for (SeriesRecording r : mSeriesRecordings.values()) {
+ if (r.getSeriesId().equals(seriesId)) {
+ return r;
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public RecordedProgram getRecordedProgram(long recordingId) {
+ return mRecordedPrograms.get(recordingId);
+ }
+
+ @Override
+ @NonNull
+ protected List<ScheduledRecording> getRecordingsWithState(int... states) {
+ ArrayList<ScheduledRecording> result = new ArrayList<>();
+ for (ScheduledRecording r : mScheduledRecordings.values()) {
+ for (int state : states) {
+ if (r.getState() == state) {
+ result.add(r);
+ break;
+ }
+ }
+ }
+ return result;
+ }
+}
diff --git a/tests/unit/src/com/android/tv/dvr/DvrScheduleManagerTest.java b/tests/unit/src/com/android/tv/dvr/DvrScheduleManagerTest.java
new file mode 100644
index 00000000..ab464b18
--- /dev/null
+++ b/tests/unit/src/com/android/tv/dvr/DvrScheduleManagerTest.java
@@ -0,0 +1,831 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.tv.dvr;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.os.Build;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+import android.test.MoreAsserts;
+import android.util.Range;
+import com.android.tv.dvr.DvrScheduleManager.ConflictInfo;
+import com.android.tv.dvr.data.ScheduledRecording;
+import com.android.tv.testing.dvr.RecordingTestUtils;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Test;
+
+/** Tests for {@link DvrScheduleManager} */
+@SmallTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+public class DvrScheduleManagerTest {
+ private static final String INPUT_ID = "input_id";
+
+ @Test
+ public void testGetConflictingSchedules_emptySchedule() {
+ List<ScheduledRecording> schedules = new ArrayList<>();
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 1));
+ }
+
+ @Test
+ public void testGetConflictingSchedules_noConflict() {
+ long priority = 0;
+ long channelId = 0;
+ List<ScheduledRecording> schedules = new ArrayList<>();
+
+ schedules.add(
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 200L));
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 1));
+
+ schedules.add(
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 100L));
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 2));
+
+ schedules.add(
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 100L, 200L));
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 2));
+
+ schedules.add(
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 100L));
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 3));
+
+ schedules.add(
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 100L, 200L));
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 3));
+ }
+
+ @Test
+ public void testGetConflictingSchedules_noTuner() {
+ long priority = 0;
+ long channelId = 0;
+ List<ScheduledRecording> schedules = new ArrayList<>();
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 0));
+
+ schedules.add(
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 200L));
+ assertEquals(schedules, DvrScheduleManager.getConflictingSchedules(schedules, 0));
+ schedules.add(
+ 0,
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 100L));
+ assertEquals(schedules, DvrScheduleManager.getConflictingSchedules(schedules, 0));
+ }
+
+ @Test
+ public void testGetConflictingSchedules_conflict() {
+ long priority = 0;
+ long channelId = 0;
+ List<ScheduledRecording> schedules = new ArrayList<>();
+
+ ScheduledRecording r1 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 200L);
+ schedules.add(r1);
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 1));
+
+ ScheduledRecording r2 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 100L);
+ schedules.add(r2);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 1), r1);
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 2));
+
+ ScheduledRecording r3 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 100L, 200L);
+ schedules.add(r3);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 1), r1);
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 2));
+
+ ScheduledRecording r4 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 100L);
+ schedules.add(r4);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 1), r2, r1);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 2), r1);
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 3));
+
+ ScheduledRecording r5 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 100L, 200L);
+ schedules.add(r5);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 1), r3, r2, r1);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 2), r1);
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 3));
+
+ ScheduledRecording r6 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 10L, 90L);
+ schedules.add(r6);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 1), r4, r3, r2, r1);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 2), r2, r1);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 3), r1);
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 4));
+
+ ScheduledRecording r7 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 110L, 190L);
+ schedules.add(r7);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 1), r5, r4, r3, r2, r1);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 2), r3, r2, r1);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 3), r1);
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 4));
+
+ ScheduledRecording r8 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 50L, 150L);
+ schedules.add(r8);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 1),
+ r7,
+ r6,
+ r5,
+ r4,
+ r3,
+ r2,
+ r1);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 2), r5, r4, r3, r2, r1);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 3), r3, r2, r1);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 4), r1);
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 5));
+ }
+
+ @Test
+ public void testGetConflictingSchedules_conflict2() {
+ // The case when there is a long schedule.
+ long priority = 0;
+ long channelId = 0;
+ List<ScheduledRecording> schedules = new ArrayList<>();
+
+ ScheduledRecording r1 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 1000L);
+ schedules.add(r1);
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 1));
+
+ ScheduledRecording r2 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 100L);
+ schedules.add(r2);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 1), r1);
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 2));
+
+ ScheduledRecording r3 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 100L, 200L);
+ schedules.add(r3);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 1), r1);
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 2));
+ }
+
+ @Test
+ public void testGetConflictingSchedules_reverseOrder() {
+ long priority = 0;
+ long channelId = 0;
+ List<ScheduledRecording> schedules = new ArrayList<>();
+
+ ScheduledRecording r1 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 200L);
+ schedules.add(0, r1);
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 1));
+
+ ScheduledRecording r2 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 100L);
+ schedules.add(0, r2);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 1), r1);
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 2));
+
+ ScheduledRecording r3 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 100L, 200L);
+ schedules.add(0, r3);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 1), r1);
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 2));
+
+ ScheduledRecording r4 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 100L);
+ schedules.add(0, r4);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 1), r2, r1);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 2), r1);
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 3));
+
+ ScheduledRecording r5 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 100L, 200L);
+ schedules.add(0, r5);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 1), r3, r2, r1);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 2), r1);
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 3));
+
+ ScheduledRecording r6 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 10L, 90L);
+ schedules.add(0, r6);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 1), r4, r3, r2, r1);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 2), r2, r1);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 3), r1);
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 4));
+
+ ScheduledRecording r7 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 110L, 190L);
+ schedules.add(0, r7);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 1), r5, r4, r3, r2, r1);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 2), r3, r2, r1);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 3), r1);
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 4));
+
+ ScheduledRecording r8 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 50L, 150L);
+ schedules.add(0, r8);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 1),
+ r7,
+ r6,
+ r5,
+ r4,
+ r3,
+ r2,
+ r1);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 2), r5, r4, r3, r2, r1);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 3), r3, r2, r1);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 4), r1);
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 5));
+ }
+
+ @Test
+ public void testGetConflictingSchedules_period1() {
+ long priority = 0;
+ long channelId = 0;
+ List<ScheduledRecording> schedules = new ArrayList<>();
+
+ ScheduledRecording r1 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 200L);
+ schedules.add(r1);
+ ScheduledRecording r2 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 100L);
+ schedules.add(r2);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(
+ schedules, 1, Collections.singletonList(new Range<>(10L, 20L))),
+ r1);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(
+ schedules, 1, Collections.singletonList(new Range<>(110L, 120L))),
+ r1);
+ }
+
+ @Test
+ public void testGetConflictingSchedules_period2() {
+ long priority = 0;
+ long channelId = 0;
+ List<ScheduledRecording> schedules = new ArrayList<>();
+
+ ScheduledRecording r1 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 200L);
+ schedules.add(r1);
+ ScheduledRecording r2 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 100L, 200L);
+ schedules.add(r2);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(
+ schedules, 1, Collections.singletonList(new Range<>(10L, 20L))),
+ r1);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(
+ schedules, 1, Collections.singletonList(new Range<>(110L, 120L))),
+ r1);
+ }
+
+ @Test
+ public void testGetConflictingSchedules_period3() {
+ long priority = 0;
+ long channelId = 0;
+ List<ScheduledRecording> schedules = new ArrayList<>();
+
+ ScheduledRecording r1 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 100L);
+ schedules.add(r1);
+ ScheduledRecording r2 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 100L, 200L);
+ schedules.add(r2);
+ ScheduledRecording r3 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 100L);
+ schedules.add(r3);
+ ScheduledRecording r4 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 100L, 200L);
+ schedules.add(r4);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(
+ schedules, 1, Collections.singletonList(new Range<>(10L, 20L))),
+ r1);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(
+ schedules, 1, Collections.singletonList(new Range<>(110L, 120L))),
+ r2);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(
+ schedules, 1, Collections.singletonList(new Range<>(50L, 150L))),
+ r2,
+ r1);
+ List<Range<Long>> ranges = new ArrayList<>();
+ ranges.add(new Range<>(10L, 20L));
+ ranges.add(new Range<>(110L, 120L));
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 1, ranges), r2, r1);
+ }
+
+ @Test
+ public void testGetConflictingSchedules_addSchedules1() {
+ long priority = 0;
+ long channelId = 0;
+ List<ScheduledRecording> schedules = new ArrayList<>();
+
+ ScheduledRecording r1 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 200L);
+ schedules.add(r1);
+ ScheduledRecording r2 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 100L);
+ schedules.add(r2);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(
+ Collections.singletonList(
+ ScheduledRecording.builder(INPUT_ID, ++channelId, 10L, 20L)
+ .setPriority(++priority)
+ .build()),
+ schedules,
+ 1),
+ r2,
+ r1);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(
+ Collections.singletonList(
+ ScheduledRecording.builder(INPUT_ID, ++channelId, 110L, 120L)
+ .setPriority(++priority)
+ .build()),
+ schedules,
+ 1),
+ r1);
+ }
+
+ @Test
+ public void testGetConflictingSchedules_addSchedules2() {
+ long priority = 0;
+ long channelId = 0;
+ List<ScheduledRecording> schedules = new ArrayList<>();
+
+ ScheduledRecording r1 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 200L);
+ schedules.add(r1);
+ ScheduledRecording r2 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 100L, 200L);
+ schedules.add(r2);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(
+ Collections.singletonList(
+ ScheduledRecording.builder(INPUT_ID, ++channelId, 10L, 20L)
+ .setPriority(++priority)
+ .build()),
+ schedules,
+ 1),
+ r1);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(
+ Collections.singletonList(
+ ScheduledRecording.builder(INPUT_ID, ++channelId, 110L, 120L)
+ .setPriority(++priority)
+ .build()),
+ schedules,
+ 1),
+ r2,
+ r1);
+ }
+
+ @Test
+ public void testGetConflictingSchedules_addLowestPriority() {
+ long priority = 0;
+ long channelId = 0;
+ List<ScheduledRecording> schedules = new ArrayList<>();
+
+ ScheduledRecording r1 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 400L);
+ schedules.add(r1);
+ ScheduledRecording r2 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 100L, 200L);
+ schedules.add(r2);
+ // Returning r1 even though r1 has the higher priority than the new one. That's because r1
+ // starts at 0 and stops at 100, and the new one will be recorded successfully.
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(
+ Collections.singletonList(
+ ScheduledRecording.builder(INPUT_ID, ++channelId, 200L, 300L)
+ .setPriority(0)
+ .build()),
+ schedules,
+ 1),
+ r1);
+ }
+
+ @Test
+ public void testGetConflictingSchedules_sameChannel() {
+ long priority = 0;
+ long channelId = 1;
+ List<ScheduledRecording> schedules = new ArrayList<>();
+ schedules.add(
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ channelId, ++priority, 0L, 200L));
+ schedules.add(
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ channelId, ++priority, 0L, 200L));
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 3));
+ }
+
+ @Test
+ public void testGetConflictingSchedule_startEarlyAndFail() {
+ long priority = 0;
+ long channelId = 0;
+ List<ScheduledRecording> schedules = new ArrayList<>();
+ ScheduledRecording r1 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 200L, 300L);
+ schedules.add(r1);
+ ScheduledRecording r2 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 400L);
+ schedules.add(r2);
+ ScheduledRecording r3 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 100L, 200L);
+ schedules.add(r3);
+ // r2 starts recording and fails when r3 starts. r1 is recorded successfully.
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 1), r2);
+ }
+
+ @Test
+ public void testGetConflictingSchedule_startLate() {
+ long priority = 0;
+ long channelId = 0;
+ List<ScheduledRecording> schedules = new ArrayList<>();
+ ScheduledRecording r1 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 200L, 400L);
+ schedules.add(r1);
+ ScheduledRecording r2 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 100L, 300L);
+ schedules.add(r2);
+ ScheduledRecording r3 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 200L);
+ schedules.add(r3);
+ // r2 and r1 are clipped.
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedules(schedules, 1), r2, r1);
+ }
+
+ @Test
+ public void testGetConflictingSchedulesForTune_canTune() {
+ // Can tune to the recorded channel if tuner count is 1.
+ long priority = 0;
+ long channelId = 1;
+ List<ScheduledRecording> schedules = new ArrayList<>();
+ schedules.add(
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ channelId, ++priority, 0L, 200L));
+ MoreAsserts.assertEmpty(
+ DvrScheduleManager.getConflictingSchedulesForTune(
+ INPUT_ID, channelId, 0L, priority + 1, schedules, 1));
+ }
+
+ @Test
+ public void testGetConflictingSchedulesForTune_cannotTune() {
+ // Can't tune to a channel if other channel is recording and tuner count is 1.
+ long priority = 0;
+ long channelId = 1;
+ List<ScheduledRecording> schedules = new ArrayList<>();
+ schedules.add(
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ channelId, ++priority, 0L, 200L));
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedulesForTune(
+ INPUT_ID, channelId + 1, 0L, priority + 1, schedules, 1),
+ schedules.get(0));
+ }
+
+ @Test
+ public void testGetConflictingSchedulesForWatching_otherChannels() {
+ // The other channels are to be recorded.
+ long priority = 0;
+ long channelToWatch = 1;
+ long channelId = 1;
+ List<ScheduledRecording> schedules = new ArrayList<>();
+ ScheduledRecording r1 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 200L);
+ schedules.add(r1);
+ ScheduledRecording r2 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 200L);
+ schedules.add(r2);
+ MoreAsserts.assertEmpty(
+ DvrScheduleManager.getConflictingSchedulesForWatching(
+ INPUT_ID, channelToWatch, 0L, ++priority, schedules, 3));
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedulesForWatching(
+ INPUT_ID, channelToWatch, 0L, ++priority, schedules, 2),
+ r1);
+ }
+
+ @Test
+ public void testGetConflictingSchedulesForWatching_sameChannel1() {
+ long priority = 0;
+ long channelToWatch = 1;
+ long channelId = 1;
+ List<ScheduledRecording> schedules = new ArrayList<>();
+ ScheduledRecording r1 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ channelToWatch, ++priority, 0L, 200L);
+ schedules.add(r1);
+ ScheduledRecording r2 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 200L);
+ schedules.add(r2);
+ MoreAsserts.assertEmpty(
+ DvrScheduleManager.getConflictingSchedulesForWatching(
+ INPUT_ID, channelToWatch, 0L, ++priority, schedules, 2));
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedulesForWatching(
+ INPUT_ID, channelToWatch, 0L, ++priority, schedules, 1),
+ r2);
+ }
+
+ @Test
+ public void testGetConflictingSchedulesForWatching_sameChannel2() {
+ long priority = 0;
+ long channelToWatch = 1;
+ long channelId = 1;
+ List<ScheduledRecording> schedules = new ArrayList<>();
+ ScheduledRecording r1 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 200L);
+ schedules.add(r1);
+ ScheduledRecording r2 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ channelToWatch, ++priority, 0L, 200L);
+ schedules.add(r2);
+ MoreAsserts.assertEmpty(
+ DvrScheduleManager.getConflictingSchedulesForWatching(
+ INPUT_ID, channelToWatch, 0L, ++priority, schedules, 2));
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedulesForWatching(
+ INPUT_ID, channelToWatch, 0L, ++priority, schedules, 1),
+ r1);
+ }
+
+ @Test
+ public void testGetConflictingSchedulesForWatching_sameChannelConflict1() {
+ long priority = 0;
+ long channelToWatch = 1;
+ long channelId = 1;
+ List<ScheduledRecording> schedules = new ArrayList<>();
+ ScheduledRecording r1 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 200L);
+ schedules.add(r1);
+ ScheduledRecording r2 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ channelToWatch, ++priority, 0L, 200L);
+ schedules.add(r2);
+ ScheduledRecording r3 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ channelToWatch, ++priority, 0L, 200L);
+ schedules.add(r3);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedulesForWatching(
+ INPUT_ID, channelToWatch, 0L, ++priority, schedules, 3),
+ r2);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedulesForWatching(
+ INPUT_ID, channelToWatch, 0L, ++priority, schedules, 2),
+ r2);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedulesForWatching(
+ INPUT_ID, channelToWatch, 0L, ++priority, schedules, 1),
+ r2,
+ r1);
+ }
+
+ @Test
+ public void testGetConflictingSchedulesForWatching_sameChannelConflict2() {
+ long priority = 0;
+ long channelToWatch = 1;
+ long channelId = 1;
+ List<ScheduledRecording> schedules = new ArrayList<>();
+ ScheduledRecording r1 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ channelToWatch, ++priority, 0L, 200L);
+ schedules.add(r1);
+ ScheduledRecording r2 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ channelToWatch, ++priority, 0L, 200L);
+ schedules.add(r2);
+ ScheduledRecording r3 =
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, ++priority, 0L, 200L);
+ schedules.add(r3);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedulesForWatching(
+ INPUT_ID, channelToWatch, 0L, ++priority, schedules, 3),
+ r1);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedulesForWatching(
+ INPUT_ID, channelToWatch, 0L, ++priority, schedules, 2),
+ r1);
+ MoreAsserts.assertContentsInOrder(
+ DvrScheduleManager.getConflictingSchedulesForWatching(
+ INPUT_ID, channelToWatch, 0L, ++priority, schedules, 1),
+ r3,
+ r1);
+ }
+
+ @Test
+ public void testPartiallyConflictingSchedules() {
+ long priority = 100;
+ long channelId = 0;
+ List<ScheduledRecording> schedules =
+ new ArrayList<>(
+ Arrays.asList(
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, --priority, 0L, 400L),
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, --priority, 0L, 200L),
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, --priority, 200L, 500L),
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, --priority, 400L, 600L),
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, --priority, 700L, 800L),
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, --priority, 600L, 900L),
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, --priority, 800L, 900L),
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, --priority, 800L, 900L),
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, --priority, 750L, 850L),
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, --priority, 300L, 450L),
+ RecordingTestUtils.createTestRecordingWithPriorityAndPeriod(
+ ++channelId, --priority, 50L, 900L)));
+ List<ConflictInfo> conflicts = DvrScheduleManager.getConflictingSchedulesInfo(schedules, 1);
+
+ assertNotInList(schedules.get(0), conflicts);
+ assertFullConflict(schedules.get(1), conflicts);
+ assertPartialConflict(schedules.get(2), conflicts);
+ assertPartialConflict(schedules.get(3), conflicts);
+ assertNotInList(schedules.get(4), conflicts);
+ assertPartialConflict(schedules.get(5), conflicts);
+ assertNotInList(schedules.get(6), conflicts);
+ assertFullConflict(schedules.get(7), conflicts);
+ assertFullConflict(schedules.get(8), conflicts);
+ assertFullConflict(schedules.get(9), conflicts);
+ assertFullConflict(schedules.get(10), conflicts);
+
+ conflicts = DvrScheduleManager.getConflictingSchedulesInfo(schedules, 2);
+
+ assertNotInList(schedules.get(0), conflicts);
+ assertNotInList(schedules.get(1), conflicts);
+ assertNotInList(schedules.get(2), conflicts);
+ assertNotInList(schedules.get(3), conflicts);
+ assertNotInList(schedules.get(4), conflicts);
+ assertNotInList(schedules.get(5), conflicts);
+ assertNotInList(schedules.get(6), conflicts);
+ assertFullConflict(schedules.get(7), conflicts);
+ assertFullConflict(schedules.get(8), conflicts);
+ assertFullConflict(schedules.get(9), conflicts);
+ assertPartialConflict(schedules.get(10), conflicts);
+
+ conflicts = DvrScheduleManager.getConflictingSchedulesInfo(schedules, 3);
+
+ assertNotInList(schedules.get(0), conflicts);
+ assertNotInList(schedules.get(1), conflicts);
+ assertNotInList(schedules.get(2), conflicts);
+ assertNotInList(schedules.get(3), conflicts);
+ assertNotInList(schedules.get(4), conflicts);
+ assertNotInList(schedules.get(5), conflicts);
+ assertNotInList(schedules.get(6), conflicts);
+ assertNotInList(schedules.get(7), conflicts);
+ assertPartialConflict(schedules.get(8), conflicts);
+ assertNotInList(schedules.get(9), conflicts);
+ assertPartialConflict(schedules.get(10), conflicts);
+ }
+
+ private void assertNotInList(ScheduledRecording schedule, List<ConflictInfo> conflicts) {
+ for (ConflictInfo conflictInfo : conflicts) {
+ if (conflictInfo.schedule.equals(schedule)) {
+ fail(schedule + " conflicts with others.");
+ }
+ }
+ }
+
+ private void assertPartialConflict(ScheduledRecording schedule, List<ConflictInfo> conflicts) {
+ for (ConflictInfo conflictInfo : conflicts) {
+ if (conflictInfo.schedule.equals(schedule)) {
+ if (conflictInfo.partialConflict) {
+ return;
+ } else {
+ fail(schedule + " fully conflicts with others.");
+ }
+ }
+ }
+ fail(schedule + " doesn't conflict");
+ }
+
+ private void assertFullConflict(ScheduledRecording schedule, List<ConflictInfo> conflicts) {
+ for (ConflictInfo conflictInfo : conflicts) {
+ if (conflictInfo.schedule.equals(schedule)) {
+ if (!conflictInfo.partialConflict) {
+ return;
+ } else {
+ fail(schedule + " partially conflicts with others.");
+ }
+ }
+ }
+ fail(schedule + " doesn't conflict");
+ }
+}
diff --git a/tests/unit/src/com/android/tv/dvr/ScheduledRecordingTest.java b/tests/unit/src/com/android/tv/dvr/ScheduledRecordingTest.java
new file mode 100644
index 00000000..bf1b4d38
--- /dev/null
+++ b/tests/unit/src/com/android/tv/dvr/ScheduledRecordingTest.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.dvr;
+
+import static com.android.tv.testing.dvr.RecordingTestUtils.createTestRecordingWithIdAndPeriod;
+import static com.android.tv.testing.dvr.RecordingTestUtils.normalizePriority;
+import static junit.framework.TestCase.assertEquals;
+
+import android.os.Build;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+import android.test.MoreAsserts;
+import android.util.Range;
+import com.android.tv.data.Channel;
+import com.android.tv.data.Program;
+import com.android.tv.dvr.data.ScheduledRecording;
+import com.android.tv.testing.dvr.RecordingTestUtils;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Test;
+
+/** Tests for {@link ScheduledRecordingTest} */
+@SmallTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+public class ScheduledRecordingTest {
+ private static final String INPUT_ID = "input_id";
+ private static final int CHANNEL_ID = 273;
+
+ @Test
+ public void testIsOverLapping() {
+ ScheduledRecording r =
+ createTestRecordingWithIdAndPeriod(1, INPUT_ID, CHANNEL_ID, 10L, 20L);
+ assertOverLapping(false, 1L, 9L, r);
+
+ assertOverLapping(true, 1L, 20L, r);
+ assertOverLapping(false, 1L, 10L, r);
+ assertOverLapping(true, 10L, 19L, r);
+ assertOverLapping(true, 10L, 20L, r);
+ assertOverLapping(true, 11L, 20L, r);
+ assertOverLapping(true, 11L, 21L, r);
+ assertOverLapping(false, 20L, 21L, r);
+
+ assertOverLapping(false, 21L, 29L, r);
+ }
+
+ @Test
+ public void testBuildProgram() {
+ Channel c = new Channel.Builder().build();
+ Program p = new Program.Builder().build();
+ ScheduledRecording actual =
+ ScheduledRecording.builder(INPUT_ID, p).setChannelId(c.getId()).build();
+ assertEquals("type", ScheduledRecording.TYPE_PROGRAM, actual.getType());
+ }
+
+ @Test
+ public void testBuildTime() {
+ ScheduledRecording actual =
+ createTestRecordingWithIdAndPeriod(1, INPUT_ID, CHANNEL_ID, 10L, 20L);
+ assertEquals("type", ScheduledRecording.TYPE_TIMED, actual.getType());
+ }
+
+ @Test
+ public void testBuildFrom() {
+ ScheduledRecording expected =
+ createTestRecordingWithIdAndPeriod(1, INPUT_ID, CHANNEL_ID, 10L, 20L);
+ ScheduledRecording actual = ScheduledRecording.buildFrom(expected).build();
+ RecordingTestUtils.assertRecordingEquals(expected, actual);
+ }
+
+ @Test
+ public void testBuild_priority() {
+ ScheduledRecording a =
+ normalizePriority(
+ createTestRecordingWithIdAndPeriod(1, INPUT_ID, CHANNEL_ID, 10L, 20L));
+ ScheduledRecording b =
+ normalizePriority(
+ createTestRecordingWithIdAndPeriod(2, INPUT_ID, CHANNEL_ID, 10L, 20L));
+ ScheduledRecording c =
+ normalizePriority(
+ createTestRecordingWithIdAndPeriod(3, INPUT_ID, CHANNEL_ID, 10L, 20L));
+
+ // default priority
+ MoreAsserts.assertContentsInOrder(sortByPriority(c, b, a), a, b, c);
+
+ // make A preferred over B
+ a = ScheduledRecording.buildFrom(a).setPriority(b.getPriority() + 2).build();
+ MoreAsserts.assertContentsInOrder(sortByPriority(a, b, c), b, c, a);
+ }
+
+ public Collection<ScheduledRecording> sortByPriority(
+ ScheduledRecording a, ScheduledRecording b, ScheduledRecording c) {
+ List<ScheduledRecording> list = Arrays.asList(a, b, c);
+ Collections.sort(list, ScheduledRecording.PRIORITY_COMPARATOR);
+ return list;
+ }
+
+ private void assertOverLapping(boolean expected, long lower, long upper, ScheduledRecording r) {
+ assertEquals(
+ "isOverlapping(Range(" + lower + "," + upper + "), recording " + r,
+ expected,
+ r.isOverLapping(new Range<>(lower, upper)));
+ }
+}
diff --git a/tests/unit/src/com/android/tv/dvr/data/SeriesRecordingTest.java b/tests/unit/src/com/android/tv/dvr/data/SeriesRecordingTest.java
new file mode 100644
index 00000000..68929e95
--- /dev/null
+++ b/tests/unit/src/com/android/tv/dvr/data/SeriesRecordingTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.tv.dvr.data;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.Build;
+import android.os.Parcel;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+import com.android.tv.data.Program;
+import org.junit.Test;
+
+/** Tests for {@link SeriesRecording}. */
+@SmallTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+public class SeriesRecordingTest {
+ private static final String PROGRAM_TITLE = "MyProgram";
+ private static final long CHANNEL_ID = 123;
+ private static final long OTHER_CHANNEL_ID = 321;
+ private static final String SERIES_ID = "SERIES_ID";
+ private static final String OTHER_SERIES_ID = "OTHER_SERIES_ID";
+
+ private final SeriesRecording mBaseSeriesRecording =
+ new SeriesRecording.Builder()
+ .setTitle(PROGRAM_TITLE)
+ .setChannelId(CHANNEL_ID)
+ .setSeriesId(SERIES_ID)
+ .build();
+ private final SeriesRecording mSeriesRecordingSeason2 =
+ SeriesRecording.buildFrom(mBaseSeriesRecording).setStartFromSeason(2).build();
+ private final SeriesRecording mSeriesRecordingSeason2Episode5 =
+ SeriesRecording.buildFrom(mSeriesRecordingSeason2).setStartFromEpisode(5).build();
+ private final Program mBaseProgram =
+ new Program.Builder()
+ .setTitle(PROGRAM_TITLE)
+ .setChannelId(CHANNEL_ID)
+ .setSeriesId(SERIES_ID)
+ .build();
+
+ @Test
+ public void testParcelable() {
+ SeriesRecording r1 =
+ new SeriesRecording.Builder()
+ .setId(1)
+ .setChannelId(2)
+ .setPriority(3)
+ .setTitle("4")
+ .setDescription("5")
+ .setLongDescription("5-long")
+ .setSeriesId("6")
+ .setStartFromEpisode(7)
+ .setStartFromSeason(8)
+ .setChannelOption(SeriesRecording.OPTION_CHANNEL_ALL)
+ .setCanonicalGenreIds(new int[] {9, 10})
+ .setPosterUri("11")
+ .setPhotoUri("12")
+ .build();
+ Parcel p1 = Parcel.obtain();
+ Parcel p2 = Parcel.obtain();
+ try {
+ r1.writeToParcel(p1, 0);
+ byte[] bytes = p1.marshall();
+ p2.unmarshall(bytes, 0, bytes.length);
+ p2.setDataPosition(0);
+ SeriesRecording r2 = SeriesRecording.fromParcel(p2);
+ assertEquals(r1, r2);
+ } finally {
+ p1.recycle();
+ p2.recycle();
+ }
+ }
+
+ @Test
+ public void testDoesProgramMatch_simpleMatch() {
+ assertDoesProgramMatch(mBaseProgram, mBaseSeriesRecording, true);
+ }
+
+ @Test
+ public void testDoesProgramMatch_differentSeriesId() {
+ Program program = new Program.Builder(mBaseProgram).setSeriesId(OTHER_SERIES_ID).build();
+ assertDoesProgramMatch(program, mBaseSeriesRecording, false);
+ }
+
+ @Test
+ public void testDoesProgramMatch_differentChannel() {
+ Program program = new Program.Builder(mBaseProgram).setChannelId(OTHER_CHANNEL_ID).build();
+ assertDoesProgramMatch(program, mBaseSeriesRecording, false);
+ }
+
+ @Test
+ public void testDoesProgramMatch_startFromSeason2() {
+ Program program = mBaseProgram;
+ assertDoesProgramMatch(program, mSeriesRecordingSeason2, true);
+ program = new Program.Builder(program).setSeasonNumber("1").build();
+ assertDoesProgramMatch(program, mSeriesRecordingSeason2, false);
+ program = new Program.Builder(program).setSeasonNumber("2").build();
+ assertDoesProgramMatch(program, mSeriesRecordingSeason2, true);
+ program = new Program.Builder(program).setSeasonNumber("3").build();
+ assertDoesProgramMatch(program, mSeriesRecordingSeason2, true);
+ }
+
+ @Test
+ public void testDoesProgramMatch_startFromSeason2episode5() {
+ Program program = mBaseProgram;
+ assertDoesProgramMatch(program, mSeriesRecordingSeason2Episode5, true);
+ program = new Program.Builder(program).setSeasonNumber("2").build();
+ assertDoesProgramMatch(program, mSeriesRecordingSeason2Episode5, true);
+ program = new Program.Builder(program).setEpisodeNumber("4").build();
+ assertDoesProgramMatch(program, mSeriesRecordingSeason2Episode5, false);
+ program = new Program.Builder(program).setEpisodeNumber("5").build();
+ assertDoesProgramMatch(program, mSeriesRecordingSeason2Episode5, true);
+ program = new Program.Builder(program).setEpisodeNumber("6").build();
+ assertDoesProgramMatch(program, mSeriesRecordingSeason2Episode5, true);
+ program = new Program.Builder(program).setSeasonNumber("3").setEpisodeNumber("1").build();
+ assertDoesProgramMatch(program, mSeriesRecordingSeason2Episode5, true);
+ }
+
+ private void assertDoesProgramMatch(
+ Program p, SeriesRecording seriesRecording, boolean expected) {
+ assertEquals(
+ seriesRecording + " doesProgramMatch " + p,
+ expected,
+ seriesRecording.matchProgram(p));
+ }
+}
diff --git a/tests/unit/src/com/android/tv/dvr/provider/DvrDbSyncTest.java b/tests/unit/src/com/android/tv/dvr/provider/DvrDbSyncTest.java
new file mode 100644
index 00000000..10a882f6
--- /dev/null
+++ b/tests/unit/src/com/android/tv/dvr/provider/DvrDbSyncTest.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.tv.dvr.provider;
+
+import static android.support.test.InstrumentationRegistry.getContext;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.os.Build;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+import com.android.tv.data.ChannelDataManager;
+import com.android.tv.data.Program;
+import com.android.tv.dvr.DvrDataManagerImpl;
+import com.android.tv.dvr.DvrManager;
+import com.android.tv.dvr.data.ScheduledRecording;
+import com.android.tv.dvr.data.SeriesRecording;
+import com.android.tv.dvr.recorder.SeriesRecordingScheduler;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Tests for {@link com.android.tv.dvr.DvrScheduleManager} */
+@SmallTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+public class DvrDbSyncTest {
+ private static final String INPUT_ID = "input_id";
+ private static final long BASE_PROGRAM_ID = 1;
+ private static final long BASE_START_TIME_MS = 0;
+ private static final long BASE_END_TIME_MS = 1;
+ private static final String BASE_SEASON_NUMBER = "2";
+ private static final String BASE_EPISODE_NUMBER = "3";
+ private static final Program BASE_PROGRAM =
+ new Program.Builder()
+ .setId(BASE_PROGRAM_ID)
+ .setStartTimeUtcMillis(BASE_START_TIME_MS)
+ .setEndTimeUtcMillis(BASE_END_TIME_MS)
+ .build();
+ private static final Program BASE_SERIES_PROGRAM =
+ new Program.Builder()
+ .setId(BASE_PROGRAM_ID)
+ .setStartTimeUtcMillis(BASE_START_TIME_MS)
+ .setEndTimeUtcMillis(BASE_END_TIME_MS)
+ .setSeasonNumber(BASE_SEASON_NUMBER)
+ .setEpisodeNumber(BASE_EPISODE_NUMBER)
+ .build();
+ private static final ScheduledRecording BASE_SCHEDULE =
+ ScheduledRecording.builder(INPUT_ID, BASE_PROGRAM).build();
+ private static final ScheduledRecording BASE_SERIES_SCHEDULE =
+ ScheduledRecording.builder(INPUT_ID, BASE_SERIES_PROGRAM).build();
+
+ private DvrDbSync mDbSync;
+ @Mock private DvrManager mDvrManager;
+ @Mock private DvrDataManagerImpl mDataManager;
+ @Mock private ChannelDataManager mChannelDataManager;
+ @Mock private SeriesRecordingScheduler mSeriesRecordingScheduler;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mChannelDataManager.isDbLoadFinished()).thenReturn(true);
+ when(mDvrManager.addSeriesRecording(anyObject(), anyObject(), anyInt()))
+ .thenReturn(SeriesRecording.builder(INPUT_ID, BASE_PROGRAM).build());
+ mDbSync =
+ new DvrDbSync(
+ getContext(),
+ mDataManager,
+ mChannelDataManager,
+ mDvrManager,
+ mSeriesRecordingScheduler);
+ }
+
+ @Test
+ public void testHandleUpdateProgram_null() {
+ addSchedule(BASE_PROGRAM_ID, BASE_SCHEDULE);
+ mDbSync.handleUpdateProgram(null, BASE_PROGRAM_ID);
+ verify(mDataManager).removeScheduledRecording(BASE_SCHEDULE);
+ }
+
+ @Test
+ public void testHandleUpdateProgram_changeTimeNotStarted() {
+ addSchedule(BASE_PROGRAM_ID, BASE_SCHEDULE);
+ long startTimeMs = BASE_START_TIME_MS + 1;
+ long endTimeMs = BASE_END_TIME_MS + 1;
+ Program program =
+ new Program.Builder(BASE_PROGRAM)
+ .setStartTimeUtcMillis(startTimeMs)
+ .setEndTimeUtcMillis(endTimeMs)
+ .build();
+ mDbSync.handleUpdateProgram(program, BASE_PROGRAM_ID);
+ assertUpdateScheduleCalled(program);
+ }
+
+ @Test
+ public void testHandleUpdateProgram_changeTimeInProgressNotCalled() {
+ addSchedule(
+ BASE_PROGRAM_ID,
+ ScheduledRecording.buildFrom(BASE_SCHEDULE)
+ .setState(ScheduledRecording.STATE_RECORDING_IN_PROGRESS)
+ .build());
+ long startTimeMs = BASE_START_TIME_MS + 1;
+ Program program =
+ new Program.Builder(BASE_PROGRAM).setStartTimeUtcMillis(startTimeMs).build();
+ mDbSync.handleUpdateProgram(program, BASE_PROGRAM_ID);
+ verify(mDataManager, never()).updateScheduledRecording(anyObject());
+ }
+
+ @Test
+ public void testHandleUpdateProgram_changeSeason() {
+ addSchedule(BASE_PROGRAM_ID, BASE_SERIES_SCHEDULE);
+ String seasonNumber = BASE_SEASON_NUMBER + "1";
+ String episodeNumber = BASE_EPISODE_NUMBER + "1";
+ Program program =
+ new Program.Builder(BASE_SERIES_PROGRAM)
+ .setSeasonNumber(seasonNumber)
+ .setEpisodeNumber(episodeNumber)
+ .build();
+ mDbSync.handleUpdateProgram(program, BASE_PROGRAM_ID);
+ assertUpdateScheduleCalled(program);
+ }
+
+ @Test
+ public void testHandleUpdateProgram_finished() {
+ addSchedule(
+ BASE_PROGRAM_ID,
+ ScheduledRecording.buildFrom(BASE_SERIES_SCHEDULE)
+ .setState(ScheduledRecording.STATE_RECORDING_FINISHED)
+ .build());
+ String seasonNumber = BASE_SEASON_NUMBER + "1";
+ String episodeNumber = BASE_EPISODE_NUMBER + "1";
+ Program program =
+ new Program.Builder(BASE_SERIES_PROGRAM)
+ .setSeasonNumber(seasonNumber)
+ .setEpisodeNumber(episodeNumber)
+ .build();
+ mDbSync.handleUpdateProgram(program, BASE_PROGRAM_ID);
+ verify(mDataManager, never()).updateScheduledRecording(anyObject());
+ }
+
+ private void addSchedule(long programId, ScheduledRecording schedule) {
+ when(mDataManager.getScheduledRecordingForProgramId(programId)).thenReturn(schedule);
+ }
+
+ private void assertUpdateScheduleCalled(Program program) {
+ verify(mDataManager)
+ .updateScheduledRecording(
+ eq(ScheduledRecording.builder(INPUT_ID, program).build()));
+ }
+}
diff --git a/tests/unit/src/com/android/tv/dvr/provider/EpisodicProgramLoadTaskTest.java b/tests/unit/src/com/android/tv/dvr/provider/EpisodicProgramLoadTaskTest.java
new file mode 100644
index 00000000..a586fd9e
--- /dev/null
+++ b/tests/unit/src/com/android/tv/dvr/provider/EpisodicProgramLoadTaskTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.dvr.provider;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Build;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+import com.android.tv.dvr.data.SeasonEpisodeNumber;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Test;
+
+/** Tests for {@link EpisodicProgramLoadTask} */
+@SmallTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+public class EpisodicProgramLoadTaskTest {
+ private static final long SERIES_RECORDING_ID1 = 1;
+ private static final long SERIES_RECORDING_ID2 = 2;
+ private static final String SEASON_NUMBER1 = "SEASON NUMBER1";
+ private static final String SEASON_NUMBER2 = "SEASON NUMBER2";
+ private static final String EPISODE_NUMBER1 = "EPISODE NUMBER1";
+ private static final String EPISODE_NUMBER2 = "EPISODE NUMBER2";
+
+ @Test
+ public void testEpisodeAlreadyScheduled_true() {
+ List<SeasonEpisodeNumber> seasonEpisodeNumbers = new ArrayList<>();
+ SeasonEpisodeNumber seasonEpisodeNumber =
+ new SeasonEpisodeNumber(SERIES_RECORDING_ID1, SEASON_NUMBER1, EPISODE_NUMBER1);
+ seasonEpisodeNumbers.add(seasonEpisodeNumber);
+ assertTrue(
+ seasonEpisodeNumbers.contains(
+ new SeasonEpisodeNumber(
+ SERIES_RECORDING_ID1, SEASON_NUMBER1, EPISODE_NUMBER1)));
+ }
+
+ @Test
+ public void testEpisodeAlreadyScheduled_false() {
+ List<SeasonEpisodeNumber> seasonEpisodeNumbers = new ArrayList<>();
+ SeasonEpisodeNumber seasonEpisodeNumber =
+ new SeasonEpisodeNumber(SERIES_RECORDING_ID1, SEASON_NUMBER1, EPISODE_NUMBER1);
+ seasonEpisodeNumbers.add(seasonEpisodeNumber);
+ assertFalse(
+ seasonEpisodeNumbers.contains(
+ new SeasonEpisodeNumber(
+ SERIES_RECORDING_ID2, SEASON_NUMBER1, EPISODE_NUMBER1)));
+ assertFalse(
+ seasonEpisodeNumbers.contains(
+ new SeasonEpisodeNumber(
+ SERIES_RECORDING_ID1, SEASON_NUMBER2, EPISODE_NUMBER1)));
+ assertFalse(
+ seasonEpisodeNumbers.contains(
+ new SeasonEpisodeNumber(
+ SERIES_RECORDING_ID1, SEASON_NUMBER1, EPISODE_NUMBER2)));
+ }
+
+ @Test
+ public void testEpisodeAlreadyScheduled_null() {
+ List<SeasonEpisodeNumber> seasonEpisodeNumbers = new ArrayList<>();
+ SeasonEpisodeNumber seasonEpisodeNumber =
+ new SeasonEpisodeNumber(SERIES_RECORDING_ID1, SEASON_NUMBER1, EPISODE_NUMBER1);
+ seasonEpisodeNumbers.add(seasonEpisodeNumber);
+ assertFalse(
+ seasonEpisodeNumbers.contains(
+ new SeasonEpisodeNumber(SERIES_RECORDING_ID1, null, EPISODE_NUMBER1)));
+ assertFalse(
+ seasonEpisodeNumbers.contains(
+ new SeasonEpisodeNumber(SERIES_RECORDING_ID1, SEASON_NUMBER1, null)));
+ assertFalse(
+ seasonEpisodeNumbers.contains(
+ new SeasonEpisodeNumber(SERIES_RECORDING_ID1, null, null)));
+ }
+}
diff --git a/tests/unit/src/com/android/tv/dvr/recorder/InputTaskSchedulerTest.java b/tests/unit/src/com/android/tv/dvr/recorder/InputTaskSchedulerTest.java
new file mode 100644
index 00000000..f4e6cdf9
--- /dev/null
+++ b/tests/unit/src/com/android/tv/dvr/recorder/InputTaskSchedulerTest.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.tv.dvr.recorder;
+
+import static android.support.test.InstrumentationRegistry.getContext;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.AlarmManager;
+import android.media.tv.TvInputInfo;
+import android.os.Build;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+import com.android.tv.InputSessionManager;
+import com.android.tv.data.Channel;
+import com.android.tv.data.ChannelDataManager;
+import com.android.tv.dvr.DvrManager;
+import com.android.tv.dvr.WritableDvrDataManager;
+import com.android.tv.dvr.data.ScheduledRecording;
+import com.android.tv.dvr.recorder.InputTaskScheduler.RecordingTaskFactory;
+import com.android.tv.testing.FakeClock;
+import com.android.tv.testing.dvr.RecordingTestUtils;
+import com.android.tv.util.Clock;
+import com.android.tv.util.TestUtils;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Tests for {@link InputTaskScheduler}. */
+@SmallTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+public class InputTaskSchedulerTest {
+ private static final String INPUT_ID = "input_id";
+ private static final int CHANNEL_ID = 1;
+ private static final long LISTENER_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(1);
+ private static final int TUNER_COUNT_ONE = 1;
+ private static final int TUNER_COUNT_TWO = 2;
+ private static final long LOW_PRIORITY = 1;
+ private static final long HIGH_PRIORITY = 2;
+
+ private FakeClock mFakeClock;
+ private InputTaskScheduler mScheduler;
+ @Mock private DvrManager mDvrManager;
+ @Mock private WritableDvrDataManager mDataManager;
+ @Mock private InputSessionManager mSessionManager;
+ @Mock private AlarmManager mMockAlarmManager;
+ @Mock private ChannelDataManager mChannelDataManager;
+ private List<RecordingTask> mRecordingTasks;
+
+ @Before
+ public void setUp() throws Exception {
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ mRecordingTasks = new ArrayList();
+ MockitoAnnotations.initMocks(this);
+ mFakeClock = FakeClock.createWithCurrentTime();
+ TvInputInfo input = createTvInputInfo(TUNER_COUNT_ONE);
+ mScheduler =
+ new InputTaskScheduler(
+ getContext(),
+ input,
+ Looper.myLooper(),
+ mChannelDataManager,
+ mDvrManager,
+ mDataManager,
+ mSessionManager,
+ mFakeClock,
+ new RecordingTaskFactory() {
+ @Override
+ public RecordingTask createRecordingTask(
+ ScheduledRecording scheduledRecording,
+ Channel channel,
+ DvrManager dvrManager,
+ InputSessionManager sessionManager,
+ WritableDvrDataManager dataManager,
+ Clock clock) {
+ RecordingTask task = mock(RecordingTask.class);
+ when(task.getPriority())
+ .thenReturn(scheduledRecording.getPriority());
+ when(task.getEndTimeMs())
+ .thenReturn(scheduledRecording.getEndTimeMs());
+ mRecordingTasks.add(task);
+ return task;
+ }
+ });
+ }
+
+ @Test
+ public void testAddSchedule_past() {
+ ScheduledRecording r =
+ RecordingTestUtils.createTestRecordingWithPeriod(INPUT_ID, CHANNEL_ID, 0L, 1L);
+ when(mDataManager.getScheduledRecording(anyLong())).thenReturn(r);
+ mScheduler.handleAddSchedule(r);
+ mScheduler.handleBuildSchedule();
+ verify(mDataManager, timeout((int) LISTENER_TIMEOUT_MS).times(1))
+ .changeState(
+ any(ScheduledRecording.class),
+ eq(ScheduledRecording.STATE_RECORDING_FAILED));
+ }
+
+ @Test
+ public void testAddSchedule_start() {
+ mScheduler.handleAddSchedule(
+ RecordingTestUtils.createTestRecordingWithPeriod(
+ INPUT_ID,
+ CHANNEL_ID,
+ mFakeClock.currentTimeMillis(),
+ mFakeClock.currentTimeMillis() + TimeUnit.HOURS.toMillis(1)));
+ mScheduler.handleBuildSchedule();
+ verify(mRecordingTasks.get(0), timeout((int) LISTENER_TIMEOUT_MS).times(1)).start();
+ }
+
+ @Test
+ public void testAddSchedule_consecutiveNoStop() {
+ long startTimeMs = mFakeClock.currentTimeMillis();
+ long endTimeMs = startTimeMs + TimeUnit.SECONDS.toMillis(1);
+ long id = 0;
+ mScheduler.handleAddSchedule(
+ RecordingTestUtils.createTestRecordingWithIdAndPriorityAndPeriod(
+ ++id, CHANNEL_ID, LOW_PRIORITY, startTimeMs, endTimeMs));
+ mScheduler.handleBuildSchedule();
+ startTimeMs = endTimeMs;
+ endTimeMs = startTimeMs + TimeUnit.SECONDS.toMillis(1);
+ mScheduler.handleAddSchedule(
+ RecordingTestUtils.createTestRecordingWithIdAndPriorityAndPeriod(
+ ++id, CHANNEL_ID, HIGH_PRIORITY, startTimeMs, endTimeMs));
+ mScheduler.handleBuildSchedule();
+ verify(mRecordingTasks.get(0), timeout((int) LISTENER_TIMEOUT_MS).times(1)).start();
+ // The first schedule should not be stopped because the second one should wait for the end
+ // of the first schedule.
+ SystemClock.sleep(LISTENER_TIMEOUT_MS);
+ verify(mRecordingTasks.get(0), never()).stop();
+ }
+
+ @Test
+ public void testAddSchedule_consecutiveNoFail() {
+ long startTimeMs = mFakeClock.currentTimeMillis();
+ long endTimeMs = startTimeMs + TimeUnit.SECONDS.toMillis(1);
+ long id = 0;
+ when(mDataManager.getScheduledRecording(anyLong()))
+ .thenReturn(ScheduledRecording.builder(INPUT_ID, CHANNEL_ID, 0L, 0L).build());
+ mScheduler.handleAddSchedule(
+ RecordingTestUtils.createTestRecordingWithIdAndPriorityAndPeriod(
+ ++id, CHANNEL_ID, HIGH_PRIORITY, startTimeMs, endTimeMs));
+ mScheduler.handleBuildSchedule();
+ startTimeMs = endTimeMs;
+ endTimeMs = startTimeMs + TimeUnit.SECONDS.toMillis(1);
+ mScheduler.handleAddSchedule(
+ RecordingTestUtils.createTestRecordingWithIdAndPriorityAndPeriod(
+ ++id, CHANNEL_ID, LOW_PRIORITY, startTimeMs, endTimeMs));
+ mScheduler.handleBuildSchedule();
+ verify(mRecordingTasks.get(0), timeout((int) LISTENER_TIMEOUT_MS).times(1)).start();
+ SystemClock.sleep(LISTENER_TIMEOUT_MS);
+ verify(mRecordingTasks.get(0), never()).stop();
+ // The second schedule should not fail because it can starts after the first one finishes.
+ SystemClock.sleep(LISTENER_TIMEOUT_MS);
+ verify(mDataManager, never())
+ .changeState(
+ any(ScheduledRecording.class),
+ eq(ScheduledRecording.STATE_RECORDING_FAILED));
+ }
+
+ @Test
+ public void testAddSchedule_consecutiveUseLessSession() throws Exception {
+ TvInputInfo input = createTvInputInfo(TUNER_COUNT_TWO);
+ mScheduler.updateTvInputInfo(input);
+ long startTimeMs = mFakeClock.currentTimeMillis();
+ long endTimeMs = startTimeMs + TimeUnit.SECONDS.toMillis(1);
+ long id = 0;
+ mScheduler.handleAddSchedule(
+ RecordingTestUtils.createTestRecordingWithIdAndPriorityAndPeriod(
+ ++id, CHANNEL_ID, LOW_PRIORITY, startTimeMs, endTimeMs));
+ mScheduler.handleBuildSchedule();
+ startTimeMs = endTimeMs;
+ endTimeMs = startTimeMs + TimeUnit.SECONDS.toMillis(1);
+ mScheduler.handleAddSchedule(
+ RecordingTestUtils.createTestRecordingWithIdAndPriorityAndPeriod(
+ ++id, CHANNEL_ID, HIGH_PRIORITY, startTimeMs, endTimeMs));
+ mScheduler.handleBuildSchedule();
+ verify(mRecordingTasks.get(0), timeout((int) LISTENER_TIMEOUT_MS).times(1)).start();
+ SystemClock.sleep(LISTENER_TIMEOUT_MS);
+ verify(mRecordingTasks.get(0), never()).stop();
+ // The second schedule should wait until the first one finishes rather than creating a new
+ // session even though there are available tuners.
+ assertTrue(mRecordingTasks.size() == 1);
+ }
+
+ @Test
+ public void testUpdateSchedule_noCancel() {
+ ScheduledRecording r =
+ RecordingTestUtils.createTestRecordingWithPeriod(
+ INPUT_ID,
+ CHANNEL_ID,
+ mFakeClock.currentTimeMillis(),
+ mFakeClock.currentTimeMillis() + TimeUnit.HOURS.toMillis(1));
+ mScheduler.handleAddSchedule(r);
+ mScheduler.handleBuildSchedule();
+ mScheduler.handleUpdateSchedule(r);
+ SystemClock.sleep(LISTENER_TIMEOUT_MS);
+ verify(mRecordingTasks.get(0), never()).cancel();
+ }
+
+ @Test
+ public void testUpdateSchedule_cancel() {
+ ScheduledRecording r =
+ RecordingTestUtils.createTestRecordingWithPeriod(
+ INPUT_ID,
+ CHANNEL_ID,
+ mFakeClock.currentTimeMillis(),
+ mFakeClock.currentTimeMillis() + TimeUnit.HOURS.toMillis(2));
+ mScheduler.handleAddSchedule(r);
+ mScheduler.handleBuildSchedule();
+ mScheduler.handleUpdateSchedule(
+ ScheduledRecording.buildFrom(r)
+ .setStartTimeMs(mFakeClock.currentTimeMillis() + TimeUnit.HOURS.toMillis(1))
+ .build());
+ verify(mRecordingTasks.get(0), timeout((int) LISTENER_TIMEOUT_MS).times(1)).cancel();
+ }
+
+ private TvInputInfo createTvInputInfo(int tunerCount) throws Exception {
+ return TestUtils.createTvInputInfo(null, null, null, 0, false, true, tunerCount);
+ }
+}
diff --git a/tests/unit/src/com/android/tv/dvr/recorder/RecordingTaskTest.java b/tests/unit/src/com/android/tv/dvr/recorder/RecordingTaskTest.java
new file mode 100644
index 00000000..03a4fe50
--- /dev/null
+++ b/tests/unit/src/com/android/tv/dvr/recorder/RecordingTaskTest.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.tv.dvr.recorder;
+
+import static android.support.test.InstrumentationRegistry.getContext;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+import com.android.tv.InputSessionManager;
+import com.android.tv.InputSessionManager.RecordingSession;
+import com.android.tv.common.feature.CommonFeatures;
+import com.android.tv.common.feature.TestableFeature;
+import com.android.tv.data.Channel;
+import com.android.tv.dvr.DvrDataManagerInMemoryImpl;
+import com.android.tv.dvr.DvrManager;
+import com.android.tv.dvr.data.ScheduledRecording;
+import com.android.tv.dvr.recorder.RecordingTask.State;
+import com.android.tv.testing.FakeClock;
+import com.android.tv.testing.dvr.RecordingTestUtils;
+import java.util.concurrent.TimeUnit;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Tests for {@link RecordingTask}. */
+@SmallTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+public class RecordingTaskTest {
+ private static final long DURATION = TimeUnit.MINUTES.toMillis(30);
+ private static final long START_OFFSET_MS = RecordingScheduler.MS_TO_WAKE_BEFORE_START;
+ private static final String INPUT_ID = "input_id";
+ private static final int CHANNEL_ID = 273;
+
+ private FakeClock mFakeClock;
+ private DvrDataManagerInMemoryImpl mDataManager;
+ @Mock Handler mMockHandler;
+ @Mock DvrManager mDvrManager;
+ @Mock InputSessionManager mMockSessionManager;
+ @Mock RecordingSession mMockRecordingSession;
+ private final TestableFeature mDvrFeature = CommonFeatures.DVR;
+
+ @Before
+ public void setUp() {
+ mDvrFeature.enableForTest();
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ MockitoAnnotations.initMocks(this);
+ mFakeClock = FakeClock.createWithCurrentTime();
+ mDataManager = new DvrDataManagerInMemoryImpl(getContext(), mFakeClock);
+ }
+
+ @After
+ public void tearDown() {
+ mDvrFeature.resetForTests();
+ }
+
+ @Test
+ public void testHandle_init() {
+ Channel channel = createTestChannel();
+ ScheduledRecording r = createRecording(channel);
+ RecordingTask task = createRecordingTask(r, channel);
+ String inputId = channel.getInputId();
+ when(mMockSessionManager.createRecordingSession(
+ eq(inputId), anyString(), eq(task), eq(mMockHandler), anyLong()))
+ .thenReturn(mMockRecordingSession);
+ when(mMockHandler.sendMessageAtTime(anyObject(), anyLong())).thenReturn(true);
+ assertTrue(task.handleMessage(createMessage(RecordingTask.MSG_INITIALIZE)));
+ assertEquals(State.CONNECTION_PENDING, task.getState());
+ verify(mMockSessionManager)
+ .createRecordingSession(
+ eq(inputId), anyString(), eq(task), eq(mMockHandler), anyLong());
+ verify(mMockRecordingSession).tune(eq(inputId), eq(channel.getUri()));
+ verifyNoMoreInteractions(mMockHandler, mMockRecordingSession, mMockSessionManager);
+ }
+
+ private static Channel createTestChannel() {
+ return new Channel.Builder()
+ .setInputId(INPUT_ID)
+ .setId(CHANNEL_ID)
+ .setDisplayName("Test Ch " + CHANNEL_ID)
+ .build();
+ }
+
+ @Test
+ public void testOnConnected() {
+ Channel channel = createTestChannel();
+ ScheduledRecording r = createRecording(channel);
+ mDataManager.addScheduledRecording(r);
+ RecordingTask task = createRecordingTask(r, channel);
+ String inputId = channel.getInputId();
+ when(mMockSessionManager.createRecordingSession(
+ eq(inputId), anyString(), eq(task), eq(mMockHandler), anyLong()))
+ .thenReturn(mMockRecordingSession);
+ when(mMockHandler.sendMessageAtTime(anyObject(), anyLong())).thenReturn(true);
+ task.handleMessage(createMessage(RecordingTask.MSG_INITIALIZE));
+ task.onTuned(channel.getUri());
+ assertEquals(State.CONNECTED, task.getState());
+ }
+
+ private ScheduledRecording createRecording(Channel c) {
+ long startTime = mFakeClock.currentTimeMillis() + START_OFFSET_MS;
+ long endTime = startTime + DURATION;
+ return RecordingTestUtils.createTestRecordingWithPeriod(
+ c.getInputId(), c.getId(), startTime, endTime);
+ }
+
+ private RecordingTask createRecordingTask(ScheduledRecording r, Channel channel) {
+ RecordingTask recordingTask =
+ new RecordingTask(
+ getContext(),
+ r,
+ channel,
+ mDvrManager,
+ mMockSessionManager,
+ mDataManager,
+ mFakeClock);
+ recordingTask.setHandler(mMockHandler);
+ return recordingTask;
+ }
+
+ private Message createMessage(int what) {
+ Message msg = new Message();
+ msg.setTarget(mMockHandler);
+ msg.what = what;
+ return msg;
+ }
+}
diff --git a/tests/unit/src/com/android/tv/dvr/recorder/ScheduledProgramReaperTest.java b/tests/unit/src/com/android/tv/dvr/recorder/ScheduledProgramReaperTest.java
new file mode 100644
index 00000000..dc47fc86
--- /dev/null
+++ b/tests/unit/src/com/android/tv/dvr/recorder/ScheduledProgramReaperTest.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.dvr.recorder;
+
+import static android.support.test.InstrumentationRegistry.getContext;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Build;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+import android.test.MoreAsserts;
+import com.android.tv.common.feature.CommonFeatures;
+import com.android.tv.common.feature.TestableFeature;
+import com.android.tv.dvr.DvrDataManagerInMemoryImpl;
+import com.android.tv.dvr.DvrManager;
+import com.android.tv.dvr.data.ScheduledRecording;
+import com.android.tv.testing.FakeClock;
+import com.android.tv.testing.dvr.RecordingTestUtils;
+import java.util.concurrent.TimeUnit;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Tests for {@link ScheduledProgramReaper}. */
+@SmallTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+public class ScheduledProgramReaperTest {
+ private static final String INPUT_ID = "input_id";
+ private static final int CHANNEL_ID = 273;
+ private static final long DURATION = TimeUnit.HOURS.toMillis(1);
+
+ private ScheduledProgramReaper mReaper;
+ private FakeClock mFakeClock;
+ private DvrDataManagerInMemoryImpl mDvrDataManager;
+ @Mock private DvrManager mDvrManager;
+ private final TestableFeature mDvrFeature = CommonFeatures.DVR;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mDvrFeature.enableForTest();
+ mFakeClock = FakeClock.createWithTimeOne();
+ mDvrDataManager = new DvrDataManagerInMemoryImpl(getContext(), mFakeClock);
+ mReaper = new ScheduledProgramReaper(mDvrDataManager, mFakeClock);
+ }
+
+ @After
+ public void tearDown() {
+ mDvrFeature.resetForTests();
+ }
+
+ @Test
+ public void testRun_noRecordings() {
+ assertTrue(mDvrDataManager.getAllScheduledRecordings().isEmpty());
+ mReaper.run();
+ assertTrue(mDvrDataManager.getAllScheduledRecordings().isEmpty());
+ }
+
+ @Test
+ public void testRun_oneRecordingsTomorrow() {
+ ScheduledRecording recording = addNewScheduledRecordingForTomorrow();
+ MoreAsserts.assertContentsInAnyOrder(
+ mDvrDataManager.getAllScheduledRecordings(), recording);
+ mReaper.run();
+ MoreAsserts.assertContentsInAnyOrder(
+ mDvrDataManager.getAllScheduledRecordings(), recording);
+ }
+
+ @Test
+ public void testRun_oneRecordingsStarted() {
+ ScheduledRecording recording = addNewScheduledRecordingForTomorrow();
+ MoreAsserts.assertContentsInAnyOrder(
+ mDvrDataManager.getAllScheduledRecordings(), recording);
+ mFakeClock.increment(TimeUnit.DAYS);
+ mReaper.run();
+ MoreAsserts.assertContentsInAnyOrder(
+ mDvrDataManager.getAllScheduledRecordings(), recording);
+ }
+
+ @Test
+ public void testRun_oneRecordingsFinished() {
+ ScheduledRecording recording = addNewScheduledRecordingForTomorrow();
+ MoreAsserts.assertContentsInAnyOrder(
+ mDvrDataManager.getAllScheduledRecordings(), recording);
+ mFakeClock.increment(TimeUnit.DAYS);
+ mFakeClock.increment(TimeUnit.MINUTES, 2);
+ mReaper.run();
+ MoreAsserts.assertContentsInAnyOrder(
+ mDvrDataManager.getAllScheduledRecordings(), recording);
+ }
+
+ @Test
+ public void testRun_oneRecordingsExpired() {
+ ScheduledRecording recording = addNewScheduledRecordingForTomorrow();
+ MoreAsserts.assertContentsInAnyOrder(
+ mDvrDataManager.getAllScheduledRecordings(), recording);
+ mFakeClock.increment(TimeUnit.DAYS, 1 + ScheduledProgramReaper.DAYS);
+ mFakeClock.increment(TimeUnit.MILLISECONDS, DURATION);
+ // After the cutoff and enough so we can see on the clock
+ mFakeClock.increment(TimeUnit.SECONDS, 1);
+
+ mReaper.run();
+ assertTrue(
+ "Recordings after reaper at "
+ + com.android.tv.util.Utils.toIsoDateTimeString(
+ mFakeClock.currentTimeMillis()),
+ mDvrDataManager.getAllScheduledRecordings().isEmpty());
+ }
+
+ private ScheduledRecording addNewScheduledRecordingForTomorrow() {
+ long startTime = mFakeClock.currentTimeMillis() + TimeUnit.DAYS.toMillis(1);
+ ScheduledRecording recording =
+ RecordingTestUtils.createTestRecordingWithPeriod(
+ INPUT_ID, CHANNEL_ID, startTime, startTime + DURATION);
+ return mDvrDataManager.addScheduledRecordingInternal(
+ ScheduledRecording.buildFrom(recording)
+ .setState(ScheduledRecording.STATE_RECORDING_FINISHED)
+ .build());
+ }
+}
diff --git a/tests/unit/src/com/android/tv/dvr/recorder/SchedulerTest.java b/tests/unit/src/com/android/tv/dvr/recorder/SchedulerTest.java
new file mode 100644
index 00000000..008e43f1
--- /dev/null
+++ b/tests/unit/src/com/android/tv/dvr/recorder/SchedulerTest.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.tv.dvr.recorder;
+
+import static android.support.test.InstrumentationRegistry.getTargetContext;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.os.Build;
+import android.os.Looper;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+import com.android.tv.InputSessionManager;
+import com.android.tv.common.feature.CommonFeatures;
+import com.android.tv.common.feature.TestableFeature;
+import com.android.tv.data.ChannelDataManager;
+import com.android.tv.dvr.DvrDataManagerInMemoryImpl;
+import com.android.tv.dvr.DvrManager;
+import com.android.tv.dvr.data.ScheduledRecording;
+import com.android.tv.testing.FakeClock;
+import com.android.tv.testing.dvr.RecordingTestUtils;
+import com.android.tv.util.TvInputManagerHelper;
+import java.util.concurrent.TimeUnit;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+/** Tests for {@link RecordingScheduler}. */
+@SmallTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+public class SchedulerTest {
+ private static final String INPUT_ID = "input_id";
+ private static final int CHANNEL_ID = 273;
+
+ private FakeClock mFakeClock;
+ private DvrDataManagerInMemoryImpl mDataManager;
+ private RecordingScheduler mScheduler;
+ @Mock DvrManager mDvrManager;
+ @Mock InputSessionManager mSessionManager;
+ @Mock AlarmManager mMockAlarmManager;
+ @Mock ChannelDataManager mChannelDataManager;
+ @Mock TvInputManagerHelper mInputManager;
+ private final TestableFeature mDvrFeature = CommonFeatures.DVR;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mDvrFeature.enableForTest();
+ mFakeClock = FakeClock.createWithCurrentTime();
+ mDataManager = new DvrDataManagerInMemoryImpl(getTargetContext(), mFakeClock);
+ Mockito.when(mChannelDataManager.isDbLoadFinished()).thenReturn(true);
+ mScheduler =
+ new RecordingScheduler(
+ Looper.myLooper(),
+ mDvrManager,
+ mSessionManager,
+ mDataManager,
+ mChannelDataManager,
+ mInputManager,
+ getTargetContext(),
+ mFakeClock,
+ mMockAlarmManager);
+ }
+
+ @After
+ public void tearDown() {
+ mDvrFeature.resetForTests();
+ }
+
+ @Test
+ public void testUpdate_none() {
+ mScheduler.updateAndStartServiceIfNeeded();
+ verifyZeroInteractions(mMockAlarmManager);
+ }
+
+ @Test
+ public void testUpdate_nextIn12Hours() {
+ long now = mFakeClock.currentTimeMillis();
+ long startTime = now + TimeUnit.HOURS.toMillis(12);
+ ScheduledRecording r =
+ RecordingTestUtils.createTestRecordingWithPeriod(
+ INPUT_ID, CHANNEL_ID, startTime, startTime + TimeUnit.HOURS.toMillis(1));
+ mDataManager.addScheduledRecording(r);
+ verify(mMockAlarmManager)
+ .setExactAndAllowWhileIdle(
+ eq(AlarmManager.RTC_WAKEUP),
+ eq(startTime - RecordingScheduler.MS_TO_WAKE_BEFORE_START),
+ any(PendingIntent.class));
+ Mockito.reset(mMockAlarmManager);
+ mScheduler.updateAndStartServiceIfNeeded();
+ verify(mMockAlarmManager)
+ .setExactAndAllowWhileIdle(
+ eq(AlarmManager.RTC_WAKEUP),
+ eq(startTime - RecordingScheduler.MS_TO_WAKE_BEFORE_START),
+ any(PendingIntent.class));
+ }
+
+ @Test
+ public void testStartsWithin() {
+ long now = mFakeClock.currentTimeMillis();
+ long startTime = now + 3;
+ ScheduledRecording r =
+ RecordingTestUtils.createTestRecordingWithPeriod(
+ INPUT_ID, CHANNEL_ID, startTime, startTime + 100);
+ assertFalse(mScheduler.startsWithin(r, 2));
+ assertTrue(mScheduler.startsWithin(r, 3));
+ }
+}
diff --git a/tests/unit/src/com/android/tv/dvr/recorder/SeriesRecordingSchedulerTest.java b/tests/unit/src/com/android/tv/dvr/recorder/SeriesRecordingSchedulerTest.java
new file mode 100644
index 00000000..c7cbff55
--- /dev/null
+++ b/tests/unit/src/com/android/tv/dvr/recorder/SeriesRecordingSchedulerTest.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.dvr.recorder;
+
+import static android.support.test.InstrumentationRegistry.getContext;
+
+import android.os.Build;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+import android.test.MoreAsserts;
+import android.util.LongSparseArray;
+import com.android.tv.common.feature.CommonFeatures;
+import com.android.tv.common.feature.TestableFeature;
+import com.android.tv.data.Program;
+import com.android.tv.dvr.DvrDataManagerInMemoryImpl;
+import com.android.tv.dvr.data.SeriesRecording;
+import com.android.tv.testing.FakeClock;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/** Tests for {@link SeriesRecordingScheduler} */
+@SmallTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+public class SeriesRecordingSchedulerTest {
+ private static final String PROGRAM_TITLE = "MyProgram";
+ private static final long CHANNEL_ID = 123;
+ private static final long SERIES_RECORDING_ID1 = 1;
+ private static final String SERIES_ID = "SERIES_ID";
+ private static final String SEASON_NUMBER1 = "SEASON NUMBER1";
+ private static final String SEASON_NUMBER2 = "SEASON NUMBER2";
+ private static final String EPISODE_NUMBER1 = "EPISODE NUMBER1";
+ private static final String EPISODE_NUMBER2 = "EPISODE NUMBER2";
+
+ private final SeriesRecording mBaseSeriesRecording =
+ new SeriesRecording.Builder()
+ .setTitle(PROGRAM_TITLE)
+ .setChannelId(CHANNEL_ID)
+ .setSeriesId(SERIES_ID)
+ .build();
+ private final Program mBaseProgram =
+ new Program.Builder()
+ .setTitle(PROGRAM_TITLE)
+ .setChannelId(CHANNEL_ID)
+ .setSeriesId(SERIES_ID)
+ .build();
+ private final TestableFeature mDvrFeature = CommonFeatures.DVR;
+
+ private DvrDataManagerInMemoryImpl mDataManager;
+
+ @Before
+ public void setUp() {
+ mDvrFeature.enableForTest();
+ FakeClock fakeClock = FakeClock.createWithCurrentTime();
+ mDataManager = new DvrDataManagerInMemoryImpl(getContext(), fakeClock);
+ }
+
+ @After
+ public void tearDown() {
+ mDvrFeature.resetForTests();
+ }
+
+ @Test
+ public void testPickOneProgramPerEpisode_onePerEpisode() {
+ SeriesRecording seriesRecording =
+ SeriesRecording.buildFrom(mBaseSeriesRecording).setId(SERIES_RECORDING_ID1).build();
+ mDataManager.addSeriesRecording(seriesRecording);
+ List<Program> programs = new ArrayList<>();
+ Program program1 =
+ new Program.Builder(mBaseProgram)
+ .setSeasonNumber(SEASON_NUMBER1)
+ .setEpisodeNumber(EPISODE_NUMBER1)
+ .build();
+ programs.add(program1);
+ Program program2 =
+ new Program.Builder(mBaseProgram)
+ .setSeasonNumber(SEASON_NUMBER2)
+ .setEpisodeNumber(EPISODE_NUMBER2)
+ .build();
+ programs.add(program2);
+ LongSparseArray<List<Program>> result =
+ SeriesRecordingScheduler.pickOneProgramPerEpisode(
+ mDataManager, Collections.singletonList(seriesRecording), programs);
+ MoreAsserts.assertContentsInAnyOrder(result.get(SERIES_RECORDING_ID1), program1, program2);
+ }
+
+ @Test
+ public void testPickOneProgramPerEpisode_manyPerEpisode() {
+ SeriesRecording seriesRecording =
+ SeriesRecording.buildFrom(mBaseSeriesRecording).setId(SERIES_RECORDING_ID1).build();
+ mDataManager.addSeriesRecording(seriesRecording);
+ List<Program> programs = new ArrayList<>();
+ Program program1 =
+ new Program.Builder(mBaseProgram)
+ .setSeasonNumber(SEASON_NUMBER1)
+ .setEpisodeNumber(EPISODE_NUMBER1)
+ .setStartTimeUtcMillis(0)
+ .build();
+ programs.add(program1);
+ Program program2 = new Program.Builder(program1).setStartTimeUtcMillis(1).build();
+ programs.add(program2);
+ Program program3 =
+ new Program.Builder(mBaseProgram)
+ .setSeasonNumber(SEASON_NUMBER2)
+ .setEpisodeNumber(EPISODE_NUMBER2)
+ .build();
+ programs.add(program3);
+ Program program4 = new Program.Builder(program1).setStartTimeUtcMillis(1).build();
+ programs.add(program4);
+ LongSparseArray<List<Program>> result =
+ SeriesRecordingScheduler.pickOneProgramPerEpisode(
+ mDataManager, Collections.singletonList(seriesRecording), programs);
+ MoreAsserts.assertContentsInAnyOrder(result.get(SERIES_RECORDING_ID1), program1, program3);
+ }
+
+ @Test
+ public void testPickOneProgramPerEpisode_nullEpisode() {
+ SeriesRecording seriesRecording =
+ SeriesRecording.buildFrom(mBaseSeriesRecording).setId(SERIES_RECORDING_ID1).build();
+ mDataManager.addSeriesRecording(seriesRecording);
+ List<Program> programs = new ArrayList<>();
+ Program program1 = new Program.Builder(mBaseProgram).setStartTimeUtcMillis(0).build();
+ programs.add(program1);
+ Program program2 = new Program.Builder(mBaseProgram).setStartTimeUtcMillis(1).build();
+ programs.add(program2);
+ LongSparseArray<List<Program>> result =
+ SeriesRecordingScheduler.pickOneProgramPerEpisode(
+ mDataManager, Collections.singletonList(seriesRecording), programs);
+ MoreAsserts.assertContentsInAnyOrder(result.get(SERIES_RECORDING_ID1), program1, program2);
+ }
+}
diff --git a/tests/unit/src/com/android/tv/dvr/ui/SortedArrayAdapterTest.java b/tests/unit/src/com/android/tv/dvr/ui/SortedArrayAdapterTest.java
new file mode 100644
index 00000000..2a1b5667
--- /dev/null
+++ b/tests/unit/src/com/android/tv/dvr/ui/SortedArrayAdapterTest.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.dvr.ui;
+
+import android.support.test.filters.SmallTest;
+import android.support.v17.leanback.widget.ClassPresenterSelector;
+import android.support.v17.leanback.widget.ObjectAdapter;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Objects;
+import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.Test;
+
+/** Tests for {@link SortedArrayAdapter}. */
+@SmallTest
+public class SortedArrayAdapterTest extends TestCase {
+ public static final TestData P1 = TestData.create(1, "c");
+ public static final TestData P2 = TestData.create(2, "b");
+ public static final TestData P3 = TestData.create(3, "a");
+ public static final TestData EXTRA = TestData.create(4, "k");
+ private TestSortedArrayAdapter mAdapter;
+
+ @Before
+ public void setUp() {
+ mAdapter = new TestSortedArrayAdapter(Integer.MAX_VALUE, null);
+ }
+
+ @Test
+ public void testContents_empty() {
+ assertEmpty();
+ }
+
+ @Test
+ public void testAdd_one() {
+ mAdapter.add(P1);
+ assertNotEmpty();
+ assertContentsInOrder(mAdapter, P1);
+ }
+
+ @Test
+ public void testAdd_two() {
+ mAdapter.add(P1);
+ mAdapter.add(P2);
+ assertNotEmpty();
+ assertContentsInOrder(mAdapter, P2, P1);
+ }
+
+ @Test
+ public void testSetInitialItems_two() {
+ mAdapter.setInitialItems(Arrays.asList(P1, P2));
+ assertNotEmpty();
+ assertContentsInOrder(mAdapter, P2, P1);
+ }
+
+ @Test
+ public void testMaxInitialCount() {
+ mAdapter = new TestSortedArrayAdapter(1, null);
+ mAdapter.setInitialItems(Arrays.asList(P1, P2));
+ assertNotEmpty();
+ assertEquals(mAdapter.size(), 1);
+ assertEquals(mAdapter.get(0), P2);
+ }
+
+ @Test
+ public void testExtraItem() {
+ mAdapter = new TestSortedArrayAdapter(Integer.MAX_VALUE, EXTRA);
+ mAdapter.setInitialItems(Arrays.asList(P1, P2));
+ assertNotEmpty();
+ assertEquals(mAdapter.size(), 3);
+ assertEquals(mAdapter.get(0), P2);
+ assertEquals(mAdapter.get(2), EXTRA);
+ mAdapter.remove(P2);
+ mAdapter.remove(P1);
+ assertEquals(mAdapter.size(), 1);
+ assertEquals(mAdapter.get(0), EXTRA);
+ }
+
+ @Test
+ public void testExtraItemWithMaxCount() {
+ mAdapter = new TestSortedArrayAdapter(1, EXTRA);
+ mAdapter.setInitialItems(Arrays.asList(P1, P2));
+ assertNotEmpty();
+ assertEquals(mAdapter.size(), 2);
+ assertEquals(mAdapter.get(0), P2);
+ assertEquals(mAdapter.get(1), EXTRA);
+ mAdapter.remove(P2);
+ assertEquals(mAdapter.size(), 1);
+ assertEquals(mAdapter.get(0), EXTRA);
+ }
+
+ @Test
+ public void testRemove() {
+ mAdapter.add(P1);
+ mAdapter.add(P2);
+ assertNotEmpty();
+ assertContentsInOrder(mAdapter, P2, P1);
+ mAdapter.remove(P3);
+ assertContentsInOrder(mAdapter, P2, P1);
+ mAdapter.remove(P2);
+ assertContentsInOrder(mAdapter, P1);
+ mAdapter.remove(P1);
+ assertEmpty();
+ mAdapter.add(P1);
+ mAdapter.add(P2);
+ mAdapter.add(P3);
+ assertContentsInOrder(mAdapter, P3, P2, P1);
+ mAdapter.removeItems(0, 2);
+ assertContentsInOrder(mAdapter, P1);
+ mAdapter.add(P2);
+ mAdapter.add(P3);
+ mAdapter.addExtraItem(EXTRA);
+ assertContentsInOrder(mAdapter, P3, P2, P1, EXTRA);
+ mAdapter.removeItems(1, 1);
+ assertContentsInOrder(mAdapter, P3, P1, EXTRA);
+ mAdapter.removeItems(1, 2);
+ assertContentsInOrder(mAdapter, P3);
+ mAdapter.addExtraItem(EXTRA);
+ mAdapter.addExtraItem(P2);
+ mAdapter.add(P1);
+ assertContentsInOrder(mAdapter, P3, P1, EXTRA, P2);
+ mAdapter.removeItems(1, 2);
+ assertContentsInOrder(mAdapter, P3, P2);
+ mAdapter.add(P1);
+ assertContentsInOrder(mAdapter, P3, P1, P2);
+ }
+
+ @Test
+ public void testReplace() {
+ mAdapter.add(P1);
+ mAdapter.add(P2);
+ assertNotEmpty();
+ assertContentsInOrder(mAdapter, P2, P1);
+ mAdapter.replace(1, P3);
+ assertContentsInOrder(mAdapter, P3, P2);
+ mAdapter.replace(0, P1);
+ assertContentsInOrder(mAdapter, P2, P1);
+ mAdapter.addExtraItem(EXTRA);
+ assertContentsInOrder(mAdapter, P2, P1, EXTRA);
+ mAdapter.replace(2, P3);
+ assertContentsInOrder(mAdapter, P2, P1, P3);
+ }
+
+ @Test
+ public void testChange_sorting() {
+ TestData p2_changed = TestData.create(2, "z changed");
+ mAdapter.add(P1);
+ mAdapter.add(P2);
+ assertNotEmpty();
+ assertContentsInOrder(mAdapter, P2, P1);
+ mAdapter.change(p2_changed);
+ assertContentsInOrder(mAdapter, P1, p2_changed);
+ }
+
+ @Test
+ public void testChange_new() {
+ mAdapter.change(P1);
+ assertNotEmpty();
+ assertContentsInOrder(mAdapter, P1);
+ }
+
+ private void assertEmpty() {
+ assertEquals("empty", true, mAdapter.isEmpty());
+ }
+
+ private void assertNotEmpty() {
+ assertEquals("empty", false, mAdapter.isEmpty());
+ }
+
+ private static void assertContentsInOrder(ObjectAdapter adapter, Object... contents) {
+ int ex = contents.length;
+ assertEquals("size", ex, adapter.size());
+ for (int i = 0; i < ex; i++) {
+ assertEquals("element " + 1, contents[i], adapter.get(i));
+ }
+ }
+
+ private static class TestData {
+ @Override
+ public String toString() {
+ return "TestData[" + mId + "]{" + mText + '}';
+ }
+
+ static TestData create(long first, String text) {
+ return new TestData(first, text);
+ }
+
+ private final long mId;
+ private final String mText;
+
+ private TestData(long id, String second) {
+ this.mId = id;
+ this.mText = second;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof TestData)) return false;
+ TestData that = (TestData) o;
+ return mId == that.mId && Objects.equals(mText, that.mText);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mId, mText);
+ }
+ }
+
+ private static class TestSortedArrayAdapter extends SortedArrayAdapter<TestData> {
+
+ private static final Comparator<TestData> TEXT_COMPARATOR =
+ new Comparator<TestData>() {
+ @Override
+ public int compare(TestData lhs, TestData rhs) {
+ return lhs.mText.compareTo(rhs.mText);
+ }
+ };
+
+ TestSortedArrayAdapter(int maxInitialCount, Object extra) {
+ super(new ClassPresenterSelector(), TEXT_COMPARATOR, maxInitialCount);
+ if (extra != null) {
+ addExtraItem((TestData) extra);
+ }
+ }
+
+ @Override
+ protected long getId(TestData item) {
+ return item.mId;
+ }
+ }
+}
diff --git a/tests/unit/src/com/android/tv/experiments/ExperimentsTest.java b/tests/unit/src/com/android/tv/experiments/ExperimentsTest.java
new file mode 100644
index 00000000..f5fb353c
--- /dev/null
+++ b/tests/unit/src/com/android/tv/experiments/ExperimentsTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.tv.experiments;
+
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.filters.SmallTest;
+import com.android.tv.common.BuildConfig;
+import org.junit.Before;
+import org.junit.Test;
+
+/** Tests for {@link Experiments}. */
+@SmallTest
+public class ExperimentsTest {
+ @Before
+ public void setUp() {
+ ExperimentFlag.initForTest();
+ }
+
+ @Test
+ public void testEngOnlyDefault() {
+ assertEquals(
+ "ENABLE_DEVELOPER_FEATURES",
+ Boolean.valueOf(BuildConfig.ENG),
+ Experiments.ENABLE_DEVELOPER_FEATURES.get());
+ }
+}
diff --git a/tests/unit/src/com/android/tv/menu/TvOptionsRowAdapterTest.java b/tests/unit/src/com/android/tv/menu/TvOptionsRowAdapterTest.java
index 04d86bfc..4faca569 100644
--- a/tests/unit/src/com/android/tv/menu/TvOptionsRowAdapterTest.java
+++ b/tests/unit/src/com/android/tv/menu/TvOptionsRowAdapterTest.java
@@ -24,7 +24,7 @@ import android.os.SystemClock;
import android.support.test.filters.MediumTest;
import android.text.TextUtils;
import com.android.tv.BaseMainActivityTestCase;
-import com.android.tv.testing.constants.Constants;
+import com.android.tv.testing.Constants;
import com.android.tv.testing.testinput.ChannelState;
import com.android.tv.testing.testinput.ChannelStateData;
import com.android.tv.testing.testinput.TvTestInputConstants;
diff --git a/tests/unit/src/com/android/tv/recommendation/ChannelRecordTest.java b/tests/unit/src/com/android/tv/recommendation/ChannelRecordTest.java
index c2f0d0c5..d868d3f8 100644
--- a/tests/unit/src/com/android/tv/recommendation/ChannelRecordTest.java
+++ b/tests/unit/src/com/android/tv/recommendation/ChannelRecordTest.java
@@ -20,7 +20,7 @@ import static android.support.test.InstrumentationRegistry.getContext;
import static org.junit.Assert.assertEquals;
import android.support.test.filters.SmallTest;
-import com.android.tv.testing.utils.Utils;
+import com.android.tv.testing.Utils;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import org.junit.Before;
diff --git a/tests/unit/src/com/android/tv/recommendation/EvaluatorTestCase.java b/tests/unit/src/com/android/tv/recommendation/EvaluatorTestCase.java
index 6e76bf36..af941177 100644
--- a/tests/unit/src/com/android/tv/recommendation/EvaluatorTestCase.java
+++ b/tests/unit/src/com/android/tv/recommendation/EvaluatorTestCase.java
@@ -23,7 +23,7 @@ import static org.junit.Assert.assertTrue;
import com.android.tv.data.Channel;
import com.android.tv.recommendation.RecommendationUtils.ChannelRecordSortedMapHelper;
import com.android.tv.recommendation.Recommender.Evaluator;
-import com.android.tv.testing.utils.Utils;
+import com.android.tv.testing.Utils;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
diff --git a/tests/unit/src/com/android/tv/recommendation/RecommendationUtils.java b/tests/unit/src/com/android/tv/recommendation/RecommendationUtils.java
index 2fc4bb1c..eea42bf5 100644
--- a/tests/unit/src/com/android/tv/recommendation/RecommendationUtils.java
+++ b/tests/unit/src/com/android/tv/recommendation/RecommendationUtils.java
@@ -18,7 +18,7 @@ package com.android.tv.recommendation;
import android.content.Context;
import com.android.tv.data.Channel;
-import com.android.tv.testing.utils.Utils;
+import com.android.tv.testing.Utils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
diff --git a/tests/unit/src/com/android/tv/recommendation/RecommenderTest.java b/tests/unit/src/com/android/tv/recommendation/RecommenderTest.java
index e2b0b249..062633a5 100644
--- a/tests/unit/src/com/android/tv/recommendation/RecommenderTest.java
+++ b/tests/unit/src/com/android/tv/recommendation/RecommenderTest.java
@@ -25,7 +25,7 @@ import android.support.test.filters.SmallTest;
import android.test.MoreAsserts;
import com.android.tv.data.Channel;
import com.android.tv.recommendation.RecommendationUtils.ChannelRecordSortedMapHelper;
-import com.android.tv.testing.utils.Utils;
+import com.android.tv.testing.Utils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -46,7 +46,7 @@ public class RecommenderTest {
System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1);
private static final long DEFAULT_MAX_WATCH_DURATION_MS = TimeUnit.HOURS.toMillis(1);
- private final Comparator<Channel> mChannelSortKeyComparator =
+ private final Comparator<Channel> CHANNEL_SORT_KEY_COMPARATOR =
new Comparator<Channel>() {
@Override
public int compare(Channel lhs, Channel rhs) {
@@ -55,7 +55,7 @@ public class RecommenderTest {
.compareTo(mRecommender.getChannelSortKey(rhs.getId()));
}
};
- private final Runnable mStartDatamanagerRunnableAddFourChannels =
+ private final Runnable START_DATAMANAGER_RUNNABLE_ADD_FOUR_CHANNELS =
new Runnable() {
@Override
public void run() {
@@ -89,7 +89,7 @@ public class RecommenderTest {
@Test
public void testRecommendChannels_includeRecommendedOnly_allChannelsHaveNoScore() {
- createRecommender(true, mStartDatamanagerRunnableAddFourChannels);
+ createRecommender(true, START_DATAMANAGER_RUNNABLE_ADD_FOUR_CHANNELS);
// Recommender doesn't recommend any channels because all channels are not recommended.
assertEquals(0, mRecommender.recommendChannels().size());
@@ -102,7 +102,7 @@ public class RecommenderTest {
@Test
public void testRecommendChannels_notIncludeRecommendedOnly_allChannelsHaveNoScore() {
- createRecommender(false, mStartDatamanagerRunnableAddFourChannels);
+ createRecommender(false, START_DATAMANAGER_RUNNABLE_ADD_FOUR_CHANNELS);
// Recommender recommends every channel because it recommends not-recommended channels too.
assertEquals(4, mRecommender.recommendChannels().size());
@@ -115,7 +115,7 @@ public class RecommenderTest {
@Test
public void testRecommendChannels_includeRecommendedOnly_allChannelsHaveScore() {
- createRecommender(true, mStartDatamanagerRunnableAddFourChannels);
+ createRecommender(true, START_DATAMANAGER_RUNNABLE_ADD_FOUR_CHANNELS);
setChannelScores_scoreIncreasesAsChannelIdIncreases();
@@ -135,7 +135,7 @@ public class RecommenderTest {
@Test
public void testRecommendChannels_notIncludeRecommendedOnly_allChannelsHaveScore() {
- createRecommender(false, mStartDatamanagerRunnableAddFourChannels);
+ createRecommender(false, START_DATAMANAGER_RUNNABLE_ADD_FOUR_CHANNELS);
setChannelScores_scoreIncreasesAsChannelIdIncreases();
@@ -155,7 +155,7 @@ public class RecommenderTest {
@Test
public void testRecommendChannels_includeRecommendedOnly_fewChannelsHaveScore() {
- createRecommender(true, mStartDatamanagerRunnableAddFourChannels);
+ createRecommender(true, START_DATAMANAGER_RUNNABLE_ADD_FOUR_CHANNELS);
mEvaluator.setChannelScore(mChannel_1.getId(), 1.0);
mEvaluator.setChannelScore(mChannel_2.getId(), 1.0);
@@ -175,7 +175,7 @@ public class RecommenderTest {
@Test
public void testRecommendChannels_notIncludeRecommendedOnly_fewChannelsHaveScore() {
- createRecommender(false, mStartDatamanagerRunnableAddFourChannels);
+ createRecommender(false, START_DATAMANAGER_RUNNABLE_ADD_FOUR_CHANNELS);
mEvaluator.setChannelScore(mChannel_1.getId(), 1.0);
mEvaluator.setChannelScore(mChannel_2.getId(), 1.0);
@@ -202,13 +202,13 @@ public class RecommenderTest {
@Test
public void testGetChannelSortKey_recommendAllChannels() {
- createRecommender(true, mStartDatamanagerRunnableAddFourChannels);
+ createRecommender(true, START_DATAMANAGER_RUNNABLE_ADD_FOUR_CHANNELS);
setChannelScores_scoreIncreasesAsChannelIdIncreases();
List<Channel> expectedChannelList = mRecommender.recommendChannels();
List<Channel> channelList = Arrays.asList(mChannel_1, mChannel_2, mChannel_3, mChannel_4);
- Collections.sort(channelList, mChannelSortKeyComparator);
+ Collections.sort(channelList, CHANNEL_SORT_KEY_COMPARATOR);
// Recommended channel list and channel list sorted by sort key must be the same.
MoreAsserts.assertContentsInOrder(channelList, expectedChannelList.toArray());
@@ -218,7 +218,7 @@ public class RecommenderTest {
@Test
public void testGetChannelSortKey_recommendFewChannels() {
// Test with recommending 3 channels.
- createRecommender(true, mStartDatamanagerRunnableAddFourChannels);
+ createRecommender(true, START_DATAMANAGER_RUNNABLE_ADD_FOUR_CHANNELS);
setChannelScores_scoreIncreasesAsChannelIdIncreases();
@@ -229,7 +229,7 @@ public class RecommenderTest {
mRecommender.getChannelSortKey(mChannel_1.getId()));
List<Channel> channelList = Arrays.asList(mChannel_2, mChannel_3, mChannel_4);
- Collections.sort(channelList, mChannelSortKeyComparator);
+ Collections.sort(channelList, CHANNEL_SORT_KEY_COMPARATOR);
MoreAsserts.assertContentsInOrder(channelList, expectedChannelList.toArray());
assertSortKeyNotInvalid(channelList);
@@ -237,7 +237,7 @@ public class RecommenderTest {
@Test
public void testListener_onRecommendationChanged() {
- createRecommender(true, mStartDatamanagerRunnableAddFourChannels);
+ createRecommender(true, START_DATAMANAGER_RUNNABLE_ADD_FOUR_CHANNELS);
// FakeEvaluator doesn't recommend a channel with empty watch log. As every channel
// doesn't have a watch log, nothing is recommended and recommendation isn't changed.
assertFalse(mOnRecommendationChanged);
diff --git a/tests/unit/src/com/android/tv/recommendation/RoutineWatchEvaluatorTest.java b/tests/unit/src/com/android/tv/recommendation/RoutineWatchEvaluatorTest.java
index a675df85..3c972e93 100644
--- a/tests/unit/src/com/android/tv/recommendation/RoutineWatchEvaluatorTest.java
+++ b/tests/unit/src/com/android/tv/recommendation/RoutineWatchEvaluatorTest.java
@@ -124,47 +124,47 @@ public class RoutineWatchEvaluatorTest extends EvaluatorTestCase<RoutineWatchEva
int tomorrowDayOfWeek = (todayDayOfWeek % 7) + 1;
// Today 00:00 - 01:00.
- ProgramTime programTimeToday0000to0100 =
+ ProgramTime programTimeToday0000_0100 =
ProgramTime.createFromProgram(
createDummyProgram(todayAtHourMin(0, 0), TimeUnit.HOURS.toMillis(1)));
assertProgramTime(
todayDayOfWeek,
hourMinuteToSec(0, 0),
hourMinuteToSec(1, 0),
- programTimeToday0000to0100);
+ programTimeToday0000_0100);
// Today 23:30 - 24:30.
- ProgramTime programTimeToday2330to2430 =
+ ProgramTime programTimeToday2330_2430 =
ProgramTime.createFromProgram(
createDummyProgram(todayAtHourMin(23, 30), TimeUnit.HOURS.toMillis(1)));
assertProgramTime(
todayDayOfWeek,
hourMinuteToSec(23, 30),
hourMinuteToSec(24, 30),
- programTimeToday2330to2430);
+ programTimeToday2330_2430);
// Tomorrow 00:00 - 01:00.
- ProgramTime programTimeTomorrow0000to0100 =
+ ProgramTime programTimeTomorrow0000_0100 =
ProgramTime.createFromProgram(
createDummyProgram(tomorrowAtHourMin(0, 0), TimeUnit.HOURS.toMillis(1)));
assertProgramTime(
tomorrowDayOfWeek,
hourMinuteToSec(0, 0),
hourMinuteToSec(1, 0),
- programTimeTomorrow0000to0100);
+ programTimeTomorrow0000_0100);
// Tomorrow 23:30 - 24:30.
- ProgramTime programTimeTomorrow2330to2430 =
+ ProgramTime programTimeTomorrow2330_2430 =
ProgramTime.createFromProgram(
createDummyProgram(tomorrowAtHourMin(23, 30), TimeUnit.HOURS.toMillis(1)));
assertProgramTime(
tomorrowDayOfWeek,
hourMinuteToSec(23, 30),
hourMinuteToSec(24, 30),
- programTimeTomorrow2330to2430);
+ programTimeTomorrow2330_2430);
// Today 18:00 - Tomorrow 12:00.
- ProgramTime programTimeToday1800to3600 =
+ ProgramTime programTimeToday1800_3600 =
ProgramTime.createFromProgram(
createDummyProgram(todayAtHourMin(18, 0), TimeUnit.HOURS.toMillis(18)));
// Maximum duration of ProgramTime is 12 hours.
@@ -173,42 +173,42 @@ public class RoutineWatchEvaluatorTest extends EvaluatorTestCase<RoutineWatchEva
todayDayOfWeek,
hourMinuteToSec(18, 0),
hourMinuteToSec(30, 0),
- programTimeToday1800to3600);
+ programTimeToday1800_3600);
}
@Test
public void testCalculateOverlappedIntervalScore() {
// Today 21:00 - 24:00.
- ProgramTime programTimeToday2100to2400 =
+ ProgramTime programTimeToday2100_2400 =
ProgramTime.createFromProgram(
createDummyProgram(todayAtHourMin(21, 0), TimeUnit.HOURS.toMillis(3)));
// Today 22:00 - 01:00.
- ProgramTime programTimeToday2200to0100 =
+ ProgramTime programTimeToday2200_0100 =
ProgramTime.createFromProgram(
createDummyProgram(todayAtHourMin(22, 0), TimeUnit.HOURS.toMillis(3)));
// Tomorrow 00:00 - 03:00.
- ProgramTime programTimeTomorrow0000to0300 =
+ ProgramTime programTimeTomorrow0000_0300 =
ProgramTime.createFromProgram(
createDummyProgram(tomorrowAtHourMin(0, 0), TimeUnit.HOURS.toMillis(3)));
// Tomorrow 20:00 - Tomorrow 23:00.
- ProgramTime programTimeTomorrow2000to2300 =
+ ProgramTime programTimeTomorrow2000_2300 =
ProgramTime.createFromProgram(
createDummyProgram(tomorrowAtHourMin(20, 0), TimeUnit.HOURS.toMillis(3)));
// Check intersection time and commutative law in all cases.
int oneHourInSec = hourMinuteToSec(1, 0);
assertOverlappedIntervalScore(
- 2 * oneHourInSec, true, programTimeToday2100to2400, programTimeToday2200to0100);
+ 2 * oneHourInSec, true, programTimeToday2100_2400, programTimeToday2200_0100);
assertOverlappedIntervalScore(
- 0, false, programTimeToday2100to2400, programTimeTomorrow0000to0300);
+ 0, false, programTimeToday2100_2400, programTimeTomorrow0000_0300);
assertOverlappedIntervalScore(
- 2 * oneHourInSec, false, programTimeToday2100to2400, programTimeTomorrow2000to2300);
+ 2 * oneHourInSec, false, programTimeToday2100_2400, programTimeTomorrow2000_2300);
assertOverlappedIntervalScore(
- oneHourInSec, true, programTimeToday2200to0100, programTimeTomorrow0000to0300);
+ oneHourInSec, true, programTimeToday2200_0100, programTimeTomorrow0000_0300);
assertOverlappedIntervalScore(
- oneHourInSec, false, programTimeToday2200to0100, programTimeTomorrow2000to2300);
+ oneHourInSec, false, programTimeToday2200_0100, programTimeTomorrow2000_2300);
assertOverlappedIntervalScore(
- 0, false, programTimeTomorrow0000to0300, programTimeTomorrow2000to2300);
+ 0, false, programTimeTomorrow0000_0300, programTimeTomorrow2000_2300);
}
@Test
diff --git a/tests/unit/src/com/android/tv/search/LocalSearchProviderTest.java b/tests/unit/src/com/android/tv/search/LocalSearchProviderTest.java
index 2bc5f05a..9ac81301 100644
--- a/tests/unit/src/com/android/tv/search/LocalSearchProviderTest.java
+++ b/tests/unit/src/com/android/tv/search/LocalSearchProviderTest.java
@@ -25,10 +25,10 @@ import android.database.Cursor;
import android.net.Uri;
import android.support.test.filters.SmallTest;
import android.test.ProviderTestCase2;
+import com.android.tv.ApplicationSingletons;
import com.android.tv.TvApplication;
-import com.android.tv.common.BaseSingletons;
import com.android.tv.perf.PerformanceMonitor;
-import com.android.tv.util.MockTvSingletons;
+import com.android.tv.util.MockApplicationSingletons;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -37,7 +37,6 @@ import org.mockito.MockitoAnnotations;
/** Unit test for {@link LocalSearchProvider}. */
@SmallTest
-@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed
public class LocalSearchProviderTest extends ProviderTestCase2<LocalSearchProvider> {
private static final String AUTHORITY = "com.android.tv.search";
private static final String KEYWORD = "keyword";
@@ -49,11 +48,11 @@ public class LocalSearchProviderTest extends ProviderTestCase2<LocalSearchProvid
+ SearchManager.SUGGEST_URI_PATH_QUERY
+ "/"
+ KEYWORD);
- private static final Uri WRONG_SEARCH_URI =
+ private static final Uri WRONG_SERACH_URI =
Uri.parse("content://" + AUTHORITY + "/wrong_path/" + KEYWORD);
- private BaseSingletons mOldTvSingletons;
- MockTvSingletons mMockTvSingletons;
+ private ApplicationSingletons mOldAppSingletons;
+ MockApplicationSingletons mMockAppSingletons;
@Mock PerformanceMonitor mMockPerformanceMointor;
@Mock SearchInterface mMockSearchInterface;
@@ -66,10 +65,10 @@ public class LocalSearchProviderTest extends ProviderTestCase2<LocalSearchProvid
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
setContext(getTargetContext());
- mOldTvSingletons = TvApplication.sSingletons;
- mMockTvSingletons = new MockTvSingletons(getTargetContext());
- mMockTvSingletons.setPerformanceMonitor(mMockPerformanceMointor);
- TvApplication.sSingletons = mMockTvSingletons;
+ mOldAppSingletons = TvApplication.sAppSingletons;
+ mMockAppSingletons = new MockApplicationSingletons(getTargetContext());
+ mMockAppSingletons.setPerformanceMonitor(mMockPerformanceMointor);
+ TvApplication.sAppSingletons = mMockAppSingletons;
super.setUp();
getProvider().setSearchInterface(mMockSearchInterface);
}
@@ -77,7 +76,7 @@ public class LocalSearchProviderTest extends ProviderTestCase2<LocalSearchProvid
@After
@Override
public void tearDown() throws Exception {
- TvApplication.sSingletons = mOldTvSingletons;
+ TvApplication.sAppSingletons = mOldAppSingletons;
super.tearDown();
}
@@ -91,7 +90,7 @@ public class LocalSearchProviderTest extends ProviderTestCase2<LocalSearchProvid
@Test
public void testQuery_invalidUri() {
- try (Cursor c = getProvider().query(WRONG_SEARCH_URI, null, null, null, null)) {
+ try (Cursor c = getProvider().query(WRONG_SERACH_URI, null, null, null, null)) {
fail("Query with invalid URI should fail.");
} catch (IllegalArgumentException e) {
// Success.
diff --git a/tests/unit/src/com/android/tv/tests/TvActivityTest.java b/tests/unit/src/com/android/tv/tests/TvActivityTest.java
index 30663e9a..346b9787 100644
--- a/tests/unit/src/com/android/tv/tests/TvActivityTest.java
+++ b/tests/unit/src/com/android/tv/tests/TvActivityTest.java
@@ -23,7 +23,7 @@ import static org.junit.Assert.assertTrue;
import android.support.test.filters.MediumTest;
import android.support.test.rule.ActivityTestRule;
import com.android.tv.TvActivity;
-import com.android.tv.testing.utils.Utils;
+import com.android.tv.testing.Utils;
import org.junit.Rule;
import org.junit.Test;
diff --git a/tests/unit/src/com/android/tv/util/ImageCacheTest.java b/tests/unit/src/com/android/tv/util/ImageCacheTest.java
index cd34895e..8352f7dc 100644
--- a/tests/unit/src/com/android/tv/util/ImageCacheTest.java
+++ b/tests/unit/src/com/android/tv/util/ImageCacheTest.java
@@ -21,15 +21,12 @@ import static org.junit.Assert.assertSame;
import android.graphics.Bitmap;
import android.support.test.filters.MediumTest;
-import android.support.test.runner.AndroidJUnit4;
import com.android.tv.util.BitmapUtils.ScaledBitmapInfo;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
/** Tests for {@link ImageCache}. */
@MediumTest
-@RunWith(AndroidJUnit4.class)
public class ImageCacheTest {
private static final Bitmap ORIG = Bitmap.createBitmap(100, 100, Bitmap.Config.RGB_565);
diff --git a/tests/unit/src/com/android/tv/util/MockTvSingletons.java b/tests/unit/src/com/android/tv/util/MockApplicationSingletons.java
index 3a74f917..4eb0c4d7 100644
--- a/tests/unit/src/com/android/tv/util/MockTvSingletons.java
+++ b/tests/unit/src/com/android/tv/util/MockApplicationSingletons.java
@@ -17,40 +17,31 @@
package com.android.tv.util;
import android.content.Context;
-import android.content.Intent;
+import com.android.tv.ApplicationSingletons;
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.config.api.RemoteConfig;
-import com.android.tv.common.experiments.ExperimentLoader;
-import com.android.tv.common.recording.RecordingStorageStatusManager;
-import com.android.tv.common.util.Clock;
+import com.android.tv.config.RemoteConfig;
import com.android.tv.data.ChannelDataManager;
import com.android.tv.data.PreviewDataManager;
import com.android.tv.data.ProgramDataManager;
-import com.android.tv.data.epg.EpgFetcher;
-import com.android.tv.data.epg.EpgReader;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.DvrManager;
import com.android.tv.dvr.DvrScheduleManager;
+import com.android.tv.dvr.DvrStorageStatusManager;
import com.android.tv.dvr.DvrWatchedPositionManager;
import com.android.tv.dvr.recorder.RecordingScheduler;
import com.android.tv.perf.PerformanceMonitor;
-import com.android.tv.testing.FakeClock;
-import com.android.tv.tuner.TunerInputController;
-import javax.inject.Provider;
-
-/** Mock {@link TvSingletons} class. */
-public class MockTvSingletons implements TvSingletons {
- public final FakeClock fakeClock = FakeClock.createWithCurrentTime();
+/** Mock {@link ApplicationSingletons} class. */
+public class MockApplicationSingletons implements ApplicationSingletons {
private final TvApplication mApp;
+
private PerformanceMonitor mPerformanceMonitor;
- public MockTvSingletons(Context context) {
+ public MockApplicationSingletons(Context context) {
mApp = (TvApplication) context.getApplicationContext();
}
@@ -60,9 +51,6 @@ public class MockTvSingletons implements TvSingletons {
}
@Override
- public void handleInputCountChanged() {}
-
- @Override
public ChannelDataManager getChannelDataManager() {
return mApp.getChannelDataManager();
}
@@ -93,13 +81,8 @@ public class MockTvSingletons implements TvSingletons {
}
@Override
- public Clock getClock() {
- return fakeClock;
- }
-
- @Override
- public RecordingStorageStatusManager getRecordingStorageStatusManager() {
- return mApp.getRecordingStorageStatusManager();
+ public DvrStorageStatusManager getDvrStorageStatusManager() {
+ return mApp.getDvrStorageStatusManager();
}
@Override
@@ -138,37 +121,12 @@ public class MockTvSingletons implements TvSingletons {
}
@Override
- public Provider<EpgReader> providesEpgReader() {
- return mApp.providesEpgReader();
- }
-
- @Override
- public EpgFetcher getEpgFetcher() {
- return mApp.getEpgFetcher();
- }
-
- @Override
- public SetupUtils getSetupUtils() {
- return mApp.getSetupUtils();
- }
-
- @Override
- public TunerInputController getTunerInputController() {
- return mApp.getTunerInputController();
- }
-
- @Override
- public ExperimentLoader getExperimentLoader() {
- return mApp.getExperimentLoader();
- }
-
- @Override
public MainActivityWrapper getMainActivityWrapper() {
return mApp.getMainActivityWrapper();
}
@Override
- public com.android.tv.util.account.AccountHelper getAccountHelper() {
+ public AccountHelper getAccountHelper() {
return mApp.getAccountHelper();
}
@@ -178,11 +136,6 @@ public class MockTvSingletons implements TvSingletons {
}
@Override
- public Intent getTunerSetupIntent(Context context) {
- return mApp.getTunerSetupIntent(context);
- }
-
- @Override
public boolean isRunningInMainProcess() {
return mApp.isRunningInMainProcess();
}
@@ -195,9 +148,4 @@ public class MockTvSingletons implements TvSingletons {
public void setPerformanceMonitor(PerformanceMonitor performanceMonitor) {
mPerformanceMonitor = performanceMonitor;
}
-
- @Override
- public String getEmbeddedTunerInputId() {
- return "com.android.tv/.tuner.tvinput.LiveTvTunerTvInputService";
- }
}
diff --git a/tests/unit/src/com/android/tv/util/MultiLongSparseArrayTest.java b/tests/unit/src/com/android/tv/util/MultiLongSparseArrayTest.java
new file mode 100644
index 00000000..42325c83
--- /dev/null
+++ b/tests/unit/src/com/android/tv/util/MultiLongSparseArrayTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.tv.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+
+import android.support.test.filters.SmallTest;
+import android.test.MoreAsserts;
+import java.util.Collections;
+import org.junit.Test;
+
+/** Tests for {@link MultiLongSparseArray}. */
+@SmallTest
+public class MultiLongSparseArrayTest {
+ @Test
+ public void testEmpty() {
+ MultiLongSparseArray<String> sparseArray = new MultiLongSparseArray<>();
+ assertSame(Collections.EMPTY_SET, sparseArray.get(0));
+ }
+
+ @Test
+ public void testOneElement() {
+ MultiLongSparseArray<String> sparseArray = new MultiLongSparseArray<>();
+ sparseArray.put(0, "foo");
+ MoreAsserts.assertContentsInAnyOrder(sparseArray.get(0), "foo");
+ }
+
+ @Test
+ public void testTwoElements() {
+ MultiLongSparseArray<String> sparseArray = new MultiLongSparseArray<>();
+ sparseArray.put(0, "foo");
+ sparseArray.put(0, "bar");
+ MoreAsserts.assertContentsInAnyOrder(sparseArray.get(0), "foo", "bar");
+ }
+
+ @Test
+ public void testClearEmptyCache() {
+ MultiLongSparseArray<String> sparseArray = new MultiLongSparseArray<>();
+ sparseArray.clearEmptyCache();
+ assertEquals(0, sparseArray.getEmptyCacheSize());
+ sparseArray.put(0, "foo");
+ sparseArray.remove(0, "foo");
+ assertEquals(1, sparseArray.getEmptyCacheSize());
+ sparseArray.clearEmptyCache();
+ assertEquals(0, sparseArray.getEmptyCacheSize());
+ }
+
+ @Test
+ public void testMaxEmptyCacheSize() {
+ MultiLongSparseArray<String> sparseArray = new MultiLongSparseArray<>();
+ sparseArray.clearEmptyCache();
+ assertEquals(0, sparseArray.getEmptyCacheSize());
+ for (int i = 0; i <= MultiLongSparseArray.DEFAULT_MAX_EMPTIES_KEPT + 2; i++) {
+ sparseArray.put(i, "foo");
+ }
+ for (int i = 0; i <= MultiLongSparseArray.DEFAULT_MAX_EMPTIES_KEPT + 2; i++) {
+ sparseArray.remove(i, "foo");
+ }
+ assertEquals(
+ MultiLongSparseArray.DEFAULT_MAX_EMPTIES_KEPT, sparseArray.getEmptyCacheSize());
+ sparseArray.clearEmptyCache();
+ assertEquals(0, sparseArray.getEmptyCacheSize());
+ }
+
+ @Test
+ public void testReuseEmptySets() {
+ MultiLongSparseArray<String> sparseArray = new MultiLongSparseArray<>();
+ sparseArray.clearEmptyCache();
+ assertEquals(0, sparseArray.getEmptyCacheSize());
+ // create a bunch of sets
+ for (int i = 0; i <= MultiLongSparseArray.DEFAULT_MAX_EMPTIES_KEPT + 2; i++) {
+ sparseArray.put(i, "foo");
+ }
+ // remove them so they are all put in the cache.
+ for (int i = 0; i <= MultiLongSparseArray.DEFAULT_MAX_EMPTIES_KEPT + 2; i++) {
+ sparseArray.remove(i, "foo");
+ }
+ assertEquals(
+ MultiLongSparseArray.DEFAULT_MAX_EMPTIES_KEPT, sparseArray.getEmptyCacheSize());
+
+ // now create elements, that use the cached empty sets.
+ for (int i = 0; i < MultiLongSparseArray.DEFAULT_MAX_EMPTIES_KEPT; i++) {
+ sparseArray.put(10 + i, "bar");
+ assertEquals(
+ MultiLongSparseArray.DEFAULT_MAX_EMPTIES_KEPT - i - 1,
+ sparseArray.getEmptyCacheSize());
+ }
+ }
+}
diff --git a/tests/unit/src/com/android/tv/util/ScaledBitmapInfoTest.java b/tests/unit/src/com/android/tv/util/ScaledBitmapInfoTest.java
index 9bb69f80..87ae5131 100644
--- a/tests/unit/src/com/android/tv/util/ScaledBitmapInfoTest.java
+++ b/tests/unit/src/com/android/tv/util/ScaledBitmapInfoTest.java
@@ -1,32 +1,14 @@
-/*
- * 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 org.junit.Assert.assertEquals;
import android.graphics.Bitmap;
import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import com.android.tv.util.BitmapUtils.ScaledBitmapInfo;
import org.junit.Test;
-import org.junit.runner.RunWith;
/** Tests for {@link ScaledBitmapInfo}. */
@SmallTest
-@RunWith(AndroidJUnit4.class)
public class ScaledBitmapInfoTest {
private static final Bitmap B80x100 = Bitmap.createBitmap(80, 100, Bitmap.Config.RGB_565);
private static final Bitmap B960x1440 = Bitmap.createBitmap(960, 1440, Bitmap.Config.RGB_565);
diff --git a/tests/unit/src/com/android/tv/util/TvInputManagerHelperTest.java b/tests/unit/src/com/android/tv/util/TvInputManagerHelperTest.java
index 168e7c6e..44c4477e 100644
--- a/tests/unit/src/com/android/tv/util/TvInputManagerHelperTest.java
+++ b/tests/unit/src/com/android/tv/util/TvInputManagerHelperTest.java
@@ -21,20 +21,17 @@ import static android.support.test.InstrumentationRegistry.getContext;
import android.content.pm.ResolveInfo;
import android.media.tv.TvInputInfo;
import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import com.android.tv.testing.ComparatorTester;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.junit.Test;
-import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
/** Test for {@link TvInputManagerHelper} */
@SmallTest
-@RunWith(AndroidJUnit4.class)
public class TvInputManagerHelperTest {
final HashMap<String, TvInputInfoWrapper> TEST_INPUT_MAP = new HashMap<>();
diff --git a/tests/unit/src/com/android/tv/util/TvTrackInfoUtilsTest.java b/tests/unit/src/com/android/tv/util/TvTrackInfoUtilsTest.java
index c4623bc7..e60aae05 100644
--- a/tests/unit/src/com/android/tv/util/TvTrackInfoUtilsTest.java
+++ b/tests/unit/src/com/android/tv/util/TvTrackInfoUtilsTest.java
@@ -20,18 +20,15 @@ import static org.junit.Assert.assertEquals;
import android.media.tv.TvTrackInfo;
import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import com.android.tv.testing.ComparatorTester;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.junit.Test;
-import org.junit.runner.RunWith;
/** Tests for {@link com.android.tv.util.TvTrackInfoUtils}. */
@SmallTest
-@RunWith(AndroidJUnit4.class)
public class TvTrackInfoUtilsTest {
private static final String UN_MATCHED_ID = "no matching ID";
diff --git a/tests/unit/src/com/android/tv/util/UtilsTest_GetDurationString.java b/tests/unit/src/com/android/tv/util/UtilsTest_GetDurationString.java
new file mode 100644
index 00000000..f5eefc64
--- /dev/null
+++ b/tests/unit/src/com/android/tv/util/UtilsTest_GetDurationString.java
@@ -0,0 +1,446 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.tv.util;
+
+import static android.support.test.InstrumentationRegistry.getContext;
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.filters.SmallTest;
+import android.text.format.DateUtils;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.Locale;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests for {@link com.android.tv.util.Utils#getDurationString}.
+ *
+ * <p>This test uses deprecated flags {@link DateUtils#FORMAT_12HOUR} and {@link
+ * DateUtils#FORMAT_24HOUR} to run this test independent to system's 12/24h format. Note that
+ * changing system setting requires permission android.permission.WRITE_SETTINGS and it should be
+ * defined in TV app, not this test.
+ */
+@SmallTest
+public class UtilsTest_GetDurationString {
+ // TODO: Mock Context so we can specify current time and locale for test.
+ private Locale mLocale;
+ private static final long DATE_THIS_YEAR_2_1_MS = getFebOfThisYearInMillis(1, 0, 0);
+
+ // All possible list for a parameter to test parameter independent result.
+ private static final boolean[] PARAM_USE_SHORT_FORMAT = {false, true};
+
+ @Before
+ public void setUp() {
+ // Set locale to US
+ mLocale = Locale.getDefault();
+ Locale.setDefault(Locale.US);
+ }
+
+ @After
+ public void tearDown() {
+ // Revive system locale.
+ Locale.setDefault(mLocale);
+ }
+
+ /** Return time in millis assuming that whose year is this year and month is Jan. */
+ private static long getJanOfThisYearInMillis(int date, int hour, int minutes) {
+ return new GregorianCalendar(getThisYear(), Calendar.JANUARY, date, hour, minutes)
+ .getTimeInMillis();
+ }
+
+ private static long getJanOfThisYearInMillis(int date, int hour) {
+ return getJanOfThisYearInMillis(date, hour, 0);
+ }
+
+ /** Return time in millis assuming that whose year is this year and month is Feb. */
+ private static long getFebOfThisYearInMillis(int date, int hour, int minutes) {
+ return new GregorianCalendar(getThisYear(), Calendar.FEBRUARY, date, hour, minutes)
+ .getTimeInMillis();
+ }
+
+ private static long getFebOfThisYearInMillis(int date, int hour) {
+ return getFebOfThisYearInMillis(date, hour, 0);
+ }
+
+ private static int getThisYear() {
+ return new GregorianCalendar().get(GregorianCalendar.YEAR);
+ }
+
+ @Test
+ public void testSameDateAndTime() {
+ assertEquals(
+ "3:00 AM",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(1, 3),
+ getFebOfThisYearInMillis(1, 3),
+ false,
+ DateUtils.FORMAT_12HOUR));
+ assertEquals(
+ "03:00",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(1, 3),
+ getFebOfThisYearInMillis(1, 3),
+ false,
+ DateUtils.FORMAT_24HOUR));
+ }
+
+ @Test
+ public void testDurationWithinToday() {
+ assertEquals(
+ "12:00 – 3:00 AM",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(1, 3),
+ false,
+ DateUtils.FORMAT_12HOUR));
+ assertEquals(
+ "00:00 – 03:00",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(1, 3),
+ false,
+ DateUtils.FORMAT_24HOUR));
+ }
+
+ @Test
+ public void testDurationFromYesterdayToToday() {
+ assertEquals(
+ "Jan 31, 3:00 AM – Feb 1, 4:00 AM",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getJanOfThisYearInMillis(31, 3),
+ getFebOfThisYearInMillis(1, 4),
+ false,
+ DateUtils.FORMAT_12HOUR));
+ assertEquals(
+ "Jan 31, 03:00 – Feb 1, 04:00",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getJanOfThisYearInMillis(31, 3),
+ getFebOfThisYearInMillis(1, 4),
+ false,
+ DateUtils.FORMAT_24HOUR));
+ assertEquals(
+ "1/31, 11:30 PM – 12:30 AM",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getJanOfThisYearInMillis(31, 23, 30),
+ getFebOfThisYearInMillis(1, 0, 30),
+ true,
+ DateUtils.FORMAT_12HOUR));
+ assertEquals(
+ "1/31, 23:30 – 00:30",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getJanOfThisYearInMillis(31, 23, 30),
+ getFebOfThisYearInMillis(1, 0, 30),
+ true,
+ DateUtils.FORMAT_24HOUR));
+ }
+
+ @Test
+ public void testDurationFromTodayToTomorrow() {
+ assertEquals(
+ "Feb 1, 3:00 AM – Feb 2, 4:00 AM",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(1, 3),
+ getFebOfThisYearInMillis(2, 4),
+ false,
+ DateUtils.FORMAT_12HOUR));
+ assertEquals(
+ "Feb 1, 03:00 – Feb 2, 04:00",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(1, 3),
+ getFebOfThisYearInMillis(2, 4),
+ false,
+ DateUtils.FORMAT_24HOUR));
+ assertEquals(
+ "2/1, 3:00 AM – 2/2, 4:00 AM",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(1, 3),
+ getFebOfThisYearInMillis(2, 4),
+ true,
+ DateUtils.FORMAT_12HOUR));
+ assertEquals(
+ "2/1, 03:00 – 2/2, 04:00",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(1, 3),
+ getFebOfThisYearInMillis(2, 4),
+ true,
+ DateUtils.FORMAT_24HOUR));
+
+ assertEquals(
+ "Feb 1, 11:30 PM – Feb 2, 12:30 AM",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(1, 23, 30),
+ getFebOfThisYearInMillis(2, 0, 30),
+ false,
+ DateUtils.FORMAT_12HOUR));
+ assertEquals(
+ "Feb 1, 23:30 – Feb 2, 00:30",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(1, 23, 30),
+ getFebOfThisYearInMillis(2, 0, 30),
+ false,
+ DateUtils.FORMAT_24HOUR));
+ assertEquals(
+ "11:30 PM – 12:30 AM",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(1, 23, 30),
+ getFebOfThisYearInMillis(2, 0, 30),
+ true,
+ DateUtils.FORMAT_12HOUR));
+ assertEquals(
+ "23:30 – 00:30",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(1, 23, 30),
+ getFebOfThisYearInMillis(2, 0, 30),
+ true,
+ DateUtils.FORMAT_24HOUR));
+ }
+
+ @Test
+ public void testDurationWithinTomorrow() {
+ assertEquals(
+ "Feb 2, 2:00 – 4:00 AM",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(2, 2),
+ getFebOfThisYearInMillis(2, 4),
+ false,
+ DateUtils.FORMAT_12HOUR));
+ assertEquals(
+ "Feb 2, 02:00 – 04:00",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(2, 2),
+ getFebOfThisYearInMillis(2, 4),
+ false,
+ DateUtils.FORMAT_24HOUR));
+ assertEquals(
+ "2/2, 2:00 – 4:00 AM",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(2, 2),
+ getFebOfThisYearInMillis(2, 4),
+ true,
+ DateUtils.FORMAT_12HOUR));
+ assertEquals(
+ "2/2, 02:00 – 04:00",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(2, 2),
+ getFebOfThisYearInMillis(2, 4),
+ true,
+ DateUtils.FORMAT_24HOUR));
+ }
+
+ @Test
+ public void testStartOfDay() {
+ assertEquals(
+ "12:00 – 1:00 AM",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(1, 1),
+ false,
+ DateUtils.FORMAT_12HOUR));
+ assertEquals(
+ "00:00 – 01:00",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(1, 1),
+ false,
+ DateUtils.FORMAT_24HOUR));
+
+ assertEquals(
+ "Feb 2, 12:00 – 1:00 AM",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(2, 0),
+ getFebOfThisYearInMillis(2, 1),
+ false,
+ DateUtils.FORMAT_12HOUR));
+ assertEquals(
+ "Feb 2, 00:00 – 01:00",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(2, 0),
+ getFebOfThisYearInMillis(2, 1),
+ false,
+ DateUtils.FORMAT_24HOUR));
+ assertEquals(
+ "2/2, 12:00 – 1:00 AM",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(2, 0),
+ getFebOfThisYearInMillis(2, 1),
+ true,
+ DateUtils.FORMAT_12HOUR));
+ assertEquals(
+ "2/2, 00:00 – 01:00",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(2, 0),
+ getFebOfThisYearInMillis(2, 1),
+ true,
+ DateUtils.FORMAT_24HOUR));
+ }
+
+ @Test
+ public void testEndOfDay() {
+ for (boolean useShortFormat : PARAM_USE_SHORT_FORMAT) {
+ assertEquals(
+ "11:00 PM – 12:00 AM",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(1, 23),
+ getFebOfThisYearInMillis(2, 0),
+ useShortFormat,
+ DateUtils.FORMAT_12HOUR));
+ assertEquals(
+ "23:00 – 00:00",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(1, 23),
+ getFebOfThisYearInMillis(2, 0),
+ useShortFormat,
+ DateUtils.FORMAT_24HOUR));
+ }
+
+ assertEquals(
+ "Feb 2, 11:00 PM – 12:00 AM",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(2, 23),
+ getFebOfThisYearInMillis(3, 0),
+ false,
+ DateUtils.FORMAT_12HOUR));
+ assertEquals(
+ "Feb 2, 23:00 – 00:00",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(2, 23),
+ getFebOfThisYearInMillis(3, 0),
+ false,
+ DateUtils.FORMAT_24HOUR));
+ assertEquals(
+ "2/2, 11:00 PM – 12:00 AM",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(2, 23),
+ getFebOfThisYearInMillis(3, 0),
+ true,
+ DateUtils.FORMAT_12HOUR));
+ assertEquals(
+ "2/2, 23:00 – 00:00",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(2, 23),
+ getFebOfThisYearInMillis(3, 0),
+ true,
+ DateUtils.FORMAT_24HOUR));
+ assertEquals(
+ "2/2, 12:00 AM – 2/3, 12:00 AM",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(2, 0),
+ getFebOfThisYearInMillis(3, 0),
+ true,
+ DateUtils.FORMAT_12HOUR));
+ assertEquals(
+ "2/2, 00:00 – 2/3, 00:00",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ getFebOfThisYearInMillis(2, 0),
+ getFebOfThisYearInMillis(3, 0),
+ true,
+ DateUtils.FORMAT_24HOUR));
+ }
+
+ @Test
+ public void testMidnight() {
+ for (boolean useShortFormat : PARAM_USE_SHORT_FORMAT) {
+ assertEquals(
+ "12:00 AM",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ DATE_THIS_YEAR_2_1_MS,
+ DATE_THIS_YEAR_2_1_MS,
+ useShortFormat,
+ DateUtils.FORMAT_12HOUR));
+ assertEquals(
+ "00:00",
+ Utils.getDurationString(
+ getContext(),
+ DATE_THIS_YEAR_2_1_MS,
+ DATE_THIS_YEAR_2_1_MS,
+ DATE_THIS_YEAR_2_1_MS,
+ useShortFormat,
+ DateUtils.FORMAT_24HOUR));
+ }
+ }
+}
diff --git a/tests/unit/src/com/android/tv/util/UtilsTest_GetMultiAudioString.java b/tests/unit/src/com/android/tv/util/UtilsTest_GetMultiAudioString.java
new file mode 100644
index 00000000..79ed14c0
--- /dev/null
+++ b/tests/unit/src/com/android/tv/util/UtilsTest_GetMultiAudioString.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.util;
+
+import static android.support.test.InstrumentationRegistry.getTargetContext;
+import static org.junit.Assert.assertEquals;
+
+import android.content.Context;
+import android.media.tv.TvTrackInfo;
+import android.support.test.filters.SmallTest;
+import org.junit.Test;
+
+/** Tests for {@link com.android.tv.util.Utils#getMultiAudioString}. */
+@SmallTest
+public class UtilsTest_GetMultiAudioString {
+ private static final String TRACK_ID = "test_track_id";
+ private static final int AUDIO_SAMPLE_RATE = 48000;
+
+ @Test
+ public void testAudioTrackLanguage() {
+ Context context = getTargetContext();
+ assertEquals(
+ "Korean", Utils.getMultiAudioString(context, createAudioTrackInfo("kor"), false));
+ assertEquals(
+ "English", Utils.getMultiAudioString(context, createAudioTrackInfo("eng"), false));
+ assertEquals(
+ "Unknown language",
+ Utils.getMultiAudioString(context, createAudioTrackInfo(null), false));
+ assertEquals(
+ "Unknown language",
+ Utils.getMultiAudioString(context, createAudioTrackInfo(""), false));
+ assertEquals("abc", Utils.getMultiAudioString(context, createAudioTrackInfo("abc"), false));
+ }
+
+ @Test
+ public void testAudioTrackCount() {
+ Context context = getTargetContext();
+ assertEquals(
+ "English",
+ Utils.getMultiAudioString(context, createAudioTrackInfo("eng", -1), false));
+ assertEquals(
+ "English",
+ Utils.getMultiAudioString(context, createAudioTrackInfo("eng", 0), false));
+ assertEquals(
+ "English (mono)",
+ Utils.getMultiAudioString(context, createAudioTrackInfo("eng", 1), false));
+ assertEquals(
+ "English (stereo)",
+ Utils.getMultiAudioString(context, createAudioTrackInfo("eng", 2), false));
+ assertEquals(
+ "English (3 channels)",
+ Utils.getMultiAudioString(context, createAudioTrackInfo("eng", 3), false));
+ assertEquals(
+ "English (4 channels)",
+ Utils.getMultiAudioString(context, createAudioTrackInfo("eng", 4), false));
+ assertEquals(
+ "English (5 channels)",
+ Utils.getMultiAudioString(context, createAudioTrackInfo("eng", 5), false));
+ assertEquals(
+ "English (5.1 surround)",
+ Utils.getMultiAudioString(context, createAudioTrackInfo("eng", 6), false));
+ assertEquals(
+ "English (7 channels)",
+ Utils.getMultiAudioString(context, createAudioTrackInfo("eng", 7), false));
+ assertEquals(
+ "English (7.1 surround)",
+ Utils.getMultiAudioString(context, createAudioTrackInfo("eng", 8), false));
+ }
+
+ @Test
+ public void testShowSampleRate() {
+ assertEquals(
+ "Korean (48kHz)",
+ Utils.getMultiAudioString(
+ getTargetContext(), createAudioTrackInfo("kor", 0), true));
+ assertEquals(
+ "Korean (7.1 surround, 48kHz)",
+ Utils.getMultiAudioString(
+ getTargetContext(), createAudioTrackInfo("kor", 8), true));
+ }
+
+ private static TvTrackInfo createAudioTrackInfo(String language) {
+ return createAudioTrackInfo(language, 0);
+ }
+
+ private static TvTrackInfo createAudioTrackInfo(String language, int channelCount) {
+ return new TvTrackInfo.Builder(TvTrackInfo.TYPE_AUDIO, TRACK_ID)
+ .setLanguage(language)
+ .setAudioChannelCount(channelCount)
+ .setAudioSampleRate(AUDIO_SAMPLE_RATE)
+ .build();
+ }
+}
diff --git a/tests/unit/src/com/android/tv/util/UtilsTest_IsInGivenDay.java b/tests/unit/src/com/android/tv/util/UtilsTest_IsInGivenDay.java
new file mode 100644
index 00000000..cf0212cb
--- /dev/null
+++ b/tests/unit/src/com/android/tv/util/UtilsTest_IsInGivenDay.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.util;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+import org.junit.Test;
+
+/** Tests for {@link com.android.tv.util.Utils#isInGivenDay}. */
+@SmallTest
+public class UtilsTest_IsInGivenDay {
+ @Test
+ public void testIsInGivenDay() {
+ assertTrue(
+ Utils.isInGivenDay(
+ new GregorianCalendar(2015, Calendar.JANUARY, 1).getTimeInMillis(),
+ new GregorianCalendar(2015, Calendar.JANUARY, 1, 0, 30).getTimeInMillis()));
+ }
+
+ @Test
+ public void testIsNotInGivenDay() {
+ assertFalse(
+ Utils.isInGivenDay(
+ new GregorianCalendar(2015, Calendar.JANUARY, 1).getTimeInMillis(),
+ new GregorianCalendar(2015, Calendar.JANUARY, 2).getTimeInMillis()));
+ }
+
+ @Test
+ public void testIfTimeZoneApplied() {
+ TimeZone timeZone = TimeZone.getDefault();
+
+ TimeZone.setDefault(TimeZone.getTimeZone("Asia/Seoul"));
+
+ // 2015.01.01 00:00 in KST = 2014.12.31 15:00 in UTC
+ long date2015StartMs = new GregorianCalendar(2015, Calendar.JANUARY, 1).getTimeInMillis();
+
+ // 2015.01.01 10:00 in KST = 2015.01.01 01:00 in UTC
+ long date2015Start10AMMs =
+ new GregorianCalendar(2015, Calendar.JANUARY, 1, 10, 0).getTimeInMillis();
+
+ // Those two times aren't in the same day in UTC, but they are in KST.
+ assertTrue(Utils.isInGivenDay(date2015StartMs, date2015Start10AMMs));
+
+ TimeZone.setDefault(timeZone);
+ }
+}
diff --git a/tuner/Android.mk b/tuner/Android.mk
deleted file mode 100644
index 24676f25..00000000
--- a/tuner/Android.mk
+++ /dev/null
@@ -1,46 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# Include all java and proto files.
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, src) \
- $(call all-proto-files-under, proto)
-
-
-LOCAL_MODULE := live-tv-tuner
-LOCAL_MODULE_CLASS := STATIC_JAVA_LIBRARIES
-LOCAL_MODULE_TAGS := optional
-LOCAL_SDK_VERSION := system_current
-
-LOCAL_USE_AAPT2 := true
-
-LOCAL_PROTOC_OPTIMIZE_TYPE := nano
-LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/proto/
-LOCAL_PROTO_JAVA_OUTPUT_PARAMS := enum_style=java
-
-LOCAL_RESOURCE_DIR := \
- $(LOCAL_PATH)/res \
- $(TOP)/prebuilts/sdk/current/support/v17/leanback/res \
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- tv-common \
- lib-exoplayer \
- lib-exoplayer-v2-core \
- android-support-annotations \
- android-support-compat \
- android-support-core-ui \
- android-support-tv-provider \
- android-support-v7-palette \
- android-support-v7-recyclerview \
- android-support-v17-leanback \
- android-support-tv-provider \
- javax-annotations-jar \
-
-LOCAL_AAPT_FLAGS := --auto-add-overlay \
- --extra-packages android.support.v17.leanback \
- --extra-packages com.android.tv.common \
-
-include $(LOCAL_PATH)/buildconfig.mk
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
diff --git a/tuner/AndroidManifest.xml b/tuner/AndroidManifest.xml
deleted file mode 100644
index 12443cde..00000000
--- a/tuner/AndroidManifest.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tv.tuner"
- android:versionCode="1">
- <uses-sdk android:targetSdkVersion="23" android:minSdkVersion="21"/>
- <application />
-</manifest>
diff --git a/tuner/BuildConfig.java.in b/tuner/BuildConfig.java.in
deleted file mode 100644
index 85967fad..00000000
--- a/tuner/BuildConfig.java.in
+++ /dev/null
@@ -1,8 +0,0 @@
-/* This file is auto generated. Do not modify. */
-package com.android.tv.tuner;
-
-public final class BuildConfig {
- public static final boolean DEBUG = %DEBUG%;
- public static final boolean ENG = %ENG%;
- private BuildConfig() {}
-} \ No newline at end of file
diff --git a/tuner/buildconfig.mk b/tuner/buildconfig.mk
deleted file mode 100644
index cece7f2b..00000000
--- a/tuner/buildconfig.mk
+++ /dev/null
@@ -1,39 +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.
-#
-
-# Emulate gradles BuildConfig.java
-
-ifeq "$(TARGET_BUILD_VARIANT)" "eng"
- BC_DEBUG_STATUS := true
-else ifeq "$(TARGET_BUILD_VARIANT)" "userdebug"
- BC_DEBUG_STATUS := true
-else
- BC_DEBUG_STATUS := false
-endif
-
-ifeq "$(TARGET_BUILD_VARIANT)" "eng"
- BC_ENG_STATUS := true
-else
- BC_ENG_STATUS := false
-endif
-
-gen := $(local-generated-sources-dir)/$(TARGET_BUILD_VARIANT)/BuildConfig.java
-$(gen): PRIVATE_CUSTOM_TOOL = sed -e \
- 's/%DEBUG%/$(BC_DEBUG_STATUS)/;s/%ENG%/$(BC_ENG_STATUS)/' \
- $< > $@
-$(gen) : $(LOCAL_PATH)/BuildConfig.java.in
- $(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(gen) \ No newline at end of file
diff --git a/tuner/src/com/android/tv/tuner/TunerFeatures.java b/tuner/src/com/android/tv/tuner/TunerFeatures.java
deleted file mode 100644
index a6dafa67..00000000
--- a/tuner/src/com/android/tv/tuner/TunerFeatures.java
+++ /dev/null
@@ -1,102 +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;
-
-import static com.android.tv.common.feature.FeatureUtils.OFF;
-
-import android.content.Context;
-import android.text.TextUtils;
-import android.util.Log;
-import com.android.tv.common.BaseApplication;
-import com.android.tv.common.config.api.RemoteConfig;
-import com.android.tv.common.feature.CommonFeatures;
-import com.android.tv.common.feature.Feature;
-import com.android.tv.common.feature.PropertyFeature;
-import com.android.tv.common.util.CommonUtils;
-import com.android.tv.common.util.LocationUtils;
-import java.util.Locale;
-
-/**
- * List of {@link Feature} for Tuner.
- *
- * <p>Remove the {@code Feature} once it is launched.
- */
-public class TunerFeatures extends CommonFeatures {
- private static final String TAG = "TunerFeatures";
- private static final boolean DEBUG = false;
-
- /** Use network tuner if it is available and there is no other tuner types. */
- public static final Feature NETWORK_TUNER =
- new Feature() {
- @Override
- public boolean isEnabled(Context context) {
- if (!TUNER.isEnabled(context)) {
- return false;
- }
- if (CommonUtils.isDeveloper()) {
- // Network tuner will be enabled for developers.
- return true;
- }
- return Locale.US
- .getCountry()
- .equalsIgnoreCase(LocationUtils.getCurrentCountry(context));
- }
- };
-
- /**
- * USE_SW_CODEC_FOR_SD
- *
- * <p>Prefer software based codec for SD channels.
- */
- public static final Feature USE_SW_CODEC_FOR_SD =
- PropertyFeature.create(
- "use_sw_codec_for_sd",
- false
- );
-
- /** Use AC3 software decode. */
- public static final Feature AC3_SOFTWARE_DECODE =
- new Feature() {
- private final String[] SUPPORTED_REGIONS = {};
-
- private Boolean mEnabled;
-
- @Override
- public boolean isEnabled(Context context) {
- if (mEnabled == null) {
- if (mEnabled == null) {
- // We will not cache the result of fallback solution.
- String country = LocationUtils.getCurrentCountry(context);
- for (int i = 0; i < SUPPORTED_REGIONS.length; ++i) {
- if (SUPPORTED_REGIONS[i].equalsIgnoreCase(country)) {
- return true;
- }
- }
- if (DEBUG) Log.d(TAG, "AC3 flag false after country check");
- return false;
- }
- }
- if (DEBUG) Log.d(TAG, "AC3 flag " + mEnabled);
- return mEnabled;
- }
- };
-
- /** Enable Dvb parsers and listeners. */
- public static final Feature ENABLE_FILE_DVB = OFF;
-
- private TunerFeatures() {}
-}
diff --git a/tuner/src/com/android/tv/tuner/TunerPreferences.java b/tuner/src/com/android/tv/tuner/TunerPreferences.java
deleted file mode 100644
index 6477235d..00000000
--- a/tuner/src/com/android/tv/tuner/TunerPreferences.java
+++ /dev/null
@@ -1,98 +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;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import com.android.tv.common.CommonPreferences;
-import com.android.tv.common.SoftPreconditions;
-
-/** A helper class for the tuner preferences. */
-public class TunerPreferences extends CommonPreferences {
- private static final String TAG = "TunerPreferences";
-
- private static final String PREFS_KEY_CHANNEL_DATA_VERSION = "channel_data_version";
- private static final String PREFS_KEY_SCANNED_CHANNEL_COUNT = "scanned_channel_count";
- private static final String PREFS_KEY_SCAN_DONE = "scan_done";
- private static final String PREFS_KEY_TRICKPLAY_EXPIRED_MS = "trickplay_expired_ms";
-
- private static final String SHARED_PREFS_NAME = "com.android.tv.tuner.preferences";
-
- public static final int CHANNEL_DATA_VERSION_NOT_SET = -1;
-
- protected static SharedPreferences getSharedPreferences(Context context) {
- return context.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE);
- }
-
- public static synchronized int getChannelDataVersion(Context context) {
- SoftPreconditions.checkState(sInitialized);
- return getSharedPreferences(context)
- .getInt(
- TunerPreferences.PREFS_KEY_CHANNEL_DATA_VERSION,
- CHANNEL_DATA_VERSION_NOT_SET);
- }
-
- public static synchronized void setChannelDataVersion(Context context, int version) {
- SoftPreconditions.checkState(sInitialized);
- getSharedPreferences(context)
- .edit()
- .putInt(TunerPreferences.PREFS_KEY_CHANNEL_DATA_VERSION, version)
- .apply();
- }
-
- public static synchronized int getScannedChannelCount(Context context) {
- SoftPreconditions.checkState(sInitialized);
- return getSharedPreferences(context)
- .getInt(TunerPreferences.PREFS_KEY_SCANNED_CHANNEL_COUNT, 0);
- }
-
- public static synchronized void setScannedChannelCount(Context context, int channelCount) {
- SoftPreconditions.checkState(sInitialized);
- getSharedPreferences(context)
- .edit()
- .putInt(TunerPreferences.PREFS_KEY_SCANNED_CHANNEL_COUNT, channelCount)
- .apply();
- }
-
- public static synchronized boolean isScanDone(Context context) {
- SoftPreconditions.checkState(sInitialized);
- return getSharedPreferences(context)
- .getBoolean(TunerPreferences.PREFS_KEY_SCAN_DONE, false);
- }
-
- public static synchronized void setScanDone(Context context) {
- SoftPreconditions.checkState(sInitialized);
- getSharedPreferences(context)
- .edit()
- .putBoolean(TunerPreferences.PREFS_KEY_SCAN_DONE, true)
- .apply();
- }
-
- public static synchronized long getTrickplayExpiredMs(Context context) {
- SoftPreconditions.checkState(sInitialized);
- return getSharedPreferences(context)
- .getLong(TunerPreferences.PREFS_KEY_TRICKPLAY_EXPIRED_MS, 0);
- }
-
- public static synchronized void setTrickplayExpiredMs(Context context, long timeMs) {
- SoftPreconditions.checkState(sInitialized);
- getSharedPreferences(context)
- .edit()
- .putLong(TunerPreferences.PREFS_KEY_TRICKPLAY_EXPIRED_MS, timeMs)
- .apply();
- }
-}
diff --git a/tuner/src/com/android/tv/tuner/setup/LiveTvTunerSetupActivity.java b/tuner/src/com/android/tv/tuner/setup/LiveTvTunerSetupActivity.java
deleted file mode 100644
index 722de7c6..00000000
--- a/tuner/src/com/android/tv/tuner/setup/LiveTvTunerSetupActivity.java
+++ /dev/null
@@ -1,75 +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.setup;
-
-import android.app.FragmentManager;
-import android.os.AsyncTask;
-import android.view.KeyEvent;
-import com.android.tv.tuner.TunerHal;
-
-/** An activity that serves tuner setup process. */
-public class LiveTvTunerSetupActivity extends BaseTunerSetupActivity {
- private static final String TAG = "LiveTvTunerSetupActivity";
-
- @Override
- protected void executeGetTunerTypeAndCountAsyncTask() {
- new AsyncTask<Void, Void, Integer>() {
- @Override
- protected Integer doInBackground(Void... arg0) {
- return TunerHal.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);
- }
-}
diff --git a/tuner/tests/unittests/javatests/AndroidManifest.xml b/tuner/tests/unittests/javatests/AndroidManifest.xml
deleted file mode 100644
index 66b898cc..00000000
--- a/tuner/tests/unittests/javatests/AndroidManifest.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tv.tuner.layout.tests" >
-
- <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="23"/>
-
- <instrumentation
- android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.android.tv.tuner" />
-
- <application android:label="TunerTvInputLayoutTests" >
- <uses-library android:name="android.test.runner" />
-
- <activity android:name="ScaledLayoutActivity"
- android:label="ScaledLayout Test" />
- </application>
-
-</manifest>
diff --git a/tuner/tests/unittests/javatests/assets/capture_kqed.ts b/tuner/tests/unittests/javatests/assets/capture_kqed.ts
deleted file mode 100644
index 624ac553..00000000
--- a/tuner/tests/unittests/javatests/assets/capture_kqed.ts
+++ /dev/null
Binary files differ
diff --git a/tuner/tests/unittests/javatests/assets/capture_stream.ts b/tuner/tests/unittests/javatests/assets/capture_stream.ts
deleted file mode 100644
index 97ee15c1..00000000
--- a/tuner/tests/unittests/javatests/assets/capture_stream.ts
+++ /dev/null
Binary files differ
diff --git a/tuner/tests/unittests/javatests/com/google/android/tv/tuner/FakeTunerHal.java b/tuner/tests/unittests/javatests/com/google/android/tv/tuner/FakeTunerHal.java
deleted file mode 100644
index cc4f6fde..00000000
--- a/tuner/tests/unittests/javatests/com/google/android/tv/tuner/FakeTunerHal.java
+++ /dev/null
@@ -1,79 +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;
-
-public class FakeTunerHal extends TunerHal {
-
- private boolean mDeviceOpened;
-
- public FakeTunerHal() {
- super(null);
- }
-
- @Override
- protected boolean openFirstAvailable() {
- mDeviceOpened = true;
- getDeliverySystemTypeFromDevice();
- return true;
- }
-
- @Override
- protected boolean isDeviceOpen() {
- return mDeviceOpened;
- }
-
- @Override
- protected long getDeviceId() {
- return 0;
- }
-
- @Override
- public void close() throws Exception {
- mDeviceOpened = false;
- }
-
- @Override
- protected void nativeFinalize(long deviceId) {}
-
- @Override
- protected boolean nativeTune(
- long deviceId, int frequency, @ModulationType String modulation, int timeoutMs) {
- return true;
- }
-
- @Override
- protected void nativeAddPidFilter(long deviceId, int pid, @FilterType int filterType) {}
-
- @Override
- protected void nativeCloseAllPidFilters(long deviceId) {}
-
- @Override
- protected void nativeStopTune(long deviceId) {}
-
- @Override
- protected int nativeWriteInBuffer(long deviceId, byte[] javaBuffer, int javaBufferSize) {
- return 0;
- }
-
- @Override
- protected void nativeSetHasPendingTune(long deviceId, boolean hasPendingTune) {}
-
- @Override
- protected int nativeGetDeliverySystemType(long deviceId) {
- return DELIVERY_SYSTEM_ATSC;
- }
-}
diff --git a/tuner/tests/unittests/javatests/com/google/android/tv/tuner/FileTunerHal.java b/tuner/tests/unittests/javatests/com/google/android/tv/tuner/FileTunerHal.java
deleted file mode 100644
index 73d234e0..00000000
--- a/tuner/tests/unittests/javatests/com/google/android/tv/tuner/FileTunerHal.java
+++ /dev/null
@@ -1,274 +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;
-
-import android.content.Context;
-import android.os.SystemClock;
-import android.util.Log;
-import android.util.SparseBooleanArray;
-import com.android.tv.testing.utils.Utils;
-import java.io.File;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.util.Random;
-
-/** This class simulate the actions happened in TunerHal. */
-public class FileTunerHal extends TunerHal {
-
- private static final String TAG = "FileTunerHal";
- private static final int DEVICE_ID = 0;
- private static final int TS_PACKET_SIZE = 188;
- // To keep consistent with tunertvinput_jni, which fit Ethernet MTU (1500)
- private static final int TS_PACKET_COUNT_PER_PAYLOAD = 7;
- private static final int TS_PAYLOAD_SIZE = TS_PACKET_SIZE * TS_PACKET_COUNT_PER_PAYLOAD;
- private static final int TS_SYNC_BYTE = 0x47;
- // Make the read size from file and size in nativeWriteInBuffer same to make read logic simpler.
- private static final int MIN_READ_UNIT = TS_PACKET_SIZE * TS_PACKET_COUNT_PER_PAYLOAD;
- private static final long DELAY_IOCTL_SET_FRONTEND = 100;
- private static final long DELAY_IOCTL_WAIT_FRONTEND_LOCKED = 500;
-
- // The terrestrial broadcast mode (known as 8-VSB) delivers an MPEG-2 TS at rate
- // approximately 19.39 Mbps in a 6 MHz channel. (See section #5 of ATSC A/53 Part 2:2011)
- private static final double TS_READ_BYTES_PER_MS = 19.39 * 1024 * 1024 / (8 * 1000.0);
- private static final long INITIAL_BUFFERED_TS_BYTES = (long) (TS_READ_BYTES_PER_MS * 150);
-
- private static boolean sIsDeviceOpen;
-
- private final SparseBooleanArray mPids = new SparseBooleanArray();
- private final byte[] mBuffer = new byte[MIN_READ_UNIT];
- private final File mTestFile;
- private final Random mGenerator;
- private RandomAccessFile mAccessFile;
- private boolean mHasPendingTune;
- private long mReadStartMs;
- private long mTotalReadBytes;
- private long mInitialSkipMs;
- private boolean mPacketMissing;
- private boolean mEnableArtificialDelay;
-
- FileTunerHal(Context context, File testFile) {
- super(context);
- mTestFile = testFile;
- mGenerator = Utils.createTestRandom();
- }
-
- /**
- * Skip Initial parts of the TS file in order to start from specified time position.
- *
- * @param initialSkipMs initial position from where TS stream should be provided
- */
- void setInitialSkipMs(long initialSkipMs) {
- mInitialSkipMs = initialSkipMs;
- }
-
- @Override
- protected boolean openFirstAvailable() {
- sIsDeviceOpen = true;
- getDeliverySystemTypeFromDevice();
- return true;
- }
-
- @Override
- public void close() {}
-
- @Override
- protected boolean isDeviceOpen() {
- return sIsDeviceOpen;
- }
-
- @Override
- protected long getDeviceId() {
- return DEVICE_ID;
- }
-
- @Override
- protected void nativeFinalize(long deviceId) {
- if (deviceId != DEVICE_ID) {
- return;
- }
- mPids.clear();
- }
-
- @Override
- protected boolean nativeTune(
- long deviceId, int frequency, @ModulationType String modulation, int timeoutMs) {
- if (deviceId != DEVICE_ID) {
- return false;
- }
- if (mHasPendingTune) {
- return false;
- }
- closeInputStream();
- openInputStream();
- if (mAccessFile == null) {
- return false;
- }
-
- // Sleeping to simulate calling FE_GET_INFO and FE_SET_FRONTEND.
- if (mEnableArtificialDelay) {
- SystemClock.sleep(DELAY_IOCTL_SET_FRONTEND);
- }
- if (mHasPendingTune) {
- return false;
- }
-
- // Sleeping to simulate waiting frontend locked.
- if (mEnableArtificialDelay) {
- SystemClock.sleep(DELAY_IOCTL_WAIT_FRONTEND_LOCKED);
- }
- if (mHasPendingTune) {
- return false;
- }
- mTotalReadBytes = 0;
- mReadStartMs = System.currentTimeMillis();
- return true;
- }
-
- @Override
- protected void nativeAddPidFilter(long deviceId, int pid, @FilterType int filterType) {
- if (deviceId != DEVICE_ID) {
- return;
- }
- mPids.put(pid, true);
- }
-
- @Override
- protected void nativeCloseAllPidFilters(long deviceId) {
- if (deviceId != DEVICE_ID) {
- return;
- }
- mPids.clear();
- }
-
- @Override
- protected void nativeStopTune(long deviceId) {
- if (deviceId != DEVICE_ID) {
- return;
- }
- mPids.clear();
- }
-
- @Override
- protected int nativeWriteInBuffer(long deviceId, byte[] javaBuffer, int javaBufferSize) {
- if (deviceId != DEVICE_ID) {
- return 0;
- }
- if (mEnableArtificialDelay) {
- long estimatedReadBytes =
- (long) (TS_READ_BYTES_PER_MS * (System.currentTimeMillis() - mReadStartMs))
- + INITIAL_BUFFERED_TS_BYTES;
- if (estimatedReadBytes < mTotalReadBytes) {
- return 0;
- }
- }
- int readSize = readInternal();
- if (readSize <= 0) {
- closeInputStream();
- openInputStream();
- if (mAccessFile == null) {
- return -1;
- }
- readSize = readInternal();
- } else {
- mTotalReadBytes += readSize;
- }
-
- if (mBuffer[0] != TS_SYNC_BYTE) {
- return -1;
- }
- int filteredSize = 0;
- javaBufferSize = (javaBufferSize / TS_PACKET_SIZE) * TS_PACKET_SIZE;
- javaBufferSize = (javaBufferSize < TS_PAYLOAD_SIZE) ? javaBufferSize : TS_PAYLOAD_SIZE;
- for (int i = 0, destPos = 0;
- i < readSize && destPos + TS_PACKET_SIZE <= javaBufferSize;
- i += TS_PACKET_SIZE) {
- if (mBuffer[i] == TS_SYNC_BYTE) {
- int pid = ((mBuffer[i + 1] & 0x1f) << 8) + (mBuffer[i + 2] & 0xff);
- if (mPids.get(pid)) {
- System.arraycopy(mBuffer, i, javaBuffer, destPos, TS_PACKET_SIZE);
- destPos += TS_PACKET_SIZE;
- filteredSize += TS_PACKET_SIZE;
- }
- }
- }
- return filteredSize;
- }
-
- @Override
- protected void nativeSetHasPendingTune(long deviceId, boolean hasPendingTune) {
- if (deviceId != DEVICE_ID) {
- return;
- }
- mHasPendingTune = hasPendingTune;
- }
-
- @Override
- protected int nativeGetDeliverySystemType(long deviceId) {
- return DELIVERY_SYSTEM_ATSC;
- }
-
- private int readInternal() {
- int readSize;
- try {
- if (mPacketMissing) {
- mAccessFile.skipBytes(
- mGenerator.nextInt(TS_PACKET_COUNT_PER_PAYLOAD) * TS_PACKET_SIZE);
- }
- readSize = mAccessFile.read(mBuffer, 0, mBuffer.length);
- } catch (IOException e) {
- return -1;
- }
- return readSize;
- }
-
- private void closeInputStream() {
- try {
- if (mAccessFile != null) {
- mAccessFile.close();
- }
- } catch (IOException e) {
- }
- mAccessFile = null;
- }
-
- private void openInputStream() {
- try {
- mAccessFile = new RandomAccessFile(mTestFile, "r");
-
- // Since sync frames are located once per 2 seconds, test with various
- // starting offsets according to mInitialSkipMs.
- long skipBytes = (long) (mInitialSkipMs * TS_READ_BYTES_PER_MS);
- skipBytes = skipBytes / TS_PACKET_SIZE * TS_PACKET_SIZE;
- mAccessFile.seek(skipBytes);
- } catch (IOException e) {
- Log.i(TAG, "open input stream failed:" + e);
- }
- }
-
- /** Gets the number of built-in tuner devices. Always 1 in this case. */
- public static int getNumberOfDevices(Context context) {
- return 1;
- }
-
- public void setEnablePacketMissing(boolean packetMissing) {
- mPacketMissing = packetMissing;
- }
-
- public void setEnableArtificialDelay(boolean enableArtificialDelay) {
- mEnableArtificialDelay = enableArtificialDelay;
- }
-}
diff --git a/tuner/tests/unittests/javatests/com/google/android/tv/tuner/ZappingTimeTest.java b/tuner/tests/unittests/javatests/com/google/android/tv/tuner/ZappingTimeTest.java
deleted file mode 100644
index 1bee341f..00000000
--- a/tuner/tests/unittests/javatests/com/google/android/tv/tuner/ZappingTimeTest.java
+++ /dev/null
@@ -1,413 +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;
-
-import android.content.Context;
-import android.graphics.SurfaceTexture;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Message;
-import android.support.test.filters.LargeTest;
-import android.test.InstrumentationTestCase;
-import android.util.Log;
-import android.view.Surface;
-import com.google.android.exoplayer.ExoPlayer;
-import com.android.tv.tuner.data.Cea708Data;
-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.buffer.BufferManager;
-import com.android.tv.tuner.exoplayer.buffer.TrickplayStorageManager;
-import com.android.tv.tuner.source.TsDataSourceManager;
-import com.android.tv.tuner.tvinput.EventDetector;
-import com.android.tv.tuner.tvinput.PlaybackBufferListener;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-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
-public class ZappingTimeTest extends InstrumentationTestCase {
- private static final String TAG = "ZappingTimeTest";
- private static final boolean DEBUG = false;
- private static final int TS_COPY_BUFFER_SIZE = 1024 * 512;
- private static final int PROGRAM_NUMBER = 1;
- private static final int VIDEO_PID = 49;
- private static final int PCR_PID = 49;
- private static final List<Integer> AUDIO_PIDS = Arrays.asList(51, 52, 53);
- private static final long BUFFER_SIZE_DEF = 2 * 1024;
- private static final int FREQUENCY = -1;
- private static final String MODULATION = "";
- private static final long ZAPPING_TIME_OUT_MS = 10000;
- private static final long MAX_AVERAGE_ZAPPING_TIME_MS = 4000;
- private static final int TEST_ITERATION_COUNT = 10;
- private static final int STRESS_ZAPPING_TEST_COUNT = 50;
- private static final long SKIP_DURATION_MS_TO_ADD = 200;
- private static final String TEST_TS_FILE_PATH = "capture_kqed.ts";
-
- private static final int MSG_START_PLAYBACK = 1;
-
- private TunerChannel mChannel;
- private FileTunerHal mTunerHal;
- private MpegTsPlayer mPlayer;
- private TsDataSourceManager mSourceManager;
- private Handler mHandler;
- private Context mTargetContext;
- private File mTrickplayBufferDir;
- private Surface mSurface;
- private CountDownLatch mErrorLatch;
- private CountDownLatch mDrawnToSurfaceLatch;
- private CountDownLatch mWaitTuneExecuteLatch;
- private AtomicLong mOnDrawnToSurfaceTimeMs = new AtomicLong(0);
- private MockMpegTsPlayerListener mMpegTsPlayerListener = new MockMpegTsPlayerListener();
- private MockPlaybackBufferListener mPlaybackBufferListener = new MockPlaybackBufferListener();
- private MockEventListener mEventListener = new MockEventListener();
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- mTargetContext = getInstrumentation().getTargetContext();
- mTrickplayBufferDir = mTargetContext.getCacheDir();
- HandlerThread handlerThread = new HandlerThread(TAG);
- handlerThread.start();
- List<PsiData.PmtItem> pmtItems = new ArrayList<>();
- pmtItems.add(new PsiData.PmtItem(Channel.VideoStreamType.MPEG2, VIDEO_PID, null, null));
- for (int audioPid : AUDIO_PIDS) {
- pmtItems.add(
- new PsiData.PmtItem(Channel.AudioStreamType.A52AC3AUDIO, audioPid, null, null));
- }
-
- Context context = getInstrumentation().getContext();
- // Since assets and resource files are compressed, random access to the specified offset
- // in assets or resource files will add some delay which is proportional to the offset.
- // So the TS stream asset file are copied to a cache file, and the starting stream position
- // in the file will be accessed by underlying {@link RandomAccessFile}.
- File tsCacheFile = createCacheFile(context, mTargetContext, TEST_TS_FILE_PATH);
- pmtItems.add(new PsiData.PmtItem(0x100, PCR_PID, null, null));
- mChannel = new TunerChannel(PROGRAM_NUMBER, pmtItems);
- mChannel.setFrequency(FREQUENCY);
- mChannel.setModulation(MODULATION);
- mTunerHal = new FileTunerHal(context, tsCacheFile);
- mTunerHal.openFirstAvailable();
- mSourceManager = TsDataSourceManager.createSourceManager(false);
- mSourceManager.addTunerHalForTest(mTunerHal);
- mHandler =
- new Handler(
- handlerThread.getLooper(),
- new Handler.Callback() {
- @Override
- public boolean handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_START_PLAYBACK:
- {
- mHandler.removeCallbacksAndMessages(null);
- stopPlayback();
- mOnDrawnToSurfaceTimeMs.set(0);
- mDrawnToSurfaceLatch = new CountDownLatch(1);
- if (mWaitTuneExecuteLatch != null) {
- mWaitTuneExecuteLatch.countDown();
- }
- int frequency = msg.arg1;
- boolean useSimpleSampleBuffer = (msg.arg2 == 1);
- BufferManager bufferManager = null;
- if (!useSimpleSampleBuffer) {
- bufferManager =
- new BufferManager(
- new TrickplayStorageManager(
- mTargetContext,
- mTrickplayBufferDir,
- 1024L
- * 1024L
- * BUFFER_SIZE_DEF));
- }
- mChannel.setFrequency(frequency);
- mSourceManager.setKeepTuneStatus(true);
- mPlayer =
- new MpegTsPlayer(
- new MpegTsRendererBuilder(
- mTargetContext,
- bufferManager,
- mPlaybackBufferListener),
- mHandler,
- mSourceManager,
- null,
- mMpegTsPlayerListener);
- mPlayer.setCaptionServiceNumber(
- Cea708Data.EMPTY_SERVICE_NUMBER);
- mPlayer.prepare(
- mTargetContext,
- mChannel,
- false,
- mEventListener);
- return true;
- }
- default:
- {
- Log.i(TAG, "Unhandled message code: " + msg.what);
- return true;
- }
- }
- }
- });
- }
-
- @Override
- protected void tearDown() throws Exception {
- if (mPlayer != null) {
- mPlayer.release();
- }
- if (mSurface != null) {
- mSurface.release();
- }
- mHandler.getLooper().quitSafely();
- super.tearDown();
- }
-
- public void testZappingTime() {
- zappingTimeTest(false, TEST_ITERATION_COUNT, true);
- }
-
- public void testZappingTimeWithSimpleSampleBuffer() {
- zappingTimeTest(true, TEST_ITERATION_COUNT, true);
- }
-
- @Ignore("b/69978026")
- @SuppressWarnings("JUnit4ClassUsedInJUnit3")
- public void testStressZapping() {
- zappingTimeTest(false, STRESS_ZAPPING_TEST_COUNT, false);
- }
-
- @Ignore("b/69978093")
- @SuppressWarnings("JUnit4ClassUsedInJUnit3")
- public void testZappingWithPacketMissing() {
- mTunerHal.setEnablePacketMissing(true);
- mTunerHal.setEnableArtificialDelay(true);
- SurfaceTexture surfaceTexture = new SurfaceTexture(0);
- mSurface = new Surface(surfaceTexture);
- long zappingStartTimeMs = System.currentTimeMillis();
- mErrorLatch = new CountDownLatch(1);
- mHandler.obtainMessage(MSG_START_PLAYBACK, FREQUENCY, 0).sendToTarget();
- boolean errorAppeared = false;
- while (System.currentTimeMillis() - zappingStartTimeMs < ZAPPING_TIME_OUT_MS) {
- try {
- errorAppeared = mErrorLatch.await(100, TimeUnit.MILLISECONDS);
- if (errorAppeared) {
- break;
- }
- } catch (InterruptedException e) {
- }
- }
- assertFalse("Error happened when packet lost", errorAppeared);
- }
-
- private static File createCacheFile(Context context, Context targetContext, String filename)
- throws IOException {
- File cacheFile = new File(targetContext.getCacheDir(), filename);
-
- if (cacheFile.createNewFile() == false) {
- cacheFile.delete();
- cacheFile.createNewFile();
- }
-
- InputStream inputStream = context.getResources().getAssets().open(filename);
- FileOutputStream fileOutputStream = new FileOutputStream(cacheFile);
-
- byte[] buffer = new byte[TS_COPY_BUFFER_SIZE];
- while (inputStream.read(buffer, 0, TS_COPY_BUFFER_SIZE) != -1) {
- fileOutputStream.write(buffer);
- }
-
- fileOutputStream.close();
- inputStream.close();
-
- return cacheFile;
- }
-
- private void zappingTimeTest(
- boolean useSimpleSampleBuffer, int testIterationCount, boolean enableArtificialDelay) {
- String bufferManagerLogString =
- !enableArtificialDelay
- ? "for stress test"
- : useSimpleSampleBuffer ? "with simple sample buffer" : "";
- SurfaceTexture surfaceTexture = new SurfaceTexture(0);
- mSurface = new Surface(surfaceTexture);
- mTunerHal.setEnablePacketMissing(false);
- mTunerHal.setEnableArtificialDelay(enableArtificialDelay);
- double totalZappingTime = 0.0;
- for (int i = 0; i < testIterationCount; i++) {
- mWaitTuneExecuteLatch = new CountDownLatch(1);
- long zappingStartTimeMs = System.currentTimeMillis();
- mTunerHal.setInitialSkipMs(SKIP_DURATION_MS_TO_ADD * (i % TEST_ITERATION_COUNT));
- mHandler.obtainMessage(MSG_START_PLAYBACK, FREQUENCY + i, useSimpleSampleBuffer ? 1 : 0)
- .sendToTarget();
- try {
- mWaitTuneExecuteLatch.await();
- } catch (InterruptedException e) {
- }
- boolean drawnToSurface = false;
- while (System.currentTimeMillis() - zappingStartTimeMs < ZAPPING_TIME_OUT_MS) {
- try {
- drawnToSurface = mDrawnToSurfaceLatch.await(100, TimeUnit.MILLISECONDS);
- if (drawnToSurface) {
- break;
- }
- } catch (InterruptedException e) {
- }
- }
- if (i == 0) {
- continue;
- // Get rid of the first result, which shows outlier often.
- }
- // In 10s, all zapping request will finish. Set the maximum zapping time as 10s could be
- // reasonable.
- totalZappingTime +=
- (mOnDrawnToSurfaceTimeMs.get() > 0
- ? mOnDrawnToSurfaceTimeMs.get() - zappingStartTimeMs
- : ZAPPING_TIME_OUT_MS);
- }
- double averageZappingTime = totalZappingTime / (testIterationCount - 1);
- Log.i(TAG, "Average zapping time " + bufferManagerLogString + ":" + averageZappingTime);
- assertTrue(
- "Average Zapping time "
- + bufferManagerLogString
- + " is too large:"
- + averageZappingTime,
- averageZappingTime < MAX_AVERAGE_ZAPPING_TIME_MS);
- }
-
- private void stopPlayback() {
- if (mPlayer != null) {
- mPlayer.setPlayWhenReady(false);
- mPlayer.release();
- mPlayer = null;
- }
- }
-
- private class MockMpegTsPlayerListener implements MpegTsPlayer.Listener {
-
- @Override
- public void onStateChanged(boolean playWhenReady, int playbackState) {
- if (DEBUG) {
- Log.d(TAG, "ExoPlayer state change: " + playbackState + " " + playWhenReady);
- }
- if (playbackState == ExoPlayer.STATE_READY) {
- mPlayer.setSurface(mSurface);
- mPlayer.setPlayWhenReady(true);
- mPlayer.setVolume(1.0f);
- }
- }
-
- @Override
- public void onError(Exception e) {
- if (DEBUG) {
- Log.d(TAG, "onError");
- }
- if (mErrorLatch != null) {
- mErrorLatch.countDown();
- }
- }
-
- @Override
- public void onVideoSizeChanged(int width, int height, float pixelWidthHeightRatio) {
- if (DEBUG) {
- Log.d(TAG, "onVideoSizeChanged");
- }
- }
-
- @Override
- public void onDrawnToSurface(MpegTsPlayer player, Surface surface) {
- if (DEBUG) {
- Log.d(TAG, "onDrawnToSurface");
- }
- mOnDrawnToSurfaceTimeMs.set(System.currentTimeMillis());
- if (mDrawnToSurfaceLatch != null) {
- mDrawnToSurfaceLatch.countDown();
- }
- }
-
- @Override
- public void onAudioUnplayable() {
- if (DEBUG) {
- Log.d(TAG, "onAudioUnplayable");
- }
- }
-
- @Override
- public void onSmoothTrickplayForceStopped() {
- if (DEBUG) {
- Log.d(TAG, "onSmoothTrickplayForceStopped");
- }
- }
- }
-
- private static class MockPlaybackBufferListener implements PlaybackBufferListener {
- @Override
- public void onBufferStartTimeChanged(long startTimeMs) {
- if (DEBUG) {
- Log.d(TAG, "onBufferStartTimeChanged");
- }
- }
-
- @Override
- public void onBufferStateChanged(boolean available) {
- if (DEBUG) {
- Log.d(TAG, "onBufferStateChanged");
- }
- }
-
- @Override
- public void onDiskTooSlow() {
- if (DEBUG) {
- Log.d(TAG, "onDiskTooSlow");
- }
- }
- }
-
- private static class MockEventListener implements EventDetector.EventListener {
- @Override
- public void onChannelDetected(TunerChannel channel, boolean channelArrivedAtFirstTime) {
- if (DEBUG) {
- Log.d(TAG, "onChannelDetected");
- }
- }
-
- @Override
- public void onEventDetected(TunerChannel channel, List<PsipData.EitItem> items) {
- if (DEBUG) {
- Log.d(TAG, "onEventDetected");
- }
- }
-
- @Override
- public void onChannelScanDone() {
- if (DEBUG) {
- Log.d(TAG, "onChannelScanDone");
- }
- }
- }
-}
diff --git a/tuner/tests/unittests/javatests/com/google/android/tv/tuner/layout/tests/AndroidManifest.xml b/tuner/tests/unittests/javatests/com/google/android/tv/tuner/layout/tests/AndroidManifest.xml
deleted file mode 100644
index d25965e0..00000000
--- a/tuner/tests/unittests/javatests/com/google/android/tv/tuner/layout/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tv.tuner"
- android:versionCode="1">
- <uses-sdk android:targetSdkVersion="23" android:minSdkVersion="21"/>
- <application android:label="TunerTvInputLayoutTests" >
- <activity android:name="com.android.tv.tuner.layout.tests.ScaledLayoutActivity"
- android:label="ScaledLayout Test" />
- </application>
-</manifest>
diff --git a/tuner/tests/unittests/javatests/com/google/android/tv/tuner/layout/tests/ScaledLayoutActivity.java b/tuner/tests/unittests/javatests/com/google/android/tv/tuner/layout/tests/ScaledLayoutActivity.java
deleted file mode 100644
index 681465e1..00000000
--- a/tuner/tests/unittests/javatests/com/google/android/tv/tuner/layout/tests/ScaledLayoutActivity.java
+++ /dev/null
@@ -1,83 +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.layout.tests;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.View;
-import android.widget.FrameLayout;
-import com.android.tv.tuner.layout.ScaledLayout;
-
-public class ScaledLayoutActivity extends Activity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.activity_scaled_layout_test);
-
- FrameLayout frameLayout = findViewById(R.id.root_layout);
- frameLayout.addView(createScaledLayoutTestcaseLayout());
- frameLayout.addView(createScaledLayoutTestcaseBounceY());
- }
-
- private ScaledLayout createScaledLayoutTestcaseLayout() {
- ScaledLayout scaledLayout = new ScaledLayout(this);
- scaledLayout.setLayoutParams(new FrameLayout.LayoutParams(100, 100));
-
- View view1 = new View(this);
- view1.setId(R.id.view1);
- view1.setLayoutParams(new ScaledLayout.ScaledLayoutParams(0f, 0.5f, 0f, 0.5f));
-
- View view2 = new View(this);
- view2.setId(R.id.view2);
- view2.setLayoutParams(new ScaledLayout.ScaledLayoutParams(0f, 0.5f, 0.5f, 1f));
-
- View view3 = new View(this);
- view3.setId(R.id.view3);
- view3.setLayoutParams(new ScaledLayout.ScaledLayoutParams(0.5f, 1f, 0f, 0.5f));
-
- View view4 = new View(this);
- view4.setId(R.id.view4);
- view4.setLayoutParams(new ScaledLayout.ScaledLayoutParams(0.5f, 1f, 0.5f, 1f));
-
- scaledLayout.addView(view1);
- scaledLayout.addView(view2);
- scaledLayout.addView(view3);
- scaledLayout.addView(view4);
-
- return scaledLayout;
- }
-
- private ScaledLayout createScaledLayoutTestcaseBounceY() {
- ScaledLayout scaledLayout = new ScaledLayout(this);
- scaledLayout.setLayoutParams(new FrameLayout.LayoutParams(100, 100));
-
- View view1 = new View(this);
- view1.setId(R.id.view1);
- view1.setLayoutParams(new ScaledLayout.ScaledLayoutParams(0.7f, 0.9f, 0f, 1f));
-
- View view2 = new View(this);
- view2.setId(R.id.view2);
- view2.setLayoutParams(new ScaledLayout.ScaledLayoutParams(0.8f, 1f, 0f, 1f));
-
- scaledLayout.addView(view1);
- scaledLayout.addView(view2);
-
- return scaledLayout;
- }
-}
diff --git a/tuner/tests/unittests/javatests/com/google/android/tv/tuner/layout/tests/ScaledLayoutTest.java b/tuner/tests/unittests/javatests/com/google/android/tv/tuner/layout/tests/ScaledLayoutTest.java
deleted file mode 100644
index 214b0631..00000000
--- a/tuner/tests/unittests/javatests/com/google/android/tv/tuner/layout/tests/ScaledLayoutTest.java
+++ /dev/null
@@ -1,147 +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.layout.tests;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
-
-import android.content.Intent;
-import android.support.test.filters.SmallTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-import android.view.View;
-import android.widget.FrameLayout;
-import com.android.tv.tuner.layout.ScaledLayout;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class ScaledLayoutTest {
-
- @Rule public ScaledActivityTestRule mActivityRule = new ScaledActivityTestRule();
-
- @Before
- public void setup() {
- mActivityRule.launchActivity(new Intent());
- }
-
- @After
- public void tearDown() {
- mActivityRule.finishActivity();
- }
-
- @Test
- public void testScaledLayout_layoutInXml() {
- ScaledLayoutActivity activity = mActivityRule.getActivity();
- assertNotNull(activity);
- FrameLayout rootLayout = mActivityRule.getActivity().findViewById(R.id.root_layout);
- assertNotNull(rootLayout);
- ScaledLayout scaledLayout = (ScaledLayout) rootLayout.getChildAt(0);
- assertNotNull(scaledLayout);
- View view1 = scaledLayout.findViewById(R.id.view1);
- assertNotNull(view1);
- View view2 = scaledLayout.findViewById(R.id.view2);
- assertNotNull(view2);
- View view3 = scaledLayout.findViewById(R.id.view3);
- assertNotNull(view3);
- View view4 = scaledLayout.findViewById(R.id.view4);
- assertNotNull(view4);
- assertEquals((int) (400 * 0.1), view1.getWidth());
- assertEquals((int) (300 * 0.2), view1.getHeight());
- assertEquals((int) (400 * 0.8), view1.getLeft());
- assertEquals((int) (300 * 0.1), view1.getTop());
- assertEquals((int) (400 * 0.1), view2.getWidth());
- assertEquals(300, view2.getHeight());
- assertEquals((int) (400 * 0.2), view2.getLeft());
- assertEquals(0, view2.getTop());
- assertEquals((int) (400 * 0.2), view3.getWidth());
- assertEquals((int) (300 * 0.1), view3.getHeight());
- assertEquals((int) (400 * 0.3), view3.getLeft());
- assertEquals((int) (300 * 0.4), view3.getTop());
- assertEquals((int) (400 * 0.1), view4.getWidth());
- assertEquals((int) (300 * 0.8), view4.getHeight());
- assertEquals((int) (400 * 0.05), view4.getLeft());
- assertEquals((int) (300 * 0.15), view4.getTop());
- }
-
- @Test
- public void testScaledLayout_layoutThroughCode() {
- ScaledLayoutActivity activity = mActivityRule.getActivity();
- assertNotNull(activity);
- FrameLayout rootLayout = mActivityRule.getActivity().findViewById(R.id.root_layout);
- assertNotNull(rootLayout);
- ScaledLayout scaledLayout = (ScaledLayout) rootLayout.getChildAt(1);
- assertNotNull(scaledLayout);
- View view1 = scaledLayout.findViewById(R.id.view1);
- assertNotNull(view1);
- View view2 = scaledLayout.findViewById(R.id.view2);
- assertNotNull(view2);
- View view3 = scaledLayout.findViewById(R.id.view3);
- assertNotNull(view3);
- View view4 = scaledLayout.findViewById(R.id.view4);
- assertNotNull(view4);
- assertEquals(50, view1.getWidth());
- assertEquals(50, view1.getHeight());
- assertEquals(0, view1.getLeft());
- assertEquals(0, view1.getTop());
- assertEquals(50, view2.getWidth());
- assertEquals(50, view2.getHeight());
- assertEquals(50, view2.getLeft());
- assertEquals(0, view2.getTop());
- assertEquals(50, view3.getWidth());
- assertEquals(50, view3.getHeight());
- assertEquals(0, view3.getLeft());
- assertEquals(50, view3.getTop());
- assertEquals(50, view4.getWidth());
- assertEquals(50, view4.getHeight());
- assertEquals(50, view4.getLeft());
- assertEquals(50, view4.getTop());
- }
-
- @Test
- public void testScaledLayout_bounceY() {
- ScaledLayoutActivity activity = mActivityRule.getActivity();
- assertNotNull(activity);
- FrameLayout rootLayout = mActivityRule.getActivity().findViewById(R.id.root_layout);
- assertNotNull(rootLayout);
- ScaledLayout scaledLayout = (ScaledLayout) rootLayout.getChildAt(2);
- assertNotNull(scaledLayout);
- View view1 = scaledLayout.findViewById(R.id.view1);
- assertNotNull(view1);
- View view2 = scaledLayout.findViewById(R.id.view2);
- assertNotNull(view2);
- assertEquals(100, view1.getWidth());
- assertEquals(20, view1.getHeight());
- assertEquals(0, view1.getLeft());
- assertEquals(60, view1.getTop());
- assertEquals(100, view2.getWidth());
- assertEquals(20, view2.getHeight());
- assertEquals(0, view2.getLeft());
- assertEquals(80, view2.getTop());
- }
-
- private static class ScaledActivityTestRule extends ActivityTestRule<ScaledLayoutActivity> {
-
- public ScaledActivityTestRule() {
- super(ScaledLayoutActivity.class);
- }
- }
-}
diff --git a/tuner/tests/unittests/javatests/com/google/android/tv/tuner/setup/TunerHalFactoryTest.java b/tuner/tests/unittests/javatests/com/google/android/tv/tuner/setup/TunerHalFactoryTest.java
deleted file mode 100644
index 18943f0e..00000000
--- a/tuner/tests/unittests/javatests/com/google/android/tv/tuner/setup/TunerHalFactoryTest.java
+++ /dev/null
@@ -1,79 +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.setup;
-
-import android.os.AsyncTask;
-import android.support.test.filters.SmallTest;
-import com.android.tv.tuner.TunerHal;
-import com.android.tv.tuner.setup.BaseTunerSetupActivity.TunerHalFactory;
-import java.util.concurrent.Executor;
-import junit.framework.TestCase;
-
-/** Tests for {@link TunerHalFactory}. */
-@SmallTest
-public class TunerHalFactoryTest extends TestCase {
- private final FakeExecutor mFakeExecutor = new FakeExecutor();
-
- private static class TestTunerHalFactory extends TunerHalFactory {
- private TestTunerHalFactory(Executor executor) {
- super(null, executor);
- }
-
- @Override
- protected TunerHal createInstance() {
- return new com.android.tv.tuner.FakeTunerHal() {};
- }
- }
-
- private static class FakeExecutor implements Executor {
- Runnable mCommand;
-
- @Override
- public synchronized void execute(final Runnable command) {
- mCommand = command;
- }
-
- private synchronized void executeActually() {
- mCommand.run();
- }
- }
-
- public void test_asyncGet() {
- TunerHalFactory tunerHalFactory = new TestTunerHalFactory(mFakeExecutor);
- assertNull(tunerHalFactory.mTunerHal);
- tunerHalFactory.generate();
- assertNull(tunerHalFactory.mTunerHal);
- mFakeExecutor.executeActually();
- TunerHal tunerHal = tunerHalFactory.getOrCreate();
- assertNotNull(tunerHal);
- assertSame(tunerHal, tunerHalFactory.getOrCreate());
- tunerHalFactory.clear();
- }
-
- public void test_syncGet() {
- TunerHalFactory tunerHalFactory = new TestTunerHalFactory(AsyncTask.SERIAL_EXECUTOR);
- assertNull(tunerHalFactory.mTunerHal);
- tunerHalFactory.generate();
- assertNotNull(tunerHalFactory.getOrCreate());
- }
-
- public void test_syncGetWithoutGenerate() {
- TunerHalFactory tunerHalFactory = new TestTunerHalFactory(mFakeExecutor);
- assertNull(tunerHalFactory.mTunerHal);
- assertNotNull(tunerHalFactory.getOrCreate());
- }
-}
diff --git a/tuner/tests/unittests/javatests/res/layout/activity_scaled_layout_test.xml b/tuner/tests/unittests/javatests/res/layout/activity_scaled_layout_test.xml
deleted file mode 100644
index be2ba950..00000000
--- a/tuner/tests/unittests/javatests/res/layout/activity_scaled_layout_test.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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.
- -->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:id="@+id/root_layout"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <com.android.tv.tuner.layout.ScaledLayout android:id="@+id/scaled_layout"
- android:layout_width="400px"
- android:layout_height="300px">
-
- <View android:id="@+id/view1"
- app:layout_scaleStartRow="0.1"
- app:layout_scaleEndRow="0.3"
- app:layout_scaleStartCol="0.8"
- app:layout_scaleEndCol="0.9" />
-
- <View android:id="@+id/view2"
- app:layout_scaleStartRow="0"
- app:layout_scaleEndRow="1"
- app:layout_scaleStartCol="0.2"
- app:layout_scaleEndCol="0.3" />
-
- <View android:id="@+id/view3"
- app:layout_scaleStartRow="0.4"
- app:layout_scaleEndRow="0.5"
- app:layout_scaleStartCol="0.3"
- app:layout_scaleEndCol="0.5" />
-
- <View android:id="@+id/view4"
- app:layout_scaleStartRow="0.15"
- app:layout_scaleEndRow="0.95"
- app:layout_scaleStartCol="0.05"
- app:layout_scaleEndCol="0.15" />
-
- </com.android.tv.tuner.layout.ScaledLayout>
-</FrameLayout>
diff --git a/tuner/tests/unittests/javatests/res/values/attrs.xml b/tuner/tests/unittests/javatests/res/values/attrs.xml
deleted file mode 100644
index 4249ed2f..00000000
--- a/tuner/tests/unittests/javatests/res/values/attrs.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ 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.
- -->
-
-<resources>
- <declare-styleable name="utScaledLayout">
- <attr name="layout_scaleStartRow" format="float" />
- <attr name="layout_scaleEndRow" format="float" />
- <attr name="layout_scaleStartCol" format="float" />
- <attr name="layout_scaleEndCol" format="float" />
- </declare-styleable>
-</resources>
diff --git a/tuner/res/drawable-xhdpi/recommendation_antenna.png b/usbtuner-res/drawable-xhdpi/recommendation_antenna.png
index c4710bcc..c4710bcc 100644
--- a/tuner/res/drawable-xhdpi/recommendation_antenna.png
+++ b/usbtuner-res/drawable-xhdpi/recommendation_antenna.png
Binary files differ
diff --git a/tuner/res/drawable-xhdpi/usb_antenna.png b/usbtuner-res/drawable-xhdpi/usb_antenna.png
index ca5b2d72..ca5b2d72 100644
--- a/tuner/res/drawable-xhdpi/usb_antenna.png
+++ b/usbtuner-res/drawable-xhdpi/usb_antenna.png
Binary files differ
diff --git a/tuner/res/drawable/ut_scan_progress.xml b/usbtuner-res/drawable/ut_scan_progress.xml
index f4daf6c8..f4daf6c8 100644
--- a/tuner/res/drawable/ut_scan_progress.xml
+++ b/usbtuner-res/drawable/ut_scan_progress.xml
diff --git a/tuner/res/layout/ut_channel_list.xml b/usbtuner-res/layout/ut_channel_list.xml
index 430234f8..430234f8 100644
--- a/tuner/res/layout/ut_channel_list.xml
+++ b/usbtuner-res/layout/ut_channel_list.xml
diff --git a/tuner/res/layout/ut_channel_scan.xml b/usbtuner-res/layout/ut_channel_scan.xml
index 415ac929..415ac929 100644
--- a/tuner/res/layout/ut_channel_scan.xml
+++ b/usbtuner-res/layout/ut_channel_scan.xml
diff --git a/tuner/res/layout/ut_overlay_view.xml b/usbtuner-res/layout/ut_overlay_view.xml
index 1ee2e340..1ee2e340 100644
--- a/tuner/res/layout/ut_overlay_view.xml
+++ b/usbtuner-res/layout/ut_overlay_view.xml
diff --git a/tuner/res/raw/ut_euro_dvbt_all b/usbtuner-res/raw/ut_euro_dvbt_all
index 101ee3eb..101ee3eb 100644
--- a/tuner/res/raw/ut_euro_dvbt_all
+++ b/usbtuner-res/raw/ut_euro_dvbt_all
diff --git a/tuner/res/raw/ut_kr_all b/usbtuner-res/raw/ut_kr_all
index 9c4d7e64..9c4d7e64 100644
--- a/tuner/res/raw/ut_kr_all
+++ b/usbtuner-res/raw/ut_kr_all
diff --git a/tuner/res/raw/ut_kr_atsc_center_frequencies_8vsb b/usbtuner-res/raw/ut_kr_atsc_center_frequencies_8vsb
index 14678d3a..14678d3a 100644
--- a/tuner/res/raw/ut_kr_atsc_center_frequencies_8vsb
+++ b/usbtuner-res/raw/ut_kr_atsc_center_frequencies_8vsb
diff --git a/tuner/res/raw/ut_kr_cable_standard_center_frequencies_qam256 b/usbtuner-res/raw/ut_kr_cable_standard_center_frequencies_qam256
index 258a179a..258a179a 100644
--- a/tuner/res/raw/ut_kr_cable_standard_center_frequencies_qam256
+++ b/usbtuner-res/raw/ut_kr_cable_standard_center_frequencies_qam256
diff --git a/tuner/res/raw/ut_kr_dev_cj_cable_center_frequencies_qam256 b/usbtuner-res/raw/ut_kr_dev_cj_cable_center_frequencies_qam256
index c52eeeea..c52eeeea 100644
--- a/tuner/res/raw/ut_kr_dev_cj_cable_center_frequencies_qam256
+++ b/usbtuner-res/raw/ut_kr_dev_cj_cable_center_frequencies_qam256
diff --git a/tuner/res/raw/ut_us_all b/usbtuner-res/raw/ut_us_all
index a5bd846a..a5bd846a 100644
--- a/tuner/res/raw/ut_us_all
+++ b/usbtuner-res/raw/ut_us_all
diff --git a/tuner/res/raw/ut_us_atsc_center_frequencies_8vsb b/usbtuner-res/raw/ut_us_atsc_center_frequencies_8vsb
index 245a68a8..245a68a8 100644
--- a/tuner/res/raw/ut_us_atsc_center_frequencies_8vsb
+++ b/usbtuner-res/raw/ut_us_atsc_center_frequencies_8vsb
diff --git a/tuner/res/raw/ut_us_cable_standard_center_frequencies_qam256 b/usbtuner-res/raw/ut_us_cable_standard_center_frequencies_qam256
index f42a5141..f42a5141 100644
--- a/tuner/res/raw/ut_us_cable_standard_center_frequencies_qam256
+++ b/usbtuner-res/raw/ut_us_cable_standard_center_frequencies_qam256
diff --git a/usbtuner-res/values-af/strings.xml b/usbtuner-res/values-af/strings.xml
new file mode 100644
index 00000000..8fd50706
--- /dev/null
+++ b/usbtuner-res/values-af/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"TV-ontvanger"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB-TV-ontvanger"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Netwerk-TV-ontvanger (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Wag asseblief dat verwerking voltooi word"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Ontvangersagteware is onlangs opgedateer. Herskandeer die kanale asseblief."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Aktiveer omringklank in stelselklankinstellings om oudio te aktiveer"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Kan nie oudio speel nie. Probeer asseblief \'n ander TV"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Opstelling van kanaalontvanger"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Opstelling van TV-ontvanger"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Opstelling van USB-kanaalontvanger"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Opstelling van netwerkontvanger"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Maak seker dat jou TV aan \'n TV-seinbron gekoppel is.\n\nAs jy \'n oor-die-lug-antenna gebruik, sal jy dalk sy plasing of rigting moet verander om die meeste kanale te ontvang. Plaas dit vir die beste resultate hoog en naby \'n venster."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Maak seker dat die USB-ontvanger ingeprop en aan \'n TV-seinbron gekoppel is.\n\nAs jy \'n oor-die-lug-antenna gebruik, sal jy dalk sy posisie of rigting moet verander om die meeste kanale te ontvang. Plaas dit vir die beste resultate hoog en naby \'n venster."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Maak seker dat die netwerkontvanger aangeskakel is en aan \'n TV-seinbron gekoppel is.\n\nAs jy \'n oor-die-lug-antenna gebruik, sal jy dalk sy plasing of rigting waarin hy wys, moet verstel om die meeste kanale te ontvang. Plaas dit vir die beste resultate hoog en naby \'n venster."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Gaan voort"</item>
+ <item msgid="727245208787621142">"Nie nou nie"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Doen kanaalopstelling weer?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Dit sal die kanale wat ontvang is, uit die TV-ontvanger verwyder en weer nuwe kanale soek.\n\nMaak seker dat jou TV aan \'n TV-seinbron gekoppel is.\n\nAs jy \'n oor-die-lug-antenna gebruik, sal jy dalk sy plasing of rigting moet verander om die meeste kanale te ontvang. Plaas dit vir die beste resultate hoog en naby \'n venster."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Dit sal die kanale wat gevind is, uit die USB-ontvanger verwyder en weer nuwe kanale soek.\n\nMaak seker dat die USB-ontvanger ingeprop en aan \'n TV-seinbron gekoppel is.\n\nAs jy \'n oor-die-lug-antenna gebruik, sal jy dalk sy posisie of rigting moet verander om die meeste kanale te ontvang. Plaas dit vir die beste resultate hoog en naby \'n venster."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Dit sal die kanale wat gevind is van die netwerkontvanger af verwyder en weer na nuwe kanale soek.\n\nMaak seker dat die netwerkontvanger aangeskakel is en aan \'n TV-seinbron gekoppel is.\n\nAs jy \'n oor-die-lug-antenna gebruik, sal jy dalk sy plasing of rigting waarin hy wys, moet verstel om die meeste kanale te ontvang. Plaas dit vir die beste resultate hoog en naby \'n venster."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Gaan voort"</item>
+ <item msgid="235450158666155406">"Kanselleer"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Kies die soort verbinding"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Kies Antenna as \'n eksterne antenna aan die ontvanger gekoppel is. Kies Kabel as jou kanale van \'n kabeldiensverskaffer af kom. As jy nie seker is nie, sal albei soorte geskandeer word, maar dit sal dalk langer neem."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antenna"</item>
+ <item msgid="2670079958754180142">"Kabel"</item>
+ <item msgid="36774059871728525">"Nie seker nie"</item>
+ <item msgid="6881204453182153978">"Net ontwikkeling"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Opstelling van TV-ontvanger"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Opstelling van USB-kanaalontvanger"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Opstelling van netwerkkanaalontvanger"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Dit kan \'n paar minute neem"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Seinontvanger is tydelik nie beskikbaar nie of word reeds deur opname gebruik."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">%1$d kanale is gevind</item>
+ <item quantity="one">%1$d kanaal is gevind</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"STOP KANAALSKANDERING"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">%1$d kanale is gevind</item>
+ <item quantity="one">%1$d kanaal is gevind</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Lekker! %1$d kanale is tydens die kanaalsoektog gevind. As dit nie reg lyk nie, probeer die antennaposisie verstel en soek weer.</item>
+ <item quantity="one">Lekker! %1$d kanaal is tydens die kanaalsoektog gevind. As dit nie reg lyk nie, probeer die antennaposisie verstel en soek weer.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Klaar"</item>
+ <item msgid="2480490326672924828">"Soek weer"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Geen kanale gevind nie"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Geen kanale is in die soektog gevind nie. Maak seker dat jou TV aan \'n TV-seinbron gekoppel is.\n\nAs jy \'n oor-die-lug-antenna gebruik, verander sy plasing of rigting. Plaas dit vir die beste resultate hoog en naby \'n venster en soek weer."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Geen kanale is in die soektog gevind nie. Maak seker dat die USB-ontvanger ingeprop en aan \'n TV-seinbron gekoppel is.\n\nAs jy \'n oor-die-lug-antenna gebruik, verander sy posisie of rigting. Plaas dit vir die beste resultate hoog en naby \'n venster en soek weer."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Geen kanale is in die soektog gevind nie. Maak seker dat die netwerkontvanger aangeskakel is en aan \'n TV-seinbron gekoppel is.\n\nAs jy \'n oor-die-lug-antenna gebruik, verstel sy plasing of rigting waarin hy wys. Plaas dit vir die beste resultate hoog en naby \'n venster en soek weer."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Soek weer"</item>
+ <item msgid="2092797862490235174">"Klaar"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Soek TV-kanale"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Opstelling van TV-ontvanger"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Opstelling van USB-TV-ontvanger"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Opstelling van netwerk-TV-ontvanger"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB-TV-ontvanger is ontkoppel."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Netwerkontvanger is ontkoppel."</string>
+</resources>
diff --git a/usbtuner-res/values-am/strings.xml b/usbtuner-res/values-am/strings.xml
new file mode 100644
index 00000000..cbf1e9fe
--- /dev/null
+++ b/usbtuner-res/values-am/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"የቴሌቪዥን መቃኛ"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"የዩኤስቢ ቴሌቪዥን መቃኛ"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"የአውታረ መረብ ቴሌቪዥን መቃኛ (ቅድመ-ይሁንታ)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"ማስኬድን ለማጠናቀቅ እባክዎ ይጠብቁ"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"የቴሌቪዥን መቃኛ ሶፍትዌር በቅርብ ጊዜ ተዘምኗል። እባክዎ ሰርጦቹን እንደገና ይቃኟቸው።"</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"ኦዲዮን ለማንቃት በስርዓት ድምጽ ቅንብሮች ውስጥ የዙሪያ ድምጽን ያንቁ"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"ኦዲዮ ማጫወት አይቻልም። እባክዎ ሌላ ቲቪ ይሞክሩ።"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"የጣቢያ መቃኛ ማዋቀር"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"የቴሌቪዥን መቃኛ ማዋቀር"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"የዩኤስቢ ጣቢያ መቃኛ ማዋቀር"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"የአውታረ መረብ መቃኛ ማዋቀር"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"የእርስዎ ቴሌቪዥን ከቴሌቪዥን ሲግናል ምልክት ምንጭ ጋር መገናኘቱን ያረጋግጡ።\n\nየአየር ላይ አንቴና የሚጠቀሙ ከሆነ አብዛኛዎቹን ጣቢያዎች ለመቀበል አቀማመጡን ወይም አቅጣጫውን ማስተካከል ሊኖርብዎት ይችላል። ለተሻሉ ውጤቶች ከፍ አድርገው ከመስኮት አጠገብ ያስቀምጡት።"</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"የዩኤስቢ መቃኛው መሰካቱን እና ከቴሌቪዥን ምልክት ምንጭ ጋር መገናኘቱን ያረጋግጡ።\n\nየአየር ላይ አንቴና የሚጠቀሙ ከሆነ አቀማመጡን ወይም አቅጣጫውን ያስተካክሉ። ለተሻሉ ውጤቶች ከፍ አድርገው ከመስኮት አጠገብ ያስቀምጡት።"</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"የአውታረ መረብ መቃኛው እና ከቴሌቪዥን ምልክት ምንጭ ጋር መገናኘቱን ያረጋግጡ።\n\nየአየር ላይ አንቴና የሚጠቀሙ ከሆነ አቀማመጡን ወይም አቅጣጫውን ያስተካክሉ። ለተሻሉ ውጤቶች ከፍ አድርገው ከመስኮት አጠገብ ያስቀምጡት።"</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"ቀጥል"</item>
+ <item msgid="727245208787621142">"አሁን አይደለም"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"የጣቢያ ቅንብር እንደገና እንዲሄድ ይደረግ?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"ይሄ ከቴሌቪዥን መቃኛ የተገኙ ጣቢያዎችን አስወግዶ አዲስ ጣቢያዎችን እንደገና ይቃኛል።\n\nየእርስዎ ቴሌቪዥን ከቴሌቪዥን ሲግናል ምልክት ምንጭ ጋር መገናኘቱን ያረጋግጡ።\n\nየአየር ላይ አንቴና የሚጠቀሙ ከሆነ አብዛኛዎቹን ጣቢያዎች ለመቀበል አቀማመጡን ወይም አቅጣጫውን ማስተካከል ሊኖርብዎት ይችላል። ለተሻሉ ውጤቶች ከፍ አድርገው ከመስኮት አጠገብ ያስቀምጡት።"</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"ይሄ ከዩኤስቢ መቃኛ የተገኙ ጣቢያዎችን አስወግዶ አዲስ ጣቢያዎችን እንደገና ይቃኛል።\n\nየዩኤስቢ መቃኛው መሰካቱን እና ከቴሌቪዥን ምልክት ምንጭ ጋር መገናኘቱን ያረጋግጡ።\n\nየአየር ላይ አንቴና የሚጠቀሙ ከሆነ አቀማመጡን ወይም አቅጣጫውን ያስተካክሉ። ለተሻሉ ውጤቶች ከፍ አድርገው ከመስኮት አጠገብ ያስቀምጡት።"</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"ይሄ ከአውታረ መረብ መቃኛ የተገኙ ጣቢያዎችን አስወግዶ አዲስ ጣቢያዎችን እንደገና ይቃኛል።\n\nየአውታረ መረብ መቃኛው እና ከቴሌቪዥን ምልክት ምንጩ መገናኘቱን ያረጋግጡ።\n\nየአየር ላይ አንቴና የሚጠቀሙ ከሆነ አቀማመጡን ወይም አቅጣጫውን ያስተካክሉ። ለተሻሉ ውጤቶች ከፍ አድርገው ከመስኮት አጠገብ ያስቀምጡት።"</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"ቀጥል"</item>
+ <item msgid="235450158666155406">"ይቅር"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"የግንኙነት ዓይነቱን ይምረጡ"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"ከመቃኛው ጋር የተገናኘ ውጫዊ አንቴና ካለ አንቴናን ይምረጡ። የእርስዎ ጣቢያዎች ከገመድ አገልግሎት አቅራቢ የሚመጡ ከሆነ ገመድን ይምረጡ። እርግጠኛ ካልሆኑ ሁለቱም ዓይነቶች ይቃኛሉ፣ ሆኖም ግን ይሄ ረዘም ያለ ጊዜ ሊወስድ ይችላል።"</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"አንቴና"</item>
+ <item msgid="2670079958754180142">"ገመድ"</item>
+ <item msgid="36774059871728525">"እርግጠኛ አይደሉም"</item>
+ <item msgid="6881204453182153978">"ግንባታ ብቻ"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"የቴሌቪዥን መቃኛ ማዋቀር"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"የዩኤስቢ ጣቢያ መቃኛ ማዋቀር"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"የአውታረ መረብ ጣቢያ መቃኛ ማዋቀር"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"ይሄ በርካታ ደቂቃዎችን ሊወስድ ይችላል"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"መቃኛው ለጊዜው አይገኝም ወይም አስቀድሞ በቀረጻው ጥቅም ላይ ውሏል።"</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="one">%1$d ጣቢያዎች ተገኝተዋል</item>
+ <item quantity="other">%1$d ጣቢያዎች ተገኝተዋል</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"የጣቢያ ቅኝትን አቁም"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="one">%1$d ጣቢያዎች ተገኝተዋል</item>
+ <item quantity="other">%1$d ጣቢያዎች ተገኝተዋል</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="one">ግሩም! በጣቢያ ቅኝት ጊዜ %1$d ጣቢያዎች ተገኝተዋል። ትክክል የማይመስል ከሆነ የአንቴናውን አቀማመጥ አስተካክለው እንደገና ለመቃኘት ይሞክሩ።</item>
+ <item quantity="other">ግሩም! በጣቢያ ቅኝት ጊዜ %1$d ጣቢያዎች ተገኝተዋል። ትክክል የማይመስል ከሆነ የአንቴናውን አቀማመጥ አስተካክለው እንደገና ለመቃኘት ይሞክሩ።</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"ተከናውኗል"</item>
+ <item msgid="2480490326672924828">"እንደገና ቃኝ"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"ምንም ጣቢያዎች አልተገኙም"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"ቅኝቱ ምንም አዲስ ጣቢያዎችን አላገኘም። የእርስዎ ቴሌቪዥን ከቴሌቪዥን ሲግናል ምንጭ ጋር መገናኘቱን ያረጋግጡ።\n\nየአየር ላይ አንቴና ከሆነ የሚጠቀሙት አቀማመጡን ወይም አቅጣጫውን ያስተካክሉት። ለተሻሉ ውጤቶች ከፍ አድርገው ከመስኮት አጠገብ ያስቀምጡትና እንደገና ይቃኙ።"</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"ቅኝቱ ምንም ጣቢያዎችን አላገኘም። የዩኤስቢ መቃኛው መሰካቱን እና ከቴሌቪዥን ሲግናል ምንጩ ጋር መገናኘቱን ያረጋግጡ።\n\nየአየር ላይ አንቴና የሚጠቀሙ ከሆነ አቀማመጡን ወይም አቅጣጫውን ያስተካክሉ። ለተሻሉ ውጤቶች ከፍ አድርገው ከመስኮት አጠገብ ያስቀምጡት እና እንደገና ይቃኙ።"</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"ቅኝቱ ምንም ጣቢያዎችን አላገኘም። የአውታረ መረብ መቃኛው እንደበራ እና ከቴሌቪዥን ሲግናል ምንጩ ጋር መገናኘቱን ያረጋግጡ።\n\nየአየር ላይ አንቴና የሚጠቀሙ ከሆነ አቀማመጡን ወይም አቅጣጫውን ያስተካክሉ። ለተሻሉ ውጤቶች ከፍ አድርገው ከመስኮት አጠገብ ያስቀምጡት እና እንደገና ይቃኙ።"</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"እንደገና ቃኝ"</item>
+ <item msgid="2092797862490235174">"ተከናውኗል"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"የቴሌቪዥን ጣቢያዎችን ቃኝ"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"የቴሌቪዥን መቃኛ ማዋቀር"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"የዩኤስቢ ቴሌቪዥን መቃኛ ማዋቀር"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"የአውታረ መረብ ቴሌቪዥን መቃኛ ማዋቀር"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"የዩኤስቢ ቴሌቪዥን መቃኛው ግንኙነት ተቋርጧል።"</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"የአውታረ መረብ መቃኛ ግንኙነት ተቋርጧል።"</string>
+</resources>
diff --git a/usbtuner-res/values-ar/strings.xml b/usbtuner-res/values-ar/strings.xml
new file mode 100644
index 00000000..ae197d19
--- /dev/null
+++ b/usbtuner-res/values-ar/strings.xml
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"موالف التلفزيون"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"‏موالف التلفزيون عبر USB"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"موالف التلفزيون على الشبكة (تجريبي)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"الرجاء الانتظار لحين انتهاء المعالجة"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"تم تحديث برنامج الموالف مؤخرًا. الرجاء إعادة البحث عن القنوات."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"يمكنك تشغيل الصوت المحيطي في إعدادات صوت النظام لتفعيل الصوت"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"لا يمكن تشغيل الصوت. الرجاء تجربة تلفزيون آخر."</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"إعداد موالف القنوات"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"إعداد موالف التلفزيون"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"‏إعداد موالف قنوات USB"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"إعداد موالف الشبكة"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"تحقق من توصيل التلفزيون بمصدر إشارة البث التلفزيوني.\n\nإذا كنت تستخدم هوائيًا للتحديث عبر الهواء، فقد تحتاج إلى ضبط موضعه أو اتجاهه لاستقبال معظم القنوات، وللحصول على أفضل النتائج، ضعه عاليًا بالقرب من النافذة."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"‏تحقق من توصيل الموالف عبر USB بمصدر إشارة البث التلفزيوني.\n\nإذا كنت تستخدم هوائيًا للتحديث عبر الهواء، فقد تحتاج إلى ضبط موضعه أو اتجاهه لاستقبال معظم القنوات، وللحصول على أفضل النتائج، ضعه عاليًا بالقرب من النافذة."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"تحقق من تشغيل موالف الشبكة وتوصيله بمصدر إشارة التلفزيون.\n\nفي حالة استخدام هوائي للتحديث عبر الهواء، قد تحتاج إلى ضبط موضعه أو تجاهه لاستقبال معظم القنوات. وللحصول على أفضل النتائج، يمكنك وضعه في مكان مرتفع أو بالقرب من النافذة."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"متابعة"</item>
+ <item msgid="727245208787621142">"ليس الآن"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"هل تريد إعادة تشغيل إعداد القنوات؟"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"سيؤدي هذا إلى إزالة القنوات التي تم العثور عليها من موالف التلفزيون والبحث مرة أخرى عن قنوات جديدة.\n\nتحقق من توصيل التلفزيون بمصدر إشارة البث التلفزيوني.\n\nإذا كنت تستخدم هوائيًا للتحديث عبر الهواء، فقد تحتاج إلى ضبط موضعه أو اتجاهه لاستقبال معظم القنوات، وللحصول على أفضل النتائج، ضعه عاليًا بالقرب من النافذة."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"‏سيؤدي هذا إلى إزالة القنوات التي تم العثور عليها من الموالف عبر USB والبحث مرة أخرى عن قنوات جديدة.\n\nتحقق من توصيل الموالف عبر USB بمصدر إشارة البث التلفزيوني.\n\nإذا كنت تستخدم هوائيًا للتحديث عبر الهواء، فقد تحتاج إلى ضبط موضعه أو اتجاهه لاستقبال معظم القنوات، وللحصول على أفضل النتائج، ضعه عاليًا بالقرب من النافذة."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"سيؤدي هذا إلى إزالة القنوات الموجودة من موالف الشبكة وإعادة المسح بحثًا عن القنوات الجديدة.\n\nتحقق من تشغيل موالف الشبكة وتوصيله بمصدر إشارة التلفزيون.\n\nفي حالة استخدام هوائي للتحديث عبر الهواء، قد تحتاج إلى ضبط موضعه أو تجاهه لاستقبال معظم القنوات. وللحصول على أفضل النتائج، يمكنك وضعه في مكان مرتفع أو بالقرب من النافذة."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"متابعة"</item>
+ <item msgid="235450158666155406">"إلغاء"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"تحديد نوع الاتصال"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"اختر \"الهوائي\" في حالة توصيل هوائي خارجي بالموالف، واختر \"الكابل\" إذا كان مصدر القنوات هو مقدم خدمة عبر الكابل، أما إذا لم تكن متأكدًا، فسيتم البحث عن القنوات من خلال هذين النوعين، إلا أن هذا قد يستغرق وقتًا أطول."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"الهوائي"</item>
+ <item msgid="2670079958754180142">"الكابل"</item>
+ <item msgid="36774059871728525">"لست متأكدًا"</item>
+ <item msgid="6881204453182153978">"للتطوير فقط"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"إعداد موالف التلفزيون"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"‏إعداد موالف قنوات USB"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"إعداد موالف قناة الشبكة"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"قد يستغرق هذا عدة دقائق"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"لا يتوفر الموالف مؤقتًا أو سبق استخدامه بواسطة التسجيل."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="zero">‏تم العثور على %1$d قناة</item>
+ <item quantity="two">‏تم العثور على قناتين (%1$d)</item>
+ <item quantity="few">‏تم العثور على %1$d قنوات</item>
+ <item quantity="many">‏تم العثور على %1$d قناة</item>
+ <item quantity="other">‏تم العثور على %1$d قناة</item>
+ <item quantity="one">‏تم العثور على %1$d قناة</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"إيقاف البحث عن القنوات"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="zero">‏تم العثور على %1$d قناة</item>
+ <item quantity="two">‏تم العثور على قناتين (%1$d)</item>
+ <item quantity="few">‏تم العثور على %1$d قنوات</item>
+ <item quantity="many">‏تم العثور على %1$d قناة</item>
+ <item quantity="other">‏تم العثور على %1$d قناة</item>
+ <item quantity="one">‏تم العثور على %1$d قناة</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="zero">‏جيد! تم العثور على %1$d قناة أثناء البحث عن القنوات. إذا كان ذلك لا يبدو صحيحًا، فجرِّب ضبط موضع الهوائي وإعادة البحث.</item>
+ <item quantity="two">‏جيد! تم العثور على قناتين (%1$d) أثناء البحث عن القنوات. إذا كان ذلك لا يبدو صحيحًا، فجرِّب ضبط موضع الهوائي وإعادة البحث.</item>
+ <item quantity="few">‏جيد! تم العثور على %1$d قنوات أثناء البحث عن القنوات. إذا كان ذلك لا يبدو صحيحًا، فجرِّب ضبط موضع الهوائي وإعادة البحث.</item>
+ <item quantity="many">‏جيد! تم العثور على %1$d قناة أثناء البحث عن القنوات. إذا كان ذلك لا يبدو صحيحًا، فجرِّب ضبط موضع الهوائي وإعادة البحث.</item>
+ <item quantity="other">‏جيد! تم العثور على %1$d قناة أثناء البحث عن القنوات. إذا كان ذلك لا يبدو صحيحًا، فجرِّب ضبط موضع الهوائي وإعادة البحث.</item>
+ <item quantity="one">‏جيد! تم العثور على %1$d قناة أثناء البحث عن القنوات. إذا كان ذلك لا يبدو صحيحًا، فجرِّب ضبط موضع الهوائي وإعادة البحث.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"تم"</item>
+ <item msgid="2480490326672924828">"بحث مرة أخرى"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"لم يتم العثور على قنوات"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"لم يتم العثور على أي قنوات أثناء البحث، لذا عليك التحقق من توصيل التلفزيون بمصدر إشارة البث التلفزيوني.\n\nإذا كنت تستخدم هوائيًا للتحديث عبر الهواء، فاضبط موضعه أو اتجاهه، وللحصول على أفضل النتائج، ضعه عاليًا بالقرب من النافذة ثم أعد البحث."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"‏لم يتم العثور على أي قنوات أثناء البحث، تحقق من توصيل الموالف عبر USB بمصدر إشارة البث التلفزيوني.\n\nإذا كنت تستخدم هوائيًا للتحديث عبر الهواء، فاضبط موضعه أو اتجاهه، وللحصول على أفضل النتائج، ضعه عاليًا بالقرب من النافذة ثم أعد البحث."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"لم يتم العثور على أي قنوات خلال المسح. تحقق من تشغيل موالف الشبكة وتوصيله بمصدر إشارة التلفزيون.\n\nفي حالة استخدام هوائي للتحديث عبر الهواء، يجب ضبط موضعه أو تجاهه. وللحصول على أفضل النتائج، يمكنك وضعه في مكان مرتفع أو بالقرب من النافذة وإعادة المسح."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"بحث مرة أخرى"</item>
+ <item msgid="2092797862490235174">"تم"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"البحث عن قنوات تلفزيونية"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"إعداد موالف التلفزيون"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"‏إعداد موالف التلفزيون عبر USB"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"إعداد موالف التلفزيون على الشبكة"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"‏تم فصل موالف التلفزيون عبر USB."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"تم فصل موالف الشبكة."</string>
+</resources>
diff --git a/usbtuner-res/values-az-rAZ/strings.xml b/usbtuner-res/values-az-rAZ/strings.xml
new file mode 100644
index 00000000..2022ad7b
--- /dev/null
+++ b/usbtuner-res/values-az-rAZ/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"TV Kökləyici"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB TV Kökləyici"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Network TV Tuner (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Lütfən, prosesi başa çatdırmaq üçün gözləyin"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Sazlayıcı proqram təminatı yenicə güncəllənib. Kanalları yenidən skan edin."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Audionu aktiv etmək üçün sistem səs ayarlarında əhatəli səsi aktiv edin"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Audio oxuna bilmir. Digər TV-dən istifadə edin"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Kanal kökləyici quraşdırması"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"TV Kökləyici quraşdırması"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB Kanal kökləyici quraşdırması"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Şəbəkə kökləyici quraşdırması"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"TV-nizin TV siqnal mənbəyinə qoşulu olduğunu doğrulayın.\n\nHava antenası istifadə etdikdə, daha çox kanal üçün onun yerini və istiqamətini tənzimləməlisiniz. Daha yaxşı nəticələr üçün hündür yerə və pəncərəyə yaxın yerləşdirin."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"USB kökləyicinin taxılı olduğunu və TV siqnal mənbəyinə qoşulu olduğunu doğrulayın.\n\nHava antenası istifadə etdikdə, daha çox kanal üçün onun yerini və istiqamətini tənzimləməlisiniz. Daha yaxşı nəticələr üçün hündür yerə və pəncərəyə yaxın yerləşdirin."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Şəbəkə kökləyicinin yanılı olduğunu və TV siqnal mənbəyinə qoşulu olduğunu doğrulayın.\n\nHava antenası istifadə etdikdə, daha çox kanal üçün onun yerini və istiqamətini tənzimləməlisiniz. Daha yaxşı nəticələr üçün hündür yerə və pəncərəyə yaxın yerləşdirin."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Davam edin"</item>
+ <item msgid="727245208787621142">"İndi yox"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Kanal quraşdırması yenidən işə salınsın?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Bu, TV kökləyici ilə tapılmış kanalları siləcək və yeni kanalları yenidən skan edəcək.\n\nTV-nizin TV siqnal mənbəyinə qoşulu olduğunu doğrulayın.\n\nHava antenası istifadə etdikdə, daha çox kanal üçün onun yerini və istiqamətini tənzimləməlisiniz. Daha yaxşı nəticələr üçün hündür yerə və pəncərəyə yaxın yerləşdirin."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Bu USB kökləyici ilə tapılmış kanalları siləcək və yeni kanalları yenidən skan edəcək.\n\nUSB kökləyicinin taxılı olduğunu və TV siqnal mənbəyinə qoşulu olduğunu doğrulayın.\n\nHava antenası istifadə etdikdə, daha çox kanal üçün onun yerini və istiqamətini tənzimləməlisiniz. Daha yaxşı nəticələr üçün hündür yerə və pəncərəyə yaxın yerləşdirin."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Bu Şəbəkə kökləyici ilə tapılmış kanalları siləcək və yeni kanalları yenidən skan edəcək.\n\nŞəbəkə kökləyicinin yanılı olduğunu və TV siqnal mənbəyinə qoşulu olduğunu doğrulayın.\n\nHava antenası istifadə etdikdə, daha çox kanal üçün onun yerini və istiqamətini tənzimləməlisiniz. Daha yaxşı nəticələr üçün hündür yerə və pəncərəyə yaxın yerləşdirin."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Davam edin"</item>
+ <item msgid="235450158666155406">"Ləğv edin"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Bağlantı növünü seçin"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Əgər kökləyiciyə xarici antena qoşulubsa Antena seçimini edin. Əgər kanallar kabel xidməti provayderi ilə gəlirsə, onda Kabel seçimini edin. Əgər əmin deyilsinizsə, hər iki növ skan ediləcək, amma bu çox vaxt çəkəcək."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antena"</item>
+ <item msgid="2670079958754180142">"Kabel"</item>
+ <item msgid="36774059871728525">"Əmin deyiləm"</item>
+ <item msgid="6881204453182153978">"Yalnız inkişaf"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"TV kökləyici quraşdırması"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB Kanal kökləyici quraşdırması"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Şəbəkə kanalı kökləyici quraşdırması"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Bu bir neçə dəqiqə çəkə bilər"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Kökləyici müvəqqəti əlçatan deyil və qeydə alma tərəfindən istifadə olunub."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">%1$d kanal tapıldı</item>
+ <item quantity="one">%1$d kanal tapıldı</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"KANAL SKANINI DAYANDIRIN"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">%1$d kanal tapıldı</item>
+ <item quantity="one">%1$d kanal tapıldı</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Yaxşıdır! Kanal skanı zamanı %1$d kanal tapıldı. Əgər düzgün deyilsə, antenanın yerini dəyişin və yenidən skan edin.</item>
+ <item quantity="one">Yaxşıdır! Kanal skanı zamanı %1$d kanal tapıldı. Əgər düzgün deyilsə, antenanın yerini dəyişin və yenidən skan edin.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Hazırdır"</item>
+ <item msgid="2480490326672924828">"Yenidən skan edin"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Kanal tapılmadı"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Skan ilə heç bir kanal tapılmadı. TV-nizin TV siqnal mənbəyinə qoşulu olduğunu doğrulayın.\n\nHava antenası istifadə etdikdə, daha çox kanal üçün onun yerini və istiqamətini tənzimləməlisiniz. Daha yaxşı nəticələr üçün hündür yerə və pəncərəyə yaxın yerləşdirin."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Skan ilə heç bir kanal tapılmadı. USB kökləyicinin taxılı olduğunu və TV siqnal mənbəyinə qoşulu olduğunu doğrulayın.\n\nHava antenası istifadə etdikdə, daha çox kanal üçün onun yerini və istiqamətini tənzimləməlisiniz. Daha yaxşı nəticələr üçün hündür yerə və pəncərəyə yaxın yerləşdirin."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Skan ilə heç bir kanal tapılmadı. Şəbəkə kökləyicinin yanılı olduğunu və TV siqnal mənbəyinə qoşulu olduğunu doğrulayın.\n\nHava antenası istifadə etdikdə, daha çox kanal üçün onun yerini və istiqamətini tənzimləməlisiniz. Daha yaxşı nəticələr üçün hündür yerə və pəncərəyə yaxın yerləşdirin."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Yenidən skan edin"</item>
+ <item msgid="2092797862490235174">"Hazırdır"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"TV kanalları üçün skan"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"TV Kökləyici quraşdırması"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB TV Kökləyici quraşdırması"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Şəbəkə TV Kökləyici quraşdırması"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB TV kökləyicisinin bağlantısı kəsildi."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Şəbəkə kökləyicisinin bağlantısı kəsildi."</string>
+</resources>
diff --git a/usbtuner-res/values-bg/strings.xml b/usbtuner-res/values-bg/strings.xml
new file mode 100644
index 00000000..996023ff
--- /dev/null
+++ b/usbtuner-res/values-bg/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Телевизионен тунер"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"Телевизионен USB тунер"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Network TV Tuner (БЕТА)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Моля, изчакайте обработването да завърши"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Софтуерът на тунера е актуализиран наскоро. Моля, сканирайте отново каналите."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Активирайте обемния звук от настройките за системния, за да включите аудиото"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Звукът не може да се възпроизведе. Моля, опитайте на друг телевизор"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Настройване на тунера за канали"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Настройване на телевизионния тунер"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Настройване на USB тунера за канали"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Настройване на мрежовия тунер"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Уверете се, че телевизорът ви е свързан с източник на телевизионен сигнал.\n\nАко използвате безжична антена, може да се наложи да коригирате разположението или посоката й, за да получите оптимален брой канали. За най-добри резултати я поставете високо и близо до прозорец."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Уверете се, че USB тунерът е включен и свързан с източник на телевизионен сигнал.\n\nАко използвате безжична антена, може да се наложи да коригирате разположението или посоката й, за да получите оптимален брой канали. За най-добри резултати я поставете високо и близо до прозорец."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Уверете се, че мрежовият тунер е включен и свързан с източник на телевизионен сигнал.\n\nАко използвате безжична антена, може да се наложи да коригирате разположението или посоката й, за да уловите най-много канали. За най-добри резултати я поставете високо и близо до прозорец."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Напред"</item>
+ <item msgid="727245208787621142">"Не сега"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Да се стартира ли отново настройването на каналите?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Така ще премахнете намерените от телевизионния тунер канали и ще сканирате за нови.\n\nУверете се, че телевизорът ви е свързан с източник на телевизионен сигнал.\n\nАко използвате безжична антена, може да се наложи да коригирате разположението или посоката й, за да получите оптимален брой канали. За най-добри резултати я поставете високо и близо до прозорец."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Така ще премахнете намерените от USB тунера канали и ще сканирате за нови.\n\nУверете се, че USB тунерът е включен и свързан с източник на телевизионен сигнал.\n\nАко използвате безжична антена, може да се наложи да коригирате разположението или посоката й, за да получите оптимален брой канали. За най-добри резултати я поставете високо и близо до прозорец."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Така ще премахнете намерените от мрежовия тунер канали и ще сканирате за нови.\n\nУверете се, че мрежовият тунер е включен и свързан с източник на телевизионен сигнал.\n\nАко използвате безжична антена, може да се наложи да коригирате разположението или посоката й, за да уловите най-много канали. За най-добри резултати я поставете високо и близо до прозорец."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Напред"</item>
+ <item msgid="235450158666155406">"Отказ"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Избиране на типа връзка"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Изберете „Антена“, ако с тунера е свързана външна антена. Посочете „Кабел“, ако източникът на каналите ви е доставчик на кабелна услуга. В случай че не сте сигурни, ще се сканира и за двата типа, но това може да отнеме по-дълго време."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Антена"</item>
+ <item msgid="2670079958754180142">"Кабел"</item>
+ <item msgid="36774059871728525">"Не знам"</item>
+ <item msgid="6881204453182153978">"Само програмиране"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Настройване на телевизионния тунер"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Настройване на USB тунера за канали"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Настройване на мрежовия тунер за канали"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Това може да отнеме няколко минути"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Временно няма достъп до тунера или той вече се използва за запис."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">Намерени са %1$d канала</item>
+ <item quantity="one">Намерен е %1$d канал</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"СПИРАНЕ НА СКАНИРАНЕТО ЗА КАНАЛИ"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">Намерени са %1$d канала</item>
+ <item quantity="one">Намерен е %1$d канал</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Много добре! По време на сканирането бяха намерени %1$d канала. Ако това не изглежда вярно, коригирайте позицията на антената и сканирайте отново.</item>
+ <item quantity="one">Много добре! По време на сканирането бе намерен %1$d канал. Ако това не изглежда вярно, коригирайте позицията на антената и сканирайте отново.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Готово"</item>
+ <item msgid="2480490326672924828">"Повторно сканиране"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Няма намерени канали"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"При сканирането не бяха открити канали. Уверете се, че телевизорът ви е свързан с източник на телевизионен сигнал.\n\nАко използвате безжична антена, коригирайте разположението или посоката й. За най-добри резултати я поставете високо и близо до прозорец и сканирайте отново."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"При сканирането не бяха открити канали. Уверете се, че USB тунерът е включен и свързан с източник на телевизионен сигнал.\n\nАко използвате безжична антена, коригирайте разположението или посоката й. За най-добри резултати я поставете високо и близо до прозорец и сканирайте отново."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"При сканирането не бяха открити канали. Уверете се, че мрежовият тунер е включен и свързан с източник на телевизионен сигнал.\n\nАко използвате безжична антена, коригирайте разположението или посоката й. За най-добри резултати я поставете високо и близо до прозорец и сканирайте отново."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Повторно сканиране"</item>
+ <item msgid="2092797862490235174">"Готово"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Сканиране за телевизионни канали"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Настройване на телевизионния тунер"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Настройване на телевизионния USB тунер"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Настройване на Network TV Tuner"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"Връзката с телевизионния USB тунер е прекратена."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Връзката с мрежовия тунер е прекратена."</string>
+</resources>
diff --git a/usbtuner-res/values-bn-rBD/strings.xml b/usbtuner-res/values-bn-rBD/strings.xml
new file mode 100644
index 00000000..8eb8a558
--- /dev/null
+++ b/usbtuner-res/values-bn-rBD/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"TV টিউনার"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB TV টিউনার"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"নেটওয়ার্ক TV টিউনার (বিটা)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"প্রক্রিয়াকরণ সম্পূর্ণ না হওয়া পর্যন্ত অনুগ্রহ করে অপেক্ষা করুন"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"টিউনার সফ্টওয়্যার সম্প্রতি আপডেট করা হয়েছে৷ অনুগ্রহ করে চ্যানেলগুলি আবার স্ক্যান করুন৷"</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"অডিও সক্ষম করতে সিস্টেম সাউন্ড সেটিংসে সারাউন্ড সাউন্ড সক্ষম করুন"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"অডিও প্লে করা যাবে না৷ অনুগ্রহ করে অন্য টিভি ব্যবহার করার চেষ্ট করুন"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"চ্যানেল টিউনার সেট আপ"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"TV টিউনার সেট আপ"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB চ্যানেল টিউনার সেটআপ"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"নেটওয়ার্ক টিউনার সেট আপ"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"আপনার TV একটি TV সিগন্যাল উৎসের সাথে সংযুক্ত রয়েছে কিনা যাচাই করুন৷\n\nযদি কোনো ওভার-দ্য-এয়ার অ্যান্টেনা ব্যবহার করা হয় তাহলে অধিকাংশ চ্যানেল পাওয়ার জন্য আপনাকে সেটির অবস্থান এবং দিক ঠিক করতে হতে পারে৷ আরো ভাল ফলাফলের জন্য, এটিকে উচুঁতে কোনো জানলার সামনে রাখুন এবং আবার স্ক্যান করুন৷"</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"USB টিউনার প্ল্যাগ ইন রয়েছে এবং একটি TV সিগন্যাল উৎসের সাথে সংযুক্ত রয়েছে তা যাচাই করুন৷\n\nযদি কোনো ওভার-দ্য-এয়ার অ্যান্টেনা ব্যবহার করা হয় তাহলে অধিকাংশ চ্যানেল পাওয়ার জন্য আপনাকে সেটির অবস্থান এবং দিক ঠিক করতে হতে পারে৷ আরো ভাল ফলাফলের জন্য, এটিকে উচুঁতে কোনো জানলার সামনে রাখুন এবং আবার স্ক্যান করুন৷"</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"নেটওয়ার্ক টিউনার চালু রয়েছে এবং কোনো TV সিগন্যাল উৎসের সাথে সংযুক্ত রয়েছে কিনা যাচাই করুন৷\n\nযদি কোনো ওভার-দ্য-এয়ার অ্যান্টেনা ব্যবহার করা হয় তাহলে অধিকাংশ চ্যানেল পাওয়ার জন্য আপনাকে সেটির অবস্থান এবং দিক ঠিক করতে হতে পারে৷ আরো ভাল ফলাফলের জন্য, এটিকে উঁচুতে কোনো জানলার সামনে রেখে আবার স্ক্যান করুন৷"</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"চালিয়ে যান"</item>
+ <item msgid="727245208787621142">"এখনই নয়"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"আবার চ্যানেল সেট আপ করবেন?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"এটি TV টিউনার থেকে পাওয়া চ্যানেলগুলিকে মুছবে এবং নতুন চ্যানেলগুলির জন্য আবার স্ক্যান করবে৷\n\nআপনার TV একটি TV সিগন্যাল উৎসের সাথে সংযুক্ত রয়েছে কিনা যাচাই করুন৷\n\nযদি কোনো ওভার-দ্য-এয়ার অ্যান্টেনা ব্যবহার করা হয় তাহলে অধিকাংশ চ্যানেল পাওয়ার জন্য আপনাকে সেটির অবস্থান এবং দিক ঠিক করতে হতে পারে৷ আরো ভাল ফলাফলের জন্য, এটিকে উচুঁতে কোনো জানলার সামনে রাখুন এবং আবার স্ক্যান করুন৷"</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"এটি USB টিউনার থেকে পাওয়া চ্যানেলগুলিকে মুছবে এবং নতুন চ্যানেলগুলির জন্য আবার স্ক্যান করবে৷\n\nUSB টিউনার প্ল্যাগ ইন রয়েছে এবং একটি TV সিগন্যাল উৎসের সাথে সংযুক্ত রয়েছে তা যাচাই করুন৷\n\nযদি কোনো ওভার-দ্য-এয়ার অ্যান্টেনা ব্যবহার করা হয় তাহলে অধিকাংশ চ্যানেল পাওয়ার জন্য আপনাকে সেটির অবস্থান এবং দিক ঠিক করতে হতে পারে৷ আরো ভাল ফলাফলের জন্য, এটিকে উচুঁতে কোনো জানলার সামনে রাখুন এবং আবার স্ক্যান করুন৷"</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"এটি নেটওয়ার্ক টিউনার থেকে পাওয়া চ্যানেলগুলি মুছবে এবং নতুন চ্যানেলগুলিকে আবার স্ক্যান করবে৷\n\nনেটওয়ার্ক টিউনার চালু রয়েছে এবং কোনো TV সিগন্যাল উৎসের সাথে সংযুক্ত রয়েছে কিনা যাচাই করুন৷\n\nযদি কোনো ওভার-দ্য-এয়ার অ্যান্টেনা ব্যবহার করা হয় তাহলে অধিকাংশ চ্যানেল পাওয়ার জন্য আপনাকে সেটির অবস্থান এবং দিক ঠিক করতে হতে পারে৷ আরো ভাল ফলাফলের জন্য, এটিকে উঁচুতে কোনো জানলার সামনে রেখে আবার স্ক্যান করুন৷"</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"চালিয়ে যান"</item>
+ <item msgid="235450158666155406">"বাতিল করুন"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"সংযোগের প্রকার নির্বাচন করুন"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"যদি আপনার টিউনারের সাথে কোনো বাহ্যিক অ্যান্টেনা সংযুক্ত থাকে তাহলে অ্যান্টেনা বাছুন৷ আপনার চ্যানেলগুলি যদি কোনো কেবল পরিষেবা প্রদানকারীর থেকে আসে তাহলে কেবল বাছুন৷ আপনি যদি নিশ্চিত না হন তাহলে উভয় প্রকারের স্ক্যান করা হবে, কিন্তু এটি অনেক সময় নিতে পারে৷"</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"অ্যান্টেনা"</item>
+ <item msgid="2670079958754180142">"কেবল"</item>
+ <item msgid="36774059871728525">"নিশ্চিত নই"</item>
+ <item msgid="6881204453182153978">"শুধুমাত্র বিকাশের উদ্দেশ্য"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"TV টিউনার সেট আপ"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB চ্যানেল টিউনার সেটআপ"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"নেটওয়ার্ক চ্যানেল টিউনার সেটআপ"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"এটি কয়েক মিনিট সময় নিতে পারে"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"টিউনার অস্থায়ীভাবে অনুপলব্ধ বা রেকডিংয়ে ইতিমধ্যেই ব্যবহৃত হয়েছে৷"</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="one">%1$dটি চ্যানেল পাওয়া গেছে</item>
+ <item quantity="other">%1$dটি চ্যানেল পাওয়া গেছে</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"চ্যানেল স্ক্যান করা থামান"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="one">%1$dটি চ্যানেল পাওয়া গেছে</item>
+ <item quantity="other">%1$dটি চ্যানেল পাওয়া গেছে</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="one">সুন্দর! চ্যানেল স্ক্যান করার সময়ে %1$dটি চ্যানেল পাওয়া গেছে। এটিকে যদি ঠিক বলে না মনে হয়, তাহলে অ্যান্টেনার অবস্থান ঠিক করার চেষ্টা করুন ও আবার স্ক্যান করুন।</item>
+ <item quantity="other">সুন্দর! চ্যানেল স্ক্যান করার সময়ে %1$dটি চ্যানেল পাওয়া গেছে। এটিকে যদি ঠিক বলে না মনে হয়, তাহলে অ্যান্টেনার অবস্থান ঠিক করার চেষ্টা করুন ও আবার স্ক্যান করুন।</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"সম্পন্ন"</item>
+ <item msgid="2480490326672924828">"আবার স্ক্যান করুন"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"কোনো চ্যানেল খুঁজে পাওয়া যায়নি"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"স্ক্যান করে কোনো চ্যানেল খুঁজে পাওয়া যায়নি৷ আপনার TV একটি TV সিগন্যাল উৎসের সাথে সংযুক্ত রয়েছে কিনা যাচাই করুন৷\n\nযদি কোনো ওভার-দ্য-এয়ার অ্যান্টেনা ব্যবহার করা হয় তাহলে সেটির অবস্থান এবং দিক ঠিক করুন৷ আরো ভাল ফলাফলের জন্য, এটিকে উচুঁতে কোনো জানলার সামনে রাখুন এবং আবার স্ক্যান করুন৷"</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"স্ক্যান করে কোনো চ্যানেল খুঁজে পাওয়া যায়নি৷ USB টিউনার প্ল্যাগ ইন রয়েছে এবং একটি TV সিগন্যাল উৎসের সাথে সংযুক্ত রয়েছে তা যাচাই করুন৷\n\nযদি কোনো ওভার-দ্য-এয়ার অ্যান্টেনা ব্যবহার করা হয় তাহলে সেটির অবস্থান এবং দিক ঠিক করুন৷ আরো ভাল ফলাফলের জন্য, এটিকে উচুঁতে কোনো জানলার সামনে রাখুন এবং আবার স্ক্যান করুন৷"</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"স্ক্যান করে কোনো চ্যানেল খুঁজে পাওয়া যায়নি৷ নেটওয়ার্ক টিউনার চালু এবং কোনো TV সিগন্যাল উৎসের সাথে সংযুক্ত রয়েছে কিনা যাচাই করুন৷\n\nযদি কোনো ওভার-দ্য-এয়ার অ্যান্টেনা ব্যবহার করা হয় তাহলে সেটির অবস্থান এবং দিক ঠিক করুন৷ আরো ভাল ফলাফলের জন্য, এটিকে উঁচুতে কোনো জানলার সামনে রেখে আবার স্ক্যান করুন৷"</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"আবার স্ক্যান করুন"</item>
+ <item msgid="2092797862490235174">"সম্পন্ন"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"টিভি চ্যানেলগুলি স্ক্যান করুন"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"TV টিউনার সেট আপ"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB টিভি টিউনার সেট আপ"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"নেটওয়ার্ক TV টিউনার সেট আপ"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB টিভি টিউনারের সংযোগ বিচ্ছিন্ন হয়েছে।"</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"নেটওয়ার্ক টিউনারের সংযোগ বিচ্ছিন্ন হয়েছে।"</string>
+</resources>
diff --git a/usbtuner-res/values-ca/strings.xml b/usbtuner-res/values-ca/strings.xml
new file mode 100644
index 00000000..d005204e
--- /dev/null
+++ b/usbtuner-res/values-ca/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Sintonitzador de televisió"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"Sintonitzador de televisió USB"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Sintonitzador de televisió en xarxa (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Espera per finalitzar el processament"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"El programari del sintonitzador s\'ha actualitzat fa poc. Torna a cercar els canals."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Activa el so envoltant a la configuració de so del sistema per activar l\'àudio"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"No es pot reproduir l\'àudio. Prova-ho amb un altre televisor."</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Configuració del sintonitzador de canals"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Configuració del sintonitzador de televisió"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Configuració del sintonitzador de canals USB"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Configuració del sintonitzador en xarxa"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Verifica que el teu televisor estigui connectat a una font de senyal de televisió.\n\nSi fas servir una antena aèria, pot ser que calgui ajustar-ne la ubicació o la direcció per rebre el màxim de canals. Per obtenir els millors resultats, col·loca-la en un lloc elevat i a prop d\'una finestra."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Verifica que el sintonitzador USB estigui endollat i connectat a una font de senyal de televisió.\n\nSi fas servir una antena aèria, pot ser que calgui ajustar-ne la ubicació o la direcció per rebre el màxim de canals. Per obtenir els millors resultats, col·loca-la en un lloc elevat i a prop d\'una finestra."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Comprova que el sintonitzador en xarxa estigui engegat i connectat a una font de senyal de televisió.\n\nSi fas servir una antena aèria, pot ser que calgui ajustar-ne la ubicació o la direcció per rebre el màxim de canals. Per obtenir uns resultats millors, col·loca-la en un lloc elevat i a prop d\'una finestra."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Continua"</item>
+ <item msgid="727245208787621142">"Ara no"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Vols tornar a executar la configuració de canals?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Això farà que se suprimeixin del sintonitzador de televisió els canals que s\'han trobat i que es tornin a cercar canals nous.\n\nVerifica que el teu televisor estigui connectat a una font de senyal de televisió.\n\nSi fas servir una antena aèria, pot ser que calgui ajustar-ne la ubicació o la direcció per rebre el màxim de canals. Per obtenir els millors resultats, col·loca-la en un lloc elevat i a prop d\'una finestra."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Això farà que se suprimeixin del sintonitzador USB els canals que s\'han trobat i que es tornin a cercar canals nous.\n\nVerifica que el sintonitzador USB estigui endollat i connectat a una font de senyal de televisió.\n\nSi fas servir una antena aèria, pot ser que calgui ajustar-ne la ubicació o la direcció per rebre el màxim de canals. Per obtenir els millors resultats, col·loca-la en un lloc elevat i a prop d\'una finestra."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Això farà que se suprimeixin del sintonitzador en xarxa els canals trobats i que se\'n tornin a cercar de nous.\n\nComprova que el sintonitzador en xarxa estigui engegat i connectat a una font de senyal de televisió.\n\nSi fas servir una antena aèria, pot ser que calgui ajustar-ne la ubicació o la direcció per rebre el màxim de canals. Per obtenir uns resultats millors, col·loca-la en un lloc elevat i a prop d\'una finestra."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Continua"</item>
+ <item msgid="235450158666155406">"Cancel·la"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Selecciona el tipus de connexió"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Tria Antena si hi ha una antena externa connectada al sintonitzador. Tria Cable si els canals provenen d\'un proveïdor de serveis per cable. Si no n\'estàs segur, se cercaran els dos tipus de canals, però el procés pot trigar més."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antena"</item>
+ <item msgid="2670079958754180142">"Cable"</item>
+ <item msgid="36774059871728525">"No ho sé"</item>
+ <item msgid="6881204453182153978">"Només per a desenvolupament"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Configuració del sintonitzador de televisió"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Configuració del sintonitzador de canals USB"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Configuració del sintonitzador de canals en xarxa"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Aquesta acció pot tardar uns quants minuts"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"El sintonitzador no està disponible en aquest moment o bé ja s\'està utilitzant en un enregistrament."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">S\'han trobat %1$d canals</item>
+ <item quantity="one">S\'ha trobat %1$d canal</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"ATURA LA CERCA DE CANALS"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">S\'han trobat %1$d canals</item>
+ <item quantity="one">S\'ha trobat %1$d canal</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Molt bé! S\'han trobat %1$d canals durant la cerca. Si creus que no és correcte, prova d\'ajustar la posició de l\'antena i torna a cercar canals.</item>
+ <item quantity="one">Molt bé! S\'ha trobat %1$d canal durant la cerca. Si creus que no és correcte, prova d\'ajustar la posició de l\'antena i torna a cercar canals.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Fet"</item>
+ <item msgid="2480490326672924828">"Torna a cercar"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"No s\'ha trobat cap canal"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"No s\'ha trobat cap canal. Verifica que el teu televisor estigui connectat a una font de senyal de televisió.\n\nSi fas servir una antena aèria, ajusta\'n la ubicació o la direcció. Per obtenir els millors resultats, col·loca-la en un lloc elevat i a prop d\'una finestra i torna a cercar canals."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"La cerca no ha trobat cap canal. Verifica que el sintonitzador USB estigui endollat i connectat a una font de senyal de televisió.\n\nSi fas servir una antena aèria, ajusta\'n la ubicació o la direcció. Per obtenir els millors resultats, col·loca-la en un lloc elevat i a prop d\'una finestra i torna a cercar."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"No s\'ha trobat cap canal. Comprova que el sintonitzador en xarxa estigui engegat i connectat a una font de senyal de televisió.\n\nSi fas servir una antena aèria, ajusta\'n la ubicació o la direcció. Per obtenir uns resultats millors, col·loca-la en un lloc elevat i a prop d\'una finestra i torna a cercar."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Torna a cercar"</item>
+ <item msgid="2092797862490235174">"Fet"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Cerca canals de televisió"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Configuració del sintonitzador de televisió"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Configuració del sintonitzador de televisió USB"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Configuració del sintonitzador de televisió en xarxa"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"El sintonitzador de televisió USB no està connectat."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"El sintonitzador de la xarxa no està connectat."</string>
+</resources>
diff --git a/usbtuner-res/values-cs/strings.xml b/usbtuner-res/values-cs/strings.xml
new file mode 100644
index 00000000..69436042
--- /dev/null
+++ b/usbtuner-res/values-cs/strings.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Televizní tuner"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"Televizní tuner USB"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Síťový televizní tuner (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Vyčkejte prosím, než bude zpracování dokončeno"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Software tuneru byl nedávno aktualizován. Vyhledejte prosím kanály znovu."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Chcete-li zapnout zvuk, v nastavení systémového zvuku povolte prostorový zvuk"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Zvuk nelze přehrát. Zkuste použít jinou televizi."</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Nastavení tuneru kanálů"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Nastavení televizního tuneru"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Nastavení tuneru kanálů USB"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Nastavení síťového tuneru"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Zkontrolujte, zda je televize připojena ke zdroji televizního signálu.\n\nPokud používáte bezdrátovou anténu, možná budete muset za účelem příjmu co největšího počtu kanálů upravit její umístění nebo nasměrování. Nejlepších výsledků dosáhnete, pokud ji umístíte vysoko a blízko okna."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Zkontrolujte, zda je tuner USB připojen k zařízení a ke zdroji televizního signálu.\n\nPokud používáte bezdrátovou anténu, možná budete muset za účelem příjmu co největšího počtu kanálů upravit její umístění nebo nasměrování. Nejlepších výsledků dosáhnete, pokud ji umístíte vysoko a blízko okna."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Zkontrolujte, zda je síťový tuner zapnut a připojen ke zdroji televizního signálu.\n\nPokud používáte bezdrátovou anténu, možná budete muset za účelem příjmu co největšího počtu kanálů upravit její umístění nebo nasměrování. Nejlepších výsledků dosáhnete, pokud ji umístíte vysoko a blízko okna."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Pokračovat"</item>
+ <item msgid="727245208787621142">"Teď ne"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Znovu spustit nastavení kanálů?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Tímto odstraníte kanály nalezené pomocí televizního tuneru a znovu vyhledáte nové kanály.\n\nZkontrolujte, zda je televize připojena ke zdroji televizního signálu.\n\nPokud používáte bezdrátovou anténu, možná budete muset za účelem příjmu co největšího počtu kanálů upravit její umístění nebo nasměrování. Nejlepších výsledků dosáhnete, pokud ji umístíte vysoko a blízko okna."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Tímto odstraníte kanály nalezené pomocí tuneru USB a znovu vyhledáte nové kanály.\n\nZkontrolujte, zda je tuner USB připojen k zařízení a ke zdroji televizního signálu.\n\nPokud používáte bezdrátovou anténu, možná budete muset za účelem příjmu co největšího počtu kanálů upravit její umístění nebo nasměrování. Nejlepších výsledků dosáhnete, pokud ji umístíte vysoko a blízko okna."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Tímto odstraníte kanály nalezené pomocí síťového tuneru a znovu vyhledáte nové kanály.\n\nZkontrolujte, zda je síťový tuner zapnut a připojen ke zdroji televizního signálu.\n\nPokud používáte bezdrátovou anténu, možná budete muset za účelem příjmu co největšího počtu kanálů upravit její umístění nebo nasměrování. Nejlepších výsledků dosáhnete, pokud ji umístíte vysoko a blízko okna."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Pokračovat"</item>
+ <item msgid="235450158666155406">"Zrušit"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Vyberte typ připojení"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Pokud je k tuneru připojena externí anténa, zvolte možnost Anténa. Pokud je zdrojem kanálů poskytovatel kabelových služeb, zvolte možnost Kabel. Pokud si nejste jisti, budou prohledány oba typy. Může to však trvat déle."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Anténa"</item>
+ <item msgid="2670079958754180142">"Kabel"</item>
+ <item msgid="36774059871728525">"Nevím"</item>
+ <item msgid="6881204453182153978">"Pouze pro vývojáře"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Nastavení televizního tuneru"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Nastavení tuneru kanálů USB"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Nastavení kanálů síťového tuneru"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Tato akce může trvat několik minut."</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Tuner dočasně není k dispozici, případně je právě používán k nahrávání."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="few">Byly nalezeny %1$d kanály</item>
+ <item quantity="many">Bylo nalezeno %1$d kanálu</item>
+ <item quantity="other">Bylo nalezeno %1$d kanálů</item>
+ <item quantity="one">Byl nalezen %1$d kanál</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"ZASTAVIT VYHLEDÁVÁNÍ KANÁLŮ"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="few">Byly nalezeny %1$d kanály</item>
+ <item quantity="many">Bylo nalezeno %1$d kanálu</item>
+ <item quantity="other">Bylo nalezeno %1$d kanálů</item>
+ <item quantity="one">Byl nalezen %1$d kanál</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="few">Skvělé! Při vyhledávání byly nalezeny %1$d kanály. Pokud vám to nepřipadá správně, zkuste upravit pozici antény a provést vyhledávání znovu.</item>
+ <item quantity="many">Skvělé! Při vyhledávání bylo nalezeno %1$d kanálu. Pokud vám to nepřipadá správně, zkuste upravit pozici antény a provést vyhledávání znovu.</item>
+ <item quantity="other">Skvělé! Při vyhledávání bylo nalezeno %1$d kanálů. Pokud vám to nepřipadá správně, zkuste upravit pozici antény a provést vyhledávání znovu.</item>
+ <item quantity="one">Skvělé! Při vyhledávání byl nalezen %1$d kanál. Pokud vám to nepřipadá správně, zkuste upravit pozici antény a provést vyhledávání znovu.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Hotovo"</item>
+ <item msgid="2480490326672924828">"Znovu vyhledat"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Nebyly nalezeny žádné kanály"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Při vyhledávání nebyly nalezeny žádné kanály. Zkontrolujte, zda je televize připojena ke zdroji televizního signálu.\n\nPokud používáte bezdrátovou anténu, upravte její umístění nebo nasměrování. Nejlepších výsledků dosáhnete, pokud ji umístíte vysoko a blízko okna. Poté spusťte vyhledávání znovu."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Při vyhledávání nebyly nalezeny žádné kanály. Zkontrolujte, zda je tuner USB připojen k zařízení a ke zdroji televizního signálu.\n\nPokud používáte bezdrátovou anténu, upravte její umístění nebo nasměrování. Nejlepších výsledků dosáhnete, pokud ji umístíte vysoko a blízko okna. Poté spusťte vyhledávání znovu."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Při vyhledávání nebyly nalezeny žádné kanály. Zkontrolujte, zda je síťový tuner zapnut a připojen ke zdroji televizního signálu.\n\nPokud používáte bezdrátovou anténu, upravte její umístění nebo nasměrování. Nejlepších výsledků dosáhnete, pokud ji umístíte vysoko a blízko okna. Poté spusťte vyhledávání znovu."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Znovu vyhledat"</item>
+ <item msgid="2092797862490235174">"Hotovo"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Vyhledejte televizní kanály"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Nastavení televizního tuneru"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Nastavení televizního tuneru USB"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Nastavení síťového televizního tuneru"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"Televizní tuner USB byl odpojen."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Síťový tuner byl odpojen."</string>
+</resources>
diff --git a/usbtuner-res/values-da/strings.xml b/usbtuner-res/values-da/strings.xml
new file mode 100644
index 00000000..96a902b8
--- /dev/null
+++ b/usbtuner-res/values-da/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"TV Tuner"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB-tuner til fjernsynet"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Netværkstuner til tv (beta)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Vent, mens behandlingen afsluttes"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Tunerens software er blevet opdateret for nylig. Scan efter kanalerne igen."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Aktivér surroundsound i systemets lydindstillinger for at aktivere lyd"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Der kan ikke afspilles lyd. Prøv på et andet fjernsyn"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Konfiguration af kanaltuneren"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Konfiguration med TV Tuner"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Konfiguration af USB-kanaltuneren"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Konfiguration af netværkstuner"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Tjek, at dit fjernsyn er forbundet til en tv-signalkilde.\n\nHvis du bruger en luftantenne, kan det være nødvendigt at justere dens position eller retning for at modtage flest muligt kanaler. Du opnår det bedste resultat ved at placere den højt oppe og i nærheden af et vindue."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Tjek, at USB-tuneren er tilsluttet og forbundet til en tv-signalkilde.\n\nHvis du bruger en luftantenne, kan det være nødvendigt at justere dens position eller retning for at modtage flest muligt kanaler. Du opnår det bedste resultat ved at placere den højt oppe og i nærheden af et vindue."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Tjek, at netværkstuneren er tændt og sluttet til en tv-signalkilde.\n\nHvis du bruger en luftantenne, kan det være nødvendigt at justere dens position eller retning for at modtage flest muligt kanaler. Du opnår det bedste resultat ved at placere den højt oppe og i nærheden af et vindue."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Fortsæt"</item>
+ <item msgid="727245208787621142">"Ikke nu"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Vil du gentage kanalkonfigurationen?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Dette fjerner de kanaler, som blev fundet, fra fjernsynets tuner og scanner efter nye kanaler igen.\n\nTjek, at dit fjernsyn er forbundet til en tv-signalkilde.\n\nHvis du bruger en luftantenne, kan det være nødvendigt at justere dens position eller retning for at modtage flest muligt kanaler. Du opnår det bedste resultat ved at placere den højt oppe og i nærheden af et vindue."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Denne handling fjerner de kanaler, der blev fundet af USB-tuneren, og starter en ny scanning efter kanaler.\n\nTjek, at USB-tuneren er tilsluttet og forbundet til en tv-signalkilde.\n\nHvis du bruger en luftantenne, kan det være nødvendigt at justere dens position eller retning for at modtage flest muligt kanaler. Du opnår det bedste resultat ved at placere den højt oppe og i nærheden af et vindue."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Denne handling fjerner de kanaler, der blev fundet af netværkstuneren, og starter en ny kanalsøgning.\n\nTjek, at netværkstuneren er tændt og sluttet til en tv-signalkilde.\n\nHvis du bruger en luftantenne, kan det være nødvendigt at justere dens position eller retning for at modtage flest muligt kanaler. Du opnår det bedste resultat ved at placere den højt oppe og i nærheden af et vindue."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Fortsæt"</item>
+ <item msgid="235450158666155406">"Annuller"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Vælg forbindelsestype"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Vælg Antenne, hvis en ekstern antenne er sluttet til tuneren. Vælg Kabel, hvis dine kanaler leveres via kabel af en tjenesteudbyder. Hvis du ikke er sikker, kan du scanne begge typer, men dette kan tage længere tid."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antenne"</item>
+ <item msgid="2670079958754180142">"Kabel"</item>
+ <item msgid="36774059871728525">"Jeg er ikke sikker"</item>
+ <item msgid="6881204453182153978">"Kun til udvikling"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Konfiguration med fjernsynets tuner"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Konfiguration af USB-kanaltuneren"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Konfiguration af netværkstuner til kanalsøgning"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Dette kan tage flere minutter"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Tuneren er midlertidigt utilgængelig eller benyttes allerede til en optagelse."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="one">Der blev fundet %1$d kanal</item>
+ <item quantity="other">Der blev fundet %1$d kanaler</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"STOP KANALSCANNINGEN"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="one">Der blev fundet %1$d kanal</item>
+ <item quantity="other">Der blev fundet %1$d kanaler</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="one">Sådan! Der blev fundet %1$d kanal ved kanalscanningen. Hvis du mener, det er forkert, kan du prøve at justere antennens position og scanne igen.</item>
+ <item quantity="other">Sådan! Der blev fundet %1$d kanaler ved kanalscanningen. Hvis du mener, det er forkert, kan du prøve at justere antennens position og scanne igen.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Udført"</item>
+ <item msgid="2480490326672924828">"Scan igen"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Der blev ikke fundet nogen kanaler"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Der blev ikke fundet nogen kanaler under scanningen. Tjek, at dit fjernsyn er forbundet til en tv-signalkilde.\n\nHvis du bruger en luftantenne, skal du justere dens position eller retning. Du opnår det bedste resultat ved at placere den højt oppe og i nærheden af et vindue. Scan igen."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Der blev ikke fundet nogen kanaler under scanningen. Tjek, at USB-tuneren er tilsluttet og forbundet til en tv-signalkilde.\n\nHvis du bruger en luftantenne, skal du justere dens position eller retning. Du opnår det bedste resultat ved at placere den højt oppe og i nærheden af et vindue. Scan igen."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Der blev ikke fundet nogen kanaler under søgningen. Tjek, at netværkstuneren er tændt og sluttet til en tv-signalkilde.\n\nHvis du bruger en luftantenne, skal du justere dens position eller retning. Du opnår det bedste resultat ved at placere den højt oppe og i nærheden af et vindue. Søg igen."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Scan igen"</item>
+ <item msgid="2092797862490235174">"Udført"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Søg efter tv-kanaler"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Konfiguration af tuner til fjernsynet"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Konfiguration af USB-tuner til fjernsynet"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Konfiguration af netværkstuner til fjernsynet"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB-tuneren til fjernsynet er ikke tilsluttet."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Netværkstuneren er ikke tilsluttet."</string>
+</resources>
diff --git a/usbtuner-res/values-de/strings.xml b/usbtuner-res/values-de/strings.xml
new file mode 100644
index 00000000..b0f17dfc
--- /dev/null
+++ b/usbtuner-res/values-de/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"TV-Tuner"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB-TV-Tuner"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Netzwerk-TV-Tuner (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Bitte warten Sie, bis die Verarbeitung abgeschlossen ist"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Die Tunersoftware wurde kürzlich aktualisiert. Bitte führen Sie die Kanalsuche noch einmal durch."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Aktivieren Sie in den Systemeinstellungen Surround-Sound, um Audio einschalten zu können"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Audio kann nicht wiedergegeben werden. Bitte versuch es mit einem anderen Fernseher."</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Kanaleinrichtung über den Tuner"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"TV-Tuner einrichten"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Kanaleinrichtung über den USB-Tuner"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Einrichtung des Netzwerk-Tuners"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Vergewissern Sie sich, dass Ihr Fernseher mit einer TV-Signalquelle verbunden ist.\n\nWenn Sie eine terrestrische Antenne verwenden, ändern Sie die Position oder Ausrichtung, um mehr Kanäle zu finden. Die besten Ergebnisse erhalten Sie, wenn Sie sie an eine erhöhte Position in Fensternähe stellen."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Vergewissern Sie sich, dass der USB-Tuner angeschlossen und mit einer TV-Signalquelle verbunden ist.\n\nWenn Sie eine terrestrische Antenne verwenden, ändern Sie die Position oder Ausrichtung, um mehr Kanäle zu finden. Die besten Ergebnisse erhalten Sie, wenn Sie sie an einer erhöhten Position in Fensternähe stellen."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Vergewissere dich, dass der Netzwerk-Tuner eingeschaltet und mit einer TV-Signalquelle verbunden ist.\n\nWenn du eine terrestrische Antenne verwendest, ändere die Position oder Ausrichtung, um mehr Kanäle zu empfangen. Die besten Ergebnisse erhältst du, wenn du die Antenne an eine erhöhte Position in Fensternähe stellst."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Weiter"</item>
+ <item msgid="727245208787621142">"Jetzt nicht"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Kanaleinrichtung erneut durchführen?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Dies entfernt die vom TV-Tuner gefundenen Kanäle und sucht noch einmal nach neuen Kanälen.\n\nVergewissern Sie sich, dass Ihr Fernseher mit einer TV-Signalquelle verbunden ist.\n\nWenn Sie eine terrestrische Antenne verwenden, ändern Sie die Position oder Ausrichtung, um mehr Kanäle zu finden. Die besten Ergebnisse erhalten Sie, wenn Sie sie an eine erhöhte Position in Fensternähe stellen."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Durch diese Aktion werden die gefundenen Kanäle vom USB-Tuner entfernt und die Kanalsuche wird erneut gestartet.\n\nVergewissern Sie sich, dass der USB-Tuner angeschlossen und mit einer TV-Signalquelle verbunden ist.\n\nWenn Sie eine terrestrische Antenne verwenden, ändern Sie die Position oder Ausrichtung, um mehr Kanäle zu finden. Die besten Ergebnisse erhalten Sie, wenn Sie sie an einer erhöhten Position in Fensternähe stellen."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Durch diese Aktion werden die vom Netzwerk-Tuner gefundenen Kanäle entfernt und die Kanalsuche wird neu gestartet.\n\nVergewissere dich, dass der Netzwerk-Tuner eingeschaltet und mit einer TV-Signalquelle verbunden ist.\n\nWenn du eine terrestrische Antenne verwendest, ändere die Position oder Ausrichtung, um mehr Kanäle zu empfangen. Die besten Ergebnisse erhältst du, wenn du die Antenne an eine erhöhte Position in Fensternähe stellst."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Weiter"</item>
+ <item msgid="235450158666155406">"Abbrechen"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Verbindungstyp auswählen"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Wählen Sie \"Antenne\" aus, wenn eine externe Antenne mit dem Tuner verbunden ist. Wählen Sie \"Kabel\" aus, wenn Sie Ihre Kanäle bei einem Kabel-TV-Anbieter abrufen. Wenn Sie \"Nicht sicher\" auswählen, wird nach beiden Typen gesucht. Der Vorgang dauert dann unter Umständen länger."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antenne"</item>
+ <item msgid="2670079958754180142">"Kabel"</item>
+ <item msgid="36774059871728525">"Nicht sicher"</item>
+ <item msgid="6881204453182153978">"Nur Entwicklung"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"TV-Tuner einrichten"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Kanaleinrichtung über den USB-Tuner"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Kanaleinrichtung über den Netzwerk-Tuner"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Dies kann einige Minuten dauern"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Der Tuner ist vorübergehend nicht verfügbar oder wird schon für eine Aufnahme verwendet."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">%1$d Kanäle gefunden</item>
+ <item quantity="one">%1$d Kanal gefunden</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"KANALSUCHE STOPPEN"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">%1$d Kanäle gefunden</item>
+ <item quantity="one">%1$d Kanal gefunden</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Wunderbar. Bei der Kanalsuche wurden %1$d Kanäle gefunden. Wenn Sie vermuten, dass dies nicht korrekt ist, ändern Sie die Antennenposition und versuchen Sie es noch einmal.</item>
+ <item quantity="one">Wunderbar. Bei der Kanalsuche wurde %1$d Kanal gefunden. Wenn Sie vermuten, dass dies nicht korrekt ist, ändern Sie die Antennenposition und versuchen Sie es noch einmal.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Fertig"</item>
+ <item msgid="2480490326672924828">"Noch einmal suchen"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Keine Kanäle gefunden"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Bei der Suche wurden keine Kanäle gefunden. Vergewissern Sie sich, dass Ihr Fernseher mit einer TV-Signalquelle verbunden ist.\n\nWenn Sie eine terrestrische Antenne verwenden, ändern Sie die Position oder Ausrichtung. Um die besten Ergebnisse zu erhalten, stellen Sie sie an eine erhöhte Position in Fensternähe und führen Sie die Suche noch einmal durch."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Bei der Suche wurden keine Kanäle gefunden. Vergewissern Sie sich, dass der USB-Tuner angeschlossen und mit einer TV-Signalquelle verbunden ist.\n\nWenn Sie eine terrestrische Antenne verwenden, ändern Sie die Position oder Ausrichtung. Die besten Ergebnisse erhalten Sie, wenn Sie sie an einer erhöhten Position in Fensternähe stellen. Führen Sie dann die Suche erneut durch."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Bei der Suche wurden keine Kanäle gefunden. Vergewissere dich, dass der Netzwerk-Tuner eingeschaltet und mit einer TV-Signalquelle verbunden ist.\n\nWenn du eine terrestrische Antenne verwendest, ändere die Position oder Ausrichtung. Die besten Ergebnisse erhältst du, wenn du sie an eine erhöhte Position in Fensternähe stellst und die Suche noch einmal durchführst."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Noch einmal suchen"</item>
+ <item msgid="2092797862490235174">"Fertig"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Nach TV-Kanälen suchen"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Einrichtung des TV-Tuners"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Einrichtung des USB-TV-Tuners"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Einrichtung des Netzwerk-TV-Tuners"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"Verbindung zum USB-TV-Tuner wurde aufgehoben."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Verbindung zum Netzwerk-Tuner wurde aufgehoben."</string>
+</resources>
diff --git a/usbtuner-res/values-el/strings.xml b/usbtuner-res/values-el/strings.xml
new file mode 100644
index 00000000..1ea637d4
--- /dev/null
+++ b/usbtuner-res/values-el/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Δέκτης τηλεόρασης"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"Δέκτης τηλεόρασης USB"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Δέκτης τηλεόρασης δικτύου (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Περιμένετε να ολοκληρωθεί η επεξεργασία"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Το λογισμικό δέκτη ενημερώθηκε πρόσφατα. Επαναλάβετε τη σάρωση των καναλιών."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Ενεργοποιήστε τον περιφερειακό ήχο στις ρυθμίσεις ήχου συστήματος για να ενεργοποιήσετε τον ήχο"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Δεν είναι δυνατή η αναπαραγωγή ήχου. Δοκιμάστε μια άλλη τηλεόραση."</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Ρύθμιση δέκτη καναλιών"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Ρύθμιση δέκτη τηλεόρασης"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Ρύθμιση δέκτη καναλιών USB"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Ρύθμιση δέκτη δικτύου"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Βεβαιωθείτε ότι η τηλεόρασή σας είναι συνδεδεμένη σε μια πηγή τηλεοπτικού σήματος.\n\nΕάν χρησιμοποιείτε ασύρματη κεραία, ίσως χρειαστεί να προσαρμόσετε την τοποθέτηση ή την κατεύθυνσή της για να λάβετε περισσότερα κανάλια. Για καλύτερα αποτελέσματα, τοποθετήστε την ψηλά και κοντά σε ένα παράθυρο."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Βεβαιωθείτε ότι ο δέκτης USB είναι συνδεδεμένος στην πρίζα και σε μια πηγή τηλεοπτικού σήματος.\n\nΕάν χρησιμοποιείτε ασύρματη κεραία, ίσως χρειαστεί να προσαρμόσετε την τοποθέτηση ή την κατεύθυνσή της για να λάβετε περισσότερα κανάλια. Για καλύτερα αποτελέσματα, τοποθετήστε την ψηλά και κοντά σε ένα παράθυρο."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Βεβαιωθείτε ότι ο δέκτης του δικτύου είναι ενεργοποιημένος και συνδεδεμένος σε μια πηγή τηλεοπτικού σήματος.\n\nΕάν χρησιμοποιείτε ασύρματη κεραία, ίσως χρειαστεί να προσαρμόσετε την τοποθέτηση ή την κατεύθυνσή της για να λάβετε περισσότερα κανάλια. Για καλύτερα αποτελέσματα, τοποθετήστε την ψηλά και κοντά σε ένα παράθυρο."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Συνέχεια"</item>
+ <item msgid="727245208787621142">"Όχι τώρα"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Επανάληψη ρύθμισης καναλιών;"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Με αυτόν τον τρόπο θα καταργηθούν τα κανάλια που βρέθηκαν από τον δέκτη τηλεόρασης και θα γίνει ξανά σάρωση για νέα κανάλια.\n\nΒεβαιωθείτε ότι η τηλεόρασή σας είναι συνδεδεμένη σε μια πηγή τηλεοπτικού σήματος.\n\nΕάν χρησιμοποιείτε ασύρματη κεραία, ίσως χρειαστεί να προσαρμόσετε την τοποθέτηση ή την κατεύθυνσή της για να λάβετε περισσότερα κανάλια. Για καλύτερα αποτελέσματα, τοποθετήστε την ψηλά και κοντά σε ένα παράθυρο."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Με αυτόν τον τρόπο θα καταργηθούν τα κανάλια που βρέθηκαν από τον δέκτη USB και θα γίνει ξανά σάρωση για νέα κανάλια.\n\nΒεβαιωθείτε ότι ο δέκτης USB είναι συνδεδεμένος στην πρίζα και σε μια πηγή τηλεοπτικού σήματος.\n\nΕάν χρησιμοποιείτε ασύρματη κεραία, ίσως χρειαστεί να προσαρμόσετε την τοποθέτηση ή την κατεύθυνσή της για να λάβετε περισσότερα κανάλια. Για καλύτερα αποτελέσματα, τοποθετήστε την ψηλά και κοντά σε ένα παράθυρο."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Με αυτόν τον τρόπο, τα κανάλια που βρέθηκαν από τον δέκτη του δικτύου θα καταργηθούν και θα γίνει ξανά σάρωση για νέα κανάλια.\n\nΒεβαιωθείτε ότι ο δέκτης του δικτύου είναι ενεργοποιημένος και συνδεδεμένος σε μια πηγή τηλεοπτικού σήματος.\n\nΕάν χρησιμοποιείτε ασύρματη κεραία, ίσως χρειαστεί να προσαρμόσετε την τοποθέτηση ή την κατεύθυνσή της για να λάβετε περισσότερα κανάλια. Για καλύτερα αποτελέσματα, τοποθετήστε την ψηλά και κοντά σε ένα παράθυρο."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Συνέχεια"</item>
+ <item msgid="235450158666155406">"Ακύρωση"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Επιλέξτε τον τύπο σύνδεσης"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Επιλέξτε \"Κεραία\" εάν έχει συνδεθεί μια εξωτερική κεραία στον δέκτη. Επιλέξτε \"Καλωδιακή\" εάν τα κανάλια σας προέρχονται από έναν παροχέα υπηρεσιών καλωδιακής τηλεόρασης. Εάν δεν είστε σίγουροι, θα γίνει σάρωση και για τους δύο τύπους, αλλά αυτό ενδέχεται να διαρκέσει περισσότερο."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Κεραία"</item>
+ <item msgid="2670079958754180142">"Καλωδιακή"</item>
+ <item msgid="36774059871728525">"Δεν είμαι σίγουρος/η"</item>
+ <item msgid="6881204453182153978">"Μόνο ανάπτυξη"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Ρύθμιση δέκτη τηλεόρασης"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Ρύθμιση δέκτη καναλιών USB"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Ρύθμιση δέκτη καναλιών δικτύου"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Αυτό μπορεί να διαρκέσει αρκετά λεπτά"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Ο δέκτης δεν είναι διαθέσιμος προσωρινά ή χρησιμοποιείται ήδη από την εγγραφή."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">Βρέθηκαν %1$d κανάλια</item>
+ <item quantity="one">Βρέθηκε %1$d κανάλι</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"ΔΙΑΚΟΠΗ ΣΑΡΩΣΗΣ ΚΑΝΑΛΙΩΝ"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">Βρέθηκαν %1$d κανάλια</item>
+ <item quantity="one">Βρέθηκε %1$d κανάλι</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Ωραία! Βρέθηκαν %1$d κανάλια κατά τη σάρωση καναλιών. Εάν αυτό δεν φαίνεται σωστό, δοκιμάστε να ρυθμίσετε τη θέση της κεραίας και επαναλάβετε τη σάρωση.</item>
+ <item quantity="one">Ωραία! Βρέθηκε %1$d κανάλι κατά τη σάρωση καναλιών. Εάν αυτό δεν φαίνεται σωστό, δοκιμάστε να ρυθμίσετε τη θέση της κεραίας και επαναλάβετε τη σάρωση.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Ολοκληρώθηκε"</item>
+ <item msgid="2480490326672924828">"Εκ νέου σάρωση"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Δεν βρέθηκαν κανάλια"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Δεν βρέθηκαν κανάλια κατά τη σάρωση. Βεβαιωθείτε ότι η τηλεόρασή σας είναι συνδεδεμένη σε μια πηγή τηλεοπτικού σήματος.\n\nΕάν χρησιμοποιείτε ασύρματη κεραία, προσαρμόστε την τοποθέτηση ή την κατεύθυνσή της. Για καλύτερα αποτελέσματα, τοποθετήστε την ψηλά και κοντά σε ένα παράθυρο και επαναλάβετε τη σάρωση."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Δεν βρέθηκαν κανάλια κατά τη σάρωση. Βεβαιωθείτε ότι ο δέκτης USB είναι συνδεδεμένος στην πρίζα και σε μια πηγή τηλεοπτικού σήματος.\n\nΕάν χρησιμοποιείτε ασύρματη κεραία, προσαρμόστε την τοποθέτηση ή την κατεύθυνσή της. Για καλύτερα αποτελέσματα, τοποθετήστε την ψηλά και κοντά σε ένα παράθυρο και επαναλάβετε τη σάρωση."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Δεν εντοπίστηκε κανένα κανάλι κατά τη σάρωση. Βεβαιωθείτε ότι ο δέκτης του δικτύου είναι ενεργοποιημένος και συνδεδεμένος σε μια πηγή τηλεοπτικού σήματος.\n\nΕάν χρησιμοποιείτε ασύρματη κεραία, προσαρμόστε την τοποθέτηση ή την κατεύθυνσή της. Για καλύτερα αποτελέσματα, τοποθετήστε την ψηλά και κοντά σε κάποιο παράθυρο και επαναλάβετε τη σάρωση."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Εκ νέου σάρωση"</item>
+ <item msgid="2092797862490235174">"Ολοκληρώθηκε"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Σάρωση για τηλεοπτικά κανάλια"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Ρύθμιση δέκτη τηλεόρασης"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Ρύθμιση δέκτη τηλεόρασης USB"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Ρύθμιση δέκτη τηλεόρασης δικτύου"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"Ο δέκτης τηλεόρασης USB έχει αποσυνδεθεί."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Ο δέκτης δικτύου έχει αποσυνδεθεί."</string>
+</resources>
diff --git a/usbtuner-res/values-en-rAU/strings.xml b/usbtuner-res/values-en-rAU/strings.xml
new file mode 100644
index 00000000..dccba99e
--- /dev/null
+++ b/usbtuner-res/values-en-rAU/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"TV Tuner"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB TV Tuner"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Network TV Tuner (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Please wait to finish processing"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Tuner software has been recently updated. Please re-scan the channels."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"To enable audio, enable surround sound in system sound settings"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Cannot play audio. Please try another TV"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Channel tuner setup"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"TV Tuner setup"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB channel tuner setup"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Network Tuner Setup"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Check that your TV is connected to a TV signal source.\n\nIf using an over-the-air aerial, you may need to adjust its placement or direction to receive the most channels. For best results, place it high and near a window."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Check that the USB tuner is plugged in and connected to a TV signal source.\n\nIf using an over-the-air aerial, you may need to adjust its placement or direction to receive the most channels. For best results, place it high and near a window."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Verify the network tuner is powered on and connected to a TV signal source.\n\nIf using an over-the-air antenna, you may need to adjust its placement or direction to receive the most channels. For best results, place it high and near a window."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Continue"</item>
+ <item msgid="727245208787621142">"Not now"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Re-run channel setup?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"This will remove the channels found from the TV tuner and scan for new channels again.\n\nCheck that your TV is connected to a TV signal source.\n\nIf using an over-the-air aerial, you may need to adjust its placement or direction to receive the most channels. For best results, place it high and near a window."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"This will remove the channels found from the USB tuner and scan for new channels again.\n\nCheck that the USB tuner is plugged in and connected to a TV signal source.\n\nIf using an over-the-air antenna, you may need to adjust its placement or direction to receive the most channels. For best results, place it high and near a window."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"This will remove the channels found from the network tuner and scan for new channels again.\n\nVerify the network tuner is powered on and connected to a TV signal source.\n\nIf using an over-the-air antenna, you may need to adjust its placement or direction to receive the most channels. For best results, place it high and near a window."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Continue"</item>
+ <item msgid="235450158666155406">"Cancel"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Select the connection type"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Choose Aerial if there is an external Aerial connected to the tuner. Choose Cable if your channels come from a cable service provider. If you are not sure, both types will be scanned, but this may take longer."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Aerial"</item>
+ <item msgid="2670079958754180142">"Cable"</item>
+ <item msgid="36774059871728525">"Not sure"</item>
+ <item msgid="6881204453182153978">"Development only"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"TV tuner setup"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB channel tuner setup"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Network channel tuner setup"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"This may take several minutes"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Tuner is temporarily unavailable or already used by recording."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">%1$d channels found</item>
+ <item quantity="one">%1$d channel found</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"STOP CHANNEL SCAN"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">%1$d channels found</item>
+ <item quantity="one">%1$d channel found</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Nice! %1$d channels were found during the channel scan. If this doesn’t seem right, try adjusting the antenna position and scan again.</item>
+ <item quantity="one">Nice! %1$d channel was found during the channel scan. If this doesn’t seem right, try adjusting the antenna position and scan again.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Finished"</item>
+ <item msgid="2480490326672924828">"Scan again"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"No channels found"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"The scan did not find any channels. Check that your TV is connected to a TV signal source.\n\nIf using an over-the-air aerial, adjust its placement or direction. For best results, place it high and near a window and scan again."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"The scan did not find any channels. Check that the USB tuner is plugged in and connected to a TV signal source.\n\nIf using an over-the-air aerial, adjust its placement or direction. For best results, place it high and near a window and scan again."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"The scan did not find any channels. Verify the network tuner is powered on and connected to a TV signal source.\n\nIf using an over-the-air antenna, adjust its placement or direction. For best results, place it high and near a window and scan again."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Scan again"</item>
+ <item msgid="2092797862490235174">"Finished"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Scan for TV channels"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"TV Tuner setup"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB TV Tuner setup"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Network TV Tuner setup"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB TV tuner disconnected."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Network tuner disconnected."</string>
+</resources>
diff --git a/usbtuner-res/values-en-rGB/strings.xml b/usbtuner-res/values-en-rGB/strings.xml
new file mode 100644
index 00000000..dccba99e
--- /dev/null
+++ b/usbtuner-res/values-en-rGB/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"TV Tuner"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB TV Tuner"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Network TV Tuner (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Please wait to finish processing"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Tuner software has been recently updated. Please re-scan the channels."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"To enable audio, enable surround sound in system sound settings"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Cannot play audio. Please try another TV"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Channel tuner setup"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"TV Tuner setup"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB channel tuner setup"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Network Tuner Setup"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Check that your TV is connected to a TV signal source.\n\nIf using an over-the-air aerial, you may need to adjust its placement or direction to receive the most channels. For best results, place it high and near a window."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Check that the USB tuner is plugged in and connected to a TV signal source.\n\nIf using an over-the-air aerial, you may need to adjust its placement or direction to receive the most channels. For best results, place it high and near a window."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Verify the network tuner is powered on and connected to a TV signal source.\n\nIf using an over-the-air antenna, you may need to adjust its placement or direction to receive the most channels. For best results, place it high and near a window."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Continue"</item>
+ <item msgid="727245208787621142">"Not now"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Re-run channel setup?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"This will remove the channels found from the TV tuner and scan for new channels again.\n\nCheck that your TV is connected to a TV signal source.\n\nIf using an over-the-air aerial, you may need to adjust its placement or direction to receive the most channels. For best results, place it high and near a window."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"This will remove the channels found from the USB tuner and scan for new channels again.\n\nCheck that the USB tuner is plugged in and connected to a TV signal source.\n\nIf using an over-the-air antenna, you may need to adjust its placement or direction to receive the most channels. For best results, place it high and near a window."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"This will remove the channels found from the network tuner and scan for new channels again.\n\nVerify the network tuner is powered on and connected to a TV signal source.\n\nIf using an over-the-air antenna, you may need to adjust its placement or direction to receive the most channels. For best results, place it high and near a window."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Continue"</item>
+ <item msgid="235450158666155406">"Cancel"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Select the connection type"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Choose Aerial if there is an external Aerial connected to the tuner. Choose Cable if your channels come from a cable service provider. If you are not sure, both types will be scanned, but this may take longer."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Aerial"</item>
+ <item msgid="2670079958754180142">"Cable"</item>
+ <item msgid="36774059871728525">"Not sure"</item>
+ <item msgid="6881204453182153978">"Development only"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"TV tuner setup"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB channel tuner setup"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Network channel tuner setup"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"This may take several minutes"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Tuner is temporarily unavailable or already used by recording."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">%1$d channels found</item>
+ <item quantity="one">%1$d channel found</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"STOP CHANNEL SCAN"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">%1$d channels found</item>
+ <item quantity="one">%1$d channel found</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Nice! %1$d channels were found during the channel scan. If this doesn’t seem right, try adjusting the antenna position and scan again.</item>
+ <item quantity="one">Nice! %1$d channel was found during the channel scan. If this doesn’t seem right, try adjusting the antenna position and scan again.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Finished"</item>
+ <item msgid="2480490326672924828">"Scan again"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"No channels found"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"The scan did not find any channels. Check that your TV is connected to a TV signal source.\n\nIf using an over-the-air aerial, adjust its placement or direction. For best results, place it high and near a window and scan again."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"The scan did not find any channels. Check that the USB tuner is plugged in and connected to a TV signal source.\n\nIf using an over-the-air aerial, adjust its placement or direction. For best results, place it high and near a window and scan again."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"The scan did not find any channels. Verify the network tuner is powered on and connected to a TV signal source.\n\nIf using an over-the-air antenna, adjust its placement or direction. For best results, place it high and near a window and scan again."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Scan again"</item>
+ <item msgid="2092797862490235174">"Finished"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Scan for TV channels"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"TV Tuner setup"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB TV Tuner setup"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Network TV Tuner setup"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB TV tuner disconnected."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Network tuner disconnected."</string>
+</resources>
diff --git a/usbtuner-res/values-en-rIN/strings.xml b/usbtuner-res/values-en-rIN/strings.xml
new file mode 100644
index 00000000..dccba99e
--- /dev/null
+++ b/usbtuner-res/values-en-rIN/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"TV Tuner"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB TV Tuner"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Network TV Tuner (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Please wait to finish processing"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Tuner software has been recently updated. Please re-scan the channels."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"To enable audio, enable surround sound in system sound settings"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Cannot play audio. Please try another TV"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Channel tuner setup"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"TV Tuner setup"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB channel tuner setup"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Network Tuner Setup"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Check that your TV is connected to a TV signal source.\n\nIf using an over-the-air aerial, you may need to adjust its placement or direction to receive the most channels. For best results, place it high and near a window."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Check that the USB tuner is plugged in and connected to a TV signal source.\n\nIf using an over-the-air aerial, you may need to adjust its placement or direction to receive the most channels. For best results, place it high and near a window."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Verify the network tuner is powered on and connected to a TV signal source.\n\nIf using an over-the-air antenna, you may need to adjust its placement or direction to receive the most channels. For best results, place it high and near a window."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Continue"</item>
+ <item msgid="727245208787621142">"Not now"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Re-run channel setup?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"This will remove the channels found from the TV tuner and scan for new channels again.\n\nCheck that your TV is connected to a TV signal source.\n\nIf using an over-the-air aerial, you may need to adjust its placement or direction to receive the most channels. For best results, place it high and near a window."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"This will remove the channels found from the USB tuner and scan for new channels again.\n\nCheck that the USB tuner is plugged in and connected to a TV signal source.\n\nIf using an over-the-air antenna, you may need to adjust its placement or direction to receive the most channels. For best results, place it high and near a window."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"This will remove the channels found from the network tuner and scan for new channels again.\n\nVerify the network tuner is powered on and connected to a TV signal source.\n\nIf using an over-the-air antenna, you may need to adjust its placement or direction to receive the most channels. For best results, place it high and near a window."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Continue"</item>
+ <item msgid="235450158666155406">"Cancel"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Select the connection type"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Choose Aerial if there is an external Aerial connected to the tuner. Choose Cable if your channels come from a cable service provider. If you are not sure, both types will be scanned, but this may take longer."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Aerial"</item>
+ <item msgid="2670079958754180142">"Cable"</item>
+ <item msgid="36774059871728525">"Not sure"</item>
+ <item msgid="6881204453182153978">"Development only"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"TV tuner setup"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB channel tuner setup"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Network channel tuner setup"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"This may take several minutes"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Tuner is temporarily unavailable or already used by recording."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">%1$d channels found</item>
+ <item quantity="one">%1$d channel found</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"STOP CHANNEL SCAN"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">%1$d channels found</item>
+ <item quantity="one">%1$d channel found</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Nice! %1$d channels were found during the channel scan. If this doesn’t seem right, try adjusting the antenna position and scan again.</item>
+ <item quantity="one">Nice! %1$d channel was found during the channel scan. If this doesn’t seem right, try adjusting the antenna position and scan again.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Finished"</item>
+ <item msgid="2480490326672924828">"Scan again"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"No channels found"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"The scan did not find any channels. Check that your TV is connected to a TV signal source.\n\nIf using an over-the-air aerial, adjust its placement or direction. For best results, place it high and near a window and scan again."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"The scan did not find any channels. Check that the USB tuner is plugged in and connected to a TV signal source.\n\nIf using an over-the-air aerial, adjust its placement or direction. For best results, place it high and near a window and scan again."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"The scan did not find any channels. Verify the network tuner is powered on and connected to a TV signal source.\n\nIf using an over-the-air antenna, adjust its placement or direction. For best results, place it high and near a window and scan again."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Scan again"</item>
+ <item msgid="2092797862490235174">"Finished"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Scan for TV channels"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"TV Tuner setup"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB TV Tuner setup"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Network TV Tuner setup"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB TV tuner disconnected."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Network tuner disconnected."</string>
+</resources>
diff --git a/usbtuner-res/values-es-rUS/strings.xml b/usbtuner-res/values-es-rUS/strings.xml
new file mode 100644
index 00000000..cca69f4e
--- /dev/null
+++ b/usbtuner-res/values-es-rUS/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Sintonizador de TV"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"Sintonizador de TV USB"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Sintonizador de TV de red (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Espera a que finalice el procesamiento"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"El software del sintonizador se actualizó recientemente. Vuelve a buscar los canales."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Para habilitar el audio, deberás activar el sonido envolvente en la configuración del sistema de sonido"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"No se puede reproducir el audio. Intenta usar otra TV."</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Configuración del sintonizador de canales"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Configuración del sintonizador de TV"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Configuración del sintonizador de canales USB"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Configuración del sintonizador de red"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Verifica que tu TV esté conectada a una fuente de señal de TV.\n\nSi usas una antena inalámbrica, es posible que tengas que ajustar su posición o dirección para recibir la mayor cantidad de canales posible. Para obtener mejores resultados, ubica la antena en un lugar alto y cerca de una ventana."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Verifica que el sintonizador USB esté enchufado y conectado a una fuente de señal de TV.\n\nSi usas una antena inalámbrica, es posible que necesites ajustar su ubicación y dirección para recibir la mayor cantidad de canales. Para obtener mejores resultados, ubica la antena en un lugar alto y cerca de una ventana."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Comprueba que el sintonizador de red esté encendido y conectado a una fuente de señal de TV.\n\nSi estás usando una antena inalámbrica, es posible que debas ajustar su ubicación o dirección para recibir la mayoría de los canales. Si deseas obtener mejores resultados, colócala en un lugar alto y cerca de una ventana."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Continuar"</item>
+ <item msgid="727245208787621142">"Ahora no"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"¿Quieres volver a configurar los canales?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Esta acción quitará los canales encontrados desde el sintonizador de TV y se volverán a buscar canales nuevos.\n\nVerifica que tu TV esté conectada a una fuente de señal de TV.\n\nSi usas una antena inalámbrica, es posible que tengas que ajustar su posición o dirección para recibir la mayor cantidad de canales posible. Para obtener mejores resultados, ubica la antena en un lugar alto y cerca de una ventana."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Esta acción quitará los canales encontrados desde el sintonizador de TV y se volverán a buscar canales nuevos.\n\nVerifica que el sintonizador USB esté enchufado y conectado a una fuente de señal de TV.\n\nSi usas una antena inalámbrica, es posible que necesites ajustar su ubicación y dirección para recibir la mayor cantidad de canales. Para obtener mejores resultados, ubica la antena en un lugar alto y cerca de una ventana."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"De esta manera, se quitarán los canales encontrados desde el sintonizador de red y se buscarán canales nuevos.\n\nComprueba que el sintonizador de red esté encendido y conectado a una fuente de señal de TV.\n\nSi estás usando una antena inalámbrica, es posible que debas ajustar su ubicación o dirección para recibir la mayor cantidad de canales. Para obtener mejores resultados, colócala en un lugar alto y cerca de una ventana."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Continuar"</item>
+ <item msgid="235450158666155406">"Cancelar"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Selecciona el tipo de conexión"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Elige la opción de antena si hay una antena externa conectada al sintonizador o la opción de cable si recibes los canales de un proveedor de servicios de cable. Si no estás seguro, se buscarán ambos tipos, pero es posible que este proceso demore más tiempo."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antena"</item>
+ <item msgid="2670079958754180142">"Cable"</item>
+ <item msgid="36774059871728525">"No estoy seguro"</item>
+ <item msgid="6881204453182153978">"Solo para desarrollo"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Configuración del sintonizador de TV"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Configuración del sintonizador de canales USB"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Configuración del sintonizador de canales de red"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Este proceso podría demorar varios minutos"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"El sintonizador no está disponible en este momento o está grabando."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">Se encontraron %1$d canales</item>
+ <item quantity="one">Se encontró %1$d canal</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"DETENER LA BÚSQUEDA DE CANALES"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">Se encontraron %1$d canales</item>
+ <item quantity="one">Se encontró %1$d canal</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Genial. Se encontraron %1$d canales durante la búsqueda de canales. Si crees que el resultado es incorrecto, ajusta la posición de la antena y vuelve a realizar la búsqueda.</item>
+ <item quantity="one">Genial. Se encontró %1$d canal durante la búsqueda de canales. Si crees que el resultado es incorrecto, ajusta la posición de la antena y vuelve a realizar la búsqueda.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Listo"</item>
+ <item msgid="2480490326672924828">"Volver a buscar"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"No se encontraron canales"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"No se encontró ningún canal. Verifica que tu TV esté conectada a una fuente de señal de TV.\n\nSi usas una antena inalámbrica, ajusta su posición o dirección. Para obtener mejores resultados, ubícala en un lugar alto y cerca de una ventana. Luego, vuelve a hacer la búsqueda."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"No se encontraron canales en la búsqueda. Verifica que el sintonizador USB esté enchufado y conectado a una fuente de señal de TV.\n\nSi usas una antena inalámbrica, ajusta su ubicación o dirección. Para obtener mejores resultados, ubícala en un lugar alto y cerca de una ventana. Luego, vuelve a hacer la búsqueda."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"No se encontró ningún canal durante la búsqueda. Comprueba que el sintonizador de red esté encendido y conectado a una fuente de señal de TV.\n\nSi estás usando una antena inalámbrica, ajusta su ubicación o dirección. Para obtener mejores resultados, colócala en un lugar alto y cerca de una ventana, y repite la búsqueda."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Volver a buscar"</item>
+ <item msgid="2092797862490235174">"Listo"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Busca canales de TV"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Configuración del sintonizador de TV"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Configuración del sintonizador de TV USB"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Configuración del sintonizador de TV de red"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"Se desconectó el sintonizador de TV USB."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Se desconectó el sintonizador de red."</string>
+</resources>
diff --git a/usbtuner-res/values-es/strings.xml b/usbtuner-res/values-es/strings.xml
new file mode 100644
index 00000000..26742e65
--- /dev/null
+++ b/usbtuner-res/values-es/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Sintonizador de canales"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"Sintonizador de canales USB"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Sintonizador de TV en red (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Espera hasta que finalice el procesamiento"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"El software del sintonizador se ha actualizado recientemente. Vuelve a buscar los canales."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Habilita el sonido envolvente en los ajustes del sistema de sonido para activar el audio"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"No se puede reproducir el audio. Prueba con otra TV"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Configuración del sintonizador de canales"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Configuración del sintonizador de canales"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Configuración del sintonizador de canales USB"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Configuración del sintonizador en red"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Comprueba que la TV esté conectada a una fuente de señal de TV.\n\n Si utilizas una antena inalámbrica, puede que tengas que cambiar su posición o dirección para recibir la mayor cantidad posible de canales. Para conseguir los mejores resultados, colócala en alto y cerca de una ventana."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Comprueba que el sintonizador USB esté enchufado y conectado a una fuente de señal de TV.\n\nSi utilizas una antena inalámbrica, puede que tengas que cambiar su emplazamiento o dirección para recibir la mayor cantidad posible de canales. Para conseguir los mejores resultados, colócala en alto y cerca de una ventana."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Comprueba que el sintonizador en red esté encendido y conectado a una fuente de señal de TV.\n\nSi utilizas una antena inalámbrica, es posible que tengas que cambiar su emplazamiento o su orientación para ver la mayoría de los canales. Para obtener los mejores resultados, colócala en un lugar alto cerca de una ventana."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Continuar"</item>
+ <item msgid="727245208787621142">"Ahora no"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"¿Quieres volver a ejecutar la configuración de canales?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Se quitarán los canales encontrados del sintonizador de canales y se volverán a buscar nuevos canales.\n\nComprueba que la TV esté conectada a una fuente de señal de TV.\n\nSi utilizas una antena inalámbrica, puede que tengas que cambiar su posición o dirección para recibir la mayor cantidad posible de canales. Para conseguir los mejores resultados, colócala en alto y cerca de una ventana."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Se quitarán los canales encontrados con el sintonizador USB y se volverán a buscar nuevos canales.\n\nComprueba que el sintonizador USB esté enchufado y conectado a una fuente de señal de TV.\n\nSi utilizas una antena inalámbrica, puede que tengas que cambiar su ubicación o dirección para recibir la mayor cantidad posible de canales. Para conseguir los mejores resultados, colócala en alto y cerca de una ventana."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Se quitarán los canales encontrados del sintonizador en red y se repetirá la búsqueda de canales.\n\nComprueba que el sintonizador en red esté encendido y conectado a una fuente de señal de TV.\n\nSi utilizas una antena inalámbrica, es posible que tengas que cambiar su emplazamiento o su orientación para ver la mayoría de los canales. Para obtener los mejores resultados, colócala en un lugar alto cerca de una ventana."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Continuar"</item>
+ <item msgid="235450158666155406">"Cancelar"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Selecciona un tipo de conexión"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Selecciona Antena si hay una antena externa conectada al sintonizador. Selecciona Cable si tus canales proceden de un proveedor de servicios de cable. Si no lo sabes con seguridad, se buscarán ambos tipos, pero este proceso puede tardar más tiempo."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antena"</item>
+ <item msgid="2670079958754180142">"Cable"</item>
+ <item msgid="36774059871728525">"No lo sé con seguridad"</item>
+ <item msgid="6881204453182153978">"Solo desarrollo"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Configuración del sintonizador de canales"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Configuración del sintonizador de canales USB"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Configuración del sintonizador de canales en red"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Este proceso puede tardar varios minutos"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"El sintonizador no está disponible temporalmente o se está utilizando en otra grabación."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">%1$d canales encontrados</item>
+ <item quantity="one">%1$d canal encontrado</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"DETENER BÚSQUEDA DE CANALES"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">%1$d canales encontrados</item>
+ <item quantity="one">%1$d canal encontrado</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">¡Genial! Se han encontrado %1$d canales durante la búsqueda de canales. Si no te parece correcto, cambia la posición de la antena y vuelve a realizar la búsqueda.</item>
+ <item quantity="one">¡Genial! Se ha encontrado %1$d canal durante la búsqueda de canales. Si no te parece correcto, cambia la posición de la antena y vuelve a realizar la búsqueda.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Listo"</item>
+ <item msgid="2480490326672924828">"Volver a buscar"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"No se han encontrado canales"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"No se ha encontrado ningún canal. Comprueba que la TV esté conectada a una fuente de señal de TV.\n\nSi utilizas una antena inalámbrica, cambia su posición o dirección. Para conseguir los mejores resultados, colócala en alto y cerca de una ventana. A continuación, vuelve a realizar la búsqueda."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"No se ha encontrado ningún canal. Comprueba que el sintonizador USB esté enchufado y conectado a una fuente de señal de TV.\n\nSi utilizas una antena inalámbrica, cambia su emplazamiento o dirección. Para conseguir los mejores resultados, colócala en alto y cerca de una ventana. A continuación, vuelve a realizar la búsqueda."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"El análisis no ha encontrado ningún canal. Comprueba que el sintonizador en red esté encendido y conectado a una fuente de señal de TV.\n\nSi utilizas una antena inalámbrica, cambia su emplazamiento u orientación. Para obtener los mejores resultados, colócala en un lugar alto cerca de una ventana y repite el análisis."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Volver a buscar"</item>
+ <item msgid="2092797862490235174">"Listo"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Buscar canales de TV"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Configuración del sintonizador de TV"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Configuración de sintonizador de TV USB"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Configuración del sintonizador de TV en red"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"El sintonizador de canales USB está desconectado."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"El sintonizador en red está desconectado."</string>
+</resources>
diff --git a/usbtuner-res/values-et-rEE/strings.xml b/usbtuner-res/values-et-rEE/strings.xml
new file mode 100644
index 00000000..3d97a31a
--- /dev/null
+++ b/usbtuner-res/values-et-rEE/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Telerituuner"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB-telerituuner"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Teleri võrgutuuner (BEETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Oodake, kuni töötlemine on lõppenud"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Tuuneri tarkvara värskendati hiljuti. Otsige kanaleid uuesti."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Heli lubamiseks lubage ruumiline heli süsteemi heliseadetes"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Heli ei saa esitada. Proovige teist telerit"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Kanalituuneri seadistus"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Telerituuneri seadistus"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB-kanalituuneri seadistus"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Võrgutuuneri seadistus"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Veenduge, et teler oleks ühendatud teleri signaaliallikaga.\n\nKui kasutate õhuantenni, peate võimalikult paljude kanalite nägemiseks võib-olla kohandama selle asendit või suunda. Parimate tulemuste saavutamiseks asetage see kõrgele ja akna lähedale."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Veenduge, et USB-tuuner oleks pistikus ja ühendatud teleri signaaliallikaga.\n\nKui kasutate õhuantenni, peate enamiku kanalite nägemiseks võib-olla kohandama selle asendit või suunda. Parimate tulemuste saavutamiseks asetage see kõrgele ja akna lähedale."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Veenduge, et võrgutuuner oleks sisse lülitatud ja teleri signaaliallikaga ühendatud.\n\nKui kasutate õhuantenni, peate võib-olla muutma selle asendit või suunda, et rohkem kanaleid leida. Parimate tulemuste saavutamiseks asetage see kõrgesse kohta akna lähedale."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Jätka"</item>
+ <item msgid="727245208787621142">"Mitte praegu"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Kas käitada kanali seadistust uuesti?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"See eemaldab telerituuneri leitud kanalid ja otsib uuesti uusi kanaleid.\n\nVeenduge, et teler oleks ühendatud teleri signaaliallikaga.\n\nKui kasutate õhuantenni, peate võimalikult paljude kanalite nägemiseks võib-olla kohandama selle asendit või suunda. Parimate tulemuste saavutamiseks asetage see kõrgele ja akna lähedale."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"See eemaldab USB-tuuneri leitud kanalid ja otsib uuesti uusi kanaleid.\n\nVeenduge, et USB-tuuner oleks pistikus ja ühendatud teleri signaaliallikaga.\n\nKui kasutate õhuantenni, peate enamiku kanalite nägemiseks võib-olla kohandama selle asendit või suunda. Parimate tulemuste saavutamiseks asetage see kõrgele ja akna lähedale."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"See eemaldab võrgutuunerist leitud kanalid ja skannib uuesti uusi kanaleid.\n\nVeenduge, et võrgutuuner oleks sisse lülitatud ja teleri signaaliallikaga ühendatud.\n\nKui kasutate õhuantenni, peate võib-olla muutma selle asendit või suunda, et rohkem kanaleid leida. Parimate tulemuste saavutamiseks asetage see kõrgesse kohta akna lähedale."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Jätka"</item>
+ <item msgid="235450158666155406">"Tühista"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Valige ühenduse tüüp"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Kui tuuneriga on ühendatud väline antenn, tehke valik Antenn. Kui kanaleid pakub kaabelteenuse pakkuja, tehke valik Kaabel. Kui te pole kindel, otsitakse mõlemat tüüpi, kuid see võib kauem aega võtta."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antenn"</item>
+ <item msgid="2670079958754180142">"Kaabel"</item>
+ <item msgid="36774059871728525">"Ei ole kindel"</item>
+ <item msgid="6881204453182153978">"Ainult arenduseks"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Telerituuneri seadistus"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB-kanalituuneri seadistus"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Võrgutuuneri kanalite seadistus"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"See võib võtta mitu minutit"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Tuuner pole ajutiselt saadaval või seda kasutatakse juba salvestamiseks."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">Leiti %1$d kanalit</item>
+ <item quantity="one">Leiti %1$d kanal</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"PEATA KANALITE OTSIMINE"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">Leiti %1$d kanalit</item>
+ <item quantity="one">Leiti %1$d kanal</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Hästi! Kanalite otsimisel leiti %1$d kanalit. Kui see ei tundu õige, kohandage antenni asendit ja otsige uuesti.</item>
+ <item quantity="one">Hästi! Kanalite otsimisel leiti %1$d kanal. Kui see ei tundu õige, kohandage antenni asendit ja otsige uuesti.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Valmis"</item>
+ <item msgid="2480490326672924828">"Otsi uuesti"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Ühtegi kanalit ei leitud"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Otsimisel ei leitud ühtegi kanalit. Veenduge, et teler oleks ühendatud teleri signaaliallikaga.\n\nKui kasutate õhuantenni, kohandage selle asendit või suunda. Parimate tulemuste saavutamiseks asetage see kõrgele ja akna lähedale ning otsige uuesti."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Otsimisel ei leitud ühtegi kanalit. Veenduge, et USB-tuuner oleks pistikus ja ühendatud teleri signaaliallikaga.\n\nKui kasutate õhuantenni, kohandage selle asendit või suunda. Parimate tulemuste saavutamiseks asetage see kõrgele ja akna lähedale ning otsige uuesti."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Skannimisel ei leitud ühtegi kanalit. Veenduge, et võrgutuuner oleks sisse lülitatud ja teleri signaaliallikaga ühendatud.\n\nKui kasutate õhuantenni, muutke selle asendit või suunda. Parimate tulemuste saavutamiseks asetage see kõrgesse kohta akna lähedale ja skannige uuesti."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Otsi uuesti"</item>
+ <item msgid="2092797862490235174">"Valmis"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Telekanalite otsimine"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Telerituuneri seadistus"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB-telerituuneri seadistus"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Teleri võrgutuuneri seadistus"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB-telerituuner eemaldati."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Võrgutuuner eemaldati."</string>
+</resources>
diff --git a/usbtuner-res/values-eu-rES/strings.xml b/usbtuner-res/values-eu-rES/strings.xml
new file mode 100644
index 00000000..0f7ac943
--- /dev/null
+++ b/usbtuner-res/values-eu-rES/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Sintonizadorea"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB bidezko sintonizadorea"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Sareko sintonizadorea (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Itxaron prozesatzen amaitu arte"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Sintonizadorearen softwarea berriki eguneratu da. Bilatu kanalak berriro."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Audioa gaitzeko, joan sistemaren soinuaren ezarpenetara eta gaitu soinu inguratzailea"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Ezin da erreproduzitu audioa. Saiatu beste telebista batean."</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Kanal-sintonizadorearen konfigurazioa"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Sintonizadorearen konfigurazioa"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB kanal-sintonizadorearen konfigurazioa"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Sareko sintonizadorearen konfigurazioa"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Egiaztatu telebista-seinalearen iturburu batera konektatuta dagoela telebista.\n\nAntena analogiko bat badarabilzu, agian bere kokapena edo norabidea doitu beharko dituzu kanal gehienak eskuratzeko. Emaitzarik onenak lortzeko, ezarri toki altu batean edo leiho baten ondoan."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Egiaztatu USB sintonizadorea entxufatuta eta telebistako seinale-iturburu batera konektatuta dagoela.\n\nHari gabeko antena badarabilzu, doitu bere kokapena edo norabidea. Emaitzarik onenak lortzeko, ezarri toki altu batean edo leiho baten ondoan eta gauzatu bilaketa berriro."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Egiaztatu sintonizadorea piztuta dagoela eta telebista-seinalea igortzen duen iturburu batera konektatu duzula.\n\nHari-gabeko antena bat erabiltzen ari bazara, doi ezazu haren kokapena edo norabidea ahal bezain beste kanal aurkitzeko. Emaitzarik onenak lortzeko, ezar ezazu ahal bezain altu eta leiho batetik gertu."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Jarraitu"</item>
+ <item msgid="727245208787621142">"Orain ez"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Berriro konfiguratu nahi dituzu kanalak?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Sintonizadoreak aurkitutako kanalak kenduko dira eta berriro bilatuko dira kanalak.\n\nEgiaztatu telebista-seinalearen iturburu batera konektatuta dagoela telebista.\n\nAntena analogiko bat badarabilzu, agian bere kokapena edo norabidea doitu beharko dituzu kanal gehienak eskuratzeko. Emaitzarik onenak lortzeko, ezarri toki altu batean edo leiho baten ondoan."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"USB sintonizadoreak aurkitutako kanalak kenduko dira eta berriro bilatuko dira kanalak.\n\nEgiaztatu USB sintonizadorea entxufatuta eta telebistako seinale-iturburu batera konektatuta dagoela.\n\nAntena analogiko bat badarabilzu, agian bere kokapena edo norabidea doitu beharko dituzu kanal gehienak eskuratzeko. Emaitzarik onenak lortzeko, ezarri toki altu batean edo leiho baten ondoan."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Hori eginez gero, kendu egingo dira sareko sintonizadoreak aurkitutako kanalak eta zerotik hasiko da berriro kanalak bilatzen.\n\n Egiaztatu sintonizadorea piztuta dagoela eta telebista-seinalea igortzen duen iturburu batera konektatu duzula.\n\nHari-gabeko antena bat erabiltzen ari bazara, doi ezazu haren kokapena edo norabidea ahal bezain beste kanal aurkitzeko. Emaitzarik onenak lortzeko, ezar ezazu ahal bezain altu eta leiho batetik gertu."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Jarraitu"</item>
+ <item msgid="235450158666155406">"Utzi"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Hautatu konexio mota"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Kanpoko antena badago sintonizadorera konektatuta, aukeratu Antena. Kableko zerbitzu-hornitzaile batek eskaintzen badizkizu kanalak, aukeratu Kablea. Ziur ez bazaude, mota bietakoak bilatuko dira, baina zertxobait luzatuko da."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antena"</item>
+ <item msgid="2670079958754180142">"Kablea"</item>
+ <item msgid="36774059871728525">"Ez dakit ziur"</item>
+ <item msgid="6881204453182153978">"Garapenerako soilik"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Sintonizadorearen konfigurazioa"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB kanal-sintonizadorearen konfigurazioa"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Sareko kanalen sintonizadorearen konfigurazioa"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Zenbait minutu beharko dira"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Sintonizadorea ez dago erabilgarri edo beste zerbait ari da grabatzen."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">%1$d kanal aurkitu dira</item>
+ <item quantity="one">%1$d kanal aurkitu da</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"UTZI KANALAK BILATZEARI"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">%1$d kanal aurkitu dira</item>
+ <item quantity="one">%1$d kanal aurkitu da</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Primeran! %1$d kanal aurkitu da kanalak bilatzean. Oker gaudela uste baduzu, doitu antenaren posizioa eta saiatu berriro.</item>
+ <item quantity="one">Primeran! %1$d kanal aurkitu da kanalak bilatzean. Oker gaudela uste baduzu, doitu antenaren posizioa eta saiatu berriro.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Eginda"</item>
+ <item msgid="2480490326672924828">"Bilatu berriro"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Ez da aurkitu kanalik"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Bilaketak ez du aurkitu kanalik. Egiaztatu telebista-seinalearen iturburu batera konektatuta dagoela telebista.\n\nAntena analogiko bat badarabilzu, doitu bere kokapena edo norabidea. Emaitzarik onenak lortzeko, ezarri toki altu batean edo leiho baten ondoan eta gauzatu bilaketa berriro."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Bilaketak ez du aurkitu kanalik. Egiaztatu USB sintonizadorea entxufatuta eta telebistako seinale-iturburu batera konektatuta dagoela.\n\nAntena analogiko bat badarabilzu, doitu bere kokapena edo norabidea. Emaitzarik onenak lortzeko, ezarri toki altu batean edo leiho baten ondoan eta gauzatu bilaketa berriro."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Ez da aurkitu kanalik. Egiaztatu sintonizadorea piztuta dagoela eta telebista-seinalea igortzen duen iturburu batera konektatu duzula.\n\nHari-gabeko antena bat erabiltzen ari bazara, doi ezazu haren kokapena edo norabidea. Emaitzarik onenak lortzeko, ezar ezazu ahal bezain altu eta leiho batetik gertu. Ondoren, bila itzazu kanalak berriro."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Bilatu berriro"</item>
+ <item msgid="2092797862490235174">"Eginda"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Bilatu telebista-kateak"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Sintonizadorearen konfigurazioa"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB bidezko sintonizadorearen konfigurazioa"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Sareko sintonizadorearen konfigurazioa"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"Deskonektatu da USB bidezko sintonizadorea."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Deskonektatu da sareko sintonizadorea."</string>
+</resources>
diff --git a/usbtuner-res/values-fa/strings.xml b/usbtuner-res/values-fa/strings.xml
new file mode 100644
index 00000000..586fc926
--- /dev/null
+++ b/usbtuner-res/values-fa/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"تنظیم‌کننده تلویزیون"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"‏تنظیم‌کننده تلویزیون USB"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"تنظیم‌کننده تلویزیون شبکه (بتا)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"لطفاً تا پایان پردازش صبر کنید"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"نرم‌افزار تنظیم‌کننده اخیراً به‌روزرسانی شده است. لطفاً کانال‌ها را دوباره اسکن کنید."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"برای فعال کردن صدا، صدای فراگیر را در تنظیمات صدای سیستم فعال کنید"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"صوت پخش نمی‌شود. لطفاً تلویزیون دیگری را امتحان کنید."</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"راه‌اندازی تنظیم‌کننده کانال"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"راه‌اندازی تنظیم‌کننده تلویزیون"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"‏راه‌اندازی تنظیم‌کننده کانال USB"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"راه‌اندازی تنظیم‌کننده شبکه‌ای"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"مطمئن شوید تلویزیونتان به منبع سیگنال تلویزیونی متصل است.\n\nدر صورت استفاده از آنتن بی‌سیم شاید لازم باشد برای دریافت کانال‌های بیشتر، موقعیت یا جهت آن را تنظیم کنید. برای بهترین نتایج، آن را در جای بلند و نزدیک پنجره قرار دهید."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"‏مطمئن شوید تنظیم‌کننده USB به منبع نیرو و منبع سیگنال تلویزیونی متصل است.\n\nدر صورت استفاده از آنتن بی‌سیم، موقعیت یا جهت آن را تنظیم کنید. برای بهترین نتایج، آن را در جای بلند و نزدیک پنجره قرار دهید."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"مطمئن شوید تنظیم‌کننده شبکه‌ای به برق و منبع سیگنال تلویزیونی وصل است.\n\nاگر از آنتن هوایی استفاده می‌کنید، ممکن است لازم باشد برای دریافت بیشترین تعداد کانال مکان و موقعیت آن را تنظیم کنید. برای بهترین نتایج، آن را در جای بلند و نزدیک پنجره قرار دهید."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"ادامه"</item>
+ <item msgid="727245208787621142">"فعلاً نه"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"تنظیم کانال دوباره اجرا شود؟"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"با این کار کانال‌های پیداشده از تنظیم‌کننده تلویزیون حذف می‌شوند و دوباره برای کانال‌های جدید اسکن می‌کند.\n\nمطمئن شوید تلویزیونتان به منبع سیگنال تلویزیونی متصل است.\n\nدر صورت استفاده از آنتن بی‌سیم، شاید لازم باشد برای دریافت کانال‌های بیشتر، موقعیت یا جهت آن را تنظیم کنید. برای بهترین نتایج، آن را در جای بلند و نزدیک پنجره قرار دهید."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"‏این کار کانال‌های پیداشده از تنظیم‌کننده USB را حذف می‌کند و دوباره کانال‌های جدید را اسکن می‌کند.\n\nمطمئن شوید تنظیم‌کننده USB به منبع نیرو و منبع سیگنال تلویزیونی متصل است.\n\nدر صورت استفاده از آنتن بی‌سیم، برای دریافت کانال‌های بیشتر، موقعیت یا جهت آن را تنظیم کنید. برای بهترین نتایج، آن را در جای بلند و نزدیک پنجره قرار دهید و دوباره اسکن کنید."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"این کار کانال‌های پیداشده را از تنظیم‌کننده شبکه‌ای حذف می‌کند و دوباره کانال‌های جدید را اسکن می‌کند.\n\nمطمئن شوید تنظیم‌کننده شبکه‌ای به برق و منبع سیگنال تلویزیونی وصل است.\n\nاگر از آنتن هوایی استفاده می‌کنید، ممکن است لازم باشد برای دریافت بیشترین تعداد کانال مکان و موقعیت آن را تنظیم کنید. برای بهترین نتایج، آن را در جای بلند و نزدیک پنجره قرار دهید."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"ادامه"</item>
+ <item msgid="235450158666155406">"لغو"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"انتخاب نوع اتصال"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"اگر یک آنتن خارجی به تنظیم‌کننده وصل است، «آنتن» را انتخاب کنید. اگر کانال‌های شما از یک ارائه‌دهنده خدمات کابلی ارائه می‌شوند، «کابل» را انتخاب کنید. اگر مطمئن نیستید، هر دو نوع اسکن می‌شوند اما بیشتر طول می‌کشد."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"آنتن"</item>
+ <item msgid="2670079958754180142">"کابل"</item>
+ <item msgid="36774059871728525">"مطمئن نیستم"</item>
+ <item msgid="6881204453182153978">"فقط برای برنامه‌نویسی"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"راه‌اندازی تنظیم‌کننده تلویزیون"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"‏راه‌اندازی تنظیم‌کننده کانال USB"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"راه‌اندازی تنظیم‌کننده کانال شبکه‌ای"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"ممکن است چند دقیقه طول بکشد"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"تنظیم‌کننده موقتاً دردسترس نیست یا در این لحظه در ضبط شدن استفاده می‌شود."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="one">‏%1$d کانال پیدا شد</item>
+ <item quantity="other">‏%1$d کانال پیدا شد</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"توقف اسکن کانال"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="one">‏%1$d کانال پیدا شد</item>
+ <item quantity="other">‏%1$d کانال پیدا شد</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="one">‏خوب است! در طول اسکن کانال %1$d کانال پیدا شد. اگر این تعداد درست به نظر نمی‌رسد، موقعیت آنتن را تنظیم کنید و دوباره اسکن کنید.</item>
+ <item quantity="other">‏خوب است! در طول اسکن کانال %1$d کانال پیدا شد. اگر این تعداد درست به نظر نمی‌رسد، موقعیت آنتن را تنظیم کنید و دوباره اسکن کنید.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"تمام"</item>
+ <item msgid="2480490326672924828">"اسکن دوباره"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"کانالی پیدا نشد"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"اسکن هیچ کانالی پیدا نکرد. مطمئن شوید تلویزیونتان به یک منبع سیگنال تلویزیونی متصل است. \n\nدر صورت استفاده از آنتن بی‌سیم، موقعیت یا جهت آن را تنظیم کنید. برای بهترین نتایج، آن را در جای بلند و نزدیک پنجره قرار دهید و دوباره اسکن کنید."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"‏اسکن هیچ کانالی پیدا نکرد. مطمئن شوید تنظیم‌کننده USB به منبع نیرو و منبع سیگنال تلویزیونی متصل است.\n\nدر صورت استفاده از آنتن بی‌سیم، موقعیت یا جهت آن را تنظیم کنید. برای بهترین نتایج، آن را در جای بلند و نزدیک پنجره قرار دهید و دوباره اسکن کنید."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"اسکن، کانالی پیدا نکرد. مطمئن شوید تنظیم‌کننده شبکه‌ای به برق و منبع سیگنال تلویزیونی وصل است.\n\nاگر از آنتن هوایی استفاده می‌کنید، موقعیت یا جهت آن را تنظیم کنید. برای بهترین نتایج، آن را در جای بلند و نزدیک پنجره قرار دهید و دوباره اسکن کنید."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"اسکن دوباره"</item>
+ <item msgid="2092797862490235174">"تمام"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"اسکن کانال‌های تلویزیون"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"راه‌اندازی تنظیم‌کننده تلویزیون"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"‏راه‌اندازی تنظیم‌کننده تلویزیون USB"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"راه‌اندازی تنظیم‌کننده تلویزیون شبکه‌ای"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"‏ارتباط تیونر USB تلویزیون قطع شد."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"ارتباط تیونر شبکه قطع شد."</string>
+</resources>
diff --git a/usbtuner-res/values-fi/strings.xml b/usbtuner-res/values-fi/strings.xml
new file mode 100644
index 00000000..4dabc97c
--- /dev/null
+++ b/usbtuner-res/values-fi/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"TV-viritin"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB-TV-viritin"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Antenni-TV-viritin (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Odota, että käsittely on valmis."</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Viritinohjelmisto on päivitetty äskettäin. Hae kanavat uudelleen."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Ota ääni käyttöön kytkemällä tilaääni päälle järjestelmän ääniasetuksissa."</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Äänen toistaminen ei onnistu. Yritä käyttää toista TV:tä."</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Kanavavirittimen määritys"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"TV-virittimen määritys"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB-kanavavirittimen määritys"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Antennivirittimen määritys"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Tarkista, että TV on liitetty TV-signaalilähteeseen.\n\nJos käytät antennia, useampien kanavien löytäminen saattaa edellyttää sen paikan tai suuntauksen säätämistä. Saat parhaan tuloksen asettamalla antennin korkealle ja lähelle ikkunaa."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Tarkista, että USB-viritin on kytketty oikein ja liitetty TV-signaalilähteeseen.\n\nJos käytät antennia, useampien kanavien löytäminen saattaa edellyttää sen paikan ja suuntauksen säätämistä. Saat parhaan tuloksen asettamalla antennin korkealle ja lähelle ikkunaa."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Tarkista, että viritin on päällä ja liitetty TV-signaalilähteeseen.\n\nJos käytät antennia, säädä sen paikkaa tai suuntausta. Aseta antenni korkealle ja lähelle ikkunaa, jotta saat parhaat tulokset, ja tee uusi haku."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Jatka"</item>
+ <item msgid="727245208787621142">"Ei nyt"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Haetaanko kanavia uudelleen?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Tämä poistaa TV-virittimen löytämät kanavat ja tekee kanavahaun uudelleen.\n\nTarkista, että TV on liitetty TV-signaalilähteeseen.\n\nJos käytät antennia, useampien kanavien löytäminen saattaa edellyttää sen paikan tai suuntauksen säätämistä. Saat parhaan tuloksen asettamalla antennin korkealle ja lähelle ikkunaa."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Tämä poistaa USB-virittimen löytämät kanavat ja tekee kanavahaun uudelleen.\n\nTarkista, että USB-viritin on kytketty oikein ja liitetty TV-signaalilähteeseen.\n\nJos käytät antennia, useampien kanavien löytäminen saattaa edellyttää sen paikan tai suuntauksen säätämistä. Saat parhaan tuloksen asettamalla antennin korkealle ja lähelle ikkunaa."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Tämä poistaa virittimen löytämät kanavat ja etsii kanavia uudestaan.\n\nTarkista, että viritin on päällä ja liitetty TV-signaalilähteeseen.\n\nJos käytät antennia, säädä sen paikkaa tai suuntausta. Aseta antenni korkealle ja lähelle ikkunaa, jotta saat parhaat tulokset, ja tee uusi haku."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Jatka"</item>
+ <item msgid="235450158666155406">"Peruuta"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Valitse yhteystyyppi"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Valitse Antenni, jos virittimeen on liitetty ulkoinen antenni. Valitse Kaapeli, jos kanavasi tulevat kaapelipalveluntarjoajalta. Jos et ole varma, haku tarkistaa molemmat tyypit, mutta se voi kestää kauemmin."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antenni"</item>
+ <item msgid="2670079958754180142">"Kaapeli"</item>
+ <item msgid="36774059871728525">"En ole varma"</item>
+ <item msgid="6881204453182153978">"Vain kehitystä varten"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"TV-virittimen määritys"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB-kanavavirittimen määritys"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Antennikanavavirittimen määritys"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Tämä voi kestää useita minuutteja."</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Viritin ei ole toistaiseksi käytettävissä tai se on nauhoitteen käytössä."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">%1$d kanavaa löytyi.</item>
+ <item quantity="one">%1$d kanava löytyi.</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"LOPETA KANAVAHAKU"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">%1$d kanavaa löytyi</item>
+ <item quantity="one">%1$d kanava löytyi</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Hienoa! Kanavahaussa löytyi %1$d kanavaa. Jos tämä tulos ei vaikuta oikealta, säädä antennin asentoa ja tee haku uudelleen.</item>
+ <item quantity="one">Hienoa! Kanavahaussa löytyi %1$d kanava. Jos tämä tulos ei vaikuta oikealta, säädä antennin asentoa ja tee haku uudelleen.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Valmis"</item>
+ <item msgid="2480490326672924828">"Hae uudelleen"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Kanavia ei löytynyt"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Haku ei löytänyt yhtään kanavaa. Tarkista, että TV on liitetty TV-signaalilähteeseen.\n\nJos käytät antennia, säädä sen paikkaa tai suuntausta. Saat parhaan tuloksen asettamalla antennin korkealle ja lähelle ikkunaa. Tee haku sitten uudelleen."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Haku ei löytänyt yhtään kanavaa. Tarkista, että USB-viritin on kytketty oikein ja liitetty TV-signaalilähteeseen.\n\nJos käytät antennia, säädä sen paikkaa tai suuntausta. Saat parhaan tuloksen asettamalla antennin korkealle ja lähelle ikkunaa. Tee haku sitten uudelleen."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Haussa ei löytynyt kanavia. Tarkista, että viritin on päällä ja liitetty TV-signaalilähteeseen.\n\nJos käytät antennia, säädä sen paikkaa tai suuntausta. Aseta antenni korkealle ja lähelle ikkunaa, jotta saat parhaat tulokset, ja tee uusi haku."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Hae uudelleen"</item>
+ <item msgid="2092797862490235174">"Valmis"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Hae TV-kanavia"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"TV-virittimen määritys"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB-TV-virittimen määritys"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Antenni-TV-virittimen määritys"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB-TV-viritin ei ole kytketty."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Verkkoviritin ei ole kytketty."</string>
+</resources>
diff --git a/usbtuner-res/values-fr-rCA/strings.xml b/usbtuner-res/values-fr-rCA/strings.xml
new file mode 100644
index 00000000..754649ae
--- /dev/null
+++ b/usbtuner-res/values-fr-rCA/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Syntoniseur télé"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"Syntoniseur télé USB"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Syntoniseur télé réseau (BÊTA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Veuillez patienter jusqu\'à la fin du traitement"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Le logiciel du syntoniseur a été mis à jour récemment. Veuillez rechercher les chaînes à nouveau."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Pour activer l\'audio, vous devez activer le son ambiophonique dans les paramètres sonores du système"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Impossible de lire l\'audio. Veuillez essayer sur un autre téléviseur."</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Configuration du syntoniseur de chaînes"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Configuration du syntoniseur télé"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Configurer les chaînes du syntoniseur USB"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Configuration du syntoniseur réseau"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Vérifiez que le téléviseur est connecté à la source d\'un signal de télévision.\n\nSi vous utilisez une antenne, vous devrez peut-être ajuster sa position ou son orientation pour recevoir le plus de chaînes possible. Pour obtenir les meilleurs résultats, placez-la dans une position élevée et près d\'une fenêtre."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Vérifiez que le syntoniseur USB est branché et connecté à la source d\'un signal de télévision.\n\nSi vous utilisez une antenne, ajustez sa position ou son orientation. Pour obtenir les meilleurs résultats, placez-la dans une position élevée et près d\'une fenêtre, puis relancez la recherche."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Assurez-vous que le syntoniseur réseau est allumé et connecté à une source de signal télé.\n\nSi vous utilisez une antenne, il se peut que vous deviez ajuster sa position ou sa direction pour capter un maximum de chaînes. Pour obtenir des résultats optimaux, placez-la en hauteur et près d\'une fenêtre."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Continuer"</item>
+ <item msgid="727245208787621142">"Pas maintenant"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Relancer la configuration de la chaîne?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Cette opération permet de supprimer les chaînes détectées du syntoniseur télé et d\'en rechercher de nouvelles.\n\nVérifiez que le téléviseur est connecté à la source d\'un signal de télévision.\n\nSi vous utilisez une antenne, vous devrez peut-être ajuster sa position ou son orientation pour recevoir le plus de chaînes possible. Pour obtenir les meilleurs résultats, placez-la dans une position élevée et près d\'une fenêtre."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Cette opération permet de supprimer les chaînes détectées du syntoniseur USB et d\'en rechercher de nouvelles.\n\nVérifiez que le syntoniseur USB est branché et connecté à la source d\'un signal de télévision.\n\nSi vous utilisez une antenne, vous devrez peut-être ajuster sa position ou son orientation pour recevoir le plus de chaînes possible. Pour obtenir les meilleurs résultats, placez-la dans une position élevée et près d\'une fenêtre."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Cela supprimera les chaînes trouvées du syntoniseur réseau et lancera une nouvelle recherche.\n\nAssurez-vous que le syntoniseur réseau est allumé et connecté à une source de signal télé.\n\nSi vous utilisez une antenne, il se peut que vous deviez ajuster sa position ou sa direction pour capter un maximum de chaînes. Pour obtenir des résultats optimaux, placez-la en hauteur et près d\'une fenêtre."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Continuer"</item>
+ <item msgid="235450158666155406">"Annuler"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Sélectionnez le type de connexion"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Sélectionnez l\'option « Antenne » si une antenne externe est connectée au syntoniseur, ou « Câble » si les chaînes sont fournies par un service de câble. Si vous n\'êtes pas sûr, vous pouvez effectuer la recherche sur ces deux types de connexion, mais cela risque de prendre plus de temps."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antenne"</item>
+ <item msgid="2670079958754180142">"Câble"</item>
+ <item msgid="36774059871728525">"Pas certain"</item>
+ <item msgid="6881204453182153978">"Developpement seulement"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Configuration du syntoniseur télé"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Configurer les chaînes du syntoniseur USB"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Configuration du syntoniseur de chaînes réseau"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Cela peut prendre plusieurs minutes"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Le syntoniseur n\'est pas accessible ou bien il est en cours d\'utilisation par l\'enregistreur."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="one">%1$d chaîne détectée</item>
+ <item quantity="other">%1$d chaînes détectées</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"ARRÊTER LA RECHERCHE DE CHAÎNES"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="one">%1$d chaîne détectée</item>
+ <item quantity="other">%1$d chaînes détectées</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="one">Excellent! %1$d chaînes ont été détectées pendant la recherche de chaînes. Si cela vous semble incorrect, essayez d\'ajuster la position de l\'antenne et d\'effectuer une nouvelle recherche.</item>
+ <item quantity="other">Excellent! %1$d chaînes ont été détectées pendant la recherche de chaînes. Si cela vous semble incorrect, essayez d\'ajuster la position de l\'antenne et d\'effectuer une nouvelle recherche.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Terminé"</item>
+ <item msgid="2480490326672924828">"Rechercher à nouveau"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Aucune chaîne"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"La recherche n\'a détecté aucune chaîne. Vérifiez que le téléviseur est connecté à la source d\'un signal de télévision.\n\nSi vous utilisez une antenne, ajustez sa position ou son orientation. Pour obtenir les meilleurs résultats, placez-la dans une position élevée et près d\'une fenêtre, puis relancez la recherche."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"La recherche n\'a détecté aucune chaîne. Vérifiez que le syntoniseur USB est branché et connecté à la source d\'un signal de télévision.\n\nSi vous utilisez une antenne, ajustez sa position ou son orientation. Pour obtenir les meilleurs résultats, placez-la dans une position élevée et près d\'une fenêtre, puis relancez la recherche."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"La recherche n\'a détecté aucune chaîne. Assurez-vous que le syntoniseur réseau est allumé et connecté à une source de signal télé.\n\nSi vous utilisez une antenne, ajustez sa position ou sa direction. Pour obtenir des résultats optimaux, placez-la en hauteur et près d\'une fenêtre, puis relancez la recherche."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Rechercher à nouveau"</item>
+ <item msgid="2092797862490235174">"Terminé"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Rechercher les chaînes de télévision"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Configuration du syntoniseur télé"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Configurer le syntoniseur télé USB"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Configuration du syntoniseur télé réseau"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"Le syntoniseur télé USB est déconnecté."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Le syntoniseur réseau est déconnecté."</string>
+</resources>
diff --git a/usbtuner-res/values-fr/strings.xml b/usbtuner-res/values-fr/strings.xml
new file mode 100644
index 00000000..3b4a6589
--- /dev/null
+++ b/usbtuner-res/values-fr/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Tuner TV"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"Tuner TV USB"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Tuner TV réseau (VERSION BÊTA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Veuillez patienter jusqu\'à la fin du traitement."</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Le logiciel du tuner a été mis à jour récemment. Veuillez lancer une nouvelle recherche des chaînes."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Activer le son surround dans les paramètres sonores du système pour activer l\'audio"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Impossible de lire le fichier audio. Veuillez utiliser un autre téléviseur"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Configuration du tuner de chaînes"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Configuration du tuner TV"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Configuration du tuner de chaînes USB"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Configuration du tuner réseau"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Vérifiez que le téléviseur est connecté à la source d\'un signal de télévision.\n\nSi vous utilisez une antenne Over The Air, vous devrez peut-être ajuster sa position ou son orientation pour recevoir le plus de chaînes possible. Pour obtenir les meilleurs résultats, placez-la dans une position élevée et près d\'une fenêtre."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Vérifiez que le tuner USB est branché et connecté à la source d\'un signal de télévision.\n\nSi vous utilisez une antenne Over The Air, ajustez sa position ou son orientation. Pour obtenir les meilleurs résultats, placez-la dans une position élevée et près d\'une fenêtre, puis relancez la recherche."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Vérifiez que le tuner réseau est allumé et connecté à la source d\'un signal de télévision.\n\nSi vous utilisez une antenne Over The Air, vous devrez peut-être ajuster sa position ou son orientation pour recevoir le plus de chaînes possible. Pour de meilleurs résultats, placez-la en hauteur et près d\'une fenêtre."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Continuer"</item>
+ <item msgid="727245208787621142">"Pas maintenant"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Relancer la configuration de la chaîne ?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Cette opération permet de supprimer les chaînes détectées du tuner TV et d\'en rechercher de nouvelles.\n\nVérifiez que le téléviseur est connecté à la source d\'un signal de télévision.\n\nSi vous utilisez une antenne Over The Air, vous devrez peut-être ajuster sa position ou son orientation pour recevoir le plus de chaînes possible. Pour obtenir les meilleurs résultats, placez-la dans une position élevée et près d\'une fenêtre."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Cette opération permet de supprimer les chaînes détectées du tuner USB et d\'en rechercher de nouvelles.\n\nVérifiez que le tuner USB est branché et connecté à la source d\'un signal de télévision.\n\nSi vous utilisez une antenne Over The Air, vous devrez peut-être ajuster sa position ou son orientation pour recevoir le plus de chaînes possible. Pour obtenir les meilleurs résultats, placez-la dans une position élevée et près d\'une fenêtre."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Cette opération permet de supprimer les chaînes détectées du tuner réseau et d\'en rechercher de nouvelles.\n\nVérifiez que le tuner réseau est allumé et connecté à la source d\'un signal de télévision.\n\nSi vous utilisez une antenne Over The Air, vous devrez peut-être ajuster sa position ou son orientation pour recevoir le plus de chaînes possible. Pour de meilleurs résultats, placez-la en hauteur et près d\'une fenêtre."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Continuer"</item>
+ <item msgid="235450158666155406">"Annuler"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Sélectionner le type de connexion"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Sélectionnez l\'option \"Antenne\" si une antenne externe est connectée au tuner, ou \"Câble\" si les chaînes sont fournies via un service de câble. Si vous n\'êtes pas sûr, vous pouvez effectuer la recherche sur ces deux types de connexion, mais cela risque de prendre plus de temps."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antenne"</item>
+ <item msgid="2670079958754180142">"Câble"</item>
+ <item msgid="36774059871728525">"Je ne sais pas"</item>
+ <item msgid="6881204453182153978">"Développement uniquement"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Configuration du tuner TV"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Configuration du tuner de chaînes USB"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Configuration du tuner de chaînes réseau"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Cette opération peut prendre plusieurs minutes."</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Le tuner est temporairement indisponible ou est déjà utilisé pour l\'enregistrement."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="one">%1$d chaîne a été détectée.</item>
+ <item quantity="other">%1$d chaînes ont été détectées.</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"ARRÊTER LA RECHERCHE DE CHAÎNES"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="one">%1$d chaîne a été détectée</item>
+ <item quantity="other">%1$d chaînes ont été détectées</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="one">Bravo ! %1$d chaîne a été détectée pendant la recherche de chaînes. Si cela vous semble incorrect, essayez d\'ajuster la position de l\'antenne et d\'effectuer une nouvelle recherche.</item>
+ <item quantity="other">Bravo ! %1$d chaînes ont été détectées pendant la recherche de chaînes. Si cela vous semble incorrect, essayez d\'ajuster la position de l\'antenne et d\'effectuer une nouvelle recherche.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"OK"</item>
+ <item msgid="2480490326672924828">"Rechercher à nouveau"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Aucune chaîne n\'a été détectée"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"La recherche n\'a détecté aucune chaîne. Vérifiez que le téléviseur est connecté à la source d\'un signal de télévision.\n\nSi vous utilisez une antenne Over The Air, ajustez sa position ou son orientation. Pour obtenir les meilleurs résultats, placez-la dans une position élevée et près d\'une fenêtre, puis relancez la recherche."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"La recherche n\'a détecté aucune chaîne. Vérifiez que le tuner USB est branché et connecté à la source d\'un signal de télévision.\n\nSi vous utilisez une antenne Over The Air, ajustez sa position ou son orientation. Pour obtenir les meilleurs résultats, placez-la dans une position élevée et près d\'une fenêtre, puis relancez la recherche."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"La recherche n\'a détecté aucune chaîne. Vérifiez que le tuner réseau est allumé et connecté à la source d\'un signal de télévision.\n\nSi vous utilisez une antenne Over The Air, ajustez sa position ou son orientation. Pour de meilleurs résultats, placez-la en hauteur et près d\'une fenêtre, puis relancez la recherche."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Rechercher à nouveau"</item>
+ <item msgid="2092797862490235174">"OK"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Rechercher les chaînes de télévision"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Configuration du tuner TV"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Configuration du tuner TV USB"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Configuration du tuner TV réseau"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"Le tuner TV USB est déconnecté."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Tuner réseau déconnecté."</string>
+</resources>
diff --git a/usbtuner-res/values-gl-rES/strings.xml b/usbtuner-res/values-gl-rES/strings.xml
new file mode 100644
index 00000000..4c75fc65
--- /dev/null
+++ b/usbtuner-res/values-gl-rES/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Sintonizador de televisión"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"Sintonizador USB de televisión"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Sintonizador de televisión de rede (beta)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Espera a que finalice o procesamento"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"O software do sintonizador actualizouse recentemente. Volve buscar canles."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Activa o son envolvente na configuración de son do sistema para activar o audio"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Non se pode reproducir o audio. Proba con outra televisión"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Configuración do sintonizador de canles"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Configuración do sintonizador de televisión"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Configuración do sintonizador de canles USB"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Configuración do sintonizador de rede"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Comproba que a televisión está conectada a unha fonte de sinal de televisión.\n\nSe usas unha antena sen fíos, é posible que teñas que axustar a súa posición ou dirección para recibir a maioría das canles. Para conseguir os mellores resultados, colócaa nun lugar alto e preto dunha ventá."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Comproba que o sintonizador USB está enchufado e conectado a unha fonte de sinal de televisión.\n\nSe usas unha antena sen fíos, é posible que teñas que axustar a súa posición ou dirección para recibir a maioría das canles. Para conseguir os mellores resultados, colócaa nun lugar alto e preto dunha ventá."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Verifica que o sintonizador de rede estea acendido e conectado a unha fonte de sinal de televisión.\n\nSe usas unha antena sen fíos, é posible que teñas que axustar a súa posición ou dirección para recibir a maioría das canles. Para conseguir os mellores resultados, colócaa nun lugar alto e preto dunha ventá."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Continuar"</item>
+ <item msgid="727245208787621142">"Agora non"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Queres volver executar a configuración da canle?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Esta acción eliminará as canles que atopaches co sintonizador de televisión e buscará outras novas.\n\nComproba que a televisión está conectada a unha fonte de sinal de televisión.\n\nSe usas unha antena sen fíos, é posible que teñas que axustar a súa posición ou dirección para recibir a maioría das canles. Para conseguir os mellores resultados, colócaa nun lugar alto e preto dunha ventá."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Esta acción eliminará as canles que atopaches co sintonizador USB e buscará outras novas.\n\nComproba que o sintonizador USB está enchufado e conectado a unha fonte de sinal de televisión.\n\nSe usas unha antena sen fíos, é posible que teñas que axustar a súa posición ou dirección para recibir a maioría das canles. Para conseguir os mellores resultados, colócaa nun lugar alto e preto dunha ventá."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Con esta acción quitaranse as canles atopadas do teu sintonizador de rede e buscaranse novas canles outra vez.\n\nVerifica que o sintonizador de rede estea acendido e conectado a unha fonte de sinal de televisión.\n\n}Se usas unha antena sen fíos, é posible que teñas que axustar a súa posición ou dirección para recibir a maioría das canles. Para conseguir os mellores resultados, colócaa nun lugar alto e preto dunha ventá."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Continuar"</item>
+ <item msgid="235450158666155406">"Cancelar"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Seleccionar tipo de conexión"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Selecciona Antena se hai unha antena externa conectada ao sintonizador. Selecciona Cable se as túas canles proceden dun fornecedor de servizo de cable. Se non o sabes con seguridade, realizarase a busca usando os dous tipos de conexión, pero este proceso pode tardar máis tempo."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antena"</item>
+ <item msgid="2670079958754180142">"Cable"</item>
+ <item msgid="36774059871728525">"Non estou seguro"</item>
+ <item msgid="6881204453182153978">"Só desenvolvemento"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Configuración do sintonizador de televisión"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Configuración do sintonizador de canles USB"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Configuración do sintonizador de canles de rede"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Esta acción pode tardar varios minutos"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"O sintonizador non está dispoñible temporalmente ou xa se utiliza para unha gravación."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">Atopáronse %1$d canles</item>
+ <item quantity="one">Atopouse %1$d canle</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"DETER BUSCA DE CANLES"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">Atopáronse %1$d canles</item>
+ <item quantity="one">Atopouse %1$d canle</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Estupendo! Atopáronse %1$d canles durante a busca de canles. Se non che parece correcto, tenta axustar a posición da antena e realiza a busca de novo.</item>
+ <item quantity="one">Estupendo! Atopouse %1$d canle durante a busca de canles. Se non che parece correcto, tenta axustar a posición da antena e realiza a busca de novo.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Feito"</item>
+ <item msgid="2480490326672924828">"Buscar de novo"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Non se atopou ningunha canle"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Durante a busca non se atopou ningunha canle. Comproba que a televisión está conectada a unha fonte de sinal de televisión.\n\nSe usas unha antena sen fíos, axusta a súa posición ou dirección. Para conseguir os mellores resultados, colócaa nun lugar alto, preto dunha ventá e realiza a fai a busca de novo."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"A busca non atopou ningunha canle. Comproba que o sintonizador USB está enchufado e conectado a unha fonte de sinal de televisión.\n\nSe usas unha antena sen fíos, axusta a súa posición ou dirección. Para conseguir os mellores resultados, colócaa nun lugar alto, preto dunha ventá e realiza a busca de novo."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"A busca de canles non obtivo resultados. Verifica que o sintonizador de rede estea acendido e conectado a unha fonte de sinal de televisión.\n\nSe usas unha antena sen fíos, axusta a súa posición ou dirección. Para conseguir os mellores resultados, colócaa nun lugar alto, preto dunha ventá, e realiza a busca de novo."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Buscar de novo"</item>
+ <item msgid="2092797862490235174">"Feito"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Buscar canles de televisión"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Configuración do sintonizador de televisión"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Configuración do sintonizador USB de televisión"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Configuración do sintonizador de televisión de rede"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"Desconectouse o sintonizador de televisión USB."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Desconectouse o sintonizador de rede."</string>
+</resources>
diff --git a/usbtuner-res/values-hi/strings.xml b/usbtuner-res/values-hi/strings.xml
new file mode 100644
index 00000000..265670e7
--- /dev/null
+++ b/usbtuner-res/values-hi/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"टीवी ट्यूनर"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB टीवी ट्यूनर"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"नेटवर्क टीवी ट्यूनर (बीटा)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"कृपया प्रक्रिया पूरी होने का इंतज़ार करें"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"ट्यूनर सॉफ़्टवेयर को हाल ही में अपडेट किया गया है. कृपया चैनलों के लिए दोबारा स्कैन करें."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"ऑडियो सक्षम करने के लिए सिस्टम साउंड सेटिंग में सराउंड साउंड सक्षम करें"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"ऑडियो नहीं चल पा रहा है. कृपया कोई दूसरा टीवी आज़माएं"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"चैनल ट्यूनर सेटअप"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"टीवी ट्यूनर सेटअप"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB चैनल ट्यूनर सेटअप"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"नेटवर्क ट्यूनर सेटअप"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"पुष्टि करें कि आपका टीवी किसी टीवी सिग्नल स्रोत से कनेक्ट किया हुआ है.\n\nयदि ओवर द एयर एंटेना का उपयोग कर रहे हैं, तो अधिकांश चैनल पाने के लिए आपको उसकी स्थिति या दिशा समायोजित करने की आवश्यकता हो सकती है. सबसे अच्छे परिणामों के लिए, उसे ऊंचाई पर और किसी खिड़की के पास लगाएं."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"पुष्टि करें कि USB ट्यूनर प्लग इन है और टीवी सिग्नल स्रोत से कनेक्ट किया हुआ है.\n\nयदि आप ओवर द एयर एंटेना का उपयोग कर रहे हैं, तो अधिकांश चैनल पाने के लिए आपको उसकी स्थिति या दिशा समायोजित करने की आवश्यकता हो सकती है. अच्छे परिणामों के लिए, उसे ऊंचाई पर और किसी खिड़की के पास लगाएं."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"सत्यापित करें कि नेटवर्क ट्यूनर चालू है और किसी टीवी सिग्नल स्रोत से कनेक्ट है.\n\nयदि किसी ओवर-द-एयर एंटेना का उपयोग कर रहे हैं, तो अधिकांश चैनल प्राप्त करने के लिए आपको एंटेना का स्थान या दिशा समायोजित करनी पड़ सकती है. सर्वश्रेष्ठ परिणामों के लिए, उसे ऊंचाई पर और किसी खिड़की के पास रखें."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"जारी रखें"</item>
+ <item msgid="727245208787621142">"अभी नहीं"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"चैनल सेटअप फिर से चलाएं?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"इससे टीवी ट्यूनर से मिले चैनल निकल जाएंगे और नए चैनल दोबारा स्कैन किए जाएंगे.\n\nपुष्टि करें कि आपका टीवी किसी टीवी सिग्नल स्रोत से कनेक्ट किया हुआ है.\n\nयदि ओवर द एयर एंटेना का उपयोग कर रहे हैं, तो अधिकांश चैनल पाने के लिए आपको उसकी स्थिति या दिशा समायोजित करने की आवश्यकता हो सकती है. सबसे अच्छे परिणामों के लिए, उसे ऊंचाई पर और किसी खिड़की के पास लगाएं."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"इससे USB ट्यूनर से मिले चैनल निकल जाएंगे और नए चैनलों के लिए फिर से स्कैन किया जाएगा.\n\nपुष्टि करें कि USB ट्यूनर प्लग इन है और टीवी सिग्नल स्रोत से कनेक्ट किया हुआ है.\n\nयदि आप ओवर द एयर एंटेना का उपयोग कर रहे हैं, तो अधिकांश चैनल पाने के लिए आपको उसकी स्थिति या दिशा समायोजित करने की आवश्यकता हो सकती है. अच्छे परिणामों के लिए, उसे ऊंचाई पर और किसी खिड़की के पास लगाएं."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"ऐसा करने से नेटवर्क ट्यूनर से मिले चैनल निकाल दिए जाएंगे और नए चैनल के लिए फिर से स्कैन किया जाएगा.\n\nसत्यापित करें कि नेटवर्क ट्यूनर चालू है और किसी टीवी सिग्नल स्रोत से कनेक्ट है.\n\nयदि किसी ओवर-द-एयर एंटेना का उपयोग कर रहे हैं, तो अधिकांश चैनल प्राप्त करने के लिए आपको एंटेना का स्थान या दिशा समायोजित करनी पड़ सकती है. सर्वश्रेष्ठ परिणामों के लिए, उसे ऊंचाई पर और किसी खिड़की के पास रखें."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"जारी रखें"</item>
+ <item msgid="235450158666155406">"रद्द करें"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"कनेक्शन का प्रकार चुनें"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"यदि ट्यूनर से कोई बाहरी एंटेना कनेक्ट है, तो एंटेना चुनें. यदि आपके चैनल किसी केबल सेवा प्रदाता से आते हैं, तो केबल चुनें. यदि आप सुनिश्चित नहीं हैं, तो दोनों प्रकारों को स्कैन किया जाएगा, लेकिन इसमें अधिक समय लग सकता है."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"एंटेना"</item>
+ <item msgid="2670079958754180142">"केबल"</item>
+ <item msgid="36774059871728525">"सुनिश्चित नहीं हैं"</item>
+ <item msgid="6881204453182153978">"केवल डेवलपमेंट"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"टीवी ट्यूनर सेटअप"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB चैनल ट्यूनर सेटअप"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"नेटवर्क चैनल ट्यूनर सेटअप"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"इसमें कुछ मिनट लग सकते हैं"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"ट्यूनर अस्थायी रूप से उपलब्ध नहीं है या रिकॉर्डिंग में उसका उपयोग पहले ही हो रहा है."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="one">%1$d चैनल मिले</item>
+ <item quantity="other">%1$d चैनल मिले</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"चैनल स्कैन रोकें"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="one">%1$d चैनल मिले</item>
+ <item quantity="other">%1$d चैनल मिले</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="one">बढ़िया! चैनल स्कैन करने के दौरान %1$d चैनल मिले. यदि यह सही नहीं लग रहा है, तो एंटेना की स्थिति समायोजित करके देखें और दोबारा स्कैन करें.</item>
+ <item quantity="other">बढ़िया! चैनल स्कैन करने के दौरान %1$d चैनल मिले. यदि यह सही नहीं लग रहा है, तो एंटेना की स्थिति समायोजित करके देखें और दोबारा स्कैन करें.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"हो गया"</item>
+ <item msgid="2480490326672924828">"दोबारा स्‍कैन करें"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"कोई चैनल नहीं मिला"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"स्कैन करने से कोई भी चैनल नहीं मिला. पुष्टि करें कि आपका टीवी किसी टीवी सिग्नल स्रोत से कनेक्ट किया हुआ है.\n\nयदि ओवर द एयर एंटेना का उपयोग कर रहे हैं, तो उसकी स्थिति या दिशा समायोजित करें. सबसे अच्छे परिणामों के लिए, उसे ऊंचाई पर और किसी खिड़की के पास लगाएं और दोबारा स्कैन करें."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"स्कैन करने से कोई चैनल नहीं मिला. पुष्टि करें कि USB ट्यूनर प्लग इन है और टीवी सिग्नल स्रोत से कनेक्ट किया हुआ है.\n\nयदि आप ओवर द एयर एंटेना का उपयोग कर रहे हैं, तो उसकी स्थिति या दिशा समायोजित करें. अच्छे परिणामों के लिए, उसे ऊंचाई पर और किसी खिड़की के पास लगाएं और दोबारा स्कैन करें."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"स्कैन में कोई चैनल नहीं मिला. सत्यापित करें कि नेटवर्क ट्यूनर चालू है और किसी टीवी संकेत स्रोत से कनेक्ट है.\n\nयदि किसी ओवर-द-एयर एंटेना का उपयोग कर रहे हैं, तो उसका स्थान या दिशा समायोजित करें. सर्वश्रेष्ठ परिणामों के लिए, उसे ऊंचाई पर और किसी खिड़की के पास रखें और फिर से स्कैन करें."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"दोबारा स्‍कैन करें"</item>
+ <item msgid="2092797862490235174">"हो गया"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"टीवी चैनलों के लिए स्‍कैन करें"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"टीवी ट्यूनर सेटअप"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB टीवी ट्यूनर सेटअप"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"नेटवर्क टीवी ट्यूनर सेटअप"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB टीवी ट्यूनर डिसकनेक्ट किया गया."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"नेटवर्क ट्यूनर डिसकनेक्ट किया गया."</string>
+</resources>
diff --git a/usbtuner-res/values-hr/strings.xml b/usbtuner-res/values-hr/strings.xml
new file mode 100644
index 00000000..42f5c3aa
--- /dev/null
+++ b/usbtuner-res/values-hr/strings.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"TV prijemnik"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB TV prijemnik"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Mrežni TV prijemnik (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Pričekajte da obrada završi"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Softver prijemnika nedavno je ažuriran. Ponovite traženje kanala."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Omogućite okružujući zvuk u postavkama zvuka na razini sustava da biste omogućili audio"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Zvuk se ne može reproducirati. Pokušajte s drugim televizorom"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Postavljanje prijemnika kanala"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Postavljanje TV prijemnika"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Postavljanje USB prijemnika za kanale"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Postavljanje mrežnog prijemnika"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Provjerite je li televizor povezan s izvorom televizijskog signala.\n\nAko upotrebljavate antenu zemaljske televizije, možda ćete joj morati promijeniti položaj ili smjer da biste pronašli najviše kanala. Za najbolje rezultate postavite je visoko i u blizini prozora."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Provjerite je li USB prijemnik priključen i povezan s izvorom TV signala.\n\nAko upotrebljavate antenu zemaljske televizije, možda trebate prilagoditi njezin položaj ili smjer da biste primali najviše kanala. Za najbolje rezultate postavite je visoko i u blizini prozora."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Provjerite je li mrežni prijemnik uključen i povezan s izvorom TV signala.\n\nAko upotrebljavate bežičnu antenu, možda ćete trebati prilagoditi položaj ili smjer da biste pronašli najviše kanala. Za najbolje rezultate postavite je visoko i blizu prozora."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Nastavi"</item>
+ <item msgid="727245208787621142">"Ne sada"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Želite li ponovo pokrenuti postavljanje kanala?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Time će se ukloniti kanali pronađeni pomoću TV prijemnika i ponovo pokrenuti pretraživanje kanala.\n\nProvjerite je li televizor povezan s izvorom televizijskog signala.\n\nAko upotrebljavate antenu zemaljske televizije, možda ćete joj morati promijeniti položaj ili smjer da biste pronašli najviše kanala. Za najbolje rezultate postavite je visoko i u blizini prozora."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Time će se ukloniti kanali pronađeni putem USB prijemnika i ponoviti pretraživanje kanala.\n\nProvjerite je li USB prijemnik priključen i povezan s izvorom televizijskog signala.\n\nAko upotrebljavate antenu zemaljske televizije, možda trebate prilagoditi njezin položaj ili smjer da biste primali najviše kanala. Za najbolje rezultate postavite je visoko i u blizini prozora."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Time će se ukloniti kanali pronađeni mrežnim prijemnikom i pokrenuti pretraživanje novih kanala.\n\nProvjerite je li mrežni prijemnik uključen i povezan s izvorom TV signala.\n\nAko upotrebljavate bežičnu antenu, možda ćete trebati prilagoditi položaj ili smjer da biste pronašli najviše kanala. Za najbolje rezultate postavite je visoko i blizu prozora."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Nastavi"</item>
+ <item msgid="235450158666155406">"Odustani"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Odaberite vrstu veze"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Ako je s prijemnikom povezana vanjska antena, odaberite opciju Antena. Ako gledate kanale s kabelske televizije, odaberite opciju Kabel. Ako niste sigurni, pretražit će se obje vrste, no to može trajati dulje."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antena"</item>
+ <item msgid="2670079958754180142">"Kabel"</item>
+ <item msgid="36774059871728525">"Nisam siguran"</item>
+ <item msgid="6881204453182153978">"Samo razvoj"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Postavljanje TV prijemnika"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Postavljanje USB prijemnika za kanale"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Postavljanje prijemnika za mrežne kanale"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"To može potrajati nekoliko minuta"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Prijemnik trenutačno nije dostupan ili se već upotrebljava za snimanje."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="one">Pronađen je %1$d kanal</item>
+ <item quantity="few">Pronađena su %1$d kanala</item>
+ <item quantity="other">Pronađeno je %1$d kanala</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"ZAUSTAVI PRETRAŽIVANJE KANALA"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="one">Pronađen je %1$d kanal</item>
+ <item quantity="few">Pronađena su %1$d kanala</item>
+ <item quantity="other">Pronađeno je %1$d kanala</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="one">Lijepo! Tijekom pretraživanja kanala pronađen je %1$d kanal. Ako mislite da to nije u redu, promijenite položaj antene i pretražite ponovo.</item>
+ <item quantity="few">Lijepo! Tijekom pretraživanja kanala pronađena su %1$d kanala. Ako mislite da to nije u redu, promijenite položaj antene i pretražite ponovo.</item>
+ <item quantity="other">Lijepo! Tijekom pretraživanja kanala pronađeno je %1$d kanala. Ako mislite da to nije u redu, promijenite položaj antene i pretražite ponovo.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Gotovo"</item>
+ <item msgid="2480490326672924828">"Pretraži ponovo"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Nije pronađen nijedan kanal"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Tijekom pretraživanja nije pronađen nijedan kanal. Provjerite je li televizor povezan s izvorom televizijskog signala.\n\nAko upotrebljavate antenu zemaljske televizije, promijenite joj položaj ili smjer. Za najbolje rezultate postavite je visoko i u blizini prozora, a zatim pretražite ponovo."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Pretraživanjem nije pronađen nijedan kanal. Provjerite je li USB prijemnik priključen i povezan s izvorom televizijskog signala.\n\nAko upotrebljavate antenu zemaljske televizije, prilagodite joj položaj ili smjer. Za najbolje rezultate postavite je visoko i u blizini prozora i pretražite ponovo."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Nije pronađen nijedan kanal. Provjerite je li mrežni prijemnik uključen i povezan s izvorom TV signala.\n\nAko upotrebljavate bežičnu antenu, prilagodite položaj ili smjer. Za najbolje rezultate postavite je visoko i blizu prozora i pretražite ponovo."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Pretraži ponovo"</item>
+ <item msgid="2092797862490235174">"Gotovo"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Pretražite TV kanale"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Postavljanje TV prijemnika"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Postavljanje USB TV prijemnika"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Postavljanje mrežnog TV prijemnika"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB TV prijemnik isključen."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Mrežni prijemnik isključen."</string>
+</resources>
diff --git a/usbtuner-res/values-hu/strings.xml b/usbtuner-res/values-hu/strings.xml
new file mode 100644
index 00000000..0d83fe31
--- /dev/null
+++ b/usbtuner-res/values-hu/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Tévétuner"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB-s tévétuner"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Hálózati tévétuner (BÉTA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Kérjük, várja meg a folyamat befejezését"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"A tuner szoftverét nemrég frissítették. Kérjük, ismételje meg a csatornakeresést."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"A hang aktiválásához engedélyezze a térhatású hangot a rendszerszintű hangbeállításokban"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"A hangot nem lehet lejátszani. Kérjük, próbálkozzon másik tévén"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Csatornatuner beállítása"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Tévétuner beállítása"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB-s csatornatuner beállítása"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Hálózati tuner beállítása"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Ellenőrizze, hogy tévéje csatlakoztatva van-e a televíziós jelforráshoz.\n\nAntenna használata esetén szükség lehet az elhelyezés, illetve az irány módosítására a lehető legtöbb csatorna befogásához. A legjobb eredmény érdekében helyezze magasra és ablak közelébe."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Győződjön meg arról, hogy az USB-tuner be van dugva, és csatlakoztatva van a televíziós jelforráshoz.\n\nAntenna használata esetén szükség lehet az elhelyezés, illetve irány módosítására a lehető legtöbb csatorna befogásához. A legjobb eredmény érdekében helyezze magasra és ablak közelébe."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Ellenőrizze, hogy a hálózati tuner be van-e kapcsolva, és csatlakozik-e televíziós jelforráshoz.\n\nHa antennát használ, módosítsa az elhelyezkedését, illetve irányát, hogy minél több csatornát fogjon. A legjobb eredmény érdekében helyezze magasra és ablak közelébe."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Folytatás"</item>
+ <item msgid="727245208787621142">"Most nem"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Újra végrehajtja a csatornabeállítást?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Ezzel eltávolítja a tévétuner segítségével megtalált csatornákat, és új csatornakeresést indít.\n\nEllenőrizze, hogy tévéje csatlakoztatva van-e a televíziós jelforráshoz.\n\nAntenna használata esetén szükség lehet az elhelyezés, illetve az irány módosítására a lehető legtöbb csatorna befogásához. A legjobb eredmény érdekében helyezze magasra és ablak közelébe."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Ezzel eltávolítja a már megtalált csatornákat az USB-tunerről, és újból elvégzi a csatornakeresést.\n\nGyőződjön meg arról, hogy az USB-tuner be van dugva, és csatlakoztatva van a televíziós jelforráshoz.\n\nAntenna használata esetén szükség lehet az elhelyezés, illetve irány módosítására a lehető legtöbb csatorna befogásához. A legjobb eredmény érdekében helyezze magasra és ablak közelébe."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Ezzel eltávolítja a hálózati tuner által talált csatornákat, és újabb csatornakeresést indít el.\n\nEllenőrizze, hogy a hálózati tuner be van-e kapcsolva, és csatlakozik-e televíziós jelforráshoz.\n\nHa antennát használ, módosítsa az elhelyezkedését, illetve irányát, hogy minél több csatornát fogjon. A legjobb eredmény érdekében helyezze magasra és ablak közelébe."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Folytatás"</item>
+ <item msgid="235450158666155406">"Mégse"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Válassza ki a csatlakozás típusát"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Válassza az „Antenna” lehetőséget, ha a tunerhez külső antenna csatlakozik. Válassza a „Kábel” lehetőséget, ha a csatornákat kábelszolgáltató biztosítja. Ha nem biztos egyikben sem, akkor a rendszer elvégzi mindkét típusú keresést, azonban elképzelhető, hogy ez tovább tart."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antenna"</item>
+ <item msgid="2670079958754180142">"Kábel"</item>
+ <item msgid="36774059871728525">"Nem tudom"</item>
+ <item msgid="6881204453182153978">"Csak fejlesztés"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Tévétuner beállítása"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB-s csatornatuner beállítása"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Hálózati csatornatuner beállítása"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Ez néhány percet is igénybe vehet"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"A tuner átmenetileg nem áll rendelkezésre, vagy már fel lett használva a felvétel során."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">%1$d csatorna észlelve</item>
+ <item quantity="one">%1$d csatorna észlelve</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"CSATORNAKERESÉS LEÁLLÍTÁSA"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">%1$d csatorna észlelve</item>
+ <item quantity="one">%1$d csatorna észlelve</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Remek! A rendszer %1$d csatornát talált a keresés során. Ha ez nem tűnik megfelelőnek, állítson az antenna helyzetén, majd végezze el újra a keresést.</item>
+ <item quantity="one">Remek! A rendszer %1$d csatornát talált a keresés során. Ha ez nem tűnik megfelelőnek, állítson az antenna helyzetén, majd végezze el újra a keresést.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Kész"</item>
+ <item msgid="2480490326672924828">"Keresés újra"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Nem található csatorna"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"A keresés nem talált csatornát. Ellenőrizze, hogy tévéje csatlakoztatva van-e a televíziós jelforráshoz.\n\nAntenna használata esetén módosítsa annak elhelyezését, illetve irányát. A legjobb eredmény érdekében helyezze magasra és ablak közelébe, majd ismételje meg a keresést."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"A keresés nem talált csatornát. Győződjön meg arról, hogy az USB-tuner be van dugva, és csatlakoztatva van a televíziós jelforráshoz.\n\nHa antennát használ, állítson annak helyzetén, illetve irányán. A legjobb eredmény érdekében helyezze magasra és ablak közelébe, majd ismételje meg a keresést."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"A rendszer nem talált egyetlen csatornát sem. Ellenőrizze, hogy a hálózati tuner be van-e kapcsolva, és csatlakozik-e televíziós jelforráshoz.\n\nHa antennát használ, módosítsa az elhelyezkedését, illetve irányát. A legjobb eredmény érdekében helyezze magasra és ablak közelébe, majd ismételje meg a keresést."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Keresés újra"</item>
+ <item msgid="2092797862490235174">"Kész"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Tévécsatornák keresése"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Tévétuner beállítása"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB-s tévétuner beállítása"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Hálózati tévétuner beállítása"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"Megszakadt a kapcsolat az USB-s tévétunerrel."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Megszakadt a kapcsolat a hálózati tunerrel."</string>
+</resources>
diff --git a/usbtuner-res/values-hy-rAM/strings.xml b/usbtuner-res/values-hy-rAM/strings.xml
new file mode 100644
index 00000000..2d3080c1
--- /dev/null
+++ b/usbtuner-res/values-hy-rAM/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Հեռուստակարգավորիչ"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB հեռուստակարգավորիչ"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Ցանցային հեռուստաընդունիչ (ԲԵՏԱ)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Սպասեք՝ մինչ որոնումը ավարտվի"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Ընդունիչի ծրագրակազմը վերջերս թարմացվել է: Նորից որոնեք ալիքները:"</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Ձայնը միացնելու համար համակարգի ձայնի կարգավորումներում ակտիվացրեք ծավալային ձայնը"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Հնարավոր չէ վերարտադրել ձայնը: Փորձեք մեկ այլ հեռուստացույց:"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Ալիքների կարգավորիչի տեղադրում"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Հեռուստակարգավորիչի տեղադրում"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Ալիքների USB կարգավորիչի տեղադրում"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Ցանցային ընդունիչի կարգավորում"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Համոզվեք, որ հեռուստացույցը միացված է հեռուստատեսային ազդանշանի աղբյուրին:\n\nԵթերային ալեհավաք օգտագործելիս հնարավոր է՝ անհրաժեշտ լինի կարգավորել դրա դիրքն ու ուղղությունը՝ ավելի շատ ալիքներ գտնելու համար: Լավագույն արդյունքներն ապահովելու համար այն դրեք բարձր տեղում՝ պատուհանի մոտ:"</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Համոզվեք, որ USB կարգավորիչը միացված է ցանցին և հեռուստատեսային ազդանշանի աղբյուրին:\n\nԵթերային ալեհավաք օգտագործելիս հնարավոր է՝ անհրաժեշտ լինի կարգավորել դրա դիրքն ու ուղղությունը՝ ավելի շատ ալիքներ գտնելու համար: Լավագույն արդյունքներն ապահովելու համար այն դրեք բարձր տեղում՝ պատուհանի մոտ:"</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Համոզվեք, որ ցանցային ընդունիրչը միացված է և կապակցված հեռուստատեսային ազդանշանի աղբյուրին:\n\nԵթերային ալեհավաք օգտագործելիս հնարավոր է՝ անհրաժեշտ լինի կարգավորել դրա դիրքն ու ուղղությունը՝ ավելի շատ ալիքներ գտնելու համար: Լավագույն արդյունքներն ապահովելու համար այն դրեք բարձր տեղում՝ պատուհանի մոտ:"</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Շարունակել"</item>
+ <item msgid="727245208787621142">"Ոչ հիմա"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Կրկի՞ն կարգավորել ալիքները:"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Այս գործողության արդյունքում կհեռացվեն հեռուստակարգավորիչից ստացված ալիքները և կկատարվի ալիքների նոր որոնում:\n\nՀամոզվեք, որ հեռուստացույցը միացված է հեռուստատեսային ազդանշանի աղբյուրին:\n\nԵթերային ալեհավաք օգտագործելիս հնարավոր է՝ անհրաժեշտ լինի կարգավորել դրա դիրքն ու ուղղությունը՝ ավելի շատ ալիքներ գտնելու համար: Լավագույն արդյունքներն ապահովելու համար այն դրեք բարձր տեղում՝ պատուհանի մոտ:"</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Այս գործողության արդյունքում կհեռացվեն USB կարգավորիչից ստացված ալիքները և կկատարվի ալիքների նոր որոնում:\n\nՀամոզվեք, որ USB կարգավորիչը միացված է ցանցին և հեռուստատեսային ազդանշանի աղբյուրին:\n\nԵթերային ալեհավաք օգտագործելիս հնարավոր է՝ անհրաժեշտ լինի կարգավորել դրա դիրքն ու ուղղությունը՝ ավելի շատ ալիքներ գտնելու համար: Լավագույն արդյունքներն ապահովելու համար այն դրեք բարձր տեղում՝ պատուհանի մոտ:"</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Այս գործողության արդյունքում կհեռացվեն ցանցային ընդունիչից ստացված ալիքները և կկատարվի ալիքների նոր որոնում:\n\nՀամոզվեք, որ ցանցային ընդունիչը միացված է և կապակցված հեռուստատեսային ազդանշանի աղբյուրին:\n\nԵթերային ալեհավաք օգտագործելիս հնարավոր է՝ անհրաժեշտ լինի կարգավորել դրա դիրքն ու ուղղությունը՝ ավելի շատ ալիքներ գտնելու համար: Լավագույն արդյունքներն ապահովելու համար այն դրեք բարձր տեղում՝ պատուհանի մոտ:"</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Շարունակել"</item>
+ <item msgid="235450158666155406">"Չեղարկել"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Ընտրեք միացման տեսակը"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Եթե ընդունիչին միացված է արտաքին ալեհավաք, ապա ընտրեք Ալեհավաքը: Եթե ալիքների ազդանշանը ստանում եք մալուխային հեռուստաընկերությունից, ապա ընտրեք Մալուխը: Եթե համոզված չեք, ապա կարող եք որոնել երկու տեսակն էլ, սակայն դա ավելի երկար կտևի:"</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Ալեհավաք"</item>
+ <item msgid="2670079958754180142">"Մալուխ"</item>
+ <item msgid="36774059871728525">"Չգիտեմ"</item>
+ <item msgid="6881204453182153978">"Միայն մշակման"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Հեռուստակարգավորիչի տեղադրում"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Ալիքների USB կարգավորիչի տեղադրում"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Ցանցային ալիքների ընդունիչի տեղադրում"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Դա կարող է տևել մի քանի րոպե"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Ընդունիչը ժամանակավորապես անհասանելի է կամ արդեն օգտագործվում է տեսագրելու համար:"</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="one">%1$d channels found</item>
+ <item quantity="other">Գտնվել է %1$d ալիք</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"ԴԱԴԱՐԵՑՆԵԼ ԱԼԻՔՆԵՐԻ ՈՐՈՆՈՒՄԸ"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="one">%1$d channels found</item>
+ <item quantity="other">Գտնվել է %1$d ալիք</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="one">Nice! %1$d channels were found during the channel scan. If this doesn’t seem right, try adjusting the antenna position and scan again.</item>
+ <item quantity="other">Գերազանց է: Ալիքների որոնման արդյունքում գտնվել է %1$d ալիք: Եթե դա բավարար չէ, փորձեք փոխել ալեհավաքի դիրքը և որոնել նորից:</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Պատրաստ է"</item>
+ <item msgid="2480490326672924828">"Կրկին որոնել"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Ալիքներ չեն գտնվել"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Որոնման արդյունքում ալիքներ չեն գտնվել: Համոզվեք, որ հեռուստացույցը միացված է հեռուստատեսային ազդանշանի աղբյուրին:\n\nԵթերային ալեհավաք օգտագործելիս կարգավորեք դրա դիրքն ու ուղղությունը: Լավագույն արդյունքներն ապահովելու համար այն դրեք բարձր տեղում՝ պատուհանի մոտ, ապա որոնեք նորից:"</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Որոնման արդյունքում ալիքներ չեն գտնվել: Համոզվեք, որ USB կարգավորիչը միացված է ցանցին և հեռուստատեսային ազդանշանի աղբյուրին:\n\nԵթերային ալեհավաք օգտագործելիս կարգավորեք դրա դիրքն ու ուղղությունը: Լավագույն արդյունքներն ապահովելու համար այն դրեք բարձր տեղում՝ պատուհանի մոտ, ապա որոնեք նորից:"</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Որոնման արդյունքում ալիքներ չեն գտնվել: Համոզվեք, որ ցանցային ընդունիչը միացված է և կապակցված հեռուստատեսային ազդանշանի աղբյուրին:\n\nԵթերային ալեհավաք օգտագործելիս կարգավորեք դրա դիրքն ու ուղղությունը: Լավագույն արդյունքներն ապահովելու համար այն դրեք բարձր տեղում՝ պատուհանի մոտ, ապա որոնեք նորից:"</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Կրկին որոնել"</item>
+ <item msgid="2092797862490235174">"Պատրաստ է"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"TV ալիքների որոնում"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"TV ընդունիչի տեղադրում"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB TV ընդունիչի տեղադրում"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Ցանցային TV ընդունիչի տեղադրում"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB հեռուստաընդունիչն անջատված է:"</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Ցանցային ընդունիչն անջատված է։"</string>
+</resources>
diff --git a/usbtuner-res/values-in/strings.xml b/usbtuner-res/values-in/strings.xml
new file mode 100644
index 00000000..8f3aa4d1
--- /dev/null
+++ b/usbtuner-res/values-in/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Tuner TV"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"Tuner TV USB"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Tuner TV Jaringan (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Harap tunggu sampai pemrosesan selesai"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Software tuner ini baru saja diperbarui. Pindai ulang saluran Anda."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Aktifkan suara surround di setelan suara sistem untuk mengaktifkan audio"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Tidak dapat memutar audio. Coba TV lainnya"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Penyiapan penyetel saluran"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Penyiapan Tuner TV"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Penyiapan tuner saluran USB"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Penyiapan tuner jaringan"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Pastikan TV terhubung ke sumber sinyal TV.\n\nJika menggunakan antena udara, Anda mungkin perlu menyesuaikan tempat atau arahnya untuk menerima sebagian besar saluran. Untuk hasil terbaik, tempatkan di lokasi yang tinggi dan dekat dengan jendela."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Pastikan tuner USB dicolokkan dan tersambung ke sumber sinyal TV.\n\nJika menggunakan antena udara, Anda mungkin perlu menyesuaikan tempat atau arahnya untuk menerima jumlah saluran paling banyak. Untuk hasil terbaik, letakkan di tempat yang tinggi dan dekat jendela."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Pastikan tuner jaringan aktif dan terhubung ke sumber sinyal TV.\n\nJika menggunakan antena udara, Anda mungkin perlu menyesuaikan tempat dan arahnya agar dapat menerima sebagian besar saluran. Untuk hasil terbaik, tempatkan antena di lokasi yang tinggi dan dekat jendela."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Lanjutkan"</item>
+ <item msgid="727245208787621142">"Jangan sekarang"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Jalankan lagi penyiapan saluran?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Tindakan ini akan menghapus saluran yang ditemukan dari tuner TV dan memindai saluran baru lagi.\n\nPastikan TV terhubung ke sumber sinyal TV.\n\nJika menggunakan antena udara, mungkin Anda perlu menyesuaikan tempat atau arahnya untuk menerima sebagian besar saluran. Untuk hasil terbaik, tempatkan di lokasi yang tinggi dan dekat dengan jendela."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Tindakan ini akan menghapus saluran yang ditemukan dari tuner USB dan memindai saluran baru lagi.\n\nPastikan tuner USB dicolokkan dan tersambung ke sumber sinyal TV.\n\nJika menggunakan antena udara, Anda mungkin perlu menyesuaikan tempat atau arahnya untuk menerima jumlah saluran paling banyak. Untuk hasil terbaik, letakkan di tempat yang tinggi dan dekat jendela."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Hal ini akan menghapus saluran yang ditemukan dari tuner jaringan dan memindai saluran baru lagi.\n\nPastikan tuner jaringan aktif dan terhubung ke sumber sinyal TV.\n\nJika menggunakan antena udara, Anda mungkin perlu menyesuaikan penempatan atau arahnya agar dapat menerima sebagian besar saluran. Untuk hasil terbaik, tempatkan antena di lokasi yang tinggi dan dekat dengan jendela."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Lanjutkan"</item>
+ <item msgid="235450158666155406">"Batal"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Pilih jenis sambungan"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Pilih Antena jika ada antena eksternal yang tersambung ke tuner. Pilih Kabel jika saluran Anda berasal dari penyedia layanan TV kabel. Jika tidak yakin, kedua jenis tersebut akan dipindai, namun prosesnya akan lebih lama."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antena"</item>
+ <item msgid="2670079958754180142">"Kabel"</item>
+ <item msgid="36774059871728525">"Tidak yakin"</item>
+ <item msgid="6881204453182153978">"Hanya pengembangan"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Penyiapan tuner TV"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Penyiapan tuner saluran USB"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Penyiapan tuner saluran jaringan"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Proses ini dapat memakan waktu beberapa menit"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Tuner sementara tidak tersedia atau sudah digunakan oleh rekaman."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">%1$d saluran ditemukan</item>
+ <item quantity="one">%1$d saluran ditemukan</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"HENTIKAN PEMINDAIAN SALURAN"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">%1$d saluran ditemukan</item>
+ <item quantity="one">%1$d saluran ditemukan</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Bagus! %1$d saluran ditemukan selama pemindaian saluran. Jika ada yang tidak beres, coba sesuaikan posisi antena dan pindai lagi.</item>
+ <item quantity="one">Bagus! %1$d saluran ditemukan selama pemindaian saluran. Jika ada yang tidak beres, coba sesuaikan posisi antena dan pindai lagi.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Selesai"</item>
+ <item msgid="2480490326672924828">"Pindai lagi"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Tidak ditemukan Saluran"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Pemindaian tidak menemukan saluran apa pun. Pastikan TV terhubung ke sumber sinyal TV.\n\nJika menggunakan antena udara, sesuaikan tempat atau arahnya. Untuk hasil terbaik, tempatkan di lokasi yang tinggi dan dekat dengan jendela kemudian pindai lagi."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Pemindaian tidak menemukan saluran apa pun. Pastikan tuner USB dicolokkan dan tersambung ke sumber sinyal TV.\n\nJika menggunakan antena udara, sesuaikan tempat atau arahnya. Untuk hasil terbaik, letakkan di tempat yang tinggi dan dekat jendela lalu pindai lagi."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Tidak menemukan saluran apa pun saat memindai. Pastikan tuner jaringan aktif dan terhubung ke sumber sinyal TV.\n\nJika Anda menggunakan antena udara, sesuaikan penempatan atau arahnya. Untuk hasil terbaik, tempatkan di lokasi yang tinggi dan dekat jendela, lalu pindai lagi."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Pindai lagi"</item>
+ <item msgid="2092797862490235174">"Selesai"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Pindai saluran TV"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Penyiapan Tuner TV"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Penyiapan Tuner TV USB"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Penyiapan Tuner TV Jaringan"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"Koneksi tuner TV USB terputus."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Koneksi tuner jaringan terputus."</string>
+</resources>
diff --git a/usbtuner-res/values-is-rIS/strings.xml b/usbtuner-res/values-is-rIS/strings.xml
new file mode 100644
index 00000000..fa1e85c7
--- /dev/null
+++ b/usbtuner-res/values-is-rIS/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Sjónvarpsmóttakari"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB-sjónvarpsmóttakari"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Netsjónvarpsmóttakari (TILRAUNAÚTGÁFA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Bíddu þar til vinnslu lýkur"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Hugbúnaður sjónvarpsmóttakarans var uppfærður nýlega. Leitaðu aftur að rásum."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Kveikja á víðómastillingu í hljóðstillingum kerfisins til að kveikja á hljóði"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Ekki er hægt að spila hljóð. Prófaðu annað sjónvarp"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Uppsetning sjónvarpskorts"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Uppsetning sjónvarpsmóttakara"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Uppsetning USB-sjónvarpsrásakorts"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Uppsetning netsjónvarpsmóttakara"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Gakktu úr skugga um að sjónvarpið sé tengt við sjónvarpstengi.\n\nEf þú ert að nota loftnet skaltu færa það á annan stað eða snúa því í aðra átt. Best er að hafa það hátt uppi og nálægt glugga þegar leitað er."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Gakktu úr skugga um að USB-sjónvarpskortið sé í sambandi og tengt við sjónvarpstengi.\n\nEf þú ert að nota loftnet skaltu færa það á annan stað eða snúa því í aðra átt til að ná fleiri rásum. Best er að hafa það hátt uppi og nálægt glugga."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Gakktu úr skugga um að kveikt sé á netsjónvarpsmóttakaranum og að hann sé tengdur við sjónvarpstengi.\n\nEf þú ert að nota loftnet skaltu færa það á annan stað eða snúa því í aðra átt. Best er að hafa það hátt uppi og nálægt glugga þegar leitað er."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Halda áfram"</item>
+ <item msgid="727245208787621142">"Ekki núna"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Viltu keyra rásauppsetningu aftur?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Þetta fjarlægir stöðvar sem sjónvarpsmóttakarinn fann og leitar aftur að nýjum stöðvum.\n\nGakktu úr skugga um að sjónvarpið sé tengt við sjónvarpstengi.\n\nEf þú ert að nota loftnet skaltu færa það á annan stað eða snúa því í aðra átt. Best er að hafa það hátt uppi og nálægt glugga þegar leitað er."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Þetta fjarlægir rásir sem skráðar eru á USB-sjónvarpskortinu og leitar að nýjum stöðvum.\n\nGakktu úr skugga um að USB-sjónvarpskortið sé í sambandi og tengt við sjónvarpstengi.\n\nEf þú ert að nota loftnet skaltu færa það á annan stað eða snúa því í aðra átt til að ná fleiri rásum. Best er að hafa það hátt uppi og nálægt glugga."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Þetta fjarlægir rásirnar sem sjónvarpsmóttakarinn þinn fann og leitar aftur að nýjum rásum.\n\nGakktu úr skugga um að kveikt sé á netsjónvarpsmóttakaranum og að hann sé tengdur við sjónvarpstengi.\n\nEf þú ert að nota loftnet skaltu færa það á annan stað eða snúa því í aðra átt. Best er að hafa það hátt uppi og nálægt glugga þegar leitað er."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Halda áfram"</item>
+ <item msgid="235450158666155406">"Hætta við"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Veldu tengigerðina"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Veldu „Loftnet“ ef utanáliggjandi loftnet er tengt við sjónvarpskortið. Veldu „Kapall“ ef rásirnar berast þér í gegnum kapal. Ef þú ert ekki viss verður leitað að báðum gerðum og það kann að taka lengri tíma."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Loftnet"</item>
+ <item msgid="2670079958754180142">"Kapall"</item>
+ <item msgid="36774059871728525">"Ekki viss"</item>
+ <item msgid="6881204453182153978">"Aðeins þróunaraðilar"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Uppsetning sjónvarpsmóttakara"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Uppsetning USB-sjónvarpsrásakorts"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Uppsetning netsjónvarpsmóttakara"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Þetta getur tekið nokkrar mínútur"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Móttakari er tímabundið ekki í boði eða er þegar að taka upp."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="one">%1$d rás fannst</item>
+ <item quantity="other">%1$d rásir fundust</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"STÖÐVA RÁSALEIT"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="one">%1$d rás fannst</item>
+ <item quantity="other">%1$d rásir fundust</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="one">Glæsilegt! %1$d rás fannst við leitina. Ef þetta er ekki eins og það á að vera skaltu prófa að stilla loftnetið og leita aftur.</item>
+ <item quantity="other">Glæsilegt! %1$d rásir fundust við leitina. Ef þetta er ekki eins og það á að vera skaltu prófa að stilla loftnetið og leita aftur.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Lokið"</item>
+ <item msgid="2480490326672924828">"Leita aftur"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Engar rásir fundust"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Engar rásir fundust. Gakktu úr skugga um að sjónvarpið sé tengt við sjónvarpstengi.\n\nEf þú ert að nota loftnet skaltu færa það á annan stað eða snúa því í aðra átt. Best er að hafa það hátt uppi og nálægt glugga þegar leitað er."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Engar rásir fundust. Gakktu úr skugga um að USB-sjónvarpskortið sé í sambandi og tengt við sjónvarpstengi.\n\nEf þú ert að nota loftnet skaltu færa það á annan stað eða snúa því í aðra átt. Best er að hafa það hátt uppi og nálægt glugga þegar leitað er."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Leitin fann engar stöðvar. Gakktu úr skugga um að kveikt sé á netsjónvarpsmóttakaranum og hann sé tengdur við sjónvarpstengi.\n\nEf þú ert að nota loftnet skaltu færa það á annan stað eða snúa því í aðra átt. Best er að hafa það hátt uppi og nálægt glugga þegar leitað er."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Leita aftur"</item>
+ <item msgid="2092797862490235174">"Lokið"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Skanna eftir sjónvarpsstöðvum"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Uppsetning sjónvarpsmóttakara"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Uppsetning USB-sjónvarpsmóttakara"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Uppsetning netsjónvarpsmóttakara"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB-sjónvarpsmóttakari tekinn úr sambandi."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Netmóttakari tekinn úr sambandi."</string>
+</resources>
diff --git a/usbtuner-res/values-it/strings.xml b/usbtuner-res/values-it/strings.xml
new file mode 100644
index 00000000..3e15fb24
--- /dev/null
+++ b/usbtuner-res/values-it/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Sintonizzatore TV"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"Sintonizzatore TV USB"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Network TV Tuner (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Attendi il completamento dell\'elaborazione"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Il software del sintonizzatore è stato aggiornato di recente. Esegui nuovamente la scansione dei canali."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Per attivare l\'audio, attiva l\'audio surround nelle impostazioni del sistema"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Impossibile riprodurre l\'audio. Prova con un\'altra TV"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Configurazione del sintonizzatore di canali"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Configurazione del sintonizzatore TV"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Configurazione del sintonizzatore di canali USB"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Configurazione del sintonizzatore di rete"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Verifica che la TV sia connessa a un\'origine del segnale TV.\n\nSe utilizzi un\'antenna OTA, regolane la posizione o la direzione per ricevere la maggior parte dei canali. Per ottenere risultati ottimali, posizionala in alto e vicino a una finestra."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Verifica che il sintonizzatore USB sia collegato e connesso a un\'origine del segnale TV.\n\nSe utilizzi un\'antenna OTA, potresti dover regolare la sua posizione o direzione per ricevere la maggior parte dei canali. Per risultati ottimali, posizionala in alto e vicino a una finestra."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Verifica che il sintonizzatore di rete sia acceso e connesso a un\'origine del segnale TV.\n\nSe utilizzi un\'antenna OTA (over-the-air), potresti doverne regolare la posizione o la direzione per ricevere il maggior numero di canali. Per ottenere risultati ottimali, posizionala in alto, vicino a una finestra."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Continua"</item>
+ <item msgid="727245208787621142">"Non ora"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Eseguire nuovamente la configurazione dei canali?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Questa operazione rimuoverà i canali trovati dal sintonizzatore TV ed eseguirà la ricerca di nuovi canali.\n\nVerifica che la TV sia connessa a un\'origine del segnale TV.\n\nSe utilizzi un\'antenna OTA, regolane la posizione o la direzione per ricevere la maggior parte dei canali. Per ottenere risultati ottimali, posizionala in alto e vicino a una finestra."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Questa operazione rimuoverà i canali trovati dal sintonizzatore USB ed eseguirà la ricerca di nuovi canali.\n\nVerifica che il sintonizzatore USB sia collegato e connesso a un\'origine del segnale TV.\n\nSe utilizzi un\'antenna OTA, potresti dover regolare la sua posizione o direzione per ricevere il maggior numero di canali. Per ottenere risultati ottimali, posizionala in alto e vicino a una finestra."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"I canali trovati dal sintonizzatore di rete verranno rimossi e verrà eseguita nuovamente la ricerca di nuovi canali.\n\nVerifica che il sintonizzatore di rete sia acceso e connesso a un\'origine del segnale TV.\n\nSe utilizzi un\'antenna OTA (over-the-air), potresti doverne regolare la posizione o la direzione per ricevere il maggior numero di canali. Per ottenere risultati ottimali, posizionala in alto, vicino a una finestra."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Continua"</item>
+ <item msgid="235450158666155406">"Annulla"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Seleziona il tipo di connessione"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Seleziona Antenna se un\'antenna esterna è collegata al sintonizzatore. Seleziona Cavo se i tuoi canali sono forniti da un provider Internet via cavo. Se non sei sicuro, verranno cercati entrambi i tipi di canale ma tale operazione potrebbe richiedere più tempo."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antenna"</item>
+ <item msgid="2670079958754180142">"Cavo"</item>
+ <item msgid="36774059871728525">"Non sono sicuro"</item>
+ <item msgid="6881204453182153978">"Solo per sviluppatori"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Configurazione del sintonizzatore TV"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Configurazione del sintonizzatore di canali USB"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Configurazione del sintonizzatore di canali della rete"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"L\'operazione potrebbe richiedere alcuni minuti"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Il sintonizzatore è temporaneamente non disponibile o già utilizzato dal registratore."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">%1$d canali trovati</item>
+ <item quantity="one">%1$d canale trovato</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"INTERROMPI RICERCA CANALI"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">%1$d canali trovati</item>
+ <item quantity="one">%1$d canale trovato</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Bene! Sono stati trovati %1$d canali durante la ricerca dei canali. Se non è corretto, prova a regolare la posizione dell\'antenna ed esegui nuovamente la ricerca.</item>
+ <item quantity="one">Bene! È stato trovato %1$d canale durante la ricerca dei canali. Se non è corretto, prova a regolare la posizione dell\'antenna ed esegui nuovamente la ricerca.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Fine"</item>
+ <item msgid="2480490326672924828">"Cerca di nuovo"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Nessun canale trovato"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Nessun canale trovato durante la ricerca. Verifica che la TV sia connessa a un\'origine del segnale TV.\n\nSe utilizzi un\'antenna OTA, regolane la posizione o la direzione. Per ottenere risultati ottimali, posizionala in alto, vicino a una finestra ed esegui nuovamente la ricerca."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Nessun canale trovato durante la ricerca. Verifica che il sintonizzatore USB sia collegato e connesso a un\'origine del segnale TV.\n\nSe utilizzi un\'antenna OTA (over-the-air), regolane la posizione o la direzione. Per ottenere risultati ottimali, posizionala in alto, vicino a una finestra ed esegui nuovamente la ricerca."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Nessun canale trovato durante la ricerca. Verifica che il sintonizzatore di rete sia acceso e connesso a un\'origine del segnale TV.\n\nSe utilizzi un\'antenna OTA (over-the-air), regolane la posizione o la direzione. Per ottenere risultati ottimali, posizionala in alto, vicino a una finestra ed esegui nuovamente la ricerca."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Cerca di nuovo"</item>
+ <item msgid="2092797862490235174">"Fine"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Cerca canali TV"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Configurazione del sintonizzatore TV"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Configurazione del sintonizzatore TV USB"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Configurazione del sintonizzatore TV di rete"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"Sintonizzatore TV USB disconnesso."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Sintonizzatore di rete disconnesso."</string>
+</resources>
diff --git a/usbtuner-res/values-iw/strings.xml b/usbtuner-res/values-iw/strings.xml
new file mode 100644
index 00000000..d30fdac5
--- /dev/null
+++ b/usbtuner-res/values-iw/strings.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"טיונר טלוויזיה"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"‏טיונר ה-USB בטלוויזיה"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"טיונר טלוויזיה לרשת (ביטא)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"המתן לסיום העיבוד"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"תוכנת הטיונר עודכנה לאחרונה. סרוק מחדש את הערוצים."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"הפעל סראונד בהגדרות צלילי מערכת כדי להפעיל אודיו"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"אין אפשרות להשמיע אודיו. נסה ערוץ טלוויזיה אחר."</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"הגדרת טיונר ערוצים"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"הגדרת טיונר טלוויזיה"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"‏הגדרת טיונר ערוצים בחיבור USB"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"הגדרת מקלט הרשת"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"ודא שהטלוויזיה מחוברת למקור אות טלוויזיה.\n\nאם אתה משתמש באנטנה אלחוטית, ייתכן שיהיה עליך לשנות את המיקום או את הכיוון שלה כדי לקלוט כמה שיותר ערוצים. לקבלת התוצאות הטובות ביותר, הצב אותה במקום גבוה ליד חלון."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"‏ודא שטיונר USB מחובר למקור אות בטלוויזיה. \n\n אם אתה משתמש באנטנה אלחוטית, ייתכן שיהיה עליך לכוון את מיקומה או את כיוונה כדי לקלוט כמה שיותר ערוצים. לתוצאות מיטביות, הצב אותה במקום גבוה ליד חלון וסרוק שוב."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"ודא שמקלט הרשת מופעל ומחובר למקור אות של טלוויזיה.\n\nאם אתה משתמש באנטנה לקליטת שידורים אלחוטיים, ייתכן שיהיה עליך לשנות את המיקום או את הכיוון שלה כדי לקלוט כמה שיותר ערוצים. לקבלת התוצאות הטובות ביותר, הצב אותה במקום גבוה ליד חלון."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"המשך"</item>
+ <item msgid="727245208787621142">"לא עכשיו"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"האם להפעיל מחדש את הגדרת הערוצים?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"פעולה זו תסיר את הערוצים שנמצאו בטיונר הטלוויזיה ותסרוק שוב ערוצים חדשים.\n\nודא שהטלוויזיה מחוברת למקור אות טלוויזיה.\n\nאם אתה משתמש באנטנה אלחוטית, ייתכן שיהיה עליך לשנות את המיקום או את הכיוון שלה כדי לקלוט כמה שיותר ערוצים. לקבלת התוצאות הטובות ביותר, הצב אותה במקום גבוה ליד חלון."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"‏פעולה זו תסיר את הערוצים שנמצאו מטיונר ה-USB ותתבצע סריקה נוספת לערוצים חדשים.\n\nודא שטיונר USB מחובר למקור אות בטלוויזיה.\n\nאם אתה משתמש באנטנה אלחוטית, ייתכן שיהיה עליך לשנות את מיקומה או את כיוונה כדי לקלוט כמה שיותר ערוצים. לתוצאות מיטביות, הצב אותה במקום גבוה ליד חלון וסרוק שוב."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"הפעולה תסיר את הערוצים שנמצאו ממקלט הרשת ותתבצע שוב סריקה לאיתור ערוצים חדשים.\n\nודא שמקלט הרשת מופעל ומחובר למקור אות של טלוויזיה.\n\nאם אתה משתמש באנטנה לקליטת שידורים אלחוטיים, ייתכן שיהיה עליך לשנות את המיקום או את הכיוון שלה כדי לקלוט כמה שיותר ערוצים. לקבלת התוצאות הטובות ביותר, הצב אותה במקום גבוה ליד חלון."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"המשך"</item>
+ <item msgid="235450158666155406">"ביטול"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"בחירת סוג החיבור"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"בחר \'אנטנה\' אם ישנה אנטנה חיצונית שמחוברת לטיונר. בחר \'כבלים\' אם הערוצים מגיעים מספק שירותי כבלים. אם אינך בטוח, שני הסוגים ייסרקו, אך הפעולה עשויה להימשך זמן רב יותר."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"אנטנה"</item>
+ <item msgid="2670079958754180142">"כבלים"</item>
+ <item msgid="36774059871728525">"לא בטוח"</item>
+ <item msgid="6881204453182153978">"פיתוח בלבד"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"הגדרת טיונר טלוויזיה"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"‏הגדרת טיונר ערוצים בחיבור USB"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"הגדרת מקלט ערוצים לרשת"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"פעולה זו עשויה להימשך מספר דקות"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"הטיונר אינו זמין באופן זמני או שהוא כבר נמצא בשימוש של הקלטה."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="two">‏נמצאו %1$d ערוצים</item>
+ <item quantity="many">‏נמצאו %1$d ערוצים</item>
+ <item quantity="other">‏נמצאו %1$d ערוצים</item>
+ <item quantity="one">נמצא ערוץ אחד</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"הפסק סריקת ערוצים"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="two">‏נמצאו %1$d ערוצים</item>
+ <item quantity="many">‏נמצאו %1$d ערוצים</item>
+ <item quantity="other">‏נמצאו %1$d ערוצים</item>
+ <item quantity="one">נמצא ערוץ אחד</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="two">‏לא רע! במהלך סריקה הערוצים, נמצאו %1$d ערוצים. אם הקליטה לא תקינה, נסה לכוונן את מיקום האנטנה ובצע סריקה נוספת.</item>
+ <item quantity="many">‏לא רע! במהלך סריקה הערוצים, נמצאו %1$d ערוצים. אם הקליטה לא תקינה, נסה לכוונן את מיקום האנטנה ובצע סריקה נוספת.</item>
+ <item quantity="other">‏לא רע! במהלך סריקה הערוצים, נמצאו %1$d ערוצים. אם הקליטה לא תקינה, נסה לכוונן את מיקום האנטנה ובצע סריקה נוספת.</item>
+ <item quantity="one">לא רע! במהלך סריקת הערוצים נמצא ערוץ אחד. אם הקליטה לא תקינה, נסה לכוונן את מיקום האנטנה ובצע סריקה נוספת.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"סיום"</item>
+ <item msgid="2480490326672924828">"סרוק שוב"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"לא נמצאו ערוצים"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"בסריקה לא נמצאו ערוצים. ודא שהטלוויזיה מחוברת למקור אות טלוויזיה.\n\nאם אתה משתמש באנטנה אלחוטית, שנה את המיקום או את הכיוון שלה. לקבלת התוצאות הטובות ביותר, הצב אותה במקום גבוה ליד חלון וסרוק שוב."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"‏לא נמצאו ערוצים בסריקה. ודא שטיונר USB מחובר למקור אות בטלוויזיה. \n\n אם אתה משתמש באנטנה אלחוטית, שנה את מיקומה או את כיוונה. לתוצאות מיטביות, הצב אותה במקום גבוה ליד חלון וסרוק שוב."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"בסריקה לא נמצאו ערוצים. ודא שמקלט הרשת מופעל ומחובר למקור אות של טלוויזיה.\n\nאם אתה משתמש באנטנה לקליטת שידורים אלחוטיים, שנה את המיקום או את הכיוון שלה. לקבלת התוצאות הטובות ביותר, הצב אותה במקום גבוה ליד חלון וסרוק שוב."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"סרוק שוב"</item>
+ <item msgid="2092797862490235174">"סיום"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"סריקה לאיתור ערוצי טלוויזיה"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"הגדרה של טיונר טלוויזיה"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"‏הגדרה של טיונר USB בטלוויזיה"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"הגדרה של טיונר טלוויזיה לרשת"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"‏טיונר ה-USB שבטלוויזיה מנותק."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"טיונר הרשת מנותק."</string>
+</resources>
diff --git a/usbtuner-res/values-ja/strings.xml b/usbtuner-res/values-ja/strings.xml
new file mode 100644
index 00000000..53223b41
--- /dev/null
+++ b/usbtuner-res/values-ja/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"テレビ チューナー"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB テレビ チューナー"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"ネットワーク テレビ チューナー(ベータ版)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"処理が完了するまでこのままお待ちください"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"最近チューナー ソフトウェアが更新されています。チャンネルをもう一度スキャンしてください。"</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"音声を有効にするには、システムのサウンド設定でサラウンド サウンドをオンにしてください"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"音声を再生できません。別のテレビをお試しください"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"チャンネル チューナーのセットアップ"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"テレビ チューナーのセットアップ"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB チャンネル チューナーのセットアップ"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"ネットワーク チューナーのセットアップ"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"テレビがテレビの信号源に接続されていることを確認してください。\n\n無線アンテナを使用している場合は、チャンネルの多くを受信するためにアンテナの場所や方向の調節が必要になる場合があります。最良の結果を得るには、アンテナを窓際の高い位置に設置します。"</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"USB チューナーが電源に接続され、テレビの信号源に接続されていることを確認してください。\n\n無線アンテナを使用している場合は、チャンネルの多くを受信するためにアンテナの場所や方向の調節が必要になる場合があります。最良の結果を得るには、アンテナを窓際の高い位置に設置します。"</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"ネットワーク チューナーの電源がオンになっていて、テレビの信号源に接続されていることを確認してください。\n\n無線アンテナを使用している場合は、チャンネルの多くを受信するためにアンテナの場所や方向の調節が必要になる場合があります。最良の結果を得るには、アンテナを窓際の高い位置に設置します。"</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"次へ"</item>
+ <item msgid="727245208787621142">"後で"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"もう一度チャンネルを設定しますか?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"テレビ チューナーで見つかったチャンネルを削除して新しいチャンネルをもう一度スキャンします。\n\nテレビがテレビの信号源に接続されていることを確認してください。\n\n無線アンテナを使用している場合は、チャンネルの多くを受信するためにアンテナの場所や方向の調節が必要になる場合があります。最良の結果を得るには、アンテナを窓際の高い位置に設置します。"</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"USB チューナーで見つかったチャンネルを削除して新しいチャンネルをもう一度スキャンします。\n\nUSB チューナーが電源に接続され、テレビの信号源に接続されていることを確認してください。\n\n無線アンテナを使用している場合は、チャンネルの多くを受信するためにアンテナの場所や方向の調節が必要になる場合があります。最良の結果を得るには、アンテナを窓際の高い位置に設置します。"</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"ネットワーク チューナーで見つかったチャンネルを削除して新しいチャンネルをもう一度スキャンします。\n\nネットワーク チューナーの電源がオンになっていて、テレビの信号源に接続されていることを確認してください。\n\n無線アンテナを使用している場合は、チャンネルの多くを受信するためにアンテナの場所や方向の調節が必要になる場合があります。最良の結果を得るには、アンテナを窓際の高い位置に設置します。"</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"次へ"</item>
+ <item msgid="235450158666155406">"キャンセル"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"接続タイプの選択"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"チューナーに外部アンテナが接続されている場合は、[アンテナ] を選択してください。ケーブル サービス プロバイダのチャンネルの場合は、[ケーブル] を選択してください。不明な場合は両方のタイプがスキャンされますが、処理に時間がかかることがあります。"</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"アンテナ"</item>
+ <item msgid="2670079958754180142">"ケーブル"</item>
+ <item msgid="36774059871728525">"不明"</item>
+ <item msgid="6881204453182153978">"開発のみ"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"テレビ チューナーのセットアップ"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB チャンネル チューナーのセットアップ"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"ネットワーク チャンネル チューナーのセットアップ"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"この処理には数分かかることがあります"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"チューナーを一時的に使用できないか、すでに録画に使用しています。"</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">%1$d 件のチャンネルが見つかりました</item>
+ <item quantity="one">%1$d 件のチャンネルが見つかりました</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"チャンネルのスキャンを停止"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">%1$d 件のチャンネルが見つかりました</item>
+ <item quantity="one">%1$d 件のチャンネルが見つかりました</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">チャンネルのスキャン中に %1$d 件のチャンネルが見つかりました。この件数が正しくないと思われる場合は、アンテナの位置を調整してもう一度スキャンしてください。</item>
+ <item quantity="one">チャンネルのスキャン中に %1$d 件のチャンネルが見つかりました。この件数が正しくないと思われる場合は、アンテナの位置を調整してもう一度スキャンしてください。</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"完了"</item>
+ <item msgid="2480490326672924828">"再スキャン"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"チャンネルが見つかりませんでした"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"スキャンの結果、チャンネルは見つかりませんでした。テレビがテレビの信号源に接続されていることを確認してください。\n\n無線アンテナを使用している場合は、アンテナの場所や方向を調節してください。最良の結果を得るには、アンテナを窓際の高い位置に設置してから、もう一度スキャンします。"</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"スキャンの結果、チャンネルは見つかりませんでした。USB チューナーが電源に接続され、テレビの信号源に接続されていることを確認してください。\n\n無線アンテナを使用している場合は、アンテナの場所や方向を調節してください。最良の結果を得るには、アンテナを窓際の高い位置に設置してから、もう一度スキャンします。"</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"スキャンの結果、チャンネルは見つかりませんでした。ネットワーク チューナーの電源がオンになっていて、テレビの信号源に接続されていることを確認してください。\n\n無線アンテナを使用している場合は、アンテナの場所や方向を調節してください。最良の結果を得るには、アンテナを窓際の高い位置に設置してから、もう一度スキャンします。"</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"再スキャン"</item>
+ <item msgid="2092797862490235174">"完了"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"テレビのチャンネルをスキャン"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"テレビ チューナーのセットアップ"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB テレビ チューナーのセットアップ"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"ネットワーク テレビ チューナーのセットアップ"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB テレビ チューナーの接続が解除されています。"</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"ネットワーク チューナーの接続が解除されています。"</string>
+</resources>
diff --git a/usbtuner-res/values-ka-rGE/strings.xml b/usbtuner-res/values-ka-rGE/strings.xml
new file mode 100644
index 00000000..055c4a99
--- /dev/null
+++ b/usbtuner-res/values-ka-rGE/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"TV-ტუნერი"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB TV-ტუნერი"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"ქსელის TV-ტუნერი (Beta)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"გთხოვთ, მოითმინოთ დამუშავების დასრულებამდე"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"ტუნერის პროგრამული უზრუნველყოფა ახლახან განახლდა. გთხოვთ, ხელახლა დაასკანიროთ არხები."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"აუდიოს ჩასართავად, სისტემის ხმის პარამეტრებში ჩართეთ მოცულობითი ხმა"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"აუდიოს დაკვრა ვერ ხერხდება. გთხოვთ, ცადოთ სხვა არხი"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"არხების ტუნერის დაყენება"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"TV-ტუნერის დაყენება"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"არხების USB ტუნერის დაყენება"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"ქსელის ტუნერის დაყენება"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"დარწმუნდით, რომ თქვენი ტელევიზორი მიერთებულია სატელევიზიო სიგნალის წყაროსთან..\n\nტერესტრიული ანტენის გამოყენების შემთხვევაში, არხების უმეტესობის მისაღებად, მისი განლაგების ან მიმართულების დარეგულება მოგიწევთ. საუკეთესო შედეგის მისაღებად, განათავსეთ ის სიმაღლეზე, ფანჯარასთან ახლოს."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"დარწმუნდით, რომ USB ტუნერი ბუდეშია და მიერთებულია სატელევიზიო სიგნალის წყაროსთან.\n\nტერესტრიული ანტენის გამოყენების შემთხვევაში, არხების უმეტესობის მისაღებად, მისი განლაგების ან მიმართულების დარეგულება მოგიწევთ. საუკეთესო შედეგის მისაღებად, განათავსეთ ის სიმაღლეზე, ფანჯარასთან ახლოს."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"დარწმუნდით, რომ ქსელის ტუნერი ჩართულია და მიერთებულია სატელევიზიო სიგნალის წყაროსთან.\n\nტერესტრიული ანტენის გამოყენების შემთხვევაში, არხების უმეტესობის მისაღებად, მისი განლაგების ან მიმართულების დარეგულირება მოგიწევთ. საუკეთესო შედეგის მისაღებად, განათავსეთ ის სიმაღლეზე, ფანჯარასთან ახლოს."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"გაგრძელება"</item>
+ <item msgid="727245208787621142">"ახლა არა"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"გსურთ არხების ხელახლა დაყენება?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"ეს მოქმედება ამოშლის TV ტუნერით ნაპოვნ არხებს და ახალი არხების სკანირება ხელახლა მოხდება.\n\nდარწმუნდით, რომ თქვენი ტელევიზორი მიერთებულია სატელევიზიო სიგნალის წყაროსთან.\n\nტერესტრიული ანტენის გამოყენების შემთხვევაში, არხების უმეტესობის მისაღებად, მისი განლაგების ან მიმართულების დარეგულება მოგიწევთ. საუკეთესო შედეგის მისაღებად, განათავსეთ ის სიმაღლეზე, ფანჯარასთან ახლოს."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"ეს მოქმედება ამოშლის USB ტუნერით ნაპოვნ არხებს და ხელახლა მოხდება ახალი არხების სკანირება.\n\nდარწმუნდით, რომ USB ტუნერი ბუდეშია და მიერთებულია სატელევიზიო სიგნალის წყაროსთან.\n\nტერესტრიული ანტენის გამოყენების შემთხვევაში, არხების უმეტესობის მისაღებად, მისი განლაგების ან მიმართულების დარეგულება მოგიწევთ. საუკეთესო შედეგის მისაღებად, განათავსეთ ის სიმაღლეზე, ფანჯარასთან ახლოს."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"ეს მოქმედება ამოშლის ქსელის ტუნერით ნაპოვნ არხებს და ახალი არხების სკანირება ხელახლა მოხდება.\n\nდარწმუნდით, რომ ქსელის ტუნერი ჩართულია და მიერთებულია სატელევიზიო სიგნალის წყაროსთან.\n\nტერესტრიული ანტენის გამოყენების შემთხვევაში, არხების უმეტესობის მისაღებად, მისი განლაგების ან მიმართულების დარეგულირება მოგიწევთ. საუკეთესო შედეგის მისაღებად, განათავსეთ ის სიმაღლეზე, ფანჯარასთან ახლოს."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"გაგრძელება"</item>
+ <item msgid="235450158666155406">"გაუქმება"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"აირჩიეთ კავშირის ტიპი"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"აირჩიეთ ანტენა, თუ ტუნერთან მიერთებულია გარე ანტენა. აირჩიეთ კაბელი, თუ არხებს საკაბელო სერვისის პროვაიდერისგან იღებთ. თუ დარწმუნებული არ ხართ, დასკანირდება ორივე ტიპი, მაგრამ ამას შეიძლება მეტი დრო დასჭირდეს."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"ანტენა"</item>
+ <item msgid="2670079958754180142">"კაბელი"</item>
+ <item msgid="36774059871728525">"არ ვიცი"</item>
+ <item msgid="6881204453182153978">"მხოლოდ დეველოპერებისთვის"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"TV-ტუნერის დაყენება"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"არხების USB ტუნერის დაყენება"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"არხების ქსელის ტუნერის დაყენება"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"ამას შეიძლება რამდენიმე წუთი დასჭირდეს"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"ტუნერი დროებით მიუწვდომელია, ან უკვე გამოიყენება ჩასაწერად."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">მოიძებნა %1$d არხი</item>
+ <item quantity="one">მოიძებნა %1$d არხი</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"არხების სკანირების შეწყვეტა"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">მოიძებნა %1$d არხი</item>
+ <item quantity="one">მოიძებნა %1$d არხი</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">მშვენიერია! არხების სკანირებისას მოიძებნა %1$d არხი. თუ სათანადო შედეგს ვერ მიიღებთ, ცადეთ ანტენის პოზიციის დარეგულირება და ხელახლა დაასკანირეთ.</item>
+ <item quantity="one">მშვენიერია! არხების სკანირებისას მოიძებნა %1$d არხი. თუ სათანადო შედეგს ვერ მიიღებთ, ცადეთ ანტენის პოზიციის დარეგულირება და ხელახლა დაასკანირეთ.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"მზადაა"</item>
+ <item msgid="2480490326672924828">"ხელახლა სკანირება"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"არხები ვერ მოიძებნა"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"სკანირებისას არხები ვერ მოიძებნა. დარწმუნდით, რომ თქვენი ტელევიზორი მიერთებულია სატელევიზიო სიგნალის წყაროსთან.\n\nტერესტრიული ანტენის გამოყენების შემთხვევაში, დაარეგულირეთ მისი განლაგება ან მიმართულება. საუკეთესო შედეგის მისაღებად, განათავსეთ ის სიმაღლეზე, ფანჯარასთან ახლოს და ხელახლა დაასკანირეთ."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"სკანირებისას არხები ვერ მოიძებნა. დარწმუნდით, რომ USB ტუნერი ბუდეშია და მიერთებულია სატელევიზიო სიგნალის წყაროსთან. \n\nტერესტრიული ანტენის გამოყენების შემთხვევაში, დაარეგულირეთ მისი განლაგება ან მიმართულება. საუკეთესო შედეგის მისაღებად, განათავსეთ ის სიმაღლეზე, ფანჯარასთან ახლოს და ხელახლა დაასკანირეთ."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"სკანირებისას არხები ვერ მოიძებნა. დარწმუნდით, რომ ქსელის ტუნერი ჩართულია და მიერთებულია სატელევიზიო სიგნალის წყაროსთან. \n\nტერესტრიული ანტენის გამოყენების შემთხვევაში, დაარეგულირეთ მისი განლაგება ან მიმართულება. საუკეთესო შედეგის მისაღებად, განათავსეთ ის სიმაღლეზე, ფანჯარასთან ახლოს და ხელახლა დაასკანირეთ."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"ხელახლა სკანირება"</item>
+ <item msgid="2092797862490235174">"მზადაა"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"სკანირება სატელევიზიო არხების აღმოსაჩენად"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"TV-ტუნერის დაყენება"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB TV-ტუნერის დაყენება"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"ქსელის TV-ტუნერის დაყენება"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB TV-ტუნერი გაითიშა."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"ქსელის ტუნერი გაითიშა."</string>
+</resources>
diff --git a/usbtuner-res/values-kk-rKZ/strings.xml b/usbtuner-res/values-kk-rKZ/strings.xml
new file mode 100644
index 00000000..7ca732b2
--- /dev/null
+++ b/usbtuner-res/values-kk-rKZ/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"ТД тюнері"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB TД тюнері"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Желілік теледидар тюнері (БЕТА НҰСҚАСЫ)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Өңдеу аяқталғанша күте тұрыңыз"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Тюнердің бағдарламалық құралы жақында жаңартылды. Арналарды қайта іздеңіз."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Аудиомазмұнды қосу үшін жүйенің параметрлерінде көлемдік дыбысты қосыңыз"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Аудиомазмұн ойнатылмайды. Басқа теледидар арнасын қосып көріңіз"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Арна тюнерін орнату"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"ТД тюнерін орнату"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB арна тюнерін орнату"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Желі тюнерін реттеу"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Теледидардың ТД сигнал көзіне қосылғанын тексеріңіз.\n\nСымсыз антеннаны пайдалансаңыз, көптеген арналарды қабылдау үшін оның орнын немесе бағытын реттеу қажет болады. Ең жақсы нәтижеге қол жеткізу үшін оны жоғарырақ және терезеге жақын орналастырыңыз."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"USB тюнерін жалғанғанын және ТД сигнал көзіне қосылғанын тексеріңіз.\n\nСымсыз антеннаны пайдалансаңыз, көптеген арналарды қабылдау үшін оның орнын немесе бағытын реттеу қажет болады. Ең жақсы нәтижеге қол жеткізу үшін оны жоғарырақ және терезеге жақын орналастырыңыз."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"USB тюнері қосылып, теледидардың сигнал көзіне жалғанғанын тексеріңіз.\n\nСымсыз антеннаны пайдалансаңыз, көптеген арналарды қабылдау үшін оның орнын ауыстырыңыз немесе бағытын реттеңіз. Ең жақсы нәтижеге қол жеткізу үшін оны жоғарырақ және терезеге жақын жерге орналастырыңыз."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Жалғастыру"</item>
+ <item msgid="727245208787621142">"Қазір емес"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Арналарды қайта орнату қажет пе?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"ТД тюнерінде табылған арналар жойылып, жаңа арналар ізделеді.\n\nТеледидардың ТД сигнал көзіне қосылғанын тексеріңіз.\n\nСымсыз антеннаны пайдалансаңыз, көптеген арналарды қабылдау үшін оның орнын немесе бағытын реттеу қажет болады. Ең жақсы нәтижеге қол жеткізу үшін оны жоғарырақ және терезеге жақын орналастырыңыз."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"USB тюнерінде табылған арналар жойылып, жаңа арналар ізделеді.\n\nUSB тюнері жалғанғанын және ТД сигнал көзіне қосылғанын тексеріңіз.\n\nСымсыз антеннаны пайдалансаңыз, көптеген арналарды қабылдау үшін оның орнын немесе бағытын реттеу қажет болады. Ең жақсы нәтижеге қол жеткізу үшін оны жоғарырақ және терезеге жақын орналастырыңыз."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Желі тюнерінде табылған арналар өшіріліп, жаңа арналар ізделеді.\n\nЖелі тюнері қосылып, теледидардың сигнал көзіне жалғанғанын тексеріңіз.\n\nСымсыз антеннаны пайдалансаңыз, көптеген арналарды қабылдау үшін оның орнын ауыстырыңыз немесе бағытын реттеңіз. Ең жақсы нәтижеге қол жеткізу үшін оны жоғарырақ және терезеге жақын жерге орналастырыңыз."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Жалғастыру"</item>
+ <item msgid="235450158666155406">"Бас тарту"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Қосылу түрін таңдау"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Тюнерге қосымша антенна қосылған болса, \"Антенна\" опциясын таңдаңыз. Арналар кабельді қызмет провайдерінен алынған болса, \"Кабель\" опциясын таңдаңыз. Нақты білмесеңіз, екі түрі де ізделеді, бірақ бұған көбірек уақыт кетуі мүмкін."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Антенна"</item>
+ <item msgid="2670079958754180142">"Кабель"</item>
+ <item msgid="36774059871728525">"Нақты білмеймін"</item>
+ <item msgid="6881204453182153978">"Тек әзірлеу"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"ТД тюнерін орнату"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB арна тюнерін орнату"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Желілік арна тюнерін реттеу"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Бұл бірнеше минутты алуы мүмкін"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Тюнер қолжетімсіз немесе жазу барысында қолданылуда."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">%1$d арна табылды</item>
+ <item quantity="one">%1$d арна табылды</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"АРНА ІЗДЕУДІ ТОҚТАТУ"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">%1$d арна табылды</item>
+ <item quantity="one">%1$d арна табылды</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Тамаша! Арналарды іздеу кезінде %1$d арна табылды. Жеткіліксіз болса, антеннаның орнын ауыстырып, қайта іздеп көріңіз.</item>
+ <item quantity="one">Тамаша! Арналарды іздеу кезінде %1$d арна табылды. Жеткіліксіз болса, антеннаның орнын ауыстырып, қайта іздеп көріңіз.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Орындалды"</item>
+ <item msgid="2480490326672924828">"Қайта іздеу"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Арналар табылмады"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Іздеу нәтижесінде ешқандай арна табылмады. Теледидардың ТД сигнал көзіне қосылғанын тексеріңіз.\n\nСымсыз антеннаны пайдалансаңыз, орнын немесе бағытын реттеңіз. Ең жақсы нәтижеге қол жеткізу үшін оны жоғарырақ және терезеге жақын орналастырып, қайта іздеп көріңіз."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Іздеу нәтижесінде арналар табылмады. USB тюнері жалғанғанын және ТД сигнал көзіне қосылғанын тексеріңіз.\n\nСымсыз антеннаны пайдалансаңыз, орнын немесе бағытын реттеңіз. Ең жақсы нәтижеге қол жеткізу үшін оны жоғарырақ және терезеге жақын орналастырып, қайта іздеп көріңіз."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Іздеу нәтижесінде арналар табылмады. Желі тюнері қосылып, теледидардың сигнал көзіне жалғанғанын тексеріңіз.\n\nСымсыз антеннаны пайдалансаңыз, оның орнын ауыстырыңыз немесе бағытын реттеңіз. Ең жақсы нәтижеге қол жеткізу үшін оны жоғарырақ және терезеге жақын жерге орналастырып, қайта іздеп көріңіз."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Қайта іздеу"</item>
+ <item msgid="2092797862490235174">"Орындалды"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"ТД арналарын іздеу"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"ТД тюнерін орнату"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB TД тюнерін орнату"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Желілік ТД тюнерін реттеу"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB TД тюнері ажыратылды."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Желі тюнері ажыратылды."</string>
+</resources>
diff --git a/usbtuner-res/values-km-rKH/strings.xml b/usbtuner-res/values-km-rKH/strings.xml
new file mode 100644
index 00000000..5bca2a02
--- /dev/null
+++ b/usbtuner-res/values-km-rKH/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"អង្គរាវប៉ុស្តិ៍ទូរទស្សន៍"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"ឧបករណ៍ USB រាវប៉ុស្តិ៍ទូរទស្សន៍"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"កម្មវិធី​រាវ​បណ្តាញ​ទូរទស្សន៍ (បេតា)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"សូមរង់ចាំដើម្បីបញ្ចប់ដំណើរការ"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"កម្មវិធីអង្គរាវប៉ុស្តិ៍បានអាប់ដេតថ្មីៗនេះ។ សូមស្កេនរកប៉ុស្តិ៍ទាំងនេះម្តងទៀត។"</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"បើកដំណើរការសំឡេងជុំវិញនៅក្នុងការកំណត់សំឡេងប្រព័ន្ធដើម្បីបើកដំណើរការអូឌីយ៉ូ"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"មិនអាចចាក់អូឌីយ៉ូបានទេ។ សូមសាកល្បងប្រើទូរទស្សន៍ផ្សេង"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"ការដំឡើងអង្គរាវប៉ុស្តិ៍"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"ការដំឡើងអង្គរាវប៉ុស្តិ៍ទូរទស្សន៍"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"ការដំឡើងឧបករណ៍ USB រាវប៉ុស្តិ៍"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"រៀបចំឧបករណ៍រាវបណ្តាញ"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"សូមផ្ទៀងផ្ទាត់ថាប៉ុស្តិ៍ទូរទស្សន៍របស់អ្នកត្រូវបានភ្ជាប់ទៅប្រភពរលកសញ្ញាទូរទស្សន៍។\n\nប្រសិនបើអ្នកប្រើអង់តែនឥតខ្សែ សូមសម្រួលទីតាំង ឬទិសដៅរបស់វាដើម្បីទទួលបានប៉ុស្តិ៍ច្រើនបំផុត។ ដើម្បីទទួលបានលទ្ធផលល្អបំផុត សូមដាក់វានៅកន្លែងខ្ពស់ និងនៅជិតបង្អួច។"</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"ផ្ទៀងផ្ទាត់ថាអ្នកបានដោតឧបករណ៍ USB រាវប៉ុស្តិ៍ និងបានភ្ជាប់ទៅប្រភពសញ្ញាទូរទស្សន៍\n\nប្រសិនបើអ្នកប្រើអង់តែនឥតខ្សែ អ្នកប្រហែលជាត្រូវកែសម្រួលទីតាំង និងទិសដៅរបស់វាដើម្បីទទួលបានប៉ុស្តិ៍ច្រើនបំផុត។ ដើម្បីទទួលបានលទ្ធផលល្អបំផុត សូមដាក់វានៅកន្លែងដែលខ្ពស់ក្បែរបង្អួច។"</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"ផ្ទៀងផ្ទាត់ថាអ្នកបានបើកឧបករណ៍រាវបណ្តាញនេះ និងបានភ្ជាប់ទៅប្រភពរលកសញ្ញាទូរទស្សន៍។\n\nប្រសិនបើអ្នកប្រើអង់តែនឥតខ្សែ អ្នកត្រូវកែសម្រួលទីតាំង និងទិសដៅរបស់វា ដើម្បីទទួលបានប៉ុស្តិ៍ច្រើនបំផុត។ ដើម្បីទទួលបានលទ្ធផលល្អបំផុត សូមដាក់វានៅកន្លែងដែលខ្ពស់ក្បែរបង្អួច។"</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"បន្ត"</item>
+ <item msgid="727245208787621142">"មិនមែនឥឡូវនេះទេ"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"ដំណើរការដំឡើងប៉ុស្តិ៍ឡើងវិញឬទេ?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"វានឹងលុបប៉ុស្តិ៍ដែលបានរកឃើញដោយអង្គរាវប៉ុស្តិ៍ទូរទស្សន៍ចេញ ហើយស្កេនរកប៉ុស្តិ៍ថ្មីម្តងទៀត។\n\nផ្ទៀងផ្ទាត់ថាអ្នកបានដោតទូរទស្សន៍ទៅប្រភពរលកសញ្ញាទូរទស្សន៍\n\nប្រសិនបើអ្នកប្រើអង់តែនឥតខ្សែ អ្នកប្រហែលជាត្រូវសម្រួលទីតាំង និងទិសដៅរបស់វាដើម្បីទទួលបានប៉ុស្តិ៍ច្រើនបំផុត។ ដើម្បីទទួលបានលទ្ធផលល្អបំផុត សូមដាក់វានៅកន្លែងដែលខ្ពស់ក្បែរបង្អួច។"</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"វានឹងលុបប៉ុស្តិ៍ដែលបានរកឃើញដោយឧបករណ៍ USB រាវប៉ុស្តិ៍ចេញ ហើយស្កេនរកប៉ុស្តិ៍ថ្មីម្តងទៀត។\n\nផ្ទៀងផ្ទាត់ថាអ្នកបានដោតឧបករណ៍ USB រាវប៉ុស្តិ៍ និងបានភ្ជាប់ទៅប្រភពសញ្ញាទូរទស្សន៍\n\nប្រសិនបើអ្នកប្រើអង់តែនឥតខ្សែ អ្នកប្រហែលជាត្រូវសម្រួលទីតាំង និងទិសដៅរបស់វាដើម្បីទទួលបានប៉ុស្តិ៍ច្រើនបំផុត។ ដើម្បីទទួលបានលទ្ធផលល្អបំផុត សូមដាក់វានៅកន្លែងដែលខ្ពស់ក្បែរបង្អួច។"</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"វានឹងលុបប៉ុស្តិ៍ដែលបានរកឃើញដោយឧបករណ៍រាវបណ្តាញ ហើយបន្ទាប់មកស្កេនរកបណ្តាញថ្មី។\n\nផ្ទៀងផ្ទាត់ថាអ្នកបានបើកអង្គរាវបណ្តាញនេះ និងបានភ្ជាប់ទៅប្រភពរលកសញ្ញាទូរទស្សន៍។\n\nប្រសិនបើអ្នកប្រើអង់តែនឥតខ្សែ អ្នកត្រូវសម្រួលទីតាំង និងទិសដៅរបស់វា ដើម្បីទទួលបានប៉ុស្តិ៍ច្រើនបំផុត។ ដើម្បីទទួលបានលទ្ធផលល្អបំផុត សូមដាក់វានៅកន្លែងដែលខ្ពស់ក្បែរបង្អួច។"</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"បន្ត"</item>
+ <item msgid="235450158666155406">"បោះបង់"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"ជ្រើសប្រភេទនៃការតភ្ជាប់"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"សូមជ្រើសរើសអង់តែន ប្រសិនបើអ្នកភ្ជាប់អង់តែនខាងក្រៅទៅនឹងអង្គរាវប៉ុស្តិ៍។ ឬជ្រើសរើសខ្សែកាប ប្រសិនបើប៉ុស្តិ៍របស់អ្នកផ្តល់ដោយក្រុមហ៊ុនផ្តល់សេវាខ្សែកាប។ ប្រសិនបើអ្នកមិនប្រាកដទេ អ្នកអាចជ្រើសរើសប្រភេទទាំងពីរដើម្បីស្កេន ប៉ុន្តែវាអាចចំណាយពេលយូរ។"</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"អង់តែន"</item>
+ <item msgid="2670079958754180142">"ខ្សែកាប"</item>
+ <item msgid="36774059871728525">"មិនប្រាកដ"</item>
+ <item msgid="6881204453182153978">"ការអភិវឌ្ឍន៍ប៉ុណ្ណោះ"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"ការដំឡើងអង្គរាវប៉ុស្តិ៍ទូរទស្សន៍"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"ការដំឡើងឧបករណ៍ USB រាវប៉ុស្តិ៍ទូរទស្សន៍"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"ការរៀបចំឧបករណ៍រាវបណ្តាញប៉ុស្តិ៍"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"វាអាចចំណាយពេលច្រើននាទី"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"អង្គរាវប៉ុស្តិ៍មិនអាចប្រើបានជាបណ្តោះអាសន្ន ឬបានប្រើសម្រាប់ការថតរួចទៅហើយ។"</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">បានរកឃើញប៉ុស្តិ៍ %1$d</item>
+ <item quantity="one">បានរកឃើញប៉ុស្តិ៍ %1$d</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"បញ្ឈប់ការស្កេនរកប៉ុស្តិ៍"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">បានរកឃើញប៉ុស្តិ៍ %1$d</item>
+ <item quantity="one">បានរកឃើញប៉ុស្តិ៍ %1$d</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">ល្អណាស់! បានរកឃើញប៉ុស្តិ៍ %1$d អំឡុងពេលស្កេន។ ប្រសិនបើការស្កេននេះរកមិនឃើញប៉ុស្តិ៍ទេ សូមសាកល្បងសម្រួលទីតាំងអង់តែន ហើយស្កេនម្តងទៀត។</item>
+ <item quantity="one">ល្អណាស់! បានរកឃើញប៉ុស្តិ៍ %1$d អំឡុងពេលស្កេន។ ប្រសិនបើការស្កេននេះរកមិនឃើញប៉ុស្តិ៍ទេ សូមសាកល្បងសម្រួលទីតាំងអង់តែន ហើយស្កេនម្តងទៀត។</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"រួចរាល់"</item>
+ <item msgid="2480490326672924828">"ស្កេនម្តងទៀត"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"រកមិនឃើញប៉ុស្តិ៍ទេ"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"ការស្កេននេះរកមិនឃើញប៉ុស្តិ៍ណាមួយឡើយ។ សូមផ្ទៀងផ្ទាត់ថាប៉ុស្តិ៍ទូរទស្សន៍របស់អ្នកត្រូវបានភ្ជាប់ទៅប្រភពរលកសញ្ញាទូរទស្សន៍។\n\nប្រសិនបើអ្នកប្រើអង់តែនឥតខ្សែ សូមសម្រួលទីតាំង ឬទិសដៅរបស់វា។ ដើម្បីទទួលបានលទ្ធផលល្អបំផុត សូមដាក់វានៅកន្លែងខ្ពស់ និងនៅជិតបង្អួច បន្ទាប់មកធ្វើការស្កេនម្តងទៀត។"</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"ការស្កេនរកមិនឃើញប៉ុស្តិ៍ទេ។ ផ្ទៀងផ្ទាត់ថាអ្នកបានដោតឧបករណ៍ USB រាវប៉ុស្តិ៍ និងបានភ្ជាប់ទៅប្រភពសញ្ញាទូរទស្សន៍។\n\nប្រសិនបើអ្នកប្រើអង់តែនឥតខ្សែ សូមសម្រួលទីតាំង និងទិសដៅរបស់វា។ ដើម្បីទទួលបានលទ្ធផលល្អបំផុត សូមដាក់វានៅកន្លែងដែលខ្ពស់ក្បែរបង្អួច ហើយបន្ទាប់មកស្កេនម្តងទៀត។"</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"ការស្កេនរកមិនឃើញប៉ុស្តិ៍ណាមួយទេ។ ផ្ទៀងផ្ទាត់ថាអ្នកបានបើកឧបករណ៍រាវបណ្តាញនេះ និងបានភ្ជាប់ទៅប្រភពរលកសញ្ញាទូរទស្សន៍។\n\nប្រសិនបើអ្នកប្រើអង់តែនឥតខ្សែ សូមសម្រួលទីតាំង និងទិសដៅរបស់វា។ ដើម្បីទទួលបានលទ្ធផលល្អបំផុត សូមដាក់វានៅកន្លែងដែលខ្ពស់ក្បែរបង្អួច បន្ទាប់មកស្កេនម្តងទៀត។"</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"ស្កេនម្តងទៀត"</item>
+ <item msgid="2092797862490235174">"រួចរាល់"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"ស្កេនរកប៉ុស្តិ៍ទូរទស្សន៍"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"ការរៀបចំអង្គរាវរកប៉ុស្តិ៍ទូរទស្សន៍"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"ការរៀបចំអង្គរាវរកប៉ុស្តិ៍ទូរទស្សន៍តាម USB"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"ការរៀបចំអង្គរាវរកបណ្តាញទូរទស្សន៍"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"អង្គរាវរកប៉ុស្តិ៍ USB សម្រាប់ទូរទស្សន៍ត្រូវបានផ្តាច់។"</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"អង្គរាវរក​បណ្តាញ​ត្រូវ​បាន​ផ្ដាច់។"</string>
+</resources>
diff --git a/usbtuner-res/values-kn-rIN/strings.xml b/usbtuner-res/values-kn-rIN/strings.xml
new file mode 100644
index 00000000..af903462
--- /dev/null
+++ b/usbtuner-res/values-kn-rIN/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"ಟಿವಿ ಟ್ಯೂನರ್"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB ಟಿವಿ ಟ್ಯೂನರ್"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"ನೆಟ್‌ವರ್ಕ್ ಟಿವಿ ಟ್ಯೂನರ್ (ಬೀಟಾ)‌‌"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"ಪ್ರಕ್ರಿಯೆಗೊಳಿಸುವುದನ್ನು ಪೂರೈಸಲು ದಯವಿಟ್ಟು ಕಾಯಿರಿ"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"ಟ್ಯೂನರ್ ಸಾಫ್ಟ್‌ವೇರ್‍ ಅನ್ನು ಇತ್ತೀಚಿಗೆ ಅಪ್‌ಡೇಟ್ ಮಾಡಲಾಗಿದೆ. ದಯವಿಟ್ಟು ಚಾನಲ್‌ಗಳನ್ನು ಮರು-ಸ್ಕ್ಯಾನ್‌ ಮಾಡಿ."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"ಆಡಿಯೊ ಸಕ್ರಿಯಗೊಳಿಸಲು ಸಿಸ್ಟಂ ಧ್ವನಿ ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ಸರೌಂಡ್ ಧ್ವನಿಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"ಆಡಿಯೊವನ್ನು ಪ್ಲೇ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ. ದಯವಿಟ್ಟು ಬೇರೊಂದು ಟಿವಿಯಲ್ಲಿ ಪ್ರಯತ್ನಿಸಿ"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"ಚಾನಲ್ ಟ್ಯೂನರ್ ಸೆಟಪ್"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"ಟಿವಿ ಟ್ಯೂನರ್ ಸೆಟಪ್"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB ಚಾನಲ್ ಟ್ಯೂನರ್ ಸೆಟಪ್"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"ನೆಟ್‌ವರ್ಕ್ ಟ್ಯೂನರ್ ಸೆಟಪ್"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"ನಿಮ್ಮ ಟಿವಿಯನ್ನು ಟಿವಿ ಸಿಗ್ನಲ್‌ ಮೂಲಕ್ಕೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆಯೆ ಎಂದು ಪರಿಶೀಲಿಸಿ.\n\nನೀವು ಪ್ರಸಾರದ ಮೂಲಕ ಆಂಟೆನಾ ಬಳಸುತ್ತಿದ್ದರೆ, ಹೆಚ್ಚಿನ ಚಾನಲ್‌ಗಳನ್ನು ಸ್ವೀಕರಿಸಲು ನೀವು ಅದರ ಸ್ಥಳ ಅಥವಾ ದಿಕ್ಕನ್ನು ಹೊಂದಿಸಬೇಕಾಗಬಹುದು. ಉತ್ತಮ ಫಲಿತಾಂಶಗಳಿಗೆ, ಇದನ್ನು ಎತ್ತರದಲ್ಲಿ ಮತ್ತು ಕಿಟಕಿಯ ಬಳಿ ಇರಿಸಿ."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"USB ಟ್ಯೂನಲ್ ಅನ್ನು ಪ್ಲಗ್ ಇನ್ ಮಾಡಲಾಗಿದೆಯೇ ಮತ್ತು ಟಿವಿ ಸಿಗ್ನಲ್ ಮೂಲಕ್ಕೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆಯೆ ಎಂದು ಪರಿಶೀಲಿಸಿ.\n\nಪ್ರಸಾರದ ಮೂಲಕ ಆಂಟೆನಾ ಬಳಸುತ್ತಿದ್ದರೆ, ಹೆಚ್ಚಿನ ಚಾನಲ್‌ಗಳನ್ನು ಸ್ವೀಕರಿಸಲು ನೀವು ಅದರ ಸ್ಥಳ ಅಥವಾ ದಿಕ್ಕನ್ನು ಹೊಂದಿಸಬೇಕಾಗಬಹುದು. ಉತ್ತಮ ಫಲಿತಾಂಶಗಳಿಗೆ, ಇದನ್ನು ಎತ್ತರದಲ್ಲಿ ಮತ್ತು ಕಿಟಕಿಯ ಬಳಿ ಇರಿಸಿ ಹಾಗೂ ಮತ್ತೆ ಸ್ಕ್ಯಾನ್ ಮಾಡಿ."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"ನೆಟ್‌ವರ್ಕ್ ಟ್ಯೂನರ್ ಆನ್ ಮಾಡಲಾಗಿದೆಯೇ ಮತ್ತು ಟಿವಿ ಸಿಗ್ನಲ್ ಮೂಲಕ್ಕೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆಯೇ ಎಂದು ಪರಿಶೀಲಿಸಿ.\n\nನೀವು ನೆಟ್‌ವರ್ಕ್ ಸಂಪರ್ಕದ ಮೂಲಕ ಆಂಟೆನಾ ಬಳಸುತ್ತಿದ್ದರೆ, ಹೆಚ್ಚಿನ ಚಾನಲ್‌ಗಳನ್ನು ಸ್ವೀಕರಿಸಲು ನೀವು ಅದರ ಸ್ಥಳ ಅಥವಾ ದಿಕ್ಕನ್ನು ಹೊಂದಿಸಬೇಕಾಗಬಹುದು. ಉತ್ತಮ ಫಲಿತಾಂಶಗಳಿಗೆ, ಅದನ್ನು ಎತ್ತರದಲ್ಲಿ ಮತ್ತು ಕಿಟಕಿಯ ಬಳಿ ಇರಿಸಿ."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"ಮುಂದುವರಿಸು"</item>
+ <item msgid="727245208787621142">"ಸದ್ಯಕ್ಕೆ ಬೇಡ"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"ಚಾನಲ್ ಸೆಟಪ್ ಅನ್ನು ಮರುರನ್ ಮಾಡುವುದೇ?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"ಟಿವಿ ಟ್ಯೂನರ್‌ನಿಂದ ಪತ್ತೆ ಮಾಡಲಾದ ಚಾನಲ್‌ಗಳನ್ನು ಇದು ತೆಗೆದುಹಾಕುತ್ತದೆ ಹಾಗೂ ಮತ್ತೆ ಹೊಸ ಚಾನಲ್‌ಗಳಿಗೆ ಸ್ಕ್ಯಾನ್ ಮಾಡಲಾಗುತ್ತದೆ.\n\nನಿಮ್ಮ ಟಿವಿಯನ್ನು ಟಿವಿ ಸಿಗ್ನಲ್‌ ಮೂಲಕ್ಕೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆಯೆ ಎಂದು ಪರಿಶೀಲಿಸಿ.\n\nನೀವು ಪ್ರಸಾರದ ಮೂಲಕ ಆಂಟೆನಾ ಬಳಸುತ್ತಿದ್ದರೆ, ಹೆಚ್ಚಿನ ಚಾನಲ್‌ಗಳನ್ನು ಸ್ವೀಕರಿಸಲು ನೀವು ಅದರ ಸ್ಥಳ ಅಥವಾ ದಿಕ್ಕನ್ನು ಹೊಂದಿಸಬೇಕಾಗಬಹುದು. ಉತ್ತಮ ಫಲಿತಾಂಶಗಳಿಗೆ, ಇದನ್ನು ಎತ್ತರದಲ್ಲಿ ಮತ್ತು ಕಿಟಕಿಯ ಬಳಿ ಇರಿಸಿ."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"USB ಟ್ಯೂನರ್‌ನಿಂದ ಪತ್ತೆ ಮಾಡಲಾದ ಚಾನಲ್‌ಗಳನ್ನು ಇದು ತೆಗೆದುಹಾಕುತ್ತದೆ ಹಾಗೂ ಮತ್ತೆ ಹೊಸ ಚಾನಲ್‌ಗಳಿಗೆ ಸ್ಕ್ಯಾನ್ ಮಾಡಲಾಗುತ್ತದೆ.\n\nUSB ಟ್ಯೂನಲ್ ಅನ್ನು ಪ್ಲಗ್ ಇನ್ ಮಾಡಲಾಗಿದೆಯೇ ಮತ್ತು ಟಿವಿ ಸಿಗ್ನಲ್ ಮೂಲಕ್ಕೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆಯೆ ಎಂದು ಪರಿಶೀಲಿಸಿ.\n\nನೀವು ಪ್ರಸಾರದ ಮೂಲಕ ಆಂಟೆನಾ ಬಳಸುತ್ತಿದ್ದರೆ, ಹೆಚ್ಚಿನ ಚಾನಲ್‌ಗಳನ್ನು ಸ್ವೀಕರಿಸಲು ನೀವು ಅದರ ಸ್ಥಳ ಅಥವಾ ದಿಕ್ಕನ್ನು ಹೊಂದಿಸಬೇಕಾಗಬಹುದು. ಉತ್ತಮ ಫಲಿತಾಂಶಗಳಿಗೆ, ಇದನ್ನು ಎತ್ತರದಲ್ಲಿ ಮತ್ತು ಕಿಟಕಿಯ ಬಳಿ ಇರಿಸಿ ಹಾಗೂ ಮತ್ತೆ ಸ್ಕ್ಯಾನ್ ಮಾಡಿ."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"ನೆಟ್‌ವರ್ಕ್ ಟ್ಯೂನರ್‌ನಿಂದ ಪತ್ತೆ ಮಾಡಲಾದ ಚಾನಲ್‌ಗಳನ್ನು ಇದು ತೆಗೆದುಹಾಕುತ್ತದೆ ಹಾಗೂ ಮತ್ತೆ ಹೊಸ ಚಾನಲ್‌ಗಳಿಗೆ ಸ್ಕ್ಯಾನ್ ಮಾಡುತ್ತದೆ.\n\nನೆಟ್‌ವರ್ಕ್ ಟ್ಯೂನಲ್ ಅನ್ನು ಆನ್ ಮಾಡಲಾಗಿದೆಯೇ ಮತ್ತು ಟಿವಿ ಸಿಗ್ನಲ್ ಮೂಲಕ್ಕೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆಯೇ ಎಂದು ಪರಿಶೀಲಿಸಿ.\n\nನೀವು ನೆಟ್‌ವರ್ಕ್ ಸಂಪರ್ಕದ ಮೂಲಕ ಆಂಟೆನಾ ಬಳಸುತ್ತಿದ್ದರೆ, ಹೆಚ್ಚಿನ ಚಾನಲ್‌ಗಳನ್ನು ಸ್ವೀಕರಿಸಲು ನೀವು ಅದರ ಸ್ಥಳ ಅಥವಾ ದಿಕ್ಕನ್ನು ಹೊಂದಿಸಬೇಕಾಗಬಹುದು. ಉತ್ತಮ ಫಲಿತಾಂಶಗಳಿಗೆ, ಅದನ್ನು ಎತ್ತರದಲ್ಲಿ ಮತ್ತು ಕಿಟಕಿಯ ಬಳಿ ಇರಿಸಿ."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"ಮುಂದುವರಿಸು"</item>
+ <item msgid="235450158666155406">"ರದ್ದುಮಾಡಿ"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"ಸಂಪರ್ಕದ ಪ್ರಕಾರ ಆಯ್ಕೆಮಾಡಿ"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"ಟ್ಯೂನರ್‌ಗೆ ಬಾಹ್ಯ ಆಂಟೆನಾವನ್ನು ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದ್ದರೆ ಆಂಟೆನಾ ಆರಿಸಿಕೊಳ್ಳಿ. ನಿಮ್ಮ ಚಾನಲ್‌ಗಳು ಕೇಬಲ್ ಸೇವೆ ಪೂರೈಕೆದಾರರಿಂದ ಬರುತ್ತಿದ್ದರೆ ಕೇಬಲ್ ಆರಿಸಿಕೊಳ್ಳಿ. ನಿಮಗೆ ಯಾವುದು ಎಂದು ಖಚಿತವಿಲ್ಲದಿದ್ದರೆ, ಎರಡೂ ಪ್ರಕಾರಗಳನ್ನು ಸ್ಕ್ಯಾನ್ ಮಾಡಲಾಗುತ್ತದೆ, ಆದರೆ ಇದಕ್ಕೆ ಹೆಚ್ಚು ಸಮಯ ತೆಗೆದುಕೊಳ್ಳಬಹುದು."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"ಆಂಟೆನಾ"</item>
+ <item msgid="2670079958754180142">"ಕೇಬಲ್"</item>
+ <item msgid="36774059871728525">"ಖಚಿತವಾಗಿಲ್ಲ"</item>
+ <item msgid="6881204453182153978">"ಅಭಿವೃದ್ಧಿ ಮಾತ್ರ"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"ಟಿವಿ ಟ್ಯೂನರ್ ಸೆಟಪ್"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB ಚಾನಲ್ ಟ್ಯೂನರ್ ಸೆಟಪ್"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"ನೆಟ್‌ವರ್ಕ್ ಚಾನಲ್ ಟ್ಯೂನರ್ ಸೆಟಪ್"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"ಇದಕ್ಕೆ ಹಲವಾರು ನಿಮಿಷಗಳು ತೆಗೆದುಕೊಳ್ಳಬಹುದು"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"ಟ್ಯೂನರ್ ತಾತ್ಕಾಲಿಕವಾಗಿ ಲಭ್ಯವಿಲ್ಲ ಅಥವಾ ಈಗಾಗಲೇ ರೆಕಾರ್ಡಿಂಗ್‌ಗೆ ಬಳಸಲಾಗಿದೆ."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="one">%1$d ಚಾನಲ್‌ಗಳು ಕಂಡುಬಂದಿವೆ</item>
+ <item quantity="other">%1$d ಚಾನಲ್‌ಗಳು ಕಂಡುಬಂದಿವೆ</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"ಚಾನಲ್ ಸ್ಕ್ಯಾನ್ ಮಾಡುವುದನ್ನು ನಿಲ್ಲಿಸಿ"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="one">%1$d ಚಾನಲ್‌ಗಳು ಕಂಡುಬಂದಿವೆ</item>
+ <item quantity="other">%1$d ಚಾನಲ್‌ಗಳು ಕಂಡುಬಂದಿವೆ</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="one">ಉತ್ತಮ! ಚಾನಲ್ ಸ್ಕ್ಯಾನ್ ಸಮಯದಲ್ಲಿ %1$d ಚಾನಲ್‌ಗಳು ಕಂಡುಬಂದಿವೆ. ಇದು ಸರಿಯಲ್ಲವೆಂದು ತೋರಿದರೆ, ಆಂಟೆನಾ ಸ್ಥಿತಿಯನ್ನು ಹೊಂದಿಸಲು ಪ್ರಯತ್ನಿಸಿ ಹಾಗೂ ಮತ್ತೆ ಸ್ಕ್ಯಾನ್ ಮಾಡಿ.</item>
+ <item quantity="other">ಉತ್ತಮ! ಚಾನಲ್ ಸ್ಕ್ಯಾನ್ ಸಮಯದಲ್ಲಿ %1$d ಚಾನಲ್‌ಗಳು ಕಂಡುಬಂದಿವೆ. ಇದು ಸರಿಯಲ್ಲವೆಂದು ತೋರಿದರೆ, ಆಂಟೆನಾ ಸ್ಥಿತಿಯನ್ನು ಹೊಂದಿಸಲು ಪ್ರಯತ್ನಿಸಿ ಹಾಗೂ ಮತ್ತೆ ಸ್ಕ್ಯಾನ್ ಮಾಡಿ.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"ಮುಗಿದಿದೆ"</item>
+ <item msgid="2480490326672924828">"ಮತ್ತೆ ಸ್ಕ್ಯಾನ್ ಮಾಡು"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"ಯಾವುದೇ ಚಾನಲ್‌ಗಳು ಕಂಡುಬಂದಿಲ್ಲ"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"ಸ್ಕ್ಯಾನ್ ಯಾವುದೇ ಚಾನಲ್‌ಗಳನ್ನು ಪತ್ತೆ ಮಾಡಿಲ್ಲ. ನಿಮ್ಮ ಟಿವಿಯನ್ನು ಟಿವಿ ಸಿಗ್ನಲ್‌ ಮೂಲಕ್ಕೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆಯೆ ಎಂದು ಪರಿಶೀಲಿಸಿ.\n\nನೀವು ಪ್ರಸಾರದ ಮೂಲಕ ಆಂಟೆನಾ ಬಳಸುತ್ತಿದ್ದರೆ, ಉತ್ತಮ ಫಲಿತಾಂಶಗಳಿಗೆ, ಇದನ್ನು ಎತ್ತರದಲ್ಲಿ ಮತ್ತು ಕಿಟಕಿಯ ಬಳಿ ಇರಿಸಿ ಹಾಗೂ ಮತ್ತೆ ಸ್ಕ್ಯಾನ್ ಮಾಡಿ."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"ಸ್ಕ್ಯಾನ್ ಯಾವುದೇ ಚಾನಲ್‌ಗಳನ್ನು ಪತ್ತೆ ಮಾಡಿಲ್ಲ. USB ಟ್ಯೂನಲ್ ಅನ್ನು ಪ್ಲಗ್ ಇನ್ ಮಾಡಲಾಗಿದೆಯೇ ಮತ್ತು ಟಿವಿ ಸಿಗ್ನಲ್ ಮೂಲಕ್ಕೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆಯೆ ಎಂದು ಪರಿಶೀಲಿಸಿ.\n\nಪ್ರಸಾರದ ಮೂಲಕ ಆಂಟೆನಾ ಬಳಸುತ್ತಿದ್ದರೆ, ಅದರ ಸ್ಥಳ ಅಥವಾ ದಿಕ್ಕನ್ನು ಸರಿಹೊಂದಿಸಿ. ಉತ್ತಮ ಫಲಿತಾಂಶಗಳಿಗೆ, ಎತ್ತರದಲ್ಲಿ ಮತ್ತು ಕಿಟಕಿಯ ಬಳಿ ಇರಿಸಿ ಹಾಗೂ ಮತ್ತೆ ಸ್ಕ್ಯಾನ್ ಮಾಡಿ."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"ಸ್ಕ್ಯಾನ್ ನಂತರ ಯಾವುದೇ ಚಾನಲ್ ಕಂಡುಬಂದಿಲ್ಲ. ನೆಟ್‌ವರ್ಕ್ ಟ್ಯೂನರ್ ಆನ್ ಮಾಡಲಾಗಿದೆಯೇ ಮತ್ತು ಟಿವಿ ಸಿಗ್ನಲ್ ಮೂಲಕ್ಕೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆಯೇ ಎಂದು ಪರಿಶೀಲಿಸಿ.\n\nನೀವು ನೆಟ್‌ವರ್ಕ್ ಸಂಪರ್ಕದ ಮೂಲಕ ಆಂಟೆನಾ ಬಳಸುತ್ತಿದ್ದರೆ, ಅದರ ಸ್ಥಳ ಅಥವಾ ದಿಕ್ಕನ್ನು ಹೊಂದಿಸಿ. ಉತ್ತಮ ಫಲಿತಾಂಶಗಳಿಗೆ, ಅದನ್ನು ಎತ್ತರದಲ್ಲಿ ಮತ್ತು ಕಿಟಕಿಯ ಬಳಿ ಇರಿಸಿ ಹಾಗೂ ಮತ್ತೊಮ್ಮೆ ಸ್ಕ್ಯಾನ್ ಮಾಡಿ."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"ಮತ್ತೆ ಸ್ಕ್ಯಾನ್ ಮಾಡು"</item>
+ <item msgid="2092797862490235174">"ಮುಗಿದಿದೆ"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"ಟಿವಿ ಚಾನಲ್‌ಗಳನ್ನು ಸ್ಕ್ಯಾನ್ ಮಾಡಿ"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"ಟಿವಿ ಟ್ಯೂನರ್ ಸೆಟಪ್"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB ಟಿವಿ ಟ್ಯೂನರ್ ಸೆಟಪ್"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"ನೆಟ್‌ವರ್ಕ್ ಟಿವಿ ಟ್ಯೂನರ್ ಸೆಟಪ್"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB ಟಿವಿ ಟ್ಯೂನರ್ ಸಂಪರ್ಕ ಕಡಿತಗೊಂಡಿದೆ."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"ನೆಟ್‌ವರ್ಕ್ ಟ್ಯೂನರ್ ಸಂಪರ್ಕ ಕಡಿತಗೊಂಡಿದೆ."</string>
+</resources>
diff --git a/usbtuner-res/values-ko/strings.xml b/usbtuner-res/values-ko/strings.xml
new file mode 100644
index 00000000..fa5b6e60
--- /dev/null
+++ b/usbtuner-res/values-ko/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"TV 튜너"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB TV 튜너"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"네트워크 TV 튜너(BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"처리가 완료될 때까지 기다려 주세요."</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"튜너 소프트웨어가 최근 업데이트되었습니다. 채널을 다시 스캔하세요."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"오디오를 사용하려면 시스템 사운드 설정에서 서라운드 사운드를 사용 설정하세요."</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"오디오를 재생할 수 없습니다. 다른 TV를 사용해 보세요."</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"채널 튜너 설정"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"TV 튜너 설정"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB 채널 튜너 설정"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"네트워크 튜너 설정"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"TV가 TV 신호 소스에 연결되어 있는지 확인하세요.\n\n무선 안테나를 사용하는 경우 대부분의 채널을 수신하려면 위치나 방향을 조정해야 할 수도 있습니다. 안테나를 창가 가까이에 높게 설치하면 가장 좋습니다."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"USB 튜너가 전원 및 TV 신호 소스에 연결되어 있는지 확인하세요.\n\n무선 안테나를 사용 중인 경우 안테나 위치나 방향을 조정하세요. 창가 가까이에 높게 설치하면 가장 좋습니다."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"네트워크 튜너의 전원이 켜져 있고 TV 신호 소스에 연결되어 있는지 확인하세요.\n\n무선 안테나를 사용하는 경우 안테나 위치나 방향을 조정하세요. 최상의 결과를 얻으려면 안테나를 창가 가까이에 높게 설치하세요."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"계속"</item>
+ <item msgid="727245208787621142">"나중에"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"채널 설정을 다시 실행하시겠습니까?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"이렇게 하면 TV 튜너에서 찾은 채널을 삭제하고 새로운 채널을 다시 스캔하게 됩니다.\n\nTV가 TV 신호 소스에 연결되어 있는지 확인하세요.\n\n무선 안테나를 사용하는 경우 대부분의 채널을 수신하려면 위치나 방향을 조정해야 할 수 있습니다. 안테나를 창가 가까이에 높게 설치하면 가장 좋습니다."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"이 작업을 수행하면 USB 튜너에서 찾은 채널이 삭제되며 새로운 채널을 다시 스캔합니다.\n\nUSB 튜너가 전원 및 TV 신호 소스에 연결되어 있는지 확인하세요.\n\n무선 안테나를 사용 중인 경우 안테나 위치나 방향을 조정하세요. 창가 가까이에 높게 설치하면 가장 좋습니다."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"네트워크 튜너에서 찾은 채널이 삭제되며 새로운 채널을 다시 스캔합니다.\n\n네트워크 튜너의 전원이 켜져 있고 TV 신호 소스에 연결되어 있는지 확인하세요.\n\n무선 안테나를 사용하는 경우 안테나 위치나 방향을 조정하세요. 최상의 결과를 얻으려면 안테나를 창가 가까이에 높게 설치하고 다시 스캔해보세요."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"계속"</item>
+ <item msgid="235450158666155406">"취소"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"연결 유형 선택"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"튜너에 외부 안테나가 연결된 경우 안테나를 선택하고 케이블 서비스 제공업체에서 채널을 제공하는 경우 케이블을 선택하세요. 잘 모르는 경우 두 가지 유형이 모두 스캔되며 시간이 더 오래 걸릴 수 있습니다."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"안테나"</item>
+ <item msgid="2670079958754180142">"케이블"</item>
+ <item msgid="36774059871728525">"잘 모르겠음"</item>
+ <item msgid="6881204453182153978">"개발자 전용"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"TV 튜너 설정"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB 채널 튜너 설정"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"네트워크 채널 튜너 설정"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"이 작업은 몇 분 정도 걸릴 수 있습니다."</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"일시적으로 튜너를 사용할 수 없거나 이미 녹화에 사용하고 있습니다."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">채널 %1$d개 발견</item>
+ <item quantity="one">채널 %1$d개 발견</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"채널 스캔 중지"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">채널 %1$d개 발견</item>
+ <item quantity="one">채널 %1$d개 발견</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">좋습니다. 채널 스캔 중에 채널 %1$d개를 발견했습니다. 맞지 않는 것 같다면 안테나 위치를 조정한 후 다시 스캔하세요.</item>
+ <item quantity="one">좋습니다. 채널 스캔 중에 채널 %1$d개를 발견했습니다. 맞지 않는 것 같다면 안테나 위치를 조정한 후 다시 스캔하세요.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"완료"</item>
+ <item msgid="2480490326672924828">"다시 스캔"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"채널 없음"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"스캔 결과 채널을 찾지 못했습니다. TV가 TV 신호 소스에 연결되어 있는지 확인하세요.\n\n무선 안테나를 사용하는 경우 위치나 방향을 조정하세요. 안테나를 창가 가까이에 높게 설치하면 가장 좋습니다."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"스캔하여 채널을 찾을 수 없습니다. USB 튜너가 전원 및 TV 신호 소스에 연결되어 있는지 확인하세요.\n\n무선 안테나를 사용 중인 경우 안테나 위치나 방향을 조정하세요. 창가 가까이에 높게 설치하면 가장 좋습니다. 그런 다음 다시 스캔해 보세요."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"스캔 결과 채널을 찾지 못했습니다. 네트워크 튜너의 전원이 켜져 있고 TV 신호 소스에 연결되어 있는지 확인하세요.\n\n무선 안테나를 사용하는 경우 안테나 위치나 방향을 조정하세요. 최상의 결과를 얻으려면 안테나를 창가 가까이에 높게 설치하고 다시 스캔해보세요."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"다시 스캔"</item>
+ <item msgid="2092797862490235174">"완료"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"TV 채널 스캔"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"TV 튜너 설정"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB TV 튜너 설정"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"네트워크 TV 튜너 설정"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB TV 튜너의 연결이 끊겼습니다."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"네트워크 튜너의 연결이 끊겼습니다."</string>
+</resources>
diff --git a/usbtuner-res/values-ky-rKG/strings.xml b/usbtuner-res/values-ky-rKG/strings.xml
new file mode 100644
index 00000000..18118225
--- /dev/null
+++ b/usbtuner-res/values-ky-rKG/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Сыналгы күүлөгүчү"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB сыналгы күүлөгүчү"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Тармактык ТВ-тюнер (БЕТА)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Иштетүүнү бүтүрүү үчүн күтө туруңуз"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Күүлөгүчтүн программасы жакында жаңыртылды. Каналдарды кайрадан издеңиз."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Каналдын үнүн чыгаруу үчүн тутумдун үн жөндөөлөрүнө өтүп, көлөмдүү добушту иштетүү керек"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Аудио ойнотулбай жатат. Башка каналды байкап көрүңүз"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Канал күүлөгүчтү жөндөө"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Сыналгынын күүлөгүчүн жөндөө"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB канал күүлөгүчүнүн жөндөөсү"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Тармактык тюнерди жөндөө"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Сыналдыңыз сыналгынын сигнал булагына туташтырылганын текшериңиз. \n\nЭгер телеантенна колдонулуп жатса, анын ордун же багытын тууралаңыз. Мыкты кармашы үчүн аны бийик жана терезеге жакын жерге коюп, кайра издеңиз."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"USB күүлөгүч сайылып турганын жана сыналгынын сигнал булагына туташтырылганын текшериңиз.\n\nЭгер телеантенна колдонулуп жатса, көпчүлүк каналдарды табуу үчүн анын ордун же багытын тууралашыңыз керек болот. Мыкты кармашы үчүн аны бийик жана терезеге жакын жерге коюп, кайра издеңиз."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Тармактык тюнер сайылып турганын жана сыналгынын сигнал булагына туташтырылганын текшериңиз.\n\nЭгер телеантенна колдонулуп жатса, каналдарды табуу үчүн анын ордун же багытын тууралашыңыз керек болот. Антенна жакшы кармашы үчүн аны бийик жана терезеге жакын жерге коюп, кайра издеп көрүңүз."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Улантуу"</item>
+ <item msgid="727245208787621142">"Азыр эмес"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Канал кайра жөндөлсүнбү?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Ушуну менен сыналгынын күүлөгүчүнөн табылган каналдар алынып салынып, жаңы каналдар кайра изделет.\n\nСыналдыңыз сыналгынын сигнал булагына туташтырылганын текшериңиз.\n\nIЭгер телеантенна колдонулуп жатса, көпчүлүк каналдарды табуу үчүн анын ордун же багытын тууралашыңыз керек болот. Мыкты кармашы үчүн аны бийик жана терезеге жакын жерге коюп, кайра издеңиз."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Ушуну менен USB күүлөгүчтөн табылган каналдар алынып салынып, жаңы каналдар кайра изделет.\n\nUSB күүлөгүч сайылып турганын жана сыналгынын сигнал булагына туташтырылганын текшериңиз.\n\nЭгер телеантенна колдонулуп жатса, көпчүлүк каналдарды табуу үчүн анын ордун же багытын тууралашыңыз керек болот. Мыкты кармашы үчүн аны бийик жана терезеге жакын жерге коюп, кайра издеңиз."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Ушуну менен тармактык тюнер аркылуу табылган каналдар алынып салынып, жаңы каналдар кайра изделет.\n\nТармактык тюнер сайылып турганын жана сыналгынын сигнал булагына туташтырылганын текшериңиз.\n\nЭгер телеантенна колдонулуп жатса, каналдарды табуу үчүн анын ордун же багытын тууралашыңыз керек болот. Антенна жакшы кармашы үчүн аны бийик жана терезеге жакын жерге коюп, кайра издеп көрүңүз."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Улантуу"</item>
+ <item msgid="235450158666155406">"Токтотуу"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Туташуу түрүн тандаңыз"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Күүлөгүчтө туташтырылган тышкы антенна болсо, Антеннаны тандаңыз. Эгер каналдарыңыз кабелдик кызмат камсыздоочусунан алынса, Кабелди тандаңыз. Эгер так билбесеңиз, эки түрү тең изделет, бирок ал узагыраак созулушу мүмкүн."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Антенна"</item>
+ <item msgid="2670079958754180142">"Кабель"</item>
+ <item msgid="36774059871728525">"Так айта албайм"</item>
+ <item msgid="6881204453182153978">"Иштеп чыгуучулар үчүн гана"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Сыналгы күүлөгүчүн жөндөө"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB канал күүлөгүчүн жөндөө"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Тармактык каналдын тюнерин жөндөө"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Бир нече мүнөт созулушу мүмкүн"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Тюнер убактылуу жеткиликсиз же жаздыруу үчүн колдонулууда."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">%1$d канал табылды</item>
+ <item quantity="one">%1$d канал табылды</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"КАНАЛ ИЗДӨӨНҮ ТОКТОТУУ"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">%1$d канал табылды</item>
+ <item quantity="one">%1$d канал табылды</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Сонун! %1$d канал табылды. Керектүү каналдар табылбаса, антеннанын багытын өзгөртүп, кайра издеп көрүңүз.</item>
+ <item quantity="one">Сонун! %1$d канал табылды. Керектүү каналдар табылбаса, антеннанын багытын өзгөртүп, кайра издеп көрүңүз.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Бүттү"</item>
+ <item msgid="2480490326672924828">"Кайра издөө"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Бир да канал табылган жок"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Издөөдөн эч бир канал табылган жок. Сыналдыңыз сыналгынын сигнал булагына туташтырылганын текшериңиз.\n\nЭгер телеантенна колдонулуп жатса, анын ордун же багытын тууралаңыз. Мыкты кармашы үчүн аны бийик жана терезеге жакын жерге коюп, кайра издеңиз."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Издөөдөн эч бир канал табылган жок. USB күүлөгүч сайылып турганын жана сыналгынын сигнал булагына туташтырылганын текшериңиз.\n\nЭгер телеантенна колдонулуп жатса, анын ордун же багытын тууралаңыз. Мыкты кармашы үчүн аны бийик жана терезеге жакын жерге коюп, кайра издеңиз."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Каналдар табылган жок. Тармактык тюнер сайылып турганын жана сыналгынын сигнал булагына туташтырылганын текшериңиз.\n\nЭгер телеантенна колдонулуп жатса, анын ордун же багытын тууралаңыз. Антенна жакшы кармашы үчүн аны бийик жана терезеге жакын жерге коюп, кайра издеп көрүңүз."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Кайра издөө"</item>
+ <item msgid="2092797862490235174">"Бүттү"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Сыналгы каналдарын издөө"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"ТВ-тюнерди жөндөө"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB ТВ-тюнерин жөндөө"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Тармактык ТВ-тюнерди жөндөө"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB TV күүлөгүчү ажыратылды."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Тармак күүлөгүчү ажыратылды."</string>
+</resources>
diff --git a/usbtuner-res/values-lo-rLA/strings.xml b/usbtuner-res/values-lo-rLA/strings.xml
new file mode 100644
index 00000000..306576a2
--- /dev/null
+++ b/usbtuner-res/values-lo-rLA/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"ຕົວຮັບສັນຍານໂທລະພາບ"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"ຕົວຮັບສັນຍານໂທລະພາບ USB"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Network TV Tuner (ເບຕ້າ)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"ກະລຸນາລໍຖ້າເພື່ອປະມວນຜົນໃຫ້ສຳເລັດ"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"ຊອບແວຕົວປັບສັນຍານໄດ້ຮັບການອັບເດດເມື່ອບໍ່ດົນມານີ້ແລ້ວ. ກະລຸນາສະແກນຫາຊ່ອງຄືນໃໝ່."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"ເປີດໃຊ້ສຽງຮອບທິດທາງໃນການຕັ້ງຄ່າລະບົບສຽງເພື່ອເປີດໃຊ້ສຽງ."</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Cannot play audio. Please try another TV"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"ຕັ້ງເຄື່ອງຮັບສັນຍານຊ່ອງ"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"ຕັ້ງຄ່າຕົວຮັບສັນຍານໂທລະພາບ"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"ຕັ້ງເຄື່ອງຮັບສັນຍານຊ່ອງ USB"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Network tuner setup"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"ໃຫ້ກວດສອບວ່າທ່ານເຊື່ອມຕໍ່ໂທລະພາບຂອງທ່ານຫາແຫລ່ງສັນຍານໂທລະພາບແລ້ວ.\n\nຫາກໃຊ້ເສົາອາກາດ, ໃຫ້ຍ້າຍບ້ອນວາງ ຫຼື ທິດທາງຂອງມັນ. ເພື່ອໃຫ້ໄດ້ຜົນທີ່ດີທີ່ສຸດ, ໃຫ້ວາງໄວ້ບ່ອນສູງໃກ້ໆປ່ອງຢ້ຽມ ແລ້ວລອງສະແກນໃໝ່."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"ກວດສອບເບິ່ງເຄື່ອງຮັບສັນຍານ USB ວ່າ ໄດ້ສຽບສາຍ ແລະ ເຊື່ອມຕໍ່ກັບແຫຼ່ງສັນຍານໂທລະພາບແລ້ວຫຼືຍັງ.\n\nຫາກໃຊ້ເສົາອາກາດ, ໃຫ້ຍ້າຍບ້ອນວາງ ຫຼື ທິດທາງຂອງມັນ. ເພື່ອໃຫ້ໄດ້ຜົນທີ່ດີທີ່ສຸດ, ໃຫ້ວາງໄວ້ບ່ອນສູງໃກ້ໆປ່ອງຢ້ຽມ ແລ້ວລອງສະແກນໃໝ່."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"ກວດສອບເບິ່ງເຄື່ອງຮັບສັນຍານເຄືອຂ່າຍວ່າ ໄດ້ສຽບສາຍ ແລະ ເຊື່ອມຕໍ່ກັບແຫຼ່ງສັນຍານໂທລະພາບແລ້ວຫຼືຍັງ.\n\nຫຼຫາກໃຊ້ເສົາອາກາດ, ໃຫ້ຍ້າຍບ່ອນວາງ ຫຼື ທິດທາງຂອງມັນ. ເພື່ອໃຫ້ໄດ້ຜົນທີ່ດີທີ່ສຸດ, ໃຫ້ວາງໄວ້ບ່ອນສູງໃກ້ໆປ່ອງຢ້ຽມ ແລ້ວລອງສະແກນໃໝ່."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"ສືບຕໍ່"</item>
+ <item msgid="727245208787621142">"ບໍ່ແມ່ນຕອນນີ້"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"ຕັ້ງຄ່າຊ່ອງຄືນໃໝ່ບໍ່?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"ນີ້ເປັນການລຶບຊ່ອງທີ່ພົບແລ້ວອອກໄປຈາກຕົວຮັບສັນຍານໂທລະພາບ ແລະ ສະແກນຫາຊ່ອງໃໝ່ອີກຄັ້ງ.\n\nກວດສອບເບິ່ງຕົວຮັບສັນຍານໂທລະພາບວ່າໄດ້ສຽບສາຍ ແລະ ເຊື່ອມຕໍ່ກັບແຫຼ່ງສັນຍານໂທລະພາບແລ້ວຫຼືຍັງ.\n\nຫາກໃຊ້ເສົາອາກາດ, ໃຫ້ຍ້າຍບ້ອນວາງ ຫຼື ທິດທາງຂອງມັນ. ເພື່ອໃຫ້ໄດ້ຜົນທີ່ດີທີ່ສຸດ, ໃຫ້ວາງໄວ້ບ່ອນສູງໃກ້ໆປ່ອງຢ້ຽມ ແລ້ວລອງສະແກນໃໝ່."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"ນີ້ຈະເປັນການລຶບຊ່ອງທີ່ພົບແລ້ວອອກໄປຈາກເຄື່ອງຮັບສັນຍານ USB ແລະ ສະແກນຫາຊ່ອງໃໝ່ອີກ.\n\nໃຫ້ກວດສອບເບິ່ງເຄື່ອງຮັບສັນຍານ USB ວ່າ ໄດ້ສຽບສາຍ ແລະ ເຊື່ອມຕໍ່ກັບແຫຼ່ງສັນຍານໂທລະພາບແລ້ວຫຼືຍັງ.\n\nຫາກໃຊ້ເສົາອາກາດ, ໃຫ້ຍ້າຍບ້ອນວາງ ຫຼື ທິດທາງຂອງມັນ. ເພື່ອໃຫ້ໄດ້ຜົນທີ່ດີທີ່ສຸດ, ໃຫ້ວາງໄວ້ບ່ອນສູງໃກ້ໆປ່ອງຢ້ຽມ ແລ້ວລອງສະແກນໃໝ່."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"ນີ້ຈະເປັນການລຶບຊ່ອງທີ່ພົບແລ້ວອອກໄປຈາກເຄື່ອງຮັບສັນຍານເຄືອຂ່າຍ ແລະ ສະແກນຫາຊ່ອງໃໝ່ອີກຄັ້ງ.\n\nໃຫ້ກວດສອບເບິ່ງເຄື່ອງຮັບສັນຍານເຄືອຂ່າຍວ່າໄດ້ສຽບສາຍ ແລະ ເຊື່ອມຕໍ່ກັບແຫຼ່ງສັນຍານໂທລະພາບແລ້ວຫຼືຍັງ.\n\nຫາກໃຊ້ເສົາອາກາດ, ທ່ານອາດຈະຕ້ອງໄດ້ປັບການຕັ້ງ ຫຼື ທິດທາງຂອງມັນ. ເພື່ອໃຫ້ໄດ້ຜົນດີຂຶ້ນ, ວາງມັນໄວ້ສູງ ແລະ ໃກ້ກັບປ່ອງຢ້ຽມແລ້ວສະແກນໃໝ່ອີກຄັ້ງ."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"ສືບຕໍ່"</item>
+ <item msgid="235450158666155406">"ຍົກເລີກ"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"ເລືອກປະເພດການເຊື່ອມຕໍ່"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"ເລືອກເສົາອາກາດ ຖ້າມີເສົາອາກາດແບບແຍກທີ່ເຊື່ອມຕໍ່ກັບເຄື່ອງຮັບສັນຍານ. ເລືອກສາຍເຄເບິ້ນ ຖ້າຊ່ອງຂອງທ່ານມາຈາກຜູ້ໃຫ້ບໍລິການສາຍເຄເບິ້ນ. ຖ້າທ່ານບໍ່ແນ່ໃຈ, ຈະມີການສະແກນທັງສອງປະເພດ, ແຕ່ແບບນີ້ຈະໃຊ້ເວລາດົນກວ່າ."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"ເສົາອາກາດ"</item>
+ <item msgid="2670079958754180142">"ສາຍຕໍ່"</item>
+ <item msgid="36774059871728525">"ບໍ່ແນ່ໃຈ"</item>
+ <item msgid="6881204453182153978">"ການພັດທະນາເທົ່ານັ້ນ"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"ຕັ້ງຄ່າຕົວຮັບສັນຍານໂທລະພາບ"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"ການຕັ້ງເຄື່ອງຮັບສັນຍານຊ່ອງ USB"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"ຕັ້ງຄ່າຕົວຈູນສັນຍານຊ່ອງເຄືອຂ່າຍ"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"ຂັ້ນຕອນນີ້ອາດຈະໃຊ້ເວລາຫຼາຍນາທີ"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"ຈູນເນີບໍ່ສາມາດໃຊ້ໄດ້ຊົ່ວຄາວ ຫຼື ຖືກໃຊ້ໂດຍການບັນທຶກໃດໜຶ່ງຢູ່ກ່ອນແລ້ວ."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">ພົບ %1$d ຊ່ອງ</item>
+ <item quantity="one">ພົບ %1$d ຊ່ອງ</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"ຢຸດການສະແກນຊ່ອງ"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">ພົບ %1$d ຊ່ອງ</item>
+ <item quantity="one">ພົບ %1$d ຊ່ອງ</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">ດີຫຼາຍ! ພົບ %1$d ຊ່ອງໃນລະຫວ່າງການສະແກນຫາຊ່ອງ. ຖ້ານີ້ປາກົດວ່າບໍ່ຖືກຕ້ອງ, ໃຫ້ລອງປັບຕຳແໜ່ງເສົາອາກາດ ແລ້ວສະແກນໃໝ່.</item>
+ <item quantity="one">ດີຫຼາຍ! ພົບ %1$d ຊ່ອງໃນລະຫວ່າງການສະແກນຫາຊ່ອງ. ຖ້ານີ້ປາກົດວ່າບໍ່ຖືກຕ້ອງ, ໃຫ້ລອງປັບຕຳແໜ່ງເສົາອາກາດ ແລ້ວສະແກນໃໝ່.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"ແລ້ວໆ"</item>
+ <item msgid="2480490326672924828">"ສະແກນອີກ"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"ບໍ່ພົບຊ່ອງໃດ"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"ການສະແກນບໍ່ພົບຊ່ອງໃດໆເລີຍ. ໃຫ້ຢັ້ງຢືນວ່າທ່ານເຊື່ອມຕໍ່ໂທລະພາບຂອງທ່ານຫາແຫລ່ງສັນຍານໂທລະພາບແລ້ວ.\n\nຫາກໃຊ້ເສົາອາກາດ, ໃຫ້ຍ້າຍບ້ອນວາງ ຫຼື ທິດທາງຂອງມັນ. ເພື່ອໃຫ້ໄດ້ຜົນທີ່ດີທີ່ສຸດ, ໃຫ້ວາງໄວ້ບ່ອນສູງໃກ້ໆປ່ອງຢ້ຽມ ແລ້ວລອງສະແກນໃໝ່."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"ການສະແກນບໍ່ພົບຊ່ອງໃດ. ໃຫ້ກວດສອບເບິ່ງເຄື່ອງຮັບສັນຍານ USB ວ່າໄດ້ສຽບສາຍ ແລະ ເຊື່ອມຕໍ່ກັບແຫຼ່ງສັນຍານໂທລະພາບແລ້ວຫຼືຍັງ.\n\nຫາກໃຊ້ເສົາອາກາດ, ໃຫ້ຍ້າຍບ້ອນວາງ ຫຼື ທິດທາງຂອງມັນ. ເພື່ອໃຫ້ໄດ້ຜົນທີ່ດີທີ່ສຸດ, ໃຫ້ວາງໄວ້ບ່ອນສູງໃກ້ໆປ່ອງຢ້ຽມ ແລ້ວລອງສະແກນໃໝ່."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"ການສະແກນບໍ່ພົບຊ່ອງໃດ. ໃຫ້ກວດສອບເບິ່ງເຄື່ອງຮັບສັນຍານເຄືອຂ່າຍວ່າໄດ້ສຽບສາຍ ແລະ ເຊື່ອມຕໍ່ກັບແຫຼ່ງສັນຍານໂທລະພາບແລ້ວຫຼືຍັງ.\n\nຫາກໃຊ້ເສົາອາກາດ, ໃຫ້ຍ້າຍບ້ອນວາງ ຫຼື ທິດທາງຂອງມັນ. ເພື່ອໃຫ້ໄດ້ຜົນທີ່ດີທີ່ສຸດ, ໃຫ້ວາງໄວ້ບ່ອນສູງໃກ້ໆປ່ອງຢ້ຽມ ແລ້ວລອງສະແກນໃໝ່."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"ສະແກນອີກ"</item>
+ <item msgid="2092797862490235174">"ແລ້ວໆ"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"ສະແກນຫາຊ່ອງໂທລະທັດ"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"ຕັ້ງຄ່າຕົວຮັບສັນຍານໂທລະທັດ"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"ຕັ້ງຄ່າຕົວຮັບສັນຍານໂທລະທັດແບບ USB"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"ຕັ້ງຄ່າຕົວຮັບສັນຍານໂທລະທັດເຄືອຂ່າຍ"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"ຕັດການເຊື່ອມຕໍ່ USB TV tuner ແລ້ວ."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"ຕັດການເຊື່ອມຕໍ່ຕົວຈູນສັນຍານເຄືອຂ່າຍແລ້ວ."</string>
+</resources>
diff --git a/usbtuner-res/values-lt/strings.xml b/usbtuner-res/values-lt/strings.xml
new file mode 100644
index 00000000..c55020bd
--- /dev/null
+++ b/usbtuner-res/values-lt/strings.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"TV imtuvas"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB TV imtuvas"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Tinklo TV imtuvas (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Palaukite, kol baigsis apdorojimas"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Imtuvo programinė įranga buvo neseniai atnaujinta. Iš naujo nuskaitykite kanalus."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Įgalinkite erdvinį garsą sistemos garso nustatymuose, kad galėtumėte įgalinti garsą"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Negalima paleisti garso įrašo. Bandykite naudoti kitą TV"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Kanalų imtuvo sąranka"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"TV imtuvo sąranka"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB kanalų imtuvo sąranka"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Tinklo imtuvo sąranka"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Įsitikinkite, kad jūsų TV prijungtas prie TV signalo šaltinio.\n\nJei naudojate belaidę anteną, koreguokite jos vietą arba kryptį. Kad pasiektumėte geriausių rezultatų, ją padėkite aukštai prie lango."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Įsitikinkite, kad USB imtuvas prijungtas prie maitinimo ir TV signalo šaltinio.\n\nJei naudojate belaidę anteną, koreguokite jos vietą arba kryptį, kad būtų rodoma kuo daugiau kanalų. Kad pasiektumėte geriausių rezultatų, ją padėkite aukštai prie lango."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Įsitikinkite, kad tinklo imtuvas yra įjungtas ir prijungtas prie TV signalo šaltinio.\n\nJei naudojate belaidę anteną, koreguokite jos vietą arba kryptį. Kad pasiektumėte geriausių rezultatų, ją padėkite aukštai prie lango ir nuskaitykite dar kartą."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Tęsti"</item>
+ <item msgid="727245208787621142">"Ne dabar"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Iš naujo vykdyti kanalų sąranką?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Tai atlikus bus pašalinti kanalai, kuriuos aptiko TV imtuvas, ir bus vėl ieškoma naujų kanalų.\n\nNuskaičius nerasta jokių kanalų. Įsitikinkite, kad jūsų TV prijungtas prie TV signalo šaltinio.\n\nJei naudojate belaidę anteną, koreguokite jos vietą arba kryptį. Kad pasiektumėte geriausių rezultatų, ją padėkite aukštai prie lango."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Taip bus pašalinti rasti kanalai iš USB imtuvo ir nauji kanalai nuskaityti dar kartą.\n\nĮsitikinkite, kad USB imtuvas prijungtas prie maitinimo ir TV signalo šaltinio.\n\nJei naudojate belaidę anteną, koreguokite jos vietą arba kryptį, kad būtų rodoma kuo daugiau kanalų. Kad pasiektumėte geriausių rezultatų, ją padėkite aukštai prie lango."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Atlikus šį veiksmą iš tinklo imtuvo bus pašalinti rasti kanalai ir bus dar kartą nuskaitoma ieškant naujų kanalų.\n\nĮsitikinkite, kad tinklo imtuvas yra įjungtas ir prijungtas prie TV signalo šaltinio.\n\nJei naudojate belaidę anteną, koreguokite jos vietą arba kryptį. Kad pasiektumėte geriausių rezultatų, ją padėkite aukštai prie lango ir nuskaitykite dar kartą."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Tęsti"</item>
+ <item msgid="235450158666155406">"Atšaukti"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Pasirinkti ryšio tipą"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Pasirinkite „Antena“, jei prie imtuvo prijungta išorinė antena. Pasirinkite „Laidas“, jei kanalus teikia kabelinės paslaugos teikėjas. Jei nesate tikri, bus nuskaityti abiejų tipų kanalai, bet tai gali užtrukti ilgiau."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antena"</item>
+ <item msgid="2670079958754180142">"Laidas"</item>
+ <item msgid="36774059871728525">"Nežinau"</item>
+ <item msgid="6881204453182153978">"Tik kūrimas"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"TV imtuvo sąranka"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB kanalų imtuvo sąranka"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Tinklo kanalų imtuvo sąranka"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Tai gali užtrukti kelias minutes"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Derintuvas laikinai nepasiekiamas arba jau yra naudojamas įrašant."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="one">Rastas %1$d kanalas</item>
+ <item quantity="few">Rasti %1$d kanalai</item>
+ <item quantity="many">Rasta %1$d kanalo</item>
+ <item quantity="other">Rasta %1$d kanalų</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"SUSTABDYTI KANALŲ NUSKAITYMĄ"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="one">Rastas %1$d kanalas</item>
+ <item quantity="few">Rasti %1$d kanalai</item>
+ <item quantity="many">Rasta %1$d kanalo</item>
+ <item quantity="other">Rasta %1$d kanalų</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="one">Puiku! Nuskaitant kanalus rastas %1$d kanalas. Jei tai neatrodo tinkamas rezultatas, pabandykite pakoreguoti antenos padėtį ir nuskaityti dar kartą.</item>
+ <item quantity="few">Puiku! Nuskaitant kanalus rasti %1$d kanalai. Jei tai neatrodo tinkamas rezultatas, pabandykite pakoreguoti antenos padėtį ir nuskaityti dar kartą.</item>
+ <item quantity="many">Puiku! Nuskaitant kanalus rasta %1$d kanalo. Jei tai neatrodo tinkamas rezultatas, pabandykite pakoreguoti antenos padėtį ir nuskaityti dar kartą.</item>
+ <item quantity="other">Puiku! Nuskaitant kanalus rasta %1$d kanalų. Jei tai neatrodo tinkamas rezultatas, pabandykite pakoreguoti antenos padėtį ir nuskaityti dar kartą.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Atlikta"</item>
+ <item msgid="2480490326672924828">"Nuskaityti dar kartą"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Nerasta kanalų"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Nuskaičius nerasta jokių kanalų. Įsitikinkite, kad jūsų TV prijungtas prie TV signalo šaltinio.\n\nJei naudojate belaidę anteną, koreguokite jos vietą arba kryptį. Kad pasiektumėte geriausių rezultatų, ją padėkite aukštai prie lango ir nuskaitykite dar kartą."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Nuskaitant nerasta kanalų. Patvirtinkite, ar USB imtuvas prijungtas prie TV signalo šaltinio.\n\nJei naudojate belaidę anteną, koreguokite jos vietą arba kryptį. Kad pasiektumėte geriausių rezultatų, ją padėkite aukštai prie lango ir nuskaitykite dar kartą."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Nuskaičius nerasta jokių kanalų. Įsitikinkite, kad tinklo imtuvas yra įjungtas ir prijungtas prie TV signalo šaltinio.\n\nJei naudojate belaidę anteną, koreguokite jos vietą arba kryptį. Kad pasiektumėte geriausių rezultatų, ją padėkite aukštai prie lango ir nuskaitykite dar kartą."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Nuskaityti dar kartą"</item>
+ <item msgid="2092797862490235174">"Atlikta"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Nuskaitykite TV kanalus"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"TV imtuvo sąranka"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB TV imtuvo sąranka"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Tinklo TV imtuvo sąranka"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB TV imtuvas atjungtas."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Tinklo imtuvas atjungtas."</string>
+</resources>
diff --git a/usbtuner-res/values-lv/strings.xml b/usbtuner-res/values-lv/strings.xml
new file mode 100644
index 00000000..df910fab
--- /dev/null
+++ b/usbtuner-res/values-lv/strings.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"TV kanālu meklētājs"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB TV kanālu meklētājs"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Interneta TV kanālu meklētājs (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Lūdzu, uzgaidiet, līdz tiks pabeigta apstrāde!"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Nesen tika atjaunināta kanālu meklētāja programmatūra. Lūdzu, atkārtoti meklējiet kanālus."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Lai ieslēgtu audio, sistēmas skaņas iestatījumos iespējojiet ieskaujošo skaņu."</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Nevar atskaņot audio. Lūdzu, izmantojiet citu televizoru."</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Kanālu meklētāja iestatīšana"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"TV kanālu meklētāja iestatīšana"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB kanālu meklētāja iestatīšana"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Interneta kanālu meklētāja iestatīšana"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Pārbaudiet, vai televizors ir pievienots TV signāla avotam.\n\nJa izmantojat bezvadu antenu, iespējams, būs jāmaina tās novietojums vai virziens, lai uztvertu lielāko daļu kanālu. Lai iegūtu labākos rezultātus, novietojiet antenu augstu pie loga."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Pārbaudiet, vai USB kanālu meklētājs ir pievienots strāvas avotam un TV signāla avotam.\n\nJa izmantojat bezvadu antenu, mainiet tās novietojumu un virzienu. Lai iegūtu labākos rezultātus, novietojiet antenu augstu pie loga un atkārtojiet kanālu meklēšanu."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Pārbaudiet, vai interneta kanālu meklētājs ir ieslēgts un pievienots TV signāla avotam.\n\nJa izmantojat bezvadu antenu, iespējams, jāmaina tās novietojums vai virziens, lai uztvertu lielāko daļu kanālu. Lai iegūtu labākos rezultātus, novietojiet antenu augstu pie loga."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Turpināt"</item>
+ <item msgid="727245208787621142">"Vēlāk"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Vai atkārtot kanālu iestatīšanu?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Šādi no TV kanālu meklētāja tiks noņemti atrastie kanāli un tiks vēlreiz meklēti jauni kanāli.\n\nPārbaudiet, vai televizors ir pievienots TV signāla avotam.\n\nJa izmantojat bezvadu antenu, iespējams, būs jāmaina tās novietojums vai virziens, lai uztvertu lielāko daļu kanālu. Lai iegūtu labākos rezultātus, novietojiet antenu augstu pie loga."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Tādējādi tiks noņemti kanāli, kas tika atrasti ar USB kanālu meklētāju, un tiks atkārtota kanālu meklēšana.\n\nPārbaudiet, vai USB kanālu meklētājs ir pievienots strāvas avotam un TV signāla avotam.\n\nJa izmantojat bezvadu antenu, mainiet tās novietojumu un virzienu, lai uztvertu lielāko daļu kanālu. Lai iegūtu labākos rezultātus, novietojiet antenu augstu pie loga."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Šādi no interneta kanālu meklētāja tiks noņemti atrastie kanāli un tiks vēlreiz meklēti jauni kanāli.\n\nPārbaudiet, vai interneta kanālu meklētājs ir ieslēgts un pievienots TV signāla avotam.\n\nJa izmantojat bezvadu antenu, iespējams, jāmaina tās novietojums vai virziens, lai uztvertu lielāko daļu kanālu. Lai iegūtu labākos rezultātus, novietojiet antenu augstu pie loga."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Turpināt"</item>
+ <item msgid="235450158666155406">"Atcelt"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Atlasiet savienojuma veidu"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Ja kanālu meklētājam ir ārējā antena, izvēlieties opciju “Antena”. Ja izmantojat kabeļtelevīziju, izvēlieties opciju “Kabelis”. Ja neesat pārliecināts, kanālu meklēšana tiks veikta, izmantojot abas opcijas, taču būs nepieciešams vairāk laika."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antena"</item>
+ <item msgid="2670079958754180142">"Kabelis"</item>
+ <item msgid="36774059871728525">"Neesmu pārliecināts"</item>
+ <item msgid="6881204453182153978">"Tikai izstrāde"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"TV kanālu meklētāja iestatīšana"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB kanālu meklētāja iestatīšana"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Interneta kanālu meklētāja iestatīšana"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Tas var ilgt vairākas minūtes."</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Kanālu meklētājs īslaicīgi nav pieejams, vai arī tas jau tiek izmantots ierakstīšanai."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="zero">Atrasti %1$d kanāli</item>
+ <item quantity="one">Atrasts %1$d kanāls</item>
+ <item quantity="other">Atrasti %1$d kanāli</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"APTURĒT KANĀLU MEKLĒŠANU"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="zero">Atrasti %1$d kanāli</item>
+ <item quantity="one">Atrasts %1$d kanāls</item>
+ <item quantity="other">Atrasti %1$d kanāli</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="zero">Lieliski! Tika atrasti %1$d kanāli. Ja jums šķiet, ka kaut kas nav pareizi, noregulējiet antenu un meklējiet kanālus vēlreiz.</item>
+ <item quantity="one">Lieliski! Tika atrasts %1$d kanāls. Ja jums šķiet, ka kaut kas nav pareizi, noregulējiet antenu un meklējiet kanālus vēlreiz.</item>
+ <item quantity="other">Lieliski! Tika atrasti %1$d kanāli. Ja jums šķiet, ka kaut kas nav pareizi, noregulējiet antenu un meklējiet kanālus vēlreiz.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Gatavs"</item>
+ <item msgid="2480490326672924828">"Meklēt vēlreiz"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Netika atrasts neviens kanāls"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Veicot meklēšanu, netika atrasts neviens kanāls. Pārbaudiet, vai televizors pievienots TV signāla avotam.\n\nJa izmantojat bezvadu antenu, mainiet tās novietojumu vai virzienu. Lai iegūtu labākos rezultātus, novietojiet antenu augstu pie loga, bet pēc tam vēlreiz veiciet meklēšanu."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Netika atrasts neviens kanāls. Pārbaudiet, vai USB kanālu meklētājs ir pievienots strāvas avotam un TV signāla avotam.\n\nJa izmantojat bezvadu antenu, mainiet tās novietojumu un virzienu. Lai iegūtu labākos rezultātus, novietojiet antenu augstu pie loga un atkārtojiet kanālu meklēšanu."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Netika atrasts neviens kanāls. Pārbaudiet, vai interneta kanālu meklētājs ir ieslēgts un pievienots TV signāla avotam.\n\nJa izmantojat bezvadu antenu, mainiet tās novietojumu un virzienu. Lai iegūtu labākos rezultātus, novietojiet antenu augstu pie loga un atkārtojiet kanālu meklēšanu."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Meklēt vēlreiz"</item>
+ <item msgid="2092797862490235174">"Gatavs"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"TV kanālu meklēšana"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"TV kanālu meklētāja iestatīšana"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB TV kanālu meklētāja iestatīšana"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Interneta TV kanālu meklētāja iestatīšana"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB TV kanālu meklētājs ir atvienots."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Interneta kanālu meklētājs ir atvienots."</string>
+</resources>
diff --git a/usbtuner-res/values-mk-rMK/strings.xml b/usbtuner-res/values-mk-rMK/strings.xml
new file mode 100644
index 00000000..2db086e1
--- /dev/null
+++ b/usbtuner-res/values-mk-rMK/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"ТВ приемник"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"ТВ приемник со USB"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Мрежен ТВ приемник (БЕТА)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Почекајте да заврши обработувањето"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Софтверот на приемникот неодамна е ажуриран. Скенирајте ги каналите повторно."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Овозможете опкружувачки звук во поставките за звуци на системот за да овозможите аудио"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Не може да се пушти аудио. Обидете се со друг ТВ"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Поставување приемник на канали"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Поставување ТВ приемник"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Поставување на USB-приемникот за канали"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Поставување мрежен приемник"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Потврдете дека телевизорот е приклучен и поврзан со изворот на ТВ сигналот.\n\nАко користите безжична антена, можеби ќе треба да ја приспособите поставеноста или насоката за да примате најмногу канали. За најдобри резултати, поставете ја високо и во близина на прозорец."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Потврдете дека USB-приемникот е приклучен и поврзан со изворот на ТВ сигналот.\n\nАко користите безжична антена, можеби ќе треба да ја приспособите поставеноста или насоката за да примате најмногу канали. За најдобри резултати, поставете ја високо и во близина на прозорец."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Потврдете дека мрежниот приемник е вклучен и поврзан со изворот на ТВ сигналот.\n\nАко користите безжична антена, може ќе треба да ја приспособите поставеноста или насоката за да примате најмногу канали. За најдобри резултати, поставете ја високо и во близина на прозорец."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Продолжи"</item>
+ <item msgid="727245208787621142">"Не сега"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Да се изврши поставувањето на каналите повторно?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Ова ќе ги отстрани каналите од ТВ приемникот и ќе скенира за нови канали повторно.\n\nПотврдете дека телевизорот е поврзан со изворот на ТВ сигналот.\n\nАко користите безжична антена, приспособете ја поставеноста или насоката. За најдобри резултати, поставете ја високо и во близина на прозорец."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Ова ќе ги отстрани каналите од USB-приемникот и ќе скенира за нови канали повторно.\n\nПотврдете дека USB-приемникот е приклучен и поврзан со изворот на ТВ сигналот.\n\nАко користите безжична антена, можеби ќе треба да ја приспособите поставеноста или насоката за да примате најмногу канали. За најдобри резултати, поставете ја високо и во близина на прозорец."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Ова ќе ги отстрани каналите од мрежниот приемник и ќе скенира за нови канали повторно.\n\nПотврдете дека мрежниот приемник е вклучен и поврзан со изворот на ТВ сигналот.\n\nАко користите безжична антена, може ќе треба да ја приспособите поставеноста или насоката. За најдобри резултати, поставете ја високо и во близина на прозорец."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Продолжи"</item>
+ <item msgid="235450158666155406">"Откажи"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Изберете го типот врска"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Изберете „Антена“ ако има надворешна антена поврзана со приемникот. Изберете „Кабел“ ако каналите ви ги обезбедува кабелски оператор. Ако не сте сигурни, и двата типа ќе се скенираат, но тоа може да трае подолго."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Антена"</item>
+ <item msgid="2670079958754180142">"Кабел"</item>
+ <item msgid="36774059871728525">"Не сум сигурен"</item>
+ <item msgid="6881204453182153978">"Само за програмери"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Поставување ТВ приемник"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Поставување на USB-приемникот за канали"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Поставување мрежен приемник на канали"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Ова може да трае неколку минути"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Приемникот е привремено недостапен или веќе се користи за снимање."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="one">Пронајден е %1$d канал</item>
+ <item quantity="other">Пронајдени се %1$d канали</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"ЗАПРИ ГО СКЕНИРАЊЕТО КАНАЛИ"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="one">Пронајден е %1$d канал</item>
+ <item quantity="other">Пронајдени се %1$d канали</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="one">Убаво! Пронајдени се %1$d канали во текот на скенирањето канали. Ако се чини дека тоа не е во ред, обидете се со приспособување на позицијата на антената и скенирајте повторно.</item>
+ <item quantity="other">Убаво! Пронајдени се %1$d канали во текот на скенирањето канали. Ако се чини дека тоа не е во ред, обидете се со приспособување на позицијата на антената и скенирајте повторно.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Готово"</item>
+ <item msgid="2480490326672924828">"Скенирај пак"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Не се пронајдени канали"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Скенирањето не пронајде ниеден канал. Потврдете дека телевизорот е поврзан со изворот на ТВ сигналот.\n\nАко користите безжична антена, приспособете ја поставеноста или насоката. За најдобри резултати, поставете ја високо и во близина на прозорец и скенирајте повторно."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Скенирањето не пронајде ниеден канал. Потврдете дека USB-приемникот е приклучен и поврзан со изворот на ТВ сигналот.\n\nАко користите безжична антена, приспособете ја поставеноста или насоката. За најдобри резултати, поставете ја високо и во близина на прозорец и скенирајте повторно."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Скенирањето не пронајде ниеден канал. Потврдете дека мрежниот приемник е вклучен и поврзан со изворот на ТВ сигналот.\n\nАко користите безжична антена, приспособете ја поставеноста или насоката. За најдобри резултати, поставете ја високо и во близина на прозорец, па скенирајте повторно."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Скенирај пак"</item>
+ <item msgid="2092797862490235174">"Готово"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Скенирајте ТВ-канали"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Поставување ТВ приемник"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Поставување ТВ приемник со USB"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Поставување мрежен ТВ приемник"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB-приемникот за TV е исклучен."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Мрежниот приемник е исклучен."</string>
+</resources>
diff --git a/usbtuner-res/values-ml-rIN/strings.xml b/usbtuner-res/values-ml-rIN/strings.xml
new file mode 100644
index 00000000..2befa74c
--- /dev/null
+++ b/usbtuner-res/values-ml-rIN/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"ടിവി ട്യൂണർ"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB ടിവി ട്യൂണർ"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"നെറ്റ്‌വർക്ക് ടിവി ട്യൂണർ (ബീറ്റ)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"പ്രോസസ്സുചെയ്യൽ പൂർത്തിയാകുന്നത് വരെ കാത്തിരിക്കുക"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"ട്യൂണർ സോഫ്‌റ്റ്‌വെയർ അടുത്തിടെ അപ്‌ഡേറ്റുചെയ്‌തു. ചാനലുകൾ വീണ്ടും സ്‌കാൻ ചെയ്യുക."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"ഓഡിയോ പ്രവർത്തനക്ഷമമാക്കുന്നതിന് സിസ്റ്റം ശബ്ദ ക്രമീകരണത്തിൽ സറൗണ്ട് ശബ്‌ദം പ്രവർത്തനക്ഷമമാക്കുക"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"ഓഡിയോ പ്ലേ ചെയ്യാൻ കഴിയുന്നില്ല. മറ്റൊരു ടിവിയിൽ ശ്രമിച്ചുനോക്കൂ"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"ചാനൽ ട്യൂണർ സജ്ജമാക്കല്‍‌"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"ടിവി ട്യൂണർ സജ്ജമാക്കല്‍‌"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB ചാനൽ ട്യൂണർ സജ്ജമാക്കല്‍‌"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"നെറ്റ്‌വർക്ക് ട്യൂണർ സജ്ജമാക്കല്‍‌"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"ഒരു ടിവി സിഗ്നൽ ഉറവിടത്തിലേക്ക് നിങ്ങളുടെ ടിവി കണക്റ്റുചെയ്തിട്ടുണ്ടെന്ന് ഉറപ്പാക്കുക.\n\nഉയരത്തിൽ വയ്ക്കേണ്ട തരത്തിലുള്ള ആന്റിനയാണ് നിങ്ങൾ ഉപയോഗിക്കുന്നതെങ്കിൽ, പരമാവധി ചാനലുകൾ ലഭിക്കുന്നതിന്, അതിന്റെ ഇരിപ്പോ ദിശയോ ക്രമീകരിക്കേണ്ടി വരാം. മികച്ച ഫലം ലഭിക്കാൻ, കുറച്ചുകൂടി ഉയരത്തിലും ജാലകത്തിന് അരികിലായും അത് സ്ഥാപിക്കുക."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"USB ട്യൂണർ പ്ലഗിൻ ചെയ്തിട്ടുണ്ടെന്നും ഒരു ടിവി സിഗ്നൽ ഉറവിടത്തിലേക്ക് കണക്റ്റുചെയ്തിട്ടുണ്ടെന്നും ഉറപ്പാക്കുക.\n\nഉയരത്തിൽ വയ്ക്കേണ്ട തരത്തിലുള്ള ആന്റിനയാണ് നിങ്ങൾ ഉപയോഗിക്കുന്നതെങ്കിൽ, പരമാവധി ചാനലുകൾ ലഭിക്കുന്നതിന്, അതിന്റെ ഇരിപ്പോ ദിശയോ ക്രമീകരിക്കേണ്ടി വരാം. മികച്ച ഫലം ലഭിക്കാൻ, കുറച്ചുകൂടി ഉയരത്തിലും ജാലകത്തിന് അരികിലായും അത് സ്ഥാപിക്കുക."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"നെറ്റ്‌വർക്ക് ട്യൂണർ ഓണാക്കിയിട്ടുണ്ടെന്നും ഒരു ടിവി സിഗ്നൽ ഉറവിടത്തിലേക്ക് കണക്റ്റുചെയ്തിട്ടുണ്ടെന്നും ഉറപ്പാക്കുക.\n\nഉയരത്തിൽ വയ്ക്കേണ്ട തരത്തിലുള്ള ആന്റിനയാണ് നിങ്ങൾ ഉപയോഗിക്കുന്നതെങ്കിൽ, പരമാവധി ചാനലുകൾ ലഭിക്കുന്നതിന്, അതിന്റെ ഇരിപ്പോ ദിശയോ ക്രമീകരിക്കേണ്ടി വരാം. മികച്ച ഫലം ലഭിക്കാൻ, കുറച്ചുകൂടി ഉയരത്തിലും ജാലകത്തിന് അരികിലായും അത് സ്ഥാപിക്കുക."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"തുടരുക"</item>
+ <item msgid="727245208787621142">"ഇപ്പോൾ വേണ്ട"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"ചാനൽ സജ്ജമാക്കൽ വീണ്ടും റൺ ചെയ്യണോ?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"ടിവി ട്യൂണറിൽ നിന്ന് കണ്ടെത്തിയ ചാനലുകളെ ഇത് നീക്കംചെയ്യും, പുതിയ ചാനലുകൾക്കായി വീണ്ടും സ്കാൻ ചെയ്യും.\n\nഒരു ടിവി സിഗ്നൽ ഉറവിടത്തിലേക്ക് നിങ്ങളുടെ ടിവി കണക്റ്റുചെയ്തിട്ടുണ്ടെന്ന് ഉറപ്പാക്കുക.\n\nഉയരത്തിൽ വയ്ക്കേണ്ട തരത്തിലുള്ള ആന്റിനയാണ് നിങ്ങൾ ഉപയോഗിക്കുന്നതെങ്കിൽ, പരമാവധി ചാനലുകൾ ലഭിക്കുന്നതിന്, അതിന്റെ ഇരിപ്പോ ദിശയോ ക്രമീകരിക്കേണ്ടി വരാം. മികച്ച ഫലം ലഭിക്കാൻ, കുറച്ചുകൂടി ഉയരത്തിലും ജാലകത്തിന് അരികിലായും അത് സ്ഥാപിക്കുക."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"USB ട്യൂണറിൽ നിന്ന് കണ്ടെത്തിയ ചാനലുകളെ ഇത് നീക്കംചെയ്യും, പുതിയ ചാനലുകൾക്കായി വീണ്ടും സ്കാൻ ചെയ്യും.\n\nസ്കാൻ ചെയ്തപ്പോൾ ചാനലുകളൊന്നും കണ്ടെത്തിയില്ല. USB ട്യൂണർ പ്ലഗിൻ ചെയ്തിട്ടുണ്ടെന്നും ഒരു ടിവി സിഗ്നൽ ഉറവിടത്തിലേക്ക് കണക്റ്റുചെയ്തിട്ടുണ്ടെന്നും ഉറപ്പാക്കുക.\n\nഉയരത്തിൽ വയ്ക്കേണ്ട തരത്തിലുള്ള ആന്റിനയാണ് നിങ്ങൾ ഉപയോഗിക്കുന്നതെങ്കിൽ, പരമാവധി ചാനലുകൾ ലഭിക്കുന്നതിന്, അതിന്റെ ഇരിപ്പോ ദിശയോ ക്രമീകരിക്കേണ്ടി വരാം. മികച്ച ഫലം ലഭിക്കാൻ, കുറച്ചുകൂടി ഉയരത്തിലും ജാലകത്തിന് അരികിലായും അത് സ്ഥാപിക്കുക."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"നെറ്റ്‌വർക്ക് ട്യൂണറിൽ നിന്ന് കണ്ടെത്തിയ ചാനലുകളെ ഇത് നീക്കംചെയ്യും, പുതിയ ചാനലുകൾക്കായി വീണ്ടും സ്കാൻ ചെയ്യും.\n\nനെറ്റ്‌വർക്ക് ട്യൂണർ ഓണാക്കിയിട്ടുണ്ടെന്നും ഒരു ടിവി സിഗ്നൽ ഉറവിടത്തിലേക്ക് കണക്റ്റുചെയ്തിട്ടുണ്ടെന്നും ഉറപ്പാക്കുക.\n\nഉയരത്തിൽ വയ്ക്കേണ്ട തരത്തിലുള്ള ആന്റിനയാണ് നിങ്ങൾ ഉപയോഗിക്കുന്നതെങ്കിൽ, പരമാവധി ചാനലുകൾ ലഭിക്കുന്നതിന്, അതിന്റെ ഇരിപ്പോ ദിശയോ ക്രമീകരിക്കേണ്ടി വരാം മികച്ച ഫലം ലഭിക്കാൻ, കുറച്ചുകൂടി ഉയരത്തിലും ജാലകത്തിന് അരികിലായും അത് സ്ഥാപിക്കുക."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"തുടരുക"</item>
+ <item msgid="235450158666155406">"റദ്ദാക്കൂ"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"കണക്ഷൻ തരം തിരഞ്ഞെടുക്കുക"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"ട്യൂണറിലേക്ക് കണക്റ്റുചെയ്തിട്ടുള്ള ഒരു ബാഹ്യ ആന്റിന ഉണ്ടെങ്കിൽ, ആന്റിന തിരഞ്ഞെടുക്കുക. കേബിൾ സേവന ദാതാവിൽ നിന്നാണ് ചാനലുകൾ ലഭിക്കുന്നതെങ്കിൽ കേബിൾ തിരഞ്ഞെടുക്കുക. ഏതാണ് ഉള്ളതെന്ന് നിങ്ങൾക്ക് അറിയില്ലെങ്കിൽ, രണ്ട് രീതികളും സ്കാൻ ചെയ്യപ്പെടും, എന്നാലിതിന് സമയമെടുക്കും."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"ആന്റിന"</item>
+ <item msgid="2670079958754180142">"കേബിള്‍"</item>
+ <item msgid="36774059871728525">"ഉറപ്പില്ല"</item>
+ <item msgid="6881204453182153978">"ഡെവലപ്പ്‌മെന്റ് മാത്രം"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"ടിവി ട്യൂണർ സജ്ജമാക്കല്‍‌"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB ചാനൽ ട്യൂണർ സജ്ജമാക്കല്‍‌"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"നെറ്റ്‌വർക്ക് ചാനൽ ട്യൂണർ സജ്ജമാക്കല്‍‌"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"ഇതിന് കുറച്ച് സമയം എടുത്തേക്കാം"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"ട്യൂണർ നിലവിൽ ലഭ്യമല്ല അല്ലെങ്കിൽ ഇതിനകം തന്നെ റെക്കോർഡിംഗ് ഉപയോഗിച്ചുകൊണ്ടിരിക്കുന്നു."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">%1$d ചാനലുകൾ കണ്ടെത്തി</item>
+ <item quantity="one">%1$d ചാനൽ കണ്ടെത്തി</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"ചാനൽ സ്കാൻ ചെയ്യുന്നത് നിർത്തുക"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">%1$d ചാനലുകൾ കണ്ടെത്തി</item>
+ <item quantity="one">%1$d ചാനൽ കണ്ടെത്തി</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">കൊള്ളാം! ചാനൽ സ്കാൻ വേളയിൽ %1$d ചാനലുകൾ കണ്ടെത്തി. എന്തോ കുഴപ്പമുണ്ടെന്ന് തോന്നുന്നുവെങ്കിൽ, ആന്റിനയുടെ ദിശ ക്രമീകരിച്ചുകൊണ്ട് വീണ്ടും സ്കാൻ ചെയ്യുക.</item>
+ <item quantity="one">കൊള്ളാം! ചാനൽ സ്കാൻ വേളയിൽ %1$d ചാനൽ കണ്ടെത്തി. എന്തോ കുഴപ്പമുണ്ടെന്ന് തോന്നുന്നുവെങ്കിൽ, ആന്റിനയുടെ ദിശ ക്രമീകരിച്ചുകൊണ്ട് വീണ്ടും സ്കാൻ ചെയ്യുക.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"പൂർത്തിയായി"</item>
+ <item msgid="2480490326672924828">"വീണ്ടും സ്കാൻ ചെയ്യുക"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"ചാനലുകളൊന്നും കണ്ടെത്തിയില്ല"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"സ്കാൻ ചെയ്തപ്പോൾ ചാനലുകളൊന്നും കണ്ടെത്തിയില്ല. ഒരു ടിവി സിഗ്നൽ ഉറവിടത്തിലേക്ക് നിങ്ങളുടെ ടിവി കണക്റ്റുചെയ്തിട്ടുണ്ടെന്ന് ഉറപ്പാക്കുക.\n\nഉയരത്തിൽ വയ്ക്കേണ്ട തരത്തിലുള്ള ആന്റിനയാണ് നിങ്ങൾ ഉപയോഗിക്കുന്നതെങ്കിൽ അതിന്റെ ഇരിപ്പോ ദിശയോ ക്രമീകരിക്കുക. മികച്ച ഫലം ലഭിക്കാൻ, കുറച്ചുകൂടി ഉയരത്തിലും ജാലകത്തിന് അരികിലായും അത് സ്ഥാപിച്ച് വീണ്ടും സ്കാൻ ചെയ്യുക."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"സ്കാൻ ചെയ്തപ്പോൾ ചാനലുകളൊന്നും കണ്ടെത്തിയില്ല. USB ട്യൂണർ പ്ലഗിൻ ചെയ്തിട്ടുണ്ടെന്നും ഒരു ടിവി സിഗ്നൽ ഉറവിടത്തിലേക്ക് കണക്റ്റുചെയ്തിട്ടുണ്ടെന്നും ഉറപ്പാക്കുക.\n\nഉയരത്തിൽ വയ്ക്കേണ്ട തരത്തിലുള്ള ആന്റിനയാണ് നിങ്ങൾ ഉപയോഗിക്കുന്നതെങ്കിൽ അതിന്റെ ഇരിപ്പോ ദിശയോ ക്രമീകരിക്കുക. മികച്ച ഫലം ലഭിക്കാൻ, കുറച്ചുകൂടി ഉയരത്തിലും ജാലകത്തിന് അരികിലായും അത് സ്ഥാപിച്ച് വീണ്ടും സ്കാൻ ചെയ്യുക."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"സ്കാൻ ചെയ്തപ്പോൾ ചാനലുകളൊന്നും കണ്ടെത്തിയില്ല. നെറ്റ്‌വർക്ക് ട്യൂണർ ഓണാക്കിയിട്ടുണ്ടെന്നും ഒരു ടിവി സിഗ്നൽ ഉറവിടത്തിലേക്ക് കണക്റ്റുചെയ്തിട്ടുണ്ടെന്നും ഉറപ്പാക്കുക.\n\nഉയരത്തിൽ വയ്ക്കേണ്ട തരത്തിലുള്ള ആന്റിനയാണ് നിങ്ങൾ ഉപയോഗിക്കുന്നതെങ്കിൽ അതിന്റെ ഇരിപ്പോ ദിശയോ ക്രമീകരിക്കുക. മികച്ച ഫലം ലഭിക്കാൻ, കുറച്ചുകൂടി ഉയരത്തിലും ജാലകത്തിന് അരികിലായും അത് സ്ഥാപിച്ച് വീണ്ടും സ്കാൻ ചെയ്യുക."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"വീണ്ടും സ്കാൻ ചെയ്യുക"</item>
+ <item msgid="2092797862490235174">"പൂർത്തിയായി"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"ടിവി ചാനലുകൾക്കായി സ്കാൻ ചെയ്യുക"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"ടിവി ട്യൂണർ സജ്ജമാക്കല്‍‌"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB ടിവി ട്യൂണർ സജ്ജമാക്കല്‍‌"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"നെറ്റ്‌വർക്ക് ടിവി ട്യൂണർ സജ്ജമാക്കല്‍‌"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB ടിവി ട്യൂണർ വിച്ഛേദിച്ചു."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"നെറ്റ്‌വർക്ക് ട്യൂണർ വിച്ഛേദിച്ചു."</string>
+</resources>
diff --git a/usbtuner-res/values-mn-rMN/strings.xml b/usbtuner-res/values-mn-rMN/strings.xml
new file mode 100644
index 00000000..996341b4
--- /dev/null
+++ b/usbtuner-res/values-mn-rMN/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"ТВ тохируулагч"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB ТВ тохируулагч"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Сүлжээний ТВ Тохируулагч (БЭТА)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Боловсруулж дуусах хүртэл хүлээнэ үү"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Тохируулагчийн програмыг саяхан шинэчилсэн байна. Дахин суваг хайна уу."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Аудиог идэвхжүүлэхийн тулд орчны дууны системийг дууны тохиргоонд идэвхжүүлнэ үү"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Аудиог тоглуулах боломжгүй байна. Өөр ТВ дээр оролдож үзнэ үү"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Суваг тохируулагчийн тохиргоо"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"ТВ тохируулагчийн тохиргоо"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB суваг тохируулагчийн тохиргоо"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Сүлжээ тохируулагчийн тохиргоо"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"ТВ-ээ ТВ дохионы үүсвэртэй холбосон эсэхээ батална уу.\n\nХэрэв агаарын антен хэрэглэж байгаа бол олон суваг авахын тулд антены байршил эсвэл чиглэлийг өөрчилнө үү. Антеныг өндөрт, цонхны дэргэд байрлуулах нь илүү үр дүнтэй."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"USB тохируулагчийг залгасан ба ТВ дохионы үүсвэртэй холбосон эсэхээ шалгана уу.\n\nХэрэв агаарын антен хэрэглэж байгаа бол олон суваг авахын тулд антены байршлыг өөрчилнө үү. Антеныг өндөрт, цонхны дэргэд байрлуулах нь илүү үр дүнтэй байдаг."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Сүлжээ тохируулагчийг асааж, ТВ дохионы үүсвэртэй холбосон эсэхээ баталгаажуулна уу.\n\nХэрэв агаарын антен хэрэглэж байгаа бол олон суваг авахын тулд антены байршлыг өөрчилнө үү. Антеныг өндөрт, цонхны дэргэд байрлуулна уу."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Үргэлжлүүлэх"</item>
+ <item msgid="727245208787621142">"Одоо биш"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Сувгийн тохируулгыг дахин ажиллуулах уу?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Энэ нь ТВ тохируулагчаас олсон сувгийг устгаад, шинэ суваг хайх болно.\n\nТВ тохируулагчаа ТВ дохионы үүсвэртэй холбосон эсэхээ шалгана уу.\n\nХэрэв агаарын антен хэрэглэж байгаа бол олон суваг авахын тулд антены байршил эсвэл чиглэлийг өөрчилнө үү. Антеныг өндөрт, цонхны дэргэд байрлуулах нь илүү үр дүнтэй."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Энэ нь USB тохируулагчаас олдсон сувгийг устгаад, шинэ суваг хайх болно.\n\nUSB тохируулагчийг залгасан, ТВ дохионы үүсвэртэй холбосон эсэхээ шалгана уу.\n\nХэрэв агаарын антен хэрэглэж байгаа бол олон суваг авахын тулд антены байршлыг өөрчилнө үү. Антеныг өндөрт, цонхны дэргэд байрлуулах нь илүү үр дүнтэй."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Энэ нь сүлжээ тохируулагчаас олдсон сувгийг устгаж, шинэ суваг хайх болно.\n\nСүлжээ тохируулагчийг асааж, ТВ дохио үүсвэртэй холбосон эсэхээ шалгана уу.\n\nХэрэв антен хэрэглэж байгаа бол антены байршлыг өөрчилнө үү. Антеныг өндөрт, цонхны дэргэд байрлуулаад, дахин хайна уу."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Үргэлжлүүлэх"</item>
+ <item msgid="235450158666155406">"Цуцлах"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Холболтын төрөл сонгоно уу"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Тохируулагчтай нэмэлт антен холбосон бол Антенаа сонгоно уу. Хэрэв сувгаа кабелийн үйлчилгээ эрхлэгчээс авдаг бол Кабелиа сонгоно уу. Та итгэлгүй байвал энэ хоёр төрлийг хоёуланг нь хайх боловч хэсэг хугацаа зарцуулах болно."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Антен"</item>
+ <item msgid="2670079958754180142">"Кабель"</item>
+ <item msgid="36774059871728525">"Итгэлгүй байна"</item>
+ <item msgid="6881204453182153978">"Зөвхөн хөгжүүлэлтийн хэрэгцээнд"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"ТВ тохируулагчийн тохиргоо"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB суваг тохируулагчийн тохиргоо"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Сүлжээний суваг тохируулагчийн тохиргоо"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Хэдэн минут шаардлагатай"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Суваг солигч одоогоор боломжгүй, эсвэл үүнийг өөр бичлэгт ашиглаж байна."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">%1$d суваг оллоо</item>
+ <item quantity="one">%1$d суваг оллоо</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"СУВАГ ХАЙХЫГ ЗОГСООХ"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">%1$d суваг оллоо</item>
+ <item quantity="one">%1$d суваг оллоо</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Сайн байна! Суваг хайх явцад %1$d сувгийг олсон байна. Хэрэв илүү олон суваг хайх бол антенаа хөдөлгөөд, дахин хайна уу.</item>
+ <item quantity="one">Сайн байна! Суваг хайх явцад %1$d суваг олдсон. Хэрэв илүү олон суваг хайх бол антенаа хөдөлгөөд, дахин хайна уу.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Дууссан"</item>
+ <item msgid="2480490326672924828">"Дахин хайх"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Суваг олсонгүй"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Хайлтын явцад суваг олсонгүй. ТВ-ээ ТВ дохионы үүсвэрт холбосон эсэхээ шалгана уу.\n\nХэрэв агаарын антен хэрэглэж байгаа бол антены байршлыг эсвэл чиглэлийг өөрчилнө үү. Антеныг өндөрт, цонхны дэргэд байрлуулаад, дахин хайх нь илүү үр дүнтэй."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Хайлтын явцад суваг олдсонгүй. USB тохируулагчийг залгасан бөгөөд ТВ дохионы үүсвэртэй холбосон эсэхээ шалгана уу.\n\nХэрэв агаарын антен хэрэглэж байгаа бол антены байршил эсвэл чиглэлийг өөрчилнө үү. Антеныг өндөрт, цонхны дэргэд байрлуулахаад, дахин хайх нь илүү үр дүнтэй."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Хайлтын явцад суваг олдсонгүй. Сүлжээ тохируулагчийг асааж, ТВ дохионы үүсвэртэй холбосон эсэхээ шалгана уу.\n\nХэрэв агаарын антен хэрэглэж байгаа бол антены байршил, эсвэл чиглэлийг өөрчилнө үү. Антеныг өндөрт, цонхны дэргэд байрлуулаад, дахин хайна уу."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Дахин хайх"</item>
+ <item msgid="2092797862490235174">"Дууссан"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"TВ-н суваг хайх"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"ТВ тохируулагчийн тохиргоо"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB ТВ тохируулагчийн тохиргоо"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Сүлжээний ТВ тохируулагчийн тохиргоо"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB ТВ тохируулагч салсан байна."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Сүлжээ тааруулагч салсан байна."</string>
+</resources>
diff --git a/usbtuner-res/values-mr-rIN/strings.xml b/usbtuner-res/values-mr-rIN/strings.xml
new file mode 100644
index 00000000..3b8c9011
--- /dev/null
+++ b/usbtuner-res/values-mr-rIN/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"टीव्ही ट्यूनर"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB टीव्ही ट्यूनर"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"नेटवर्क टीव्ही ट्यूनर (बीटा)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"कृपया प्रक्रिया पूर्ण होण्‍याची प्रतीक्षा करा"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"ट्यूनर सॉफ्टवेअर अलीकडे अद्यतनित केले आहे. कृपया चॅनेल पुन्हा स्कॅन करा."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"ऑडिओ सक्षम करण्यासाठी सिस्टीम ध्वनी सेटिंग्ज मध्ये सराउंड ध्वनी सक्षम करा"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"ऑडिओ प्ले करू शकत नाही. कृपया दुसरा टीव्ही वापरून पहा"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"चॅनेल ट्यूनर सेटअप"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"टीव्ही ट्यूनर सेटअप"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB चॅनेल ट्यूनर सेटअप"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"नेटवर्क ट्यूनर सेटअप"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"टीव्ही सिग्नल स्रोताशी आपला टीव्ही कनेक्ट केला असल्याची खात्री करा. \n\n बिनतारी अँटेना वापरत असल्‍यास, आपल्‍याला कदाचित सर्वाधिक चॅनेल मिळविण्‍यासाठी त्याचे स्थान किंवा दिशा समायोजित करावी लागेल. उत्कृष्‍ट परिणामांसाठी, त्‍यास उंचावर आणि खिडकी जवळ ठेवा."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"USB ट्यूनर प्लगिन केले आणि TV सिग्नल स्रोताशी कनेक्‍ट केले आहे हे सत्यापित करा.\n\nबिनतारी अँटेना वापरत असल्‍यास, आपल्‍याला कदाचित सर्वाधिक चॅनेल मिळविण्‍यासाठी त्याचे स्थान किंवा दिशा समायोजित करावी लागेल. उत्कृष्‍ट परिणामांसाठी, त्‍यास उंचावर आणि खिडकी जवळ ठेवा."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"नेटवर्क ट्यूनर प्लगिन केले आणि TV सिग्नल स्रोताशी कनेक्‍ट केले आहे हे सत्यापित करा.\n\nबिनतारी अँटेना वापरत असल्‍यास, आपल्‍याला कदाचित सर्वाधिक चॅनेल मिळविण्‍यासाठी त्याचे स्थान किंवा दिशा समायोजित करावी लागेल. उत्कृष्‍ट परिणामांसाठी, त्‍यास उंचावर आणि खिडकी जवळ ठेवा."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"सुरू ठेवा"</item>
+ <item msgid="727245208787621142">"सध्या नाही"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"चॅनेल सेटअप वर परत यायचे?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"हे टीव्ही ट्यूनर वरून शोधलेले चॅनेल काढेल आणि नवीन चॅनेलसाठी पुन्हा स्कॅन करेल.\n\n टीव्ही सिग्नल स्रोताशी आपला टीव्ही कनेक्ट केला असल्याचे सत्यापित करा.\n\nबिनतारी अँटेना वापरत असल्‍यास, आपल्‍याला कदाचित सर्वाधिक चॅनेल मिळविण्‍यासाठी त्याचे स्थान किंवा दिशा समायोजित करावी लागेल. उत्कृष्‍ट परिणामांसाठी, त्‍यास उंचावर आणि खिडकी जवळ ठेवा."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"हे USB ट्यूनर वरून शोधलेले चॅनेल काढेल आणि नवीन चॅनेलसाठी पुन्हा स्कॅन करेल.\n\n USB ट्यूनर प्लगिन केले आणि TV सिग्नल स्त्रोताशी कनेक्‍ट केले आहे हे सत्यापित करा.\n\nबिनतारी अँटेना वापरत असल्‍यास, आपल्‍याला कदाचित सर्वाधिक चॅनेल मिळविण्‍यासाठी त्याचे स्थान किंवा दिशा समायोजित करावी लागेल. उत्कृष्‍ट परिणामांसाठी, त्‍यास उंचावर आणि खिडकी जवळ ठेवा."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"हे नेटवर्क ट्यूनर वरून शोधलेले चॅनेल काढेल आणि नवीन चॅनेलसाठी पुन्हा स्कॅन करेल.\n\n नेटवर्क ट्यूनर प्लगिन केले आणि टीव्ही सिग्नल स्रोताशी कनेक्‍ट केले आहे हे सत्यापित करा.\n\nबिनतारी अँटेना वापरत असल्‍यास, आपल्याला कदाचित सर्वाधिक चॅनेल मिळविण्‍यासाठी त्याचे स्थान किंवा दिशा समायोजित करावी लागेल. उत्कृष्‍ट परिणामांसाठी, त्‍यास उंचावर आणि खिडकी जवळ ठेवा."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"सुरू ठेवा"</item>
+ <item msgid="235450158666155406">"रद्द करा"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"कनेक्‍शन प्रकार निवडा"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"ट्यूनरशी बाह्य अँटेना कनेक्‍ट केला असल्‍यास अँटेना निवडा. आपले चॅनेल केबल सेवा प्रदात्याकडून येत असल्‍यास केबल निवडा. आपल्‍याला खात्री नसल्‍यास, दोन्ही प्रकार स्कॅन केले जातील परंतु यास वेळ लागेल."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"अँटेना"</item>
+ <item msgid="2670079958754180142">"केबल"</item>
+ <item msgid="36774059871728525">"खात्री नाही"</item>
+ <item msgid="6881204453182153978">"केवळ विकास"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"टीव्ही ट्यूनर सेटअप"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB चॅनेल ट्यूनर सेटअप"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"नेटवर्क चॅनेल ट्यूनर सेटअप"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"यास काही मिनिटे लागू शकतात"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"ट्यूनर तात्पुरते उपलब्ध नाही किंवा रेकॉर्डिंगद्वारे आधीपासून वापरले गेले आहे."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="one">%1$d चॅनेल सापडले</item>
+ <item quantity="other">%1$d चॅनेल सापडले</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"चॅनेल स्कॅन करणे थांबवा"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="one">%1$d चॅनेल सापडले</item>
+ <item quantity="other">%1$d चॅनेल सापडले</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="one">छान! चॅनेल स्कॅन करताना %1$d चॅनेल सापडले. हे योग्य वाटत नसल्यास, अँटेना स्थिती समायोजित करून पहा आणि पुन्हा स्कॅन करा.</item>
+ <item quantity="other">छान! चॅनेल स्कॅन करताना %1$d चॅनेल सापडले. हे योग्य वाटत नसल्यास, अँटेना स्थिती समायोजित करून पहा आणि पुन्हा स्कॅन करा.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"पूर्ण झाले"</item>
+ <item msgid="2480490326672924828">"पुन्हा स्कॅन करा"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"कोणतेही चॅनेल आढळले नाही"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"स्कॅन करताना कोणतेही चॅनेल आढळले नाही. टीव्ही सिग्नल स्रोताशी आपला टीव्ही कनेक्ट केला असल्याचे सत्यापित करा.\n\nबिनतारी अँटेना वापरत असल्‍यास, त्याचे स्थान किंवा दिशा समायोजित करा. उत्कृष्‍ट परिणामांसाठी, त्‍यास उंचावर आणि खिडकी जवळ ठेवा आणि पुन्हा स्कॅन करा."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"स्कॅन करताना कोणतेही चॅनेल आढळले नाही. USB ट्यूनर प्लगिन केले आणि TV सिग्नल स्रोताशी कनेक्‍ट केले आहे हे सत्यापित करा.\n\nबिनतारी अँटेना वापरत असल्‍यास, त्याचे स्थान किंवा दिशा समायोजित करा. उत्कृष्‍ट परिणामांसाठी, त्‍यास उंचावर आणि खिडकी जवळ ठेवा आणि पुन्हा स्कॅन करा."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"स्कॅन करताना कोणतेही चॅनेल आढळले नाहीत. नेटवर्क ट्यूनर प्लगिन केले आणि टीव्ही सिग्नल स्रोताशी कनेक्‍ट केले आहे हे सत्यापित करा.\n\nबिनतारी अँटेना वापरत असल्‍यास, त्याचे स्थान किंवा दिशा समायोजित करा. उत्कृष्‍ट परिणामांसाठी, त्‍यास उंचावर आणि खिडकी जवळ ठेवा आणि पुन्हा स्कॅन करा."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"पुन्हा स्कॅन करा"</item>
+ <item msgid="2092797862490235174">"पूर्ण झाले"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"टीव्ही चॅनेलसाठी स्कॅन करा"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"टीव्ही ट्यूनर सेटअप"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB टीव्ही ट्यूनर सेटअप"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"नेटवर्क टीव्ही ट्यूनर सेटअप"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB टीव्ही ट्यूनर डिस्कनेक्ट केला."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"नेटवर्क ट्यूनर डिस्कनेक्ट केले."</string>
+</resources>
diff --git a/usbtuner-res/values-ms-rMY/strings.xml b/usbtuner-res/values-ms-rMY/strings.xml
new file mode 100644
index 00000000..c85ce142
--- /dev/null
+++ b/usbtuner-res/values-ms-rMY/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Penala TV"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"Penala TV USB"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Penala TV Rangkaian (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Sila tunggu sehingga proses selesai"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Perisian penala telah dikemas kini baru-baru ini. Sila imbas semula saluran."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Dayakan bunyi keliling dalam tetapan bunyi sistem untuk mendayakan audio"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Tidak dapat memainkan audio. Sila cuba TV lain"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Persediaan penala saluran"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Persediaan Penala TV"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Persediaan penala saluran USB"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Persediaan penala rangkaian"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Sahkan bahawa TV anda disambungkan pada sumber isyarat TV.\n\nJika menggunakan antena siaran, anda mungkin perlu melaraskan peletakan atau arahnya untuk menerima saluran terbanyak. Untuk mendapatkan hasil yang terbaik, letakkan antena itu di tempat yang tinggi dan berdekatan dengan tingkap."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Sahkan bahawa penala USB dipalamkan dan disambungkan pada sumber isyarat TV.\n\nJika menggunakan antena siaran, anda mungkin perlu melaraskan peletakan atau arahnya untuk menerima saluran terbanyak. Untuk mendapatkan hasil yang terbaik, letakkan antena itu di tempat yang tinggi dan berdekatan dengan tingkap."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Sahkan bahawa penala rangkaian telah dihidupkan dan disambungkan pada sumber isyarat TV\n\nJika menggunakan antena siaran, anda mungkin perlu melaraskan peletakan atau arahnya untuk menerima saluran terbanyak. Untuk mendapatkan hasil yang terbaik, letakkan antena itu di tempat yang tinggi dan berdekatan dengan tingkap."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Teruskan"</item>
+ <item msgid="727245208787621142">"Bukan sekarang"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Jalankan semula persediaan saluran?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Tindakan ini akan mengalih keluar saluran yang ditemui daripada penala TV dan mengimbas saluran baharu sekali lagi.\n\nSahkan bahawa penala TV telah disambungkan pada sumber isyarat TV.\n\nJika menggunakan antena siaran, anda mungkin perlu melaraskan peletakan atau arahnya untuk menerima saluran terbanyak. Untuk mendapatkan hasil yang terbaik, letakkan antena itu di tempat yang tinggi dan berdekatan dengan tingkap."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Tindakan ini akan mengalih keluar saluran yang ditemui daripada penala USB dan mengimbas saluran baharu sekali lagi.\n\nSahkan bahawa penala USB telah dipalamkan dan disambungkan pada sumber isyarat TV.\n\nJika menggunakan antena siaran, anda mungkin perlu melaraskan peletakan atau arahnya untuk menerima saluran terbanyak. Untuk mendapatkan hasil yang terbaik, letakkan antena itu di tempat yang tinggi dan berdekatan dengan tingkap."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Tindakan ini akan mengalih keluar saluran yang ditemui daripada penala rangkaian dan mengimbas saluran baharu sekali lagi.\n\nSahkan bahawa penala rangkaian telah dihidupkan dan disambungkan pada sumber isyarat TV.\n\nJika menggunakan antena siaran, anda mungkin perlu melaraskan peletakan atau arahnya untuk menerima saluran terbanyak. Untuk mendapatkan hasil yang terbaik, letakkan antena itu di tempat yang tinggi dan berdekatan dengan tingkap."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Teruskan"</item>
+ <item msgid="235450158666155406">"Batal"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Pilih jenis sambungan"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Pilih Antena jika terdapat antena luaran yang disambungkan pada penala. Pilih Kabel jika saluran anda adalah daripada penyedia perkhidmatan kabel. Jika anda tidak pasti, kedua-dua jenis sambungan akan diimbas tetapi proses ini mungkin mengambil masa yang lebih lama."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antena"</item>
+ <item msgid="2670079958754180142">"Kabel"</item>
+ <item msgid="36774059871728525">"Tidak pasti"</item>
+ <item msgid="6881204453182153978">"Pembangunan sahaja"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Persediaan penala TV"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Persediaan penala saluran USB"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Persediaan penala saluran rangkaian"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Proses ini mungkin mengambil masa beberapa minit"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Penala tidak tersedia buat sementara waktu atau sudah pun digunakan oleh rakaman."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">%1$d saluran ditemui</item>
+ <item quantity="one">%1$d saluran ditemui</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"HENTIKAN PENGIMBASAN SALURAN"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">%1$d saluran ditemui</item>
+ <item quantity="one">%1$d saluran ditemui</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Bagus! %1$d saluran ditemui semasa pengimbasan saluran. Jika hasil pengimbasan ini salah, cuba laraskan kedudukan antena dan imbas sekali lagi.</item>
+ <item quantity="one">Bagus! %1$d saluran ditemui semasa pengimbasan saluran. Jika hasil pengimbasan ini salah, cuba laraskan kedudukan antena dan imbas sekali lagi.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Selesai"</item>
+ <item msgid="2480490326672924828">"Imbas lagi"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Tiada Saluran ditemui"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Pengimbasan ini tidak menemui sebarang saluran. Sahkan bahawa TV anda disambungkan pada sumber isyarat TV.\n\nJika menggunakan antena siaran, laraskan peletakan atau arahnya. Untuk mendapatkan hasil yang terbaik, letakkan antena itu di tempat yang tinggi dan berdekatan dengan tingkap, kemudian imbas sekali lagi."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Pengimbasan tidak menemui sebarang saluran. Sahkan bahawa penala USB dipalamkan dan disambungkan pada sumber isyarat TV.\n\nJika menggunakan antena siaran, laraskan peletakan atau arahnya. Untuk mendapatkan hasil yang terbaik, letakkan antena itu di tempat yang tinggi dan berdekatan dengan tingkap, kemudian imbas sekali lagi."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Pengimbasan ini tidak menemui sebarang saluran. Sahkan bahawa penala rangkaian telah dihidupkan dan disambungkan pada sumber isyarat TV.\n\nJika menggunakan antena siaran, laraskan peletakan atau arahnya. Untuk mendapatkan hasil yang terbaik, letakkan antena itu di tempat yang tinggi dan berdekatan dengan tingkap, kemudian imbas sekali lagi."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Imbas lagi"</item>
+ <item msgid="2092797862490235174">"Selesai"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Imbas saluran TV"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Persediaan Penala TV"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Persediaan Penala TV USB"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Persediaan Penala TV Rangkaian"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"Penala TV USB diputuskan sambungan."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Penala rangkaian diputuskan sambungan."</string>
+</resources>
diff --git a/usbtuner-res/values-my-rMM/strings.xml b/usbtuner-res/values-my-rMM/strings.xml
new file mode 100644
index 00000000..a2cf6c80
--- /dev/null
+++ b/usbtuner-res/values-my-rMM/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"တီဗီချန်နယ်ချိန်ကိရိယာ"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB တီဗီချန်နယ်ချိန်ကိရိယာ"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"ကွန်ရက်တီဗီ လိုင်းချိန်စနစ် (စမ်းသပ်ဆော့ဖ်ဝဲ)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"စီမံဆောင်ရွက်မှု အဆုံးသတ်ရန် ခဏစောင့်ပါ"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"ချန်နယ်ချိန်ဆော့ဖ်ဝဲကို မကြာသေးမီက အပ်ဒိတ်လုပ်ခဲ့သည်။ ချန်နယ်လိုင်းများကို ပြန်ရှာပါ။"</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"အသံဖွင့်ရန် ပတ်ပတ်လည်အသံစနစ်ဆက်တင်များကို ဖွင့်ပါ"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"အသံဖွင့်၍မရပါ။ အခြားတီဗီတွင် စမ်းကြည့်ပါ"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"ချန်နယ်ချိန်ကိရိယာ ထည့်သွင်းတပ်ဆင်မှု"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"တီဗီချန်နယ်ချိန်ကိရိယာ ပြင်ဆင်သတ်မှတ်မှု"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB ချန်နယ်ချိန်ကိရိယာ ပြင်ဆင်သတ်မှတ်မှု"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"တီဗီလိုင်းဖမ်းကိရိယာ စနစ်ထည့်သွင်းမှု"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"သင့်တီဗီသည် တီဗီချန်နယ်ထုတ်လွှင့်ရာ အရင်းအမြစ်တစ်ခုနှင့် ချိတ်ဆက်ထားကြောင်း အတည်ပြုပါ။\n\nအကယ်၍ ကောင်းကင်အန်တန်နာတိုင်ကို အသုံးပြုနေပါက ချန်နယ်အများစုကို ဖမ်းယူနိုင်ရန် ၎င်း၏အနေအထား (သို့) ဦးတည်ဘက်ကို ချိန်ညှိရန် လိုပါသည်။ ရလဒ်များအကောင်းဆုံး ဖြစ်စေရန် ၎င်းကို ပြတင်းပေါက်နားတွင် မြင့်မြင့်ထားပါ။"</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"USB ချန်နယ်ချိန်ကိရိယာကို တပ်ဆင်ထားပြီး တီဗီချန်နယ်ထုတ်လွှင့်ရာ အရင်းအမြစ်တစ်ခုနှင့် ချိတ်ဆက်ထားကြောင်း အတည်ပြုပါ။\n\nအကယ်၍ ကောင်းကင်အန်တန်နာတိုင်ကို အသုံးပြုနေပါက ချန်နယ်အများစုကို ဖမ်းယူနိုင်ရန် ၎င်း၏အနေအထား (သို့) ဦးတည်ဘက်ကို ချိန်ညှိရန် လိုပါသည်။ ရလဒ်များအကောင်းဆုံး ဖြစ်စေရန် ၎င်းကို ပြတင်းပေါက်နားတွင် မြင့်မြင့်ထားပါ။"</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"တီဗီလိုင်းဖမ်းကိရိယာကို ပါဝါဖွင့်ထားခြင်း ရှိ မရှိနှင့် တီဗီစလောင်းသို့ ချိတ်ဆက်ထားခြင်းရှိမရှိ စစ်ဆေးပါ။\n\nအင်တင်နာကို အသုံးပြုလျှင် ၎င်း၏အနေအထား သို့မဟုတ် ဦးတည်ချက်တို့ကို ချိန်ညှိရန် လိုအပ်ပါသည်။ အကောင်းဆုံးရလဒ်အတွက် ပြတင်းပေါက်အနီး အမြင့်ပိုင်းတွင် ထားပါ။"</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"ရှေ့ဆက်ရန်"</item>
+ <item msgid="727245208787621142">"မလုပ်သေးပါ"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"ချန်နယ်စနစ်ထည့်သွင်းမှု ပြန်စမလား။"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"ဤလုပ်ဆောင်ချက်သည် တီဗီချန်နယ်ချိန်ကိရိယာက တွေ့ရှိထားသော ချန်နယ်လိုင်းများကို ဖယ်ရှားလိုက်ပြီး ချန်နယ်အသစ်များကို ထပ်မံရှာဖွေလိမ့်မည်။\n\nသင့်တီဗီသည် တီဗီချန်နယ်ထုတ်လွှင့်ရာ အရင်းအမြစ်တစ်ခုနှင့် ချိတ်ဆက်ထားကြောင်း အတည်ပြုပါ။\n\nအကယ်၍ ကောင်းကင်အန်တန်နာတိုင်ကို အသုံးပြုနေပါက ချန်နယ်အများစုကို ဖမ်းယူနိုင်ရန် ၎င်း၏အနေအထား (သို့) ဦးတည်ဘက်ကို ချိန်ညှိရန် လိုပါသည်။ ရလဒ်များအကောင်းဆုံး ဖြစ်စေရန် ၎င်းကို ပြတင်းပေါက်နားတွင် မြင့်မြင့်ထားပါ။"</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"ဤလုပ်ဆောင်ချက်သည် USB ချန်နယ်ချိန်ကိရိယာက တွေ့ရှိထားသော ချန်နယ်လိုင်းများကို ဖယ်ရှားလိုက်ပြီး ချန်နယ်အသစ်များကို ထပ်မံရှာဖွေလိမ့်မည်။\n\nUSB ချန်နယ်ချိန်ကိရိယာကို တပ်ဆင်ထားပြီး တီဗီချန်နယ်ထုတ်လွှင့်ရာ အရင်းအမြစ်တစ်ခုနှင့် ချိတ်ဆက်ထားကြောင်း အတည်ပြုပါ။\n\nအကယ်၍ ကောင်းကင်အန်တန်နာတိုင်ကို အသုံးပြုနေပါက ချန်နယ်အများစုကို ဖမ်းယူနိုင်ရန် ၎င်း၏အနေအထား (သို့) ဦးတည်ဘက်ကို ချိန်ညှိရန် လိုပါသည်။ ရလဒ်များအကောင်းဆုံး ဖြစ်စေရန် ၎င်းကို ပြတင်းပေါက်နားတွင် မြင့်မြင့်ထားပါ။"</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"၎င်းသည် တီဗီလိုင်းဖမ်းကိရိယာက ရှာဖွေတွေ့ရှိခဲ့သည့် ချန်နယ်များကို ဖယ်ရှားလိုက်မည်ဖြစ်ပြီး ချန်နယ်အသစ်များကို ထပ်မံရှာဖွေသွားပါမည်။\n\nတီဗီလိုင်းဖမ်းကိရိယာကို ပါဝါဖွင့်ထားခြင်း ရှိ မရှိနှင့် တီဗီစလောင်းသို့ ချိတ်ဆက်ထားခြင်းရှိမရှိ စစ်ဆေးပါ။\n\nအင်တင်နာကို အသုံးပြုလျှင် ၎င်း၏အနေအထား သို့မဟုတ် ဦးတည်ချက်တို့ကို ချိန်ညှိရန် လိုအပ်ပါသည်။ အကောင်းဆုံးရလဒ်အတွက် ပြတင်းပေါက်အနီး အမြင့်ပိုင်းတွင် ထားပါ။"</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"ရှေ့ဆက်ရန်"</item>
+ <item msgid="235450158666155406">"မလုပ်တော့"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"ချိတ်ဆက်မှု အမျိုးအစားကို ရွေးပါ"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"ချန်နယ်ချိန်ကိရိယာနှင့် ချိတ်ဆက်ထားသော ပြင်ပအန်တန်နာရှိပါက အန်တန်နာကို ရွေးပါ။ ချန်နယ်လိုင်းများအသုံးပြုရန် ကေဘယ်စနစ်သုံး ဝန်ဆောင်မှုပေးသူနှင့် ချိတ်ဆက်ထားပါက ကေဘယ်ကြိုးကို ရွေးပါ။ မသေချာဖြစ်နေလျှင် နှစ်မျိုးလုံးဖြင့် ရှာဖွေနိုင်သော်လည်း အချိန်ပိုကြာနိုင်ပါသည်။"</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"အန်တန်နာ"</item>
+ <item msgid="2670079958754180142">"ကေဘယ်ကြိုး"</item>
+ <item msgid="36774059871728525">"မသေချာပါ။"</item>
+ <item msgid="6881204453182153978">"စမ်းသပ်မှုအတွက်သာ"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"တီဗီချန်နယ်ချိန်ကိရိယာ ပြင်ဆင်သတ်မှတ်မှု"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB ချန်နယ်ချိန်ကိရိယာ ပြင်ဆင်သတ်မှတ်မှု"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"တီဗီလိုင်းဖမ်းကိရိယာ စနစ်ထည့်သွင်းမှု"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"မိနစ်အနည်းငယ် ကြာနိုင်ပါသည်"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"လိုင်းချိန်စက်သည် ယာယီမရနိုင်သေးပါ သို့မဟုတ် ဖမ်းယူခြင်းအတွက် အသုံးပြုနေပြီး ဖြစ်ပါသည်။"</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">ချန်နယ် %1$d လိုင်းတွေ့သည်</item>
+ <item quantity="one">ချန်နယ် %1$d လိုင်းတွေ့သည်</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"ချန်နယ်ရှာဖွေမှုကို ရပ်ရန်"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">ချန်နယ် %1$d လိုင်းတွေ့သည်</item>
+ <item quantity="one">ချန်နယ် %1$d လိုင်းတွေ့သည်</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">သိပ်ကောင်း။ ချန်နယ်ရှာဖွေရာတွင် ချန်နယ် %1$d လိုင်းတွေ့သည်။ မှားယွင်းနေသည်ဟုထင်လျှင် အန်တန်နာအနေအထားကို ချိန်ညှိပြီး ထပ်ရှာကြည့်ပါ။</item>
+ <item quantity="one">သိပ်ကောင်း။ ချန်နယ်ရှာဖွေရာတွင် ချန်နယ် %1$d လိုင်းတွေ့သည်။ မှားယွင်းနေသည်ဟုထင်လျှင် အန်တန်နာအနေအထားကို ချိန်ညှိပြီး ထပ်ရှာကြည့်ပါ။</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"ပြီးသွားပြီ"</item>
+ <item msgid="2480490326672924828">"ထပ်ရှာရန်"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"ချန်နယ်တစ်လိုင်းမျှ မတွေ့ပါ"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"ချန်နယ်များရှာဖွေရာတွင် တစ်လိုင်းမျှ ရှာမတွေ့ပါ။ သင့်တီဗီသည် တီဗီချန်နယ်ထုတ်လွှင့်ရာ အရင်းအမြစ်တစ်ခုနှင့် ချိတ်ဆက်ထားကြောင်း အတည်ပြုပါ။\n\n အကယ်၍ ကောင်းကင်အန်တန်နာတိုင်ကို အသုံးပြုနေပါက ၎င်း၏ အနေအထား (သို့) ဦးတည်ဘက်ကို ချိန်ညှိပါ။ ရလဒ်များအကောင်းဆုံးဖြစ်စေရန် ၎င်းကို ပြတင်းပေါက်နားတွင် မြင့်မြင့်ထားပြီး ထပ်ရှာကြည့်ပါ။"</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"ချန်နယ်များရှာဖွေရာတွင် တစ်လိုင်းမျှ ရှာမတွေ့ပါ။ USB ချန်နယ်ချိန်ကိရိယာကို တပ်ဆင်ထား၍ တီဗီချန်နယ်ထုတ်လွှင့်ရာ အရင်းအမြစ်တစ်ခုနှင့် ချိတ်ဆက်ထားကြောင်း အတည်ပြုပါ။\n\n အကယ်၍ ကောင်းကင်အန်တန်နာတိုင်ကို အသုံးပြုနေပါက ၎င်း၏ အနေအထား (သို့) ဦးတည်ဘက်ကို ချိန်ညှိပါ။ ရလဒ်များအကောင်းဆုံးဖြစ်စေရန် ၎င်းကို ပြတင်းပေါက်နားတွင် မြင့်မြင့်ထားပြီး ထပ်ရှာကြည့်ပါ။"</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"မည်သည့် ချန်နယ်မျှ ရှာမတွေ့ပါ။ တီဗီလိုင်းဖမ်းကိရိယာကို ပါဝါဖွင့်ထားခြင်းရှိ မရှိနှင့် တီဗီစလောင်းသို့ ချိတ်ဆက်ထားခြင်းရှိမရှိ စစ်ဆေးပါ။\n\nအင်တင်နာကို အသုံးပြုလျှင် ၎င်း၏အနေအထား သို့မဟုတ် ဦးတည်ချက်တို့ကို ချိန်ညှိရန် လိုအပ်ပါသည်။ အကောင်းဆုံးရလဒ်အတွက် ပြတင်းပေါက်အနီး အမြင့်ပိုင်းတွင် ထားပါ။"</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"ထပ်ရှာရန်"</item>
+ <item msgid="2092797862490235174">"ပြီးသွားပြီ"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"TV ချန်နယ်ရှာမည်"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"တီဗီဖမ်းစက် အပြင်အဆင်"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB တီဗီဖမ်းစက် အပြင်အဆင်"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"အင်တာနက် တီဗီဖမ်းစက် အပြင်အဆင်"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB တီဗီလိုင်းချိန်ကိရိယာကို ဖြုတ်လိုက်ပါပြီ။"</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"ကွန်ရက်လိုင်းချိန်ကိရိယာကို ဖြုတ်လိုက်ပါပြီ။"</string>
+</resources>
diff --git a/usbtuner-res/values-nb/strings.xml b/usbtuner-res/values-nb/strings.xml
new file mode 100644
index 00000000..ed45555b
--- /dev/null
+++ b/usbtuner-res/values-nb/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"TV-tuner"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB-tuneren for TV"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Nettverkstuner for TV (betaversjon)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Vent til behandlingen er fullført"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Programvaren for tuneren er nylig blitt oppdatert. Du må skanne kanalene på nytt."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Slå på surroundlyd i innstillingene for systemlyd for å slå på lyd"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Kan ikke spille av lyd. Prøv en annen TV"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Konfigurasjon av kanaler via tuneren"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Konfigurasjon av TV-tuneren"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Konfigurasjon av kanaler via USB-tuneren"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Konfigurasjon av nettverkstuner"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Bekreft at TV-en din er koblet til en TV-signalkilde.\n\nHvis du bruker en trådløs antenne, kan det hende du må justere posisjonen eller retningen for å motta flest mulig kanaler. For å få de beste resultatene bør du plassere antennen høyt og i nærheten av et vindu."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Bekreft at USB-tuneren er plugget i og koblet til en TV-signalkilde.\n\nHvis du bruker en trådløs antenne, kan det hende du må justere posisjonen eller retningen for å motta flest mulig kanaler. For å få de beste resultatene bør du plassere antennen høyt og i nærheten av et vindu."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Bekreft at nettverkstuneren er slått på og koblet til en TV-signalkilde.\n\nHvis du bruker en trådløs antenne, må du kanskje justere posisjonen eller retningen for å motta flere kanaler. For å få de beste resultatene bør du plassere antennen høyt og i nærheten av et vindu."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Fortsett"</item>
+ <item msgid="727245208787621142">"Ikke nå"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Vil du kjøre kanalkonfigureringen på nytt?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Dette fjerner kanalene som ble funnet med TV-tuneren, og skanner etter nye kanaler igjen.\n\nBekreft at TV-en din er koblet til en TV-signalkilde.\n\nHvis du bruker en trådløs antenne, kan det hende du må justere posisjonen eller retningen for å motta flest mulig kanaler. For å få de beste resultatene bør du plassere antennen høyt og i nærheten av et vindu."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Dette fjerner kanaler som er funnet via USB-tuneren, og skanner på nytt etter nye kanaler.\n\nBekreft at USB-tuneren er plugget i og koblet til en TV-signalkilde.\n\nHvis du bruker en trådløs antenne, kan det hende du må justere posisjonen eller retningen for å motta flest mulig kanaler. For å få de beste resultatene bør du plassere antennen høyt og i nærheten av et vindu."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Dette fjerner kanalene som ble funnet av nettverkstuneren, og skanner på nytt etter nye kanaler.\n\nBekreft at nettverkstuneren er slått på og koblet til en TV-signalkilde.\n\nHvis du bruker en trådløs antenne, må du kanskje justere posisjonen eller retningen for å motta flere kanaler. For å få de beste resultatene bør du plassere antennen høyt og i nærheten av et vindu."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Fortsett"</item>
+ <item msgid="235450158666155406">"Avbryt"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Velg tilkoblingstypen"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Velg «Antenne» hvis tuneren er koblet til en ekstern antenne. Velg «Kabel» hvis kanalene kommer fra en kabeltjenesteleverandør. Hvis du ikke er sikker, blir begge typene skannet – men det kan ta lengre tid."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antenne"</item>
+ <item msgid="2670079958754180142">"Kabel"</item>
+ <item msgid="36774059871728525">"Vet ikke"</item>
+ <item msgid="6881204453182153978">"Bare for utvikling"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Konfigurasjon av TV-tuneren"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Konfigurasjon av kanaler via USB-tuneren"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Konfigurasjon av tuner for nettverkskanaler"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Dette kan ta flere minutter"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Tuneren er midlertidig utilgjengelig eller brukes allerede av opptak."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">%1$d kanaler er funnet</item>
+ <item quantity="one">%1$d kanal er funnet</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"STOPP KANALSKANNINGEN"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">%1$d kanaler er funnet</item>
+ <item quantity="one">%1$d kanal er funnet</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Flott! %1$d kanaler er funnet under kanalskanningen. Hvis dette virker feil, kan du prøve å justere antenneposisjonen og skanne på nytt.</item>
+ <item quantity="one">Flott! %1$d kanal er funnet under kanalskanningen. Hvis dette virker feil, kan du prøve å justere antenneposisjonen og skanne på nytt.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Ferdig"</item>
+ <item msgid="2480490326672924828">"Skann på nytt"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Fant ingen kanaler"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Ingen kanaler ble funnet under skanningen. Bekreft at TV-en din er koblet til en TV-signalkilde.\n\nHvis du bruker en trådløs antenne, kan du justere posisjonen eller retningen. For å få de beste resultatene bør du plassere antennen høyt og i nærheten av et vindu. Deretter skanner du på nytt."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Fant ingen kanaler under skanningen. Bekreft at USB-tuneren er plugget i og koblet til en TV-signalkilde.\n\nHvis du bruker en trådløs antenne, kan du justere posisjonen eller retningen. For å få de beste resultatene bør du plassere antennen høyt og i nærheten av et vindu. Deretter skanner du på nytt."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Skanningen fant ingen kanaler. Bekreft at nettverkstuneren er slått på og koblet til en TV-signalkilde.\n\nHvis du bruker en trådløs antenne, må du justere posisjonen eller retningen. For å få de beste resultatene bør du plassere antennen høyt og i nærheten av et vindu. Deretter skanner du på nytt."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Skann på nytt"</item>
+ <item msgid="2092797862490235174">"Ferdig"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Skann etter TV-kanaler"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Konfigurasjon av TV-tuneren"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Konfigurasjon av USB-tuner for TV"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Konfigurasjon av nettverkstuner for TV"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB-tuneren for TV er frakoblet."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Nettverkstuneren er frakoblet."</string>
+</resources>
diff --git a/usbtuner-res/values-ne-rNP/strings.xml b/usbtuner-res/values-ne-rNP/strings.xml
new file mode 100644
index 00000000..5f1e3330
--- /dev/null
+++ b/usbtuner-res/values-ne-rNP/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"TV ट्युनर"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB TV ट्युनर"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"नेटवर्कको TV ट्युनर (बिटा)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"कृपया प्रक्रिया सम्पन्न हुने प्रतीक्षा गर्नुहोस्"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"ट्युनरको सफ्टवेयरलाई हालसालै अद्यावधिक गरिएको छ। कृपया च्यानलहरू पुन:स्क्यान गर्नुहोस्।"</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"अडियोलाई सक्षम पार्न प्रणालीको ध्वनि सम्बन्धी सेटिङहरूमा गई सराउन्ड साउन्डलाई सक्षम पार्नुहोस्"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"अडियो बजाउन सकिँदैन। कृपया अर्को TV को प्रयोग गरी हेर्नुहोस्"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"च्यानल ट्युनरको सेटअप"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"TV ट्युनरको सेटअप"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB च्यानल ट्युनरको सेटअप"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"नेटवर्क ट्युनरको सेटअप"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"तपाईँको TV कुनै TV सिग्नलको स्रोतमा जडान गरिएको छ भनी पुष्टि गर्नुहोस्।\n\nयदि कुनै ओभर-दि-एयर एन्टेनाको प्रयोग भइरहेको छ भने धेरै च्यानलहरू प्राप्त गर्न तपाईँले त्यसको स्थान वा दिशा समायोजन गर्नुपर्ने हुन सक्छ। उत्कृष्ट परिणामहरूका लागि त्यसलाई उच्च स्थानमा र कुनै झ्यालको नजिक राख्नुहोस्।"</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"USB ट्युनर प्लगइन रहेको र कुनै TV सिग्नलको स्रोतमा जडान गरिएको छ भनी पुष्टि गर्नुहोस्।\n\nयदि कुनै ओभर-दि-एयर एन्टेनाको प्रयोग भइरहेको छ भने धेरै च्यानलहरू प्राप्त गर्न तपाईँले त्यसको स्थान वा दिशा समायोजन गर्नुपर्ने हुन सक्छ। उत्कृष्ट परिणामहरूका लागि त्यसलाई उच्च स्थानमा र कुनै झ्यालको नजिक राख्नुहोस्।"</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"नेटवर्क ट्युनर सक्रिय रहेको र कुनै TV सिग्नलको स्रोतमा जडान गरिएको छ भनी पुष्टि गर्नुहोस्।\n\nयदि कुनै ओभर-दि-एयर एन्टेनाको प्रयोग भइरहेको छ भने धेरै च्यानलहरू प्राप्त गर्न तपाईंले त्यसको स्थान वा दिशा समायोजन गर्नुपर्ने हुन सक्छ। उत्कृष्ट परिणामहरूका लागि त्यसलाई उच्च स्थानमा र कुनै झ्यालको नजिक राख्नुहोस्।"</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"जारी राख्नुहोस्"</item>
+ <item msgid="727245208787621142">"अहिले होइन"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"च्यानलको सेटअप पुनःसञ्चालन गर्ने हो?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"यसले USB ट्युनरबाट भेट्टिएका च्यानलहरूलाई हटाउनेछ र नयाँ च्यानलहरू भेट्टाउन फेरि स्क्यान गर्नेछ।\n\nतपाईँको TV कुनै TV सिग्नलको स्रोतमा जडान गरिएको छ भनी पुष्टि गर्नुहोस्।\n\nयदि कुनै ओभर-दि-एयर एन्टेनाको प्रयोग भइरहेको छ भने धेरै च्यानलहरू प्राप्त गर्न तपाईँले त्यसको स्थान वा दिशा समायोजन गर्नुपर्ने हुन सक्छ। उत्कृष्ट परिणामहरूका लागि त्यसलाई उच्च स्थानमा र कुनै झ्यालको नजिक राख्नुहोस्।"</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"यसले USB ट्युनरबाट भेट्टिएका च्यानलहरूलाई हटाउनेछ र नयाँ च्यानलहरू भेट्टाउन फेरि स्क्यान गर्नेछ।\n\nUSB ट्युनर प्लगइन गरिएको र कुनै TV सिग्नलको स्रोतमा जडान गरिएको छ भनी पुष्टि गर्नुहोस्।\n\nयदि कुनै ओभर-दि-एयर एन्टेनाको प्रयोग भइरहेको छ भने धेरै च्यानलहरू प्राप्त गर्न तपाईँले त्यसको स्थान वा दिशा समायोजन गर्नुपर्ने हुन सक्छ। उत्कृष्ट परिणामहरूका लागि त्यसलाई उच्च स्थानमा र कुनै झ्यालको नजिक राख्नुहोस्।"</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"यसले नेटवर्क ट्युनर मार्फत भेट्टिएका च्यानलहरूलाई हटाउनेछ र नयाँ च्यानलहरू भेट्टाउन फेरि स्क्यान गर्नेछ।\n\nनेटवर्क ट्युनरलाई सक्रिय गरिएको र कुनै TV सिग्नलको स्रोतमा जडान गरिएको छ भनी पुष्टि गर्नुहोस्।\n\nयदि कुनै ओभर-दि-एयर एन्टेनाको प्रयोग भइरहेको छ भने धेरै च्यानलहरू प्राप्त गर्न तपाईंले त्यसको स्थान वा दिशा समायोजन गर्नुपर्ने हुन सक्छ। उत्कृष्ट परिणामहरूका लागि त्यसलाई उच्च स्थानमा र कुनै झ्यालको नजिक राख्नुहोस्।"</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"जारी राख्नुहोस्"</item>
+ <item msgid="235450158666155406">"रद्द गर्नुहोस्"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"जडानको प्रकार चयन गर्नुहोस्"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"यदि उक्त ट्युनरमा कुनै बाह्य एन्टेना जडान गरिएको छ भने एन्टेना छनौट गर्नुहोस्। यदि तपाईंका च्यानलहरू केबल सेवा प्रदायक मार्फत आउँछन् भने केबल छनौट गर्नुहोस्। यदि तपाईं निश्चित हुनुहुन्न भने दुवै प्रकारहरू स्क्यान गरिने छन् तर यसमा लामो समय लाग्न सक्छ।"</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"एन्टेना"</item>
+ <item msgid="2670079958754180142">"केबल"</item>
+ <item msgid="36774059871728525">"निश्चित छैन"</item>
+ <item msgid="6881204453182153978">"विकासका लागि मात्र"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"TV ट्युनरको सेटअप"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB च्यानल ट्युनरको सेटअप"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"नेटवर्कको च्यानल ट्युनरको सेटअप"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"यसमा धेरै मिनेट लाग्न सक्छ"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"ट्युनर अस्थायी रूपले अनुपलब्ध छ वा रेकर्डिङद्वारा पहिले नै प्रयोग गरिएको छ।"</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">%1$d च्यानलहरू भेट्टिए</item>
+ <item quantity="one">%1$d च्यानल भेट्टियो</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"च्यानल स्क्यान गर्न रोक्नुहोस्"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">%1$d च्यानलहरू भेट्टिए</item>
+ <item quantity="one">%1$d च्यानल भेट्टियो</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">राम्रो खबर छ! च्यानल स्क्यान गर्दा %1$d च्यानलहरू भेट्टिए। यदि यो सही हो जस्तो लाग्दैन भने एन्टेनाको स्थिति समायोजन गरी हेर्नुहोस् र फेरि स्क्यान गर्नुहोस्।</item>
+ <item quantity="one">राम्रो खबर छ! च्यानल स्क्यान गर्दा %1$d च्यानल भेट्टियो। यदि यो सही हो जस्तो लाग्दैन भने एन्टेनाको स्थिति समायोजन गरी हेर्नुहोस् र फेरि स्क्यान गर्नुहोस्।</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"सम्पन्न भयो"</item>
+ <item msgid="2480490326672924828">"फेरि स्क्यान गर्नुहोस्"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"कुनै च्यानल भेट्टिएन"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"उक्त स्क्यानले कुनै पनि च्यानल भेट्टाएन। तपाईँको TV कुनै TV सिग्नलको स्रोतमा जडान गरिएको छ भनी पुष्टि गर्नुहोस्।\n\nयदि कुनै ओभर-दि-एयर एन्टेनाको प्रयोग भइरहेको छ भने त्यसको स्थान वा दिशा समायोजन गर्नुहोस्। उत्कृष्ट परिणामहरूका लागि त्यसलाई उच्च स्थानमा र कुनै झ्यालको नजिक राखी फेरि स्क्यान गर्नुहोस्।"</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"उक्त स्क्यानले कुनै पनि च्यानल भेट्टाएन। USB ट्युनर प्लगइन गरिएको र कुनै TV सिग्नलको स्रोतमा जडान गरिएको छ भनी पुष्टि गर्नुहोस्।\n\nयदि कुनै ओभर-दि-एयर एन्टेनाको प्रयोग भइरहेको छ भने त्यसको स्थान वा दिशा समायोजन गर्नुहोस्। उत्कृष्ट परिणामहरूका लागि त्यसलाई उच्च स्थानमा र कुनै झ्यालको नजिक राखी फेरि स्क्यान गर्नुहोस्।"</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"उक्त स्क्यानले कुनै पनि च्यानल भेट्टाएन। नेटवर्क ट्युनरलाई सक्रिय गरिएको र कुनै TV सिग्नलको स्रोतमा जडान गरिएको छ भनी पुष्टि गर्नुहोस्।\n\nयदि कुनै ओभर-दि-एयर एन्टेनाको प्रयोग भइरहेको छ भने त्यसको स्थान वा दिशा समायोजन गर्नुहोस्। उत्कृष्ट परिणामहरूका लागि त्यसलाई उच्च स्थानमा र कुनै झ्यालको नजिक राखी फेरि स्क्यान गर्नुहोस्।"</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"फेरि स्क्यान गर्नुहोस्"</item>
+ <item msgid="2092797862490235174">"सम्पन्न भयो"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"TV च्यानलहरू भेट्टाउन स्क्यान गर्नुहोस्"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"TV ट्युनरको सेटअप"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB TV ट्युनरको सेटअप"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"नेटवर्कको TV ट्युनरको सेटअप"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB TV ट्युनरलाई विच्छेद गरियो।"</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"नेटवर्क ट्युनरलाई विच्छेद गरियो।"</string>
+</resources>
diff --git a/usbtuner-res/values-nl/strings.xml b/usbtuner-res/values-nl/strings.xml
new file mode 100644
index 00000000..34b0d927
--- /dev/null
+++ b/usbtuner-res/values-nl/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Tv-tuner"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB-tv-tuner"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Netwerk-tv-tuner (BÈTA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Wacht tot het proces is voltooid"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"De software van de tuner is recent geüpdatet. Scan de kanalen opnieuw."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Schakel surrond sound in via de geluidsinstellingen van het systeem om audio in te schakelen"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Kan audio niet afspelen. Probeer een andere tv."</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Configuratie van kanaaltuner"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Tv-tuner instellen"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Kanaalconfiguratie van USB-tuner"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Netwerktuner instellen"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Controleer of je tv is aangesloten op een tv-signaalbron.\n\nAls je een over-the-air-antenne gebruikt, moet je de positie of richting daarvan mogelijk aanpassen om zo veel mogelijk kanalen te ontvangen. Voor de beste resultaten plaats je de antenne op een hoge plek in de buurt van een raam."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Controleer of de USB-tuner is ingeschakeld en aangesloten op een tv-signaalbron.\n\nAls je een over-the-air-antenne gebruikt, moet je de positie of richting daarvan mogelijk aanpassen om zo veel mogelijk kanalen te ontvangen. Voor de beste resultaten plaats je de antenne op een hoge plek in de buurt van een raam."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Controleer of de netwerktuner is ingeschakeld en aangesloten op een tv-signaalbron.\n\nAls je een over-the-air-antenne gebruikt, moet je de positie of richting daarvan mogelijk aanpassen om zo veel mogelijk kanalen te ontvangen. Voor de beste resultaten plaats je de antenne op een hoge plek in de buurt van een raam."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Doorgaan"</item>
+ <item msgid="727245208787621142">"Niet nu"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Kanaalconfiguratie opnieuw uitvoeren?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Hiermee worden de gevonden kanalen verwijderd van de tv-tuner en wordt opnieuw gezocht naar nieuwe kanalen.\n\nControleer of je tv is aangesloten op een tv-signaalbron.\n\nAls je een over-the-air-antenne gebruikt, moet je de positie of richting daarvan mogelijk aanpassen om zo veel mogelijk kanalen te ontvangen. Voor de beste resultaten plaats je de antenne op een hoge plek in de buurt van een raam."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Hiermee worden de gevonden kanalen verwijderd van de USB-tuner en wordt opnieuw gescand naar nieuwe kanalen.\n\nControleer of de USB-tuner is ingeschakeld en aangesloten op een tv-signaalbron.\n\nAls je een over-the-air-antenne gebruikt, moet je de positie of richting daarvan mogelijk aanpassen om zo veel mogelijk kanalen te ontvangen. Voor de beste resultaten plaats je de antenne op een hoge plek in de buurt van een raam."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Hiermee worden de gevonden kanalen verwijderd van de netwerktuner en wordt opnieuw gezocht naar nieuwe kanalen.\n\nControleer of de netwerktuner is ingeschakeld en aangesloten op een tv-signaalbron.\n\nAls je een over-the-air-antenne gebruikt, moet je de positie of richting daarvan mogelijk aanpassen om zo veel mogelijk kanalen te ontvangen. Voor de beste resultaten plaats je de antenne op een hoge plek in de buurt van een raam."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Doorgaan"</item>
+ <item msgid="235450158666155406">"Annuleren"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Het verbindingstype selecteren"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Kies Antenne als er een externe antenne is aangesloten op de tuner. Kies Kabel als je kanalen afkomstig zijn van een kabelprovider. Als je het niet zeker weet, worden beide typen gescand. Dit kan echter langer duren."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antenne"</item>
+ <item msgid="2670079958754180142">"Kabel"</item>
+ <item msgid="36774059871728525">"Niet zeker"</item>
+ <item msgid="6881204453182153978">"Alleen ontwikkeling"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Tv-tuner instellen"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Kanaalconfiguratie van USB-tuner"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Netwerkkanaaltuner instellen"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Dit kan enkele minuten duren"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"De tuner is tijdelijk niet beschikbaar of wordt al gebruikt voor een opname."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">%1$d kanalen gevonden</item>
+ <item quantity="one">%1$d kanaal gevonden</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"KANAALSCAN STOPPEN"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">%1$d kanalen gevonden</item>
+ <item quantity="one">%1$d kanaal gevonden</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Er zijn %1$d kanalen gevonden tijdens de kanaalscan. Als je denkt dat dit niet klopt, pas je de antennepositie aan en voer je de scan opnieuw uit.</item>
+ <item quantity="one">Er is %1$d kanaal gevonden tijdens de kanaalscan. Als je denkt dat dit niet klopt, pas je de antennepositie aan en voer je de scan opnieuw uit.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Gereed"</item>
+ <item msgid="2480490326672924828">"Opnieuw scannen"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Geen kanalen gevonden"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Er zijn geen kanalen gevonden tijdens de scan. Controleer of je tv is aangesloten op een tv-signaalbron.\n\nAls je een over-the-air-antenne gebruikt, pas je de positie of richting daarvan aan. Voor de beste resultaten plaats je de antenne op een hoge plek in de buurt van een raam en voer je de scan opnieuw uit."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Er zijn geen kanalen gevonden tijdens de scan. Controleer of de USB-tuner is ingeschakeld en aangesloten op een tv-signaalbron.\n\nAls je een over-the-air-antenne gebruikt, pas je de positie of richting daarvan aan. Voor de beste resultaten plaats je de antenne op een hoge plek in de buurt van een raam en voer je de scan opnieuw uit."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"De scan heeft geen kanalen gevonden. Controleer of de netwerktuner is ingeschakeld en aangesloten op een tv-signaalbron.\n\nAls je een over-the-air-antenne gebruikt, moet je de positie of richting daarvan mogelijk aanpassen. Voor de beste resultaten plaats je de antenne op een hoge plek in de buurt van een raam en voer je de scan opnieuw uit."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Opnieuw scannen"</item>
+ <item msgid="2092797862490235174">"Gereed"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Zoeken naar tv-zenders"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Tv-tuner instellen"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB-tv-tuner instellen"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Netwerk-tv-tuner instellen"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB-tv-tuner losgekoppeld."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Netwerktuner losgekoppeld."</string>
+</resources>
diff --git a/usbtuner-res/values-pl/strings.xml b/usbtuner-res/values-pl/strings.xml
new file mode 100644
index 00000000..9daa3621
--- /dev/null
+++ b/usbtuner-res/values-pl/strings.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Tuner TV"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"Tuner TV USB"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Sieciowy tuner TV (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Poczekaj na zakończenie przetwarzania"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Oprogramowanie tunera zostało niedawno zaktualizowane. Przeskanuj ponownie kanały."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Aby włączyć dźwięk, włącz dźwięk przestrzenny w ustawieniach systemowych dźwięku"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Nie można odtworzyć dźwięku. Spróbuj użyć innego telewizora"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Konfiguracja kanałów w tunerze"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Konfiguracja tunera TV"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Konfiguracja kanałów w tunerze USB"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Konfiguracja tunera sieciowego"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Upewnij się, że telewizor jest podłączony do źródła sygnału telewizyjnego.\n\nJeśli używasz anteny telewizyjnej, może być konieczne wyregulowanie jej położenia lub kierunku, by można było odbierać jak najwięcej kanałów. Aby uzyskać najlepszy sygnał, umieść antenę na podwyższeniu, w pobliżu okna."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Upewnij się, że tuner USB jest podłączony do telewizora oraz do źródła sygnału telewizyjnego.\n\nJeśli używasz anteny telewizyjnej, może być konieczne wyregulowanie jej położenia lub kierunku, by można było odbierać jak najwięcej kanałów. Aby uzyskać najlepszy sygnał, umieść antenę na podwyższeniu, w pobliżu okna."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Upewnij się, że tuner sieciowy jest włączony i został podłączony do źródła sygnału telewizyjnego.\n\nJeśli używasz anteny telewizyjnej, może być konieczne wyregulowanie jej położenia lub kierunku, by można było odbierać jak najwięcej kanałów. Aby uzyskać najlepszy sygnał, umieść antenę na podwyższeniu, w pobliżu okna."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Kontynuuj"</item>
+ <item msgid="727245208787621142">"Nie teraz"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Skonfigurować ponownie kanały?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Spowoduje to usunięcie kanałów znalezionych przez tuner TV i ponowne wykonanie skanowania.\n\nUpewnij się, że telewizor jest podłączony do źródła sygnału telewizyjnego.\n\nJeśli używasz anteny telewizyjnej, może być konieczne wyregulowanie jej położenia lub kierunku, by można było odbierać jak najwięcej kanałów. Aby uzyskać najlepszy sygnał, umieść antenę na podwyższeniu, w pobliżu okna."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Spowoduje to usunięcie kanałów znalezionych przez tuner USB i ponowne wykonanie skanowania.\n\nUpewnij się, że tuner USB jest podłączony do telewizora oraz do źródła sygnału telewizyjnego.\n\nJeśli używasz anteny telewizyjnej, może być konieczne wyregulowanie jej położenia lub kierunku, by można było odbierać jak najwięcej kanałów. Aby uzyskać najlepszy sygnał, umieść antenę na podwyższeniu, w pobliżu okna."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Spowoduje to usunięcie kanałów znalezionych przez tuner sieciowy i ponowne wykonanie skanowania.\n\nUpewnij się, że tuner sieciowy jest włączony i został podłączony do źródła sygnału telewizyjnego.\n\nJeśli używasz anteny telewizyjnej, może być konieczne wyregulowanie jej położenia lub kierunku, by można było odbierać jak najwięcej kanałów. Aby uzyskać najlepszy sygnał, umieść antenę na podwyższeniu, w pobliżu okna."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Kontynuuj"</item>
+ <item msgid="235450158666155406">"Anuluj"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Wybierz typ połączenia"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Jeśli do tunera jest podłączona zewnętrzna antena, wybierz opcję Antena. Jeśli kanały udostępnia dostawca telewizji kablowej, wybierz opcję Telewizja kablowa. Jeśli nie masz pewności, przeskanowane zostaną oba źródła, ale może to dłużej potrwać."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antena"</item>
+ <item msgid="2670079958754180142">"Telewizja kablowa"</item>
+ <item msgid="36774059871728525">"Nie mam pewności"</item>
+ <item msgid="6881204453182153978">"Tylko dla programistów"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Konfiguracja tunera TV"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Konfiguracja kanałów w tunerze USB"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Konfiguracja kanałów w tunerze sieciowym"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Może to potrwać kilka minut"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Tuner jest czasowo niedostępny lub właśnie nagrywa."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="few">Znaleziono %1$d kanały</item>
+ <item quantity="many">Znaleziono %1$d kanałów</item>
+ <item quantity="other">Znaleziono %1$d kanału</item>
+ <item quantity="one">Znaleziono %1$d kanał</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"ZATRZYMAJ WYSZUKIWANIE KANAŁÓW"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="few">Znaleziono %1$d kanały</item>
+ <item quantity="many">Znaleziono %1$d kanałów</item>
+ <item quantity="other">Znaleziono %1$d kanału</item>
+ <item quantity="one">Znaleziono %1$d kanał</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="few">Super! Podczas skanowania znaleziono %1$d kanały. Jeśli coś jest nie tak, wyreguluj położenie anteny i ponownie wykonaj skanowanie.</item>
+ <item quantity="many">Super! Podczas skanowania znaleziono %1$d kanałów. Jeśli coś jest nie tak, wyreguluj położenie anteny i ponownie wykonaj skanowanie.</item>
+ <item quantity="other">Super! Podczas skanowania znaleziono %1$d kanału. Jeśli coś jest nie tak, wyreguluj położenie anteny i ponownie wykonaj skanowanie.</item>
+ <item quantity="one">Super! Podczas skanowania znaleziono %1$d kanał. Jeśli coś jest nie tak, wyreguluj położenie anteny i ponownie wykonaj skanowanie.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Gotowe"</item>
+ <item msgid="2480490326672924828">"Skanuj ponownie"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Nie znaleziono kanałów"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Podczas skanowania nie znaleziono żadnych kanałów. Upewnij się, że telewizor jest podłączony do źródła sygnału telewizyjnego.\n\nJeśli używasz anteny telewizyjnej, wyreguluj jej położenie lub kierunek. Aby uzyskać najlepszy sygnał, umieść antenę na podwyższeniu, w pobliżu okna, a następnie ponownie wykonaj skanowanie."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Podczas skanowania nie znaleziono żadnych kanałów. Upewnij się, że tuner USB jest podłączony do telewizora oraz do źródła sygnału telewizyjnego.\n\nJeśli używasz anteny telewizyjnej, wyreguluj jej położenie lub kierunek. Aby uzyskać najlepszy sygnał, umieść antenę na podwyższeniu, w pobliżu okna, a następnie ponownie wykonaj skanowanie."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Podczas skanowania nie znaleziono żadnych kanałów. Upewnij się, że tuner sieciowy jest włączony i został podłączony do źródła sygnału telewizyjnego.\n\nJeśli używasz anteny telewizyjnej, wyreguluj jej położenie lub kierunek. Aby uzyskać najlepszy sygnał, umieść antenę na podwyższeniu, w pobliżu okna, a następnie ponownie wykonaj skanowanie."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Skanuj ponownie"</item>
+ <item msgid="2092797862490235174">"Gotowe"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Wyszukaj kanały TV"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Konfiguracja tunera TV"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Konfiguracja tunera TV USB"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Konfiguracja sieciowego tunera TV"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"Telewizyjny tuner USB rozłączony."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Tuner sieciowy rozłączony."</string>
+</resources>
diff --git a/usbtuner-res/values-pt-rPT/strings.xml b/usbtuner-res/values-pt-rPT/strings.xml
new file mode 100644
index 00000000..02f4dd9d
--- /dev/null
+++ b/usbtuner-res/values-pt-rPT/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Sintonizador de TV"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"Sintonizador de TV USB"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Sintonizador de televisão (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Aguarde enquanto o processamento é terminado"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"O software do sintonizador foi atualizado recentemente. Procure novamente os canais."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Ative o som surround nas definições de som do sistema para ativar o áudio"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Não é possível reproduzir áudio. Experimente outra TV."</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Configuração do sintonizador de canais"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Configuração do sintonizador de TV"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Configuração do sintonizador de canais USB"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Configuração do sintonizador de rede"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Confirme se a sua TV está ligada a uma fonte de sinal da TV.\n\nSe estiver a utilizar uma antena via rede sem fios, pode ter de ajustar a respetiva posição ou a direção para receber a maioria dos canais. Para obter os melhores resultados, coloque-a num ponto alto e junto a uma janela."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Confirme se o sintonizador USB está ativado e ligado a uma fonte de sinal da TV.\n\nSe estiver a utilizar uma antena via rede sem fios, pode ter de ajustar a respetiva posição ou a direção para receber a maioria dos canais. Para obter os melhores resultados, coloque-a num ponto alto e junto a uma janela."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Confirme se o sintonizador de rede está ligado à alimentação e ligado a uma fonte de sinal de TV.\n\nSe estiver a utilizar uma antena via rede sem fios, pode ter de ajustar a respetiva posição ou direção para receber a maioria dos canais. Para obter os melhores resultados, coloque-a num ponto alto e junto a uma janela."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Continuar"</item>
+ <item msgid="727245208787621142">"Agora não"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Pretende executar novamente a configuração do canal?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Esta ação remove os canais encontrados pelo sintonizador de TV e procura novamente canais novos.\n\nConfirme se a sua TV está ligada a uma fonte de sinal da TV.\n\nSe estiver a utilizar uma antena via rede sem fios, pode ter de ajustar a respetiva posição ou a direção para receber a maioria dos canais. Para obter os melhores resultados, coloque-a num ponto alto e junto a uma janela."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Esta ação remove os canais encontrados do sintonizador USB e procura novamente canais novos.\n\nConfirme se o sintonizador USB está ativado e ligado a uma fonte de sinal da TV.\n\nSe estiver a utilizar uma antena via rede sem fios, pode ter de ajustar a respetiva posição ou a direção para receber a maioria dos canais. Para obter os melhores resultados, coloque-a num ponto alto e junto a uma janela."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Esta ação vai remover os canais encontrados do sintonizador de rede e procurar novos canais novamente.\n\nConfirme se o sintonizador de rede está ligado à alimentação e ligado a uma fonte de sinal de TV.\n\nSe estiver a utilizar uma antena via rede sem fios, pode ter de ajustar a respetiva posição ou direção para receber a maioria dos canais. Para obter os melhores resultados, coloque-a num ponto alto e junto a uma janela."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Continuar"</item>
+ <item msgid="235450158666155406">"Cancelar"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Selecionar o tipo de ligação"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Escolha Antena se existir uma antena externa ligada ao sintonizador. Escolha Cabo se os canais forem provenientes de um fornecedor de serviços por cabo. Se não tiver a certeza, ambos os tipos são procurados, mas esta ação pode demorar mais tempo."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antena"</item>
+ <item msgid="2670079958754180142">"Cabo"</item>
+ <item msgid="36774059871728525">"Não tenho a certeza"</item>
+ <item msgid="6881204453182153978">"Apenas para desenvolvimento"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Configuração do sintonizador de TV"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Configuração do sintonizador de canais USB"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Configuração do sintonizador de canais"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Esta operação pode demorar vários minutos"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"O sintonizador está temporariamente indisponível ou já está a ser utilizado pela gravação."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="one">%1$d canal encontrado</item>
+ <item quantity="other">%1$d canais encontrados</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"INTERROMPER A PROCURA DE CANAIS"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="one">%1$d canal encontrado</item>
+ <item quantity="other">%1$d canais encontrados</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="one">Boa! Foi encontrado %1$d canal durante a procura de canais. Se isso não lhe parecer correto, experimente ajustar a posição da antena e procurar novamente.</item>
+ <item quantity="other">Boa! Foram encontrados %1$d canais durante a procura de canais. Se isto não lhe parecer correto, experimente ajustar a posição da antena e procurar novamente.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Concluído"</item>
+ <item msgid="2480490326672924828">"Procurar novamente"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Não foram encontrados canais"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"A procura não encontrou quaisquer canais. Confirme se a TV está ligada a uma fonte de sinal da TV.\n\nSe estiver a utilizar uma antena via rede sem fios, ajuste a respetiva posição ou a direção. Para obter os melhores resultados, coloque-a num ponto alto e junto a uma janela e procure novamente."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Não foram encontrados quaisquer canais. Verifique se o sintonizador USB está ativado e ligado a uma fonte de sinal da TV.\n\nSe estiver a utilizar uma antena via rede sem fios, ajuste a respetiva posição ou a direção. Para obter os melhores resultados, coloque-a num ponto alto e junto a uma janela e procure novamente."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"A procura não encontrou quaisquer canais. Confirme se o sintonizador de rede está ligado à alimentação e ligado a uma fonte de sinal de TV.\n\nSe estiver a utilizar uma antena via rede sem fios, ajuste a respetiva posição ou direção. Para obter os melhores resultados, coloque-a num ponto alto e junto a uma janela. Em seguida, procure novamente."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Procurar novamente"</item>
+ <item msgid="2092797862490235174">"Concluído"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Procurar canais de TV"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Configuração do sintonizador de TV"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Configuração do sintonizador de TV USB"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Configuração do sintonizador de TV por cabo"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"Sintonizador de TV USB desligado."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Sintonizador de rede desligado."</string>
+</resources>
diff --git a/usbtuner-res/values-pt/strings.xml b/usbtuner-res/values-pt/strings.xml
new file mode 100644
index 00000000..d123306a
--- /dev/null
+++ b/usbtuner-res/values-pt/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Sintonizador de TV"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"Sintonizador de TV USB"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Sintonizador de rede de TV (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Aguarde a conclusão do processamento"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"O software do sintonizador foi atualizado recentemente. Procure os canais mais uma vez."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Ative o som surround nas configurações de som do sistema para ativar o áudio"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Não foi possível reproduzir o áudio. Tente em outra TV"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Configuração do sintonizador de canais"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Configuração do Sintonizador de TV"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Configuração do sintonizador de canais USB"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Configuração do sintonizador de rede"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Verifique se sua TV está conecta a uma fonte de sinal de TV.\n\nSe você estiver usando uma antena Over-the-air (OTA), talvez seja necessário ajustar o posicionamento ou a direção dela para receber o máximo de canais. Para ter resultados melhores, coloque-a em um lugar alto e perto de uma janela."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Verifique se o sintonizador USB está conectado a uma fonte de sinal de TV.\n\nSe você usa uma antena Over the air, talvez seja necessário ajustar o posicionamento ou a direção dela para receber o maior número de canais. Para ter resultados melhores, coloque-a em um lugar alto e perto de uma janela."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Verifique se o sintonizador de rede está ligado e conectado a uma fonte de sinal de TV.\n\nSe você estiver usando uma antena OTA (over-the-air), talvez seja necessário ajustar o posicionamento ou a direção dela para receber o máximo de canais. Para ter resultados melhores, coloque-a em um lugar alto e perto de uma janela."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Continuar"</item>
+ <item msgid="727245208787621142">"Agora não"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Executar novamente a configuração de canais?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Isso removerá os canais encontrados do Sintonizador de TV e procurará novos canais mais uma vez.\n\nVerifique se sua TV está conectada a uma fonte de sinal de TV.\n\nSe você estiver usando uma antena Over-the-air (OTA), talvez seja necessário ajustar o posicionamento ou a direção dela para receber o máximo de canais. Para ter resultados melhores, coloque-a em um lugar alto e perto de uma janela."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Essa ação remove os canais encontrados pelo sintonizador USB e procura canais novamente.\n\nVerifique se o sintonizador USB está conectado a uma fonte de sinal de TV.\n\n.Se você usa uma antena Over the air, talvez seja necessário ajustar o posicionamento ou a direção dela para receber o maior número de canais. Para ter resultados melhores, coloque-a em um lugar alto e perto de uma janela."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Essa ação removerá os canais encontrados do sintonizador de rede e procurará novos canais mais uma vez.\n\nVerifique se o sintonizador de rede está ligado e conectado a uma fonte de sinal de TV.\n\nSe você estiver usando uma antena OTA (over-the-air), talvez seja necessário ajustar o posicionamento ou a direção dela para receber o máximo de canais. Para ter resultados melhores, coloque-a em um lugar alto e perto de uma janela."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Continuar"</item>
+ <item msgid="235450158666155406">"Cancelar"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Selecione o tipo de conexão"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Selecione \"Antena\", se houver uma antena externa conectada ao sintonizador. Selecione \"Cabo\", se seus canais vierem de um provedor de serviços a cabo. Se você não tiver certeza, será feita uma procura usando os dois tipos, mas isso pode demorar mais tempo."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antena"</item>
+ <item msgid="2670079958754180142">"Cabo"</item>
+ <item msgid="36774059871728525">"Não tenho certeza"</item>
+ <item msgid="6881204453182153978">"Somente desenvolvimento"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Configuração do Sintonizador de TV"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Configuração do sintonizador de canais USB"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Configuração do sintonizador de canais de rede"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Isso pode demorar alguns minutos"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"O sintonizador está temporariamente indisponível ou já está sendo usado pela gravação."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="one">%1$d canal encontrado</item>
+ <item quantity="other">%1$d canais encontrados</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"INTERROMPER PROCURA DE CANAIS"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="one">%1$d canal encontrado</item>
+ <item quantity="other">%1$d canais encontrados</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="one">Legal! %1$d canal foi encontrado durante a procura de canais. Se você acha que esse número não está correto, tente ajustar a posição da antena e procure novamente.</item>
+ <item quantity="other">Legal! %1$d canais foram encontrados durante a procura de canais. Se você acha que esse número não está correto, tente ajustar a posição da antena e procure novamente.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Concluído"</item>
+ <item msgid="2480490326672924828">"Procurar novamente"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Nenhum canal encontrado"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"A procura não encontrou nenhum canal. Verifique se sua TV está conectada a uma fonte de sinal de TV.\n\nSe você estiver usando uma antena Over-the-air (OTA), ajuste o posicionamento ou a direção dela. Para ter resultados melhores, coloque-a em um lugar alto e perto de uma janela e procure novamente."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Nenhum canal foi encontrado pela procura. Verifique se o sintonizador USB está conectado a uma fonte de sinal de TV.\n\nSe você estiver usando uma antena Over the air, ajuste o posicionamento ou a direção dela. Para ter resultados melhores, coloque-a em um lugar alto e perto de uma janela e procure novamente."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Nenhum canal foi encontrado pela procura. Verifique se o sintonizador de rede está ligado e conectado a uma fonte de sinal de TV.\n\nSe você estiver usando uma antena OTA (over-the-air), ajuste o posicionamento ou a direção dela. Para ter resultados melhores, coloque-a em um lugar alto e perto de uma janela, depois procure novamente."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Procurar novamente"</item>
+ <item msgid="2092797862490235174">"Concluído"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Procurar canais de TV"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Configuração do Sintonizador de TV"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Configuração do Sintonizador de TV USB"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Configuração do sintonizador de rede de TV"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"Sintonizador de TV USB desconectado."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Sintonizador de rede desconectado."</string>
+</resources>
diff --git a/usbtuner-res/values-ro/strings.xml b/usbtuner-res/values-ro/strings.xml
new file mode 100644
index 00000000..d30101a4
--- /dev/null
+++ b/usbtuner-res/values-ro/strings.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Tuner TV"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"Tuner TV USB"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Tuner de rețea TV (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Așteptați ca procesarea să fie finalizată"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Software-ul tunerului a fost actualizat recent. Scanați din nou canalele."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Pentru a activa conținutul audio, activați sunetul surround din setările de sunet ale sistemului"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Conținutul audio nu poate fi redat. Încercați pe un alt televizor."</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Configurarea tunerului de canale"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Configurarea tunerului TV"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Configurarea tunerului de canale USB"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Configurarea tunerului de rețea"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Asigurați-vă că televizorul este conectat la o sursă de semnal TV.\n\nDacă folosiți o antenă over the air, poate fi necesar să-i ajustați amplasarea sau direcția astfel încât să capteze majoritatea canalelor. Pentru cele mai bune rezultate, amplasați-o la înălțime și în apropierea unei ferestre."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Asigurați-vă că tunerul USB este conectat la o sursă de alimentare și la o sursă de semnal TV.\n\nDacă folosiți o antenă over the air, poate fi necesar să-i ajustați amplasarea sau direcția astfel încât să capteze majoritatea canalelor. Pentru cele mai bune rezultate, amplasați-o la înălțime și în apropierea unei ferestre."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Verificați dacă tunerul de rețea este pornit și conectat la o sursă de semnal TV.\n\nDacă folosiți o antenă over-the-air, ar putea fi necesar să-i ajustați poziția sau direcția pentru a recepționa cât mai multe canale. Pentru rezultate optime, plasați-o sus și lângă o fereastră."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Continuați"</item>
+ <item msgid="727245208787621142">"Nu acum"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Configurați din nou canalul?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Astfel, vor fi eliminate canalele găsite de tunerul TV și se vor căuta din nou canale.\n\nAsigurați-vă că televizorul este conectat la o sursă de semnal TV.\n\nDacă folosiți o antenă over the air, poate fi necesar să-i ajustați amplasarea sau direcția astfel încât să capteze majoritatea canalelor. Pentru cele mai bune rezultate, amplasați-o la înălțime și în apropierea unei ferestre."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Astfel, vor fi eliminate canalele găsite de pe tunerul USB și se vor căuta din nou canale.\n\nAsigurați-vă că tunerul USB este conectat la o sursă de alimentare și la o sursă de semnal TV.\n\nDacă folosiți o antenă over the air, poate fi necesar să-i ajustați amplasarea sau direcția pentru a capta majoritatea canalelor. Pentru cele mai bune rezultate, amplasați-o la înălțime și în apropierea unei ferestre."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Astfel veți elimina canalele găsite din tunerul de rețea și veți scana iar pentru a găsi canale noi.\n\nVerificați dacă tunerul de rețea este pornit și conectat la o sursă de semnal TV.\n\nDacă folosiți o antenă over-the-air, ar putea fi necesar să-i ajustați poziția sau direcția pentru a recepționa cât mai multe canale. Pentru rezultate optime, plasați-o sus și lângă o fereastră."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Continuați"</item>
+ <item msgid="235450158666155406">"Anulați"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Selectați tipul de conexiune"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Alegeți Antenă dacă există o antenă externă conectată la tuner. Alegeți Cablu în cazul în care canalele provin de la un furnizor de servicii prin cablu. Dacă nu știți sigur care este situația, se vor scana ambele tipuri, însă poate dura mai mult."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antenă"</item>
+ <item msgid="2670079958754180142">"Cablu"</item>
+ <item msgid="36774059871728525">"Nu știu sigur"</item>
+ <item msgid="6881204453182153978">"Numai pentru dezvoltare"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Configurarea tunerului TV"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Configurarea tunerului de canale USB"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Configurarea tunerului de canale de rețea"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Poate dura câteva minute"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Tunerul nu este disponibil temporar sau este folosit deja de înregistrare."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="few">%1$d canale găsite</item>
+ <item quantity="other">%1$d de canale găsite</item>
+ <item quantity="one">%1$d canal găsit</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"OPRIȚI SCANAREA CANALELOR"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="few">%1$d canale găsite</item>
+ <item quantity="other">%1$d de canale găsite</item>
+ <item quantity="one">%1$d canal găsit</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="few">Excelent! La scanarea canalelor s-au găsit %1$d canale. Dacă vi se pare că ceva nu este în regulă, ajustați poziția antenei și repetați scanarea.</item>
+ <item quantity="other">Excelent! La scanarea canalelor s-au găsit %1$d de canale. Dacă vi se pare că ceva nu este în regulă, ajustați poziția antenei și repetați scanarea.</item>
+ <item quantity="one">Excelent! La scanarea canalelor s-a găsit %1$d canal. Dacă vi se pare că ceva nu este în regulă, ajustați poziția antenei și repetați scanarea.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Terminat"</item>
+ <item msgid="2480490326672924828">"Scanați din nou"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Nu s-au găsit canale"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Scanarea nu a găsit niciun canal. Asigurați-vă că televizorul este conectat la o sursă de semnal TV.\n\nDacă folosiți o antenă over the air, ajustați-i amplasarea sau direcția. Pentru cele mai bune rezultate, amplasați-o la înălțime și în apropierea unei ferestre, apoi repetați scanarea."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Nu s-a găsit niciun canal la scanare. Asigurați-vă că tunerul USB este conectat la o sursă de alimentare și la o sursă de semnal TV. \n\nDacă folosiți o antenă over the air, ajustați-i amplasarea sau direcția. Pentru cele mai bune rezultate, amplasați-o la înălțime și în apropierea unei ferestre, apoi repetați scanarea."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Scanarea nu a găsit niciun canal. Verificați dacă tunerul de rețea este pornit și conectat la o sursă de semnal TV.\n\nDacă folosiți o antenă over-the-air, ajustați poziția sau direcția. Pentru rezultate optime, plasați-o sus și lângă o fereastră și scanați din nou."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Scanați din nou"</item>
+ <item msgid="2092797862490235174">"Terminat"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Căutați canale TV"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Configurarea tunerului TV"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Configurarea tunerului TV USB"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Configurarea tunerului de rețea TV"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"Tunerul TV USB este deconectat."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Tunerul de rețea este deconectat."</string>
+</resources>
diff --git a/usbtuner-res/values-ru/strings.xml b/usbtuner-res/values-ru/strings.xml
new file mode 100644
index 00000000..33f97db0
--- /dev/null
+++ b/usbtuner-res/values-ru/strings.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"ТВ-тюнер"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB-тюнер"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Сетевой ТВ-тюнер (бета)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Дождитесь окончания обработки"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Программное обеспечение тюнера было обновлено. Повторите сканирование."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Включите объемный звук в системных настройках"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Не удается воспроизвести аудио. Выберите другой канал."</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Настройка тюнера"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Настройка ТВ-тюнера"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Настройка USB-тюнера"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Настройка сетевого тюнера"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Убедитесь, что телевизор подключен к источнику сигнала.\n\nЕсли вы используете телеантенну, переместите или перенаправьте ее. Рекомендуем расположить ее высоко и рядом с окном."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Убедитесь, что USB-тюнер включен в сеть и подсоединен к источнику сигнала.\n\nЕсли вы используете телеантенну, переместите или перенаправьте ее. Рекомендуем расположить ее высоко и рядом с окном."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Убедитесь, что сетевой тюнер включен в сеть и подсоединен к источнику ТВ-сигнала.\n\nЕсли вы используете телеантенну, поместите и направьте ее так, чтобы она принимала большинство каналов. Рекомендуем расположить антенну высоко и рядом с окном."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Продолжить"</item>
+ <item msgid="727245208787621142">"Не сейчас"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Настроить каналы заново?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Все каналы, найденные с помощью ТВ-тюнера, будут удалены, и поиск начнется заново.\n\nУбедитесь, что телевизор подключен к источнику сигнала.\n\nЕсли вы используете телеантенну, переместите или перенаправьте ее. Рекомендуем расположить ее высоко и рядом с окном."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Все каналы, найденные с помощью USB-тюнера, будут удалены, и сканирование начнется заново.\n\nУбедитесь, что USB-тюнер включен в сеть и подсоединен к источнику сигнала.\n\nЕсли вы используете телеантенну, переместите или перенаправьте ее. Рекомендуем расположить ее высоко и рядом с окном."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Все каналы, найденные с помощью сетевого тюнера, будут удалены, и сканирование начнется заново.\n\nУбедитесь, что сетевой тюнер включен в сеть и подсоединен к источнику ТВ-сигнала.\n\nЕсли вы используете телеантенну, поместите и направьте ее так, чтобы она принимала большинство каналов. Рекомендуем расположить антенну высоко и рядом с окном."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Продолжить"</item>
+ <item msgid="235450158666155406">"Отмена"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Выберите тип соединения"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Если к тюнеру подключена внешняя антенна, выберите вариант \"Антенна\". Если вы ищете кабельные каналы, выберите \"Кабельное ТВ\". Если вы затрудняетесь ответить, мы будем искать оба типа каналов, но это займет чуть больше времени."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Антенна"</item>
+ <item msgid="2670079958754180142">"Кабельное ТВ"</item>
+ <item msgid="36774059871728525">"Неизвестно"</item>
+ <item msgid="6881204453182153978">"Только для разработки"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Настройка ТВ-тюнера"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Настройка USB-тюнера"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Настройка каналов сетевого тюнера"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Это может занять несколько минут"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Тюнер временно недоступен или уже используется для записи."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="one">Найден %1$d канал</item>
+ <item quantity="few">Найдено %1$d канала</item>
+ <item quantity="many">Найдено %1$d каналов</item>
+ <item quantity="other">Найдено %1$d канала</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"НЕ СКАНИРОВАТЬ"</string>
+ <!-- String.format failed for translation -->
+ <!-- no translation found for ut_result_found_title (1448908152026339099) -->
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="one">Отлично! Найден %1$d канал. Если результат вас не устраивает, переместите антенну и повторите сканирование.</item>
+ <item quantity="few">Отлично! Найдено %1$d канала. Если результат вас не устраивает, переместите антенну и повторите сканирование.</item>
+ <item quantity="many">Отлично! Найдено %1$d каналов. Если результат вас не устраивает, переместите антенну и повторите сканирование.</item>
+ <item quantity="other">Отлично! Найдено %1$d канала. Если результат вас не устраивает, переместите антенну и повторите сканирование.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Готово"</item>
+ <item msgid="2480490326672924828">"Искать повторно"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Каналы не найдены"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Каналы не найдены. Убедитесь, что телевизор подключен к источнику сигнала.\n\nЕсли вы используете телеантенну, переместите или перенаправьте ее. Рекомендуем расположить ее высоко и рядом с окном."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Каналы не найдены. Убедитесь, что USB-тюнер включен в сеть и подсоединен к источнику сигнала.\n\nЕсли вы используете телеантенну, переместите или перенаправьте ее. Рекомендуем расположить ее высоко и рядом с окном."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Каналы не найдены. Убедитесь, что сетевой тюнер включен в сеть и подсоединен к источнику ТВ-сигнала.\n\nЕсли вы используете телеантенну, переместите или перенаправьте ее (рекомендуем расположить антенну высоко и рядом с окном). Затем повторите сканирование."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Искать повторно"</item>
+ <item msgid="2092797862490235174">"Готово"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Сканируйте телеканалы"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Настройка ТВ-тюнера"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Настройка USB-тюнера"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Настройка сетевого ТВ-тюнера"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB-тюнер отключен."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Сетевой тюнер отключен."</string>
+</resources>
diff --git a/usbtuner-res/values-si-rLK/strings.xml b/usbtuner-res/values-si-rLK/strings.xml
new file mode 100644
index 00000000..577015b6
--- /dev/null
+++ b/usbtuner-res/values-si-rLK/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"TV සුසරකය"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB TV සුසරකය"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Network TV Tuner (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"සැකසීම අවසන් කිරීමට කරුණාකර රැඳී සිටින්න"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"සුසරක මෘදුකාංගය පසුගියදා යාවත්කාලීන කර ඇත. කරුණාකර නාලිකා නැවත ස්කෑන් කරන්න."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"ශ්‍රව්‍ය සබල කිරීමට හඬ සැකසීම් තුළ අවට හඬ සබල කරන්න"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"ශ්‍රව්‍යය ධාවනය කළ නොහැකිය. කරුණාකර වෙනත් TV එකක් උත්සාහ කරන්න"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"නාලිකා සුසරක පිහිටුවීම"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"TV සුසරක පිහිටුවීම"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB නාලිකා සුසරක පිහිටුවීම"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"ජාල සුසරකය පිහිටුවීම"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"ඔබේ TV, TV සංඥා මූලාශ්‍රයකට සම්බන්ධ කර ඇති බව තහවුරු කර ගන්න.\n\nගුවන-ඔස්සේ ඇන්ටනාවක් භාවිත කරන්නේ නම්, ඔබට බොහොමයක් නාලිකා ලබා ගැනීමට පිහිටීම හෝ දිශාව සීරුමාරු කිරීමට අවශ්‍ය විය හැකිය. හොඳම ප්‍රතිඵල සඳහා, එය ඉහළින් සහ කවුළුවක් ආසන්නයේ තබන්න."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"සුසරකය පේනුගත කර ඇති බව සහ TV සංඥා මූලාශ්‍රයකට සම්බන්ධ කර ඇති බව තහවුරු කර ගන්න.\n\nගුවන-ඔස්සේ ඇන්ටනාවක් භාවිත කරන්නේ නම්, ඔබට බොහොමයක් නාලිකා ලබා ගැනීමට පිහිටීම හෝ දිශාව සීරුමාරු කිරීමට අවශ්‍ය විය හැකිය. හොඳම ප්‍රතිඵල සඳහා, එය ඉහළින් සහ කවුළුවක් ආසන්නයේ තබන්න."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"ජාල සුසරකය බලයට සම්බන්ධ කර ඇති බව සහ TV සංඥා මූලාශ්‍රයකට සම්බන්ධ කර ඇති බව තහවුරු කර ගන්න.\n\nගුවන-ඔස්සේ ඇන්ටනාවක් භාවිත කරන්නේ නම්, ඔබට බොහොමයක් නාලිකා ලබා ගැනීමට පිහිටීම හෝ දිශාව සීරුමාරු කිරීමට අවශ්‍ය විය හැකිය. හොඳම ප්‍රතිඵල සඳහා, එය ඉහළින් සහ කවුළුවක් ආසන්නයේ තබන්න."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"දිගටම කර ගෙන යන්න"</item>
+ <item msgid="727245208787621142">"දැන් නොවේ"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"නාලිකා පිහිටුවීම නැවත ධාවනය කරන්නද?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"මෙය TV සුසරකය වෙතින් සොයා ගත් නාලිකා ඉවත් කරනු ඇති අතර නව නාලිකා සඳහා නැවත ස්කෑන් කරනු ඇත.\n\nඔබේ TV, TV සංඥා මූලාශ්‍රයකට සම්බන්ධ කර ඇති බව තහවුරු කර ගන්න.\n\nගුවන-ඔස්සේ ඇන්ටනාවක් භාවිත කරන්නේ නම්, ඔබට බොහොමයක් නාලිකා ලබා ගැනීමට පිහිටීම හෝ දිශාව සීරුමාරු කිරීමට අවශ්‍ය විය හැකිය. හොඳම ප්‍රතිඵල සඳහා, එය ඉහළින් සහ කවුළුවක් ආසන්නයේ තබන්න."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"මෙය USB සුසරකය වෙතින් සොයා ගත් නාලිකා ඉවත් කරනු ඇති අතර නව නාලිකා සඳහා නැවත ස්කෑන් කරනු ඇත.\n\nUSB සුසරකය පේනුගත කර ඇති බව සහ TV සංඥා මූලාශ්‍රයකට සම්බන්ධ කර ඇති බව තහවුරු කර ගන්න.\n\nගුවන-ඔස්සේ ඇන්ටනාවක් භාවිත කරන්නේ නම්, ඔබට බොහොමයක් නාලිකා ලබා ගැනීමට පිහිටීම හෝ දිශාව සීරුමාරු කිරීමට අවශ්‍ය විය හැකිය. හොඳම ප්‍රතිඵල සඳහා, එය ඉහළින් සහ කවුළුවක් ආසන්නයේ තබන්න."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"මෙය ජාල සුසරකය වෙතින් සොයා ගත් නාලිකා ඉවත් කරනු ඇති අතර නව නාලිකා සඳහා නැවත ස්කෑන් කරනු ඇත.\n\nජාල සුසරකය බලයට සම්බන්ධ කර ඇති බව සහ TV සංඥා මූලාශ්‍රයකට සම්බන්ධ කර ඇති බව තහවුරු කර ගන්න.\n\nගුවන-ඔස්සේ ඇන්ටනාවක් භාවිත කරන්නේ නම්, ඔබට බොහොමයක් නාලිකා ලබා ගැනීමට පිහිටීම හෝ දිශාව සීරුමාරු කිරීමට අවශ්‍ය විය හැකිය. හොඳම ප්‍රතිඵල සඳහා, එය ඉහළින් සහ කවුළුවක් ආසන්නයේ තබන්න."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"දිගටම කර ගෙන යන්න"</item>
+ <item msgid="235450158666155406">"අවලංගු කරන්න"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"සබැඳුම් ආකාරය තෝරන්න"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"සුසරකයට බාහිර අැන්ටනාවක් සම්බන්ධ කර ඇත්නම්, ඇන්ටනාව තෝරන්න. ඔබේ නාලිකා කේබල් සැපයුම්කරුවෙකු වෙතින් පැමිණෙන්නේ නම් කේබලය තෝරන්න. ඔබට ස්ථිර නැත්නම්, ආකාර දෙකම ස්කෑන් කරනු ඇත, නමුත් මෙයට වැඩි කාලයක් ගත විය හැකිය."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"ඇන්ටනාව"</item>
+ <item msgid="2670079958754180142">"කේබලය"</item>
+ <item msgid="36774059871728525">"ස්ථිර නැත"</item>
+ <item msgid="6881204453182153978">"සංවර්ධනයට පමණි"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"TV සුසරක පිහිටුවීම"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB නාලිකා සුසරක පිහිටුවීම"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"ජාල නාලිකා සුසරකය පිහිටුවීම"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"මෙය මිනිත්තු කිහිපයක් ගත හැකිය"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"සුසරකය තාවකාලිකව ලබා ගත නොහැකිය නැතහොත් දැනටමත් පටිගත කිරීම මගින් භාවිත කරනු ලැබේ."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="one">නාලිකා %1$dක් සොයා ගන්නා ලදී</item>
+ <item quantity="other">නාලිකා %1$dක් සොයා ගන්නා ලදී</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"නාලිකා ස්කෑන් කිරීම නවත්වන්න"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="one">නාලිකා %1$dක් සොයා ගන්නා ලදී</item>
+ <item quantity="other">නාලිකා %1$dක් සොයා ගන්නා ලදී</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="one">කදිමයි! නාලිකා ස්කෑන් කිරීම අතරතුර නාලිකා %1$dක් සොයා ගන්නා ලදී. මෙය නිවැරදි බව නොපෙනේ නම්, ඇන්ටනාවේ පිහිටීම සීරුමාරු කිරීම උත්සාහ කර නැවත ස්කෑන් කරන්න.</item>
+ <item quantity="other">කදිමයි! නාලිකා ස්කෑන් කිරීම අතරතුර නාලිකා %1$dක් සොයා ගන්නා ලදී. මෙය නිවැරදි බව නොපෙනේ නම්, ඇන්ටනාවේ පිහිටීම සීරුමාරු කිරීම උත්සාහ කර නැවත ස්කෑන් කරන්න.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"නිමයි"</item>
+ <item msgid="2480490326672924828">"නැවත ස්කෑන් කරන්න"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"නාලිකා හමු නොවීය"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"ස්කෑන් කිරීමට නාලිකා කිසිවක් හමු නොවීය. ඔබේ TV, TV සංඥා මූලාශ්‍රයකට සම්බන්ධ කර ඇති බව තහවුරු කර ගන්න.\n\nගුවන-ඔස්සේ ඇන්ටනාවක් භාවිත කරන්නේ නම්, එහි පිහිටීම හෝ දිශාව සීරුමාරු කරන්න. හොඳම ප්‍රතිඵල සඳහා, එය ඉහළින් සහ කවුළුවක් ආසන්නයේ තබා නැවත ස්කෑන් කරන්න."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"ස්කෑන් කිරීමට නාලිකා කිසිවක් හමු නොවීය. USB සුසරකය පේනුගත කර ඇති බව සහ TV සංඥා මූලාශ්‍රයකට සම්බන්ධ කර ඇති බව තහවුරු කර ගන්න.\n\nගුවන-ඔස්සේ ඇන්ටනාවක් භාවිත කරන්නේ නම්, පිහිටීම හෝ දිශාව සීරුමාරු කරන්න. හොඳම ප්‍රතිඵල සඳහා, එය ඉහළින් සහ කවුළුවක් ආසන්නයේ තබා නැවත ස්කෑන් කරන්න."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"ස්කෑන් කිරීමට නාලිකා කිසිවක් හමු නොවීය. ජාල සුසරකය බලයට සම්බන්ධ කර ඇති බව සහ TV සංඥා මූලාශ්‍රයකට සම්බන්ධ කර ඇති බව තහවුරු කර ගන්න.\n\nගුවන-ඔස්සේ ඇන්ටනාවක් භාවිත කරන්නේ නම්, පිහිටීම හෝ දිශාව සීරුමාරු කරන්න. හොඳම ප්‍රතිඵල සඳහා, එය ඉහළින් සහ කවුළුවක් ආසන්නයේ තබා නැවත ස්කෑන් කරන්න."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"නැවත ස්කෑන් කරන්න"</item>
+ <item msgid="2092797862490235174">"නිමයි"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"TV නාලිකා සඳහා ස්කෑන් කරන්න"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"TV සුසරක පිහිටුවීම"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB TV සුසරක පිහිටුවීම"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"ජාල TV සුසරක පිහිටුවීම"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB TV සුසරකය විසන්ධි වුණි."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"ජාල සුසරකය විසන්ධි වුණි."</string>
+</resources>
diff --git a/usbtuner-res/values-sk/strings.xml b/usbtuner-res/values-sk/strings.xml
new file mode 100644
index 00000000..60448b2b
--- /dev/null
+++ b/usbtuner-res/values-sk/strings.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Televízny tuner"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"Televízny tuner s rozhraním USB"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Televízny sieťový tuner (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Počkajte, kým bude spracovanie dokončené"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Softvér tunera bol nedávno aktualizovaný. Znova vyhľadajte kanály."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Ak chcete zapnúť zvuk, v nastaveniach systémového zvuku povoľte priestorový zvuk"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Zvuk nie je možné prehrať. Skúste použiť iný televízor."</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Nastavenie tunera kanálov"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Nastavenie televízneho tunera"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Nastavenie kanálov tunera USB"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Nastavenie sieťového tunera"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Skontrolujte, či je televízor pripojený k zdroju televízneho signálu.\n\nAk používate vzdušnú anténu, upravte jej umiestnenie alebo orientáciu, aby ste získali čo najviac kanálov. Najlepšie výsledky dosiahnete umiestnením antény dostatočne vysoko a do blízkosti okna."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Skontrolujte, či je tuner USB zapojený a pripojený k zdroju televízneho signálu.\n\nAk používate vzdušnú anténu, upravte jej umiestnenie alebo orientáciu, aby ste získali čo najviac kanálov. Najlepšie výsledky dosiahnete umiestnením antény dostatočne vysoko a do blízkosti okna."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Skontrolujte, či je sieťový tuner zapnutý a pripojený k zdroju televízneho signálu.\n\nAk používate bezdrôtovú anténu, upravte jej umiestnenie alebo orientáciu tak, aby ste získali čo najviac kanálov. Najlepšie výsledky dosiahnete umiestnením antény dostatočne vysoko a do blízkosti okna."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Pokračovať"</item>
+ <item msgid="727245208787621142">"Teraz nie"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Znova spustiť nastavenie kanálov?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Táto akcia odstráni nájdené kanály z televízneho tunera a opätovne spustí vyhľadávanie nových kanálov.\n\nSkontrolujte, či je televízor pripojený k zdroju televízneho signálu.\n\nAk používate vzdušnú anténu, upravte jej umiestnenie alebo orientáciu, aby ste získali čo najviac kanálov. Najlepšie výsledky dosiahnete umiestnením antény dostatočne vysoko a do blízkosti okna."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Táto akcia odstráni nájdené kanály z tunera USB a opätovne spustí vyhľadávanie nových kanálov.\n\nSkontrolujte, či je tuner USB zapojený a pripojený k zdroju televízneho signálu.\n\nAk používate vzdušnú anténu, upravte jej umiestnenie alebo orientáciu, aby ste získali čo najviac kanálov. Najlepšie výsledky dosiahnete umiestnením antény dostatočne vysoko a do blízkosti okna."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Táto akcia odstráni nájdené kanály zo sieťového tunera a opätovne spustí vyhľadávanie nových kanálov.\n\nSkontrolujte, či je sieťový tuner zapnutý a pripojený k zdroju televízneho signálu.\n\nAk používate bezdrôtovú anténu, upravte jej umiestnenie alebo orientáciu tak, aby ste získali čo najviac kanálov. Najlepšie výsledky dosiahnete umiestnením antény dostatočne vysoko a do blízkosti okna."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Pokračovať"</item>
+ <item msgid="235450158666155406">"Zrušiť"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Výber typu pripojenia"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Ak je k tuneru pripojená externá anténa, vyberte možnosť Anténa. Ak máte kanály od poskytovateľa káblových služieb, vyberte možnosť Kábel. Ak to neviete isto, prehľadajú sa oba typy, ale môže to trvať dlhšie."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Anténa"</item>
+ <item msgid="2670079958754180142">"Kábel"</item>
+ <item msgid="36774059871728525">"Neviem"</item>
+ <item msgid="6881204453182153978">"Iba pre vývojárov"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Nastavenie televízneho tunera"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Nastavenie kanálov tunera USB"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Nastavenie kanálov sieťového tunera"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Môže to trvať niekoľko minút"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Tuner nie je dočasne kˆ dispozícii alebo sa práve používa na nahrávanie."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="few">Našli sa %1$d kanály</item>
+ <item quantity="many">Našlo sa %1$d kanála</item>
+ <item quantity="other">Našlo sa %1$d kanálov</item>
+ <item quantity="one">Našiel sa %1$d kanál</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"ZASTAVIŤ HĽADANIE KANÁLOV"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="few">Našli sa %1$d kanály</item>
+ <item quantity="many">Našlo sa %1$d kanála</item>
+ <item quantity="other">Našlo sa %1$d kanálov</item>
+ <item quantity="one">Našiel sa %1$d kanál</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="few">Skvelé! Pri hľadaní kanálov sa našli %1$d kanály. Ak sa vám to nezdá, skúste upraviť pozíciu antény a znova spustite hľadanie.</item>
+ <item quantity="many">Skvelé! Pri hľadaní kanálov sa našlo %1$d kanála. Ak sa vám to nezdá, skúste upraviť pozíciu antény a znova spustite hľadanie.</item>
+ <item quantity="other">Skvelé! Pri hľadaní kanálov sa našlo %1$d kanálov. Ak sa vám to nezdá, skúste upraviť pozíciu antény a znova spustite hľadanie.</item>
+ <item quantity="one">Skvelé! Pri hľadaní kanálov sa našiel %1$d kanál. Ak sa vám to nezdá, skúste upraviť pozíciu antény a znova spustite hľadanie.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Hotovo"</item>
+ <item msgid="2480490326672924828">"Hľadať znova"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Nenašli sa žiadne kanály"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Nenašli sa žiadne kanály. Skontrolujte, či je televízor pripojený k zdroju televízneho signálu.\n\nAk používate vzdušnú anténu, upravte jej umiestnenie alebo orientáciu. Najlepšie výsledky dosiahnete umiestnením antény dostatočne vysoko a do blízkosti okna. Potom znova spustite hľadanie."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Nenašli sa žiadne kanály. Skontrolujte, či je tuner USB zapojený a pripojený k zdroju televízneho signálu.\n\nAk používate vzdušnú anténu, upravte jej umiestnenie alebo orientáciu. Najlepšie výsledky dosiahnete umiestnením antény dostatočne vysoko a do blízkosti okna. Potom znova spustite hľadanie."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Nenašli sa žiadne kanály. Skontrolujte, či je sieťový tuner zapnutý a pripojený k zdroju televízneho signálu.\n\nAk používate bezdrôtovú anténu, upravte jej umiestnenie alebo orientáciu. Najlepšie výsledky dosiahnete umiestnením antény dostatočne vysoko a do blízkosti okna. Potom znova spustite hľadanie."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Hľadať znova"</item>
+ <item msgid="2092797862490235174">"Hotovo"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Vyhľadajte televízne kanály"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Nastavenie televízneho tunera"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Nastavenie televízneho tunera s rozhraním USB"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Nastavenie televízneho sieťového tunera"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"TV tuner s rozhraním USB bol odpojený."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Sieťový tuner bol odpojený."</string>
+</resources>
diff --git a/usbtuner-res/values-sl/strings.xml b/usbtuner-res/values-sl/strings.xml
new file mode 100644
index 00000000..2f0812bb
--- /dev/null
+++ b/usbtuner-res/values-sl/strings.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Sprejemnik TV-kanalov"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"Sprejemnik TV-kanalov USB"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Omrežni sprejemnik TV-kanalov (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Počakajte, da se dokonča obdelava"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Programska oprema sprejemnika je bila nedavno posodobljena. Znova poiščite kanale."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"V sistemskih nastavitvah zvoka omogočite prostorski zvok, če želite omogočiti zvok"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Zvoka ni mogoče predvajati. Poskusite na drugem televizorju."</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Nastavitev sprejemnika kanalov"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Nastavitev sprejemnika TV-kanalov"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Nastavitev sprejemnika kanalov USB"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Nastavitev omrežnega sprejemnika"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Preverite, ali je televizor povezan z virom TV-signala.\n\nČe uporabljate anteno za prizemno televizijo, prilagodite njen položaj oziroma njeno usmerjenost. Če želite najboljši rezultat, jo postavite na visok položaj in blizu okna ter iščite kanale znova."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Preverite, ali je sprejemnik USB priključen in povezan z virom TV-signala.\n\nČe uporabljate anteno za prizemno televizijo, morate morda prilagoditi njen položaj oziroma njeno usmerjenost, če želite prejemati največ kanalov. Če želite najboljši rezultat, jo postavite na visok položaj in blizu okna."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Preverite, ali je omrežni sprejemnik vklopljen in povezan z virom TV-signala.\n\nČe uporabljate anteno za prizemno televizijo, prilagodite njen položaj oziroma njeno usmerjenost. Če želite najboljši rezultat, jo postavite na visok položaj in blizu okna."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Naprej"</item>
+ <item msgid="727245208787621142">"Ne zdaj"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Ali želite znova zagnati namestitev kanalov?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"S tem bodo odstranjeni kanali, najdeni prek sprejemnika TV-kanalov, in iskanje kanalov se bo začelo znova.\n\nPreverite, ali je televizor povezan z virom TV-signala.\n\nČe uporabljate anteno za prizemno televizijo, prilagodite njen položaj oziroma njeno usmerjenost. Če želite najboljši rezultat, jo postavite na visok položaj in blizu okna ter iščite kanale znova."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"S tem bodo odstranjeni kanali, najdeni prek sprejemnika USB, in iskanje kanalov se bo začelo znova.\n\nPreverite, ali je sprejemnik USB priključen in povezan z virom TV-signala.\n\nČe uporabljate anteno za prizemno televizijo, morate morda prilagoditi njen položaj oziroma njeno usmerjenost, če želite prejemati največ kanalov. Če želite najboljši rezultat, jo postavite na visok položaj in blizu okna."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"S tem bodo odstranjeni kanali, najdeni z omrežnim sprejemnikom kanalov, in vnovič se bo začelo iskanje novih kanalov.\n\nPreverite, ali je omrežni sprejemnik vklopljen in povezan z virom TV-signala.\n\nČe uporabljate anteno za prizemno televizijo, prilagodite njen položaj oziroma njeno usmerjenost. Če želite najboljši rezultat, jo postavite na visok položaj in blizu okna."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Naprej"</item>
+ <item msgid="235450158666155406">"Prekliči"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Izbira vrste povezave"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Izberite »Antena«, če je v sprejemnik priključena zunanja antena. Izberite »Kabelska televizija«, če kanale zagotavlja ponudnik storitve kabelske televizije. Če niste prepričani, bo preiskano oboje, vendar lahko traja dlje."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antena"</item>
+ <item msgid="2670079958754180142">"Kabelska televizija"</item>
+ <item msgid="36774059871728525">"Ne vem"</item>
+ <item msgid="6881204453182153978">"Samo za razvoj"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Nastavitev sprejemnika TV-kanalov"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Nastavitev sprejemnika kanalov USB"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Nastavitev omrežnega sprejemnika kanalov"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"To lahko traja nekaj minut"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Sprejemnik začasno ni na voljo ali se že uporablja za snemanje."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="one">Najden je bil %1$d kanal</item>
+ <item quantity="two">Najdena sta bila %1$d kanala</item>
+ <item quantity="few">Najdeni so bili %1$d kanali</item>
+ <item quantity="other">Najdenih je bilo %1$d kanalov</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"USTAVI ISKANJE KANALOV"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="one">Najden je bil %1$d kanal</item>
+ <item quantity="two">Najdena sta bila %1$d kanala</item>
+ <item quantity="few">Najdeni so bili %1$d kanali</item>
+ <item quantity="other">Najdenih je bilo %1$d kanalov</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="one">Super. Med iskanjem kanalov je bil najden %1$d kanal. Če menite, da to ni pravilno, poskusite prilagoditi položaj antene in iščite znova.</item>
+ <item quantity="two">Super. Med iskanjem kanalov sta bila najdena %1$d kanala. Če menite, da to ni pravilno, poskusite prilagoditi položaj antene in iščite znova.</item>
+ <item quantity="few">Super. Med iskanjem kanalov so bili najdeni %1$d kanali. Če menite, da to ni pravilno, poskusite prilagoditi položaj antene in iščite znova.</item>
+ <item quantity="other">Super. Med iskanjem kanalov je bilo najdenih %1$d kanalov. Če menite, da to ni pravilno, poskusite prilagoditi položaj antene in iščite znova.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Končano"</item>
+ <item msgid="2480490326672924828">"Znova išči"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Ni najdenih kanalov"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Pri iskanju kanali niso bili najdeni. Preverite, ali je televizor povezan z virom TV-signala.\n\nČe uporabljate anteno za prizemno televizijo, prilagodite njen položaj oziroma njeno usmerjenost. Če želite najboljši rezultat, jo postavite na visok položaj in blizu okna ter iščite kanale znova."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Pri iskanju kanali niso bili najdeni. Preverite, ali je sprejemnik USB priključen in povezan z virom TV-signala.\n\nČe uporabljate anteno za prizemno televizijo, prilagodite njen položaj oziroma njeno usmerjenost. Če želite najboljši rezultat, jo postavite na visok položaj in blizu okna ter iščite kanale znova."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Pri iskanju ni bil najden noben kanal. Preverite, ali je omrežni sprejemnik vklopljen in povezan z virom TV-signala.\n\nČe uporabljate anteno za prizemno televizijo, prilagodite njen položaj oziroma njeno usmerjenost. Če želite najboljši rezultat, jo postavite na visok položaj in blizu okna ter iščite kanale znova."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Znova išči"</item>
+ <item msgid="2092797862490235174">"Končano"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Iskanje TV-kanalov"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Nastavitev sprejemnika TV-kanalov"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Nastavitev sprejemnika TV-kanalov USB"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Nastavitev omrežnega sprejemnika TV-kanalov"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"Povezava s sprejemnikom za TV-kanale USB je prekinjena."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Povezava z omrežnim sprejemnikom je prekinjena."</string>
+</resources>
diff --git a/usbtuner-res/values-sr/strings.xml b/usbtuner-res/values-sr/strings.xml
new file mode 100644
index 00000000..ce7c4d53
--- /dev/null
+++ b/usbtuner-res/values-sr/strings.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Тјунер за ТВ"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB тјунер за ТВ"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Мрежни тјунер за ТВ (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Сачекајте да се заврши обрада"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Софтвер тјунера је недавно ажуриран. Претражите канале поново."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Омогући звучни систем у подешавањима звука да бисте омогућили аудио"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Звук не може да се пусти. Испробајте други ТВ уређај"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Подешавање тјунера за канале"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Подешавање тјунера за ТВ"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Подешавање USB тјунера за канале"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Подешавање мрежног тјунера"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Проверите да ли је ТВ повезан са извором ТВ сигнала.\n\nАко користите антену за сигнал преко мреже, можда треба да прилагодите њен положај или смер да бисте имали највише канала. Ако желите најбоље резултате, поставите је високо и близу прозора."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Проверите да ли је USB тјунер прикључен и повезан са извором ТВ сигнала.\n\nАко користите антену за сигнал преко мреже, можда треба да прилагодите њен положај или смер да бисте имали највише канала. Ако желите најбоље резултате, поставите је високо и близу прозора."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Проверите да ли је мрежни тјунер укључен и повезан са извором ТВ сигнала.\n\nАко користите антену за сигнал преко мреже, можда треба да прилагодите њен положај или смер да бисте имали највише канала. Ако желите најбоље резултате, поставите је високо и близу прозора."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Настави"</item>
+ <item msgid="727245208787621142">"Не сада"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Желите ли да поново покренете подешавање канала?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"На овај начин уклањате канале пронађене помоћу тјунера за ТВ и поново тражите нове канале.\n\nПроверите да ли је ТВ повезан са извором ТВ сигнала.\n\nАко користите антену за сигнал преко мреже, можда треба да прилагодите њен положај или смер да бисте имали највише канала. Ако желите најбоље резултате, поставите је високо и близу прозора."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"На овај начин уклањате канале пронађене помоћу USB тјунера и поново тражите нове канале.\n\nПроверите да ли је USB тјунер прикључен и повезан са извором ТВ сигнала.\n\nАко користите антену за сигнал преко мреже, можда треба да прилагодите њен положај или смер да бисте имали највише канала. Ако желите најбоље резултате, поставите је високо и близу прозора."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"На овај начин уклањате канале пронађене помоћу мрежног тјунера и поново скенирате нове канале.\n\nПроверите да ли је мрежни тјунер укључен и повезан са извором ТВ сигнала.\n\nАко користите антену за сигнал преко мреже, можда треба да прилагодите њен положај или смер да бисте имали највише канала. Ако желите најбоље резултате, поставите је високо и близу прозора."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Настави"</item>
+ <item msgid="235450158666155406">"Откажи"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Изаберите тип везе"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Изаберите „Антена“ ако је спољна антена повезана са тјунером. Изаберите „Кабловска“ ако су вам канали доступни преко добављача услуге кабловске телевизије. Ако нисте сигурни, тражиће се оба типа, али ово може да потраје дуже."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Антена"</item>
+ <item msgid="2670079958754180142">"Кабловска"</item>
+ <item msgid="36774059871728525">"Нисам сигуран/на"</item>
+ <item msgid="6881204453182153978">"Само за програмирање"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Подешавање тјунера за ТВ"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Подешавање USB тјунера за канале"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Подешавање мрежног тјунера за канале"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Ово може да потраје неколико минута"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Тјунер привремено није доступан или се већ користи за снимање."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="one">Пронађен је %1$d канал</item>
+ <item quantity="few">Пронађена су %1$d канала</item>
+ <item quantity="other">Пронађено је %1$d канала</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"ЗАУСТАВИ ПРЕТРАГУ КАНАЛА"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="one">Пронађен је %1$d канал</item>
+ <item quantity="few">Пронађена су %1$d канала</item>
+ <item quantity="other">Пронађено је %1$d канала</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="one">Одлично! Пронађен је %1$d канал током претраге канала. Ако сматрате да је ово погрешно, покушајте да прилагодите положај антене и да поново обавите претрагу.</item>
+ <item quantity="few">Одлично! Пронађена су %1$d канала током претраге канала. Ако сматрате да је ово погрешно, покушајте да прилагодите положај антене и да поново обавите претрагу.</item>
+ <item quantity="other">Одлично! Пронађено је %1$d канала током претраге канала. Ако сматрате да је ово погрешно, покушајте да прилагодите положај антене и да поново обавите претрагу.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Готово"</item>
+ <item msgid="2480490326672924828">"Претражи поново"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Није пронађен ниједан канал"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Претрагом није пронађен ниједан канал. Проверите да ли је ТВ повезан са извором ТВ сигнала.\n\nАко користите антену за сигнал преко мреже, прилагодите њен положај или смер. Ако желите најбоље резултате, поставите је високо и близу прозора, па поново обавите претрагу."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Претрагом није пронађен ниједан канал. Проверите да ли је USB тјунер прикључен и повезан са извором ТВ сигнала.\n\nАко користите антену за сигнал преко мреже, прилагодите њен положај или смер. Ако желите најбоље резултате, поставите је високо и близу прозора, па поново обавите претрагу."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Скенирањем није пронађен ниједан канал. Проверите да ли је мрежни тјунер укључен и повезан са извором ТВ сигнала.\n\nАко користите антену за сигнал преко мреже, прилагодите њен положај или смер. Ако желите најбоље резултате, поставите је високо и близу прозора, па поново обавите скенирање."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Претражи поново"</item>
+ <item msgid="2092797862490235174">"Готово"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Потражите ТВ канале"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Подешавање тјунера за ТВ"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Подешавање USB тјунера за ТВ"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Подешавање мрежног тјунера за ТВ"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB тјунер за ТВ није прикључен."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Мрежни тјунер није прикључен."</string>
+</resources>
diff --git a/usbtuner-res/values-sv/strings.xml b/usbtuner-res/values-sv/strings.xml
new file mode 100644
index 00000000..81c37921
--- /dev/null
+++ b/usbtuner-res/values-sv/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"TV-mottagare"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB-TV-mottagare"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Mottagare för TV över nätverket (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Vänta tills sökningen är klar"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Programvaran för mottagaren har nyligen uppdaterats. Sök igenom kanalerna igen."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Aktivera surroundljud under inställningarna för systemljud om du vill aktivera ljud"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Det går inte att spela upp ljud. Testa en annan TV"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Inställning av kanalmottagare"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Konfiguration av TV-mottagare"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Kanalinställning för USB-mottagare"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Konfiguration av nätverksmottagare"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Verifiera att TV:n är ansluten till en signalkälla på TV:n.\n\nOm du använder en antenn för over the air-uppdateringar justerar du dess placering eller riktning. Placera den högt upp och nära ett fönster och sök på nytt för bästa resultat."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Verifiera att USB-mottagaren är ansluten till en signalkälla på TV:n.\n\nOm du använder en antenn för over the air-uppdateringar kan du behöva justera dess placering eller riktning för att hitta så många kanaler som möjligt. Placera den högt upp och nära ett fönster för bästa resultat."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Verifiera att nätverksmottagaren är på och ansluten till en signalkälla på TV:n.\n\nOm du använder en antenn för over the air-uppdateringar justerar du dess placering eller riktning. Placera den högt upp och nära ett fönster och sök på nytt för bästa resultat."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Fortsätt"</item>
+ <item msgid="727245208787621142">"Inte nu"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Vill du göra om kanalinställningen?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Kanalerna som hittats via TV-mottagaren tas bort och en ny kanalsökning startas.\n\nVerifiera att TV:n är ansluten till en signalkälla på TV:n.\n\nOm du använder en antenn för over the air-uppdateringar justerar du dess placering eller riktning. Placera den högt upp och nära ett fönster och sök på nytt för bästa resultat."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Kanalerna som hittats via USB-mottagaren tas bort och en ny kanalsökning startas.\n\nVerifiera att USB-mottagaren är ansluten till en signalkälla på TV:n.\n\nOm du använder en antenn för over the air-uppdateringar kan du behöva justera dess placering eller riktning för att hitta så många kanaler som möjligt. Placera den högt upp och nära ett fönster för bästa resultat."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Åtgärden tar bort alla kanaler som hittades av nätverksmottagaren och söker efter nya kanaler igen.\n\nVerifiera att nätverksmottagaren är på och ansluten till en signalkälla på TV:n.\n\nOm du använder en antenn för over the air-uppdateringar justerar du dess placering eller riktning. Placera den högt upp och nära ett fönster och sök på nytt för bästa resultat."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Fortsätt"</item>
+ <item msgid="235450158666155406">"Avbryt"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Välj anslutningstyp"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Välj Antenn om det finns en extern antenn som är ansluten till mottagaren. Välj Kabel om kanalerna kommer från en kabeltjänstleverantör. Om du är osäker genomsöks båda typerna, men detta kan ta längre tid."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antenn"</item>
+ <item msgid="2670079958754180142">"Kabel"</item>
+ <item msgid="36774059871728525">"Inte säker"</item>
+ <item msgid="6881204453182153978">"Endast för utveckling"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Konfiguration av TV-mottagare"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Kanalinställning för USB-mottagare"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Konfiguration av mottagare för nätverkskanaler"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Det här kan ta flera minuter"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Mottagaren är inte tillgänglig just nu eller så spelas andra program in med den."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">%1$d kanaler hittades</item>
+ <item quantity="one">%1$d kanal hittades</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"STOPPA KANALSÖKNINGEN"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">%1$d kanaler hittades</item>
+ <item quantity="one">%1$d kanal hittades</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Härligt! %1$d kanaler hittades vid kanalsökningen. Om det här inte verkar stämma kan du testa att justera antennens läge och söka igen.</item>
+ <item quantity="one">Härligt! %1$d kanal hittades vid kanalsökningen. Om det här inte verkar stämma kan du testa att justera antennens läge och söka igen.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Klar"</item>
+ <item msgid="2480490326672924828">"Sök igen"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Inga kanaler hittades"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Inga kanaler hittades vid sökningen. Verifiera att TV:n är ansluten till en signalkälla på TV:n.\n\nOm du använder en antenn för over the air-uppdateringar justerar du dess placering eller riktning. Placera den högt upp och nära ett fönster och sök på nytt för bästa resultat."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Inga kanaler hittades vid sökningen. Verifiera att USB-mottagaren är ansluten till en signalkälla på TV:n.\n\nOm du använder en antenn för over the air-uppdateringar justerar du dess placering eller riktning. Placera den högt upp och nära ett fönster och sök på nytt för bästa resultat."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Inga kanaler hittades under genomsökningen. Verifiera att nätverksmottagaren är på och ansluten till en signalkälla på TV:n.\n\nOm du använder en antenn för over the air-uppdateringar justerar du dess placering eller riktning. Placera den högt upp och nära ett fönster och sök på nytt för bästa resultat."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Sök igen"</item>
+ <item msgid="2092797862490235174">"Klar"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Sök efter TV-kanaler"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Konfiguration av TV-mottagare"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Konfiguration av USB-ansluten TV-mottagare"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Konfiguration av nätverksansluten TV-mottagare"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB-TV-mottagaren har kopplats från."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Nätverksmottagaren har kopplats från."</string>
+</resources>
diff --git a/usbtuner-res/values-sw/strings.xml b/usbtuner-res/values-sw/strings.xml
new file mode 100644
index 00000000..c81614c0
--- /dev/null
+++ b/usbtuner-res/values-sw/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Kitafutaji cha vituo vya TV"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"Kitafutaji cha Vituo vya TV cha USB"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Kitafuta Vituo vya TV ya Mtandao (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Tafadhali subiri ili shughuli imalizike"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Programu ya kitafutaji cha vituo cha USB ilisasishwa hivi majuzi. Tafadhali tafuta vituo tena."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Washa sauti ya mzunguko katika mipangilio ya mfumo wa sauti ili uruhusu sauti"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Haiwezi kucheza sauti. Tafadhali jaribu TV nyingine"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Kuweka mipangilio ya kitafutaji cha vituo"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Kuweka mipangilio ya kitafutaji cha vituo vya TV"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Kuweka mipangilio ya kitafutaji cha vituo cha USB"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Kuweka mipangilio ya kitafuta vituo vya TV"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Hakikisha TV yako imeunganishwa kwenye chanzo cha TV.\n\nIkiwa unatumia antena ya hewani, rekebisha jinsi ilivyowekwa au mwelekeo wake. Ili kupata matokeo bora zaidi, ipandishe juu na uiweke karibu na dirisha."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Thibitisha kuwa kitafutaji cha vituo cha USB kimechomekwa katika chanzo cha umeme na kuunganishwa katika chanzo cha mawimbi ya TV.\n\nKama unatumia antena ya hewani, rekebisha mkao wake au kule inakoelekea. Kwa matokeo bora zaidi, iweke juu , karibu na dirisha."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Thibitisha kuwa kitafuta vituo kimewashwa na kuunganishwa kwenye chanzo cha mawimbi ya TV. \n\nIkiwa unatumia antena ya hewani, huenda ukahitaji kurekebisha jinsi ilivyowekwa au inakoelekea, ili upate vituo vingi. Kwa matokeo bora zaidi, ipandishe juu na iwe karibu na dirisha."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Endelea"</item>
+ <item msgid="727245208787621142">"Si sasa"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Ungependa kuweka mipangilio ya vituo upya?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Hatua hii itaondoa vituo vilivyopatikana kwenye kitafutaji cha vituo vya TV na kutafuta vituo vipya tena.\n\nHakikisha TV yako imeunganishwa kwenye chanzo cha mawimbi ya TV.\n\nIkiwa unatumia antena ya hewani, rekebisha jinsi ilivyowekwa au mwelekeo wake. Ili kupata matokeo bora zaidi, ipandishe juu na uiweke karibu na dirisha kisha utafute tena."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Hatua hii itaondoa vituo vilivyopatikana kwenye kitafutaji cha vituo cha USB na kutafuta vituo tena. \n\nThibitisha kuwa kitafutaji cha vituo cha USB kimechomekwa kwenye chanzo cha umeme na kuunganishwa katika chanzo cha mawimbi ya TV.\n\nKama unatumia antena ya hewani, rekebisha mkao wake au kule inakoelekea. Kwa matokeo bora zaidi, iweke juu, karibu na dirisha."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Hatua hii itaondoa vituo ulivyopata kwenye kitafuta vituo na kutafuta vituo vipya tena.\n\nThibitisha kwamba kitafuta vituo kimewashwa na kuunganishwa kwenye chanzo cha mawimbi ya TV.\n\nIkiwa unatumia antena ya hewani, rekebisha jinsi ilivyowekwa au inakoelekea, ili upate vituo vingi. Kwa matokeo bora zaidi, ipandishe juu na iwe karibu na dirisha."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Endelea"</item>
+ <item msgid="235450158666155406">"Ghairi"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Chagua aina ya muunganisho"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Chagua Antena kama unatumia antena ya nje iliyounganishwa kwenye kitafuta vituo. Chagua Kebo kama vituo vyako vinapeperushwa na mtoa huduma za vifaa vinavyotumia kebo. Kama huna uhakika, aina zote zitatafutwa na huenda utafutaji ukachukua muda mrefu."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antena"</item>
+ <item msgid="2670079958754180142">"Kebo"</item>
+ <item msgid="36774059871728525">"Sina uhakika"</item>
+ <item msgid="6881204453182153978">"Kusanidi pekee"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Kuweka mipangilio ya kitafutaji cha vituo vya TV"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Kuweka mipangilio ya kitafutaji cha vituo cha USB"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Kuweka mipangilio ya kitafuta vituo"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Shughuli hii inaweza kuchukua dakika kadhaa"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Kitafuta vituo hakipatikani kwa sasa au tayari kinatumiwa kurekodi."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">Vituo %1$d vimepatikana</item>
+ <item quantity="one">Kituo %1$d kimepatikana</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"SIMAMISHA UTAFUTAJI WA VITUO"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">Vituo %1$d vimepatikana</item>
+ <item quantity="one">Kituo %1$d kimepatikana</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Sadakta! Vituo %1$d vimepatikana baada ya kutafuta vituo. Kama hujaridhika, jaribu kurekebisha mkao wa antena kisha utafute tena.</item>
+ <item quantity="one">Sadakta! Kituo %1$d kimepatikana baada ya kutafuta vituo. Kama hujaridhika, jaribu kurekebisha mkao wa antena kisha utafute tena.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Nimemaliza"</item>
+ <item msgid="2480490326672924828">"Tafuta tena"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Hakuna Vituo vilivyopatikana"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Hakuna vituo vilivyopatikana baada ya kutafuta. Hakikisha TV yako imeunganishwa kwenye chanzo cha mawimbi ya TV.\n\nIkiwa unatumia antena ya hewani, rekebisha jinsi ilivyowekwa au mwelekeo wake. Ili kupata matokeo bora zaidi, ipandishe juu na uiweke karibu na dirisha kisha utafute tena."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Utafutaji haukupata vituo vyovyote. Thibitisha kuwa kitafutaji cha vituo cha USB kimechomekwa kwenye chanzo cha umeme na kuunganishwa katika chanzo cha mawimbi ya TV.\n\nKama unatumia antena ya hewani, rekebisha mkao wake au kule inakoelekea. Kwa matokeo bora zaidi, iweke juu, karibu na dirisha na utafute tena."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Haikupata vituo vyovyote. Thibitisha kwamba kitafuta vituo kimewashwa na kuunganishwa kwenye chanzo cha mawimbi ya TV.\n\nIkiwa unatumia antena ya hewani, rekebisha jinsi ilivyowekwa au inakoelekea. Ili upate matokeo bora zaidi, ipandishe juu na karibu na dirisha kisha utafute tena."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Tafuta tena"</item>
+ <item msgid="2092797862490235174">"Nimemaliza"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Tafuta vituo vya TV"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Kuweka mipangilio ya kitafutaji cha vituo vya TV"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Kuweka mipangilio ya Kitafutaji cha Vituo vya TV kupitia USB"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Kuweka mipangilio ya Kitafutaji cha Vituo vya TV kupitia Mtandao"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"Umeondoa kichagua programu cha USB cha TV."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Umeondoa kitafuta mitandao."</string>
+</resources>
diff --git a/usbtuner-res/values-ta-rIN/strings.xml b/usbtuner-res/values-ta-rIN/strings.xml
new file mode 100644
index 00000000..1c71722e
--- /dev/null
+++ b/usbtuner-res/values-ta-rIN/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"டிவி ட்யூனர்"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB டிவி ட்யூனர்"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"நெட்வொர்க் டிவி டியூனர் (பீட்டா)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"செயலாக்கம் முடியும் வரை காத்திருக்கவும்"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"ட்யூனர் மென்பொருள் சமீபத்தில் புதுப்பிக்கப்பட்டது. சேனல்களை மீண்டும் ஸ்கேன் செய்யவும்."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"ஆடியோவை இயக்க, சாதன ஒலி அமைப்புகளில் \"சரவுண்ட் சவுண்ட்\" என்பதை இயக்கவும்"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"ஆடியோவை இயக்க முடியவில்லை. வேறு டிவியைப் பயன்படுத்தவும்"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"சேனல் ட்யூனர் அமைவு"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"டிவி ட்யூனர் அமைவு"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB சேனல் ட்யூனர் அமைவு"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"நெட்வொர்க் டியூனர் அமைவு"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"டிவி சிக்னல் மூலத்துடன் உங்கள் டிவி இணைக்கப்பட்டுள்ளதைச் சரிபார்க்கவும்.\n\nஆன்டெனாவைப் பயன்படுத்தினால், அதிகமான சேனல்களைப் பெறுவதற்காக அதன் இடம் அல்லது திசையைச் சரிசெய்ய வேண்டியிருக்கலாம். இன்னும் சிறப்பான முடிவுகளுக்கு, அதை உயரமான இடத்தில் ஜன்னலுக்கு அருகே வைக்கவும்."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"USB ட்யூனர் செருகப்பட்டுள்ளதையும் டிவி சிக்னல் மூலத்துடன் இணைக்கப்பட்டுள்ளதையும் சரிபார்க்கவும்.\n\nஆன்டெனாவைப் பயன்படுத்தினால், அதிகமான சேனல்களைப் பெறுவதற்காக அதன் இடம் அல்லது திசையைச் சரிசெய்ய வேண்டியிருக்கலாம். இன்னும் சிறப்பான முடிவுகளுக்கு, அதை உயரமான இடத்தில் ஜன்னலுக்கு அருகே வைக்கவும்."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"நெட்வொர்க் டியூனர் ஆன் செய்யப்பட்டுள்ளதையும் டிவி சிக்னல் மூலத்துடன் இணைக்கப்பட்டுள்ளதையும் சரிபார்க்கவும்.\n\nஆன்டெனாவைப் பயன்படுத்தினால், அதிகமான சேனல்களைப் பெறுவதற்காக அதன் இடம் அல்லது திசையைச் சரிசெய்ய வேண்டியிருக்கலாம். இன்னும் சிறப்பான முடிவுகளுக்கு, அதை உயரமான இடத்தில் ஜன்னலுக்கு அருகே வைக்கவும்."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"தொடர்க"</item>
+ <item msgid="727245208787621142">"இப்போது வேண்டாம்"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"சேனல் அமைவை மீண்டும் இயக்கவா?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"இவ்வாறு செய்வதால் டிவி ட்யூனர் மூலம் கண்டறிந்த சேனல்கள் அகற்றப்படுவதுடன், புதிய சேனல்களுக்காக மீண்டும் ஸ்கேன் செய்யும்.\n\nடிவி சிக்னல் மூலத்துடன் உங்கள் டிவி இணைக்கப்பட்டுள்ளதைச் சரிபார்க்கவும்.\n\nஆன்டெனாவைப் பயன்படுத்தினால், அதிகமான சேனல்களைப் பெறுவதற்காக அதன் இடம் அல்லது திசையைச் சரிசெய்ய வேண்டியிருக்கலாம். இன்னும் சிறப்பான முடிவுகளுக்கு, அதை உயரமான இடத்தில் ஜன்னலுக்கு அருகே வைக்கவும்."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"இவ்வாறு செய்வதால் USB ட்யூனர் மூலம் கண்டறிந்த சேனல்கள் அகற்றப்படுவதுடன், புதிய சேனல்களுக்காக மீண்டும் ஸ்கேன் செய்யும்.\n\nUSB ட்யூனர் செருகப்பட்டுள்ளதையும் டிவி சிக்னல் மூலத்துடன் இணைக்கப்பட்டுள்ளதையும் சரிபார்க்கவும்.\n\nஆன்டெனாவைப் பயன்படுத்தினால், அதிகமான சேனல்களைப் பெறுவதற்காக அதன் இடம் அல்லது திசையைச் சரிசெய்ய வேண்டியிருக்கலாம். இன்னும் சிறப்பான முடிவுகளுக்கு, அதை உயரமான இடத்தில் ஜன்னலுக்கு அருகே வைக்கவும்."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"இது நெட்வொர்க் டியூனரிலிருந்து கண்டறிந்த சேனல்களை அகற்றும் மற்றும் புதிய சேனல்களுக்காக மீண்டும் ஸ்கேன் செய்யும்.\n\nநெட்வொர்க் டியூனர் ஆன் செய்யப்பட்டுள்ளதையும் டிவி சிக்னல் மூலத்துடன் இணைக்கப்பட்டுள்ளதையும் சரிபார்க்கவும்.\n\nஆன்டெனாவைப் பயன்படுத்தினால், அதிகமான சேனல்களைப் பெறுவதற்காக, அதன் இடம் அல்லது திசையைச் சரிசெய்ய வேண்டியிருக்கலாம். இன்னும் சிறப்பான முடிவுகளுக்கு, உயரமான இடத்தில், ஜன்னலுக்கு அருகில் வைக்கவும்."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"தொடர்க"</item>
+ <item msgid="235450158666155406">"ரத்துசெய்"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"இணைப்பு வகையைத் தேர்ந்தெடுக்கவும்"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"ட்யூனருடன் வெளிப்புற ஆன்டெனா இணைக்கப்பட்டிருந்தால், ஆன்டெனாவைத் தேர்வுசெய்யவும். கேபிள் சேவை வழங்குநரிடமிருந்து சேனல்கள் கிடைக்கின்றன என்றால், கேபிளைத் தேர்வுசெய்யவும். எதையும் தேர்வுசெய்யவில்லை எனில், இரு வகைகளிலும் ஸ்கேன் செய்யப்படும். ஆனால் இதற்கு அதிக நேரம் ஆகலாம்."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"ஆன்டெனா"</item>
+ <item msgid="2670079958754180142">"கேபிள்"</item>
+ <item msgid="36774059871728525">"நிச்சயமாகத் தெரியவில்லை"</item>
+ <item msgid="6881204453182153978">"டெவெலப்மென்ட் மட்டும்"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"டிவி ட்யூனர் அமைவு"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB சேனல் ட்யூனர் அமைவு"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"நெட்வொர்க் சேனல் டியூனர் அமைவு"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"இதற்குச் சில நிமிடங்கள் ஆகலாம்"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"ட்யூனர் தற்காலிகமாகக் கிடைக்கவில்லை அல்லது ரெக்கார்டு செய்வதற்காக ஏற்கனவே பயன்படுத்தப்படுகிறது."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">%1$d சேனல்கள் கண்டறியப்பட்டன</item>
+ <item quantity="one">%1$d சேனல் கண்டறியப்பட்டது</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"சேனலை ஸ்கேன் செய்வதை நிறுத்து"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">%1$d சேனல்கள் கண்டறியப்பட்டன</item>
+ <item quantity="one">%1$d சேனல் கண்டறியப்பட்டது</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">அருமை! சேனலை ஸ்கேன் செய்யும் போது, %1$d சேனல்கள் கண்டறியப்பட்டன. இவை சரியாகத் தெரியவில்லை என்றால், ஆன்டெனாவின் நிலையை மாற்றி, மீண்டும் ஸ்கேன் செய்யவும்.</item>
+ <item quantity="one">அருமை! சேனலை ஸ்கேன் செய்யும் போது, %1$d சேனல் கண்டறியப்பட்டது. இது சரியாகத் தெரியவில்லை என்றால், ஆன்டெனாவின் நிலையை மாற்றி, மீண்டும் ஸ்கேன் செய்யவும்.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"முடிந்தது"</item>
+ <item msgid="2480490326672924828">"மீண்டும் ஸ்கேன் செய்"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"சேனல்கள் இல்லை"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"ஸ்கேன் செய்ததில் சேனல்கள் எவையும் கண்டறியப்படவில்லை. டிவி சிக்னல் மூலத்துடன் உங்கள் டிவி இணைக்கப்பட்டுள்ளதைச் சரிபார்க்கவும்.\n\nஆன்டெனாவைப் பயன்படுத்தினால், அதன் இடம் அல்லது திசையைச் சரிசெய்யவும். இன்னும் சிறப்பான முடிவுகளுக்கு, அதை உயரமான இடத்தில் ஜன்னலுக்கு அருகே வைத்து, மீண்டும் ஸ்கேன் செய்யவும்."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"ஸ்கேன் செய்ததில் சேனல்கள் எவையும் கண்டறியப்படவில்லை. USB ட்யூனர் செருகப்பட்டுள்ளதையும் டிவி சிக்னல் மூலத்துடன் இணைக்கப்பட்டுள்ளதையும் சரிபார்க்கவும்.\n\nஆன்டெனாவைப் பயன்படுத்தினால், அதன் இடம் அல்லது திசையைச் சரிசெய்யவும். இன்னும் சிறப்பான முடிவுகளுக்கு, அதை உயரமான இடத்தில் ஜன்னலுக்கு அருகே வைத்து, மீண்டும் ஸ்கேன் செய்யவும்."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"ஸ்கேன் செய்ததில் சேனல்கள் எதுவும் கண்டறியப்படவில்லை. நெட்வொர்க் டியூனர் ஆன் செய்யப்பட்டுள்ளதையும் டிவி சிக்னல் மூலத்துடன் இணைக்கப்பட்டுள்ளதையும் சரிபார்க்கவும்.\n\nஆன்டெனாவைப் பயன்படுத்தினால், அதன் இடம் அல்லது திசையைச் சரிசெய்யவும். இன்னும் சிறப்பான முடிவுகளுக்கு, அதை உயரமான இடத்தில் ஜன்னலுக்கு அருகே வைத்து, மீண்டும் ஸ்கேன் செய்யவும்."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"மீண்டும் ஸ்கேன் செய்"</item>
+ <item msgid="2092797862490235174">"முடிந்தது"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"டிவி சேனல்களைத் தேடுக"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"டிவி டியூனர் அமைவு"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB டிவி டியூனர் அமைவு"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"நெட்வொர்க் டிவி டியூனர் அமைவு"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB டிவி ட்யூனர் துண்டிக்கப்பட்டது."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"நெட்வொர்க் ட்யூனர் துண்டிக்கப்பட்டது."</string>
+</resources>
diff --git a/usbtuner-res/values-te-rIN/strings.xml b/usbtuner-res/values-te-rIN/strings.xml
new file mode 100644
index 00000000..fb6bcf37
--- /dev/null
+++ b/usbtuner-res/values-te-rIN/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"టీవీ ట్యూనర్"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB టీవీ ట్యూనర్"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"నెట్‌వర్క్ టీవీ ట్యూనర్ (బీటా)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"దయచేసి ప్రాసెస్ చేయడం పూర్తయ్యే వరకు వేచి ఉండండి"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"ట్యూనర్ సాఫ్ట్‌వేర్ ఇటీవల నవీకరించబడింది. దయచేసి ఛానెల్‌లను మళ్లీ స్కాన్ చేయండి."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"ఆడియోను ప్రారంభించడానికి సిస్టమ్ శబ్ద సెట్టింగ్‌ల్లో పరిసర వ్యాప్త శబ్దాన్ని ప్రారంభించండి"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"ఆడియోను ప్లే చేయడం సాధ్యపడదు. దయచేసి మరో టీవీలో ప్రయత్నించండి"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"ఛానెల్ ట్యూనర్ సెటప్"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"టీవీ ట్యూనర్ సెటప్"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB ఛానెల్ ట్యూనర్ సెటప్"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"నెట్‍వర్క్ ట్యూనర్ సెటప్"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"టీవీ.సిగ్నల్ సోర్స్‌కు మీ టీవీ కనెక్ట్ చేయబడిందని ధృవపరుచుకోండి.\n\nప్రసారాల కోసం యాంటెన్నాను ఉపయోగిస్తుంటే, మీరు మరిన్ని ఛానెల్‌లను స్వీకరించడానికి దాని స్థానాన్ని లేదా దిశను మార్చాల్సి రావచ్చు. ఉత్తమ ఫలితాల కోసం, దాన్ని ఎత్తులో కిటికీకి దగ్గరగా ఉంచండి."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"USB ట్యూనర్ ప్లగిన్ చేయబడి, టీవీ సిగ్నల్ సోర్స్‌కు కనెక్ట్ చేయబడినట్లు ధృవపరుచుకోండి.\n\nప్రసారాల కోసం యాంటెన్నాను ఉపయోగిస్తుంటే, మీరు మరిన్ని ఛానెల్‌లను స్వీకరించడానికి దాని స్థానాన్ని లేదా దిశను మార్చాల్సి రావచ్చు. ఉత్తమ ఫలితాల కోసం, దాన్ని ఎత్తులో కిటికీకి దగ్గరగా ఉంచండి."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"నెట్‍వర్క్ ట్యూనర్ పవర్ ఆన్ చేయబడి, టీవీ సిగ్నల్ సోర్స్‌కు కనెక్ట్ చేయబడినట్లు ధృవపరుచుకోండి.\n\nప్రసారాల కోసం యాంటెన్నాను ఉపయోగిస్తుంటే, మీరు మరిన్ని ఛానెల్‌లను స్వీకరించడానికి దాని స్థానాన్ని లేదా దిశను మార్చాల్సి రావచ్చు. ఉత్తమ ఫలితాల కోసం, దాన్ని ఎత్తులో కిటికీకి దగ్గరగా ఉంచండి."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"కొనసాగించు"</item>
+ <item msgid="727245208787621142">"ఇప్పుడు కాదు"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"ఛానెల్ సెటప్‌ను మళ్లీ అమలు చేయాలా?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"ఇది టీవీ ట్యూనర్ నుండి కనుగొన్న ఛానెల్‌లను తీసివేస్తుంది మరియు మళ్లీ కొత్త ఛానెల్‌ల కోసం స్కాన్ చేస్తుంది.\n\nటీవీ సిగ్నల్ సోర్స్‌కు మీ టీవీ కనెక్ట్ చేయబడిందని ధృవపరుచుకోండి.\n\nప్రసారాల కోసం యాంటెన్నాను ఉపయోగిస్తుంటే, మీరు మరిన్ని ఛానెల్‌లను స్వీకరించడానికి దాని స్థానాన్ని లేదా దిశను మార్చాల్సి రావచ్చు. ఉత్తమ ఫలితాల కోసం, దాన్ని ఎత్తులో కిటికీకి దగ్గరగా ఉంచండి."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"ఇది USB ట్యూనర్ నుండి కనుగొన్న ఛానెల్‌లను తీసివేస్తుంది మరియు మళ్లీ కొత్త ఛానెల్‌ల కోసం స్కాన్ చేస్తుంది.\n\nUSB ట్యూనర్ ప్లగిన్ చేయబడి, టీవీ సిగ్నల్ సోర్స్‌కు కనెక్ట్ చేయబడిందని ధృవపరుచుకోండి.\n\nప్రసారాల కోసం యాంటెన్నాను ఉపయోగిస్తుంటే, మీరు మరిన్ని ఛానెల్‌లను స్వీకరించడానికి దాని స్థానాన్ని లేదా దిశను మార్చాల్సి రావచ్చు. ఉత్తమ ఫలితాల కోసం, దాన్ని ఎత్తులో కిటికీకి దగ్గరగా ఉంచండి."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"ఇది నెట్‍వర్క్ ట్యూనర్ నుండి కనుగొన్న ఛానెల్‌లను తీసివేస్తుంది మరియు మళ్లీ కొత్త ఛానెల్‌ల కోసం స్కాన్ చేస్తుంది.\n\nనెట్‍వర్క్ ట్యూనర్ పవర్ ఆన్ చేయబడి, టీవీ సిగ్నల్ సోర్స్‌కు కనెక్ట్ చేయబడిందని ధృవపరుచుకోండి.\n\nప్రసారాల కోసం యాంటెన్నాను ఉపయోగిస్తుంటే, మీరు మరిన్ని ఛానెల్‌లను స్వీకరించడానికి దాని స్థానాన్ని లేదా దిశను మార్చాలి. ఉత్తమ ఫలితాల కోసం, దాన్ని ఎత్తులో కిటికీకి దగ్గరగా ఉంచండి."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"కొనసాగించు"</item>
+ <item msgid="235450158666155406">"రద్దు చేయి"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"కనెక్షన్ రకాన్ని ఎంచుకోండి"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"ట్యూనర్‌కు బాహ్య యాంటెన్నా కనెక్ట్ చేసి ఉంటే యాంటెన్నాను ఎంచుకోండి. మీ ఛానెల్‌‍‍లను కేబుల్ సేవా ప్రదాత అందిస్తుంటే, కేబుల్‌ను ఎంచుకోండి. మీకు ఏ సంగతి ఖచ్చితంగా తెలియకుంటే, రెండు రకాలు స్కాన్ చేయబడతాయి, కానీ దీనికి ఎక్కువ సమయం పట్టవచ్చు."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"యాంటెన్నా"</item>
+ <item msgid="2670079958754180142">"కేబుల్"</item>
+ <item msgid="36774059871728525">"అంత ఖచ్చితంగా తెలియదు"</item>
+ <item msgid="6881204453182153978">"అభివృద్ధి మాత్రమే"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"టీవీ ట్యూనర్ సెటప్"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB ఛానెల్ ట్యూనర్ సెటప్"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"నెట్‍వర్క్ ఛానెల్ ట్యూనర్ సెటప్"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"దీనికి కొన్ని నిమిషాలు పట్టవచ్చు"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"ట్యూనర్ తాత్కాలికంగా అందుబాటులో లేదు లేదా ఇప్పటికే రికార్డింగ్ ద్వారా ఉపయోగించబడుతోంది."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">%1$d ఛానెల్‌లు కనుగొనబడ్డాయి</item>
+ <item quantity="one">%1$d ఛానెల్ కనుగొనబడింది</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"ఛానెల్ స్కాన్‌ను ఆపివేయి"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">%1$d ఛానెల్‌లు కనుగొనబడ్డాయి</item>
+ <item quantity="one">%1$d ఛానెల్ కనుగొనబడింది</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">మంచిది! ఛానెల్ స్కాన్‌లో %1$d ఛానెల్‌లు కనుగొనబడ్డాయి. ఇది సరైనదిగా అనిపించకుంటే, యాంటెన్నా స్థానం సర్దుబాటు చేసి, ఆపై మళ్లీ స్కాన్ చేయడం ప్రయత్నించండి.</item>
+ <item quantity="one">మంచిది! ఛానెల్ స్కాన్‌లో %1$d ఛానెల్ కనుగొనబడింది. ఇది సరైనదిగా అనిపించకుంటే, యాంటెన్నా స్థానం సర్దుబాటు చేసి, ఆపై మళ్లీ స్కాన్ చేయడం ప్రయత్నించండి.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"పూర్తయింది"</item>
+ <item msgid="2480490326672924828">"మళ్లీ స్కాన్ చేయి"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"ఛానెల్‌లు ఏవీ కనుగొనబడలేదు"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"స్కాన్‌లో ఏ ఛానెల్ కనుగొనబడలేదు. టీవీ సిగ్నల్ సోర్స్‌కి మీ టీవీ కనెక్ట్ చేయబడిందని ధృవపరుచుకోండి. \n\nప్రసారాల కోసం యాంటెన్నాను ఉపయోగిస్తుంటే, దాని స్థానాన్ని లేదా దిశను సర్దుబాటు చేయండి. ఉత్తమ ఫలితాల కోసం, దాన్ని ఎత్తులో కిటికీకి దగ్గరగా ఉంచి, ఆపై మళ్లీ స్కాన్ చేయండి."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"స్కాన్‌లో ఛానెల్‌లు ఏవీ కనుగొనబడలేదు. USB ట్యూనర్ ప్లగిన్ చేయబడి, టీవీ సిగ్నల్ సోర్స్‌కు కనెక్ట్ చేయబడిందని ధృవపరుచుకోండి.\n\nప్రసారాల కోసం యాంటెన్నాను ఉపయోగిస్తుంటే, దాని స్థానాన్ని లేదా దిశను సర్దుబాటు చేయండి. ఉత్తమ ఫలితాల కోసం, దాన్ని ఎత్తులో కిటికీకి దగ్గరగా ఉంచి, ఆపై మళ్లీ స్కాన్ చేయండి."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"స్కాన్‌లో ఛానెల్‌లు ఏవీ కనుగొనబడలేదు. నెట్‍వర్క్ ట్యూనర్ పవర్ ఆన్ చేయబడి, టీవీ సిగ్నల్ సోర్స్‌కు కనెక్ట్ చేయబడిందని ధృవపరుచుకోండి.\n\nప్రసారాల కోసం యాంటెన్నాను ఉపయోగిస్తుంటే, దాని స్థానాన్ని లేదా దిశను సర్దుబాటు చేయండి. ఉత్తమ ఫలితాల కోసం, దాన్ని ఎత్తులో కిటికీకి దగ్గరగా ఉంచి, ఆపై మళ్లీ స్కాన్ చేయండి."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"మళ్లీ స్కాన్ చేయి"</item>
+ <item msgid="2092797862490235174">"పూర్తయింది"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"టీవీ ఛానెల్‌ల కోసం స్కాన్ చేయండి"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"టీవీ ట్యూనర్ సెటప్"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB టీవీ ట్యూనర్ సెటప్"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"నెట్‍వర్క్ టీవీ ట్యూనర్ సెటప్"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB టీవీ ట్యూనర్ డిస్‌కనెక్ట్ చేయబడింది."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"నెట్‌వర్క్ ట్యూనర్ డిస్‌కనెక్ట్ చేయబడింది."</string>
+</resources>
diff --git a/usbtuner-res/values-th/strings.xml b/usbtuner-res/values-th/strings.xml
new file mode 100644
index 00000000..703c0f02
--- /dev/null
+++ b/usbtuner-res/values-th/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"ตัวรับสัญญาณทีวี"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"ตัวรับสัญญาณทีวีแบบ USB"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"ตัวรับสัญญาณทีวีเครือข่าย (เบต้า)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"โปรดรอให้การดำเนินการหยุดลงสักครู่"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"ซอฟต์แวร์ตัวรับสัญญาณมีการอัปเดตเมื่อเร็วๆ นี้ โปรดสแกนช่องอีกครั้ง"</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"เปิดใช้เสียงเซอร์ราวด์ในการตั้งค่าเสียงของระบบเพื่อเปิดใช้เสียง"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"เล่นเสียงไม่ได้ โปรดลองทีวีเครื่องอื่น"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"ตั้งค่าตัวรับสัญญาณช่อง"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"ตั้งค่าตัวรับสัญญาณทีวี"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"ตั้งค่าตัวรับสัญญาณช่องแบบ USB"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"ตั้งค่าตัวรับสัญญาณเครือข่าย"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"โปรดตรวจสอบว่าทีวีของคุณเชื่อมต่อกับแหล่งสัญญาณทีวีแล้ว\n\nหากใช้เสาอากาศแบบผ่านอากาศ คุณอาจต้องปรับตำแหน่งและทิศทางเพื่อรับช่องให้ได้มากที่สุด เพื่อผลลัพธ์ที่ดีที่สุด ให้วางไว้บนที่สูงใกล้หน้าต่าง"</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"โปรดตรวจสอบว่าได้เสียบปลั๊กตัวรับสัญญาณแบบ USB และเชื่อมต่อกับแหล่งสัญญาณทีวีแล้ว\n\nหากใช้เสาอากาศแบบผ่านอากาศ คุณอาจต้องปรับตำแหน่งหรือทิศทางเพื่อรับช่องให้ได้มากที่สุด เพื่อผลลัพธ์ที่ดีที่สุด ให้วางไว้บนที่สูงใกล้หน้าต่าง"</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"โปรดตรวจสอบว่าตัวรับสัญญาณเครือข่ายเปิดอยู่และเชื่อมต่อกับแหล่งสัญญาณทีวีแล้ว\n\nหากใช้เสาอากาศแบบผ่านอากาศ (OTA) คุณอาจต้องปรับตำแหน่งหรือทิศทางเพื่อรับช่องให้ได้มากที่สุด เพื่อผลลัพธ์ที่ดีที่สุด ให้วางไว้บนที่สูงใกล้หน้าต่าง"</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"ต่อไป"</item>
+ <item msgid="727245208787621142">"ข้ามไปก่อน"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"ต้องการเริ่มการตั้งค่าช่องอีกครั้งใช่ไหม"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"วิธีนี้จะนำช่องที่พบจากตัวรับสัญญาณทีวีออกและสแกนหาช่องใหม่อีกครั้ง\n\nโปรดตรวจสอบว่าทีวีของคุณเชื่อมต่อกับแหล่งสัญญาณทีวีแล้ว\n\nหากใช้เสาอากาศแบบผ่านอากาศ คุณอาจต้องปรับตำแหน่งและทิศทางเพื่อรับช่องให้ได้มากที่สุด เพื่อผลลัพธ์ที่ดีที่สุด ให้วางไว้บนที่สูงใกล้หน้าต่าง"</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"วิธีนี้จะนำช่องที่พบจากตัวรับสัญญาณแบบ USB ออกและสแกนหาช่องใหม่อีกครั้ง\n\nโปรดตรวจสอบว่าได้เสียบปลั๊กตัวรับสัญญาณแบบ USB และเชื่อมต่อกับแหล่งสัญญาณทีวีแล้ว\n\nหากใช้เสาอากาศแบบผ่านอากาศ คุณอาจต้องปรับตำแหน่งหรือทิศทางเพื่อรับช่องให้ได้มากที่สุด เพื่อผลลัพธ์ที่ดีที่สุด ให้วางไว้บนที่สูงใกล้หน้าต่าง"</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"การดำเนินการนี้จะนำช่องที่พบจากตัวรับสัญญาณเครือข่ายออกแล้วสแกนหาช่องใหม่อีกครั้ง\n\nโปรดตรวจสอบว่าตัวรับสัญญาณเครือข่ายเปิดอยู่และเชื่อมต่อกับแหล่งสัญญาณทีวีแล้ว\n\nหากใช้เสาอากาศแบบผ่านอากาศ (OTA) คุณอาจต้องปรับตำแหน่งหรือทิศทางเพื่อรับช่องให้ได้มากที่สุด เพื่อผลลัพธ์ที่ดีที่สุด ให้วางไว้บนที่สูงใกล้หน้าต่าง"</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"ต่อไป"</item>
+ <item msgid="235450158666155406">"ยกเลิก"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"เลือกประเภทการเชื่อมต่อ"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"เลือกเสาอากาศหากมีการเชื่อมต่อเสาอากาศภายนอกกับตัวรับสัญญาณ เลือกเคเบิลหากช่องของคุณมาจากผู้ให้บริการเคเบิล หากคุณไม่แน่ใจ ระบบจะสแกนทั้ง 2 แบบซึ่งอาจใช้เวลานานขึ้น"</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"เสาอากาศ"</item>
+ <item msgid="2670079958754180142">"เคเบิล"</item>
+ <item msgid="36774059871728525">"ไม่แน่ใจ"</item>
+ <item msgid="6881204453182153978">"เฉพาะการพัฒนาเท่านั้น"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"ตั้งค่าตัวรับสัญญาณทีวี"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"ตั้งค่าตัวรับสัญญาณช่องแบบ USB"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"ตั้งค่าตัวรับสัญญาณช่องเครือข่าย"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"อาจใช้เวลาหลายนาที"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"ตัวรับสัญญาณไม่สามารถใช้ได้ชั่วคราว หรือถูกใช้ในการบันทึกแล้ว"</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">พบ %1$d ช่อง</item>
+ <item quantity="one">พบ %1$d ช่อง</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"หยุดการสแกนช่อง"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">พบ %1$d ช่อง</item>
+ <item quantity="one">พบ %1$d ช่อง</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">เยี่ยมมาก! สแกนพบ %1$d ช่อง หากคุณคิดว่าไม่ถูกต้อง ให้ลองปรับตำแหน่งเสาอากาศแล้วสแกนอีกครั้ง</item>
+ <item quantity="one">เยี่ยมมาก! สแกนพบ %1$d ช่อง หากคุณคิดว่าไม่ถูกต้อง ให้ลองปรับตำแหน่งเสาอากาศแล้วสแกนอีกครั้ง</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"เสร็จสิ้น"</item>
+ <item msgid="2480490326672924828">"สแกนอีกครั้ง"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"ไม่พบช่อง"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"สแกนไม่พบช่องใดเลย โปรดตรวจสอบว่าทีวีของคุณเชื่อมต่อกับแหล่งสัญญาณทีวีแล้ว\n\nหากคุณใช้เสาอากาศแบบผ่านอากาศ ให้ปรับตำแหน่งและทิศทาง เพื่อผลลัพธ์ที่ดีที่สุด ให้วางไว้บนที่สูงใกล้หน้าต่างแล้วสแกนอีกครั้ง"</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"สแกนไม่พบช่องใดเลย โปรดตรวจสอบว่าได้เสียบปลั๊กตัวรับสัญญาณแบบ USB และเชื่อมต่อกับแหล่งสัญญาณทีวีแล้ว\n\nหากคุณใช้เสาอากาศแบบผ่านอากาศ ให้ปรับตำแหน่งหรือทิศทาง เพื่อให้ได้ผลลัพธ์ที่ดีที่สุด ให้วางไว้บนที่สูงใกล้หน้าต่างแล้วสแกนอีกครั้ง"</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"สแกนไม่พบช่องใดเลย โปรดตรวจสอบว่าตัวรับสัญญาณเครือข่ายเปิดอยู่และเชื่อมต่อกับแหล่งสัญญาณทีวีแล้ว\n\nหากใช้เสาอากาศแบบผ่านอากาศ (OTA) ให้ปรับตำแหน่งหรือทิศทาง เพื่อผลลัพธ์ที่ดีที่สุด ให้วางไว้บนที่สูงใกล้หน้าต่างแล้วสแกนอีกครั้ง"</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"สแกนอีกครั้ง"</item>
+ <item msgid="2092797862490235174">"เสร็จสิ้น"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"สแกนหาช่องทีวี"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"ตั้งค่าตัวรับสัญญาณทีวี"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"ตั้งค่าตัวรับสัญญาณทีวีแบบ USB"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"ตั้งค่าตัวรับสัญญาณทีวีเครือข่าย"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"ยกเลิกการเชื่อมต่อตัวรับสัญญาณทีวีผ่าน USB แล้ว"</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"ยกเลิกการเชื่อมต่อตัวรับสัญญาณเครือข่ายแล้ว"</string>
+</resources>
diff --git a/usbtuner-res/values-tl/strings.xml b/usbtuner-res/values-tl/strings.xml
new file mode 100644
index 00000000..52c99eac
--- /dev/null
+++ b/usbtuner-res/values-tl/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"TV Tuner"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB TV Tuner"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Network TV Tuner (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Mangyaring maghintay na matapos ang pagpoproseso"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Na-update kamakailan ang software ng tuner. Paki-scan muli ang mga channel."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"I-enable ang surround sound sa mga setting ng tunog ng system upang ma-enable ang audio"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Hindi ma-play ang audio. Mangyaring sumubok ng ibang TV"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Setup ng channel tuner"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Setup ng TV Tuner"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Setup ng USB channel tuner"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Pag-set up ng network tuner"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"I-verify na nakakonekta ang iyong TV sa isang TV signal source.\n\nKung gumagamit ng over-the-air antenna, maaaring kailanganin mong ayusin ang pagkakalagay o direksyon nito upang makuha ang pinakamaraming channel. Para sa mga pinakamainam na resulta, ilagay ito sa mataas na lugar at malapit sa isang bintana."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"I-verify na nakasaksak at nakakonekta ang USB tuner sa isang TV source signal.\n\nKung gumagamit ka ng isang over-the-air antenna, maaaring kailanganin mong ayusin ang pagkakalagay o direksyon nito upang makuha ang pinakamaraming channel. Para sa mga pinakamainam na resulta, ilagay ito sa isang mataas na lugar at malapit sa isang bintana."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"I-verify na naka-on ang network tuner at nakakonekta sa isang pinagmumulan ng TV signal.\n\nKung gumagamit ng over-the-air na antenna, maaaring kailanganin mong ayusin ang pagkakalagay o direksyon nito upang masagap ang karamihan ng mga channel. Para sa mga pinakamainam na resulta, ilagay ito sa mataas na lugar at malapit sa bintana."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Magpatuloy"</item>
+ <item msgid="727245208787621142">"Hindi ngayon"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Gusto mo bang muling patakbuhin ang pag-set up ng channel?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Aalisin nito ang mga nakitang channel mula sa TV tuner at mag-scan muli para sa mga bagong channel.\n\nI-verify na nakakonekta ang iyong TV sa isang TV signal source.\n\nKung gumagamit ka ng over-the-air antenna, maaaring kailanganin mong ayusin ang pagkakalagay o direksyon nito upang makuha ang pinakamaraming channel. Para sa mga pinakamainam na resulta, ilagay ito sa mataas na lugar at malapit sa isang bintana."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Aalisin nito ang mga channel na nahanap mula sa USB tuner at mag-scan muli para sa mga bagong channel.\n\nI-verify na nakasaksak at nakakonekta ang USB tuner sa isang TV source signal.\n\nKung gumagamit ng over-the-air antenna, maaaring kailanganin mong ayusin ang pagkakalagay o direksyon nito upang makuha ang pinakamaraming channel. Para sa mga pinakamainam na resulta, ilagay ito sa isang mataas na lugar at malapit sa isang bintana."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Aalisin nito ang mga nahanap na channel sa network tuner at muling magsa-scan ng mga bagong channel.\n\nI-verify na naka-on ang network tuner at nakakonekta sa isang pinagmumulan ng TV signal.\n\nKung gumagamit ng over-the-air na antenna, maaaring kailanganin mong ayusin ang pagkakalagay o direksyon nito upang masagap ang karamihan ng mga channel. Para sa mga pinakamainam na resulta, ilagay ito sa mataas na lugar at malapit sa bintana."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Magpatuloy"</item>
+ <item msgid="235450158666155406">"Kanselahin"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Piliin ang uri ng koneksyon"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Piliin ang Antenna kung may nakakonektang external na antenna sa tuner. Piliin ang Cable kung nanggagaling ang iyong mga channel sa isang service provider ng cable. Kung hindi ka sigurado, iii-scan ang parehong nabanggit na uri, ngunit maaaring mas magtagal ito."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antenna"</item>
+ <item msgid="2670079958754180142">"Cable"</item>
+ <item msgid="36774059871728525">"Hindi sigurado"</item>
+ <item msgid="6881204453182153978">"Development lang"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Setup ng TV tuner"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Setup ng USB channel tuner"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Pag-set up ng network channel tuner"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Maaari itong tumagal ng ilang minuto"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Pansamantalang hindi available ang Tuner o ginagamit na ito ng recording."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="one">Nakahanap ng %1$d channel</item>
+ <item quantity="other">Nakahanap ng %1$d na channel</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"IHINTO ANG PAG-SCAN NG CHANNEL"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="one">Nakahanap ng %1$d channel</item>
+ <item quantity="other">Nakahanap ng %1$d na channel</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="one">Ayos! Nakahanap ng %1$d channel noong nag-ii-scan ng channel. Kung sa palagay mo ay kulang pa ito, subukang ayusin ang posisyon ng antenna at muling mag-scan.</item>
+ <item quantity="other">Ayos! Nakahanap ng %1$d na channel noong nag-ii-scan ng channel. Kung sa palagay mo ay kulang pa ito, subukang ayusin ang posisyon ng antenna at muling mag-scan.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Tapos Na"</item>
+ <item msgid="2480490326672924828">"Muling mag-scan"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Walang nakitang Mga Channel"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Hindi nakahanap ng anumang mga channel ang pag-scan. I-verify na nakakonekta ang iyong TV sa isang TV signal source.\n\nKung gumagamit ka ng over-the-air antenna, ayusin ang pagkakalagay o direksyon nito. Para sa mga pinakamainam na resulta, ilagay ito sa mataas na lugar malapit sa isang bintana at mag-scan muli."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Walang nahanap na anumang mga channel noong nag-scan. I-verify na nakasaksak at nakakonekta ang USB tuner sa isang TV signal source.\n\nKung gumagamit ka ng over-the-air antenna, ayusin ang pagkakalagay o direksyon nito. Para sa mga pinakamainam na resulta, ilagay ito sa isang mataas na lugar at malapit sa isang bintana mag-scan muli."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Walang nahanap na channel sa pag-scan. I-verify na naka-on ang network tuner at nakakonekta sa isang pinagmumulan ng TV signal.\n\nKung gumagamit ng over-the-air na antenna, ayusin ang pagkakalagay o direksyon nito. Para sa mga pinakamainam na resulta, ilagay ito sa mataas na lugar at malapit sa bintana at muling mag-scan."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Muling mag-scan"</item>
+ <item msgid="2092797862490235174">"Tapos Na"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Mag-scan ng mga channel sa TV"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Setup ng TV Tuner"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Setup ng USB TV Tuner"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Setup ng Network TV Tuner"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"Nadiskonekta ang USB TV tuner."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Nadiskonekta ang network tuner."</string>
+</resources>
diff --git a/usbtuner-res/values-tr/strings.xml b/usbtuner-res/values-tr/strings.xml
new file mode 100644
index 00000000..5196bfa3
--- /dev/null
+++ b/usbtuner-res/values-tr/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"TV Kanal Ayarlayıcı"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB TV Kanal Ayarlayıcı"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Ağ TV Kanal Ayarlayıcı (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Lütfen işlemin tamamlanmasını bekleyin"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Kanal ayarlayıcı yazılımı yakın zamanda güncellendi. Lütfen kanalları yeniden tarayın."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Sesi etkinleştirmek için sistemin ses ayarlarında surround sesi etkinleştirin"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Ses çalınamıyor. Lütfen başka bir TV deneyin"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Kanal ayarlayıcı kurulumu"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"TV Kanal Ayarlayıcı kurulumu"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB kanal ayarlayıcı kurulumu"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Ağ kanal ayarlayıcı kurulumu"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"TV\'nizin bir TV sinyal kaynağına bağlı olduğunu doğrulayın.\n\nHavadan yayın alan bir anten kullanıyorsanız en çok sayıda kanalı almak için antenin yerini veya yönünü ayarlamanız gerekebilir. En iyi sonucu elde etmek için anteni yüksek ve pencereye yakın bir yere yerleştirin."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"USB kanal ayarlayıcının takılı olduğunu ve bir TV sinyali kaynağına bağlandığını doğrulayın.\n\nHavadan yayın alan bir anten kullanıyorsanız en çok sayıda kanalı almak için antenin yerini veya yönünü ayarlamanız gerekebilir. En iyi sonucu elde etmek için anteni yüksek ve pencereye yakın bir yere yerleştirin."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Ağ kanal ayarlayıcının açık olduğunu ve TV sinyali alabileceği bir kaynağa bağlandığını doğrulayın.\n\nHavadan gelen yayını alacak bir anten kullanıyorsanız en fazla sayıda kanalı almak için antenin yerini veya yönünü ayarlamanız gerekebilir. En iyi sonuçları elde etmek için anteni yüksek ve pencereye yakın bir yere yerleştirin."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Devam"</item>
+ <item msgid="727245208787621142">"Şimdi değil"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Kanal kurulumu yeniden çalıştırılsın mı?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Bu işlem, TV kanal ayarlayıcının bulduğu kanalları kaldıracak ve tekrar yeni kanallar arayacak.\n\nTV\'nizin bir TV sinyal kaynağına bağlı olduğunu doğrulayın.\n\nHavadan yayın alan bir anten kullanıyorsanız en çok sayıda kanalı almak için antenin yerini veya yönünü ayarlamanız gerekebilir. En iyi sonucu elde etmek için anteni yüksek ve pencereye yakın bir yere yerleştirin."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Bu işlem, USB kanal ayarlayıcıdan bulunan kanalları kaldıracak ve yeni kanallar için tekrar tarama yapacaktır.\n\nUSB kanal ayarlayıcının takılı olduğunu ve bir TV sinyali kaynağına bağlandığını doğrulayın.\n\nHavadan yayın alan bir anten kullanıyorsanız en çok sayıda kanalı almak için antenin yerini veya yönünü ayarlamanız gerekebilir. En iyi sonucu elde etmek için anteni yüksek ve pencereye yakın bir yere yerleştirin."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Bu işlem, bulunan kanalları ağ kanal ayarlayıcıdan kaldıracak ve yeni kanalların bulunması için tekrar tarama yapacak.\n\nAğ kanal ayarlayıcının açık olduğunu ve TV sinyali alabileceği bir kaynağa bağlandığını doğrulayın.\n\nHavadan gelen yayını alacak bir anten kullanıyorsanız en fazla sayıda kanalı almak için antenin yerini veya yönünü ayarlamanız gerekebilir. En iyi sonucu elde etmek için anteni yüksek ve pencereye yakın bir yere yerleştirin."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Devam"</item>
+ <item msgid="235450158666155406">"İptal"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Bağlantı türünü seçin"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Kanal ayarlayıcıya bağlı harici bir anteniniz varsa Anten\'i seçin. Kanallarınız bir kablolu yayın hizmeti sağlayıcısından geliyorsa Kablolu\'yu seçin. Emin değilseniz her iki tür de taranacaktır, ancak işlem daha uzun sürebilir."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Anten"</item>
+ <item msgid="2670079958754180142">"Kablolu"</item>
+ <item msgid="36774059871728525">"Emin değilim"</item>
+ <item msgid="6881204453182153978">"Yalnızca geliştirme"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"TV kanal ayarlayıcı kurulumu"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB kanal ayarlayıcı kurulumu"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Ağ kanal ayarlayıcı kurulumu"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Bu işlem birkaç dakika sürebilir"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Kanal ayarlayıcı geçici olarak kullanılamıyor veya şu anda kayıt yapmak için kullanılıyor."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">%1$d kanal bulundu</item>
+ <item quantity="one">%1$d kanal bulundu</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"KANAL TARAMASINI DURDUR"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">%1$d kanal bulundu</item>
+ <item quantity="one">%1$d kanal bulundu</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Başarılı! Kanal tarama sırasında %1$d kanal bulundu. Bu sonuç doğru görünmüyorsa antenin konumunu ayarlayıp tekrar taramayı deneyin.</item>
+ <item quantity="one">Başarılı! Kanal tarama sırasında %1$d kanal bulundu. Bu sonuç doğru görünmüyorsa antenin konumunu ayarlayıp tekrar taramayı deneyin.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Bitti"</item>
+ <item msgid="2480490326672924828">"Yeniden tara"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Hiçbir kanal bulunamadı"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Tarama işleminde hiçbir kanal bulunamadı. TV\'nizin bir TV sinyal kaynağına bağlı olduğunu doğrulayın.\n\nHavadan yayın alan bir anten kullanıyorsanız yerini veya yönünü ayarlayın. En iyi sonucu elde etmek için anteni yüksek ve pencereye yakın bir yere yerleştirerek tekrar tarayın."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Tarama işlemi herhangi bir kanal bulamadı. USB kanal ayarlayıcının takılı olduğunu ve bir TV sinyali kaynağına bağlandığını doğrulayın.\n\nHavadan yayın alan bir anten kullanıyorsanız yerini veya yönünü ayarlayın. En iyi sonucu elde etmek için anteni yüksek ve pencereye yakın bir yere yerleştirerek tekrar tarayın."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Taramada herhangi bir kanal bulunamadı. Ağ kanal ayarlayıcının açık olduğunu ve TV sinyali alabileceği bir kaynağa bağlandığını doğrulayın.\n\nHavadan gelen yayınları alacak bir anten kullanıyorsanız antenin yerini veya yönünü ayarlayın. En iyi sonucu elde etmek için anteni yüksek ve pencereye yakın bir yere yerleştirin."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Yeniden tara"</item>
+ <item msgid="2092797862490235174">"Bitti"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"TV kanallarını tarayın"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"TV Kanal Ayarlayıcı kurulumu"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB TV Kanal Ayarlayıcı kurulumu"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Ağ TV Kanal Ayarlayıcı kurulumu"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB TV kanal ayarlayıcı bağlantısı kesildi."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Ağ kanal ayarlayıcı bağlantısı kesildi."</string>
+</resources>
diff --git a/usbtuner-res/values-uk/strings.xml b/usbtuner-res/values-uk/strings.xml
new file mode 100644
index 00000000..50c84efc
--- /dev/null
+++ b/usbtuner-res/values-uk/strings.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"ТВ-тюнер"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"ТВ-тюнер USB"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Мережевий ТВ-тюнер (БЕТА-ВЕРСІЯ)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Зачекайте, доки завершиться пошук"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Програмне забезпечення тюнера нещодавно оновлено. Проскануйте канали знову."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Увімкнути об’ємний звук у налаштуваннях системи, щоб слухати аудіо"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Не вдається відтворити відео. Спробуйте на іншому телевізорі"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Налаштування тюнера"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Налаштування ТВ-тюнера"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Налаштування USB-тюнера"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Налаштування мережевого тюнера"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Переконайтеся, що ви під’єднали телевізор до джерела вхідного телевізійного сигналу.\n\nЯкщо ви користуєтесь ефірною антеною, змініть її положення,щоб знайти більше каналів. Розмістіть антену вище та біля вікна."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Переконайтеся, що ви підключили USB-тюнер і під’єднали джерело вхідного телевізійного сигналу.\n\nЯкщо ви користуєтесь ефірною антеною, змініть її положення, щоб знайти більше каналів. Розмістіть антену вище та біля вікна."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Переконайтеся, що мережевий тюнер увімкнено та під’єднано до джерела телевізійного сигналу.\n\nЯкщо у вас ефірна антена, змініть її положення. Розмістіть антену вище та біля вікна й повторіть спробу."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Продовжити"</item>
+ <item msgid="727245208787621142">"Не зараз"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Відновити налаштування каналу?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Канали, знайдені за допомогою ТВ-тюнера, буде видалено. Пошук почнеться знову.\n\nПереконайтеся, що ви під’єднали телевізор до джерела вхідного телевізійного сигналу.\n\nЯкщо ви користуєтесь ефірною антеною, змініть її положення, щоб знайти більше каналів. Розмістіть антену вище та біля вікна й повторіть спробу."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Канали, знайдені за допомогою USB-тюнера, буде видалено. Пошук почнеться знову.\n\nПереконайтеся, що ви підключили USB-тюнер і під’єднали джерело вхідного телевізійного сигналу.\n\nЯкщо ви користуєтесь ефірною антеною, змініть її положення, щоб знайти більше каналів. Розмістіть антену вище та біля вікна."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Канали, знайдені мережевим тюнером, буде видалено. Пошук почнеться знову.\n\nПереконайтеся, що мережевий тюнер увімкнено та під’єднано до джерела телевізійного сигналу.\n\nЯкщо у вас ефірна антена, змініть її положення. Розмістіть антену вище та біля вікна й повторіть спробу."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Продовжити"</item>
+ <item msgid="235450158666155406">"Скасувати"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Вибір типу з’єднання"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Виберіть \"Антена\", якщо до тюнера під’єднано зовнішню антену. Виберіть \"Кабель\", якщо у вас кабельне телебачення. Якщо вибрати \"Не знаю\", тюнер шукатиме обидва типи сигналу, але це займе більше часу."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Антена"</item>
+ <item msgid="2670079958754180142">"Кабель"</item>
+ <item msgid="36774059871728525">"Не знаю"</item>
+ <item msgid="6881204453182153978">"Лише для розробки"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Налаштування ТВ-тюнера"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Налаштування USB-тюнера"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Налаштування мережевого тюнера"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Це може зайняти декілька хвилин"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Тюнер тимчасово недоступний або вже використовується для запису."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="one">Знайдено %1$d канал</item>
+ <item quantity="few">Знайдено %1$d канали</item>
+ <item quantity="many">Знайдено %1$d каналів</item>
+ <item quantity="other">Знайдено %1$d каналу</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"ПРИПИНИТИ ПОШУК КАНАЛІВ"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="one">Знайдено %1$d канал</item>
+ <item quantity="few">Знайдено %1$d канали</item>
+ <item quantity="many">Знайдено %1$d каналів</item>
+ <item quantity="other">Знайдено %1$d каналу</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="one"> Під час сканування знайдено %1$d канал. Якщо має бути більше каналів, змініть положення антени та повторіть спробу.</item>
+ <item quantity="few"> Під час сканування знайдено %1$d канали. Якщо має бути більше каналів, змініть положення антени та повторіть спробу.</item>
+ <item quantity="many"> Під час сканування знайдено %1$d каналів. Якщо має бути більше каналів, змініть положення антени та повторіть спробу.</item>
+ <item quantity="other"> Під час сканування знайдено %1$d каналу. Якщо має бути більше каналів, змініть положення антени та повторіть спробу.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Готово"</item>
+ <item msgid="2480490326672924828">"Шукати знову"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Канали не знайдено"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Канали не знайдено. Переконайтеся, що ви під’єднали телевізор до джерела вхідного телевізійного сигналу.\n\nЯкщо ви користуєтесь ефірною антеною, змініть її положення. Розмістіть антену вище та біля вікна й повторіть спробу."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Канали не знайдено. Переконайтеся, що ви підключили USB-тюнер і під’єднали джерело вхідного телевізійного сигналу.\n\nЯкщо ви користуєтесь ефірною антеною, змініть її положення. Розмістіть антену вище та біля вікна й повторіть спробу."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Каналів не знайдено. Переконайтеся, що мережевий тюнер увімкнено та під’єднано до джерела телевізійного сигналу.\n\nЯкщо у вас ефірна антена, змініть її положення. Розмістіть антену вище та біля вікна й повторіть спробу."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Шукати знову"</item>
+ <item msgid="2092797862490235174">"Готово"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Пошук телевізійних каналів"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Налаштування ТВ-тюнера"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Налаштування ТВ-тюнера USB"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Налаштування мережевого ТВ-тюнера"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"ТВ-тюнер USB від’єднано."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Мережевий тюнер від’єднано."</string>
+</resources>
diff --git a/usbtuner-res/values-ur-rPK/strings.xml b/usbtuner-res/values-ur-rPK/strings.xml
new file mode 100644
index 00000000..49dc9e34
--- /dev/null
+++ b/usbtuner-res/values-ur-rPK/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"‏TV ٹیونر"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"‏USB TV ٹیونر"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"‏نیٹ ورک TV ٹیونر (بی ٹا)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"براہ کرم کارروائی ختم ہونے کا انتظار کریں"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"ٹیونر سافٹ ویئر حال ہی میں اپ ڈیٹ کیا گیا ہے۔ براہ کرم چینلز کو دوبارہ اسکین کریں۔"</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"آڈیو کو فعال کرنے کیلئے سسٹم کی آواز کی ترتیبات میں محیط آواز فعال کریں"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"آڈیو نہیں چل رہی۔ براہ کرم کوئی اور ٹی وی آزمائیں"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"چینل ٹیونر سیٹ اپ"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"‏TV ٹیونر سیٹ اپ"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"‏USB چینل ٹیونر سیٹ اپ"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"نیٹ ورک ٹیونر سیٹ اپ"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"‏اپنے TV کے کسی TV سگنل ماخذ سے منسلک ہونے کی توثیق کریں۔\n\nاگر وائرلیس نیٹ ورک کنکشن انٹینا استعمال کر رہے ہیں تو زیادہ تر چینلز موصول کرنے کیلئے آپ کو اس کا مقام یا سمت ایڈجسٹ کرنے کی ضرورت پیش آ سکتی ہے۔ بہترین نتائج کیلئے اسے اونچی جگہ اور کھڑکی کے پاس رکھیں۔"</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"‏USB ٹیونر کے پلگ ان ہونے اور TV سگنل ماخذ سے منسلک ہونے کی توثیق کریں۔\n\nاگر وائرلیس نیٹ ورک کنکشن انٹینا استعمال کر رہے ہیں تو زیادہ تر چینلز موصول کرنے کیلئے آپ کو اس کا مقام یا سمت ایڈجسٹ کرنے کی ضرورت پیش آ سکتی ہے۔ بہترین نتائج کیلئے اسے اونچی جگہ اور کھڑکی کے پاس رکھیں۔"</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"‏نیٹ ورک ٹیونر کے آن ہونے اور TV سگنل ماخذ سے منسلک ہونے کی توثیق کریں۔\n\nاگر وائرلیس نیٹ ورک کنکشن انٹینا استعمال کر رہے ہیں تو زیادہ تر چینلز موصول کرنے کیلئے آپ کو اس کا مقام یا سمت ایڈجسٹ کرنے کی ضرورت پیش آ سکتی ہے۔ بہترین نتائج کیلئے اسے اونچی جگہ اور کھڑکی کے پاس رکھیں۔"</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"جاری رکھیں"</item>
+ <item msgid="727245208787621142">"ابھی نہیں"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"چینل سیٹ اپ دوبارہ چلائیں؟"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"‏یہ TV ٹیونر سے ملے چینلز ہٹا دے گا اور دوبارہ نئے چینلز کیلئے اسکین کرے گا۔\n\nاپنے TV کے کسی سگنل ماخذ سے منسلک ہونے کی توثیق کریں۔\n\nاگر وائرلیس نیٹ ورک کنکشن انٹینا استعمال کر رہے ہیں تو زیادہ تر چینلز موصول کرنے کیلئے آپ کو اس کا مقام یا سمت ایڈجسٹ کرنے کی ضرورت پیش آ سکتی ہے۔ بہترین نتائج کیلئے اسے اونچی جگہ اور کھڑکی کے پاس رکھیں۔"</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"‏یہ USB ٹیونر سے ملے چینلز ہٹا دے گا اور دوبارہ نئے چینلز کیلئے اسکین کرے گا۔\n\nTV ٹیونر کے پلگ ان ہونے اور سگنل ماخذ سے منسلک ہونے کی توثیق کریں۔\n\nاگر وائرلیس نیٹ ورک کنکشن انٹینا استعمال کر رہے ہیں تو زیادہ تر چینلز موصول کرنے کیلئے آپ کو اس کا مقام یا سمت ایڈجسٹ کرنے کی ضرورت پیش آ سکتی ہے۔ بہترین نتائج کیلئے اسے اونچی جگہ اور کھڑکی کے پاس رکھیں۔"</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"‏یہ نیٹ ورک ٹیونر سے ملنے والے چیلنز ہٹا دے گا اور دوبارہ نئے چینلز کیلئے اسکین کرے گا۔\n\nTV ٹیونر کے آن ہونے اور سگنل ماخذ سے منسلک ہونے کی توثیق کریں۔\n\nاگر وائرلیس نیٹ ورک کنکشن انٹینا استعمال کر رہے ہیں، تو زیادہ تر چینلز موصول کرنے کیلئے آپ کو اس کی مقام بندی یا سمت ایڈجسٹ کرنے کی ضرورت پیش آ سکتی ہے۔ بہترین نتائج کیلئے اسے اونچی جگہ اور کھڑکی کے پاس رکھیں۔"</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"جاری رکھیں"</item>
+ <item msgid="235450158666155406">"منسوخ کریں"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"کنکشن کی قسم منتخب کریں"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"اگر ٹیونر سے کوئی بیرونی انٹینا منسلک ہے تو انٹینا کا انتخاب کریں۔ اگر آپ کے چینلز کسی کیبل سروس فراہم کنندہ کی طرف سے موصول ہوتے ہیں تو کیبل کا انتخاب کریں۔ اگر آپ پُر یقین نہیں ہیں تو دونوں اقسام کو اسکین کیا جائے گا، مگر اس میں زیادہ وقت لگ سکتا ہے۔"</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"انٹینا"</item>
+ <item msgid="2670079958754180142">"کیبل"</item>
+ <item msgid="36774059871728525">"یقین نہیں ہے"</item>
+ <item msgid="6881204453182153978">"صرف ڈیولپمنٹ"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"‏TV ٹیونر سیٹ اپ"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"‏USB چینل ٹیونر سیٹ اپ"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"نیٹ ورک چینل ٹیونر سیٹ اپ"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"اس میں کئی منٹ لگ سکتے ہیں"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"ٹیونر عارضی طور پر غیر دستیاب ہے یا پہلے سے ریکارڈنگ کی وجہ سے استعمال ہو گیا ہے۔"</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">‏%1$d چینلز ملے</item>
+ <item quantity="one">‏%1$d چینل ملا</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"چینل اسکین روکیں"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">‏‎%1$d چینلز ملے</item>
+ <item quantity="one">‏%1$d چینل ملا</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">‏خوب! چینل اسکین کے دوران ‎%1$d چینلز ملے۔ اگر یہ ٹھیک نہیں لگ رہا تو انٹینا کی پوزیشن ایڈجسٹ کرنے کی کوشش کریں اور دوبارہ اسکین کریں۔</item>
+ <item quantity="one">‏خوب! چینل اسکین کے دوران ‎%1$d چینل ملا۔ اگر یہ ٹھیک نہیں لگ رہا تو انٹینا کی پوزیشن ایڈجسٹ کرنے کی کوشش کریں اور دوبارہ اسکین کریں۔</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"ہو گیا"</item>
+ <item msgid="2480490326672924828">"دوبارہ اسکین کریں"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"کوئی چینلز نہیں ملے"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"‏اسکین سے کوئی چینلز نہیں ملے۔ اپنے TV کے ایک TV سگنل ماخذ سے منسلک ہونے کی توثیق کریں۔\n\nاگر وائرلیس نیٹ ورک کنکشن انٹینا استعمال کر رہے ہیں تو اس کا مقام یا سمت ایڈجسٹ کریں۔ بہترین نتائج کیلئے اسے اونچی جگہ اور کھڑکی کے پاس رکھیں اور دوبارہ اسکین کریں۔"</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"‏اسکین سے کوئی چینلز نہیں ملے۔ USB ٹیونر کے پلگ ان ہونے اور TV سگنل ماخذ سے منسلک ہونے کی توثیق کریں۔\n\nاگر وائرلیس نیٹ ورک کنکشن انٹینا استعمال کر رہے ہیں تو اس کا مقام یا سمت ایڈجسٹ کریں۔ بہترین نتائج کیلئے اسے اونچی جگہ اور کھڑکی کے پاس رکھیں اور دوبارہ اسکین کریں۔"</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"‏اسکین سے کوئی چینلز نہیں ملے۔ توثیق کریں کہ نیٹ ورک ٹیونر آن ہے اور TV سگنل ماخذ سے منسلک ہے۔\n\nاگر وائرلیس نیٹ ورک کنکشن انٹینا استعمال کر رہے ہیں، تو اس کا مقام یا سمت ایڈجسٹ کریں۔ بہترین نتائج کیلئے، اسے اونچی جگہ اور کھڑکی کے قریب رکھیں اور دوبارہ اسکین کریں۔"</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"دوبارہ اسکین کریں"</item>
+ <item msgid="2092797862490235174">"ہو گیا"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"‏TV چینلز کے لیے اسکین کریں"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"‏TV ٹیونر سیٹ اپ"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"‏USB TV ٹیونر سیٹ اپ"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"‏نیٹ ورک TV ٹیونر سیٹ اپ"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"‏USB TV ٹیونر غیر منسلک ہے۔"</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"نیٹ ورک ٹیونر غیر منسلک ہے۔"</string>
+</resources>
diff --git a/usbtuner-res/values-uz-rUZ/strings.xml b/usbtuner-res/values-uz-rUZ/strings.xml
new file mode 100644
index 00000000..2709dec0
--- /dev/null
+++ b/usbtuner-res/values-uz-rUZ/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"TV-tyuner"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB TV-tyuner"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Tarmoq TV-tyuneri (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Iltimos, jarayon tugashini kuting"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Tyunerning dasturiy ta’minoti yaqinda yangilandi. Kanallarni qaytadan qidiring."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Audioni yoqish uchun tizim ovozi sozlamalari orqali qamrovli ovozni yoqing"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Audioni ijro ettirib bo‘lmadi. Boshqa kanalni sinab ko‘ring."</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Tyunerni sozlash"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"TV-tyunerni sozlash"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB-tyunerni sozlash"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Tarmoq tyunerini sozlash"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Televizor signali manbasiga ulangan ekanligini tekshiring.\n\nAgar havo orqali to‘lqin tutuvchi antennadan foydalanayotgan bo‘lsangiz, ko‘proq kanal topilishi uchun uning joyi va yo‘nalishini sozlang. Eng yaxshi natijaga erishish uchun uni yuqoriroq va oynaga yaqin joyga o‘rnating."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"USB-tyuner suqilgan hamda televizor signali manbasiga ulangan ekanligini tekshiring.\n\nAgar havo orqali to‘lqin tutuvchi antennadan foydalanayotgan bo‘lsangiz, ko‘proq kanal topilishi uchun uning joyi va yo‘nalishini sozlang. Eng yaxshi natijaga erishish uchun uni yuqoriroq va oynaga yaqin joyga o‘rnating."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Tarmoq tyuneri yoqilgan hamda televizor signali manbasiga ulangan ekanligini tekshiring.\n\nAgar havo orqali to‘lqin tutuvchi antennadan foydalanayotgan bo‘lsangiz, ko‘proq kanal topilishi uchun uning joyi va yo‘nalishini sozlang. Eng yaxshi natijaga erishish uchun uni yuqoriroq va oynaga yaqin joyga o‘rnating."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Davom etish"</item>
+ <item msgid="727245208787621142">"Hozir emas"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Kanallar qaytadan sozlansinmi?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Buning natijasida TV-tyuner orqali topilgan kanallar o‘chirib tashlanadi va kanallar boshqatdan qidiriladi.\n\nTelevizor signal manbasiga ulangan ekanligini tekshiring.\n\nAgar havo orqali to‘lqin tutuvchi antennadan foydalanayotgan bo‘lsangiz, uning joyi va yo‘nalishini sozlang. Eng yaxshi natijaga erishish uchun uni yuqoriroq va oynaga yaqin joyga o‘rnating hamda qaytadan qidiring."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Buning natijasida USB-tyuner orqali topilgan kanallar o‘chirib tashlanadi va kanallar boshqatdan qidiriladi.\n\nUSB-tyuner suqilgan hamda televizor signali manbasiga ulangan ekanligini tekshiring.\n\nAgar havo orqali to‘lqin tutuvchi antennadan foydalanayotgan bo‘lsangiz, uning joyi va yo‘nalishini sozlang. Eng yaxshi natijaga erishish uchun uni yuqoriroq va oynaga yaqin joyga o‘rnating hamda qaytadan qidiring."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Buning natijasida tarmoq tyuneri orqali topilgan kanallar o‘chirib tashlanadi va kanallar boshqatdan qidiriladi.\n\nTarmoq tyuneri yoqilgan hamda televizor signali manbasiga ulangan ekanligini tekshiring.\n\nAgar havo orqali to‘lqin tutuvchi antennadan foydalanayotgan bo‘lsangiz, uning joyi va yo‘nalishini sozlang. Eng yaxshi natijaga erishish uchun uni yuqoriroq va oynaga yaqin joyga o‘rnating hamda qaytadan qidiring."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Davom etish"</item>
+ <item msgid="235450158666155406">"Bekor qilish"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Aloqa turini tanlang"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Agar tyunerga tashqi antenna ulangan bo‘lsa, “Antenna” variantini tanlang. Agar kanallar kabel televideniye ta’minotchisidan olinadigan bo‘lsa, “Kabel TV” variantini tanlang. Agar qaysi biri ekanligini aniq bilmasangiz, har ikkala tur ham qidiriladi, shuning uchun uzoqroq vaqt ketishi mumkin."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Antenna"</item>
+ <item msgid="2670079958754180142">"Kabel"</item>
+ <item msgid="36774059871728525">"Aniq bilmayman"</item>
+ <item msgid="6881204453182153978">"Faqat dasturchilar uchun"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"TV-tyunerni sozlash"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB-tyunerni sozlash"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Tarmoq tyuneri kanallarini sozlash"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Bu bir necha daqiqa vaqt olishi mumkin"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Tyunerdan vaqtinchalik foydalanib bo‘lmaydi yoki allaqachon yozib olishda foydalanilmoqda."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">%1$d ta kanal topildi</item>
+ <item quantity="one">%1$d ta kanal topildi</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"KANAL QIDIRUVINI TO‘XTATISH"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">%1$d ta kanal topildi</item>
+ <item quantity="one">%1$d ta kanal topildi</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Ajoyib! Kanal qidirish natijasida %1$d ta kanal topildi. Agar yanada ko‘proq kanal topilishi kerak deb hisoblasangiz, antenna joylashuvini sozlang va qaytadan qidiring.</item>
+ <item quantity="one">Ajoyib! Kanal qidirish natijasida %1$d ta kanal topildi. Agar yanada ko‘proq kanal topilishi kerak deb hisoblasangiz, antenna joylashuvini sozlang va qaytadan qidiring.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Tayyor"</item>
+ <item msgid="2480490326672924828">"Yana qidirish"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Hech qanday kanal topilmadi"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Qidiruv natijasida hech qanday kanal topilmadi. Televizor signal manbasiga ulangan ekanligini tekshiring.\n\nAgar havo orqali to‘lqin tutuvchi antennadan foydalanayotgan bo‘lsangiz, uning joyi va yo‘nalishini sozlang. Eng yaxshi natijaga erishish uchun uni yuqoriroq va oynaga yaqin joyga o‘rnating hamda qaytadan qidiring."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Qidiruv natijasida hech qanday kanal topilmadi. USB-tyuner suqilgan hamda televizor signali manbasiga ulangan ekanligini tekshiring.\n\nAgar havo orqali to‘lqin tutuvchi antennadan foydalanayotgan bo‘lsangiz, uning joyi va yo‘nalishini sozlang. Eng yaxshi natijaga erishish uchun uni yuqoriroq va oynaga yaqin joyga o‘rnating hamda qaytadan qidiring."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Qidiruv natijasida hech qanday kanal topilmadi. Tarmoq tyuneri yoqilgan hamda televizor signali manbasiga ulangan ekanligini tekshiring.\n\nAgar havo orqali to‘lqin tutuvchi antennadan foydalanayotgan bo‘lsangiz, uning joyi va yo‘nalishini sozlang. Eng yaxshi natijaga erishish uchun uni yuqoriroq va oynaga yaqin joyga o‘rnating hamda qaytadan qidiring."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Yana qidirish"</item>
+ <item msgid="2092797862490235174">"Tayyor"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Telekanallarni qidiring"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"TV-tyunerni sozlash"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB TV-tyunerni sozlang"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Tarmoq TV-tyunerini sozlash"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB-tyuner o‘chirib qo‘yildi."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Tarmoq tyuneri uzib qo‘yildi."</string>
+</resources>
diff --git a/usbtuner-res/values-vi/strings.xml b/usbtuner-res/values-vi/strings.xml
new file mode 100644
index 00000000..6e6cef72
--- /dev/null
+++ b/usbtuner-res/values-vi/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Bộ dò TV"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"Bộ dò TV USB"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Bộ dò TV mạng (BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Vui lòng đợi để hoàn tất xử lý"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Phần mềm bộ dò đã được cập nhật gần đây. Vui lòng quét lại các kênh."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Bật tính năng âm thanh vòm trong cài đặt âm thanh hệ thống để bật âm thanh"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Không thể phát âm thanh. Vui lòng thử TV khác"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Thiết lập bộ dò kênh"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Thiết lập bộ dò TV"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Thiết lập bộ dò kênh USB"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Thiết lập bộ dò mạng"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Hãy xác minh rằng TV của bạn đã được kết nối với nguồn tín hiệu TV.\n\nNếu sử dụng ăng-ten không dây thì bạn có thể cần phải điều chỉnh vị trí hoặc hướng của ăng-ten đó để nhận nhiều kênh nhất. Để có kết quả tốt nhất, hãy đặt ăng-ten lên cao và gần cửa sổ."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Xác minh rằng bộ dò USB đã được cắm và được kết nối với nguồn tín hiệu TV.\n\nNếu sử dụng ăng-ten không dây, có thể bạn cần phải điều chỉnh vị trí hoặc hướng của ăng-ten đó để nhận được nhiều kênh nhất. Để có kết quả tốt nhất, hãy đặt ăng-ten lên cao và gần cửa sổ."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Hãy xác minh là bộ dò mạng đã được bật nguồn và kết nối với một nguồn tín hiệu TV.\n\nNếu sử dụng ăng-ten không dây, hãy điều chỉnh vị trí hoặc hướng của ăng-ten để nhận hầu hết kênh. Để có kết quả tốt nhất, hãy đặt ăng-ten ở vị trí cao và gần cửa sổ."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Tiếp tục"</item>
+ <item msgid="727245208787621142">"Không phải bây giờ"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Chạy lại quá trình thiết lập kênh?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Điều này sẽ xóa các kênh được tìm thấy khỏi bộ dò TV và quét các kênh mới lần nữa.\n\nHãy xác minh rằng TV của bạn đã được kết nối với nguồn tín hiệu TV.\n\nNếu sử dụng ăng-ten không dây thì bạn có thể cần phải điều chỉnh vị trí hoặc hướng của ăng-ten đó để nhận nhiều kênh nhất. Để có kết quả tốt nhất, hãy đặt ăng-ten lên cao và gần cửa sổ."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Quá trình này sẽ xóa các kênh bộ dò USB đã tìm thấy và quét lại để tìm các kênh mới.\n\nHãy xác minh rằng bộ dò USB đã được cắm và kết nối với nguồn tín hiệu TV.\n\nNếu sử dụng ăng-ten không dây, bạn có thể cần phải điều chỉnh vị trí hoặc hướng của ăng-ten đó để nhận được nhiều kênh nhất. Để có kết quả tốt nhất, hãy đặt ăng-ten lên cao và gần cửa sổ."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Điều này sẽ xóa các kênh được tìm thấy từ bộ dò mạng và quét các kênh mới một lần nữa.\n\nHãy xác minh là bộ dò mạng đã được bật nguồn và kết nối với một nguồn tín hiệu TV.\n\nNếu sử dụng ăng-ten không dây, hãy điều chỉnh vị trí hoặc hướng của ăng-ten để nhận hầu hết kênh. Để có kết quả tốt nhất, hãy đặt ăng-ten ở vị trí cao và gần cửa sổ."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Tiếp tục"</item>
+ <item msgid="235450158666155406">"Hủy"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Chọn loại kết nối"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Chọn Ăng-ten nếu có ăng-ten bên ngoài được kết nối với bộ dò. Chọn Cáp nếu kênh của bạn đến từ nhà cung cấp dịch vụ cáp. Nếu bạn không chắc chắn thì cả hai loại sẽ đều được quét. Tuy nhiên, quá trình này có thể mất nhiều thời gian hơn."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"Ăng-ten"</item>
+ <item msgid="2670079958754180142">"Cáp"</item>
+ <item msgid="36774059871728525">"Không chắc chắn"</item>
+ <item msgid="6881204453182153978">"Chỉ phát triển"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Thiết lập bộ dò TV"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Thiết lập bộ dò kênh USB"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Thiết lập bộ do kênh mạng"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Quá trình này có thể mất vài phút"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Bộ dò tạm thời không có sẵn hoặc đã được sử dụng để ghi."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">Đã tìm thấy %1$d kênh</item>
+ <item quantity="one">Đã tìm thấy %1$d kênh</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"NGỪNG QUÉT KÊNH"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">Đã tìm thấy %1$d kênh</item>
+ <item quantity="one">Đã tìm thấy %1$d kênh</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">Tuyệt! Đã tìm thấy %1$d kênh trong quá trình quét kênh. Nếu điều này có vẻ không ổn, hãy thử điều chỉnh vị trí ăng-ten và quét lại.</item>
+ <item quantity="one">Tuyệt! Đã tìm thấy %1$d kênh trong quá trình quét kênh. Nếu điều này có vẻ không ổn, hãy thử điều chỉnh vị trí ăng-ten và quét lại.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Xong"</item>
+ <item msgid="2480490326672924828">"Quét lại"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Không tìm thấy kênh nào"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Quá trình quét không tìm thấy bất kỳ kênh nào. Hãy xác minh rằng TV của bạn đã được kết nối với nguồn tín hiệu TV.\n\nNếu sử dụng ăng-ten không dây, hãy điều chỉnh vị trí hoặc hướng của ăng-ten đó. Để có kết quả tốt nhất, hãy đặt ăng-ten lên cao và gần cửa sổ rồi quét lại."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Quá trình quét không tìm thấy bất kỳ kênh nào. Hãy xác minh rằng bộ dò USB đã được cắm và kết nối với nguồn tín hiệu TV.\n\nNếu sử dụng ăng-ten không dây, hãy điều chỉnh vị trí hoặc hướng của ăng-ten đó. Để có kết quả tốt nhất, hãy đặt ăng-ten lên cao và gần cửa sổ rồi quét lại."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Quá trình quét không tìm thấy bất kỳ kênh nào. Hãy xác minh là bộ dò mạng đã được bật nguồn và kết nối với một nguồn tín hiệu TV.\n\nNếu sử dụng ăng-ten không dây, hãy điều chỉnh vị trí hoặc hướng của ăng-ten. Để có kết quả tốt nhất, hãy đặt ăng-ten ở vị trí cao và gần cửa sổ và quét lại."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Quét lại"</item>
+ <item msgid="2092797862490235174">"Xong"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Quét tìm các kênh TV"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Thiết lập bộ dò TV"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Thiết lập bộ dò TV USB."</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Thiết lập bộ dò TV mạng"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"Đã ngắt kết nối bộ dò truyền hình USB."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Đã ngắt kết nối bộ dò mạng."</string>
+</resources>
diff --git a/usbtuner-res/values-zh-rCN/strings.xml b/usbtuner-res/values-zh-rCN/strings.xml
new file mode 100644
index 00000000..cf2b477f
--- /dev/null
+++ b/usbtuner-res/values-zh-rCN/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"电视调谐器"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB 电视调谐器"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"网络电视调谐器(测试版)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"请耐心等待处理完毕"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"调谐器软件近期已更新。请重新扫描频道。"</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"在系统声音设置中启用环绕声即可启用音频"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"无法播放音频,请试试其他电视频道"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"频道调谐器设置"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"电视调谐器设置"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB 频道调谐器设置"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"网络调谐器设置"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"请检查您的电视是否已连接到电视信号源。\n\n如果您使用的是无线电视,则可能需要调节天线的位置或方向,以便接收尽可能多的频道。要获得最佳效果,请将天线的位置调高并靠近窗户。"</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"请检查 USB 调谐器是否已插好并连接到电视信号源。\n\n如果您使用的是无线电视,则可能需要调节天线的位置或方向,以便接收尽可能多的频道。要获得最佳效果,请将天线的位置调高并靠近窗户。"</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"请检查网络调谐器是否已接通电源并连接到电视信号源。\n\n如果您使用的是无线电视,则可能需要调节天线的位置或方向,以便接收尽可能多的频道。要获得最佳效果,请将天线的位置调高并靠近窗户。"</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"继续"</item>
+ <item msgid="727245208787621142">"以后再说"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"要重新进行频道设置吗?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"此操作将移除通过电视调谐器找到的频道,并重新扫描新频道。\n\n请检查您的电视是否已连接到电视信号源。\n\n如果您使用的是无线电视,则可能需要调节天线的位置或方向,以便接收尽可能多的频道。要获得最佳效果,请将天线的位置调高并靠近窗户。"</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"此操作将移除通过 USB 调谐器找到的频道,并重新扫描新频道。\n\n请检查 USB 调谐器是否已插好并连接到电视信号源。\n\n如果您使用的是无线电视,则可能需要调节天线的位置或方向,以便接收尽可能多的频道。要获得最佳效果,请将天线的位置调高并靠近窗户。"</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"此操作将移除通过网络调谐器找到的频道,并重新扫描新频道。\n\n请检查网络调谐器是否已接通电源并连接到电视信号源。\n\n如果您使用的是无线电视,则可能需要调节天线的位置或方向,以便接收尽可能多的频道。要获得最佳效果,请将天线的位置调高并靠近窗户。"</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"继续"</item>
+ <item msgid="235450158666155406">"取消"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"选择连接类型"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"如果调谐器连接了外部天线,请选择“天线”。如果您的频道由有线电视服务商提供,请选择“有线电视”。如果您不确定,则系统会扫描以上两种类型,不过这可能会花费更长的时间。"</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"天线"</item>
+ <item msgid="2670079958754180142">"有线电视"</item>
+ <item msgid="36774059871728525">"不确定"</item>
+ <item msgid="6881204453182153978">"仅限开发用途"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"电视调谐器设置"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB 频道调谐器设置"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"网络频道调谐器设置"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"此过程可能需要几分钟时间"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"调谐器暂时无法使用或已用于录制。"</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">找到 %1$d 个频道</item>
+ <item quantity="one">找到 %1$d 个频道</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"停止频道扫描"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">找到 %1$d 个频道</item>
+ <item quantity="one">找到 %1$d 个频道</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">很好!系统在频道扫描过程中找到 %1$d 个频道。如果您觉得数量有误,请尝试调整天线的位置,然后再扫描一次。</item>
+ <item quantity="one">很好!系统在频道扫描过程中找到 %1$d 个频道。如果您觉得数量有误,请尝试调整天线的位置,然后再扫描一次。</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"完成"</item>
+ <item msgid="2480490326672924828">"重新扫描"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"未找到任何频道"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"扫描后未找到任何频道。请检查您的电视是否已连接到电视信号源。\n\n如果您使用的是无线电视,请调节天线的位置或方向。要获得最佳效果,请将天线的位置调高并靠近窗户,然后再扫描一次。"</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"扫描后未找到任何频道。请检查 USB 调谐器是否已插好并连接到电视信号源。\n\n如果您使用的是无线电视,请调节天线的位置或方向。要获得最佳效果,请将天线的位置调高并靠近窗户,然后再扫描一次。"</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"扫描后未找到任何频道。请检查网络调谐器是否已接通电源并连接到电视信号源。\n\n如果您使用的是无线电视,请调节天线的位置或方向。要获得最佳效果,请将天线的位置调高并靠近窗户,然后再扫描一次。"</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"重新扫描"</item>
+ <item msgid="2092797862490235174">"完成"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"扫描电视频道"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"电视调谐器设置"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB 电视调谐器设置"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"网络电视调谐器设置"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB 电视调谐器已断开连接。"</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"网络调谐器已断开连接。"</string>
+</resources>
diff --git a/usbtuner-res/values-zh-rHK/strings.xml b/usbtuner-res/values-zh-rHK/strings.xml
new file mode 100644
index 00000000..f2b89519
--- /dev/null
+++ b/usbtuner-res/values-zh-rHK/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"電視調諧器"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB 電視調諧器"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"網絡電視調諧器 (測試版)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"請等待系統完成處理程序"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"調諧器軟件最近已更新。請重新掃瞄頻道。"</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"在系統音效設定中啟用環迴立體聲功能即可啟用音效"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"無法播放音效,請嘗試使用其他電視頻道"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"頻道調諧器設定"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"電視調諧器設定"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB 頻道調諧器設定"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"網絡調諧器設定"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"請確定電視已連接至電視訊號來源。\n\n如果您使用無線天線,可能需要調整天線的位置或方向,以接收最多頻道。您亦可將天線放在較高位置並靠近窗戶,以獲得最佳效果。"</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"請確定 USB 調諧器已接駁並連接至電視訊號來源。\n\n如果您使用無線天線,可能需要調整天線的位置或方向,以接收最多頻道。您亦可以將天線放在較高位置並靠近窗戶,以獲取最佳效果。"</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"請確定網絡調諧器已開啟電源,並連接至電視訊號來源。\n\n如果您使用無線天線,可能需要調整天線的位置或方向,以接收最多頻道。要取得最佳效果,請將天線放在較高位置並靠近窗戶,然後重新掃瞄。"</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"繼續"</item>
+ <item msgid="727245208787621142">"暫時不要"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"要重新設定頻道嗎?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"這項操作將移除電視調諧器找到的頻道,並重新掃瞄新的頻道。\n\n請確定電視已連接至電視訊號來源。\n\n如果您使用無線天線,可能需要調整天線的位置或方向,以接收最多頻道。您亦可將天線放在較高位置並靠近窗戶,以獲得最佳效果。"</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"這項操作將移除 USB 調諧器找到的頻道,並會重新掃瞄新頻道。\n\n請確定 USB 調諧器已接駁並連接至電視訊號來源。\n\n如果您使用無線天線,可能需要調整天線的位置或方向,以接收最多頻道。您亦可將天線放在較高位置並靠近窗戶,以獲取最佳效果。"</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"這項操作將移除網絡調諧器找到的頻道,並再次掃瞄新頻道。\n\n請確定網絡調諧器已開啟電源並連接至電視訊號來源。\n\n如果您使用無線天線,請調整天線的位置或方向。要取得最佳效果,請將天線放在較高位置並靠近窗戶,然後重新掃瞄。"</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"繼續"</item>
+ <item msgid="235450158666155406">"取消"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"選擇連接類型"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"如果調諧器連接至外置天線,請選擇 [天線]。如果頻道由有線服務供應商提供,請選擇 [有線電視]。如果您不確定,系統會同時掃瞄這兩種類型的頻道,但可能需時較長。"</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"天線"</item>
+ <item msgid="2670079958754180142">"有線電視"</item>
+ <item msgid="36774059871728525">"不確定"</item>
+ <item msgid="6881204453182153978">"只限開發用途"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"電視調諧器設定"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB 頻道調諧器設定"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"網絡頻道調諧器設定"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"可能需時數分鐘"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"調諧器暫時無法使用,或已用於錄影。"</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">已找到 %1$d 個頻道</item>
+ <item quantity="one">已找到 %1$d 個頻道</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"停止頻道掃瞄"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">已找到 %1$d 個頻道</item>
+ <item quantity="one">已找到 %1$d 個頻道</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">太好了!掃瞄頻道時找到 %1$d 個頻道。如果掃瞄結果看來不正確,請嘗試調整天線位置並重新掃瞄。</item>
+ <item quantity="one">太好了!掃瞄頻道時找到 %1$d 個頻道。如果掃瞄結果看來不正確,請嘗試調整天線位置並重新掃瞄。</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"完成"</item>
+ <item msgid="2480490326672924828">"重新掃瞄"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"找不到頻道"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"掃瞄後找不到頻道。請確定電視已連接至電視訊號來源。\n\n如果您使用無線天線,請調整天線的位置或方向。您亦可將天線放在較高位置並靠近窗戶,然後重新掃瞄,以獲得最佳效果。"</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"掃瞄找不到頻道。請確定 USB 調諧器已接駁並連接至電視訊號來源。\n\n如果您使用無線天線,請調整天線的位置或方向。您亦可將天線放在較高位置並靠近窗戶,然後重新掃瞄,以獲取最佳效果。"</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"掃瞄後找不到任何頻道。請確定網絡調諧器已開啟電源,並連接至電視訊號來源。\n\n如果您使用無線天線,請調整天線的位置或方向。要取得最佳效果,請將天線放在較高位置並靠近窗戶,然後重新掃瞄。"</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"重新掃瞄"</item>
+ <item msgid="2092797862490235174">"完成"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"掃瞄電視頻道"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"電視調諧器設定"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB 電視調諧器設定"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"網絡電視調諧器設定"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB 電視調諧器已中斷連線。"</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"網絡調諧器已中斷連線。"</string>
+</resources>
diff --git a/usbtuner-res/values-zh-rTW/strings.xml b/usbtuner-res/values-zh-rTW/strings.xml
new file mode 100644
index 00000000..86624ef5
--- /dev/null
+++ b/usbtuner-res/values-zh-rTW/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"電視調諧器"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB 電視調諧器"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"網路電視調諧器 (測試版)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"請等待處理程序完成"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"調諧器軟體最近已更新。請重新掃描頻道。"</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"前往系統音效設定開啟環繞音效即可啟用音訊"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"無法播放音訊,請改用其他電視頻道"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"頻道調諧器設定"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"電視調諧器設定"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"USB 頻道調諧器設定"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"網路調諧器設定"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"請確認你的電視已連接到電視訊號來源。\n\n如果你使用無線電視天線,可能需要調整天線的位置和方向,以便接收最多頻道。為達最佳效果,請將天線放在靠近窗戶的較高位置。"</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"請確認 USB 調諧器已插入並連接到電視訊號來源。\n\n如果你使用無線電視天線,可能需要調整天線的位置和方向,以便接收最多頻道。為達最佳效果,請將天線放在靠近窗戶的較高位置。"</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"請確認你的網路調諧器已開啟電源,並連接到電視訊號來源。\n\n如果你使用無線電視天線,可能需要調整天線的位置和方向,以便接收最多頻道。為達最佳效果,請將天線放在靠近窗戶的較高位置。"</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"繼續"</item>
+ <item msgid="727245208787621142">"暫時不要"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"要重新設定頻道嗎?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"這項動作將移除電視調諧器找到的頻道,並再次掃描新的頻道。\n\n請確認你的電視已連接到電視訊號來源。\n\n如果你使用無線電視天線,可能需要調整天線的位置和方向,以便接收最多頻道。為達最佳效果,請將天線放在靠近窗戶的較高位置。"</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"這項動作將移除 USB 調諧器找到的頻道,並再次掃描新的頻道。\n\n請確認 USB 調諧器已插入並連接到電視訊號來源。\n\n如果你使用無線電視天線,可能需要調整天線的位置和方向,以便接收最多頻道。為達最佳效果,請將天線放在靠近窗戶的較高位置。"</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"這個動作將移除網路調諧器找到的頻道,並再次掃描新的頻道。\n\n請確認你的網路調諧器已開啟電源,並連接到電視訊號來源。\n\n如果你使用無線電視天線,可能需要調整天線的位置和方向,以便接收最多頻道。為達最佳效果,請將天線放在靠近窗戶的較高位置。"</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"繼續"</item>
+ <item msgid="235450158666155406">"取消"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"選取連接類型"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"如果調諧器連接外部天線,請選擇 [天線]。如果你的頻道來自有線電視服務供應商,請選擇 [有線電視]。如果你不確定,系統會掃描這兩種類型,但是可能需要較長的時間。"</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"天線"</item>
+ <item msgid="2670079958754180142">"有線電視"</item>
+ <item msgid="36774059871728525">"不確定"</item>
+ <item msgid="6881204453182153978">"僅供開發之用"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"電視調諧器設定"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"USB 頻道調諧器設定"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"網路頻道調諧器設定"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"這可能需要幾分鐘的時間"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"調諧器暫時無法使用,或是已用於錄製。"</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="other">找到 %1$d 個頻道</item>
+ <item quantity="one">找到 %1$d 個頻道</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"停止頻道掃描作業"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="other">找到 %1$d 個頻道</item>
+ <item quantity="one">找到 %1$d 個頻道</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="other">太好了!頻道掃描作業結束後找到 %1$d 個頻道。如果數量不太正確,請嘗試調整天線的位置,然後再掃描一次。</item>
+ <item quantity="one">太好了!頻道掃描作業結束後找到 %1$d 個頻道。如果數量不太正確,請嘗試調整天線的位置,然後再掃描一次。</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"完成"</item>
+ <item msgid="2480490326672924828">"重新掃描"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"找不到任何頻道"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"掃描後並未發現任何頻道。請確認你的電視已連接到電視訊號來源。\n\n如果你使用無線電視天線,請調整天線的位置和方向。為達最佳效果,請將天線放在靠近窗戶的較高位置,然後再掃描一次。"</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"掃描後並未發現任何頻道。請確認 USB 調諧器已插入並連接到電視訊號來源。\n\n如果你使用無線電視天線,請調整天線的位置和方向。為達最佳效果,請將天線放在靠近窗戶的較高位置,然後再掃描一次。"</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"掃描後並未發現任何頻道。請確認你的網路調諧器已開啟電源,並連接到電視訊號來源。\n\n如果你使用無線電視天線,請調整天線的位置和方向。為達最佳效果,請將天線放在靠近窗戶的較高位置,然後再掃描一次。"</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"重新掃描"</item>
+ <item msgid="2092797862490235174">"完成"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"掃描電視頻道"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"電視調諧器設定"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"USB 電視調諧器設定"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"網路電視調諧器設定"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"USB 電視調諧器已中斷連線。"</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"網路調諧器已中斷連線。"</string>
+</resources>
diff --git a/usbtuner-res/values-zu/strings.xml b/usbtuner-res/values-zu/strings.xml
new file mode 100644
index 00000000..fa8df8d3
--- /dev/null
+++ b/usbtuner-res/values-zu/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bt_app_name" msgid="5515382901862469770">"Ishuna ye-TV"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"Ishuna ye-USB TV"</string>
+ <string name="nt_app_name" msgid="4627006858832620833">"Ishuna yenethiwekhi ye-TV (i-BETA)"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Sicela ulinde ukuze uqede ukucubungula"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Isofthiwe yeshuna ibuyekezwe kamuva. Sicela uphinde uskene iziteshi."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Nika amandla umsindo ozungezile kuzilungiselelo zomsindo wesistimu"</string>
+ <string name="audio_passthrough_not_supported" msgid="8766302073295760976">"Ayikwazi ukudlala umsindo. Sicela uzame enye i-TV"</string>
+ <string name="ut_setup_breadcrumb" msgid="2810318605327367247">"Ukusethwa kweshuna yesiteshi"</string>
+ <string name="bt_setup_new_title" msgid="8447554965697762891">"Ukusethwa kweshuna ye-TV"</string>
+ <string name="ut_setup_new_title" msgid="2118880835101453405">"Ukusetha kweshuna yesiteshi se-USB"</string>
+ <string name="nt_setup_new_title" msgid="2996573474450060002">"Ukusethwa kweshuna yenethiwekhi"</string>
+ <string name="bt_setup_new_description" msgid="256690722062003128">"Qinisekisa ukuthi i-TV yakho ixhunywe kumthombo wesignali ye-TV.\n\nUma usebenzisa i-antenna esemoyeni, kungenzeka ukuthi kumele ulungise ukubekwa noma ukubheka ukuze uthole iziteshi eziningi. Ukuze uthole imiphumela ehamba phambili, beka phezulu naseduze kwewindi."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Qinisekisa ukuthi ishuna ye-USB ixhunyiwe futhi ixhumeke kumthombo wesignali ye-TV.\n\nUma usebenzisa i-antenna esemoyeni, kuzomele ulungise ukubekwa kwayo noma ukubheka kwayo ukuze uthole iziteshi eziningi. Ukuze uthole imiphumela ehamba phambili, yibeke phezulu eduze kwewindi."</string>
+ <string name="nt_setup_new_description" msgid="8315318180352515751">"Qinisekisa ukuthi ishuna yenethiwekhi ivuliwe yaphinde yaxhunywa kumthombo wesignali ye-TV.\n\nUma usebenzisa i-antenna esemoyeni, kungenzeka ukuthi kumele ulungise ukubekwa kwayo noma indawo ebhekiwe ukuze uthole iziteshi eziningi. Ukuze uthole imiphumela ehamba phambili, ibeke ngaphezulu naseduze kwewindi."</string>
+ <string-array name="ut_setup_new_choices">
+ <item msgid="8728069574888601683">"Qhubeka"</item>
+ <item msgid="727245208787621142">"Hhayi manje"</item>
+ </string-array>
+ <string name="bt_setup_again_title" msgid="884713873101099572">"Phinda uqalise ukusethwa kwesiteshi?"</string>
+ <string name="bt_setup_again_description" msgid="1247792492948741337">"Lokhu kuzosusa iziteshi ezitholwe kusukela kushuna ye-TV kuphinde kuskenele iziteshi ezintsha.\n\nQinisekisa ukuthi i-TV yakho ixhunywe kumthombo wesignali ye-TV.\n\nUma usebenzisa i-antenna esemoyeni, kungenzeka ukuthi kumele ulungise ukubekwa noma ukubheka ukuze uthole iziteshi eziningi. Ukuze uthole imiphumela ehamba phambili, beka phezulu naseduze kwewindi."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Lokhu kuzosusa iziteshi ezitholakele kusukela kushuna ye-USB kuphinde kuskenele iziteshi ezintsha futhi.\n\nQinisekisa ukuthi ishuna ye-USB ixhunyiwe futhi ixhumeke kumthombo wesignali ye-TV.\n\nUma usebenzisa i-antenna esemoyeni, kuzomele ulungise ukubekwa kwayo noma ukubheka kwayo ukuze uthole iziteshi eziningi. Ukuze uthole imiphumela ehamba phambili, yibeke ngaphezulu naseduze kwewindi."</string>
+ <string name="nt_setup_again_description" msgid="681642895365018072">"Lokhu kuzosusa iziteshi ezitholakele kusukela kushuna yenethiwekhi kuphinde kuskenele iziteshi ezintsha futhi.\n\nQinisekisa ukuthi ishuna yenethiwekhi ixhunyiwe futhi ixhumeke kumthombo wesignali ye-TV.\n\nUma usebenzisa i-antenna esemoyeni, kuzomele ulungise ukubekwa kwayo noma ukubheka kwayo ukuze uthole iziteshi eziningi. Ukuze uthole imiphumela ehamba phambili, yibeke ngaphezulu naseduze kwewindi."</string>
+ <string-array name="ut_setup_again_choices">
+ <item msgid="2557527790311851317">"Qhubeka"</item>
+ <item msgid="235450158666155406">"Khansela"</item>
+ </string-array>
+ <string name="ut_connection_title" msgid="8435949189164677545">"Khetha uhlobo lokuxhumeka"</string>
+ <string name="ut_connection_description" msgid="7234582943233286192">"Khetha i-Antenna uma ngabe kukhona i-antenna yangaphandle exhunywe kusishuni. Khetha ikhebuli uma ngabe iziteshi zakho ziza kusukela kumhlinzeki wesevisi yekhebuli. Uma ungaqinisekanga, zombili izinhlobo zizoskenwa, kodwa lokhu kungathatha isikhathi eside."</string>
+ <string-array name="ut_connection_choices">
+ <item msgid="1499878461856892555">"I-Antenna"</item>
+ <item msgid="2670079958754180142">"Ikhebuli"</item>
+ <item msgid="36774059871728525">"Angiqinisekile"</item>
+ <item msgid="6881204453182153978">"Ukuthuthukiswa kuphela"</item>
+ </string-array>
+ <string name="bt_channel_scan" msgid="3291924771702347469">"Ukusethwa kweshuna ye-TV"</string>
+ <string name="ut_channel_scan" msgid="6100090671500464604">"Ukusetha kweshuna yesiteshi se-USB"</string>
+ <string name="nt_channel_scan" msgid="30206992732534178">"Ukusethwa kweshuna yesiteshi senethiwekhi"</string>
+ <string name="ut_channel_scan_time" msgid="1844845425359642393">"Lokhu kungathatha amaminithi athile"</string>
+ <string name="ut_channel_scan_tuner_unavailable" msgid="3135723754380409658">"Ishuna okwamanje ayitholakali noma isivele isetshenziswa ngokurekhodwa."</string>
+ <plurals name="ut_channel_scan_message" formatted="false" msgid="3131606783282632056">
+ <item quantity="one">%1$d iziteshi ezitholakele</item>
+ <item quantity="other">%1$d iziteshi ezitholakele</item>
+ </plurals>
+ <string name="ut_stop_channel_scan" msgid="566811986747774193">"MISA UKUSKENA KWESITESHI"</string>
+ <plurals name="ut_result_found_title" formatted="false" msgid="1448908152026339099">
+ <item quantity="one">%1$d iziteshi ezitholakele</item>
+ <item quantity="other">%1$d iziteshi ezitholakele</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <item quantity="one">Kuhle! %1$d iziteshi ezitholakele ngesikhathi sokuskena kwesiteshi. Uma lokhu kungabonakali kulungile, zama ukulungisa ukuma kwe-antenna uphinde uskene futhi.</item>
+ <item quantity="other">Kuhle! %1$d iziteshi ezitholakele ngesikhathi sokuskena kwesiteshi. Uma lokhu kungabonakali kulungile, zama ukulungisa ukuma kwe-antenna uphinde uskene futhi.</item>
+ </plurals>
+ <string-array name="ut_result_found_choices">
+ <item msgid="3220617441427115421">"Kwenziwe"</item>
+ <item msgid="2480490326672924828">"Skena futhi"</item>
+ </string-array>
+ <string name="ut_result_not_found_title" msgid="4649533929056795595">"Azikho iziteshi ezitholiwe"</string>
+ <string name="bt_result_not_found_description" msgid="7378208337325024042">"Ukuskena akuzange kuthole iziteshi. Qinisekisa ukuthi i-TV yakho ixhumeke kumthombo wesignali we-TV.\n\nUma usebenzisa i-antenna esemoyeni, kungenzeka ukuthi kumele ulungise ukubekwa noma ukubheka ukuze uthole iziteshi eziningi. Ukuze uthole imiphumela ehamba phambili, beka phezulu naseduze kwewindi."</string>
+ <string name="ut_result_not_found_description" msgid="1080746285957681414">"Iskena asizange sithole noma yiziphi iziteshi. Qinisekisa ukuthi ishuna ye-USB ixhunyiwe futhi ixhumeke kumthombo wesignali ye-TV.\n\nUma usebenzisa i-antenna esemoyeni, lungisa ukubekwa kwayo noma ukuma kwayo. Ukuze uthole imiphumela ehamba phambili, yibeke phezulu naseduze kwewindi uphinde uskene."</string>
+ <string name="nt_result_not_found_description" msgid="2177919867285510855">"Iskena asizange sithole noma iziphi iziteshi. Qinisekisa ukuthi ishuna ye-USB ixhunyiwe futhi ixhumeke kumthombo wesignali ye-TV.\n\nUma usebenzisa i-antenna esemoyeni, lungisa ukubekwa kwayo noma ukuma kwayo. Ukuze uthole imiphumela ehamba phambili, yibeke phezulu naseduze kwewindi uphinde uskene."</string>
+ <string-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Skena futhi"</item>
+ <item msgid="2092797862490235174">"Kwenziwe"</item>
+ </string-array>
+ <string name="ut_setup_notification_content_title" msgid="3439301313253273422">"Skenela iziteshi ze-TV"</string>
+ <string name="bt_setup_notification_content_text" msgid="7578820978070596694">"Ukusethwa kweshuna ye-TV"</string>
+ <string name="ut_setup_notification_content_text" msgid="1656697878628557384">"Ukusetha kweshuna ye-USB TV"</string>
+ <string name="nt_setup_notification_content_text" msgid="1186152789699583895">"Ukusethwa kweshuna yenethiwekhi ye-TV"</string>
+ <string name="msg_usb_tuner_disconnected" msgid="1206606328815245830">"Ishuna ye-USB TV inqanyuliwe."</string>
+ <string name="msg_network_tuner_disconnected" msgid="7103193099674978964">"Ishuna yenethiwekhi inqanyuliwe."</string>
+</resources>
diff --git a/tuner/res/values/attrs.xml b/usbtuner-res/values/attrs.xml
index 4249ed2f..4249ed2f 100644
--- a/tuner/res/values/attrs.xml
+++ b/usbtuner-res/values/attrs.xml
diff --git a/tuner/res/values/colors.xml b/usbtuner-res/values/colors.xml
index 873ecc8e..873ecc8e 100644
--- a/tuner/res/values/colors.xml
+++ b/usbtuner-res/values/colors.xml
diff --git a/tuner/res/values/dimens.xml b/usbtuner-res/values/dimens.xml
index 1fe39f6c..1fe39f6c 100644
--- a/tuner/res/values/dimens.xml
+++ b/usbtuner-res/values/dimens.xml
diff --git a/tuner/res/values/integers.xml b/usbtuner-res/values/integers.xml
index 65d20c67..65d20c67 100644
--- a/tuner/res/values/integers.xml
+++ b/usbtuner-res/values/integers.xml
diff --git a/tuner/res/values/strings.xml b/usbtuner-res/values/strings.xml
index 58d7214c..dd393c3e 100644
--- a/tuner/res/values/strings.xml
+++ b/usbtuner-res/values/strings.xml
@@ -127,36 +127,18 @@
</plurals>
<!-- Title for a button which will stop channel scanning process -->
<string name="ut_stop_channel_scan">STOP CHANNEL SCAN</string>
-
- <!-- Title for lineup selection menu when TV lineups are found -->
- <string name="ut_lineup_title_lineups_found" >Select a TV lineup</string>
- <!-- Description for lineup selection menu when TV lineups are found.-->
- <string name="ut_lineup_description_lineups_found" >Choose how you receive your TV signal.</string>
- <!-- Title for lineup selection menu when no TV lineups is found -->
- <string name="ut_lineup_title_lineups_not_found" >No TV lineups found</string>
- <!-- Description for lineup selection menu when no TV lineups is found -->
- <string name="ut_lineup_description_lineups_not_found" >Please make sure your device is connected to the internet and the zip code / postal code is correct.</string>
- <!-- Title for lineup selection menu when fetching lineups -->
- <string name="ut_lineup_title_fetching_lineups">Fetching TV lineups…</string>
- <!-- Description for lineup selection menu when fetching lineups -->
- <string name="ut_lineup_description_fetching_lineups">This may take a few minutes. Please wait…</string>
- <!-- Description for a button when no channels match -->
- <string name="ut_lineup_no_channels_matched">No channels match</string>
- <!-- Number of matched channels for lineup selection menu when lineups were found -->
- <plurals name="ut_lineup_channels_matched">
- <item quantity="one"><xliff:g id="channels_matched_one">%1$d</xliff:g> channel matches</item>
- <item quantity="other"><xliff:g id="channels_matched_other">%1$d</xliff:g> channels match</item>
- </plurals>
- <!-- A button to select a specific TV lineup of channels for the channels received by a "Television Antenna" -->
- <string name="ut_lineup_name_antenna">Antenna</string>
<!-- Title for channel scanning result menu when channels were found -->
<plurals name="ut_result_found_title">
<item quantity="one">%1$d channel found</item>
<item quantity="other">%1$d channels found</item>
</plurals>
- <!-- Channel description for channel scanning result menu when channels were found "scan again" should match the button in string ut_result_found_choices-->
- <string name="ut_result_found_description">If that seems incorrect, try adjusting your antenna and scan again.</string>
- <!-- Rescan description for channel scanning result menu when channels were found -->
+ <!-- Description for channel scanning result menu when channels were found -->
+ <plurals name="ut_result_found_description">
+ <item quantity="one">Nice! %1$d channel was found during the channel scan.
+ If this doesn’t seem right, try adjusting the antenna position and scan again.</item>
+ <item quantity="other">Nice! %1$d channels were found during the channel scan.
+ If this doesn’t seem right, try adjusting the antenna position and scan again.</item>
+ </plurals>
<!-- Menu items for channel scanning result menu when channels were found -->
<string-array name="ut_result_found_choices">
<item>Done</item>
@@ -187,8 +169,8 @@
</string-array>
<!-- Notification of USB channel tuner setup strings. -->
- <!-- Name of notification channel which is for tuner setup. "USB Tuner" is a TV Tuner that is connected via a USB connection.-->
- <string name="ut_setup_notification_channel_name" >USB Tuner setup</string>
+ <!-- Name of notification channel which is for tuner setup. -->
+ <string name="ut_setup_notification_channel_name" translatable="false">USB tuner set up</string>
<!-- Content title of the notification to launch the setup application of
USB tuner TV input for scanning channels. -->
<string name="ut_setup_notification_content_title">Scan for TV channels</string>
@@ -206,14 +188,4 @@
<string name="msg_usb_tuner_disconnected">USB TV tuner disconnected.</string>
<!-- Message when Network tuner device is unplugged or disconnected. [CHAR LIMIT=NONE] -->
<string name="msg_network_tuner_disconnected">Network tuner disconnected.</string>
-
- <!-- Title of postal/zip code input guided step fragment [CHAR LIMIT=30] -->
- <string name="postal_code_guidance_title">Enter your ZIP Code.</string>
- <!-- Description of postal/zip code input guided step fragment [CHAR LIMIT=NONE] -->
- <string name="postal_code_guidance_description">Live TV app will use the ZIP Code to provide a complete program guide for the TV channels.</string>
- <!-- Description of postal/zip code input edit text view to prompt users entering ZIP Code [CHAR LIMIT=30] -->
- <string name="postal_code_action_description">Enter your ZIP Code</string>
- <!-- Warning message shown in description field of postal/zip code input edit text view when user enters an invalid ZIP Code and presses Done [CHAR LIMIT=30] -->
- <string name="postal_code_invalid_warning">Invalid ZIP Code</string>
-
</resources>
diff --git a/tuner/res/xml/ut_tvinputservice.xml b/usbtuner-res/xml/ut_tvinputservice.xml
index a2f45a91..9b7fdbc2 100644
--- a/tuner/res/xml/ut_tvinputservice.xml
+++ b/usbtuner-res/xml/ut_tvinputservice.xml
@@ -34,6 +34,6 @@
-->
<tv-input xmlns:android="http://schemas.android.com/apk/res/android"
- android:setupActivity="com.android.tv.tuner.setup.LiveTvTunerSetupActivity"
+ android:setupActivity="com.android.tv.tuner.setup.TunerSetupActivity"
android:canRecord="true"
android:tunerCount="1" />
diff --git a/version.mk b/version.mk
index 57f3a43b..6886dc07 100644
--- a/version.mk
+++ b/version.mk
@@ -1,4 +1,4 @@
-#####################################################
+#
# Copyright (C) 2015 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -48,13 +48,13 @@
base_version_major := 1
# Change this for each branch
-base_version_minor := 17
+base_version_minor := 15
# code_version_major will overflow at 22
code_version_major := $(shell echo $$(($(base_version_major)+3)))
# x86 and arm sometimes don't match.
-code_version_build := 001
+code_version_build := 007
#####################################################
#####################################################
# Collect automatic version code parameters